Skip to content

Commit

Permalink
Setup guardian session sharing with main app
Browse files Browse the repository at this point in the history
  • Loading branch information
zacksiri committed Nov 25, 2024
1 parent f757e86 commit 07fb744
Show file tree
Hide file tree
Showing 17 changed files with 179 additions and 36 deletions.
4 changes: 4 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ config :opsmaru, Opsmaru.Cache,
backend: :shards
]

config :opsmaru, Opsmaru.Guardian,
issuer: "instellar",
secret_key: "XsaA1vyT1Z9bnBh5e0J/G9/lhQRpbypHKCgF0ZoAJTbj3ActaAMjt0Y7GuB+IkL2"

# Configures the mailer
#
# By default it uses the "Local" adapter which stores the emails
Expand Down
2 changes: 1 addition & 1 deletion config/dev.exs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ config :opsmaru, OpsmaruWeb.Endpoint,
check_origin: false,
code_reloader: true,
debug_errors: true,
secret_key_base: "l7A+cY9tJkVgLhd+66+iPTV+8yIa56Nf1ku2f1kv+BMALcJMhDVLote692Iw+gI6",
secret_key_base: "TH0doam1v01ExZH98/1mUvgq+JstaA7Msn8I8l9oPa/pqCk5Kelwa16m012F7tmE",
watchers: [
esbuild: {Esbuild, :install_and_run, [:opsmaru, ~w(--sourcemap=inline --watch)]},
tailwind: {Tailwind, :install_and_run, [:opsmaru, ~w(--watch)]}
Expand Down
4 changes: 4 additions & 0 deletions config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ if config_env() == :prod do
],
secret_key_base: secret_key_base

config :opsmaru, Opsmaru.Guardian,
issuer: "instellar",
secret_key: secret_key_base

# ## SSL Support
#
# To get SSL working, you will need to add the `https` key
Expand Down
13 changes: 13 additions & 0 deletions lib/opsmaru/accounts/user.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
defmodule Opsmaru.Accounts.User do
use Ecto.Schema
import Ecto.Changeset

embedded_schema do
field :username, :string
end

def changeset(user, attrs) do
user
|> cast(attrs, [:id, :username])
end
end
1 change: 0 additions & 1 deletion lib/opsmaru/content/technology/manager.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ defmodule Opsmaru.Content.Technology.Manager do
|> Sanity.query(options, perspective: "published")
|> Sanity.request!(sanity_request_opts())
|> Sanity.result!()
|> IO.inspect()
|> Enum.map(&Technology.parse/1)
end
end
27 changes: 27 additions & 0 deletions lib/opsmaru/guardian.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
defmodule Opsmaru.Guardian do
use Guardian, otp_app: :opsmaru

alias Opsmaru.Accounts.User

def subject_for_token(%{id: id}, _claims) do
sub = to_string(id)

{:ok, sub}
end

def subject_for_token(_, _) do
{:error, :invalid_resource}
end

def resource_from_claims(%{"sub" => id}) do
id = String.to_integer(id)

resource = %User{id: id}

{:ok, resource}
end

def resource_from_claims(_claims) do
{:error, :invalid_claim}
end
end
11 changes: 11 additions & 0 deletions lib/opsmaru_web/components/base_components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ defmodule OpsmaruWeb.BaseComponents do

attr :mobile_nav_active, :boolean, default: false
attr :navigation, Content.Navigation, required: true
attr :current_user, Opsmaru.Accounts.User, default: nil

