Merge branch 'develop' into fix/attachments-cleanup
This commit is contained in:
commit
390bf9b097
|
@ -6,10 +6,6 @@ variables: &global_variables
|
||||||
POSTGRES_PASSWORD: postgres
|
POSTGRES_PASSWORD: postgres
|
||||||
DB_HOST: postgres
|
DB_HOST: postgres
|
||||||
MIX_ENV: test
|
MIX_ENV: test
|
||||||
DOCKER_DRIVER: overlay2
|
|
||||||
DOCKER_HOST: unix:///var/run/docker.sock
|
|
||||||
DOCKER_IMAGE: $CI_REGISTRY_IMAGE:latest
|
|
||||||
DOCKER_IMAGE_SHA: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
|
|
||||||
|
|
||||||
cache: &global_cache_policy
|
cache: &global_cache_policy
|
||||||
key: ${CI_COMMIT_REF_SLUG}
|
key: ${CI_COMMIT_REF_SLUG}
|
||||||
|
@ -274,16 +270,62 @@ arm64-musl:
|
||||||
docker:
|
docker:
|
||||||
stage: docker
|
stage: docker
|
||||||
image: docker:latest
|
image: docker:latest
|
||||||
tags:
|
cache: {}
|
||||||
- dind
|
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
|
before_script: &before-docker
|
||||||
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
- 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_JOB_TIMESTAMP=$(date --utc -Iseconds)
|
||||||
- export CI_VCS_REF=$CI_COMMIT_SHORT_SHA
|
- export CI_VCS_REF=$CI_COMMIT_SHORT_SHA
|
||||||
|
allow_failure: true
|
||||||
script:
|
script:
|
||||||
- docker pull $DOCKER_IMAGE || true
|
- 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 build --cache-from $DOCKER_IMAGE --build-arg VCS_REF=$CI_VCS_REF --build-arg BUILD_DATE=$CI_JOB_TIMESTAMP -t $DOCKER_IMAGE_SHA -t $DOCKER_IMAGE .
|
- docker push $IMAGE_TAG
|
||||||
- docker push $DOCKER_IMAGE_SHA
|
- docker push $IMAGE_TAG_SLUG
|
||||||
- docker push $DOCKER_IMAGE
|
- docker push $IMAGE_TAG_LATEST
|
||||||
|
tags:
|
||||||
|
- dind
|
||||||
only:
|
only:
|
||||||
- develop
|
- 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
|
||||||
|
|
|
@ -10,9 +10,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- **Breaking**: MDII uploader
|
- **Breaking**: MDII uploader
|
||||||
|
|
||||||
### Changed
|
### 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:** 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:** 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:** 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)
|
- 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
|
- Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler
|
||||||
- Enabled `:instance, extended_nickname_format` in the default config
|
- 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.
|
- Mastodon API, streaming: Add `pleroma.direct_conversation_id` to the `conversation` stream event payload.
|
||||||
- Admin API: Render whole status in grouped reports
|
- 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: 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.
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -90,6 +93,7 @@ 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.
|
- Mastodon API: `/api/v1/update_credentials` accepts `actor_type` field.
|
||||||
- Captcha: Support native provider
|
- Captcha: Support native provider
|
||||||
- Captcha: Enable by default
|
- Captcha: Enable by default
|
||||||
|
- Mastodon API: Add support for `account_id` param to filter notifications by the account
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -9,7 +9,7 @@ def generate_like_activities(user, posts) do
|
||||||
{time, _} =
|
{time, _} =
|
||||||
:timer.tc(fn ->
|
:timer.tc(fn ->
|
||||||
Task.async_stream(
|
Task.async_stream(
|
||||||
Enum.take_random(posts, count_likes),
|
Enum.take_random(posts, count_likes),
|
||||||
fn post -> {:ok, _, _} = CommonAPI.favorite(post.id, user) end,
|
fn post -> {:ok, _, _} = CommonAPI.favorite(post.id, user) end,
|
||||||
max_concurrency: 10,
|
max_concurrency: 10,
|
||||||
timeout: 30_000
|
timeout: 30_000
|
||||||
|
@ -142,6 +142,48 @@ defp do_generate_activity(users) do
|
||||||
CommonAPI.post(Enum.random(users), post)
|
CommonAPI.post(Enum.random(users), post)
|
||||||
end
|
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
|
defp do_generate_activity_with_mention(user, users) do
|
||||||
mentions_cnt = Enum.random([2, 3, 4, 5])
|
mentions_cnt = Enum.random([2, 3, 4, 5])
|
||||||
with_user = Enum.random([true, false])
|
with_user = Enum.random([true, false])
|
||||||
|
|
|
@ -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
|
|
@ -561,7 +561,7 @@
|
||||||
|
|
||||||
config :pleroma,
|
config :pleroma,
|
||||||
:auth,
|
:auth,
|
||||||
enforce_oauth_admin_scope_usage: false,
|
enforce_oauth_admin_scope_usage: true,
|
||||||
oauth_consumer_strategies: oauth_consumer_strategies
|
oauth_consumer_strategies: oauth_consumer_strategies
|
||||||
|
|
||||||
config :pleroma, Pleroma.Emails.Mailer, adapter: Swoosh.Adapters.Sendmail, enabled: false
|
config :pleroma, Pleroma.Emails.Mailer, adapter: Swoosh.Adapters.Sendmail, enabled: false
|
||||||
|
|
|
@ -33,6 +33,7 @@ def user_agent do
|
||||||
def start(_type, _args) do
|
def start(_type, _args) do
|
||||||
Pleroma.HTML.compile_scrubbers()
|
Pleroma.HTML.compile_scrubbers()
|
||||||
Pleroma.Config.DeprecationWarnings.warn()
|
Pleroma.Config.DeprecationWarnings.warn()
|
||||||
|
Pleroma.Repo.check_migrations_applied!()
|
||||||
setup_instrumenters()
|
setup_instrumenters()
|
||||||
load_custom_modules()
|
load_custom_modules()
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ def call(%{assigns: %{user: %User{is_admin: true}} = assigns} = conn, _) do
|
||||||
token && OAuth.Scopes.contains_admin_scopes?(token.scopes) ->
|
token && OAuth.Scopes.contains_admin_scopes?(token.scopes) ->
|
||||||
# Note: checking for _any_ admin scope presence, not necessarily fitting requested action.
|
# Note: checking for _any_ admin scope presence, not necessarily fitting requested action.
|
||||||
# Thus, controller must explicitly invoke OAuthScopesPlug to verify scope requirements.
|
# 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
|
conn
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
|
|
|
@ -8,6 +8,8 @@ defmodule Pleroma.Repo do
|
||||||
adapter: Ecto.Adapters.Postgres,
|
adapter: Ecto.Adapters.Postgres,
|
||||||
migration_timestamps: [type: :naive_datetime_usec]
|
migration_timestamps: [type: :naive_datetime_usec]
|
||||||
|
|
||||||
|
require Logger
|
||||||
|
|
||||||
defmodule Instrumenter do
|
defmodule Instrumenter do
|
||||||
use Prometheus.EctoInstrumenter
|
use Prometheus.EctoInstrumenter
|
||||||
end
|
end
|
||||||
|
@ -47,4 +49,37 @@ def get_assoc(resource, association) do
|
||||||
_ -> {:error, :not_found}
|
_ -> {:error, :not_found}
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
|
@ -1874,22 +1874,13 @@ defp truncate_field(%{"name" => name, "value" => value}) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def admin_api_update(user, params) do
|
def admin_api_update(user, params) do
|
||||||
changeset =
|
user
|
||||||
cast(user, params, [
|
|> cast(params, [
|
||||||
:is_moderator,
|
:is_moderator,
|
||||||
:is_admin,
|
:is_admin,
|
||||||
:show_role
|
:show_role
|
||||||
])
|
])
|
||||||
|
|> update_and_set_cache()
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "Signs user out of all applications"
|
@doc "Signs user out of all applications"
|
||||||
|
|
|
@ -20,7 +20,7 @@ def filter(%{"type" => message_type} = message) do
|
||||||
with accepted_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :accept]),
|
with accepted_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :accept]),
|
||||||
rejected_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :reject]),
|
rejected_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :reject]),
|
||||||
true <-
|
true <-
|
||||||
length(accepted_vocabulary) == 0 || Enum.member?(accepted_vocabulary, message_type),
|
Enum.empty?(accepted_vocabulary) || Enum.member?(accepted_vocabulary, message_type),
|
||||||
false <-
|
false <-
|
||||||
length(rejected_vocabulary) > 0 && Enum.member?(rejected_vocabulary, message_type),
|
length(rejected_vocabulary) > 0 && Enum.member?(rejected_vocabulary, message_type),
|
||||||
{:ok, _} <- filter(message["object"]) do
|
{:ok, _} <- filter(message["object"]) do
|
||||||
|
|
|
@ -658,24 +658,8 @@ def handle_incoming(
|
||||||
with %User{ap_id: ^actor_id} = actor <- User.get_cached_by_ap_id(object["id"]) do
|
with %User{ap_id: ^actor_id} = actor <- User.get_cached_by_ap_id(object["id"]) do
|
||||||
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)
|
{: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
|
actor
|
||||||
|> User.upgrade_changeset(update_data, true)
|
|> User.upgrade_changeset(new_user_data, true)
|
||||||
|> User.update_and_set_cache()
|
|> User.update_and_set_cache()
|
||||||
|
|
||||||
ActivityPub.update(%{
|
ActivityPub.update(%{
|
||||||
|
|
|
@ -32,19 +32,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
||||||
plug(
|
plug(
|
||||||
OAuthScopesPlug,
|
OAuthScopesPlug,
|
||||||
%{scopes: ["read:accounts"], admin: true}
|
%{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(
|
plug(
|
||||||
OAuthScopesPlug,
|
OAuthScopesPlug,
|
||||||
%{scopes: ["write:accounts"], admin: true}
|
%{scopes: ["write:accounts"], admin: true}
|
||||||
when action in [
|
when action in [
|
||||||
:get_invite_token,
|
|
||||||
:revoke_invite,
|
|
||||||
:email_invite,
|
|
||||||
:get_password_reset,
|
:get_password_reset,
|
||||||
:user_follow,
|
|
||||||
:user_unfollow,
|
|
||||||
:user_delete,
|
:user_delete,
|
||||||
:users_create,
|
:users_create,
|
||||||
:user_toggle_activation,
|
: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(
|
plug(
|
||||||
OAuthScopesPlug,
|
OAuthScopesPlug,
|
||||||
%{scopes: ["read:reports"], admin: true}
|
%{scopes: ["read:reports"], admin: true}
|
||||||
|
@ -66,7 +75,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
||||||
plug(
|
plug(
|
||||||
OAuthScopesPlug,
|
OAuthScopesPlug,
|
||||||
%{scopes: ["write:reports"], admin: true}
|
%{scopes: ["write:reports"], admin: true}
|
||||||
when action in [:report_update_state, :report_respond]
|
when action in [:reports_update]
|
||||||
)
|
)
|
||||||
|
|
||||||
plug(
|
plug(
|
||||||
|
@ -90,7 +99,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
||||||
plug(
|
plug(
|
||||||
OAuthScopesPlug,
|
OAuthScopesPlug,
|
||||||
%{scopes: ["write"], admin: true}
|
%{scopes: ["write"], admin: true}
|
||||||
when action in [:relay_follow, :relay_unfollow, :config_update]
|
when action == :config_update
|
||||||
)
|
)
|
||||||
|
|
||||||
@users_page_size 50
|
@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
|
def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
|
||||||
users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
|
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(%{
|
ModerationLog.insert_log(%{
|
||||||
actor: admin,
|
actor: admin,
|
||||||
|
|
|
@ -85,9 +85,13 @@ def delete(activity_id, user) do
|
||||||
def repeat(id_or_ap_id, user, params \\ %{}) do
|
def repeat(id_or_ap_id, user, params \\ %{}) do
|
||||||
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
|
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
|
||||||
object <- Object.normalize(activity),
|
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
|
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
|
else
|
||||||
_ -> {:error, dgettext("errors", "Could not repeat")}
|
_ -> {:error, dgettext("errors", "Could not repeat")}
|
||||||
end
|
end
|
||||||
|
@ -105,8 +109,12 @@ def unrepeat(id_or_ap_id, user) do
|
||||||
def favorite(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),
|
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
|
||||||
object <- Object.normalize(activity),
|
object <- Object.normalize(activity),
|
||||||
nil <- Utils.get_existing_like(user.ap_id, object) do
|
like_activity <- Utils.get_existing_like(user.ap_id, object) do
|
||||||
ActivityPub.like(user, object)
|
if like_activity do
|
||||||
|
{:ok, like_activity, object}
|
||||||
|
else
|
||||||
|
ActivityPub.like(user, object)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
_ -> {:error, dgettext("errors", "Could not favorite")}
|
_ -> {:error, dgettext("errors", "Could not favorite")}
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,6 +23,23 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
|
||||||
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
|
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
|
||||||
|
|
||||||
# GET /api/v1/notifications
|
# 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
|
def index(%{assigns: %{user: user}} = conn, params) do
|
||||||
notifications = MastodonAPI.get_notifications(user, params)
|
notifications = MastodonAPI.get_notifications(user, params)
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,9 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionController do
|
||||||
@moduledoc "The module represents functions to manage user subscriptions."
|
@moduledoc "The module represents functions to manage user subscriptions."
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
|
alias Pleroma.Web.MastodonAPI.PushSubscriptionView, as: View
|
||||||
alias Pleroma.Web.Push
|
alias Pleroma.Web.Push
|
||||||
alias Pleroma.Web.Push.Subscription
|
alias Pleroma.Web.Push.Subscription
|
||||||
alias Pleroma.Web.MastodonAPI.PushSubscriptionView, as: View
|
|
||||||
|
|
||||||
action_fallback(:errors)
|
action_fallback(:errors)
|
||||||
|
|
||||||
|
|
|
@ -77,10 +77,7 @@ def public(%{assigns: %{user: user}} = conn, params) do
|
||||||
|> render("index.json", activities: activities, for: user, as: :activity)
|
|> render("index.json", activities: activities, for: user, as: :activity)
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET /api/v1/timelines/tag/:tag
|
def hashtag_fetching(params, user, local_only) do
|
||||||
def hashtag(%{assigns: %{user: user}} = conn, params) do
|
|
||||||
local_only = truthy_param?(params["local"])
|
|
||||||
|
|
||||||
tags =
|
tags =
|
||||||
[params["tag"], params["any"]]
|
[params["tag"], params["any"]]
|
||||||
|> List.flatten()
|
|> List.flatten()
|
||||||
|
@ -98,7 +95,7 @@ def hashtag(%{assigns: %{user: user}} = conn, params) do
|
||||||
|> Map.get("none", [])
|
|> Map.get("none", [])
|
||||||
|> Enum.map(&String.downcase(&1))
|
|> Enum.map(&String.downcase(&1))
|
||||||
|
|
||||||
activities =
|
_activities =
|
||||||
params
|
params
|
||||||
|> Map.put("type", "Create")
|
|> Map.put("type", "Create")
|
||||||
|> Map.put("local_only", local_only)
|
|> 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_all", tag_all)
|
||||||
|> Map.put("tag_reject", tag_reject)
|
|> Map.put("tag_reject", tag_reject)
|
||||||
|> ActivityPub.fetch_public_activities()
|
|> 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
|
conn
|
||||||
|> add_link_headers(activities, %{"local" => local_only})
|
|> add_link_headers(activities, %{"local" => local_only})
|
||||||
|
|
|
@ -56,6 +56,7 @@ def get_notifications(user, params \\ %{}) do
|
||||||
user
|
user
|
||||||
|> Notification.for_user_query(options)
|
|> Notification.for_user_query(options)
|
||||||
|> restrict(:exclude_types, options)
|
|> restrict(:exclude_types, options)
|
||||||
|
|> restrict(:account_ap_id, options)
|
||||||
|> Pagination.fetch_paginated(params)
|
|> Pagination.fetch_paginated(params)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -71,7 +72,8 @@ defp cast_params(params) do
|
||||||
exclude_visibilities: {:array, :string},
|
exclude_visibilities: {:array, :string},
|
||||||
reblogs: :boolean,
|
reblogs: :boolean,
|
||||||
with_muted: :boolean,
|
with_muted: :boolean,
|
||||||
with_move: :boolean
|
with_move: :boolean,
|
||||||
|
account_ap_id: :string
|
||||||
}
|
}
|
||||||
|
|
||||||
changeset = cast({%{}, param_types}, params, Map.keys(param_types))
|
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))
|
|> where([q, a], not fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data))
|
||||||
end
|
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
|
defp restrict(query, _, _), do: query
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,10 +14,10 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
||||||
alias Pleroma.Web.ControllerHelper
|
alias Pleroma.Web.ControllerHelper
|
||||||
alias Pleroma.Web.OAuth.App
|
alias Pleroma.Web.OAuth.App
|
||||||
alias Pleroma.Web.OAuth.Authorization
|
alias Pleroma.Web.OAuth.Authorization
|
||||||
|
alias Pleroma.Web.OAuth.Scopes
|
||||||
alias Pleroma.Web.OAuth.Token
|
alias Pleroma.Web.OAuth.Token
|
||||||
alias Pleroma.Web.OAuth.Token.Strategy.RefreshToken
|
alias Pleroma.Web.OAuth.Token.Strategy.RefreshToken
|
||||||
alias Pleroma.Web.OAuth.Token.Strategy.Revoke, as: RevokeToken
|
alias Pleroma.Web.OAuth.Token.Strategy.Revoke, as: RevokeToken
|
||||||
alias Pleroma.Web.OAuth.Scopes
|
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ def token_exchange(
|
||||||
{:user_active, true} <- {:user_active, !user.deactivated},
|
{:user_active, true} <- {:user_active, !user.deactivated},
|
||||||
{:password_reset_pending, false} <-
|
{:password_reset_pending, false} <-
|
||||||
{:password_reset_pending, user.password_reset_pending},
|
{: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, auth} <- Authorization.create_authorization(app, user, scopes),
|
||||||
{:ok, token} <- Token.exchange_token(app, auth) do
|
{:ok, token} <- Token.exchange_token(app, auth) do
|
||||||
json(conn, Token.Response.build(user, token))
|
json(conn, Token.Response.build(user, token))
|
||||||
|
@ -471,7 +471,7 @@ defp do_create_authorization(
|
||||||
{:get_user, (user && {:ok, user}) || Authenticator.get_user(conn)},
|
{:get_user, (user && {:ok, user}) || Authenticator.get_user(conn)},
|
||||||
%App{} = app <- Repo.get_by(App, client_id: client_id),
|
%App{} = app <- Repo.get_by(App, client_id: client_id),
|
||||||
true <- redirect_uri in String.split(app.redirect_uris),
|
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
|
{:auth_active, true} <- {:auth_active, User.auth_active?(user)} do
|
||||||
Authorization.create_authorization(app, user, scopes)
|
Authorization.create_authorization(app, user, scopes)
|
||||||
end
|
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),
|
defp put_session_registration_id(%Plug.Conn{} = conn, registration_id),
|
||||||
do: put_session(conn, :registration_id, 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}
|
{:ok, list()} | {:error, :missing_scopes | :unsupported_scopes}
|
||||||
defp validate_scopes(%App{} = app, params, %User{} = user) do
|
defp validate_scopes(%App{} = app, params) do
|
||||||
params
|
params
|
||||||
|> Scopes.fetch_scopes(app.scopes)
|
|> Scopes.fetch_scopes(app.scopes)
|
||||||
|> Scopes.validate(app.scopes, user)
|
|> Scopes.validate(app.scopes)
|
||||||
end
|
end
|
||||||
|
|
||||||
def default_redirect_uri(%App{} = app) do
|
def default_redirect_uri(%App{} = app) do
|
||||||
|
|
|
@ -8,7 +8,6 @@ defmodule Pleroma.Web.OAuth.Scopes do
|
||||||
"""
|
"""
|
||||||
|
|
||||||
alias Pleroma.Plugs.OAuthScopesPlug
|
alias Pleroma.Plugs.OAuthScopesPlug
|
||||||
alias Pleroma.User
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Fetch scopes from request params.
|
Fetch scopes from request params.
|
||||||
|
@ -56,35 +55,18 @@ def to_string(scopes), do: Enum.join(scopes, " ")
|
||||||
@doc """
|
@doc """
|
||||||
Validates scopes.
|
Validates scopes.
|
||||||
"""
|
"""
|
||||||
@spec validate(list() | nil, list(), User.t()) ::
|
@spec validate(list() | nil, list()) ::
|
||||||
{:ok, list()} | {:error, :missing_scopes | :unsupported_scopes}
|
{: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}
|
do: {:error, :missing_scopes}
|
||||||
|
|
||||||
def validate(scopes, app_scopes, %User{} = user) do
|
def validate(scopes, app_scopes) 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
|
|
||||||
case OAuthScopesPlug.filter_descendants(scopes, app_scopes) do
|
case OAuthScopesPlug.filter_descendants(scopes, app_scopes) do
|
||||||
^scopes -> {:ok, scopes}
|
^scopes -> {:ok, scopes}
|
||||||
_ -> {:error, :unsupported_scopes}
|
_ -> {:error, :unsupported_scopes}
|
||||||
end
|
end
|
||||||
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
|
def contains_admin_scopes?(scopes) do
|
||||||
scopes
|
scopes
|
||||||
|> OAuthScopesPlug.filter_descendants(["admin"])
|
|> OAuthScopesPlug.filter_descendants(["admin"])
|
||||||
|
|
|
@ -23,7 +23,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
|
||||||
plug(
|
plug(
|
||||||
OAuthScopesPlug,
|
OAuthScopesPlug,
|
||||||
%{scopes: ["read:statuses"]}
|
%{scopes: ["read:statuses"]}
|
||||||
when action in [:conversation, :conversation_statuses, :emoji_reactions_by]
|
when action in [:conversation, :conversation_statuses]
|
||||||
)
|
)
|
||||||
|
|
||||||
plug(
|
plug(
|
||||||
|
|
2
mix.exs
2
mix.exs
|
@ -124,7 +124,7 @@ defp deps do
|
||||||
{:earmark, "~> 1.3"},
|
{:earmark, "~> 1.3"},
|
||||||
{:bbcode, "~> 0.1.1"},
|
{:bbcode, "~> 0.1.1"},
|
||||||
{:ex_machina, "~> 2.3", only: :test},
|
{: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},
|
{:mock, "~> 0.3.3", only: :test},
|
||||||
{:crypt,
|
{:crypt,
|
||||||
git: "https://github.com/msantos/crypt", ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"},
|
git: "https://github.com/msantos/crypt", ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"},
|
||||||
|
|
4
mix.lock
4
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"},
|
"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"},
|
"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"},
|
"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"},
|
"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"]},
|
"crypt": {:git, "https://github.com/msantos/crypt", "1f2b58927ab57e72910191a7ebaeff984382a1d3", [ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"]},
|
||||||
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm"},
|
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm"},
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
"mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"},
|
"mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"},
|
||||||
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
|
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
|
||||||
"mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [: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"},
|
"mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"},
|
||||||
"mox": {:hex, :mox, "0.5.1", "f86bb36026aac1e6f924a4b6d024b05e9adbed5c63e8daa069bd66fb3292165b", [: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]},
|
"myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "ad0097e2f61d4953bfef20fb6abddf23b87111e6", [ref: "ad0097e2f61d4953bfef20fb6abddf23b87111e6", submodules: true]},
|
||||||
|
|
|
@ -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
|
|
@ -1 +1 @@
|
||||||
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1,user-scalable=no"><title>Pleroma</title><!--server-generated-meta--><link rel=icon type=image/png href=/favicon.png><link href=/static/css/vendors~app.b2603a50868c68a1c192.css rel=stylesheet><link href=/static/css/app.ae04505b31bb0ee2765e.css rel=stylesheet><link href=/static/fontello.1576166651574.css rel=stylesheet></head><body class=hidden><noscript>To use Pleroma, please enable JavaScript.</noscript><div id=app></div><script type=text/javascript src=/static/js/vendors~app.3f1ed7a4fdfc37ee27a7.js></script><script type=text/javascript src=/static/js/app.a9b3f4c3e79baf3fa8b7.js></script></body></html>
|
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1,user-scalable=no"><title>Pleroma</title><!--server-generated-meta--><link rel=icon type=image/png href=/favicon.png><link href=/static/css/vendors~app.b2603a50868c68a1c192.css rel=stylesheet><link href=/static/css/app.ae04505b31bb0ee2765e.css rel=stylesheet><link href=/static/fontello.1579102213354.css rel=stylesheet></head><body class=hidden><noscript>To use Pleroma, please enable JavaScript.</noscript><div id=app></div><script type=text/javascript src=/static/js/vendors~app.86bc6d5e06d2e17976c5.js></script><script type=text/javascript src=/static/js/app.a43640742dacfb13b6b0.js></script></body></html>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
14
priv/static/static/font/fontello.1576166651574.svg → priv/static/static/font/fontello.1579102213354.svg
Executable file → Normal file
14
priv/static/static/font/fontello.1576166651574.svg → priv/static/static/font/fontello.1579102213354.svg
Executable file → Normal file
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" standalone="no"?>
|
<?xml version="1.0" standalone="no"?>
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg">
|
<svg xmlns="http://www.w3.org/2000/svg">
|
||||||
<metadata>Copyright (C) 2019 by original authors @ fontello.com</metadata>
|
<metadata>Copyright (C) 2020 by original authors @ fontello.com</metadata>
|
||||||
<defs>
|
<defs>
|
||||||
<font id="fontello" horiz-adv-x="1000" >
|
<font id="fontello" horiz-adv-x="1000" >
|
||||||
<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="857" descent="-143" />
|
<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="857" descent="-143" />
|
||||||
|
@ -64,6 +64,18 @@
|
||||||
|
|
||||||
<glyph glyph-name="zoom-in" unicode="" d="M571 411v-36q0-7-5-13t-12-5h-125v-125q0-7-6-13t-12-5h-36q-7 0-13 5t-5 13v125h-125q-7 0-12 5t-6 13v36q0 7 6 12t12 5h125v125q0 8 5 13t13 5h36q7 0 12-5t6-13v-125h125q7 0 12-5t5-12z m72-18q0 103-73 176t-177 74-177-74-73-176 73-177 177-73 177 73 73 177z m286-465q0-29-21-50t-51-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 153-31 125-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" />
|
<glyph glyph-name="zoom-in" unicode="" d="M571 411v-36q0-7-5-13t-12-5h-125v-125q0-7-6-13t-12-5h-36q-7 0-13 5t-5 13v125h-125q-7 0-12 5t-6 13v36q0 7 6 12t12 5h125v125q0 8 5 13t13 5h36q7 0 12-5t6-13v-125h125q7 0 12-5t5-12z m72-18q0 103-73 176t-177 74-177-74-73-176 73-177 177-73 177 73 73 177z m286-465q0-29-21-50t-51-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 153-31 125-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" />
|
||||||
|
|
||||||
|
<glyph glyph-name="users" unicode="" d="M331 357q-90-3-148-71h-75q-45 0-77 22t-31 66q0 197 69 197 4 0 25-11t54-24 66-12q38 0 75 13-3-21-3-37 0-78 45-143z m598-355q0-67-41-106t-108-39h-488q-68 0-108 39t-41 106q0 29 2 57t8 61 14 61 24 54 35 45 48 30 62 11q6 0 24-12t41-26 59-27 76-12 75 12 60 27 41 26 24 12q34 0 62-11t47-30 35-45 24-54 15-61 8-61 2-57z m-572 712q0-59-42-101t-101-42-101 42-42 101 42 101 101 42 101-42 42-101z m393-214q0-89-63-152t-151-62-152 62-63 152 63 151 152 63 151-63 63-151z m321-126q0-43-31-66t-77-22h-75q-57 68-147 71 45 65 45 143 0 16-3 37 37-13 74-13 33 0 67 12t54 24 24 11q69 0 69-197z m-71 340q0-59-42-101t-101-42-101 42-42 101 42 101 101 42 101-42 42-101z" horiz-adv-x="1071.4" />
|
||||||
|
|
||||||
|
<glyph glyph-name="chat" unicode="" d="M786 428q0-77-53-143t-143-104-197-38q-48 0-98 9-70-49-155-72-21-5-48-9h-2q-6 0-12 5t-6 12q-1 1-1 3t1 4 1 3l1 3t2 3 2 3 3 3 2 2q3 3 13 14t15 16 12 17 14 21 11 25q-69 40-108 98t-40 125q0 78 53 144t143 104 197 38 197-38 143-104 53-144z m214-142q0-67-40-126t-108-98q5-14 11-25t14-21 13-16 14-17 13-14q0 0 2-2t3-3 2-3 2-3l1-3t1-3 1-4-1-3q-2-8-7-13t-12-4q-28 4-48 9-86 23-156 72-50-9-98-9-151 0-263 74 32-3 49-3 90 0 172 25t148 72q69 52 107 119t37 141q0 43-13 85 72-39 114-99t42-128z" horiz-adv-x="1000" />
|
||||||
|
|
||||||
|
<glyph glyph-name="info-circled" unicode="" d="M571 89v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h250q7 0 12 5t5 13z m-71 500v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h107q8 0 13 5t5 13z m357-232q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
|
||||||
|
|
||||||
|
<glyph glyph-name="login" unicode="" d="M661 357q0-14-11-25l-303-304q-11-10-26-10t-25 10-10 25v161h-250q-15 0-25 11t-11 25v214q0 15 11 25t25 11h250v161q0 14 10 25t25 10 26-10l303-304q11-10 11-25z m196 196v-392q0-67-47-114t-114-47h-178q-7 0-13 5t-5 13q0 2-1 11t0 15 2 13 5 11 12 3h178q37 0 64 27t26 63v392q0 37-26 64t-64 26h-174t-6 0-6 2-5 3-4 5-1 8q0 2-1 11t0 15 2 13 5 11 12 3h178q67 0 114-47t47-114z" horiz-adv-x="857.1" />
|
||||||
|
|
||||||
|
<glyph glyph-name="home-2" unicode="" d="M521 826q322-279 500-429 20-16 20-40 0-21-15-37t-36-15l-105 0 0-364q0-21-15-37t-36-16l-156 0q-22 0-37 16t-16 37l0 208-209 0 0-208q0-21-15-37t-36-16l-156 0q-21 0-37 16t-16 37l0 364-103 0q-22 0-37 15t-16 37 19 40z" horiz-adv-x="1041" />
|
||||||
|
|
||||||
|
<glyph glyph-name="arrow-curved" unicode="" d="M799 302l0-56 112 0-223-223-224 223 112 0 0 56q0 116-81 197t-197 82-198-82-82-197q0 162 115 276t276 114 276-114 114-276z" horiz-adv-x="928" />
|
||||||
|
|
||||||
<glyph glyph-name="spin3" unicode="" d="M494 857c-266 0-483-210-494-472-1-19 13-20 13-20l84 0c16 0 19 10 19 18 10 199 176 358 378 358 107 0 205-45 273-118l-58-57c-11-12-11-27 5-31l247-50c21-5 46 11 37 44l-58 227c-2 9-16 22-29 13l-65-60c-89 91-214 148-352 148z m409-508c-16 0-19-10-19-18-10-199-176-358-377-358-108 0-205 45-274 118l59 57c10 12 10 27-5 31l-248 50c-21 5-46-11-37-44l58-227c2-9 16-22 30-13l64 60c89-91 214-148 353-148 265 0 482 210 493 473 1 18-13 19-13 19l-84 0z" horiz-adv-x="1000" />
|
<glyph glyph-name="spin3" unicode="" d="M494 857c-266 0-483-210-494-472-1-19 13-20 13-20l84 0c16 0 19 10 19 18 10 199 176 358 378 358 107 0 205-45 273-118l-58-57c-11-12-11-27 5-31l247-50c21-5 46 11 37 44l-58 227c-2 9-16 22-29 13l-65-60c-89 91-214 148-352 148z m409-508c-16 0-19-10-19-18-10-199-176-358-377-358-108 0-205 45-274 118l59 57c10 12 10 27-5 31l-248 50c-21 5-46-11-37-44l58-227c2-9 16-22 30-13l64 60c89-91 214-148 353-148 265 0 482 210 493 473 1 18-13 19-13 19l-84 0z" horiz-adv-x="1000" />
|
||||||
|
|
||||||
<glyph glyph-name="spin4" unicode="" d="M498 857c-114 0-228-39-320-116l0 0c173 140 428 130 588-31 134-134 164-332 89-495-10-29-5-50 12-68 21-20 61-23 84 0 3 3 12 15 15 24 71 180 33 393-112 539-99 98-228 147-356 147z m-409-274c-14 0-29-5-39-16-3-3-13-15-15-24-71-180-34-393 112-539 185-185 479-195 676-31l0 0c-173-140-428-130-589 31-134 134-163 333-89 495 11 29 6 50-12 68-11 11-27 17-44 16z" horiz-adv-x="1001" />
|
<glyph glyph-name="spin4" unicode="" d="M498 857c-114 0-228-39-320-116l0 0c173 140 428 130 588-31 134-134 164-332 89-495-10-29-5-50 12-68 21-20 61-23 84 0 3 3 12 15 15 24 71 180 33 393-112 539-99 98-228 147-356 147z m-409-274c-14 0-29-5-39-16-3-3-13-15-15-24-71-180-34-393 112-539 185-185 479-195 676-31l0 0c-173-140-428-130-589 31-134 134-163 333-89 495 11 29 6 50-12 68-11 11-27 17-44 16z" horiz-adv-x="1001" />
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 24 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -303,6 +303,42 @@
|
||||||
"css": "gauge",
|
"css": "gauge",
|
||||||
"code": 61668,
|
"code": 61668,
|
||||||
"src": "fontawesome"
|
"src": "fontawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "31972e4e9d080eaa796290349ae6c1fd",
|
||||||
|
"css": "users",
|
||||||
|
"code": 59421,
|
||||||
|
"src": "fontawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "e82cedfa1d5f15b00c5a81c9bd731ea2",
|
||||||
|
"css": "info-circled",
|
||||||
|
"code": 59423,
|
||||||
|
"src": "fontawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "w3nzesrlbezu6f30q7ytyq919p6gdlb6",
|
||||||
|
"css": "home-2",
|
||||||
|
"code": 59425,
|
||||||
|
"src": "typicons"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "dcedf50ab1ede3283d7a6c70e2fe32f3",
|
||||||
|
"css": "chat",
|
||||||
|
"code": 59422,
|
||||||
|
"src": "fontawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "3a00327e61b997b58518bd43ed83c3df",
|
||||||
|
"css": "login",
|
||||||
|
"code": 59424,
|
||||||
|
"src": "fontawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "f3ebd6751c15a280af5cc5f4a764187d",
|
||||||
|
"css": "arrow-curved",
|
||||||
|
"code": 59426,
|
||||||
|
"src": "iconic"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"pleroma-dark": [ "Pleroma Dark", "#121a24", "#182230", "#b9b9ba", "#d8a070", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ],
|
"pleroma-dark": [ "Pleroma Dark", "#121a24", "#182230", "#b9b9ba", "#d8a070", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ],
|
||||||
"pleroma-light": [ "Pleroma Light", "#f2f4f6", "#dbe0e8", "#304055", "#f86f0f", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ],
|
"pleroma-light": [ "Pleroma Light", "#f2f4f6", "#dbe0e8", "#304055", "#f86f0f", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ],
|
||||||
|
"pleroma-amoled": [ "Pleroma Dark AMOLED", "#000000", "#111111", "#b0b0b1", "#d8a070", "#aa0000", "#0fa00f", "#0095ff", "#d59500"],
|
||||||
"classic-dark": [ "Classic Dark", "#161c20", "#282e32", "#b9b9b9", "#baaa9c", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ],
|
"classic-dark": [ "Classic Dark", "#161c20", "#282e32", "#b9b9b9", "#baaa9c", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ],
|
||||||
"bird": [ "Bird", "#f8fafd", "#e6ecf0", "#14171a", "#0084b8", "#e0245e", "#17bf63", "#1b95e0", "#fab81e"],
|
"bird": [ "Bird", "#f8fafd", "#e6ecf0", "#14171a", "#0084b8", "#e0245e", "#17bf63", "#1b95e0", "#fab81e"],
|
||||||
"ir-black": [ "Ir Black", "#000000", "#242422", "#b5b3aa", "#ff6c60", "#FF6C60", "#A8FF60", "#96CBFE", "#FFFFB6" ],
|
"ir-black": [ "Ir Black", "#000000", "#242422", "#b5b3aa", "#ff6c60", "#FF6C60", "#A8FF60", "#96CBFE", "#FFFFB6" ],
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -745,7 +745,7 @@ test "it doesn't return notifications from a blocked user when with_muted is set
|
||||||
|
|
||||||
{:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
|
{:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
|
||||||
|
|
||||||
assert length(Notification.for_user(user, %{with_muted: true})) == 0
|
assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it doesn't return notifications from a domain-blocked user when with_muted is set" do
|
test "it doesn't return notifications from a domain-blocked user when with_muted is set" do
|
||||||
|
@ -755,7 +755,7 @@ test "it doesn't return notifications from a domain-blocked user when with_muted
|
||||||
|
|
||||||
{:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
|
{:ok, _activity} = CommonAPI.post(blocked, %{"status" => "hey @#{user.nickname}"})
|
||||||
|
|
||||||
assert length(Notification.for_user(user, %{with_muted: true})) == 0
|
assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it returns notifications from muted threads when with_muted is set" do
|
test "it returns notifications from muted threads when with_muted is set" do
|
||||||
|
|
|
@ -4,7 +4,10 @@
|
||||||
|
|
||||||
defmodule Pleroma.RepoTest do
|
defmodule Pleroma.RepoTest do
|
||||||
use Pleroma.DataCase
|
use Pleroma.DataCase
|
||||||
|
import ExUnit.CaptureLog
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
import Mock
|
||||||
|
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
describe "find_resource/1" do
|
describe "find_resource/1" do
|
||||||
|
@ -46,4 +49,44 @@ test "return error if has not assoc " do
|
||||||
assert Repo.get_assoc(token, :user) == {:error, :not_found}
|
assert Repo.get_assoc(token, :user) == {:error, :not_found}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "check_migrations_applied!" do
|
||||||
|
setup_with_mocks([
|
||||||
|
{Ecto.Migrator, [],
|
||||||
|
[
|
||||||
|
with_repo: fn repo, fun -> passthrough([repo, fun]) end,
|
||||||
|
migrations: fn Pleroma.Repo ->
|
||||||
|
[
|
||||||
|
{:up, 20_191_128_153_944, "fix_missing_following_count"},
|
||||||
|
{:up, 20_191_203_043_610, "create_report_notes"},
|
||||||
|
{:down, 20_191_220_174_645, "add_scopes_to_pleroma_feo_auth_records"}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
]}
|
||||||
|
]) do
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
|
test "raises if it detects unapplied migrations" do
|
||||||
|
assert_raise Pleroma.Repo.UnappliedMigrationsError, fn ->
|
||||||
|
capture_log(&Repo.check_migrations_applied!/0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "doesn't do anything if disabled" do
|
||||||
|
disable_migration_check =
|
||||||
|
Pleroma.Config.get([:i_am_aware_this_may_cause_data_loss, :disable_migration_check])
|
||||||
|
|
||||||
|
Pleroma.Config.put([:i_am_aware_this_may_cause_data_loss, :disable_migration_check], true)
|
||||||
|
|
||||||
|
on_exit(fn ->
|
||||||
|
Pleroma.Config.put(
|
||||||
|
[:i_am_aware_this_may_cause_data_loss, :disable_migration_check],
|
||||||
|
disable_migration_check
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert :ok == Repo.check_migrations_applied!()
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -78,7 +78,7 @@ test "with locked accounts, it does not create a follow or an accept" do
|
||||||
)
|
)
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
|
|
||||||
assert length(accepts) == 0
|
assert Enum.empty?(accepts)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it works for follow requests when you are already followed, creating a new accept activity" do
|
test "it works for follow requests when you are already followed, creating a new accept activity" do
|
||||||
|
|
|
@ -1363,6 +1363,30 @@ test "returns 404 when report id is invalid", %{conn: conn} do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do
|
||||||
|
read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"])
|
||||||
|
write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> assign(:token, read_token)
|
||||||
|
|> patch("/api/pleroma/admin/reports", %{
|
||||||
|
"reports" => [%{"state" => "resolved", "id" => id}]
|
||||||
|
})
|
||||||
|
|> json_response(403)
|
||||||
|
|
||||||
|
assert response == %{
|
||||||
|
"error" => "Insufficient permissions: admin:write:reports."
|
||||||
|
}
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> assign(:token, write_token)
|
||||||
|
|> patch("/api/pleroma/admin/reports", %{
|
||||||
|
"reports" => [%{"state" => "resolved", "id" => id}]
|
||||||
|
})
|
||||||
|
|> json_response(:no_content)
|
||||||
|
end
|
||||||
|
|
||||||
test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
|
test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
|
||||||
conn
|
conn
|
||||||
|> patch("/api/pleroma/admin/reports", %{
|
|> patch("/api/pleroma/admin/reports", %{
|
||||||
|
@ -2840,7 +2864,7 @@ test "GET /instances/:instance/statuses", %{conn: conn} do
|
||||||
|
|
||||||
response = json_response(ret_conn, 200)
|
response = json_response(ret_conn, 200)
|
||||||
|
|
||||||
assert length(response) == 0
|
assert Enum.empty?(response)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -284,22 +284,22 @@ test "favoriting a status" do
|
||||||
{:ok, %Activity{}, _} = CommonAPI.favorite(activity.id, user)
|
{:ok, %Activity{}, _} = CommonAPI.favorite(activity.id, user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "retweeting a status twice returns an error" do
|
test "retweeting a status twice returns the status" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
other_user = insert(:user)
|
other_user = insert(:user)
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
|
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
|
||||||
{:ok, %Activity{}, _object} = CommonAPI.repeat(activity.id, user)
|
{:ok, %Activity{} = activity, object} = CommonAPI.repeat(activity.id, user)
|
||||||
{:error, _} = CommonAPI.repeat(activity.id, user)
|
{:ok, ^activity, ^object} = CommonAPI.repeat(activity.id, user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "favoriting a status twice returns an error" do
|
test "favoriting a status twice returns the status" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
other_user = insert(:user)
|
other_user = insert(:user)
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
|
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
|
||||||
{:ok, %Activity{}, _object} = CommonAPI.favorite(activity.id, user)
|
{:ok, %Activity{} = activity, object} = CommonAPI.favorite(activity.id, user)
|
||||||
{:error, _} = CommonAPI.favorite(activity.id, user)
|
{:ok, ^activity, ^object} = CommonAPI.favorite(activity.id, user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -307,7 +307,7 @@ test "for private posts, not a reply" do
|
||||||
|
|
||||||
{to, cc} = Utils.get_to_and_cc(user, mentions, nil, "private", nil)
|
{to, cc} = Utils.get_to_and_cc(user, mentions, nil, "private", nil)
|
||||||
assert length(to) == 2
|
assert length(to) == 2
|
||||||
assert length(cc) == 0
|
assert Enum.empty?(cc)
|
||||||
|
|
||||||
assert mentioned_user.ap_id in to
|
assert mentioned_user.ap_id in to
|
||||||
assert user.follower_address in to
|
assert user.follower_address in to
|
||||||
|
@ -323,7 +323,7 @@ test "for private posts, a reply" do
|
||||||
{to, cc} = Utils.get_to_and_cc(user, mentions, activity, "private", nil)
|
{to, cc} = Utils.get_to_and_cc(user, mentions, activity, "private", nil)
|
||||||
|
|
||||||
assert length(to) == 3
|
assert length(to) == 3
|
||||||
assert length(cc) == 0
|
assert Enum.empty?(cc)
|
||||||
|
|
||||||
assert mentioned_user.ap_id in to
|
assert mentioned_user.ap_id in to
|
||||||
assert third_user.ap_id in to
|
assert third_user.ap_id in to
|
||||||
|
@ -338,7 +338,7 @@ test "for direct posts, not a reply" do
|
||||||
{to, cc} = Utils.get_to_and_cc(user, mentions, nil, "direct", nil)
|
{to, cc} = Utils.get_to_and_cc(user, mentions, nil, "direct", nil)
|
||||||
|
|
||||||
assert length(to) == 1
|
assert length(to) == 1
|
||||||
assert length(cc) == 0
|
assert Enum.empty?(cc)
|
||||||
|
|
||||||
assert mentioned_user.ap_id in to
|
assert mentioned_user.ap_id in to
|
||||||
end
|
end
|
||||||
|
@ -353,7 +353,7 @@ test "for direct posts, a reply" do
|
||||||
{to, cc} = Utils.get_to_and_cc(user, mentions, activity, "direct", nil)
|
{to, cc} = Utils.get_to_and_cc(user, mentions, activity, "direct", nil)
|
||||||
|
|
||||||
assert length(to) == 2
|
assert length(to) == 2
|
||||||
assert length(cc) == 0
|
assert Enum.empty?(cc)
|
||||||
|
|
||||||
assert mentioned_user.ap_id in to
|
assert mentioned_user.ap_id in to
|
||||||
assert third_user.ap_id in to
|
assert third_user.ap_id in to
|
||||||
|
|
|
@ -457,6 +457,30 @@ test "preserves parameters in link headers" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "from specified user" do
|
||||||
|
test "account_id" do
|
||||||
|
%{user: user, conn: conn} = oauth_access(["read:notifications"])
|
||||||
|
|
||||||
|
%{id: account_id} = other_user1 = insert(:user)
|
||||||
|
other_user2 = insert(:user)
|
||||||
|
|
||||||
|
{:ok, _activity} = CommonAPI.post(other_user1, %{"status" => "hi @#{user.nickname}"})
|
||||||
|
{:ok, _activity} = CommonAPI.post(other_user2, %{"status" => "bye @#{user.nickname}"})
|
||||||
|
|
||||||
|
assert [%{"account" => %{"id" => ^account_id}}] =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> get("/api/v1/notifications", %{account_id: account_id})
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
assert %{"error" => "Account is not found"} =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> get("/api/v1/notifications", %{account_id: "cofe"})
|
||||||
|
|> json_response(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp get_notification_id_by_activity(%{id: id}) do
|
defp get_notification_id_by_activity(%{id: id}) do
|
||||||
Notification
|
Notification
|
||||||
|> Repo.get_by(activity_id: id)
|
|> Repo.get_by(activity_id: id)
|
||||||
|
|
|
@ -638,6 +638,13 @@ test "favs a status and returns it", %{conn: conn} do
|
||||||
assert to_string(activity.id) == id
|
assert to_string(activity.id) == id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "favoriting twice will just return 200", %{conn: conn} do
|
||||||
|
activity = insert(:note_activity)
|
||||||
|
|
||||||
|
post(conn, "/api/v1/statuses/#{activity.id}/favourite")
|
||||||
|
assert post(conn, "/api/v1/statuses/#{activity.id}/favourite") |> json_response(200)
|
||||||
|
end
|
||||||
|
|
||||||
test "returns 400 error for a wrong id", %{conn: conn} do
|
test "returns 400 error for a wrong id", %{conn: conn} do
|
||||||
conn = post(conn, "/api/v1/statuses/1/favourite")
|
conn = post(conn, "/api/v1/statuses/1/favourite")
|
||||||
|
|
||||||
|
|
|
@ -568,29 +568,34 @@ test "with existing authentication and OOB `redirect_uri`, redirects to app with
|
||||||
|
|
||||||
describe "POST /oauth/authorize" do
|
describe "POST /oauth/authorize" do
|
||||||
test "redirects with oauth authorization, " <>
|
test "redirects with oauth authorization, " <>
|
||||||
"keeping only non-admin scopes for non-admin user" do
|
"granting requested app-supported scopes to both admin- and non-admin users" do
|
||||||
app = insert(:oauth_app, scopes: ["read", "write", "admin"])
|
app_scopes = ["read", "write", "admin", "secret_scope"]
|
||||||
|
app = insert(:oauth_app, scopes: app_scopes)
|
||||||
redirect_uri = OAuthController.default_redirect_uri(app)
|
redirect_uri = OAuthController.default_redirect_uri(app)
|
||||||
|
|
||||||
non_admin = insert(:user, is_admin: false)
|
non_admin = insert(:user, is_admin: false)
|
||||||
admin = insert(:user, is_admin: true)
|
admin = insert(:user, is_admin: true)
|
||||||
|
scopes_subset = ["read:subscope", "write", "admin"]
|
||||||
|
|
||||||
for {user, expected_scopes} <- %{
|
# In case scope param is missing, expecting _all_ app-supported scopes to be granted
|
||||||
non_admin => ["read:subscope", "write"],
|
for user <- [non_admin, admin],
|
||||||
admin => ["read:subscope", "write", "admin"]
|
{requested_scopes, expected_scopes} <-
|
||||||
} do
|
%{scopes_subset => scopes_subset, nil => app_scopes} do
|
||||||
conn =
|
conn =
|
||||||
build_conn()
|
post(
|
||||||
|> post("/oauth/authorize", %{
|
build_conn(),
|
||||||
"authorization" => %{
|
"/oauth/authorize",
|
||||||
"name" => user.nickname,
|
%{
|
||||||
"password" => "test",
|
"authorization" => %{
|
||||||
"client_id" => app.client_id,
|
"name" => user.nickname,
|
||||||
"redirect_uri" => redirect_uri,
|
"password" => "test",
|
||||||
"scope" => "read:subscope write admin",
|
"client_id" => app.client_id,
|
||||||
"state" => "statepassed"
|
"redirect_uri" => redirect_uri,
|
||||||
|
"scope" => requested_scopes,
|
||||||
|
"state" => "statepassed"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
|
|
||||||
target = redirected_to(conn)
|
target = redirected_to(conn)
|
||||||
assert target =~ redirect_uri
|
assert target =~ redirect_uri
|
||||||
|
@ -631,34 +636,31 @@ test "returns 401 for wrong credentials", %{conn: conn} do
|
||||||
assert result =~ "Invalid Username/Password"
|
assert result =~ "Invalid Username/Password"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns 401 for missing scopes " <>
|
test "returns 401 for missing scopes" do
|
||||||
"(including all admin-only scopes for non-admin user)" do
|
|
||||||
user = insert(:user, is_admin: false)
|
user = insert(:user, is_admin: false)
|
||||||
app = insert(:oauth_app, scopes: ["read", "write", "admin"])
|
app = insert(:oauth_app, scopes: ["read", "write", "admin"])
|
||||||
redirect_uri = OAuthController.default_redirect_uri(app)
|
redirect_uri = OAuthController.default_redirect_uri(app)
|
||||||
|
|
||||||
for scope_param <- ["", "admin:read admin:write"] do
|
result =
|
||||||
result =
|
build_conn()
|
||||||
build_conn()
|
|> post("/oauth/authorize", %{
|
||||||
|> post("/oauth/authorize", %{
|
"authorization" => %{
|
||||||
"authorization" => %{
|
"name" => user.nickname,
|
||||||
"name" => user.nickname,
|
"password" => "test",
|
||||||
"password" => "test",
|
"client_id" => app.client_id,
|
||||||
"client_id" => app.client_id,
|
"redirect_uri" => redirect_uri,
|
||||||
"redirect_uri" => redirect_uri,
|
"state" => "statepassed",
|
||||||
"state" => "statepassed",
|
"scope" => ""
|
||||||
"scope" => scope_param
|
}
|
||||||
}
|
})
|
||||||
})
|
|> html_response(:unauthorized)
|
||||||
|> html_response(:unauthorized)
|
|
||||||
|
|
||||||
# Keep the details
|
# Keep the details
|
||||||
assert result =~ app.client_id
|
assert result =~ app.client_id
|
||||||
assert result =~ redirect_uri
|
assert result =~ redirect_uri
|
||||||
|
|
||||||
# Error message
|
# Error message
|
||||||
assert result =~ "This action is outside the authorized scopes"
|
assert result =~ "This action is outside the authorized scopes"
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns 401 for scopes beyond app scopes hierarchy", %{conn: conn} do
|
test "returns 401 for scopes beyond app scopes hierarchy", %{conn: conn} do
|
||||||
|
|
|
@ -14,6 +14,10 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do
|
||||||
"emoji"
|
"emoji"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
clear_config([:auth, :enforce_oauth_admin_scope_usage]) do
|
||||||
|
Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], false)
|
||||||
|
end
|
||||||
|
|
||||||
test "shared & non-shared pack information in list_packs is ok" do
|
test "shared & non-shared pack information in list_packs is ok" do
|
||||||
conn = build_conn()
|
conn = build_conn()
|
||||||
resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200)
|
resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200)
|
||||||
|
|
|
@ -57,11 +57,6 @@ test "GET /api/v1/pleroma/statuses/:id/emoji_reactions_by", %{conn: conn} do
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe"})
|
{:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe"})
|
||||||
|
|
||||||
conn =
|
|
||||||
conn
|
|
||||||
|> assign(:user, user)
|
|
||||||
|> assign(:token, insert(:oauth_token, user: user, scopes: ["read:statuses"]))
|
|
||||||
|
|
||||||
result =
|
result =
|
||||||
conn
|
conn
|
||||||
|> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by")
|
|> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by")
|
||||||
|
|
|
@ -55,7 +55,7 @@ test "it returns HTTP 200", %{conn: conn} do
|
||||||
|
|
||||||
user = refresh_record(user)
|
user = refresh_record(user)
|
||||||
assert Comeonin.Pbkdf2.checkpw("test", user.password_hash)
|
assert Comeonin.Pbkdf2.checkpw("test", user.password_hash)
|
||||||
assert length(Token.get_user_tokens(user)) == 0
|
assert Enum.empty?(Token.get_user_tokens(user))
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it sets password_reset_pending to false", %{conn: conn} do
|
test "it sets password_reset_pending to false", %{conn: conn} do
|
||||||
|
|
Loading…
Reference in New Issue