Merge branch 'small-jsonld-refactor' into 'develop'
authorlambda <pleromagit@rogerbraun.net>
Thu, 8 Nov 2018 16:23:58 +0000 (16:23 +0000)
committerlambda <pleromagit@rogerbraun.net>
Thu, 8 Nov 2018 16:23:58 +0000 (16:23 +0000)
Small jsonld refactor

See merge request pleroma/pleroma!433

24 files changed:
installation/pleroma.nginx
lib/pleroma/config.ex
lib/pleroma/formatter.ex
lib/pleroma/gopher/server.ex
lib/pleroma/html.ex
lib/pleroma/notification.ex
lib/pleroma/upload.ex
lib/pleroma/uploaders/swift/keystone.ex
lib/pleroma/uploaders/swift/swift.ex
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/activity_pub/mrf/normalize_markup.ex
lib/pleroma/web/activity_pub/mrf/reject_non_public.ex
lib/pleroma/web/activity_pub/mrf/simple_policy.ex
lib/pleroma/web/activity_pub/transmogrifier.ex
lib/pleroma/web/common_api/common_api.ex
lib/pleroma/web/federator/federator.ex
lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
lib/pleroma/web/router.ex
lib/pleroma/web/twitter_api/controllers/util_controller.ex
lib/pleroma/web/twitter_api/twitter_api.ex
lib/pleroma/web/twitter_api/twitter_api_controller.ex
test/config_test.exs
test/notification_test.exs
test/web/twitter_api/twitter_api_controller_test.exs