def header(assigns) do
~H"""
Expand Down Expand Up @@ -44,6 +45,16 @@ defmodule OpsmaruWeb.BaseComponents do
<%= link.title %>
</.link>
</.nav>
<.nav class="relative flex group/item">
<.link :if={!@current_user} navigate={"/auth/users/log_in"} class="flex items-center px-4 py-3 text-base font-medium text-slate-950 bg-blend-multiply hover:bg-black/[2.5%]">
<%= gettext("Log in") %>
</.link>
</.nav>
<.nav class="relative flex group/item">
<.link :if={@current_user} navigate={"/home"} class="flex items-center px-4 py-3 text-base font-medium text-slate-950 bg-blend-multiply hover:bg-black/[2.5%]">
<%= gettext("Dashboard") %>
</.link>
</.nav>
</nav>
<button
phx-click={JS.push("toggle", value: %{"component" => "mobile-nav"})}
Expand Down
53 changes: 41 additions & 12 deletions lib/opsmaru_web/components/course_components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ defmodule OpsmaruWeb.CourseComponents do
def get_support(assigns) do
h2 = Enum.find(assigns.section.contents, &(&1.slug == "learn-get-support-h2"))
title = Enum.find(assigns.section.contents, &(&1.slug == "learn-get-support-title"))
description = Enum.find(assigns.section.contents, &(&1.slug == "learn-get-support-description"))

description =
Enum.find(assigns.section.contents, &(&1.slug == "learn-get-support-description"))

content = Enum.find(assigns.section.contents, &(&1.slug == "learn-get-support-content"))
card = Enum.find(assigns.section.cards, &(&1.slug == "learn-get-support-card"))

Expand All @@ -106,34 +109,49 @@ defmodule OpsmaruWeb.CourseComponents do
~H"""
<div class="my-32 px-6 lg:px-8">
<div class="mx-auto max-w-2xl lg:max-w-7xl">
<h2 class="font-mono text-xs/5 font-semibold uppercase tracking-widest text-slate-500"><%= @h2.body %></h2>
<h3 class="mt-2 text-pretty text-4xl font-medium tracking-tighter text-slate-950 sm:text-6xl"><%= @title.body %></h3>
<h2 class="font-mono text-xs/5 font-semibold uppercase tracking-widest text-slate-500">
<%= @h2.body %>
</h2>
<h3 class="mt-2 text-pretty text-4xl font-medium tracking-tighter text-slate-950 sm:text-6xl">
<%= @title.body %>
</h3>
<p class="mt-6 max-w-3xl text-2xl font-medium text-slate-500"><%= @description.body %></p>
<div class="mt-24 grid grid-cols-1 gap-16 lg:grid-cols-[1fr_24rem]">
<div class="max-w-lg">
<div class="prose text-slate-600">
<%= raw(render_markdown(@content.body)) %>
</div>
<div class="mt-6">
<a href="https://discord.gg/gPFvN9QW" class="w-full sm:w-auto inline-flex items-center justify-center px-4 py-[calc(theme(spacing.2)-1px)] rounded-full border border-transparent bg-gray-950 shadow-md whitespace-nowrap text-base font-medium text-white data-[disabled]:bg-gray-950 data-[hover]:bg-gray-800 data-[disabled]:opacity-40">
<a
href="https://discord.gg/gPFvN9QW"
class="w-full sm:w-auto inline-flex items-center justify-center px-4 py-[calc(theme(spacing.2)-1px)] rounded-full border border-transparent bg-gray-950 shadow-md whitespace-nowrap text-base font-medium text-white data-[disabled]:bg-gray-950 data-[hover]:bg-gray-800 data-[disabled]:opacity-40"
>
<%= gettext("Join Discord") %>
</a>
<a href="https://cal.com/zacksiri/opsmaru-onboarding" class="w-full sm:w-auto mt-6 sm:ml-2 inline-flex items-center justify-center px-4 py-[calc(theme(spacing.2)-1px)] rounded-full border border-transparent shadow ring-1 ring-black/10 whitespace-nowrap text-base font-medium text-gray-950 data-[disabled]:bg-transparent data-[hover]:bg-gray-50 data-[disabled]:opacity-40">
<a
href="https://cal.com/zacksiri/opsmaru-onboarding"
class="w-full sm:w-auto mt-6 sm:ml-2 inline-flex items-center justify-center px-4 py-[calc(theme(spacing.2)-1px)] rounded-full border border-transparent shadow ring-1 ring-black/10 whitespace-nowrap text-base font-medium text-gray-950 data-[disabled]:bg-transparent data-[hover]:bg-gray-50 data-[disabled]:opacity-40"
>
<%= gettext("Book a call") %>
</a>
</div>
</div>
<div class="relative flex aspect-square flex-col justify-end overflow-hidden rounded-3xl sm:aspect-[5/4] lg:aspect-[3/4]">
<img src={Image.url(@card.cover, w: 600)} class="absolute inset-0 object-cover" />
<div class="absolute inset-0 rounded-3xl bg-gradient-to-t from-black from-10% to-75% ring-1 ring-inset ring-gray-950/10 lg:from-25%"></div>
<div class="absolute inset-0 rounded-3xl bg-gradient-to-t from-black from-10% to-75% ring-1 ring-inset ring-gray-950/10 lg:from-25%">
</div>
<figure class="relative p-10">
<blockquote>
<p class="relative text-md text-white before:absolute before:-translate-x-full"><%= @card.description %></p>
<p class="relative text-md text-white before:absolute before:-translate-x-full">
<%= @card.description %>
</p>
</blockquote>
<figcaption class="mt-6 border-t border-white/20 pt-6">
<p class="text-sm/6 font-medium text-white"><%= @card.heading %></p>
<p class="text-sm/6 font-medium">
<span class="bg-gradient-to-r from-cyan-300 from-[28%] via-[#c084fc] via-[70%] to-[#7c3aed] bg-clip-text text-transparent"><%= @card.title %></span>
<span class="bg-gradient-to-r from-cyan-300 from-[28%] via-[#c084fc] via-[70%] to-[#7c3aed] bg-clip-text text-transparent">
<%= @card.title %>
</span>
</p>
</figcaption>
</figure>
Expand Down Expand Up @@ -204,14 +222,25 @@ defmodule OpsmaruWeb.CourseComponents do
<h2 class="mt-24 font-mono text-xs/5 font-semibold uppercase tracking-widest text-slate-500">
<%= @category.name %>
</h2>
<h3 class="mt-2 text-pretty text-4xl font-medium tracking-tighter text-gray-950 data-[dark]:text-white sm:text-6xl"><%= @category.title %></h3>
<h3 class="mt-2 text-pretty text-4xl font-medium tracking-tighter text-gray-950 data-[dark]:text-white sm:text-6xl">
<%= @category.title %>
</h3>
<p class="mt-6 max-w-3xl text-2xl font-medium text-gray-500"><%= @category.description %></p>
<ul role="list" class="mx-auto mt-20 grid max-w-2xl grid-cols-1 gap-x-6 gap-y-20 sm:grid-cols-2 lg:max-w-4xl lg:gap-x-8 xl:max-w-none">
<ul
role="list"
class="mx-auto mt-20 grid max-w-2xl grid-cols-1 gap-x-6 gap-y-20 sm:grid-cols-2 lg:max-w-4xl lg:gap-x-8 xl:max-w-none"
>
<li :for={course <- @category.courses} class="flex flex-col gap-6 xl:flex-row">
<img class="aspect-[4/5] w-52 flex-none rounded-2xl object-cover" src={Image.url(course.cover, w: 600)} alt={course.cover.alt} />
<img
class="aspect-[4/5] w-52 flex-none rounded-2xl object-cover"
src={Image.url(course.cover, w: 600)}
alt={course.cover.alt}
/>
<div class="flex-auto">
<h3 class="text-lg/8 font-semibold tracking-tight text-gray-900"><%= course.title %></h3>
<p class="text-base/7 text-gray-600"><%= course.main_technology.title %> - <%= course.main_technology.category.name %></p>
<p class="text-base/7 text-gray-600">
<%= course.main_technology.title %> - <%= course.main_technology.category.name %>
</p>
<p class="mt-6 text-base/7 text-gray-600"><%= course.description %></p>
<.link
navigate={~p"/how-to/#{course.slug}"}
Expand Down
2 changes: 1 addition & 1 deletion lib/opsmaru_web/components/layouts/app.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</div>
<div class="relative px-6 lg:px-8">
<div class="mx-auto max-w-2xl lg:max-w-7xl">
<BaseComponents.header navigation={@main_nav} mobile_nav_active={@mobile_nav_active} />
<BaseComponents.header navigation={@main_nav} mobile_nav_active={@mobile_nav_active} current_user={@current_user} />
</div>
</div>
<.flash_group flash={@flash} />
Expand Down
4 changes: 2 additions & 2 deletions lib/opsmaru_web/endpoint.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ defmodule OpsmaruWeb.Endpoint do
# Set :encryption_salt if you would also like to encrypt it.
@session_options [
store: :cookie,
key: "_opsmaru_key",
signing_salt: "UTmcQflg",
key: "_instellar_key",
signing_salt: "1ZHdrgO2",
same_site: "Lax"
]

