aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/mix/tasks/pleroma/emoji.ex28
-rw-r--r--lib/pleroma/conversation/participation.ex13
-rw-r--r--lib/pleroma/marker.ex74
-rw-r--r--lib/pleroma/notification.ex15
-rw-r--r--lib/pleroma/user.ex3
-rw-r--r--lib/pleroma/user/info.ex12
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex4
-rw-r--r--lib/pleroma/web/activity_pub/relay.ex8
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex10
-rw-r--r--lib/pleroma/web/activity_pub/utils.ex10
-rw-r--r--lib/pleroma/web/activity_pub/views/user_view.ex3
-rw-r--r--lib/pleroma/web/masto_fe_controller.ex6
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/marker_controller.ex32
-rw-r--r--lib/pleroma/web/mastodon_api/views/marker_view.ex17
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex9
-rw-r--r--lib/pleroma/web/router.ex10
-rw-r--r--lib/pleroma/web/templates/masto_fe/index.html.eex6
-rw-r--r--lib/pleroma/web/views/masto_fe_view.ex19
18 files changed, 250 insertions, 29 deletions
diff --git a/lib/mix/tasks/pleroma/emoji.ex b/lib/mix/tasks/pleroma/emoji.ex
index 6ef0a635d..35669af27 100644
--- a/lib/mix/tasks/pleroma/emoji.ex
+++ b/lib/mix/tasks/pleroma/emoji.ex
@@ -111,19 +111,21 @@ defmodule Mix.Tasks.Pleroma.Emoji do
file_list: files_to_unzip
)
- IO.puts(IO.ANSI.format(["Writing emoji.txt for ", :bright, pack_name]))
-
- emoji_txt_str =
- Enum.map(
- files,
- fn {shortcode, path} ->
- emojo_path = Path.join("/emoji/#{pack_name}", path)
- "#{shortcode}, #{emojo_path}"
- end
- )
- |> Enum.join("\n")
-
- File.write!(Path.join(pack_path, "emoji.txt"), emoji_txt_str)
+ IO.puts(IO.ANSI.format(["Writing pack.json for ", :bright, pack_name]))
+
+ pack_json = %{
+ pack: %{
+ "license" => pack["license"],
+ "homepage" => pack["homepage"],
+ "description" => pack["description"],
+ "fallback-src" => pack["src"],
+ "fallback-src-sha256" => pack["src_sha256"],
+ "share-files" => true
+ },
+ files: files
+ }
+
+ File.write!(Path.join(pack_path, "pack.json"), Jason.encode!(pack_json, pretty: true))
else
IO.puts(IO.ANSI.format([:bright, :red, "No pack named \"#{pack_name}\" found"]))
end
diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex
index e17f49e58..41918fa78 100644
--- a/lib/pleroma/conversation/participation.ex
+++ b/lib/pleroma/conversation/participation.ex
@@ -69,6 +69,19 @@ defmodule Pleroma.Conversation.Participation do
end
end
+ def mark_all_as_read(user) do
+ {_, participations} =
+ __MODULE__
+ |> where([p], p.user_id == ^user.id)
+ |> where([p], not p.read)
+ |> update([p], set: [read: true])
+ |> select([p], p)
+ |> Repo.update_all([])
+
+ User.set_unread_conversation_count(user)
+ {:ok, participations}
+ end
+
def mark_as_unread(participation) do
participation
|> read_cng(%{read: false})
diff --git a/lib/pleroma/marker.ex b/lib/pleroma/marker.ex
new file mode 100644
index 000000000..7f87c86c3
--- /dev/null
+++ b/lib/pleroma/marker.ex
@@ -0,0 +1,74 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Marker do
+ use Ecto.Schema
+
+ import Ecto.Changeset
+ import Ecto.Query
+
+ alias Ecto.Multi
+ alias Pleroma.Repo
+ alias Pleroma.User
+
+ @timelines ["notifications"]
+
+ schema "markers" do
+ field(:last_read_id, :string, default: "")
+ field(:timeline, :string, default: "")
+ field(:lock_version, :integer, default: 0)
+
+ belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
+ timestamps()
+ end
+
+ def get_markers(user, timelines \\ []) do
+ Repo.all(get_query(user, timelines))
+ end
+
+ def upsert(%User{} = user, attrs) do
+ attrs
+ |> Map.take(@timelines)
+ |> Enum.reduce(Multi.new(), fn {timeline, timeline_attrs}, multi ->
+ marker =
+ user
+ |> get_marker(timeline)
+ |> changeset(timeline_attrs)
+
+ Multi.insert(multi, timeline, marker,
+ returning: true,
+ on_conflict: {:replace, [:last_read_id]},
+ conflict_target: [:user_id, :timeline]
+ )
+ end)
+ |> Repo.transaction()
+ end
+
+ defp get_marker(user, timeline) do
+ case Repo.find_resource(get_query(user, timeline)) do
+ {:ok, marker} -> %__MODULE__{marker | user: user}
+ _ -> %__MODULE__{timeline: timeline, user_id: user.id}
+ end
+ end
+
+ @doc false
+ defp changeset(marker, attrs) do
+ marker
+ |> cast(attrs, [:last_read_id])
+ |> validate_required([:user_id, :timeline, :last_read_id])
+ |> validate_inclusion(:timeline, @timelines)
+ end
+
+ defp by_timeline(query, timeline) do
+ from(m in query, where: m.timeline in ^List.wrap(timeline))
+ end
+
+ defp by_user_id(query, id), do: from(m in query, where: m.user_id == ^id)
+
+ defp get_query(user, timelines) do
+ __MODULE__
+ |> by_user_id(user.id)
+ |> by_timeline(timelines)
+ end
+end
diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex
index d145f8d5b..e5da1492b 100644
--- a/lib/pleroma/notification.ex
+++ b/lib/pleroma/notification.ex
@@ -55,9 +55,19 @@ defmodule Pleroma.Notification do
)
|> preload([n, a, o], activity: {a, object: o})
|> exclude_muted(user, opts)
+ |> exclude_blocked(user)
|> exclude_visibility(opts)
end
+ defp exclude_blocked(query, user) do
+ query
+ |> where([n, a], a.actor not in ^user.info.blocks)
+ |> where(
+ [n, a],
+ fragment("substring(? from '.*://([^/]*)')", a.actor) not in ^user.info.domain_blocks
+ )
+ end
+
defp exclude_muted(query, _, %{with_muted: true}) do
query
end
@@ -65,11 +75,6 @@ defmodule Pleroma.Notification do
defp exclude_muted(query, user, _opts) do
query
|> where([n, a], a.actor not in ^user.info.muted_notifications)
- |> where([n, a], a.actor not in ^user.info.blocks)
- |> where(
- [n, a],
- fragment("substring(? from '.*://([^/]*)')", a.actor) not in ^user.info.domain_blocks
- )
|> join(:left, [n, a], tm in Pleroma.ThreadMute,
on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data)
)
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index ec705b8f6..2bbfaa55b 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -88,6 +88,9 @@ defmodule Pleroma.User do
def superuser?(%User{local: true, info: %User.Info{is_moderator: true}}), do: true
def superuser?(_), do: false
+ def invisible?(%User{info: %User.Info{invisible: true}}), do: true
+ def invisible?(_), do: false
+
def avatar_url(user, options \\ []) do
case user.avatar do
%{"url" => [%{"href" => href} | _]} -> href
diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex
index 2d39abcb3..982fb61c6 100644
--- a/lib/pleroma/user/info.ex
+++ b/lib/pleroma/user/info.ex
@@ -53,6 +53,7 @@ defmodule Pleroma.User.Info do
field(:fields, {:array, :map}, default: nil)
field(:raw_fields, {:array, :map}, default: [])
field(:discoverable, :boolean, default: false)
+ field(:invisible, :boolean, default: false)
field(:notification_settings, :map,
default: %{
@@ -266,7 +267,8 @@ defmodule Pleroma.User.Info do
:follower_count,
:fields,
:following_count,
- :discoverable
+ :discoverable,
+ :invisible
])
|> validate_fields(true)
end
@@ -393,6 +395,14 @@ defmodule Pleroma.User.Info do
|> validate_required([:source_data])
end
+ def set_invisible(info, invisible) do
+ params = %{invisible: invisible}
+
+ info
+ |> cast(params, [:invisible])
+ |> validate_required([:invisible])
+ end
+
def admin_api_update(info, params) do
info
|> cast(params, [
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 94c467b69..9a0a3522a 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -1106,6 +1106,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
locked = data["manuallyApprovesFollowers"] || false
data = Transmogrifier.maybe_fix_user_object(data)
discoverable = data["discoverable"] || false
+ invisible = data["invisible"] || false
user_data = %{
ap_id: data["id"],
@@ -1115,7 +1116,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
banner: banner,
fields: fields,
locked: locked,
- discoverable: discoverable
+ discoverable: discoverable,
+ invisible: invisible
},
avatar: avatar,
name: data["name"],
diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex
index 03fc434a9..de80612f1 100644
--- a/lib/pleroma/web/activity_pub/relay.ex
+++ b/lib/pleroma/web/activity_pub/relay.ex
@@ -10,8 +10,12 @@ defmodule Pleroma.Web.ActivityPub.Relay do
require Logger
def get_actor do
- "#{Pleroma.Web.Endpoint.url()}/relay"
- |> User.get_or_create_service_actor_by_ap_id()
+ actor =
+ "#{Pleroma.Web.Endpoint.url()}/relay"
+ |> User.get_or_create_service_actor_by_ap_id()
+
+ {:ok, actor} = User.update_info(actor, &User.Info.set_invisible(&1, true))
+ actor
end
@spec follow(String.t()) :: {:ok, Activity.t()} | {:error, any()}
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 2c1ce9c55..4a250d131 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -596,13 +596,19 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
data,
_options
)
- when object_type in ["Person", "Application", "Service", "Organization"] do
+ when object_type in [
+ "Person",
+ "Application",
+ "Service",
+ "Organization"
+ ] do
with %User{ap_id: ^actor_id} = actor <- User.get_cached_by_ap_id(object["id"]) do
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)
banner = new_user_data[:info][:banner]
locked = new_user_data[:info][:locked] || false
attachment = get_in(new_user_data, [:info, :source_data, "attachment"]) || []
+ invisible = new_user_data[:info][:invisible] || false
fields =
attachment
@@ -612,7 +618,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
update_data =
new_user_data
|> Map.take([:name, :bio, :avatar])
- |> Map.put(:info, %{banner: banner, locked: locked, fields: fields})
+ |> Map.put(:info, %{banner: banner, locked: locked, fields: fields, invisible: invisible})
actor
|> User.upgrade_changeset(update_data, true)
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index 4ef479f96..6b28df92c 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -491,10 +491,14 @@ defmodule Pleroma.Web.ActivityPub.Utils do
%Activity{data: %{"actor" => actor}},
object
) do
- announcements = take_announcements(object)
+ unless actor |> User.get_cached_by_ap_id() |> User.invisible?() do
+ announcements = take_announcements(object)
- with announcements <- Enum.uniq([actor | announcements]) do
- update_element_in_object("announcement", announcements, object)
+ with announcements <- Enum.uniq([actor | announcements]) do
+ update_element_in_object("announcement", announcements, object)
+ end
+ else
+ {:ok, object}
end
end
diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex
index 9b39d1629..8c5b4460b 100644
--- a/lib/pleroma/web/activity_pub/views/user_view.ex
+++ b/lib/pleroma/web/activity_pub/views/user_view.ex
@@ -55,7 +55,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do
"owner" => user.ap_id,
"publicKeyPem" => public_key
},
- "endpoints" => endpoints
+ "endpoints" => endpoints,
+ "invisible" => User.invisible?(user)
}
|> Map.merge(Utils.make_json_ld_header())
end
diff --git a/lib/pleroma/web/masto_fe_controller.ex b/lib/pleroma/web/masto_fe_controller.ex
index 87860f1d5..93b38e8f4 100644
--- a/lib/pleroma/web/masto_fe_controller.ex
+++ b/lib/pleroma/web/masto_fe_controller.ex
@@ -34,6 +34,12 @@ defmodule Pleroma.Web.MastoFEController do
end
end
+ @doc "GET /web/manifest.json"
+ def manifest(conn, _params) do
+ conn
+ |> render("manifest.json")
+ end
+
@doc "PUT /api/web/settings"
def put_settings(%{assigns: %{user: user}} = conn, %{"data" => settings} = _params) do
with {:ok, _} <- User.update_info(user, &User.Info.mastodon_settings_update(&1, settings)) do
diff --git a/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex b/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex
new file mode 100644
index 000000000..ce025624d
--- /dev/null
+++ b/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex
@@ -0,0 +1,32 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.MarkerController do
+ use Pleroma.Web, :controller
+ alias Pleroma.Plugs.OAuthScopesPlug
+
+ plug(
+ OAuthScopesPlug,
+ %{scopes: ["read:statuses"]}
+ when action == :index
+ )
+
+ plug(OAuthScopesPlug, %{scopes: ["write:statuses"]} when action == :upsert)
+ plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
+ action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
+
+ # GET /api/v1/markers
+ def index(%{assigns: %{user: user}} = conn, params) do
+ markers = Pleroma.Marker.get_markers(user, params["timeline"])
+ render(conn, "markers.json", %{markers: markers})
+ end
+
+ # POST /api/v1/markers
+ def upsert(%{assigns: %{user: user}} = conn, params) do
+ with {:ok, result} <- Pleroma.Marker.upsert(user, params),
+ markers <- Map.values(result) do
+ render(conn, "markers.json", %{markers: markers})
+ end
+ end
+end
diff --git a/lib/pleroma/web/mastodon_api/views/marker_view.ex b/lib/pleroma/web/mastodon_api/views/marker_view.ex
new file mode 100644
index 000000000..38fbeed5f
--- /dev/null
+++ b/lib/pleroma/web/mastodon_api/views/marker_view.ex
@@ -0,0 +1,17 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.MarkerView do
+ use Pleroma.Web, :view
+
+ def render("markers.json", %{markers: markers}) do
+ Enum.reduce(markers, %{}, fn m, acc ->
+ Map.put_new(acc, m.timeline, %{
+ last_read_id: m.last_read_id,
+ version: m.lock_version,
+ updated_at: NaiveDateTime.to_iso8601(m.updated_at)
+ })
+ end)
+ end
+end
diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
index 9d50a7ca9..fc39abf05 100644
--- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
@@ -79,6 +79,15 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
end
end
+ def read_conversations(%{assigns: %{user: user}} = conn, _params) do
+ with {:ok, participations} <- Participation.mark_all_as_read(user) do
+ conn
+ |> add_link_headers(participations)
+ |> put_view(ConversationView)
+ |> render("participations.json", participations: participations, for: user)
+ end
+ end
+
def read_notification(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
with {:ok, notification} <- Notification.read_one(user, notification_id) do
conn
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index d68fb87da..f69c5c2bc 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -266,6 +266,7 @@ defmodule Pleroma.Web.Router do
get("/conversations/:id/statuses", PleromaAPIController, :conversation_statuses)
get("/conversations/:id", PleromaAPIController, :conversation)
+ post("/conversations/read", PleromaAPIController, :read_conversations)
end
scope [] do
@@ -404,6 +405,9 @@ defmodule Pleroma.Web.Router do
get("/push/subscription", SubscriptionController, :get)
put("/push/subscription", SubscriptionController, :update)
delete("/push/subscription", SubscriptionController, :delete)
+
+ get("/markers", MarkerController, :index)
+ post("/markers", MarkerController, :upsert)
end
scope "/api/web", Pleroma.Web do
@@ -592,6 +596,12 @@ defmodule Pleroma.Web.Router do
end
scope "/", Pleroma.Web do
+ pipe_through(:api)
+
+ get("/web/manifest.json", MastoFEController, :manifest)
+ end
+
+ scope "/", Pleroma.Web do
pipe_through(:mastodon_html)
get("/web/login", MastodonAPI.AuthController, :login)
diff --git a/lib/pleroma/web/templates/masto_fe/index.html.eex b/lib/pleroma/web/templates/masto_fe/index.html.eex
index feff36fae..c330960fa 100644
--- a/lib/pleroma/web/templates/masto_fe/index.html.eex
+++ b/lib/pleroma/web/templates/masto_fe/index.html.eex
@@ -4,9 +4,13 @@
<meta charset='utf-8'>
<meta content='width=device-width, initial-scale=1' name='viewport'>
<title>
-<%= Pleroma.Config.get([:instance, :name]) %>
+<%= Config.get([:instance, :name]) %>
</title>
<link rel="icon" type="image/png" href="/favicon.png"/>
+<link rel="manifest" type="applicaton/manifest+json" href="<%= masto_fe_path(Pleroma.Web.Endpoint, :manifest) %>" />
+
+<meta name="theme-color" content="<%= Config.get([:manifest, :theme_color]) %>" />
+
<script crossorigin='anonymous' src="/packs/locales.js"></script>
<script crossorigin='anonymous' src="/packs/locales/glitch/en.js"></script>
diff --git a/lib/pleroma/web/views/masto_fe_view.ex b/lib/pleroma/web/views/masto_fe_view.ex
index 21b086d4c..85b164b59 100644
--- a/lib/pleroma/web/views/masto_fe_view.ex
+++ b/lib/pleroma/web/views/masto_fe_view.ex
@@ -99,4 +99,23 @@ defmodule Pleroma.Web.MastoFEView do
defp present?(nil), do: false
defp present?(false), do: false
defp present?(_), do: true
+
+ def render("manifest.json", _params) do
+ %{
+ name: Config.get([:instance, :name]),
+ description: Config.get([:instance, :description]),
+ icons: Config.get([:manifest, :icons]),
+ theme_color: Config.get([:manifest, :theme_color]),
+ background_color: Config.get([:manifest, :background_color]),
+ display: "standalone",
+ scope: Pleroma.Web.base_url(),
+ start_url: masto_fe_path(Pleroma.Web.Endpoint, :index, ["getting-started"]),
+ categories: [
+ "social"
+ ],
+ serviceworker: %{
+ src: "/sw.js"
+ }
+ }
+ end
end