diff --git a/lib/architex/schema/account.ex b/lib/architex/schema/account.ex index 3801ecb..57f408a 100644 --- a/lib/architex/schema/account.ex +++ b/lib/architex/schema/account.ex @@ -16,7 +16,8 @@ defmodule Architex.Account do schema "accounts" do field :localpart, :string field :password_hash, :string, redact: true - field :avatar_url + field :avatar_url, :string + field :displayname, :string has_many :devices, Device many_to_many :joined_rooms, Room, diff --git a/lib/architex_web/client/controllers/profile_controller.ex b/lib/architex_web/client/controllers/profile_controller.ex index 796d91b..7364569 100644 --- a/lib/architex_web/client/controllers/profile_controller.ex +++ b/lib/architex_web/client/controllers/profile_controller.ex @@ -1,4 +1,5 @@ defmodule ArchitexWeb.Client.ProfileController do + # TODO: Changes should be propagated using join events and presence. use ArchitexWeb, :controller import ArchitexWeb.Error @@ -9,18 +10,32 @@ defmodule ArchitexWeb.Client.ProfileController do alias Plug.Conn alias Ecto.Changeset + @doc """ + Get the user's display name. + + Action for GET /_matrix/client/r0/profile/{userId}/displayname. + """ + def get_displayname(conn, %{"user_id" => user_id}) do + get_property(conn, :displayname, user_id) + end + @doc """ Get the user's avatar URL. Action for GET /_matrix/client/r0/profile/{userId}/avatar_url. """ def get_avatar_url(conn, %{"user_id" => user_id}) do + get_property(conn, :avatar_url, user_id) + end + + defp get_property(conn, property_key, user_id) do case UserId.cast(user_id) do {:ok, %UserId{localpart: localpart, domain: domain}} -> if domain == Architex.server_name() do case Repo.one(from a in Account, where: a.localpart == ^localpart) do - %Account{avatar_url: avatar_url} -> - data = if avatar_url, do: %{avatar_url: avatar_url}, else: %{} + %Account{} = account -> + property_val = Map.get(account, property_key) + data = if property_val, do: %{property_key => property_val}, else: %{} conn |> put_status(200) @@ -39,20 +54,33 @@ defmodule ArchitexWeb.Client.ProfileController do end end + @doc """ + This API sets the given user's display name. + + Action for PUT /_matrix/client/r0/profile/{userId}/displayname. + """ + def set_displayname(conn, %{"user_id" => user_id} = params) do + displayname = Map.get(params, "displayname") + + update_property(conn, :displayname, displayname, user_id) + end + @doc """ This API sets the given user's avatar URL. Action for PUT /_matrix/client/r0/profile/{userId}/avatar_url. """ - def set_avatar_url(%Conn{assigns: %{account: account}} = conn, %{"user_id" => user_id} = params) do - if Account.get_mxid(account) == user_id do - avatar_url = Map.get(params, "avatar_url") + def set_avatar_url(conn, %{"user_id" => user_id} = params) do + avatar_url = Map.get(params, "avatar_url") - if not is_nil(avatar_url) do - account - |> Changeset.change(avatar_url: avatar_url) - |> Repo.update() - end + update_property(conn, :avatar_url, avatar_url, user_id) + end + + defp update_property(%Conn{assigns: %{account: account}} = conn, property_key, property, user_id) do + if Account.get_mxid(account) == user_id do + account + |> Changeset.change([{property_key, property}]) + |> Repo.update() conn |> send_resp(200, []) diff --git a/lib/architex_web/router.ex b/lib/architex_web/router.ex index eca45d9..47ac7c0 100644 --- a/lib/architex_web/router.ex +++ b/lib/architex_web/router.ex @@ -26,12 +26,22 @@ defmodule ArchitexWeb.Router do pipe_through :public scope "/r0" do - post "/register", RegisterController, :register - get "/register/available", AccountController, :available - get "/login", LoginController, :login_types - post "/login", LoginController, :login get "/directory/list/room/:room_id", RoomDirectoryController, :get_visibility - get "/profile/:user_id/avatar_url", ProfileController, :get_avatar_url + + scope "/login" do + get "/", LoginController, :login_types + post "/", LoginController, :login + end + + scope "/register" do + post "/", RegisterController, :register + get "/available", AccountController, :available + end + + scope "/profile/:user_id" do + get "/avatar_url", ProfileController, :get_avatar_url + get "/displayname", ProfileController, :get_displayname + end end get "/versions", InfoController, :versions @@ -56,7 +66,11 @@ defmodule ArchitexWeb.Router do get "/joined_rooms", RoomController, :joined_rooms get "/capabilities", InfoController, :capabilities get "/sync", SyncController, :sync - put "/profile/:user_id/avatar_url", ProfileController, :set_avatar_url + + scope "/profile/:user_id" do + put "/avatar_url", ProfileController, :set_avatar_url + put "/displayname", ProfileController, :set_displayname + end scope "/directory" do put "/room/:alias", AliasesController, :create diff --git a/priv/repo/migrations/20210830160818_create_initial_tables.exs b/priv/repo/migrations/20210830160818_create_initial_tables.exs index 2b643a2..c8fae73 100644 --- a/priv/repo/migrations/20210830160818_create_initial_tables.exs +++ b/priv/repo/migrations/20210830160818_create_initial_tables.exs @@ -6,6 +6,7 @@ defmodule Architex.Repo.Migrations.CreateInitialTables do add :localpart, :string, null: false add :password_hash, :string, size: 60, null: false add :avatar_url, :string, null: true + add :displayname, :string, null: true timestamps(updated_at: false) end