Expand Down
2 changes: 1 addition & 1 deletion lib/opsmaru_web/live/home_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ defmodule OpsmaruWeb.HomeLive do
</div>
<div class="relative px-6 lg:px-8">
<div class="mx-auto max-w-2xl lg:max-w-7xl">
<BaseComponents.header navigation={@main_nav} mobile_nav_active={@mobile_nav_active} />
<BaseComponents.header navigation={@main_nav} mobile_nav_active={@mobile_nav_active} current_user={@current_user} />
<HomeComponents.hero section={@hero_section} />
</div>
</div>
Expand Down
23 changes: 23 additions & 0 deletions lib/opsmaru_web/live/hooks/user_hook.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
defmodule OpsmaruWeb.UserHook do
import Phoenix.Component

def on_mount(:current_user, _params, session, socket) do
socket = mount_current_user(session, socket)

{:cont, socket}
end

defp mount_current_user(session, socket) do
with %{"guardian_default_token" => token} <- session,
{:ok, user, _claims} <- Opsmaru.Guardian.resource_from_token(token) do
socket
|> assign_new(:current_user, fn -> user end)
|> assign_new(:current_user_id, fn -> user.id end)
else
_ ->
socket
|> assign_new(:current_user, fn -> nil end)
|> assign_new(:current_user_id, fn -> nil end)
end
end
end
16 changes: 16 additions & 0 deletions lib/opsmaru_web/plugs/browser_error_handler.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
defmodule OpsmaruWeb.Plugs.BrowserErrorHandler do
use OpsmaruWeb, :controller

@behaviour Guardian.Plug.ErrorHandler

