Merge branch 'develop' into feature/tag_feed

This commit is contained in:
Maksim Pechnikov 2020-01-21 09:23:35 +03:00
commit 41e2332007
25 changed files with 310 additions and 62 deletions

View file

@ -281,11 +281,11 @@ docker:
IMAGE_TAG_LATEST_STABLE: $CI_REGISTRY_IMAGE:latest-stable 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 allow_failure: true
script: script:
- docker pull $IMAGE_TAG_SLUG || 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 $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
- docker push $IMAGE_TAG_SLUG - docker push $IMAGE_TAG_SLUG
@ -293,7 +293,7 @@ docker:
tags: tags:
- dind - dind
only: only:
- develop - develop@pleroma/pleroma
docker-stable: docker-stable:
stage: docker stage: docker
@ -304,7 +304,6 @@ docker-stable:
before_script: *before-docker before_script: *before-docker
allow_failure: true allow_failure: true
script: script:
- docker pull $IMAGE_TAG_SLUG || 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_STABLE . - 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
- docker push $IMAGE_TAG_SLUG - docker push $IMAGE_TAG_SLUG
@ -312,4 +311,21 @@ docker-stable:
tags: tags:
- dind - dind
only: only:
- stable - 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

View file

@ -10,6 +10,7 @@ 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
@ -43,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

View file

@ -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])

View file

@ -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

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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(%{

View file

@ -75,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(
@ -639,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,

View file

@ -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
if announce_activity do
{:ok, announce_activity, object}
else
ActivityPub.announce(user, object, nil, true, public) 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
if like_activity do
{:ok, like_activity, object}
else
ActivityPub.like(user, object) ActivityPub.like(user, object)
end
else else
_ -> {:error, dgettext("errors", "Could not favorite")} _ -> {:error, dgettext("errors", "Could not favorite")}
end end

View file

@ -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)

View file

@ -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})

View file

@ -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

View file

@ -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(

View file

@ -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"},

View file

@ -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]},

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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")

View file

@ -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")

View file

@ -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