diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index dc85eaba2..5d0d3316a 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -10,14 +10,16 @@ variables: &global_variables
cache: &global_cache_policy
key: ${CI_COMMIT_REF_SLUG}
paths:
- - deps
- - _build
+ - deps
+ - _build
+
stages:
- build
- test
- benchmark
- deploy
- release
+ - docker
before_script:
- mix local.hex --force
@@ -264,3 +266,66 @@ arm64-musl:
variables: *release-variables
before_script: *before-release-musl
script: *release
+
+docker:
+ stage: docker
+ image: docker:latest
+ cache: {}
+ dependencies: []
+ variables: &docker-variables
+ DOCKER_DRIVER: overlay2
+ DOCKER_HOST: unix:///var/run/docker.sock
+ IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
+ IMAGE_TAG_SLUG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
+ IMAGE_TAG_LATEST: $CI_REGISTRY_IMAGE:latest
+ IMAGE_TAG_LATEST_STABLE: $CI_REGISTRY_IMAGE:latest-stable
+ before_script: &before-docker
+ - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+ - docker pull $IMAGE_TAG_SLUG || true
+ - export CI_JOB_TIMESTAMP=$(date --utc -Iseconds)
+ - export CI_VCS_REF=$CI_COMMIT_SHORT_SHA
+ allow_failure: true
+ script:
+ - docker build --cache-from $IMAGE_TAG_SLUG --build-arg VCS_REF=$CI_VCS_REF --build-arg BUILD_DATE=$CI_JOB_TIMESTAMP -t $IMAGE_TAG -t $IMAGE_TAG_SLUG -t $IMAGE_TAG_LATEST .
+ - docker push $IMAGE_TAG
+ - docker push $IMAGE_TAG_SLUG
+ - docker push $IMAGE_TAG_LATEST
+ tags:
+ - dind
+ only:
+ - develop@pleroma/pleroma
+
+docker-stable:
+ stage: docker
+ image: docker:latest
+ cache: {}
+ dependencies: []
+ variables: *docker-variables
+ before_script: *before-docker
+ allow_failure: true
+ script:
+ - docker build --cache-from $IMAGE_TAG_SLUG --build-arg VCS_REF=$CI_VCS_REF --build-arg BUILD_DATE=$CI_JOB_TIMESTAMP -t $IMAGE_TAG -t $IMAGE_TAG_SLUG -t $IMAGE_TAG_LATEST_STABLE .
+ - docker push $IMAGE_TAG
+ - docker push $IMAGE_TAG_SLUG
+ - docker push $IMAGE_TAG_LATEST_STABLE
+ tags:
+ - dind
+ only:
+ - stable@pleroma/pleroma
+
+docker-release:
+ stage: docker
+ image: docker:latest
+ cache: {}
+ dependencies: []
+ variables: *docker-variables
+ before_script: *before-docker
+ allow_failure: true
+ script:
+ - docker build --cache-from $IMAGE_TAG_SLUG --build-arg VCS_REF=$CI_VCS_REF --build-arg BUILD_DATE=$CI_JOB_TIMESTAMP -t $IMAGE_TAG -t $IMAGE_TAG_SLUG .
+ - docker push $IMAGE_TAG
+ - docker push $IMAGE_TAG_SLUG
+ tags:
+ - dind
+ only:
+ - /^release/.*$/@pleroma/pleroma
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 397348304..09f31d5a9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,9 +10,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- **Breaking**: MDII uploader
### Changed
+- **Breaking:** Pleroma won't start if it detects unapplied migrations
- **Breaking:** attachments are removed along with statuses when there are no other references to it
- **Breaking:** Elixir >=1.8 is now required (was >= 1.7)
- **Breaking:** attachment links (`config :pleroma, :instance, no_attachment_links` and `config :pleroma, Pleroma.Upload, link_name`) disabled by default
+- **Breaking:** OAuth: defaulted `[:auth, :enforce_oauth_admin_scope_usage]` setting to `true` which demands `admin` OAuth scope to perform admin actions (in addition to `is_admin` flag on User); make sure to use bundled or newer versions of AdminFE & PleromaFE to access admin / moderator features.
- Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings)
- Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler
- Enabled `:instance, extended_nickname_format` in the default config
@@ -42,6 +44,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Mastodon API, streaming: Add `pleroma.direct_conversation_id` to the `conversation` stream event payload.
- Admin API: Render whole status in grouped reports
- Mastodon API: User timelines will now respect blocks, unless you are getting the user timeline of somebody you blocked (which would be empty otherwise).
+- Mastodon API: Favoriting / Repeating a post multiple times will now return the identical response every time. Before, executing that action twice would return an error ("already favorited") on the second try.
### Added
@@ -90,6 +93,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Mastodon API: `/api/v1/update_credentials` accepts `actor_type` field.
- Captcha: Support native provider
- Captcha: Enable by default
+- Mastodon API: Add support for `account_id` param to filter notifications by the account
+- Mastodon API: Add `emoji_reactions` property to Statuses
### Fixed
diff --git a/Dockerfile b/Dockerfile
index c61dcfde9..4f7f12716 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -14,6 +14,20 @@ RUN apk add git gcc g++ musl-dev make &&\
FROM alpine:3.9
+ARG BUILD_DATE
+ARG VCS_REF
+
+LABEL maintainer="ops@pleroma.social" \
+ org.opencontainers.image.title="pleroma" \
+ org.opencontainers.image.description="Pleroma for Docker" \
+ org.opencontainers.image.authors="ops@pleroma.social" \
+ org.opencontainers.image.vendor="pleroma.social" \
+ org.opencontainers.image.documentation="https://git.pleroma.social/pleroma/pleroma" \
+ org.opencontainers.image.licenses="AGPL-3.0" \
+ org.opencontainers.image.url="https://pleroma.social" \
+ org.opencontainers.image.revision=$VCS_REF \
+ org.opencontainers.image.created=$BUILD_DATE
+
ARG HOME=/opt/pleroma
ARG DATA=/var/lib/pleroma
diff --git a/benchmarks/load_testing/generator.ex b/benchmarks/load_testing/generator.ex
index a957e0ffb..3f88fefd7 100644
--- a/benchmarks/load_testing/generator.ex
+++ b/benchmarks/load_testing/generator.ex
@@ -9,7 +9,7 @@ def generate_like_activities(user, posts) do
{time, _} =
:timer.tc(fn ->
Task.async_stream(
- Enum.take_random(posts, count_likes),
+ Enum.take_random(posts, count_likes),
fn post -> {:ok, _, _} = CommonAPI.favorite(post.id, user) end,
max_concurrency: 10,
timeout: 30_000
@@ -142,6 +142,48 @@ defp do_generate_activity(users) do
CommonAPI.post(Enum.random(users), post)
end
+ def generate_power_intervals(opts \\ []) do
+ count = Keyword.get(opts, :count, 20)
+ power = Keyword.get(opts, :power, 2)
+ IO.puts("Generating #{count} intervals for a power #{power} series...")
+ counts = Enum.map(1..count, fn n -> :math.pow(n, power) end)
+ sum = Enum.sum(counts)
+
+ densities =
+ Enum.map(counts, fn c ->
+ c / sum
+ end)
+
+ densities
+ |> Enum.reduce(0, fn density, acc ->
+ if acc == 0 do
+ [{0, density}]
+ else
+ [{_, lower} | _] = acc
+ [{lower, lower + density} | acc]
+ end
+ end)
+ |> Enum.reverse()
+ end
+
+ def generate_tagged_activities(opts \\ []) do
+ tag_count = Keyword.get(opts, :tag_count, 20)
+ users = Keyword.get(opts, :users, Repo.all(User))
+ activity_count = Keyword.get(opts, :count, 200_000)
+
+ intervals = generate_power_intervals(count: tag_count)
+
+ IO.puts(
+ "Generating #{activity_count} activities using #{tag_count} different tags of format `tag_n`, starting at tag_0"
+ )
+
+ Enum.each(1..activity_count, fn _ ->
+ random = :rand.uniform()
+ i = Enum.find_index(intervals, fn {lower, upper} -> lower <= random && upper > random end)
+ CommonAPI.post(Enum.random(users), %{"status" => "a post with the tag #tag_#{i}"})
+ end)
+ end
+
defp do_generate_activity_with_mention(user, users) do
mentions_cnt = Enum.random([2, 3, 4, 5])
with_user = Enum.random([true, false])
diff --git a/benchmarks/mix/tasks/pleroma/benchmarks/tags.ex b/benchmarks/mix/tasks/pleroma/benchmarks/tags.ex
new file mode 100644
index 000000000..fd1506907
--- /dev/null
+++ b/benchmarks/mix/tasks/pleroma/benchmarks/tags.ex
@@ -0,0 +1,87 @@
+defmodule Mix.Tasks.Pleroma.Benchmarks.Tags do
+ use Mix.Task
+ alias Pleroma.Repo
+ alias Pleroma.LoadTesting.Generator
+ import Ecto.Query
+
+ def run(_args) do
+ Mix.Pleroma.start_pleroma()
+ activities_count = Repo.aggregate(from(a in Pleroma.Activity), :count, :id)
+
+ if activities_count == 0 do
+ IO.puts("Did not find any activities, cleaning and generating")
+ clean_tables()
+ Generator.generate_users(users_max: 10)
+ Generator.generate_tagged_activities()
+ else
+ IO.puts("Found #{activities_count} activities, won't generate new ones")
+ end
+
+ tags = Enum.map(0..20, fn i -> {"For #tag_#{i}", "tag_#{i}"} end)
+
+ Enum.each(tags, fn {_, tag} ->
+ query =
+ from(o in Pleroma.Object,
+ where: fragment("(?)->'tag' \\? (?)", o.data, ^tag)
+ )
+
+ count = Repo.aggregate(query, :count, :id)
+ IO.puts("Database contains #{count} posts tagged with #{tag}")
+ end)
+
+ user = Repo.all(Pleroma.User) |> List.first()
+
+ Benchee.run(
+ %{
+ "Hashtag fetching, any" => fn tags ->
+ Pleroma.Web.MastodonAPI.TimelineController.hashtag_fetching(
+ %{
+ "any" => tags
+ },
+ user,
+ false
+ )
+ end,
+ # Will always return zero results because no overlapping hashtags are generated.
+ "Hashtag fetching, all" => fn tags ->
+ Pleroma.Web.MastodonAPI.TimelineController.hashtag_fetching(
+ %{
+ "all" => tags
+ },
+ user,
+ false
+ )
+ end
+ },
+ inputs:
+ tags
+ |> Enum.map(fn {_, v} -> v end)
+ |> Enum.chunk_every(2)
+ |> Enum.map(fn tags -> {"For #{inspect(tags)}", tags} end),
+ time: 5
+ )
+
+ Benchee.run(
+ %{
+ "Hashtag fetching" => fn tag ->
+ Pleroma.Web.MastodonAPI.TimelineController.hashtag_fetching(
+ %{
+ "tag" => tag
+ },
+ user,
+ false
+ )
+ end
+ },
+ inputs: tags,
+ time: 5
+ )
+ end
+
+ defp clean_tables do
+ IO.puts("Deleting old data...\n")
+ Ecto.Adapters.SQL.query!(Repo, "TRUNCATE users CASCADE;")
+ Ecto.Adapters.SQL.query!(Repo, "TRUNCATE activities CASCADE;")
+ Ecto.Adapters.SQL.query!(Repo, "TRUNCATE objects CASCADE;")
+ end
+end
diff --git a/config/config.exs b/config/config.exs
index 8b8ecc833..d706adc6e 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -488,7 +488,8 @@
mailer: 10,
transmogrifier: 20,
scheduled_activities: 10,
- background: 5
+ background: 5,
+ attachments_cleanup: 5
],
crontab: [
{"0 0 * * *", Pleroma.Workers.Cron.ClearOauthTokenWorker},
@@ -553,7 +554,7 @@
config :pleroma,
:auth,
- enforce_oauth_admin_scope_usage: false,
+ enforce_oauth_admin_scope_usage: true,
oauth_consumer_strategies: oauth_consumer_strategies
config :pleroma, Pleroma.Emails.Mailer, adapter: Swoosh.Adapters.Sendmail, enabled: false
diff --git a/docs/API/differences_in_mastoapi_responses.md b/docs/API/differences_in_mastoapi_responses.md
index bb62ed5f2..50076cf98 100644
--- a/docs/API/differences_in_mastoapi_responses.md
+++ b/docs/API/differences_in_mastoapi_responses.md
@@ -29,6 +29,7 @@ Has these additional fields under the `pleroma` object:
- `spoiler_text`: a map consisting of alternate representations of the `spoiler_text` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`
- `expires_at`: a datetime (iso8601) that states when the post will expire (be deleted automatically), or empty if the post won't expire
- `thread_muted`: true if the thread the post belongs to is muted
+- `emoji_reactions`: An object with all the emoji reactions with count. Contains no information about the reacting users, for that use the `emoji_reactions_by` endpoint.
## Attachments
diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex
index 510d3273c..896cbb3c5 100644
--- a/lib/pleroma/activity.ex
+++ b/lib/pleroma/activity.ex
@@ -312,9 +312,7 @@ def restrict_deactivated_users(query) do
from(u in User.Query.build(deactivated: true), select: u.ap_id)
|> Repo.all()
- from(activity in query,
- where: activity.actor not in ^deactivated_users
- )
+ Activity.Queries.exclude_authors(query, deactivated_users)
end
defdelegate search(user, query, options \\ []), to: Pleroma.Activity.Search
diff --git a/lib/pleroma/activity/queries.ex b/lib/pleroma/activity/queries.ex
index 26bc1099d..79f305201 100644
--- a/lib/pleroma/activity/queries.ex
+++ b/lib/pleroma/activity/queries.ex
@@ -12,6 +12,7 @@ defmodule Pleroma.Activity.Queries do
@type query :: Ecto.Queryable.t() | Activity.t()
alias Pleroma.Activity
+ alias Pleroma.User
@spec by_ap_id(query, String.t()) :: query
def by_ap_id(query \\ Activity, ap_id) do
@@ -29,6 +30,11 @@ def by_actor(query \\ Activity, actor) do
)
end
+ @spec by_author(query, String.t()) :: query
+ def by_author(query \\ Activity, %User{ap_id: ap_id}) do
+ from(a in query, where: a.actor == ^ap_id)
+ end
+
@spec by_object_id(query, String.t() | [String.t()]) :: query
def by_object_id(query \\ Activity, object_id)
@@ -72,4 +78,8 @@ def exclude_type(query \\ Activity, activity_type) do
where: fragment("(?)->>'type' != ?", activity.data, ^activity_type)
)
end
+
+ def exclude_authors(query \\ Activity, actors) do
+ from(activity in query, where: activity.actor not in ^actors)
+ end
end
diff --git a/lib/pleroma/activity/search.ex b/lib/pleroma/activity/search.ex
index d30a5a6a5..f96e208da 100644
--- a/lib/pleroma/activity/search.ex
+++ b/lib/pleroma/activity/search.ex
@@ -26,18 +26,23 @@ def search(user, search_query, options \\ []) do
|> query_with(index_type, search_query)
|> maybe_restrict_local(user)
|> maybe_restrict_author(author)
+ |> maybe_restrict_blocked(user)
|> Pagination.fetch_paginated(%{"offset" => offset, "limit" => limit}, :offset)
|> maybe_fetch(user, search_query)
end
def maybe_restrict_author(query, %User{} = author) do
- from([a, o] in query,
- where: a.actor == ^author.ap_id
- )
+ Activity.Queries.by_author(query, author)
end
def maybe_restrict_author(query, _), do: query
+ def maybe_restrict_blocked(query, %User{} = user) do
+ Activity.Queries.exclude_authors(query, User.blocked_users_ap_ids(user))
+ end
+
+ def maybe_restrict_blocked(query, _), do: query
+
defp restrict_public(q) do
from([a, o] in q,
where: fragment("?->>'type' = 'Create'", a.data),
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index 98d7a6e86..6fdc54aed 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -33,6 +33,7 @@ def user_agent do
def start(_type, _args) do
Pleroma.HTML.compile_scrubbers()
Pleroma.Config.DeprecationWarnings.warn()
+ Pleroma.Repo.check_migrations_applied!()
setup_instrumenters()
load_custom_modules()
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index 2452a7389..38e372f6d 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -19,6 +19,8 @@ defmodule Pleroma.Object do
@type t() :: %__MODULE__{}
+ @derive {Jason.Encoder, only: [:data]}
+
schema "objects" do
field(:data, :map)
@@ -180,85 +182,17 @@ def swap_object_with_tombstone(object) do
def delete(%Object{data: %{"id" => id}} = object) do
with {:ok, _obj} = swap_object_with_tombstone(object),
- :ok <- delete_attachments(object),
deleted_activity = Activity.delete_all_by_object_ap_id(id),
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}"),
- {:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do
+ {:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path),
+ {:ok, _} <-
+ Pleroma.Workers.AttachmentsCleanupWorker.enqueue("cleanup_attachments", %{
+ "object" => object
+ }) do
{:ok, object, deleted_activity}
end
end
- defp delete_attachments(%{data: %{"attachment" => [_ | _] = attachments, "actor" => actor}}) do
- hrefs =
- Enum.flat_map(attachments, fn attachment ->
- Enum.map(attachment["url"], & &1["href"])
- end)
-
- names = Enum.map(attachments, & &1["name"])
-
- uploader = Pleroma.Config.get([Pleroma.Upload, :uploader])
-
- # find all objects for copies of the attachments, name and actor doesn't matter here
- delete_ids =
- from(o in Object,
- where:
- fragment(
- "to_jsonb(array(select jsonb_array_elements((?)#>'{url}') ->> 'href'))::jsonb \\?| (?)",
- o.data,
- ^hrefs
- )
- )
- |> Repo.all()
- # we should delete 1 object for any given attachment, but don't delete files if
- # there are more than 1 object for it
- |> Enum.reduce(%{}, fn %{
- id: id,
- data: %{
- "url" => [%{"href" => href}],
- "actor" => obj_actor,
- "name" => name
- }
- },
- acc ->
- Map.update(acc, href, %{id: id, count: 1}, fn val ->
- case obj_actor == actor and name in names do
- true ->
- # set id of the actor's object that will be deleted
- %{val | id: id, count: val.count + 1}
-
- false ->
- # another actor's object, just increase count to not delete file
- %{val | count: val.count + 1}
- end
- end)
- end)
- |> Enum.map(fn {href, %{id: id, count: count}} ->
- # only delete files that have single instance
- with 1 <- count do
- prefix =
- case Pleroma.Config.get([Pleroma.Upload, :base_url]) do
- nil -> "media"
- _ -> ""
- end
-
- base_url = Pleroma.Config.get([__MODULE__, :base_url], Pleroma.Web.base_url())
-
- file_path = String.trim_leading(href, "#{base_url}/#{prefix}")
-
- uploader.delete_file(file_path)
- end
-
- id
- end)
-
- from(o in Object, where: o.id in ^delete_ids)
- |> Repo.delete_all()
-
- :ok
- end
-
- defp delete_attachments(%{data: _data}), do: :ok
-
def prune(%Object{data: %{"id" => id}} = object) do
with {:ok, object} <- Repo.delete(object),
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}"),
diff --git a/lib/pleroma/plugs/user_is_admin_plug.ex b/lib/pleroma/plugs/user_is_admin_plug.ex
index 582fb1f92..3190163d3 100644
--- a/lib/pleroma/plugs/user_is_admin_plug.ex
+++ b/lib/pleroma/plugs/user_is_admin_plug.ex
@@ -23,6 +23,7 @@ def call(%{assigns: %{user: %User{is_admin: true}} = assigns} = conn, _) do
token && OAuth.Scopes.contains_admin_scopes?(token.scopes) ->
# Note: checking for _any_ admin scope presence, not necessarily fitting requested action.
# Thus, controller must explicitly invoke OAuthScopesPlug to verify scope requirements.
+ # Admin might opt out of admin scope for some apps to block any admin actions from them.
conn
true ->
diff --git a/lib/pleroma/repo.ex b/lib/pleroma/repo.ex
index f57e088bc..cb0b6653c 100644
--- a/lib/pleroma/repo.ex
+++ b/lib/pleroma/repo.ex
@@ -8,6 +8,8 @@ defmodule Pleroma.Repo do
adapter: Ecto.Adapters.Postgres,
migration_timestamps: [type: :naive_datetime_usec]
+ require Logger
+
defmodule Instrumenter do
use Prometheus.EctoInstrumenter
end
@@ -47,4 +49,37 @@ def get_assoc(resource, association) do
_ -> {:error, :not_found}
end
end
+
+ def check_migrations_applied!() do
+ unless Pleroma.Config.get(
+ [:i_am_aware_this_may_cause_data_loss, :disable_migration_check],
+ false
+ ) do
+ Ecto.Migrator.with_repo(__MODULE__, fn repo ->
+ down_migrations =
+ Ecto.Migrator.migrations(repo)
+ |> Enum.reject(fn
+ {:up, _, _} -> true
+ {:down, _, _} -> false
+ end)
+
+ if length(down_migrations) > 0 do
+ down_migrations_text =
+ Enum.map(down_migrations, fn {:down, id, name} -> "- #{name} (#{id})\n" end)
+
+ Logger.error(
+ "The following migrations were not applied:\n#{down_migrations_text}If you want to start Pleroma anyway, set\nconfig :pleroma, :i_am_aware_this_may_cause_data_loss, disable_migration_check: true"
+ )
+
+ raise Pleroma.Repo.UnappliedMigrationsError
+ end
+ end)
+ else
+ :ok
+ end
+ end
+end
+
+defmodule Pleroma.Repo.UnappliedMigrationsError do
+ defexception message: "Unapplied Migrations detected"
end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 2e225415c..430f04ae9 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -1874,22 +1874,13 @@ defp truncate_field(%{"name" => name, "value" => value}) do
end
def admin_api_update(user, params) do
- changeset =
- cast(user, params, [
- :is_moderator,
- :is_admin,
- :show_role
- ])
-
- with {:ok, updated_user} <- update_and_set_cache(changeset) do
- if user.is_admin != updated_user.is_admin do
- # Admin status change results in change of accessible OAuth scopes, and instead of changing
- # already issued tokens we revoke them, requiring user to sign in again
- global_sign_out(user)
- end
-
- {:ok, updated_user}
- end
+ user
+ |> cast(params, [
+ :is_moderator,
+ :is_admin,
+ :show_role
+ ])
+ |> update_and_set_cache()
end
@doc "Signs user out of all applications"
diff --git a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex
index 4eaea00d8..c184c3b66 100644
--- a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex
@@ -20,7 +20,7 @@ def filter(%{"type" => message_type} = message) do
with accepted_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :accept]),
rejected_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :reject]),
true <-
- length(accepted_vocabulary) == 0 || Enum.member?(accepted_vocabulary, message_type),
+ Enum.empty?(accepted_vocabulary) || Enum.member?(accepted_vocabulary, message_type),
false <-
length(rejected_vocabulary) > 0 && Enum.member?(rejected_vocabulary, message_type),
{:ok, _} <- filter(message["object"]) do
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 3fa789d53..2b8bfc3bd 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -658,24 +658,8 @@ def handle_incoming(
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)
- locked = new_user_data[:locked] || false
- attachment = get_in(new_user_data, [:source_data, "attachment"]) || []
- invisible = new_user_data[:invisible] || false
-
- fields =
- attachment
- |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
- |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
-
- update_data =
- new_user_data
- |> Map.take([:avatar, :banner, :bio, :name, :also_known_as])
- |> Map.put(:fields, fields)
- |> Map.put(:locked, locked)
- |> Map.put(:invisible, invisible)
-
actor
- |> User.upgrade_changeset(update_data, true)
+ |> User.upgrade_changeset(new_user_data, true)
|> User.update_and_set_cache()
ActivityPub.update(%{
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index c8abeff06..7118faf94 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -32,19 +32,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
plug(
OAuthScopesPlug,
%{scopes: ["read:accounts"], admin: true}
- when action in [:list_users, :user_show, :right_get, :invites]
+ when action in [:list_users, :user_show, :right_get]
)
plug(
OAuthScopesPlug,
%{scopes: ["write:accounts"], admin: true}
when action in [
- :get_invite_token,
- :revoke_invite,
- :email_invite,
:get_password_reset,
- :user_follow,
- :user_unfollow,
:user_delete,
:users_create,
:user_toggle_activation,
@@ -57,6 +52,20 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
]
)
+ plug(OAuthScopesPlug, %{scopes: ["read:invites"], admin: true} when action == :invites)
+
+ plug(
+ OAuthScopesPlug,
+ %{scopes: ["write:invites"], admin: true}
+ when action in [:create_invite_token, :revoke_invite, :email_invite]
+ )
+
+ plug(
+ OAuthScopesPlug,
+ %{scopes: ["write:follows"], admin: true}
+ when action in [:user_follow, :user_unfollow, :relay_follow, :relay_unfollow]
+ )
+
plug(
OAuthScopesPlug,
%{scopes: ["read:reports"], admin: true}
@@ -66,7 +75,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
plug(
OAuthScopesPlug,
%{scopes: ["write:reports"], admin: true}
- when action in [:report_update_state, :report_respond]
+ when action in [:reports_update]
)
plug(
@@ -90,7 +99,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
plug(
OAuthScopesPlug,
%{scopes: ["write"], admin: true}
- when action in [:relay_follow, :relay_unfollow, :config_update]
+ when action == :config_update
)
@users_page_size 50
@@ -630,7 +639,7 @@ def get_password_reset(conn, %{"nickname" => nickname}) do
def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
- Enum.map(users, &User.force_password_reset_async/1)
+ Enum.each(users, &User.force_password_reset_async/1)
ModerationLog.insert_log(%{
actor: admin,
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 2f3bcfc3c..c05a6c544 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -85,9 +85,13 @@ def delete(activity_id, user) do
def repeat(id_or_ap_id, user, params \\ %{}) do
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
object <- Object.normalize(activity),
- nil <- Utils.get_existing_announce(user.ap_id, object),
+ announce_activity <- Utils.get_existing_announce(user.ap_id, object),
public <- public_announce?(object, params) do
- ActivityPub.announce(user, object, nil, true, public)
+ if announce_activity do
+ {:ok, announce_activity, object}
+ else
+ ActivityPub.announce(user, object, nil, true, public)
+ end
else
_ -> {:error, dgettext("errors", "Could not repeat")}
end
@@ -105,8 +109,12 @@ def unrepeat(id_or_ap_id, user) do
def favorite(id_or_ap_id, user) do
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
object <- Object.normalize(activity),
- nil <- Utils.get_existing_like(user.ap_id, object) do
- ActivityPub.like(user, object)
+ like_activity <- Utils.get_existing_like(user.ap_id, object) do
+ if like_activity do
+ {:ok, like_activity, object}
+ else
+ ActivityPub.like(user, object)
+ end
else
_ -> {:error, dgettext("errors", "Could not favorite")}
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
index 16759be6a..f2508aca4 100644
--- a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
@@ -23,6 +23,23 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
# GET /api/v1/notifications
+ def index(conn, %{"account_id" => account_id} = params) do
+ case Pleroma.User.get_cached_by_id(account_id) do
+ %{ap_id: account_ap_id} ->
+ params =
+ params
+ |> Map.delete("account_id")
+ |> Map.put("account_ap_id", account_ap_id)
+
+ index(conn, params)
+
+ _ ->
+ conn
+ |> put_status(:not_found)
+ |> json(%{"error" => "Account is not found"})
+ end
+ end
+
def index(%{assigns: %{user: user}} = conn, params) do
notifications = MastodonAPI.get_notifications(user, params)
diff --git a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex
index 0a929f55b..5a5db8e00 100644
--- a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex
@@ -43,7 +43,7 @@ defp do_search(version, %{assigns: %{user: user}} = conn, %{"q" => query} = para
result =
default_values
|> Enum.map(fn {resource, default_value} ->
- if params["type"] == nil or params["type"] == resource do
+ if params["type"] in [nil, resource] do
{resource, fn -> resource_search(version, resource, query, options) end}
else
{resource, fn -> default_value end}
diff --git a/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex b/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex
index fc7d52824..11f7b85d3 100644
--- a/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex
@@ -6,9 +6,9 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionController do
@moduledoc "The module represents functions to manage user subscriptions."
use Pleroma.Web, :controller
+ alias Pleroma.Web.MastodonAPI.PushSubscriptionView, as: View
alias Pleroma.Web.Push
alias Pleroma.Web.Push.Subscription
- alias Pleroma.Web.MastodonAPI.PushSubscriptionView, as: View
action_fallback(:errors)
diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
index 384159336..29964a1d4 100644
--- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
@@ -77,10 +77,7 @@ def public(%{assigns: %{user: user}} = conn, params) do
|> render("index.json", activities: activities, for: user, as: :activity)
end
- # GET /api/v1/timelines/tag/:tag
- def hashtag(%{assigns: %{user: user}} = conn, params) do
- local_only = truthy_param?(params["local"])
-
+ def hashtag_fetching(params, user, local_only) do
tags =
[params["tag"], params["any"]]
|> List.flatten()
@@ -98,7 +95,7 @@ def hashtag(%{assigns: %{user: user}} = conn, params) do
|> Map.get("none", [])
|> Enum.map(&String.downcase(&1))
- activities =
+ _activities =
params
|> Map.put("type", "Create")
|> Map.put("local_only", local_only)
@@ -109,6 +106,13 @@ def hashtag(%{assigns: %{user: user}} = conn, params) do
|> Map.put("tag_all", tag_all)
|> Map.put("tag_reject", tag_reject)
|> ActivityPub.fetch_public_activities()
+ end
+
+ # GET /api/v1/timelines/tag/:tag
+ def hashtag(%{assigns: %{user: user}} = conn, params) do
+ local_only = truthy_param?(params["local"])
+
+ activities = hashtag_fetching(params, user, local_only)
conn
|> add_link_headers(activities, %{"local" => local_only})
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex
index b1816370e..390a2b190 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex
@@ -56,6 +56,7 @@ def get_notifications(user, params \\ %{}) do
user
|> Notification.for_user_query(options)
|> restrict(:exclude_types, options)
+ |> restrict(:account_ap_id, options)
|> Pagination.fetch_paginated(params)
end
@@ -71,7 +72,8 @@ defp cast_params(params) do
exclude_visibilities: {:array, :string},
reblogs: :boolean,
with_muted: :boolean,
- with_move: :boolean
+ with_move: :boolean,
+ account_ap_id: :string
}
changeset = cast({%{}, param_types}, params, Map.keys(param_types))
@@ -88,5 +90,9 @@ defp restrict(query, :exclude_types, %{exclude_types: mastodon_types = [_ | _]})
|> where([q, a], not fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data))
end
+ defp restrict(query, :account_ap_id, %{account_ap_id: account_ap_id}) do
+ where(query, [n, a], a.actor == ^account_ap_id)
+ end
+
defp restrict(query, _, _), do: query
end
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index e9590224b..b59ac39bc 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -253,6 +253,16 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity}
nil
end
+ emoji_reactions =
+ with %{data: %{"reactions" => emoji_reactions}} <- object do
+ Enum.map(emoji_reactions, fn {emoji, users} ->
+ {emoji, length(users)}
+ end)
+ |> Enum.into(%{})
+ else
+ _ -> %{}
+ end
+
%{
id: to_string(activity.id),
uri: object.data["id"],
@@ -293,7 +303,8 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity}
spoiler_text: %{"text/plain" => summary_plaintext},
expires_at: expires_at,
direct_conversation_id: direct_conversation_id,
- thread_muted: thread_muted?
+ thread_muted: thread_muted?,
+ emoji_reactions: emoji_reactions
}
}
end
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 87acdec97..5292aedf2 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -14,10 +14,10 @@ defmodule Pleroma.Web.OAuth.OAuthController do
alias Pleroma.Web.ControllerHelper
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization
+ alias Pleroma.Web.OAuth.Scopes
alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.OAuth.Token.Strategy.RefreshToken
alias Pleroma.Web.OAuth.Token.Strategy.Revoke, as: RevokeToken
- alias Pleroma.Web.OAuth.Scopes
require Logger
@@ -222,7 +222,7 @@ def token_exchange(
{:user_active, true} <- {:user_active, !user.deactivated},
{:password_reset_pending, false} <-
{:password_reset_pending, user.password_reset_pending},
- {:ok, scopes} <- validate_scopes(app, params, user),
+ {:ok, scopes} <- validate_scopes(app, params),
{:ok, auth} <- Authorization.create_authorization(app, user, scopes),
{:ok, token} <- Token.exchange_token(app, auth) do
json(conn, Token.Response.build(user, token))
@@ -471,7 +471,7 @@ defp do_create_authorization(
{:get_user, (user && {:ok, user}) || Authenticator.get_user(conn)},
%App{} = app <- Repo.get_by(App, client_id: client_id),
true <- redirect_uri in String.split(app.redirect_uris),
- {:ok, scopes} <- validate_scopes(app, auth_attrs, user),
+ {:ok, scopes} <- validate_scopes(app, auth_attrs),
{:auth_active, true} <- {:auth_active, User.auth_active?(user)} do
Authorization.create_authorization(app, user, scopes)
end
@@ -487,12 +487,12 @@ defp get_session_registration_id(%Plug.Conn{} = conn), do: get_session(conn, :re
defp put_session_registration_id(%Plug.Conn{} = conn, registration_id),
do: put_session(conn, :registration_id, registration_id)
- @spec validate_scopes(App.t(), map(), User.t()) ::
+ @spec validate_scopes(App.t(), map()) ::
{:ok, list()} | {:error, :missing_scopes | :unsupported_scopes}
- defp validate_scopes(%App{} = app, params, %User{} = user) do
+ defp validate_scopes(%App{} = app, params) do
params
|> Scopes.fetch_scopes(app.scopes)
- |> Scopes.validate(app.scopes, user)
+ |> Scopes.validate(app.scopes)
end
def default_redirect_uri(%App{} = app) do
diff --git a/lib/pleroma/web/oauth/scopes.ex b/lib/pleroma/web/oauth/scopes.ex
index 00da225b9..151467494 100644
--- a/lib/pleroma/web/oauth/scopes.ex
+++ b/lib/pleroma/web/oauth/scopes.ex
@@ -8,7 +8,6 @@ defmodule Pleroma.Web.OAuth.Scopes do
"""
alias Pleroma.Plugs.OAuthScopesPlug
- alias Pleroma.User
@doc """
Fetch scopes from request params.
@@ -56,35 +55,18 @@ def to_string(scopes), do: Enum.join(scopes, " ")
@doc """
Validates scopes.
"""
- @spec validate(list() | nil, list(), User.t()) ::
+ @spec validate(list() | nil, list()) ::
{:ok, list()} | {:error, :missing_scopes | :unsupported_scopes}
- def validate(blank_scopes, _app_scopes, _user) when blank_scopes in [nil, []],
+ def validate(blank_scopes, _app_scopes) when blank_scopes in [nil, []],
do: {:error, :missing_scopes}
- def validate(scopes, app_scopes, %User{} = user) do
- with {:ok, _} <- ensure_scopes_support(scopes, app_scopes),
- {:ok, scopes} <- authorize_admin_scopes(scopes, app_scopes, user) do
- {:ok, scopes}
- end
- end
-
- defp ensure_scopes_support(scopes, app_scopes) do
+ def validate(scopes, app_scopes) do
case OAuthScopesPlug.filter_descendants(scopes, app_scopes) do
^scopes -> {:ok, scopes}
_ -> {:error, :unsupported_scopes}
end
end
- defp authorize_admin_scopes(scopes, app_scopes, %User{} = user) do
- if user.is_admin || !contains_admin_scopes?(scopes) || !contains_admin_scopes?(app_scopes) do
- {:ok, scopes}
- else
- # Gracefully dropping admin scopes from requested scopes if user isn't an admin (not raising)
- scopes = scopes -- OAuthScopesPlug.filter_descendants(scopes, ["admin"])
- validate(scopes, app_scopes, user)
- end
- end
-
def contains_admin_scopes?(scopes) do
scopes
|> OAuthScopesPlug.filter_descendants(["admin"])
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 772c535a4..3285dc11b 100644
--- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
@@ -23,7 +23,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
plug(
OAuthScopesPlug,
%{scopes: ["read:statuses"]}
- when action in [:conversation, :conversation_statuses, :emoji_reactions_by]
+ when action in [:conversation, :conversation_statuses]
)
plug(
diff --git a/lib/pleroma/workers/attachments_cleanup_worker.ex b/lib/pleroma/workers/attachments_cleanup_worker.ex
new file mode 100644
index 000000000..3f421db40
--- /dev/null
+++ b/lib/pleroma/workers/attachments_cleanup_worker.ex
@@ -0,0 +1,88 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Workers.AttachmentsCleanupWorker do
+ import Ecto.Query
+
+ alias Pleroma.Object
+ alias Pleroma.Repo
+
+ use Pleroma.Workers.WorkerHelper, queue: "attachments_cleanup"
+
+ @impl Oban.Worker
+ def perform(
+ %{"object" => %{"data" => %{"attachment" => [_ | _] = attachments, "actor" => actor}}},
+ _job
+ ) do
+ hrefs =
+ Enum.flat_map(attachments, fn attachment ->
+ Enum.map(attachment["url"], & &1["href"])
+ end)
+
+ names = Enum.map(attachments, & &1["name"])
+
+ uploader = Pleroma.Config.get([Pleroma.Upload, :uploader])
+
+ # find all objects for copies of the attachments, name and actor doesn't matter here
+ delete_ids =
+ from(o in Object,
+ where:
+ fragment(
+ "to_jsonb(array(select jsonb_array_elements((?)#>'{url}') ->> 'href' where jsonb_typeof((?)#>'{url}') = 'array'))::jsonb \\?| (?)",
+ o.data,
+ o.data,
+ ^hrefs
+ )
+ )
+ # The query above can be time consumptive on large instances until we
+ # refactor how uploads are stored
+ |> Repo.all(timout: :infinity)
+ # we should delete 1 object for any given attachment, but don't delete
+ # files if there are more than 1 object for it
+ |> Enum.reduce(%{}, fn %{
+ id: id,
+ data: %{
+ "url" => [%{"href" => href}],
+ "actor" => obj_actor,
+ "name" => name
+ }
+ },
+ acc ->
+ Map.update(acc, href, %{id: id, count: 1}, fn val ->
+ case obj_actor == actor and name in names do
+ true ->
+ # set id of the actor's object that will be deleted
+ %{val | id: id, count: val.count + 1}
+
+ false ->
+ # another actor's object, just increase count to not delete file
+ %{val | count: val.count + 1}
+ end
+ end)
+ end)
+ |> Enum.map(fn {href, %{id: id, count: count}} ->
+ # only delete files that have single instance
+ with 1 <- count do
+ prefix =
+ case Pleroma.Config.get([Pleroma.Upload, :base_url]) do
+ nil -> "media"
+ _ -> ""
+ end
+
+ base_url = Pleroma.Config.get([__MODULE__, :base_url], Pleroma.Web.base_url())
+
+ file_path = String.trim_leading(href, "#{base_url}/#{prefix}")
+
+ uploader.delete_file(file_path)
+ end
+
+ id
+ end)
+
+ from(o in Object, where: o.id in ^delete_ids)
+ |> Repo.delete_all()
+ end
+
+ def perform(%{"object" => _object}, _job), do: :ok
+end
diff --git a/mix.exs b/mix.exs
index a9ad3dab0..76bf2848e 100644
--- a/mix.exs
+++ b/mix.exs
@@ -123,7 +123,7 @@ defp deps do
{:earmark, "~> 1.3"},
{:bbcode, "~> 0.1.1"},
{:ex_machina, "~> 2.3", only: :test},
- {:credo, "~> 0.9.3", only: [:dev, :test]},
+ {:credo, "~> 1.1.0", only: [:dev, :test], runtime: false},
{:mock, "~> 0.3.3", only: :test},
{:crypt,
git: "https://github.com/msantos/crypt", ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"},
diff --git a/mix.lock b/mix.lock
index 432d55e04..08ed8fb72 100644
--- a/mix.lock
+++ b/mix.lock
@@ -16,7 +16,7 @@
"cors_plug": {:hex, :cors_plug, "1.5.2", "72df63c87e4f94112f458ce9d25800900cc88608c1078f0e4faddf20933eda6e", [:mix], [{:plug, "~> 1.3 or ~> 1.4 or ~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"cowboy": {:hex, :cowboy, "2.7.0", "91ed100138a764355f43316b1d23d7ff6bdb0de4ea618cb5d8677c93a7a2f115", [:rebar3], [{:cowlib, "~> 2.8.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
"cowlib": {:hex, :cowlib, "2.8.0", "fd0ff1787db84ac415b8211573e9a30a3ebe71b5cbff7f720089972b2319c8a4", [:rebar3], [], "hexpm"},
- "credo": {:hex, :credo, "0.9.3", "76fa3e9e497ab282e0cf64b98a624aa11da702854c52c82db1bf24e54ab7c97a", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:poison, ">= 0.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
+ "credo": {:hex, :credo, "1.1.5", "caec7a3cadd2e58609d7ee25b3931b129e739e070539ad1a0cd7efeeb47014f4", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
"crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
"crypt": {:git, "https://github.com/msantos/crypt", "1f2b58927ab57e72910191a7ebaeff984382a1d3", [ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"]},
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm"},
@@ -63,7 +63,7 @@
"mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
"mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"},
- "mock": {:hex, :mock, "0.3.3", "42a433794b1291a9cf1525c6d26b38e039e0d3a360732b5e467bfc77ef26c914", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
+ "mock": {:hex, :mock, "0.3.4", "c5862eb3b8c64237f45f586cf00c9d892ba07bb48305a43319d428ce3c2897dd", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
"mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"},
"mox": {:hex, :mox, "0.5.1", "f86bb36026aac1e6f924a4b6d024b05e9adbed5c63e8daa069bd66fb3292165b", [:mix], [], "hexpm"},
"myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "ad0097e2f61d4953bfef20fb6abddf23b87111e6", [ref: "ad0097e2f61d4953bfef20fb6abddf23b87111e6", submodules: true]},
diff --git a/priv/repo/migrations/20191220174645_add_scopes_to_pleroma_feo_auth_records.exs b/priv/repo/migrations/20191220174645_add_scopes_to_pleroma_feo_auth_records.exs
new file mode 100644
index 000000000..6b160ad16
--- /dev/null
+++ b/priv/repo/migrations/20191220174645_add_scopes_to_pleroma_feo_auth_records.exs
@@ -0,0 +1,17 @@
+defmodule Pleroma.Repo.Migrations.AddScopesToPleromaFEOAuthRecords do
+ use Ecto.Migration
+
+ def up do
+ update_scopes_clause = "SET scopes = '{read,write,follow,push,admin}'"
+ apps_where = "WHERE apps.client_name like 'PleromaFE_%' or apps.client_name like 'AdminFE_%'"
+ app_id_subquery_where = "WHERE app_id IN (SELECT apps.id FROM apps #{apps_where})"
+
+ execute("UPDATE apps #{update_scopes_clause} #{apps_where}")
+
+ for table <- ["oauth_authorizations", "oauth_tokens"] do
+ execute("UPDATE #{table} #{update_scopes_clause} #{app_id_subquery_where}")
+ end
+ end
+
+ def down, do: :noop
+end
diff --git a/priv/static/adminfe/chunk-15fa.5a5f973d.css b/priv/static/adminfe/chunk-15fa.5a5f973d.css
new file mode 100644
index 000000000..30bf7de23
Binary files /dev/null and b/priv/static/adminfe/chunk-15fa.5a5f973d.css differ
diff --git a/priv/static/adminfe/chunk-18e1.dd09fe2e.css b/priv/static/adminfe/chunk-18e1.dd09fe2e.css
new file mode 100644
index 000000000..da819ca09
Binary files /dev/null and b/priv/static/adminfe/chunk-18e1.dd09fe2e.css differ
diff --git a/priv/static/adminfe/chunk-1ada.90dffac4.css b/priv/static/adminfe/chunk-1ada.90dffac4.css
new file mode 100644
index 000000000..c0074e6f7
Binary files /dev/null and b/priv/static/adminfe/chunk-1ada.90dffac4.css differ
diff --git a/priv/static/adminfe/chunk-2aa6.8ce63ac0.css b/priv/static/adminfe/chunk-2aa6.8ce63ac0.css
new file mode 100644
index 000000000..8bd6a2e50
Binary files /dev/null and b/priv/static/adminfe/chunk-2aa6.8ce63ac0.css differ
diff --git a/priv/static/adminfe/chunk-3d8e.48523459.css b/priv/static/adminfe/chunk-3d8e.48523459.css
new file mode 100644
index 000000000..8eefd9493
Binary files /dev/null and b/priv/static/adminfe/chunk-3d8e.48523459.css differ
diff --git a/priv/static/adminfe/chunk-4dc2.25d3bcab.css b/priv/static/adminfe/chunk-4dc2.25d3bcab.css
new file mode 100644
index 000000000..48784b9d2
Binary files /dev/null and b/priv/static/adminfe/chunk-4dc2.25d3bcab.css differ
diff --git a/priv/static/adminfe/chunk-6b7b.1ab4da3b.css b/priv/static/adminfe/chunk-6b7b.1ab4da3b.css
new file mode 100644
index 000000000..7124c9690
Binary files /dev/null and b/priv/static/adminfe/chunk-6b7b.1ab4da3b.css differ
diff --git a/priv/static/adminfe/chunk-6e77.57276c93.css b/priv/static/adminfe/chunk-6e77.57276c93.css
new file mode 100644
index 000000000..f0b3bf144
Binary files /dev/null and b/priv/static/adminfe/chunk-6e77.57276c93.css differ
diff --git a/priv/static/adminfe/chunk-7f83.f9f73c8e.css b/priv/static/adminfe/chunk-7f83.f9f73c8e.css
new file mode 100644
index 000000000..29f7b475d
Binary files /dev/null and b/priv/static/adminfe/chunk-7f83.f9f73c8e.css differ
diff --git a/priv/static/adminfe/chunk-7f8e.1d10e1c7.css b/priv/static/adminfe/chunk-7f8e.1d10e1c7.css
new file mode 100644
index 000000000..6cd674a28
Binary files /dev/null and b/priv/static/adminfe/chunk-7f8e.1d10e1c7.css differ
diff --git a/priv/static/adminfe/chunk-elementUI.1abbc9b8.css b/priv/static/adminfe/chunk-elementUI.1abbc9b8.css
new file mode 100644
index 000000000..c802d3a40
Binary files /dev/null and b/priv/static/adminfe/chunk-elementUI.1abbc9b8.css differ
diff --git a/priv/static/adminfe/chunk-elementUI.a842fb0a.css b/priv/static/adminfe/chunk-elementUI.a842fb0a.css
deleted file mode 100644
index 3fef5e5fd..000000000
Binary files a/priv/static/adminfe/chunk-elementUI.a842fb0a.css and /dev/null differ
diff --git a/priv/static/adminfe/index.html b/priv/static/adminfe/index.html
index d238accb5..e28125b5e 100644
--- a/priv/static/adminfe/index.html
+++ b/priv/static/adminfe/index.html
@@ -1 +1 @@
-
Admin FE
\ No newline at end of file
+Admin FE
\ No newline at end of file
diff --git a/priv/static/adminfe/static/js/app.19b7049e.js b/priv/static/adminfe/static/js/app.19b7049e.js
deleted file mode 100644
index d33589df4..000000000
Binary files a/priv/static/adminfe/static/js/app.19b7049e.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/app.19b7049e.js.map b/priv/static/adminfe/static/js/app.19b7049e.js.map
deleted file mode 100644
index 90c7816c0..000000000
Binary files a/priv/static/adminfe/static/js/app.19b7049e.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/app.3da0f475.js b/priv/static/adminfe/static/js/app.3da0f475.js
new file mode 100644
index 000000000..c6bd005d2
Binary files /dev/null and b/priv/static/adminfe/static/js/app.3da0f475.js differ
diff --git a/priv/static/adminfe/static/js/app.3da0f475.js.map b/priv/static/adminfe/static/js/app.3da0f475.js.map
new file mode 100644
index 000000000..999df6709
Binary files /dev/null and b/priv/static/adminfe/static/js/app.3da0f475.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-0cc4.35b47d0a.js b/priv/static/adminfe/static/js/chunk-0cc4.35b47d0a.js
deleted file mode 100644
index 71b39bb28..000000000
Binary files a/priv/static/adminfe/static/js/chunk-0cc4.35b47d0a.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-0cc4.35b47d0a.js.map b/priv/static/adminfe/static/js/chunk-0cc4.35b47d0a.js.map
deleted file mode 100644
index 4935ac41f..000000000
Binary files a/priv/static/adminfe/static/js/chunk-0cc4.35b47d0a.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-15fa.10871dbf.js b/priv/static/adminfe/static/js/chunk-15fa.34070731.js
similarity index 99%
rename from priv/static/adminfe/static/js/chunk-15fa.10871dbf.js
rename to priv/static/adminfe/static/js/chunk-15fa.34070731.js
index 8c7b033cf..937908d00 100644
Binary files a/priv/static/adminfe/static/js/chunk-15fa.10871dbf.js and b/priv/static/adminfe/static/js/chunk-15fa.34070731.js differ
diff --git a/priv/static/adminfe/static/js/chunk-15fa.10871dbf.js.map b/priv/static/adminfe/static/js/chunk-15fa.34070731.js.map
similarity index 99%
rename from priv/static/adminfe/static/js/chunk-15fa.10871dbf.js.map
rename to priv/static/adminfe/static/js/chunk-15fa.34070731.js.map
index a4b89ba68..d3830be7c 100644
Binary files a/priv/static/adminfe/static/js/chunk-15fa.10871dbf.js.map and b/priv/static/adminfe/static/js/chunk-15fa.34070731.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-18e1.9f7c9b0f.js b/priv/static/adminfe/static/js/chunk-18e1.c5abe3f2.js
similarity index 97%
rename from priv/static/adminfe/static/js/chunk-18e1.9f7c9b0f.js
rename to priv/static/adminfe/static/js/chunk-18e1.c5abe3f2.js
index 237c35b90..e0561aa1a 100644
Binary files a/priv/static/adminfe/static/js/chunk-18e1.9f7c9b0f.js and b/priv/static/adminfe/static/js/chunk-18e1.c5abe3f2.js differ
diff --git a/priv/static/adminfe/static/js/chunk-18e1.9f7c9b0f.js.map b/priv/static/adminfe/static/js/chunk-18e1.c5abe3f2.js.map
similarity index 98%
rename from priv/static/adminfe/static/js/chunk-18e1.9f7c9b0f.js.map
rename to priv/static/adminfe/static/js/chunk-18e1.c5abe3f2.js.map
index 2cfd1cfcc..27f79dceb 100644
Binary files a/priv/static/adminfe/static/js/chunk-18e1.9f7c9b0f.js.map and b/priv/static/adminfe/static/js/chunk-18e1.c5abe3f2.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-9bb0.9c56835f.js b/priv/static/adminfe/static/js/chunk-1ada.b41cb585.js
similarity index 97%
rename from priv/static/adminfe/static/js/chunk-9bb0.9c56835f.js
rename to priv/static/adminfe/static/js/chunk-1ada.b41cb585.js
index 3e9a3e795..b7bc3b278 100644
Binary files a/priv/static/adminfe/static/js/chunk-9bb0.9c56835f.js and b/priv/static/adminfe/static/js/chunk-1ada.b41cb585.js differ
diff --git a/priv/static/adminfe/static/js/chunk-9bb0.9c56835f.js.map b/priv/static/adminfe/static/js/chunk-1ada.b41cb585.js.map
similarity index 99%
rename from priv/static/adminfe/static/js/chunk-9bb0.9c56835f.js.map
rename to priv/static/adminfe/static/js/chunk-1ada.b41cb585.js.map
index 929c7ed14..27a2f8e5c 100644
Binary files a/priv/static/adminfe/static/js/chunk-9bb0.9c56835f.js.map and b/priv/static/adminfe/static/js/chunk-1ada.b41cb585.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-2aa6.be23b313.js b/priv/static/adminfe/static/js/chunk-2aa6.be23b313.js
new file mode 100644
index 000000000..21a0fde72
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-2aa6.be23b313.js differ
diff --git a/priv/static/adminfe/static/js/chunk-2aa6.be23b313.js.map b/priv/static/adminfe/static/js/chunk-2aa6.be23b313.js.map
new file mode 100644
index 000000000..64ac03193
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-2aa6.be23b313.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-3d8e.916ea1c1.js b/priv/static/adminfe/static/js/chunk-3d8e.916ea1c1.js
new file mode 100644
index 000000000..57831d50d
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-3d8e.916ea1c1.js differ
diff --git a/priv/static/adminfe/static/js/chunk-3d8e.916ea1c1.js.map b/priv/static/adminfe/static/js/chunk-3d8e.916ea1c1.js.map
new file mode 100644
index 000000000..a66a5fc00
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-3d8e.916ea1c1.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-1c46.b92c7c1b.js b/priv/static/adminfe/static/js/chunk-4dc2.ec296292.js
similarity index 98%
rename from priv/static/adminfe/static/js/chunk-1c46.b92c7c1b.js
rename to priv/static/adminfe/static/js/chunk-4dc2.ec296292.js
index c63a38759..f7cbe90c4 100644
Binary files a/priv/static/adminfe/static/js/chunk-1c46.b92c7c1b.js and b/priv/static/adminfe/static/js/chunk-4dc2.ec296292.js differ
diff --git a/priv/static/adminfe/static/js/chunk-1c46.b92c7c1b.js.map b/priv/static/adminfe/static/js/chunk-4dc2.ec296292.js.map
similarity index 99%
rename from priv/static/adminfe/static/js/chunk-1c46.b92c7c1b.js.map
rename to priv/static/adminfe/static/js/chunk-4dc2.ec296292.js.map
index a0d4a6655..898961dd6 100644
Binary files a/priv/static/adminfe/static/js/chunk-1c46.b92c7c1b.js.map and b/priv/static/adminfe/static/js/chunk-4dc2.ec296292.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-6b7b.e7ed7973.js b/priv/static/adminfe/static/js/chunk-6b7b.e7ed7973.js
new file mode 100644
index 000000000..3a2a7694b
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-6b7b.e7ed7973.js differ
diff --git a/priv/static/adminfe/static/js/chunk-6b7b.e7ed7973.js.map b/priv/static/adminfe/static/js/chunk-6b7b.e7ed7973.js.map
new file mode 100644
index 000000000..570df08e6
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-6b7b.e7ed7973.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-d01a.970cf312.js b/priv/static/adminfe/static/js/chunk-6e77.d1988eaf.js
similarity index 99%
rename from priv/static/adminfe/static/js/chunk-d01a.970cf312.js
rename to priv/static/adminfe/static/js/chunk-6e77.d1988eaf.js
index 7bbd51e24..9fef6e5dc 100644
Binary files a/priv/static/adminfe/static/js/chunk-d01a.970cf312.js and b/priv/static/adminfe/static/js/chunk-6e77.d1988eaf.js differ
diff --git a/priv/static/adminfe/static/js/chunk-d01a.970cf312.js.map b/priv/static/adminfe/static/js/chunk-6e77.d1988eaf.js.map
similarity index 99%
rename from priv/static/adminfe/static/js/chunk-d01a.970cf312.js.map
rename to priv/static/adminfe/static/js/chunk-6e77.d1988eaf.js.map
index da3fbc95a..4b756b70a 100644
Binary files a/priv/static/adminfe/static/js/chunk-d01a.970cf312.js.map and b/priv/static/adminfe/static/js/chunk-6e77.d1988eaf.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-7de9.7b8cda50.js b/priv/static/adminfe/static/js/chunk-7f83.1321eab8.js
similarity index 99%
rename from priv/static/adminfe/static/js/chunk-7de9.7b8cda50.js
rename to priv/static/adminfe/static/js/chunk-7f83.1321eab8.js
index 6311e5aa9..52c9efc2d 100644
Binary files a/priv/static/adminfe/static/js/chunk-7de9.7b8cda50.js and b/priv/static/adminfe/static/js/chunk-7f83.1321eab8.js differ
diff --git a/priv/static/adminfe/static/js/chunk-7de9.7b8cda50.js.map b/priv/static/adminfe/static/js/chunk-7f83.1321eab8.js.map
similarity index 99%
rename from priv/static/adminfe/static/js/chunk-7de9.7b8cda50.js.map
rename to priv/static/adminfe/static/js/chunk-7f83.1321eab8.js.map
index 2172dcc92..5a7d9d6a2 100644
Binary files a/priv/static/adminfe/static/js/chunk-7de9.7b8cda50.js.map and b/priv/static/adminfe/static/js/chunk-7f83.1321eab8.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-7f8e.2c3e63e9.js b/priv/static/adminfe/static/js/chunk-7f8e.0505d295.js
similarity index 99%
rename from priv/static/adminfe/static/js/chunk-7f8e.2c3e63e9.js
rename to priv/static/adminfe/static/js/chunk-7f8e.0505d295.js
index 06988ef73..43d8a02d8 100644
Binary files a/priv/static/adminfe/static/js/chunk-7f8e.2c3e63e9.js and b/priv/static/adminfe/static/js/chunk-7f8e.0505d295.js differ
diff --git a/priv/static/adminfe/static/js/chunk-7f8e.2c3e63e9.js.map b/priv/static/adminfe/static/js/chunk-7f8e.0505d295.js.map
similarity index 99%
rename from priv/static/adminfe/static/js/chunk-7f8e.2c3e63e9.js.map
rename to priv/static/adminfe/static/js/chunk-7f8e.0505d295.js.map
index bf96082a8..d1100abb0 100644
Binary files a/priv/static/adminfe/static/js/chunk-7f8e.2c3e63e9.js.map and b/priv/static/adminfe/static/js/chunk-7f8e.0505d295.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-7fe2.458f9da5.js b/priv/static/adminfe/static/js/chunk-7fe2.458f9da5.js
deleted file mode 100644
index ae8abe56d..000000000
Binary files a/priv/static/adminfe/static/js/chunk-7fe2.458f9da5.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-7fe2.458f9da5.js.map b/priv/static/adminfe/static/js/chunk-7fe2.458f9da5.js.map
deleted file mode 100644
index 34a06172f..000000000
Binary files a/priv/static/adminfe/static/js/chunk-7fe2.458f9da5.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-a601.cc880efe.js b/priv/static/adminfe/static/js/chunk-a601.cc880efe.js
deleted file mode 100644
index b30fe3033..000000000
Binary files a/priv/static/adminfe/static/js/chunk-a601.cc880efe.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-a601.cc880efe.js.map b/priv/static/adminfe/static/js/chunk-a601.cc880efe.js.map
deleted file mode 100644
index 5d2358da2..000000000
Binary files a/priv/static/adminfe/static/js/chunk-a601.cc880efe.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-elementUI.2de79b84.js b/priv/static/adminfe/static/js/chunk-elementUI.2de79b84.js
new file mode 100644
index 000000000..c76b0430b
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-elementUI.2de79b84.js differ
diff --git a/priv/static/adminfe/static/js/chunk-elementUI.2de79b84.js.map b/priv/static/adminfe/static/js/chunk-elementUI.2de79b84.js.map
new file mode 100644
index 000000000..fa9dc12f0
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-elementUI.2de79b84.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-elementUI.fa319e7b.js b/priv/static/adminfe/static/js/chunk-elementUI.fa319e7b.js
deleted file mode 100644
index 90ae35a35..000000000
Binary files a/priv/static/adminfe/static/js/chunk-elementUI.fa319e7b.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-elementUI.fa319e7b.js.map b/priv/static/adminfe/static/js/chunk-elementUI.fa319e7b.js.map
deleted file mode 100644
index 678122a98..000000000
Binary files a/priv/static/adminfe/static/js/chunk-elementUI.fa319e7b.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-f3c9.b3de53e2.js b/priv/static/adminfe/static/js/chunk-f3c9.b3de53e2.js
deleted file mode 100644
index 1c301e14a..000000000
Binary files a/priv/static/adminfe/static/js/chunk-f3c9.b3de53e2.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-f3c9.b3de53e2.js.map b/priv/static/adminfe/static/js/chunk-f3c9.b3de53e2.js.map
deleted file mode 100644
index 3b53caf53..000000000
Binary files a/priv/static/adminfe/static/js/chunk-f3c9.b3de53e2.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-libs.35c18287.js.map b/priv/static/adminfe/static/js/chunk-libs.35c18287.js.map
deleted file mode 100644
index 0a3580834..000000000
Binary files a/priv/static/adminfe/static/js/chunk-libs.35c18287.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-libs.35c18287.js b/priv/static/adminfe/static/js/chunk-libs.680db3fc.js
similarity index 94%
rename from priv/static/adminfe/static/js/chunk-libs.35c18287.js
rename to priv/static/adminfe/static/js/chunk-libs.680db3fc.js
index 4b76d98e6..478edf880 100644
Binary files a/priv/static/adminfe/static/js/chunk-libs.35c18287.js and b/priv/static/adminfe/static/js/chunk-libs.680db3fc.js differ
diff --git a/priv/static/adminfe/static/js/chunk-libs.680db3fc.js.map b/priv/static/adminfe/static/js/chunk-libs.680db3fc.js.map
new file mode 100644
index 000000000..f8c92c2fa
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-libs.680db3fc.js.map differ
diff --git a/priv/static/adminfe/static/js/runtime.cab03b3e.js b/priv/static/adminfe/static/js/runtime.cab03b3e.js
new file mode 100644
index 000000000..f700f7ccc
Binary files /dev/null and b/priv/static/adminfe/static/js/runtime.cab03b3e.js differ
diff --git a/priv/static/adminfe/static/js/runtime.cab03b3e.js.map b/priv/static/adminfe/static/js/runtime.cab03b3e.js.map
new file mode 100644
index 000000000..eca2ddd29
Binary files /dev/null and b/priv/static/adminfe/static/js/runtime.cab03b3e.js.map differ
diff --git a/priv/static/adminfe/static/js/runtime.d6d1aaab.js b/priv/static/adminfe/static/js/runtime.d6d1aaab.js
deleted file mode 100644
index ca1a91002..000000000
Binary files a/priv/static/adminfe/static/js/runtime.d6d1aaab.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/runtime.d6d1aaab.js.map b/priv/static/adminfe/static/js/runtime.d6d1aaab.js.map
deleted file mode 100644
index b938f1ba6..000000000
Binary files a/priv/static/adminfe/static/js/runtime.d6d1aaab.js.map and /dev/null differ
diff --git a/priv/static/index.html b/priv/static/index.html
index 2467aa22a..b0aadb1a1 100644
--- a/priv/static/index.html
+++ b/priv/static/index.html
@@ -1 +1 @@
-Pleroma
\ No newline at end of file
+Pleroma
\ No newline at end of file
diff --git a/priv/static/static/font/fontello.1576166651574.woff b/priv/static/static/font/fontello.1576166651574.woff
deleted file mode 100644
index bbffd6413..000000000
Binary files a/priv/static/static/font/fontello.1576166651574.woff and /dev/null differ
diff --git a/priv/static/static/font/fontello.1576166651574.woff2 b/priv/static/static/font/fontello.1576166651574.woff2
deleted file mode 100644
index d35dce862..000000000
Binary files a/priv/static/static/font/fontello.1576166651574.woff2 and /dev/null differ
diff --git a/priv/static/static/font/fontello.1576166651574.eot b/priv/static/static/font/fontello.1579102213354.eot
similarity index 80%
rename from priv/static/static/font/fontello.1576166651574.eot
rename to priv/static/static/font/fontello.1579102213354.eot
index fb27d4037..160cfa9f6 100644
Binary files a/priv/static/static/font/fontello.1576166651574.eot and b/priv/static/static/font/fontello.1579102213354.eot differ
diff --git a/priv/static/static/font/fontello.1576166651574.svg b/priv/static/static/font/fontello.1579102213354.svg
old mode 100755
new mode 100644
similarity index 89%
rename from priv/static/static/font/fontello.1576166651574.svg
rename to priv/static/static/font/fontello.1579102213354.svg
index f5e497ce4..44beba9a2
--- a/priv/static/static/font/fontello.1576166651574.svg
+++ b/priv/static/static/font/fontello.1579102213354.svg
@@ -1,7 +1,7 @@