+ def get_lists(%{assigns: %{user: user}} = conn, opts) do
+ lists = Pleroma.List.for_user(user, opts)
+ res = ListView.render("lists.json", lists: lists)
+ json(conn, res)
+ end
+
+ def get_list(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with %Pleroma.List{} = list <- Pleroma.List.get(id, user) do
+ res = ListView.render("list.json", list: list)
+ json(conn, res)
+ else
+ _e -> json(conn, "error")
+ end
+ end
+
+ def account_lists(%{assigns: %{user: user}} = conn, %{"id" => account_id}) do
+ lists = Pleroma.List.get_lists_account_belongs(user, account_id)
+ res = ListView.render("lists.json", lists: lists)
+ json(conn, res)
+ end
+
+ def delete_list(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
+ {:ok, _list} <- Pleroma.List.delete(list) do
+ json(conn, %{})
+ else
+ _e ->
+ json(conn, "error")
+ end
+ end
+
+ def create_list(%{assigns: %{user: user}} = conn, %{"title" => title}) do
+ with {:ok, %Pleroma.List{} = list} <- Pleroma.List.create(title, user) do
+ res = ListView.render("list.json", list: list)
+ json(conn, res)
+ end
+ end
+
+ def add_to_list(%{assigns: %{user: user}} = conn, %{"id" => id, "account_ids" => accounts}) do
+ accounts
+ |> Enum.each(fn account_id ->
+ with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
+ %User{} = followed <- Repo.get(User, account_id) do
+ Pleroma.List.follow(list, followed)
+ end
+ end)
+
+ json(conn, %{})
+ end
+
+ def remove_from_list(%{assigns: %{user: user}} = conn, %{"id" => id, "account_ids" => accounts}) do
+ accounts
+ |> Enum.each(fn account_id ->
+ with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
+ %User{} = followed <- Repo.get(Pleroma.User, account_id) do
+ Pleroma.List.unfollow(list, followed)
+ end
+ end)
+
+ json(conn, %{})
+ end
+
+ def list_accounts(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
+ {:ok, users} = Pleroma.List.get_following(list) do
+ render(conn, AccountView, "accounts.json", %{users: users, as: :user})
+ end
+ end
+
+ def rename_list(%{assigns: %{user: user}} = conn, %{"id" => id, "title" => title}) do
+ with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
+ {:ok, list} <- Pleroma.List.rename(list, title) do
+ res = ListView.render("list.json", list: list)
+ json(conn, res)
+ else
+ _e ->
+ json(conn, "error")
+ end
+ end
+
+ def list_timeline(%{assigns: %{user: user}} = conn, %{"list_id" => id} = params) do
+ with %Pleroma.List{title: title, following: following} <- Pleroma.List.get(id, user) do
+ params =
+ params
+ |> Map.put("type", "Create")
+ |> Map.put("blocking_user", user)
+
+ # we must filter the following list for the user to avoid leaking statuses the user
+ # does not actually have permission to see (for more info, peruse security issue #270).
+ following_to =
+ following
+ |> Enum.filter(fn x -> x in user.following end)
+
+ activities =
+ ActivityPub.fetch_activities_bounded(following_to, following, params)
+ |> Enum.reverse()
+
+ conn
+ |> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity})
+ else
+ _e ->
+ conn
+ |> put_status(403)
+ |> json(%{error: "Error."})
+ end
+ end
+
+ def index(%{assigns: %{user: user}} = conn, _params) do
+ token =
+ conn
+ |> get_session(:oauth_token)
+
+ if user && token do
+ mastodon_emoji = mastodonized_emoji()
+
+ limit = Pleroma.Config.get([:instance, :limit])
+
+ accounts =
+ Map.put(%{}, user.id, AccountView.render("account.json", %{user: user, for: user}))
+
+ initial_state =
+ %{
+ meta: %{
+ streaming_api_base_url:
+ String.replace(Pleroma.Web.Endpoint.static_url(), "http", "ws"),
+ access_token: token,
+ locale: "en",
+ domain: Pleroma.Web.Endpoint.host(),
+ admin: "1",
+ me: "#{user.id}",
+ unfollow_modal: false,
+ boost_modal: false,
+ delete_modal: true,
+ auto_play_gif: false,
+ display_sensitive_media: false,
+ reduce_motion: false,
+ max_toot_chars: limit
+ },
+ rights: %{
+ delete_others_notice: !!user.info.is_moderator
+ },
+ compose: %{
+ me: "#{user.id}",
+ default_privacy: user.info.default_scope,
+ default_sensitive: false
+ },
+ media_attachments: %{
+ accept_content_types: [
+ ".jpg",
+ ".jpeg",
+ ".png",
+ ".gif",
+ ".webm",
+ ".mp4",
+ ".m4v",
+ "image\/jpeg",
+ "image\/png",
+ "image\/gif",
+ "video\/webm",
+ "video\/mp4"
+ ]
+ },
+ settings:
+ Map.get(user.info, :settings) ||
+ %{
+ onboarded: true,
+ home: %{
+ shows: %{
+ reblog: true,
+ reply: true
+ }
+ },
+ notifications: %{
+ alerts: %{
+ follow: true,
+ favourite: true,
+ reblog: true,
+ mention: true
+ },
+ shows: %{
+ follow: true,
+ favourite: true,
+ reblog: true,
+ mention: true
+ },
+ sounds: %{
+ follow: true,
+ favourite: true,
+ reblog: true,
+ mention: true
+ }
+ }
+ },
+ push_subscription: nil,
+ accounts: accounts,
+ custom_emojis: mastodon_emoji,
+ char_limit: limit
+ }
+ |> Jason.encode!()
+
+ conn
+ |> put_layout(false)
+ |> render(MastodonView, "index.html", %{initial_state: initial_state})
+ else
+ conn
+ |> redirect(to: "/web/login")
+ end
+ end
+
+ def put_settings(%{assigns: %{user: user}} = conn, %{"data" => settings} = _params) do
+ with new_info <- Map.put(user.info, "settings", settings),
+ change <- User.info_changeset(user, %{info: new_info}),
+ {:ok, _user} <- User.update_and_set_cache(change) do
+ conn
+ |> json(%{})
+ else
+ e ->
+ conn
+ |> json(%{error: inspect(e)})
+ end
+ end
+
+ def login(conn, %{"code" => code}) do
+ with {:ok, app} <- get_or_make_app(),
+ %Authorization{} = auth <- Repo.get_by(Authorization, token: code, app_id: app.id),
+ {:ok, token} <- Token.exchange_token(app, auth) do
+ conn
+ |> put_session(:oauth_token, token.token)
+ |> redirect(to: "/web/getting-started")
+ end
+ end
+
+ def login(conn, _) do
+ with {:ok, app} <- get_or_make_app() do
+ path =
+ o_auth_path(
+ conn,
+ :authorize,
+ response_type: "code",
+ client_id: app.client_id,
+ redirect_uri: ".",
+ scope: app.scopes
+ )
+
+ conn
+ |> redirect(to: path)
+ end
+ end
+
+ defp get_or_make_app() do
+ with %App{} = app <- Repo.get_by(App, client_name: "Mastodon-Local") do
+ {:ok, app}
+ else
+ _e ->
+ cs =
+ App.register_changeset(%App{}, %{
+ client_name: "Mastodon-Local",
+ redirect_uris: ".",
+ scopes: "read,write,follow"
+ })
+
+ Repo.insert(cs)
+ end
+ end
+
+ def logout(conn, _) do
+ conn
+ |> clear_session
+ |> redirect(to: "/")
+ end
+