X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fweb%2Fmastodon_api%2Fmastodon_api_controller.ex;h=c713c561bca81bab208d62feacfd555d27403714;hb=3ca853fb6165b82c39f23e24783e813015db48d5;hp=9e4d13b3acf975312335a8b73b36c1096796ad45;hpb=f0d41a3abf3e584c90c96644f73d533ea0680237;p=akkoma diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 9e4d13b3a..c713c561b 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.TwitterAPI.TwitterAPI alias Pleroma.Web.CommonAPI + import Ecto.Query import Logger def create_app(conn, params) do @@ -27,6 +28,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do json(conn, account) end + def user(conn, %{"id" => id}) do + with %User{} = user <- Repo.get(User, id) do + account = AccountView.render("account.json", %{user: user}) + json(conn, account) + else + _e -> conn + |> put_status(404) + |> json(%{error: "Can't find user"}) + end + end + def masto_instance(conn, _params) do response = %{ uri: Web.base_url, @@ -38,10 +50,28 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do json(conn, response) end + defp add_link_headers(conn, method, activities) do + last = List.last(activities) + first = List.first(activities) + if last do + min = last.id + max = first.id + next_url = mastodon_api_url(Pleroma.Web.Endpoint, method, max_id: min) + prev_url = mastodon_api_url(Pleroma.Web.Endpoint, method, since_id: max) + conn + |> put_resp_header("link", "<#{next_url}>; rel=\"next\", <#{prev_url}>; rel=\"prev\"") + else + conn + end + end + def home_timeline(%{assigns: %{user: user}} = conn, params) do activities = ActivityPub.fetch_activities([user.ap_id | user.following], Map.put(params, "type", "Create")) |> Enum.reverse - render conn, StatusView, "index.json", %{activities: activities, for: user, as: :activity} + + conn + |> add_link_headers(:home_timeline, activities) + |> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity}) end def public_timeline(%{assigns: %{user: user}} = conn, params) do @@ -52,9 +82,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do activities = ActivityPub.fetch_public_activities(params) |> Enum.reverse - render conn, StatusView, "index.json", %{activities: activities, for: user, as: :activity} + conn + |> add_link_headers(:public_timeline, activities) + |> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity}) end + # TODO: Link headers def user_statuses(%{assigns: %{user: user}} = conn, params) do with %User{ap_id: ap_id} <- Repo.get(User, params["id"]) do params = params @@ -136,6 +169,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do notifications = Notification.for_user(user, params) result = Enum.map(notifications, fn (%{id: id, activity: activity, inserted_at: created_at}) -> actor = User.get_cached_by_ap_id(activity.data["actor"]) + created_at = NaiveDateTime.to_iso8601(created_at) + |> String.replace(~r/(\.\d+)?$/, ".000Z", global: false) case activity.data["type"] do "Create" -> %{id: id, type: "mention", created_at: created_at, account: AccountView.render("account.json", %{user: actor}), status: StatusView.render("status.json", %{activity: activity})} @@ -152,7 +187,104 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end) |> Enum.filter(&(&1)) - json(conn, result) + conn + |> add_link_headers(:notifications, notifications) + |> json(result) + end + + def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do + id = List.wrap(id) + q = from u in User, + where: u.id in ^id + targets = Repo.all(q) + render conn, AccountView, "relationships.json", %{user: user, targets: targets} + end + + def upload(%{assigns: %{user: user}} = conn, %{"file" => file}) do + with {:ok, object} <- ActivityPub.upload(file) do + data = object.data + |> Map.put("id", object.id) + + render conn, StatusView, "attachment.json", %{attachment: data} + end + end + + def favourited_by(conn, %{"id" => id}) do + with %Activity{data: %{"object" => %{"likes" => likes} = data}} <- Repo.get(Activity, id) do + q = from u in User, + where: u.ap_id in ^likes + users = Repo.all(q) + render conn, AccountView, "accounts.json", %{users: users, as: :user} + else + _ -> json(conn, []) + end + end + + def reblogged_by(conn, %{"id" => id}) do + with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Repo.get(Activity, id) do + q = from u in User, + where: u.ap_id in ^announces + users = Repo.all(q) + render conn, AccountView, "accounts.json", %{users: users, as: :user} + else + _ -> json(conn, []) + end + end + + # TODO: Link headers + def hashtag_timeline(%{assigns: %{user: user}} = conn, params) do + params = params + |> Map.put("type", "Create") + |> Map.put("local_only", !!params["local"]) + + activities = ActivityPub.fetch_public_activities(params) + |> Enum.reverse + + conn + |> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity}) + end + + # TODO: Pagination + def followers(conn, %{"id" => id}) do + with %User{} = user <- Repo.get(User, id), + {:ok, followers} <- User.get_followers(user) do + render conn, AccountView, "accounts.json", %{users: followers, as: :user} + end + end + + def following(conn, %{"id" => id}) do + with %User{} = user <- Repo.get(User, id), + {:ok, followers} <- User.get_friends(user) do + render conn, AccountView, "accounts.json", %{users: followers, as: :user} + end + end + + def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do + with %User{} = followed <- Repo.get(User, id), + {:ok, follower} <- User.follow(follower, followed), + {:ok, activity} <- ActivityPub.follow(follower, followed) do + render conn, AccountView, "relationship.json", %{user: follower, target: followed} + end + end + + # TODO: Clean up and unify + def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do + with %User{} = followed <- Repo.get(User, id), + { :ok, follower, follow_activity } <- User.unfollow(follower, followed), + { :ok, _activity } <- ActivityPub.insert(%{ + "type" => "Undo", + "actor" => follower.ap_id, + "object" => follow_activity.data["id"] # get latest Follow for these users + }) do + render conn, AccountView, "relationship.json", %{user: follower, target: followed} + end + end + + def relationship_noop(%{assigns: %{user: user}} = conn, %{"id" => id}) do + Logger.debug("Unimplemented, returning unmodified relationship") + with %User{} = target <- Repo.get(User, id) do + render conn, AccountView, "relationship.json", %{user: user, target: target} + end end def empty_array(conn, _) do