An example AT Protocol application, written in Elixir using atex and Drinkup.
1defmodule StatusphereWeb.PageController do
2 alias Statusphere.Repo
3 alias Statusphere.Status
4 require Logger
5 import Ecto.Query, only: [from: 2]
6 use StatusphereWeb, :controller
7
8 def home(conn, _params) do
9 query =
10 from u in Status,
11 order_by: [desc: u.indexed_at],
12 limit: 10
13
14 statuses = Repo.all(query)
15
16 status_identities =
17 statuses
18 |> Enum.map(fn %{author_did: did} ->
19 case Atex.IdentityResolver.resolve(did) do
20 {:ok, identity} -> {identity.did, identity.handle}
21 {:error, _} -> {did, did}
22 end
23 end)
24 |> Enum.into(%{})
25
26 with {:ok, client} <- Atex.XRPC.OAuthClient.from_conn(conn),
27 {:ok, %{body: %{value: profile}}, client} <-
28 Atex.XRPC.get(client, %Com.Atproto.Repo.GetRecord{
29 params: %{
30 repo: client.did,
31 collection: "app.bsky.actor.profile",
32 rkey: "self"
33 }
34 }) do
35 conn
36 |> Atex.XRPC.OAuthClient.update_plug(client)
37 |> render(:home,
38 profile: profile,
39 did: client.did,
40 statuses: statuses,
41 status_identities: status_identities
42 )
43 else
44 {:error, err, client} ->
45 Logger.error("Failed to fetch Bluesky profile for #{client.did}: #{inspect(err)}")
46
47 conn
48 |> Atex.XRPC.OAuthClient.update_plug(client)
49 |> render(:home,
50 profile: %{},
51 did: client.did,
52 statuses: statuses,
53 status_identities: status_identities
54 )
55
56 _err ->
57 render(conn, :home,
58 profile: nil,
59 did: nil,
60 statuses: statuses,
61 status_identities: status_identities
62 )
63 end
64 end
65
66 def login(conn, _params) do
67 render(conn, :login)
68 end
69
70 def logout(conn, _params) do
71 conn
72 |> delete_session(:atex_oauth)
73 |> redirect(to: "/")
74 end
75end