diff --git a/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex index b144c2ac06..14f0f41302 100644 --- a/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex @@ -126,6 +126,31 @@ defmodule Pleroma.Web.ApiSpec.PleromaAccountOperation do } end + def events_ics_operation do + %Operation{ + tags: ["Retrieve account information"], + summary: "Export events", + description: "Export events posted by given account in .ics format", + operationId: "PleromaAPI.AccountController.events_ics", + parameters: + [ + id_param(), + Operation.parameter( + :exclude_visibilities, + :query, + %Schema{type: :array, items: VisibilityScope}, + "Exclude visibilities" + ) + ] ++ pagination_params(), + responses: %{ + 200 => + Operation.response("Events", "text/calendar; charset=utf-8", %Schema{type: :string}), + 401 => Operation.response("Error", "application/json", ApiError), + 404 => Operation.response("Error", "application/json", ApiError) + } + } + end + defp id_param do Operation.parameter(:id, :path, FlakeID.schema(), "Account ID", example: "9umDrYheeY451cQnEe", diff --git a/lib/pleroma/web/api_spec/operations/pleroma_event_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_event_operation.ex index e47947d7e1..eeca66eccb 100644 --- a/lib/pleroma/web/api_spec/operations/pleroma_event_operation.ex +++ b/lib/pleroma/web/api_spec/operations/pleroma_event_operation.ex @@ -176,7 +176,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaEventOperation do def export_ics_operation do %Operation{ tags: ["Event actions"], - summary: "Export status", + summary: "Export event", description: "Export event to .ics", operationId: "PleromaAPI.EventController.export_ics", security: [%{"oAuth" => ["read:statuses"]}], diff --git a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex index 0b8e0b7ad4..b128414892 100644 --- a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex @@ -44,6 +44,12 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do %{scopes: ["read:favourites"], fallback: :proceed_unauthenticated} when action == :favourites ) + plug( + OAuthScopesPlug, + %{scopes: ["read:statuses"], fallback: :proceed_unauthenticated} + when action == :events_ics + ) + plug( OAuthScopesPlug, %{scopes: ["read:accounts"]} when action == :birthdays @@ -53,7 +59,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do plug( :assign_account_by_id - when action in [:favourites, :subscribe, :unsubscribe] + when action in [:favourites, :subscribe, :unsubscribe, :events_ics] ) defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaAccountOperation @@ -133,4 +139,26 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do as: :user ) end + + def events_ics(%{assigns: %{user: reading_user, account: user}} = conn, params) do + with :visible <- User.visible_for(user, reading_user) do + params = + params + |> Map.delete(:tagged) + |> Map.put(:tag, params[:tagged]) + |> Map.put(:only_events, true) + + activities = ActivityPub.fetch_user_activities(user, reading_user, params) + + conn + |> put_view(Pleroma.Web.PleromaAPI.EventView) + |> render("index.ics", activities: activities) + else + :restrict_unauthenticated -> + render_error(conn, :unauthorized, "This API requires an authenticated user") + + _ -> + render_error(conn, :not_found, "Can't find user") + end + end end diff --git a/lib/pleroma/web/pleroma_api/controllers/event_controller.ex b/lib/pleroma/web/pleroma_api/controllers/event_controller.ex index e108975159..449d4226e5 100644 --- a/lib/pleroma/web/pleroma_api/controllers/event_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/event_controller.ex @@ -65,8 +65,8 @@ defmodule Pleroma.Web.PleromaAPI.EventController do plug( OAuthScopesPlug, - %{fallback: :proceed_unauthenticated, scopes: ["read:statuses"]} - when action in [:export_ics] + %{scopes: ["read:statuses"], fallback: :proceed_unauthenticated} + when action == :export_ics ) @rate_limited_event_actions ~w(create update join leave)a diff --git a/lib/pleroma/web/pleroma_api/views/event_view.ex b/lib/pleroma/web/pleroma_api/views/event_view.ex index 079e5bee06..9eb7a90d94 100644 --- a/lib/pleroma/web/pleroma_api/views/event_view.ex +++ b/lib/pleroma/web/pleroma_api/views/event_view.ex @@ -33,10 +33,18 @@ defmodule Pleroma.Web.PleromaAPI.EventView do } end - def render("show.ics", %{activity: %Activity{actor: actor_ap_id} = activity}) do + def render("index.json", %{activities: activities}) do + %ICalendar{events: [activities |> Enum.map(&activity_to_ics/1)]} + end + + def render("show.ics", %{activity: %Activity{} = activity}) do + %ICalendar{events: [activity_to_ics(activity)]} + end + + defp activity_to_ics(%Activity{actor: actor_ap_id} = activity) do with %Object{} = object <- Object.normalize(activity, fetch: false), %User{} = user <- User.get_cached_by_ap_id(actor_ap_id) do - event = %ICalendar.Event{ + %ICalendar.Event{ summary: object.data["name"], dtstart: object.data["startTime"] |> get_date, dtend: object.data["endTime"] |> get_date, @@ -47,8 +55,6 @@ defmodule Pleroma.Web.PleromaAPI.EventView do location: get_location(object), organizer: Pleroma.HTML.strip_tags(user.name || user.nickname) } - - %ICalendar{events: [event]} end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 07605a7958..4438f96aec 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -645,6 +645,8 @@ defmodule Pleroma.Web.Router do get("/events/:id/ics", EventController, :export_ics) get("/search/location", SearchController, :location) + + get("/accounts/:id/events_ics", AccountController, :events_ics) end scope [] do