@impl Guardian.Plug.ErrorHandler
def auth_error(conn, {:unauthenticated, _reason}, _opts) do
redirect(conn, to: "/auth/users/log_in")
end

def auth_error(conn, {:invalid_token, :token_expired}, _opts) do
conn
|> Opsmaru.Guardian.Plug.sign_out()
|> redirect(to: "/auth/users/log_in")
end
end
14 changes: 13 additions & 1 deletion lib/opsmaru_web/router.ex
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
defmodule OpsmaruWeb.Router do
use OpsmaruWeb, :router

alias Guardian.Plug.Pipeline
alias Guardian.Plug.VerifySession

pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :put_root_layout, html: {OpsmaruWeb.Layouts, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers

plug Pipeline,
module: Opsmaru.Guardian,
error_handler: OpsmaruWeb.Plugs.BrowserErrorHandler

plug VerifySession, refresh_from_cookie: true
end

pipeline :api do
Expand All @@ -20,7 +29,10 @@ defmodule OpsmaruWeb.Router do
get "/blog/rss.xml", Blog.RssController, :index

live_session :default,
on_mount: [{OpsmaruWeb.NavigationHook, :main}] do
on_mount: [
{OpsmaruWeb.UserHook, :current_user},
{OpsmaruWeb.NavigationHook, :main}
] do
live "/", HomeLive

live "/blog", BlogLive.Index
Expand Down
3 changes: 3 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ defmodule Opsmaru.MixProject do
{:stripity_stripe, "~> 3.2.0"},
{:money, "~> 1.13.1"},

# Auth
{:guardian, "~> 2.3"},

# Content
{:sanity, "~> 2.0"},
{:mdex, github: "leandrocp/mdex", branch: "main"},
Expand Down
2 changes: 2 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
"gettext": {:hex, :gettext, "0.26.1", "38e14ea5dcf962d1fc9f361b63ea07c0ce715a8ef1f9e82d3dfb8e67e0416715", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "01ce56f188b9dc28780a52783d6529ad2bc7124f9744e571e1ee4ea88bf08734"},
"google_protos": {:hex, :google_protos, "0.4.0", "93e1be2c1a07517ffed761f69047776caf35e4acd385aac4f5ce4fedd07f3660", [:mix], [{:protobuf, "~> 0.10", [hex: :protobuf, repo: "hexpm", optional: false]}], "hexpm", "4c54983d78761a3643e2198adf0f5d40a5a8b08162f3fc91c50faa257f3fa19f"},
"grpc": {:hex, :grpc, "0.9.0", "1b930a57272d4356ea65969b984c2eb04f3dab81420e1e28f0e6ec04b8f88515", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:cowboy, "~> 2.10", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowlib, "~> 2.12", [hex: :cowlib, repo: "hexpm", optional: false]}, {:gun, "~> 2.0", [hex: :gun, repo: "hexpm", optional: false]}, {:jason, ">= 0.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mint, "~> 1.5", [hex: :mint, repo: "hexpm", optional: false]}, {:protobuf, "~> 0.11", [hex: :protobuf, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7c059698248738fcf7ad551f1d78f4a3d2e0642a72a5834f2a0b0db4b9f3d2b5"},
"guardian": {:hex, :guardian, "2.3.2", "78003504b987f2b189d76ccf9496ceaa6a454bb2763627702233f31eb7212881", [:mix], [{:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "b189ff38cd46a22a8a824866a6867ca8722942347f13c33f7d23126af8821b52"},
"gun": {:hex, :gun, "2.1.0", "b4e4cbbf3026d21981c447e9e7ca856766046eff693720ba43114d7f5de36e87", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "52fc7fc246bfc3b00e01aea1c2854c70a366348574ab50c57dfe796d24a0101d"},
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
"heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized"]},
"hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"insterra_bridge": {:git, "https://github.com/upmaru/insterra-bridge.git", "7ce6a31cb7d3fe9bf058948bdd3f097d2a890746", [branch: "develop"]},
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
"jose": {:hex, :jose, "1.11.10", "a903f5227417bd2a08c8a00a0cbcc458118be84480955e8d251297a425723f83", [:mix, :rebar3], [], "hexpm", "0d6cd36ff8ba174db29148fc112b5842186b68a90ce9fc2b3ec3afe76593e614"},
"mdex": {:git, "https://github.com/leandrocp/mdex.git", "7ec0c0d6fc2091b5aa9c03f1e1cc50c85a16f960", [branch: "main"]},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"},
Expand Down
34 changes: 17 additions & 17 deletions priv/static/images/site.webmanifest
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
{
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
"name": "Opsmaru",
"short_name": "Opsmaru",
"icons": [
{
"src": "/site/images/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/site/images/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

0 comments on commit 07fb744

Please sign in to comment.