From 7c4b415929cfef17c409eab095b8e1eb956607cc Mon Sep 17 00:00:00 2001 From: sfr Date: Wed, 7 Dec 2022 11:20:53 +0000 Subject: [PATCH] static-fe overhaul (#236) makes static-fe look more like pleroma-fe, with the stylesheets matching pleroma-dark and pleroma-light based on `prefers-color-scheme`. - [x] navbar - [x] about sidebar - [x] background image - [x] statuses - [x] "reply to" or "edited" tags - [x] accounts - [x] show more / show less - [x] posts / with replies / media / followers / following - [x] followers/following would require user card snippets - [x] admin/bot indicators - [x] attachments - [x] nsfw attachments - [x] fontawesome icons - [x] clean up and sort css - [x] add pleroma-light - [x] replace hardcoded strings also i forgot - [x] repeated headers how it looks + sneak peek at statuses: ![](https://akkoma.dev/attachments/c0d3a025-6987-4630-8eb9-5f4db6858359) Co-authored-by: Sol Fisher Romanoff Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/236 Co-authored-by: sfr Co-committed-by: sfr --- .gitattributes | 5 +- CHANGELOG.md | 1 + lib/pleroma/web/router.ex | 14 +- .../web/static_fe/static_fe_controller.ex | 74 +++++++- lib/pleroma/web/static_fe/static_fe_view.ex | 26 ++- .../web/templates/layout/static_fe.html.eex | 31 ++- .../static_fe/static_fe/_attachment.html.eex | 23 ++- .../static_fe/static_fe/_notice.html.eex | 144 ++++++++++---- .../static_fe/static_fe/_user_card.html.eex | 28 ++- .../static_fe/static_fe/conversation.html.eex | 17 +- .../static_fe/static_fe/error.html.eex | 15 +- .../static_fe/static_fe/profile.html.eex | 177 +++++++++++++++--- lib/pleroma/web/views/layout_view.ex | 7 + priv/static/static-fe/static-fe.css | Bin 2735 -> 12696 bytes priv/static/static-fe/svg/globe-solid.svg | 1 + priv/static/static-fe/svg/lock-open-solid.svg | 1 + priv/static/static-fe/svg/lock-solid.svg | 1 + priv/static/static-fe/svg/reply-solid.svg | 1 + priv/static/static-fe/svg/retweet-solid.svg | 1 + priv/static/static-fe/svg/star-regular.svg | 1 + .../static_fe/static_fe_controller_test.exs | 83 ++++++-- 21 files changed, 525 insertions(+), 126 deletions(-) create mode 100644 priv/static/static-fe/svg/globe-solid.svg create mode 100644 priv/static/static-fe/svg/lock-open-solid.svg create mode 100644 priv/static/static-fe/svg/lock-solid.svg create mode 100644 priv/static/static-fe/svg/reply-solid.svg create mode 100644 priv/static/static-fe/svg/retweet-solid.svg create mode 100644 priv/static/static-fe/svg/star-regular.svg diff --git a/.gitattributes b/.gitattributes index eb0c94757..7273afe43 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,10 +1,11 @@ *.ex diff=elixir *.exs diff=elixir -priv/static/instance/static.css diff=css - # Most of js/css files included in the repo are minified bundles, # and we don't want to search/diff those as text files. *.js binary *.js.map binary *.css binary + +priv/static/instance/static.css diff=css +priv/static/static-fe/static-fe.css diff=css diff --git a/CHANGELOG.md b/CHANGELOG.md index e0946b76d..07ed6653a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - NormalizeMarkup MRF is now on by default - Follow/Block/Mute imports now spin off into *n* tasks to avoid the oban timeout - Transient activities recieved from remote servers are no longer persisted in the database +- Overhauled static-fe view for logged-out users ## Upgrade Notes - If you have an old instance, you will probably want to run `mix pleroma.database prune_task` in the foreground to catch it up with the history of your instance. diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index a34dd26ce..22a35e8e2 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -728,6 +728,12 @@ defmodule Pleroma.Web.Router do get("/users/:nickname/feed", Feed.UserController, :feed, as: :user_feed) end + scope "/", Pleroma.Web.StaticFE do + # Profile pages for static-fe + get("/users/:nickname/with_replies", StaticFEController, :show) + get("/users/:nickname/media", StaticFEController, :show) + end + scope "/", Pleroma.Web do pipe_through(:accepts_html) get("/notice/:id/embed_player", OStatus.OStatusController, :notice_player) @@ -771,10 +777,16 @@ defmodule Pleroma.Web.Router do post("/users/:nickname/outbox", ActivityPubController, :update_outbox) post("/api/ap/upload_media", ActivityPubController, :upload_media) + get("/users/:nickname/collections/featured", ActivityPubController, :pinned) + end + + scope "/", Pleroma.Web.ActivityPub do + # Note: html format is supported only if static FE is enabled + pipe_through([:accepts_html_json, :static_fe, :activitypub_client]) + # The following two are S2S as well, see `ActivityPub.fetch_follow_information_for_user/1`: get("/users/:nickname/followers", ActivityPubController, :followers) get("/users/:nickname/following", ActivityPubController, :following) - get("/users/:nickname/collections/featured", ActivityPubController, :pinned) end scope "/", Pleroma.Web.ActivityPub do diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 827c0a384..6f73b575e 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -45,7 +45,7 @@ def show(%{assigns: %{notice_id: notice_id}} = conn, _params) do end end - def show(%{assigns: %{username_or_id: username_or_id}} = conn, params) do + def show(%{assigns: %{username_or_id: username_or_id, tab: tab}} = conn, params) do with {_, %User{local: true} = user} <- {:fetch_user, User.get_cached_by_nickname_or_id(username_or_id)}, {_, :visible} <- {:visibility, User.visible_for(user, _reading_user = nil)} do @@ -55,11 +55,36 @@ def show(%{assigns: %{username_or_id: username_or_id}} = conn, params) do params |> Map.take(@page_keys) |> Map.new(fn {k, v} -> {String.to_existing_atom(k), v} end) + |> Map.put(:limit, 20) + + params = + case tab do + "posts" -> + Map.put(params, :exclude_replies, true) + + "media" -> + Map.put(params, :only_media, true) + + _ -> + params + end timeline = - user - |> ActivityPub.fetch_user_activities(_reading_user = nil, params) - |> Enum.map(&represent/1) + case tab do + tab when tab in ["posts", "with_replies", "media"] -> + user + |> ActivityPub.fetch_user_activities(_reading_user = nil, params) + |> Enum.map(&represent/1) + + "following" when not user.hide_follows -> + User.get_friends(user) + + "followers" when not user.hide_followers -> + User.get_followers(user) + + _ -> + [] + end prev_page_id = (params["min_id"] || params["max_id"]) && @@ -75,6 +100,11 @@ def show(%{assigns: %{username_or_id: username_or_id}} = conn, params) do meta: meta }) else + {_, %User{} = user} -> + conn + |> put_status(:found) + |> redirect(external: user.uri || user.ap_id) + _ -> not_found(conn, "User not found.") end @@ -150,6 +180,23 @@ defp represent(%Activity{object: %Object{data: data}} = activity, selected) do nil end + reply_to_user = + if data["inReplyTo"] do + activity + |> Activity.get_in_reply_to_activity() + |> Map.get(:actor) + |> User.get_cached_by_ap_id() + else + nil + end + + total_votes = + if data["oneOf"] do + Enum.sum(for option <- data["oneOf"], do: option["replies"]["totalItems"]) + else + 0 + end + %{ user: User.sanitize_html(user), title: get_title(activity.object), @@ -160,7 +207,13 @@ defp represent(%Activity{object: %Object{data: data}} = activity, selected) do sensitive: data["sensitive"], selected: selected, counts: get_counts(activity), - id: activity.id + id: activity.id, + visibility: Visibility.get_visibility(activity.object), + reply_to: data["inReplyTo"], + reply_to_user: reply_to_user, + edited_at: data["updated"], + poll: data["oneOf"], + total_votes: total_votes } end @@ -177,7 +230,16 @@ defp assign_id(%{path_info: [_nickname, "status", notice_id]} = conn, _opts), do: assign(conn, :notice_id, notice_id) defp assign_id(%{path_info: ["users", user_id]} = conn, _opts), - do: assign(conn, :username_or_id, user_id) + do: + conn + |> assign(:username_or_id, user_id) + |> assign(:tab, "posts") + + defp assign_id(%{path_info: ["users", user_id, tab]} = conn, _opts), + do: + conn + |> assign(:username_or_id, user_id) + |> assign(:tab, tab) defp assign_id(%{path_info: ["objects", object_id]} = conn, _opts), do: assign(conn, :object_id, object_id) diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex index c04715337..f0c9ddd22 100644 --- a/lib/pleroma/web/static_fe/static_fe_view.ex +++ b/lib/pleroma/web/static_fe/static_fe_view.ex @@ -8,7 +8,6 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do alias Calendar.Strftime alias Pleroma.Emoji.Formatter alias Pleroma.User - alias Pleroma.Web.Endpoint alias Pleroma.Web.Gettext alias Pleroma.Web.MediaProxy alias Pleroma.Web.Metadata.Utils @@ -22,17 +21,38 @@ def fetch_media_type(%{"mediaType" => mediaType}) do Utils.fetch_media_type(@media_types, mediaType) end + def time_ago(date) do + {:ok, date, _} = DateTime.from_iso8601(date) + now = DateTime.utc_now() + + Timex.from_now(date, now) + end + def format_date(date) do {:ok, date, _} = DateTime.from_iso8601(date) Strftime.strftime!(date, "%Y/%m/%d %l:%M:%S %p UTC") end - def instance_name, do: Pleroma.Config.get([:instance, :name], "Pleroma") + def instance_name, do: Pleroma.Config.get([:instance, :name], "Akkoma") def open_content? do Pleroma.Config.get( [:frontend_configurations, :collapse_message_with_subjects], - true + false ) end + + def get_attachment_name(%{"name" => name}), do: name + + def get_attachment_name(_), do: "" + + def poll_percentage(count, total_votes) do + case count do + 0 -> + "0%" + + _ -> + Integer.to_string(trunc(count / total_votes * 100)) <> "%" + end + end end diff --git a/lib/pleroma/web/templates/layout/static_fe.html.eex b/lib/pleroma/web/templates/layout/static_fe.html.eex index e6adb526b..3d55393f0 100644 --- a/lib/pleroma/web/templates/layout/static_fe.html.eex +++ b/lib/pleroma/web/templates/layout/static_fe.html.eex @@ -6,10 +6,39 @@ <%= Pleroma.Config.get([:instance, :name]) %> <%= Phoenix.HTML.raw(assigns[:meta] || "") %> + +
+
- <%= @inner_content %> +
+
+ <%= @inner_content %> +
+
+ + diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex index 4853e7f4b..f5bbe9a07 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex @@ -1,8 +1,15 @@ -<%= case @mediaType do %> -<% "audio" -> %> - -<% "video" -> %> - -<% _ -> %> -<%= @name %> -<% end %> +" title="<%= @name %>"> + <%= if @nsfw do %> +
+
<%= gettext("Hover to show content") %>
+
+ <% end %> + <%= case @mediaType do %> + <% "audio" -> %> + + <% "video" -> %> + + <% _ -> %> + + <% end %> +
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex index df0244795..6585e81b6 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex @@ -1,41 +1,109 @@ -
id="selected" <% end %>> -

- - +

id="selected" <% end %>> +
+ +
+ <%= @user.nickname %> +
-

- <%= render("_user_card.html", %{user: @user}) %> -
- <%= if @title != "" do %> -
open<% end %>> - <%= raw @title %> -
<%= raw @content %>
-
- <% else %> -
<%= raw @content %>
- <% end %> - <%= for %{"name" => name, "url" => [url | _]} <- @attachment do %> - <%= if @sensitive do %> -
- <%= Gettext.gettext("sensitive media") %> -
- <%= render("_attachment.html", %{name: name, url: url["href"], - mediaType: fetch_media_type(url)}) %> -
-
- <% else %> - <%= render("_attachment.html", %{name: name, url: url["href"], - mediaType: fetch_media_type(url)}) %> - <% end %> - <% end %>
- <%= if @selected do %> -
-
<%= Gettext.gettext("replies") %>
<%= @counts.replies %>
-
<%= Gettext.gettext("announces") %>
<%= @counts.announces %>
-
<%= Gettext.gettext("likes") %>
<%= @counts.likes %>
-
- <% end %> +
+
+
+
+

+ <%= raw Formatter.emojify(@user.name, @user.emoji) %> +

+ +
+
+ + + + <%= if @visibility == "public" do %> + + <% else %> + <%= if @visibility == "unlisted" do %> + + <% end %> + <% end %> +
+
+ <%= if @reply_to do %> + + <% end %> + <%= if @edited_at do %> +
+ <%= gettext("Edited %{timeago}", timeago: time_ago(@edited_at)) %> +
+ <% end %> +
+
+ <%= if @title && @title != "" do %> + <%= raw @title %> +
open<% end %>> + <%= gettext("Show content") %> + <% end %> +
+ <%= raw @content %> + <%= if @poll && length(@poll) > 0 do %> +
+ <%= for %{"name" => option, "replies" => %{"totalItems" => count}} <- @poll do %> +
+ <%= poll_percentage(count, @total_votes) %> + <%= raw option %> +
+
+ <% end %> +
+ <% end %> + <%= if length(@attachment) > 0 do %> +
+ <%= for attachment = %{"url" => [url | _]} <- @attachment do %> + <%= render("_attachment.html", %{name: get_attachment_name(attachment), + url: url["href"], mediaType: fetch_media_type(url), nsfw: @sensitive}) %> + <% end %> +
+ <% end %> +
+ <%= if @title && @title != "" do %> +
+ <% end %> +
+ +
+
+ + <%= @counts.replies %> +
+
+ + <%= @counts.announces %> +
+
+ + <%= @counts.likes %> +
+
+
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex index 977b894d3..dc8717ea0 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex @@ -1,11 +1,21 @@ -
- -
- +
+ +
+
+ <%= raw Formatter.emojify(@user.name, @user.emoji) %>
- - <%= raw Formatter.emojify(@user.name, @user.emoji) %> - <%= @user.nickname %> - - + +
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex index 2acd84828..b825c85e7 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex @@ -1,11 +1,8 @@ -
-

<%= link instance_name(), to: "/" %>

-
- -
-
- <%= for activity <- @activities do %> - <%= render("_notice.html", activity) %> - <% end %> +
+
+ <%= gettext("Conversation") %>
-
+ <%= for activity <- @activities do %> + <%= render("_notice.html", activity) %> + <% end %> +
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/error.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/error.html.eex index d98a1eba7..a9dbbf427 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/error.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/error.html.eex @@ -1,7 +1,8 @@ -
-

<%= gettext("Oops") %>

-
- -
-

<%= @message %>

-
+
+
+ <%= gettext("Error") %> +
+
+ <%= @message %> +
+
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex index a14ca305e..3d1cf77e5 100644 --- a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex +++ b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex @@ -1,31 +1,148 @@ -
-

<%= link instance_name(), to: "/" %>

- -

-
- - - -
- <%= raw Formatter.emojify(@user.name, @user.emoji) %> | - <%= link "@#{@user.nickname}@#{Endpoint.host()}", to: (@user.uri || @user.ap_id) %> -

-

<%= raw @user.bio %>

-
- -
-
- <%= for activity <- @timeline do %> - <%= render("_notice.html", Map.put(activity, :selected, false)) %> - <% end %> -

- <%= if @prev_page_id do %> - <%= link "«", to: "?min_id=" <> @prev_page_id %> - <% end %> - <%= if @prev_page_id && @next_page_id, do: " | " %> - <%= if @next_page_id do %> - <%= link "»", to: "?max_id=" <> @next_page_id %> - <% end %> -

+
+
+
+ +
+
+
<%= gettext("Posts") %>
+ <%= @user.note_count %> +
+
+
<%= gettext("Following") %>
+ <%= if @user.hide_follows_count do gettext("Hidden") else @user.following_count end %> +
+
+
<%= gettext("Followers") %>
+ <%= if @user.hide_followers_count do gettext("Hidden") else @user.follower_count end %> +
+
+ <%= raw Formatter.emojify(@user.bio, @user.emoji) %>
-
+ + + <%= if @prev_page_id do %> + <%= link gettext("Show newer"), to: "?min_id=" <> @prev_page_id, class: "load-posts" %> + <% end %> +
+ <%= if @tab in ["posts", "with_replies", "media"] do %> + <%= for activity <- @timeline do %> + <%= if(activity.user.id != @user.id) do %> +
+ + +
+ <% end %> + <%= render("_notice.html", Map.put(activity, :selected, false)) %> + <% end %> + <% else %> + <%= for user <- @timeline do %> + <%= render("_user_card.html", %{user: user}) %> + <% end %> + <% end %> +
+ <%= if @next_page_id do %> + <%= link gettext("Show older"), to: "?max_id=" <> @next_page_id, class: "load-posts" %> + <% end %> +
+ + diff --git a/lib/pleroma/web/views/layout_view.ex b/lib/pleroma/web/views/layout_view.ex index c2da10f04..ac13cf962 100644 --- a/lib/pleroma/web/views/layout_view.ex +++ b/lib/pleroma/web/views/layout_view.ex @@ -4,4 +4,11 @@ defmodule Pleroma.Web.LayoutView do use Pleroma.Web, :view + import Phoenix.HTML + + def render_html(file) do + case :httpc.request(Pleroma.Web.Endpoint.url() <> file) do + {:ok, {{_, 200, _}, _headers, body}} -> body + end + end end diff --git a/priv/static/static-fe/static-fe.css b/priv/static/static-fe/static-fe.css index 89e9f48777926d50450235221dcf8131d72e65d9..657556077f3a06687670005a6e7e389c29dbc746 100644 GIT binary patch literal 12696 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 literal 2735 zcmc&#U2oGc6n*cnu$YhlEg?-?)&=nbV}Ani;Mh)L>e!LvY%7TW&h=+oQb3y~vAt~9 zxnJj=dv2}h9{pG#_^C13wOUP*W<&|4D|AtAOR~Cp@17eaP1fL^i+zPgEXQnQnm7J2 zINW#Ku=k6fi$#yQ3~_s`TP`cKDTW7xC!@Sej~}voPEA*#>v!dASqLf=vBV+KjM90R5v*gdp37A2dK>Bc+kBk;Kt>Ejg&;AD zVGkywj3|u_SFj~gNxwmXz_{wv9n(ji-Vmys`NR4$EqDl$Q$7v??=y*eb~=yDs3DBg zPC0y7p;{=i^Neu8ZFWHJzCuh0K8$?yj|Y3lDP_`IXQ;h>gLaG!i1q3lM~zlJsu^rJ z>bSs~t7#N_)J-izZ{99W%RO-Qm>OwGj#w0Dcj})@PIixO+^$n}{5#ZXRQWIok+}s4 z7ze63QzWJkco^dlJW(oCc-VpvdUdpfS%yGI-&u1R%u%4PYs|>j$8Z9D9~MX|-D7d| zF!JvVgyd-3tSToZ@p20(8gL9rLQ%`2c!1L? zr*|AY6g6LN-PZV3acO_^XABk8;|kw47QekjA)ex=QP1+xc`DX@W-(EgR>AgqtGJ+gStD@4|u3v0xgs z56d>)>8GG^aRbMq_!JtR<8ga?Q{I%%jK_hpk8YUDCSJxTwObUM^7`W++x>X+d2<^S x;n~Ljly*VAb1(WofEhtcR;9m`@y^Hp6a5@v;Nlogu*k6BE!@N&4vcVD@fZKQHGBX7 diff --git a/priv/static/static-fe/svg/globe-solid.svg b/priv/static/static-fe/svg/globe-solid.svg new file mode 100644 index 000000000..06aa71e62 --- /dev/null +++ b/priv/static/static-fe/svg/globe-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/priv/static/static-fe/svg/lock-open-solid.svg b/priv/static/static-fe/svg/lock-open-solid.svg new file mode 100644 index 000000000..a122cc414 --- /dev/null +++ b/priv/static/static-fe/svg/lock-open-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/priv/static/static-fe/svg/lock-solid.svg b/priv/static/static-fe/svg/lock-solid.svg new file mode 100644 index 000000000..3fdea7a51 --- /dev/null +++ b/priv/static/static-fe/svg/lock-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/priv/static/static-fe/svg/reply-solid.svg b/priv/static/static-fe/svg/reply-solid.svg new file mode 100644 index 000000000..a798b7666 --- /dev/null +++ b/priv/static/static-fe/svg/reply-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/priv/static/static-fe/svg/retweet-solid.svg b/priv/static/static-fe/svg/retweet-solid.svg new file mode 100644 index 000000000..260976770 --- /dev/null +++ b/priv/static/static-fe/svg/retweet-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/priv/static/static-fe/svg/star-regular.svg b/priv/static/static-fe/svg/star-regular.svg new file mode 100644 index 000000000..71d15e95d --- /dev/null +++ b/priv/static/static-fe/svg/star-regular.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/pleroma/web/static_fe/static_fe_controller_test.exs b/test/pleroma/web/static_fe/static_fe_controller_test.exs index 5752cffda..25ed6e193 100644 --- a/test/pleroma/web/static_fe/static_fe_controller_test.exs +++ b/test/pleroma/web/static_fe/static_fe_controller_test.exs @@ -6,6 +6,8 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do use Pleroma.Web.ConnCase alias Pleroma.Activity + alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.CommonAPI @@ -42,8 +44,67 @@ test "profile does not include private messages", %{conn: conn, user: user} do html = html_response(conn, 200) - assert html =~ ">public<" - refute html =~ ">private<" + assert html =~ "\npublic\n" + refute html =~ "\nprivate\n" + end + + test "main page does not include replies", %{conn: conn, user: user} do + {:ok, op} = CommonAPI.post(user, %{status: "beep"}) + CommonAPI.post(user, %{status: "boop", in_reply_to_id: op}) + + conn = get(conn, "/users/#{user.nickname}") + + html = html_response(conn, 200) + + assert html =~ "\nbeep\n" + refute html =~ "\nboop\n" + end + + test "media page only includes posts with attachments", %{conn: conn, user: user} do + file = %Plug.Upload{ + content_type: "image/jpeg", + path: Path.absname("test/fixtures/image.jpg"), + filename: "an_image.jpg" + } + + {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id) + + CommonAPI.post(user, %{status: "virgin text post"}) + CommonAPI.post(user, %{status: "chad post with attachment", media_ids: [media_id]}) + + conn = get(conn, "/users/#{user.nickname}/media") + + html = html_response(conn, 200) + + assert html =~ "\nchad post with attachment\n" + refute html =~ "\nvirgin text post\n" + end + + test "show follower list", %{conn: conn, user: user} do + follower = insert(:user) + CommonAPI.follow(follower, user) + + conn = get(conn, "/users/#{user.nickname}/followers") + + html = html_response(conn, 200) + + assert html =~ "user-card" + end + + test "don't show followers if hidden", %{conn: conn, user: user} do + follower = insert(:user) + CommonAPI.follow(follower, user) + + {:ok, user} = + user + |> User.update_changeset(%{hide_followers: true}) + |> User.update_and_set_cache() + + conn = get(conn, "/users/#{user.nickname}/followers") + + html = html_response(conn, 200) + + refute html =~ "user-card" end test "pagination", %{conn: conn, user: user} do @@ -53,10 +114,10 @@ test "pagination", %{conn: conn, user: user} do html = html_response(conn, 200) - assert html =~ ">test30<" - assert html =~ ">test11<" - refute html =~ ">test10<" - refute html =~ ">test1<" + assert html =~ "\ntest30\n" + assert html =~ "\ntest11\n" + refute html =~ "\ntest10\n" + refute html =~ "\ntest1\n" end test "pagination, page 2", %{conn: conn, user: user} do @@ -67,10 +128,10 @@ test "pagination, page 2", %{conn: conn, user: user} do html = html_response(conn, 200) - assert html =~ ">test1<" - assert html =~ ">test10<" - refute html =~ ">test20<" - refute html =~ ">test29<" + assert html =~ "\ntest1\n" + assert html =~ "\ntest10\n" + refute html =~ "\ntest20\n" + refute html =~ "\ntest29\n" end test "does not require authentication on non-federating instances", %{ @@ -104,7 +165,7 @@ test "single notice page", %{conn: conn, user: user} do conn = get(conn, "/notice/#{activity.id}") html = html_response(conn, 200) - assert html =~ "
" + assert html =~ "
" assert html =~ user.nickname assert html =~ "testing a thing!" end