index 6dc2c97609f5b68a000acc14e97df70c0da23b84..65a3cdb4cecce21f00caf974646b775b825d04f8 100644 (file)
@@ -62,7 +62,6 @@ server {
     location / {
         # if you do not want remote frontends to be able to access your Pleroma backend
         # server, remove these lines.
-        add_header 'Access-Control-Allow-Origin' '*' always;
         add_header 'Access-Control-Allow-Methods' 'POST, PUT, DELETE, GET, PATCH, OPTIONS' always;
         add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Idempotency-Key' always;
         add_header 'Access-Control-Expose-Headers' 'Link, X-RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining, X-Request-Id' always;
index fc5338591d684b9da364644d99a33cfc84dc0155..15f771b6e29c2803a807d3138e36740e949088f2 100644 (file)
@@ -1,13 +1,29 @@
 defmodule Pleroma.Config do
-  def get([key]), do: get(key)
+  defmodule Error do
+    defexception [:message]
+  end
+
+  def get(key), do: get(key, nil)
+
+  def get([key], default), do: get(key, default)
 
-  def get([parent_key | keys]) do
+  def get([parent_key | keys], default) do
     Application.get_env(:pleroma, parent_key)
-    |> get_in(keys)
+    |> get_in(keys) || default
   end
 
-  def get(key) do
-    Application.get_env(:pleroma, key)
+  def get(key, default) do
+    Application.get_env(:pleroma, key, default)
+  end
+
+  def get!(key) do
+    value = get(key, nil)
+
+    if value == nil do
+      raise(Error, message: "Missing configuration value: #{inspect(key)}")
+    else
+      value
+    end
   end
 
   def put([key], value), do: put(key, value)
index dd971df9b98d3b02694565633794f94f507723a6..26bb17377094340d69a0280086cc146ee4e85f83 100644 (file)
@@ -29,8 +29,6 @@ defmodule Pleroma.Formatter do
     |> Enum.filter(fn {_match, user} -> user end)
   end
 
-  @instance Application.get_env(:pleroma, :instance)
-
   def emojify(text) do
     emojify(text, Emoji.get_all())
   end
index d34037f4f69f7c05f47a098d06b057e248f7e65e..e6361a82ca78a5161851e9449d85a9466d030341 100644 (file)
@@ -1,16 +1,16 @@
 defmodule Pleroma.Gopher.Server do
   use GenServer
   require Logger
-  @gopher Application.get_env(:pleroma, :gopher)
 
   def start_link() do
-    ip = Keyword.get(@gopher, :ip, {0, 0, 0, 0})
-    port = Keyword.get(@gopher, :port, 1234)
+    config = Pleroma.Config.get(:gopher, [])
+    ip = Keyword.get(config, :ip, {0, 0, 0, 0})
+    port = Keyword.get(config, :port, 1234)
     GenServer.start_link(__MODULE__, [ip, port], [])
   end
 
   def init([ip, port]) do
-    if Keyword.get(@gopher, :enabled, false) do
+    if Pleroma.Config.get([:gopher, :enabled], false) do
       Logger.info("Starting gopher server on #{port}")
 
       :ranch.start_listener(
@@ -37,9 +37,6 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do
   alias Pleroma.Repo
   alias Pleroma.HTML
 
-  @instance Application.get_env(:pleroma, :instance)
-  @gopher Application.get_env(:pleroma, :gopher)
-
   def start_link(ref, socket, transport, opts) do
     pid = spawn_link(__MODULE__, :init, [ref, socket, transport, opts])
     {:ok, pid}
@@ -62,7 +59,7 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do
 
   def link(name, selector, type \\ 1) do
     address = Pleroma.Web.Endpoint.host()
-    port = Keyword.get(@gopher, :port, 1234)
+    port = Pleroma.Config.get([:gopher, :port], 1234)
     "#{type}#{name}\t#{selector}\t#{address}\t#{port}\r\n"
   end
 
@@ -85,7 +82,7 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do
   end
 
   def response("") do
-    info("Welcome to #{Keyword.get(@instance, :name, "Pleroma")}!") <>
+    info("Welcome to #{Pleroma.Config.get([:instance, :name], "Pleroma")}!") <>
       link("Public Timeline", "/main/public") <>
       link("Federated Timeline", "/main/all") <> ".\r\n"
   end
index 00b26963da070e4685be1ce6dbb128c7e7ff621e..1b920d7fd5cf95781bbaa08d6d5f9107ad810658 100644 (file)
@@ -1,14 +1,12 @@
 defmodule Pleroma.HTML do
   alias HtmlSanitizeEx.Scrubber
 
-  @markup Application.get_env(:pleroma, :markup)
-
   defp get_scrubbers(scrubber) when is_atom(scrubber), do: [scrubber]
   defp get_scrubbers(scrubbers) when is_list(scrubbers), do: scrubbers
   defp get_scrubbers(_), do: [Pleroma.HTML.Scrubber.Default]
 
   def get_scrubbers() do
-    Keyword.get(@markup, :scrub_policy)
+    Pleroma.Config.get([:markup, :scrub_policy])
     |> get_scrubbers
   end
 
index e0dcd98236eb8984a4b2b36ae13b15b65d4d97b4..75d7461e41dcce52120560cd4112a6af135b2e47 100644 (file)
@@ -42,6 +42,20 @@ defmodule Pleroma.Notification do
     Repo.all(query)
   end
 
+  def set_read_up_to(%{id: user_id} = _user, id) do
+    query =
+      from(
+        n in Notification,
+        where: n.user_id == ^user_id,
+        where: n.id <= ^id,
+        update: [
+          set: [seen: true]
+        ]
+      )
+
+    Repo.update_all(query, [])
+  end
+
   def get(%{id: user_id} = _user, id) do
     query =
       from(
index 2293ff54e4fab1d3604771980207fab48c3925d9..89aa779f93e153f700953f6374cf3b4903e642f0 100644 (file)
@@ -1,9 +1,6 @@
 defmodule Pleroma.Upload do
   alias Ecto.UUID
 
-  @storage_backend Application.get_env(:pleroma, Pleroma.Upload)
-                   |> Keyword.fetch!(:uploader)
-
   def check_file_size(path, nil), do: true
 
   def check_file_size(path, size_limit) do
@@ -21,8 +18,7 @@ defmodule Pleroma.Upload do
          true <- check_file_size(file.path, size_limit) do
       strip_exif_data(content_type, file.path)
 
-      {:ok, url_path} =
-        @storage_backend.put_file(name, uuid, file.path, content_type, should_dedupe)
+      {:ok, url_path} = uploader().put_file(name, uuid, file.path, content_type, should_dedupe)
 
       %{
         "type" => "Document",
@@ -57,8 +53,7 @@ defmodule Pleroma.Upload do
           content_type
         )
 
-      {:ok, url_path} =
-        @storage_backend.put_file(name, uuid, tmp_path, content_type, should_dedupe)
+      {:ok, url_path} = uploader().put_file(name, uuid, tmp_path, content_type, should_dedupe)
 
       %{
         "type" => "Image",
@@ -182,4 +177,8 @@ defmodule Pleroma.Upload do
       _e -> "application/octet-stream"
     end
   end
+
+  defp uploader() do
+    Pleroma.Config.get!([Pleroma.Upload, :uploader])
+  end
 end
index a7921431943979195a1a1619094fc3853479394d..e578b3c619e850a20d1bfa68f281c841fb1778fa 100644 (file)
@@ -1,11 +1,9 @@
 defmodule Pleroma.Uploaders.Swift.Keystone do
   use HTTPoison.Base
 
-  @settings Application.get_env(:pleroma, Pleroma.Uploaders.Swift)
-
   def process_url(url) do
     Enum.join(
-      [Keyword.fetch!(@settings, :auth_url), url],
+      [Pleroma.Config.get!([Pleroma.Uploaders.Swift, :auth_url]), url],
       "/"
     )
   end
@@ -16,9 +14,10 @@ defmodule Pleroma.Uploaders.Swift.Keystone do
   end
 
   def get_token() do
-    username = Keyword.fetch!(@settings, :username)
-    password = Keyword.fetch!(@settings, :password)
-    tenant_id = Keyword.fetch!(@settings, :tenant_id)
+    settings = Pleroma.Config.get(Pleroma.Uploaders.Swift)
+    username = Keyword.fetch!(settings, :username)
+    password = Keyword.fetch!(settings, :password)
+    tenant_id = Keyword.fetch!(settings, :tenant_id)
 
     case post(
            "/tokens",
index 819dfebda1f77442dae16977266f3c541484c17b..fa08ca9661168e9b7abbb8cbb85cadbda100e279 100644 (file)
@@ -1,17 +1,15 @@
 defmodule Pleroma.Uploaders.Swift.Client do
   use HTTPoison.Base
 
-  @settings Application.get_env(:pleroma, Pleroma.Uploaders.Swift)
-
   def process_url(url) do
     Enum.join(
-      [Keyword.fetch!(@settings, :storage_url), url],
+      [Pleroma.Config.get!([Pleroma.Uploaders.Swift, :storage_url]), url],
       "/"
     )
   end
 
   def upload_file(filename, body, content_type) do
-    object_url = Keyword.fetch!(@settings, :object_url)
+    object_url = Pleroma.Config.get!([Pleroma.Uploaders.Swift, :object_url])
     token = Pleroma.Uploaders.Swift.Keystone.get_token()
 
     case put("#{filename}", body, "X-Auth-Token": token, "Content-Type": content_type) do
index 32c14995f3312ba4630eb777801fa210596710ad..c6733e48714060539236be17f06f6885bcbb77c1 100644 (file)
@@ -10,8 +10,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
 
   @httpoison Application.get_env(:pleroma, :httpoison)
 
-  @instance Application.get_env(:pleroma, :instance)
-
   # For Announce activities, we filter the recipients based on following status for any actors
   # that match actual users.  See issue #164 for more information about why this is necessary.
   defp get_recipients(%{"type" => "Announce"} = data) do
@@ -659,14 +657,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     end
   end
 
-  @quarantined_instances Keyword.get(@instance, :quarantined_instances, [])
-
   def should_federate?(inbox, public) do
     if public do
       true
     else
       inbox_info = URI.parse(inbox)
-      inbox_info.host not in @quarantined_instances
+      !Enum.member?(Pleroma.Config.get([:instance, :quarantined_instances], []), inbox_info.host)
     end
   end
 
index b4f91f3cc66e68e3c7a589d0b407e65a4da0238b..c53cb1ad2ed39fc4f7745ac90f9f8f1704e2c609 100644 (file)
@@ -3,10 +3,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkup do
 
   @behaviour Pleroma.Web.ActivityPub.MRF
 
-  @mrf_normalize_markup Application.get_env(:pleroma, :mrf_normalize_markup)
-
   def filter(%{"type" => activity_type} = object) when activity_type == "Create" do
-    scrub_policy = Keyword.get(@mrf_normalize_markup, :scrub_policy)
+    scrub_policy = Pleroma.Config.get([:mrf_normalize_markup, :scrub_policy])
 
     child = object["object"]
 
index 129d0461775b27aa5a1ca03da690f4e83cd54c59..6272840838dfbf8740aa0bf6f299812b878b14db 100644 (file)
@@ -2,10 +2,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
   alias Pleroma.User
   @behaviour Pleroma.Web.ActivityPub.MRF
 
-  @mrf_rejectnonpublic Application.get_env(:pleroma, :mrf_rejectnonpublic)
-  @allow_followersonly Keyword.get(@mrf_rejectnonpublic, :allow_followersonly)
-  @allow_direct Keyword.get(@mrf_rejectnonpublic, :allow_direct)
-
   @impl true
   def filter(%{"type" => "Create"} = object) do
     user = User.get_cached_by_ap_id(object["actor"])
@@ -20,6 +16,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
         true -> "direct"
       end
 
+    policy = Pleroma.Config.get(:mrf_rejectnonpublic)
+
     case visibility do
       "public" ->
         {:ok, object}
@@ -28,14 +26,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
         {:ok, object}
 
       "followers" ->
-        with true <- @allow_followersonly do
+        with true <- Keyword.get(policy, :allow_followersonly) do
           {:ok, object}
         else
           _e -> {:reject, nil}
         end
 
       "direct" ->
-        with true <- @allow_direct do
+        with true <- Keyword.get(policy, :allow_direct) do
           {:ok, object}
         else
           _e -> {:reject, nil}
index 319721d4810f5a0decbb1573ea87b27d3a4d95b6..86dcf5080532b1054bfba7e00a97d2c4114a9ff7 100644 (file)
@@ -2,60 +2,76 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
   alias Pleroma.User
   @behaviour Pleroma.Web.ActivityPub.MRF
 
-  @mrf_policy Application.get_env(:pleroma, :mrf_simple)
-
-  @accept Keyword.get(@mrf_policy, :accept)
-  defp check_accept(%{host: actor_host} = actor_info, object)
-       when length(@accept) > 0 and not (actor_host in @accept) do
-    {:reject, nil}
+  defp check_accept(%{host: actor_host} = _actor_info, object) do
+    accepts = Pleroma.Config.get([:mrf_simple, :accept])
+
+    cond do
+      accepts == [] -> {:ok, object}
+      actor_host == Pleroma.Config.get([Pleroma.Web.Endpoint, :url, :host]) -> {:ok, object}
+      Enum.member?(accepts, actor_host) -> {:ok, object}
+      true -> {:reject, nil}
+    end
   end
 
-  defp check_accept(actor_info, object), do: {:ok, object}
-
-  @reject Keyword.get(@mrf_policy, :reject)
-  defp check_reject(%{host: actor_host} = actor_info, object) when actor_host in @reject do
-    {:reject, nil}
+  defp check_reject(%{host: actor_host} = _actor_info, object) do
+    if Enum.member?(Pleroma.Config.get([:mrf_simple, :reject]), actor_host) do
+      {:reject, nil}
+    else
+      {:ok, object}
+    end
   end
 
-  defp check_reject(actor_info, object), do: {:ok, object}
+  defp check_media_removal(
+         %{host: actor_host} = _actor_info,
+         %{"type" => "Create", "object" => %{"attachement" => child_attachment}} = object
+       )
+       when length(child_attachment) > 0 do
+    object =
+      if Enum.member?(Pleroma.Config.get([:mrf_simple, :media_removal]), actor_host) do
+        child_object = Map.delete(object["object"], "attachment")
+        Map.put(object, "object", child_object)
+      else
+        object
+      end
 
-  @media_removal Keyword.get(@mrf_policy, :media_removal)
-  defp check_media_removal(%{host: actor_host} = actor_info, %{"type" => "Create"} = object)
-       when actor_host in @media_removal do
-    child_object = Map.delete(object["object"], "attachment")
-    object = Map.put(object, "object", child_object)
     {:ok, object}
   end
 
-  defp check_media_removal(actor_info, object), do: {:ok, object}
+  defp check_media_removal(_actor_info, object), do: {:ok, object}
 
-  @media_nsfw Keyword.get(@mrf_policy, :media_nsfw)
   defp check_media_nsfw(
-         %{host: actor_host} = actor_info,
+         %{host: actor_host} = _actor_info,
          %{
            "type" => "Create",
            "object" => %{"attachment" => child_attachment} = child_object
          } = object
        )
-       when actor_host in @media_nsfw and length(child_attachment) > 0 do
-    tags = (child_object["tag"] || []) ++ ["nsfw"]
-    child_object = Map.put(child_object, "tags", tags)
-    child_object = Map.put(child_object, "sensitive", true)
-    object = Map.put(object, "object", child_object)
+       when length(child_attachment) > 0 do
+    object =
+      if Enum.member?(Pleroma.Config.get([:mrf_simple, :media_nsfw]), actor_host) do
+        tags = (child_object["tag"] || []) ++ ["nsfw"]
+        child_object = Map.put(child_object, "tags", tags)
+        child_object = Map.put(child_object, "sensitive", true)
+        Map.put(object, "object", child_object)
+      else
+        object
+      end
+
     {:ok, object}
   end
 
-  defp check_media_nsfw(actor_info, object), do: {:ok, object}
-
-  @ftl_removal Keyword.get(@mrf_policy, :federated_timeline_removal)
-  defp check_ftl_removal(%{host: actor_host} = actor_info, object)
-       when actor_host in @ftl_removal do
-    user = User.get_by_ap_id(object["actor"])
+  defp check_media_nsfw(_actor_info, object), do: {:ok, object}
 
-    # flip to/cc relationship to make the post unlisted
+  defp check_ftl_removal(%{host: actor_host} = _actor_info, object) do
     object =
-      if "https://www.w3.org/ns/activitystreams#Public" in object["to"] and
-           user.follower_address in object["cc"] do
+      with true <-
+             Enum.member?(
+               Pleroma.Config.get([:mrf_simple, :federated_timeline_removal]),
+               actor_host
+             ),
+           user <- User.get_cached_by_ap_id(object["actor"]),
+           true <- "https://www.w3.org/ns/activitystreams#Public" in object["to"],
+           true <- user.follower_address in object["cc"] do
         to =
           List.delete(object["to"], "https://www.w3.org/ns/activitystreams#Public") ++
             [user.follower_address]
@@ -68,14 +84,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
         |> Map.put("to", to)
         |> Map.put("cc", cc)
       else
-        object
+        _ -> object
       end
 
     {:ok, object}
   end
 
-  defp check_ftl_removal(actor_info, object), do: {:ok, object}
-
   @impl true
   def filter(object) do
     actor_info = URI.parse(object["actor"])
index db6823f2c282fe10ec0b59e33f2fa10a26ac1872..a112d4cedbf2308f6487cc3fd8f92f19f39e214e 100644 (file)
@@ -506,9 +506,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     end
   end
 
-  @ap_config Application.get_env(:pleroma, :activitypub)
-  @accept_blocks Keyword.get(@ap_config, :accept_blocks)
-
   def handle_incoming(
         %{
           "type" => "Undo",
@@ -517,7 +514,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
           "id" => id
         } = _data
       ) do
-    with true <- @accept_blocks,
+    with true <- Pleroma.Config.get([:activitypub, :accept_blocks]),
          %User{local: true} = blocked <- User.get_cached_by_ap_id(blocked),
          %User{} = blocker <- User.get_or_fetch_by_ap_id(blocker),
          {:ok, activity} <- ActivityPub.unblock(blocker, blocked, id, false) do
@@ -531,7 +528,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   def handle_incoming(
         %{"type" => "Block", "object" => blocked, "actor" => blocker, "id" => id} = data
       ) do
-    with true <- @accept_blocks,
+    with true <- Pleroma.Config.get([:activitypub, :accept_blocks]),
          %User{local: true} = blocked = User.get_cached_by_ap_id(blocked),
          %User{} = blocker = User.get_or_fetch_by_ap_id(blocker),
          {:ok, activity} <- ActivityPub.block(blocker, blocked, id, false) do
index 8f47bb12785aa0e12ee092473dfd36a46203b140..77e4dbbd708057e55a9dbee8226efd5761cf5ce5 100644 (file)
@@ -70,15 +70,17 @@ defmodule Pleroma.Web.CommonAPI do
 
   def get_visibility(_), do: "public"
 
-  @instance Application.get_env(:pleroma, :instance)
-  @allowed_post_formats Keyword.get(@instance, :allowed_post_formats)
-
-  defp get_content_type(content_type) when content_type in @allowed_post_formats, do: content_type
-  defp get_content_type(_), do: "text/plain"
+  defp get_content_type(content_type) do
+    if Enum.member?(Pleroma.Config.get([:instance, :allowed_post_formats]), content_type) do
+      content_type
+    else
+      "text/plain"
+    end
+  end
 
-  @limit Keyword.get(@instance, :limit)
   def post(user, %{"status" => status} = data) do
     visibility = get_visibility(data)
+    limit = Pleroma.Config.get([:instance, :limit])
 
     with status <- String.trim(status),
          attachments <- attachments_from_ids(data["media_ids"]),
@@ -98,7 +100,7 @@ defmodule Pleroma.Web.CommonAPI do
          context <- make_context(inReplyTo),
          cw <- data["spoiler_text"],
          full_payload <- String.trim(status <> (data["spoiler_text"] || "")),
-         length when length in 1..@limit <- String.length(full_payload),
+         length when length in 1..limit <- String.length(full_payload),
          object <-
            make_note_data(
              user.ap_id,
index 01c2c89c35285d5a27cabafeb105dd09a1ade45b..6071d08e4a40f38b990303d8de681dfe042ea46d 100644 (file)
@@ -12,8 +12,6 @@ defmodule Pleroma.Web.Federator do
   @websub Application.get_env(:pleroma, :websub)
   @ostatus Application.get_env(:pleroma, :ostatus)
   @httpoison Application.get_env(:pleroma, :httpoison)
-  @instance Application.get_env(:pleroma, :instance)
-  @federating Keyword.get(@instance, :federating)
   @max_jobs 20
 
   def init(args) do
@@ -147,7 +145,7 @@ defmodule Pleroma.Web.Federator do
   end
 
   def enqueue(type, payload, priority \\ 1) do
-    if @federating do
+    if Pleroma.Config.get([:instance, :federating]) do
       if Mix.env() == :test do
         handle(type, payload)
       else
index 5cb007740bcebc66129584a7db6f32c6f1dca114..83728c81e7baab42900fc8d1cebc51b10662c635 100644 (file)
@@ -132,22 +132,23 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     end
   end
 
-  @instance Application.get_env(:pleroma, :instance)
   @mastodon_api_level "2.5.0"
 
   def masto_instance(conn, _params) do
+    instance = Pleroma.Config.get(:instance)
+
     response = %{
       uri: Web.base_url(),
-      title: Keyword.get(@instance, :name),
-      description: Keyword.get(@instance, :description),
-      version: "#{@mastodon_api_level} (compatible; #{Keyword.get(@instance, :version)})",
-      email: Keyword.get(@instance, :email),
+      title: Keyword.get(instance, :name),
+      description: Keyword.get(instance, :description),
+      version: "#{@mastodon_api_level} (compatible; #{Keyword.get(instance, :version)})",
+      email: Keyword.get(instance, :email),
       urls: %{
         streaming_api: String.replace(Pleroma.Web.Endpoint.static_url(), "http", "ws")
       },
       stats: Stats.get_stats(),
       thumbnail: Web.base_url() <> "/instance/thumbnail.jpeg",
-      max_toot_chars: Keyword.get(@instance, :limit)
+      max_toot_chars: Keyword.get(instance, :limit)
     }
 
     json(conn, response)
@@ -443,6 +444,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     render(conn, AccountView, "relationships.json", %{user: user, targets: targets})
   end
 
+  # Instead of returning a 400 when no "id" params is present, Mastodon returns an empty array.
+  def relationships(%{assigns: %{user: user}} = conn, _) do
+    conn
+    |> json([])
+  end
+
   def update_media(%{assigns: %{user: _}} = conn, data) do
     with %Object{} = object <- Repo.get(Object, data["id"]),
          true <- is_binary(data["description"]),
@@ -581,15 +588,16 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     end
   end
 
-  @activitypub Application.get_env(:pleroma, :activitypub)
-  @follow_handshake_timeout Keyword.get(@activitypub, :follow_handshake_timeout)
-
   def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
     with %User{} = followed <- Repo.get(User, id),
          {:ok, follower} <- User.maybe_direct_follow(follower, followed),
          {:ok, _activity} <- ActivityPub.follow(follower, followed),
          {:ok, follower, followed} <-
-           User.wait_and_refresh(@follow_handshake_timeout, follower, followed) do
+           User.wait_and_refresh(
+             Pleroma.Config.get([:activitypub, :follow_handshake_timeout]),
+             follower,
+             followed
+           ) do
       render(conn, AccountView, "relationship.json", %{user: follower, target: followed})
     else
       {:error, message} ->
@@ -880,6 +888,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     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}))
 
@@ -899,7 +909,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
             auto_play_gif: false,
             display_sensitive_media: false,
             reduce_motion: false,
-            max_toot_chars: Keyword.get(@instance, :limit)
+            max_toot_chars: limit
           },
           rights: %{
             delete_others_notice: !!user.info["is_moderator"]
@@ -959,7 +969,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
           push_subscription: nil,
           accounts: accounts,
           custom_emojis: mastodon_emoji,
-          char_limit: Keyword.get(@instance, :limit)
+          char_limit: limit
         }
         |> Jason.encode!()
 
@@ -1169,18 +1179,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     |> json("Something went wrong")
   end
 
-  @suggestions Application.get_env(:pleroma, :suggestions)
-
   def suggestions(%{assigns: %{user: user}} = conn, _) do
-    if Keyword.get(@suggestions, :enabled, false) do
-      api = Keyword.get(@suggestions, :third_party_engine, "")
-      timeout = Keyword.get(@suggestions, :timeout, 5000)
-      limit = Keyword.get(@suggestions, :limit, 23)
-
-      host =
-        Application.get_env(:pleroma, Pleroma.Web.Endpoint)
-        |> Keyword.get(:url)
-        |> Keyword.get(:host)
+    suggestions = Pleroma.Config.get(:suggestions)
+
+    if Keyword.get(suggestions, :enabled, false) do
+      api = Keyword.get(suggestions, :third_party_engine, "")
+      timeout = Keyword.get(suggestions, :timeout, 5000)
+      limit = Keyword.get(suggestions, :limit, 23)
+
+      host = Pleroma.Config.get([Pleroma.Web.Endpoint, :url, :host])
 
       user = user.nickname
       url = String.replace(api, "{{host}}", host) |> String.replace("{{user}}", user)
index b461def82e155be654ff7c90efa0c427bc4e0a06..06d0f062376082448f9b42fa720dac515f08457c 100644 (file)
@@ -272,6 +272,10 @@ defmodule Pleroma.Web.Router do
     get("/statuses/mentions_timeline", TwitterAPI.Controller, :mentions_timeline)
     get("/qvitter/statuses/notifications", TwitterAPI.Controller, :notifications)
 
+    # XXX: this is really a pleroma API, but we want to keep the pleroma namespace clean
+    #      for now.
+    post("/qvitter/statuses/notifications/read", TwitterAPI.Controller, :notifications_read)
+
     post("/statuses/update", TwitterAPI.Controller, :status_update)
     post("/statuses/retweet/:id", TwitterAPI.Controller, :retweet)
     post("/statuses/unretweet/:id", TwitterAPI.Controller, :unretweet)
index e84438e97d561b47c9cd3216d8bf05c6c80571e8..dc4a864d66b704fb47e1958332c0b17452234c6c 100644 (file)
@@ -134,19 +134,20 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
     end
   end
 
-  @instance Application.get_env(:pleroma, :instance)
-  @instance_fe Application.get_env(:pleroma, :fe)
-  @instance_chat Application.get_env(:pleroma, :chat)
   def config(conn, _params) do
+    instance = Pleroma.Config.get(:instance)
+    instance_fe = Pleroma.Config.get(:fe)
+    instance_chat = Pleroma.Config.get(:chat)
+
     case get_format(conn) do
       "xml" ->
         response = """
         <config>
           <site>
-            <name>#{Keyword.get(@instance, :name)}</name>
+            <name>#{Keyword.get(instance, :name)}</name>
             <site>#{Web.base_url()}</site>
-            <textlimit>#{Keyword.get(@instance, :limit)}</textlimit>
-            <closed>#{!Keyword.get(@instance, :registrations_open)}</closed>
+            <textlimit>#{Keyword.get(instance, :limit)}</textlimit>
+            <closed>#{!Keyword.get(instance, :registrations_open)}</closed>
           </site>
         </config>
         """
@@ -157,32 +158,32 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
 
       _ ->
         data = %{
-          name: Keyword.get(@instance, :name),
-          description: Keyword.get(@instance, :description),
+          name: Keyword.get(instance, :name),
+          description: Keyword.get(instance, :description),
           server: Web.base_url(),
-          textlimit: to_string(Keyword.get(@instance, :limit)),
-          closed: if(Keyword.get(@instance, :registrations_open), do: "0", else: "1"),
-          private: if(Keyword.get(@instance, :public, true), do: "0", else: "1")
+          textlimit: to_string(Keyword.get(instance, :limit)),
+          closed: if(Keyword.get(instance, :registrations_open), do: "0", else: "1"),
+          private: if(Keyword.get(instance, :public, true), do: "0", else: "1")
         }
 
         pleroma_fe = %{
-          theme: Keyword.get(@instance_fe, :theme),
-          background: Keyword.get(@instance_fe, :background),
-          logo: Keyword.get(@instance_fe, :logo),
-          logoMask: Keyword.get(@instance_fe, :logo_mask),
-          logoMargin: Keyword.get(@instance_fe, :logo_margin),
-          redirectRootNoLogin: Keyword.get(@instance_fe, :redirect_root_no_login),
-          redirectRootLogin: Keyword.get(@instance_fe, :redirect_root_login),
-          chatDisabled: !Keyword.get(@instance_chat, :enabled),
-          showInstanceSpecificPanel: Keyword.get(@instance_fe, :show_instance_panel),
-          scopeOptionsEnabled: Keyword.get(@instance_fe, :scope_options_enabled),
-          formattingOptionsEnabled: Keyword.get(@instance_fe, :formatting_options_enabled),
-          collapseMessageWithSubject: Keyword.get(@instance_fe, :collapse_message_with_subject),
-          hidePostStats: Keyword.get(@instance_fe, :hide_post_stats),
-          hideUserStats: Keyword.get(@instance_fe, :hide_user_stats)
+          theme: Keyword.get(instance_fe, :theme),
+          background: Keyword.get(instance_fe, :background),
+          logo: Keyword.get(instance_fe, :logo),
+          logoMask: Keyword.get(instance_fe, :logo_mask),
+          logoMargin: Keyword.get(instance_fe, :logo_margin),
+          redirectRootNoLogin: Keyword.get(instance_fe, :redirect_root_no_login),
+          redirectRootLogin: Keyword.get(instance_fe, :redirect_root_login),
+          chatDisabled: !Keyword.get(instance_chat, :enabled),
+          showInstanceSpecificPanel: Keyword.get(instance_fe, :show_instance_panel),
+          scopeOptionsEnabled: Keyword.get(instance_fe, :scope_options_enabled),
+          formattingOptionsEnabled: Keyword.get(instance_fe, :formatting_options_enabled),
+          collapseMessageWithSubject: Keyword.get(instance_fe, :collapse_message_with_subject),
+          hidePostStats: Keyword.get(instance_fe, :hide_post_stats),
+          hideUserStats: Keyword.get(instance_fe, :hide_user_stats)
         }
 
-        managed_config = Keyword.get(@instance, :managed_config)
+        managed_config = Keyword.get(instance, :managed_config)
 
         data =
           if managed_config do
@@ -196,7 +197,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
   end
 
   def version(conn, _params) do
-    version = Keyword.get(@instance, :version)
+    version = Pleroma.Config.get([:instance, :version])
 
     case get_format(conn) do
       "xml" ->
index cb483df9d7c384bdc0af141895287e6a3308525e..5bfb83b1e940a6f70b676d4746f140856300f91e 100644 (file)
@@ -6,9 +6,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
   alias Pleroma.Web.MediaProxy
   import Ecto.Query
 
-  @instance Application.get_env(:pleroma, :instance)
   @httpoison Application.get_env(:pleroma, :httpoison)
-  @registrations_open Keyword.get(@instance, :registrations_open)
 
   def create_status(%User{} = user, %{"status" => _} = data) do
     CommonAPI.post(user, data)
@@ -21,15 +19,16 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
     end
   end
 
-  @activitypub Application.get_env(:pleroma, :activitypub)
-  @follow_handshake_timeout Keyword.get(@activitypub, :follow_handshake_timeout)
-
   def follow(%User{} = follower, params) do
     with {:ok, %User{} = followed} <- get_user(params),
          {:ok, follower} <- User.maybe_direct_follow(follower, followed),
          {:ok, activity} <- ActivityPub.follow(follower, followed),
          {:ok, follower, followed} <-
-           User.wait_and_refresh(@follow_handshake_timeout, follower, followed) do
+           User.wait_and_refresh(
+             Pleroma.Config.get([:activitypub, :follow_handshake_timeout]),
+             follower,
+             followed
+           ) do
       {:ok, follower, followed, activity}
     else
       err -> err
@@ -139,18 +138,20 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
       password_confirmation: params["confirm"]
     }
 
+    registrations_open = Pleroma.Config.get([:instance, :registrations_open])
+
     # no need to query DB if registration is open
     token =
-      unless @registrations_open || is_nil(tokenString) do
+      unless registrations_open || is_nil(tokenString) do
         Repo.get_by(UserInviteToken, %{token: tokenString})
       end
 
     cond do
-      @registrations_open || (!is_nil(token) && !token.used) ->
+      registrations_open || (!is_nil(token) && !token.used) ->
         changeset = User.register_changeset(%User{}, params)
 
         with {:ok, user} <- Repo.insert(changeset) do
-          !@registrations_open && UserInviteToken.mark_as_used(token.token)
+          !registrations_open && UserInviteToken.mark_as_used(token.token)
           {:ok, user}
         else
           {:error, changeset} ->
@@ -161,10 +162,10 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
             {:error, %{error: errors}}
         end
 
-      !@registrations_open && is_nil(token) ->
+      !registrations_open && is_nil(token) ->
         {:error, "Invalid token"}
 
-      !@registrations_open && token.used ->
+      !registrations_open && token.used ->
         {:error, "Expired token"}
     end
   end
index 83d725f13987da91f6807a3586c934fc613563b2..727469a662ddfd9237c4d785df9fab3f7911c227 100644 (file)
@@ -133,6 +133,19 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
     |> render(NotificationView, "notification.json", %{notifications: notifications, for: user})
   end
 
+  def notifications_read(%{assigns: %{user: user}} = conn, %{"latest_id" => latest_id} = params) do
+    Notification.set_read_up_to(user, latest_id)
+
+    notifications = Notification.for_user(user, params)
+
+    conn
+    |> render(NotificationView, "notification.json", %{notifications: notifications, for: user})
+  end
+
+  def notifications_read(%{assigns: %{user: user}} = conn, _) do
+    bad_request_reply(conn, "You need to specify latest_id")
+  end
+
   def follow(%{assigns: %{user: user}} = conn, params) do
     case TwitterAPI.follow(user, params) do
       {:ok, user, followed, _activity} ->
index 32d5cc90c082c253c0424cec066610797cd4b53d..0124544c865e0976b94d819bbc25c727eccfda0e 100644 (file)
@@ -4,6 +4,7 @@ defmodule Pleroma.ConfigTest do
   test "get/1 with an atom" do
     assert Pleroma.Config.get(:instance) == Application.get_env(:pleroma, :instance)
     assert Pleroma.Config.get(:azertyuiop) == nil
+    assert Pleroma.Config.get(:azertyuiop, true) == true
   end
 
   test "get/1 with a list of keys" do
@@ -20,6 +21,22 @@ defmodule Pleroma.ConfigTest do
              )
 
     assert Pleroma.Config.get([:azerty, :uiop]) == nil
+    assert Pleroma.Config.get([:azerty, :uiop], true) == true
+  end
+
+  test "get!/1" do
+    assert Pleroma.Config.get!(:instance) == Application.get_env(:pleroma, :instance)
+
+    assert Pleroma.Config.get!([:instance, :public]) ==
+             Keyword.get(Application.get_env(:pleroma, :instance), :public)
+
+    assert_raise(Pleroma.Config.Error, fn ->
+      Pleroma.Config.get!(:azertyuiop)
+    end)
+
+    assert_raise(Pleroma.Config.Error, fn ->
+      Pleroma.Config.get!([:azerty, :uiop])
+    end)
   end
 
   test "put/2 with a key" do
index d86b5c1ab2530a4c5cfef5d346626a75b734a3a1..79290ac78211f0df4e27de8be1c1647771162415 100644 (file)
@@ -121,6 +121,41 @@ defmodule Pleroma.NotificationTest do
     end
   end
 
+  describe "set_read_up_to()" do
+    test "it sets all notifications as read up to a specified notification ID" do
+      user = insert(:user)
+      other_user = insert(:user)
+
+      {:ok, activity} =
+        TwitterAPI.create_status(user, %{
+          "status" => "hey @#{other_user.nickname}!"
+        })
+
+      {:ok, activity} =
+        TwitterAPI.create_status(user, %{
+          "status" => "hey again @#{other_user.nickname}!"
+        })
+
+      [n2, n1] = notifs = Notification.for_user(other_user)
+      assert length(notifs) == 2
+
+      assert n2.id > n1.id
+
+      {:ok, activity} =
+        TwitterAPI.create_status(user, %{
+          "status" => "hey yet again @#{other_user.nickname}!"
+        })
+
+      Notification.set_read_up_to(other_user, n2.id)
+
+      [n3, n2, n1] = notifs = Notification.for_user(other_user)
+
+      assert n1.seen == true
+      assert n2.seen == true
+      assert n3.seen == false
+    end
+  end
+
   describe "notification lifecycle" do
     test "liking an activity results in 1 notification, then 0 if the activity is deleted" do
       user = insert(:user)
index b64f416e32a75449f52ccd9ba89044081904a35b..13480c21bdde00fde397a6cc29816951da6eec10 100644 (file)
@@ -331,6 +331,56 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
     end
   end
 
+  describe "POST /api/qvitter/statuses/notifications/read" do
+    setup [:valid_user]
+
+    test "without valid credentials", %{conn: conn} do
+      conn = post(conn, "/api/qvitter/statuses/notifications/read", %{"latest_id" => 1_234_567})
+      assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
+    end
+
+    test "with credentials, without any params", %{conn: conn, user: current_user} do
+      conn =
+        conn
+        |> with_credentials(current_user.nickname, "test")
+        |> post("/api/qvitter/statuses/notifications/read")
+
+      assert json_response(conn, 400) == %{
+               "error" => "You need to specify latest_id",
+               "request" => "/api/qvitter/statuses/notifications/read"
+             }
+    end
+
+    test "with credentials, with params", %{conn: conn, user: current_user} do
+      other_user = insert(:user)
+
+      {:ok, _activity} =
+        ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: other_user})
+
+      response_conn =
+        conn
+        |> with_credentials(current_user.nickname, "test")
+        |> get("/api/qvitter/statuses/notifications.json")
+
+      [notification] = response = json_response(response_conn, 200)
+
+      assert length(response) == 1
+
+      assert notification["is_seen"] == 0
+
+      response_conn =
+        conn
+        |> with_credentials(current_user.nickname, "test")
+        |> post("/api/qvitter/statuses/notifications/read", %{"latest_id" => notification["id"]})
+
+      [notification] = response = json_response(response_conn, 200)
+
+      assert length(response) == 1
+
+      assert notification["is_seen"] == 1
+    end
+  end
+
   describe "GET /statuses/user_timeline.json" do
     setup [:valid_user]