Merge branch 'develop' into feature/attachments-cleanup
This commit is contained in:
commit
506e399114
|
@ -1,13 +1,13 @@
|
|||
image: elixir:1.8.1
|
||||
|
||||
variables:
|
||||
variables: &global_variables
|
||||
POSTGRES_DB: pleroma_test
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
DB_HOST: postgres
|
||||
MIX_ENV: test
|
||||
|
||||
cache:
|
||||
cache: &global_cache_policy
|
||||
key: ${CI_COMMIT_REF_SLUG}
|
||||
paths:
|
||||
- deps
|
||||
|
@ -46,6 +46,10 @@ benchmark:
|
|||
|
||||
unit-testing:
|
||||
stage: test
|
||||
cache: &testing_cache_policy
|
||||
<<: *global_cache_policy
|
||||
policy: pull
|
||||
|
||||
services:
|
||||
- name: postgres:9.6
|
||||
alias: postgres
|
||||
|
@ -58,6 +62,7 @@ unit-testing:
|
|||
|
||||
federated-testing:
|
||||
stage: test
|
||||
cache: *testing_cache_policy
|
||||
services:
|
||||
- name: minibikini/postgres-with-rum:12
|
||||
alias: postgres
|
||||
|
@ -71,11 +76,13 @@ federated-testing:
|
|||
|
||||
unit-testing-rum:
|
||||
stage: test
|
||||
cache: *testing_cache_policy
|
||||
services:
|
||||
- name: minibikini/postgres-with-rum:12
|
||||
alias: postgres
|
||||
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
|
||||
variables:
|
||||
<<: *global_variables
|
||||
RUM_ENABLED: "true"
|
||||
script:
|
||||
- mix deps.get
|
||||
|
@ -86,17 +93,20 @@ unit-testing-rum:
|
|||
|
||||
lint:
|
||||
stage: test
|
||||
cache: *testing_cache_policy
|
||||
script:
|
||||
- mix format --check-formatted
|
||||
|
||||
analysis:
|
||||
stage: test
|
||||
cache: *testing_cache_policy
|
||||
script:
|
||||
- mix deps.get
|
||||
- mix credo --strict --only=warnings,todo,fixme,consistency,readability
|
||||
|
||||
docs-deploy:
|
||||
stage: deploy
|
||||
cache: *testing_cache_policy
|
||||
image: alpine:latest
|
||||
only:
|
||||
- stable@pleroma/pleroma
|
||||
|
|
|
@ -29,6 +29,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
- **Breaking:** Admin API: `PUT /api/pleroma/admin/reports/:id` is now `PATCH /api/pleroma/admin/reports`, see admin_api.md for details
|
||||
- **Breaking:** `/api/pleroma/admin/users/invite_token` now uses `POST`, changed accepted params and returns full invite in json instead of only token string.
|
||||
- **Breaking** replying to reports is now "report notes", enpoint changed from `POST /api/pleroma/admin/reports/:id/respond` to `POST /api/pleroma/admin/reports/:id/notes`
|
||||
- **Breaking** `/api/v1/stats` now return statuses count by scope (i.e. `all`, `public`, `unlisted`, `direct` and `private`)
|
||||
- Admin API: Return `total` when querying for reports
|
||||
- Mastodon API: Return `pleroma.direct_conversation_id` when creating a direct message (`POST /api/v1/statuses`)
|
||||
- Admin API: Return link alongside with token on password reset
|
||||
|
|
|
@ -70,6 +70,8 @@ config :pleroma, Pleroma.Captcha,
|
|||
seconds_valid: 60,
|
||||
method: Pleroma.Captcha.Native
|
||||
|
||||
config :pleroma, Pleroma.Captcha.Kocaptcha, endpoint: "https://captcha.kotobank.ch"
|
||||
|
||||
config :pleroma, :hackney_pools,
|
||||
federation: [
|
||||
max_connections: 50,
|
||||
|
|
|
@ -95,8 +95,6 @@ config :joken, default_signer: "yU8uHKq+yyAkZ11Hx//jcdacWc8yQ1bxAAGrplzB0Zwwjkp3
|
|||
|
||||
config :pleroma, Pleroma.ReverseProxy.Client, Pleroma.ReverseProxy.ClientMock
|
||||
|
||||
config :pleroma, Pleroma.Captcha.Kocaptcha, endpoint: "https://captcha.kotobank.ch"
|
||||
|
||||
if File.exists?("./config/test.secret.exs") do
|
||||
import_config "test.secret.exs"
|
||||
else
|
||||
|
|
|
@ -70,59 +70,6 @@ Request parameters can be passed via [query strings](https://en.wikipedia.org/wi
|
|||
* Response: JSON. Returns `{"status": "success"}` if the account was successfully disabled, `{"error": "[error message]"}` otherwise
|
||||
* Example response: `{"error": "Invalid password."}`
|
||||
|
||||
## `/api/account/register`
|
||||
### Register a new user
|
||||
* Method `POST`
|
||||
* Authentication: not required
|
||||
* Params:
|
||||
* `nickname`
|
||||
* `fullname`
|
||||
* `bio`
|
||||
* `email`
|
||||
* `password`
|
||||
* `confirm`
|
||||
* `captcha_solution`: optional, contains provider-specific captcha solution,
|
||||
* `captcha_token`: optional, contains provider-specific captcha token
|
||||
* `token`: invite token required when the registrations aren't public.
|
||||
* Response: JSON. Returns a user object on success, otherwise returns `{"error": "error_msg"}`
|
||||
* Example response:
|
||||
```json
|
||||
{
|
||||
"background_image": null,
|
||||
"cover_photo": "https://pleroma.soykaf.com/images/banner.png",
|
||||
"created_at": "Tue Dec 18 16:55:56 +0000 2018",
|
||||
"default_scope": "public",
|
||||
"description": "blushy-crushy fediverse idol + pleroma dev\nlet's be friends \nぷれろまの生徒会長。謎の外人。日本語OK. \n公主病.",
|
||||
"description_html": "blushy-crushy fediverse idol + pleroma dev.<br />let's be friends <br />ぷれろまの生徒会長。謎の外人。日本語OK. <br />公主病.",
|
||||
"favourites_count": 0,
|
||||
"fields": [],
|
||||
"followers_count": 0,
|
||||
"following": false,
|
||||
"follows_you": false,
|
||||
"friends_count": 0,
|
||||
"id": 6,
|
||||
"is_local": true,
|
||||
"locked": false,
|
||||
"name": "lain",
|
||||
"name_html": "lain",
|
||||
"no_rich_text": false,
|
||||
"pleroma": {
|
||||
"tags": []
|
||||
},
|
||||
"profile_image_url": "https://pleroma.soykaf.com/images/avi.png",
|
||||
"profile_image_url_https": "https://pleroma.soykaf.com/images/avi.png",
|
||||
"profile_image_url_original": "https://pleroma.soykaf.com/images/avi.png",
|
||||
"profile_image_url_profile_size": "https://pleroma.soykaf.com/images/avi.png",
|
||||
"rights": {
|
||||
"delete_others_notice": false
|
||||
},
|
||||
"screen_name": "lain",
|
||||
"statuses_count": 0,
|
||||
"statusnet_blocking": false,
|
||||
"statusnet_profile_url": "https://pleroma.soykaf.com/users/lain"
|
||||
}
|
||||
```
|
||||
|
||||
## `/api/pleroma/admin/`…
|
||||
See [Admin-API](admin_api.md)
|
||||
|
||||
|
|
|
@ -3,11 +3,15 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Stats do
|
||||
use GenServer
|
||||
|
||||
import Ecto.Query
|
||||
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
|
||||
use GenServer
|
||||
require Pleroma.Constants
|
||||
|
||||
@interval 1000 * 60 * 60
|
||||
|
||||
|
@ -56,7 +60,7 @@ defmodule Pleroma.Stats do
|
|||
%{peers: [], stats: %{}}
|
||||
end
|
||||
|
||||
defp get_stat_data do
|
||||
def get_stat_data do
|
||||
peers =
|
||||
from(
|
||||
u in User,
|
||||
|
@ -68,13 +72,71 @@ defmodule Pleroma.Stats do
|
|||
|
||||
domain_count = Enum.count(peers)
|
||||
|
||||
status_count = Repo.aggregate(User.Query.build(%{local: true}), :sum, :note_count)
|
||||
|
||||
user_count = Repo.aggregate(User.Query.build(%{local: true, active: true}), :count, :id)
|
||||
|
||||
%{
|
||||
peers: peers,
|
||||
stats: %{domain_count: domain_count, status_count: status_count, user_count: user_count}
|
||||
stats: %{domain_count: domain_count, status_count: status_count(), user_count: user_count}
|
||||
}
|
||||
end
|
||||
|
||||
defp status_count do
|
||||
%{
|
||||
all: all_statuses_query() |> Repo.aggregate(:count, :id),
|
||||
public: public_statuses_query() |> Repo.aggregate(:count, :id),
|
||||
unlisted: unlisted_statuses_query() |> Repo.aggregate(:count, :id),
|
||||
direct: direct_statuses_query() |> Repo.aggregate(:count, :id),
|
||||
private: private_statuses_query() |> Repo.aggregate(:count, :id)
|
||||
}
|
||||
end
|
||||
|
||||
defp all_statuses_query do
|
||||
from(o in Object, where: fragment("(?)->>'type' = 'Note'", o.data))
|
||||
end
|
||||
|
||||
def public_statuses_query do
|
||||
from(o in Object,
|
||||
where: fragment("(?)->'to' \\? ?", o.data, ^Pleroma.Constants.as_public())
|
||||
)
|
||||
end
|
||||
|
||||
def unlisted_statuses_query do
|
||||
from(o in Object,
|
||||
where: not fragment("(?)->'to' \\? ?", o.data, ^Pleroma.Constants.as_public()),
|
||||
where: fragment("(?)->'cc' \\? ?", o.data, ^Pleroma.Constants.as_public())
|
||||
)
|
||||
end
|
||||
|
||||
def direct_statuses_query do
|
||||
private_statuses_ids = from(p in private_statuses_query(), select: p.id) |> Repo.all()
|
||||
|
||||
from(o in Object,
|
||||
where:
|
||||
fragment(
|
||||
"? \\? 'directMessage' AND (?->>'directMessage')::boolean = true",
|
||||
o.data,
|
||||
o.data
|
||||
) or
|
||||
(not fragment("(?)->'to' \\? ?", o.data, ^Pleroma.Constants.as_public()) and
|
||||
not fragment("(?)->'cc' \\? ?", o.data, ^Pleroma.Constants.as_public()) and
|
||||
o.id not in ^private_statuses_ids)
|
||||
)
|
||||
end
|
||||
|
||||
def private_statuses_query do
|
||||
from(o in subquery(recipients_query()),
|
||||
where: ilike(o.recipients, "%/followers%")
|
||||
)
|
||||
end
|
||||
|
||||
defp recipients_query do
|
||||
from(o in Object,
|
||||
select: %{
|
||||
id: o.id,
|
||||
recipients: fragment("jsonb_array_elements_text((?)->'to')", o.data)
|
||||
},
|
||||
where: not fragment("(?)->'to' \\? ?", o.data, ^Pleroma.Constants.as_public()),
|
||||
where: not fragment("(?)->'cc' \\? ?", o.data, ^Pleroma.Constants.as_public())
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1298,28 +1298,26 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
def fetch_follow_information_for_user(user) do
|
||||
with {:ok, following_data} <-
|
||||
Fetcher.fetch_and_contain_remote_object_from_id(user.following_address),
|
||||
following_count when is_integer(following_count) <- following_data["totalItems"],
|
||||
{:ok, hide_follows} <- collection_private(following_data),
|
||||
{:ok, followers_data} <-
|
||||
Fetcher.fetch_and_contain_remote_object_from_id(user.follower_address),
|
||||
followers_count when is_integer(followers_count) <- followers_data["totalItems"],
|
||||
{:ok, hide_followers} <- collection_private(followers_data) do
|
||||
{:ok,
|
||||
%{
|
||||
hide_follows: hide_follows,
|
||||
follower_count: followers_count,
|
||||
following_count: following_count,
|
||||
follower_count: normalize_counter(followers_data["totalItems"]),
|
||||
following_count: normalize_counter(following_data["totalItems"]),
|
||||
hide_followers: hide_followers
|
||||
}}
|
||||
else
|
||||
{:error, _} = e ->
|
||||
e
|
||||
|
||||
e ->
|
||||
{:error, e}
|
||||
{:error, _} = e -> e
|
||||
e -> {:error, e}
|
||||
end
|
||||
end
|
||||
|
||||
defp normalize_counter(counter) when is_integer(counter), do: counter
|
||||
defp normalize_counter(_), do: 0
|
||||
|
||||
defp maybe_update_follow_information(data) do
|
||||
with {:enabled, true} <-
|
||||
{:enabled, Pleroma.Config.get([:instance, :external_user_synchronization])},
|
||||
|
@ -1339,24 +1337,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
end
|
||||
|
||||
defp collection_private(%{"first" => %{"type" => type}})
|
||||
when type in ["CollectionPage", "OrderedCollectionPage"],
|
||||
do: {:ok, false}
|
||||
|
||||
defp collection_private(%{"first" => first}) do
|
||||
if is_map(first) and
|
||||
first["type"] in ["CollectionPage", "OrderedCollectionPage"] do
|
||||
with {:ok, %{"type" => type}} when type in ["CollectionPage", "OrderedCollectionPage"] <-
|
||||
Fetcher.fetch_and_contain_remote_object_from_id(first) do
|
||||
{:ok, false}
|
||||
else
|
||||
with {:ok, %{"type" => type}} when type in ["CollectionPage", "OrderedCollectionPage"] <-
|
||||
Fetcher.fetch_and_contain_remote_object_from_id(first) do
|
||||
{:ok, false}
|
||||
else
|
||||
{:error, {:ok, %{status: code}}} when code in [401, 403] ->
|
||||
{:ok, true}
|
||||
|
||||
{:error, _} = e ->
|
||||
e
|
||||
|
||||
e ->
|
||||
{:error, e}
|
||||
end
|
||||
{:error, {:ok, %{status: code}}} when code in [401, 403] -> {:ok, true}
|
||||
{:error, _} = e -> e
|
||||
e -> {:error, e}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -397,7 +397,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
%{"type" => "Create", "object" => %{"type" => objtype} = object} = data,
|
||||
options
|
||||
)
|
||||
when objtype in ["Article", "Note", "Video", "Page", "Question", "Answer"] do
|
||||
when objtype in ["Article", "Event", "Note", "Video", "Page", "Question", "Answer"] do
|
||||
actor = Containment.get_actor(data)
|
||||
|
||||
data =
|
||||
|
|
|
@ -22,7 +22,16 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
require Logger
|
||||
require Pleroma.Constants
|
||||
|
||||
@supported_object_types ["Article", "Note", "Video", "Page", "Question", "Answer", "Audio"]
|
||||
@supported_object_types [
|
||||
"Article",
|
||||
"Note",
|
||||
"Event",
|
||||
"Video",
|
||||
"Page",
|
||||
"Question",
|
||||
"Answer",
|
||||
"Audio"
|
||||
]
|
||||
@strip_status_report_states ~w(closed resolved)
|
||||
@supported_report_states ~w(open closed resolved)
|
||||
@valid_visibilities ~w(public unlisted private direct)
|
||||
|
|
|
@ -201,7 +201,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
%{
|
||||
"id" => "#{user.ap_id}/followers",
|
||||
"type" => "OrderedCollection",
|
||||
"totalItems" => total,
|
||||
"first" =>
|
||||
if showing_items do
|
||||
collection(followers, "#{user.ap_id}/followers", 1, showing_items, total)
|
||||
|
@ -209,6 +208,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
"#{user.ap_id}/followers?page=1"
|
||||
end
|
||||
}
|
||||
|> maybe_put_total_items(showing_count, total)
|
||||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
||||
|
@ -251,6 +251,12 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
||||
defp maybe_put_total_items(map, false, _total), do: map
|
||||
|
||||
defp maybe_put_total_items(map, true, total) do
|
||||
Map.put(map, "totalItems", total)
|
||||
end
|
||||
|
||||
def collection(collection, iri, page, show_items \\ true, total \\ nil) do
|
||||
offset = (page - 1) * 10
|
||||
items = Enum.slice(collection, offset, 10)
|
||||
|
|
|
@ -421,7 +421,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
end
|
||||
end
|
||||
|
||||
def render_content(%{data: %{"type" => "Video"}} = object) do
|
||||
def render_content(%{data: %{"type" => object_type}} = object)
|
||||
when object_type in ["Video", "Event"] do
|
||||
with name when not is_nil(name) and name != "" <- object.data["name"] do
|
||||
"<p><a href=\"#{object.data["id"]}\">#{name}</a></p>#{object.data["content"]}"
|
||||
else
|
||||
|
|
|
@ -31,7 +31,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
|
|||
if attachments == [] or Metadata.activity_nsfw?(object) do
|
||||
[
|
||||
image_tag(user),
|
||||
{:meta, [property: "twitter:card", content: "summary_large_image"], []}
|
||||
{:meta, [property: "twitter:card", content: "summary"], []}
|
||||
]
|
||||
else
|
||||
attachments
|
||||
|
|
|
@ -104,7 +104,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
|
||||
defp is_status?(acct) do
|
||||
case Pleroma.Object.Fetcher.fetch_and_contain_remote_object_from_id(acct) do
|
||||
{:ok, %{"type" => type}} when type in ["Article", "Note", "Video", "Page", "Question"] ->
|
||||
{:ok, %{"type" => type}}
|
||||
when type in ["Article", "Event", "Note", "Video", "Page", "Question"] ->
|
||||
true
|
||||
|
||||
_ ->
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
defmodule Pleroma.Conversation.ParticipationTest do
|
||||
use Pleroma.DataCase
|
||||
import Pleroma.Factory
|
||||
alias Pleroma.Conversation
|
||||
alias Pleroma.Conversation.Participation
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
|
@ -98,7 +100,9 @@ defmodule Pleroma.Conversation.ParticipationTest do
|
|||
assert participation.user_id == user.id
|
||||
assert participation.conversation_id == conversation.id
|
||||
|
||||
# Needed because updated_at is accurate down to a second
|
||||
:timer.sleep(1000)
|
||||
|
||||
# Creating again returns the same participation
|
||||
{:ok, %Participation{} = participation_two} =
|
||||
Participation.create_for_user_and_conversation(user, conversation)
|
||||
|
@ -150,9 +154,7 @@ defmodule Pleroma.Conversation.ParticipationTest do
|
|||
test "gets all the participations for a user, ordered by updated at descending" do
|
||||
user = insert(:user)
|
||||
{:ok, activity_one} = CommonAPI.post(user, %{"status" => "x", "visibility" => "direct"})
|
||||
:timer.sleep(1000)
|
||||
{:ok, activity_two} = CommonAPI.post(user, %{"status" => "x", "visibility" => "direct"})
|
||||
:timer.sleep(1000)
|
||||
|
||||
{:ok, activity_three} =
|
||||
CommonAPI.post(user, %{
|
||||
|
@ -161,6 +163,17 @@ defmodule Pleroma.Conversation.ParticipationTest do
|
|||
"in_reply_to_status_id" => activity_one.id
|
||||
})
|
||||
|
||||
# Offset participations because the accuracy of updated_at is down to a second
|
||||
|
||||
for {activity, offset} <- [{activity_two, 1}, {activity_three, 2}] do
|
||||
conversation = Conversation.get_for_ap_id(activity.data["context"])
|
||||
participation = Participation.for_user_and_conversation(user, conversation)
|
||||
updated_at = NaiveDateTime.add(Map.get(participation, :updated_at), offset)
|
||||
|
||||
Ecto.Changeset.change(participation, %{updated_at: updated_at})
|
||||
|> Repo.update!()
|
||||
end
|
||||
|
||||
assert [participation_one, participation_two] = Participation.for_user(user)
|
||||
|
||||
object2 = Pleroma.Object.normalize(activity_two)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"@context":["https://www.w3.org/ns/activitystreams","https://litepub.social/litepub/context.jsonld",{"GeoCoordinates":"sc:GeoCoordinates","Hashtag":"as:Hashtag","Place":"sc:Place","PostalAddress":"sc:PostalAddress","address":{"@id":"sc:address","@type":"sc:PostalAddress"},"addressCountry":"sc:addressCountry","addressLocality":"sc:addressLocality","addressRegion":"sc:addressRegion","category":"sc:category","commentsEnabled":{"@id":"pt:commentsEnabled","@type":"sc:Boolean"},"geo":{"@id":"sc:geo","@type":"sc:GeoCoordinates"},"ical":"http://www.w3.org/2002/12/cal/ical#","joinMode":{"@id":"mz:joinMode","@type":"mz:joinModeType"},"joinModeType":{"@id":"mz:joinModeType","@type":"rdfs:Class"},"location":{"@id":"sc:location","@type":"sc:Place"},"maximumAttendeeCapacity":"sc:maximumAttendeeCapacity","mz":"https://joinmobilizon.org/ns#","postalCode":"sc:postalCode","pt":"https://joinpeertube.org/ns#","repliesModerationOption":{"@id":"mz:repliesModerationOption","@type":"mz:repliesModerationOptionType"},"repliesModerationOptionType":{"@id":"mz:repliesModerationOptionType","@type":"rdfs:Class"},"sc":"http://schema.org#","streetAddress":"sc:streetAddress","uuid":"sc:identifier"}],"actor":"https://mobilizon.org/@tcit","attributedTo":"https://mobilizon.org/@tcit","category":"meeting","cc":[],"commentsEnabled":true,"content":"<p>Mobilizon is now federated! 🎉</p><p></p><p>You can view this event from other instances if they are subscribed to mobilizon.org, and soon directly from Mastodon and Pleroma. It is possible that you may see some comments from other instances, including Mastodon ones, just below.</p><p></p><p>With a Mobilizon account on an instance, you may <strong>participate</strong> at events from other instances and <strong>add comments</strong> on events.</p><p></p><p>Of course, it's still <u>a work in progress</u>: if reports made from an instance on events and comments can be federated, you can't block people right now, and moderators actions are rather limited, but this <strong>will definitely get fixed over time</strong> until first stable version next year.</p><p></p><p>Anyway, if you want to come up with some feedback, head over to our forum or - if you feel you have technical skills and are familiar with it - on our Gitlab repository.</p><p></p><p>Also, to people that want to set Mobilizon themselves even though we really don't advise to do that for now, we have a little documentation but it's quite the early days and you'll probably need some help. No worries, you can chat with us on our Forum or though our Matrix channel.</p><p></p><p>Check our website for more informations and follow us on Twitter or Mastodon.</p>","endTime":"2019-12-18T14:00:00Z","ical:status":"CONFIRMED","id":"https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39","joinMode":"free","location":{"address":{"addressCountry":"France","addressLocality":"Nantes","addressRegion":"Pays de la Loire","postalCode":null,"streetAddress":" ","type":"PostalAddress"},"geo":{"latitude":-1.54939699141711,"longitude":47.21617415,"type":"GeoCoordinates"},"id":"https://mobilizon.org/address/1368fdab-1e2c-4de6-bcff-a90c84abdee1","name":"Cour du Château des Ducs de Bretagne","type":"Place"},"maximumAttendeeCapacity":0,"mediaType":"text/html","name":"Mobilizon Launching Party","published":"2019-12-17T11:33:56Z","repliesModerationOption":"allow_all","startTime":"2019-12-18T13:00:00Z","tag":[{"href":"https://mobilizon.org/tags/mobilizon","name":"#Mobilizon","type":"Hashtag"},{"href":"https://mobilizon.org/tags/federation","name":"#Federation","type":"Hashtag"},{"href":"https://mobilizon.org/tags/activitypub","name":"#ActivityPub","type":"Hashtag"},{"href":"https://mobilizon.org/tags/party","name":"#Party","type":"Hashtag"}],"to":["https://www.w3.org/ns/activitystreams#Public"],"type":"Event","updated":"2019-12-17T12:25:01Z","url":"https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39","uuid":"252d5816-00a3-4a89-a66f-15bf65c33e39"}
|
|
@ -0,0 +1 @@
|
|||
{"@context":["https://www.w3.org/ns/activitystreams","https://litepub.social/litepub/context.jsonld",{"GeoCoordinates":"sc:GeoCoordinates","Hashtag":"as:Hashtag","Place":"sc:Place","PostalAddress":"sc:PostalAddress","address":{"@id":"sc:address","@type":"sc:PostalAddress"},"addressCountry":"sc:addressCountry","addressLocality":"sc:addressLocality","addressRegion":"sc:addressRegion","category":"sc:category","commentsEnabled":{"@id":"pt:commentsEnabled","@type":"sc:Boolean"},"geo":{"@id":"sc:geo","@type":"sc:GeoCoordinates"},"ical":"http://www.w3.org/2002/12/cal/ical#","joinMode":{"@id":"mz:joinMode","@type":"mz:joinModeType"},"joinModeType":{"@id":"mz:joinModeType","@type":"rdfs:Class"},"location":{"@id":"sc:location","@type":"sc:Place"},"maximumAttendeeCapacity":"sc:maximumAttendeeCapacity","mz":"https://joinmobilizon.org/ns#","postalCode":"sc:postalCode","pt":"https://joinpeertube.org/ns#","repliesModerationOption":{"@id":"mz:repliesModerationOption","@type":"mz:repliesModerationOptionType"},"repliesModerationOptionType":{"@id":"mz:repliesModerationOptionType","@type":"rdfs:Class"},"sc":"http://schema.org#","streetAddress":"sc:streetAddress","uuid":"sc:identifier"}],"endpoints":{"sharedInbox":"https://mobilizon.org/inbox"},"followers":"https://mobilizon.org/@tcit/followers","following":"https://mobilizon.org/@tcit/following","icon":{"mediaType":null,"type":"Image","url":"https://mobilizon.org/media/3a5f18c058a8193b1febfaf561f94ae8b91f85ac64c01ddf5ad7b251fb43baf5.jpg?name=profil.jpg"},"id":"https://mobilizon.org/@tcit","inbox":"https://mobilizon.org/@tcit/inbox","manuallyApprovesFollowers":false,"name":"Thomas Citharel","outbox":"https://mobilizon.org/@tcit/outbox","preferredUsername":"tcit","publicKey":{"id":"https://mobilizon.org/@tcit#main-key","owner":"https://mobilizon.org/@tcit","publicKeyPem":"-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAtzuZFviv5f12SuA0wZFMuwKS8RIlT3IjPCMLRDhiorZeV3UJ1lik\nDYO6mEh22KDXYgJtNVSYGF0Q5LJivgcvuvU+VQ048iTB1B2x0rHMr47KPByPjfVb\nKDeHt6fkHcLY0JK8UkIxW542wXAg4jX5w3gJi3pgTQrCT8VNyPbH1CaA0uW//9jc\nqzZQVFzpfdJoVOM9E3Urc/u58HC4xOptlM7+B/594ZI9drYwy5m+ZxHwlQUYCva4\n34dvwsfOGxkQyIrzXoep80EnWnFpYCLMcCiz+sEhPYxqLgNE+Cmn/6pv7SIscz6p\neVlQXIchdw+J4yl07paJDkFc6CNTCmaIHQIDAQAB\n-----END RSA PUBLIC KEY-----\n\n"},"summary":"Main profile","type":"Person","url":"https://mobilizon.org/@tcit"}
|
|
@ -77,6 +77,15 @@ defmodule Pleroma.Object.FetcherTest do
|
|||
assert object
|
||||
end
|
||||
|
||||
test "it can fetch Mobilizon events" do
|
||||
{:ok, object} =
|
||||
Fetcher.fetch_object_from_id(
|
||||
"https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39"
|
||||
)
|
||||
|
||||
assert object
|
||||
end
|
||||
|
||||
test "it can fetch wedistribute articles" do
|
||||
{:ok, object} =
|
||||
Fetcher.fetch_object_from_id("https://wedistribute.org/wp-json/pterotype/v1/object/85810")
|
||||
|
|
|
@ -145,9 +145,9 @@ defmodule Pleroma.Plugs.RateLimiterTest do
|
|||
test "can have limits seperate from unauthenticated connections" do
|
||||
limiter_name = :test_authenticated
|
||||
|
||||
scale = 1000
|
||||
scale = 50
|
||||
limit = 5
|
||||
Pleroma.Config.put([:rate_limit, limiter_name], [{1, 10}, {scale, limit}])
|
||||
Pleroma.Config.put([:rate_limit, limiter_name], [{1000, 1}, {scale, limit}])
|
||||
|
||||
opts = RateLimiter.init(name: limiter_name)
|
||||
|
||||
|
@ -164,16 +164,6 @@ defmodule Pleroma.Plugs.RateLimiterTest do
|
|||
|
||||
assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
|
||||
assert conn.halted
|
||||
|
||||
Process.sleep(1550)
|
||||
|
||||
conn = conn(:get, "/") |> assign(:user, user)
|
||||
conn = RateLimiter.call(conn, opts)
|
||||
assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, opts)
|
||||
|
||||
refute conn.status == Plug.Conn.Status.code(:too_many_requests)
|
||||
refute conn.resp_body
|
||||
refute conn.halted
|
||||
end
|
||||
|
||||
test "diffrerent users are counted independently" do
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.StatsTest do
|
||||
use Pleroma.DataCase
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
describe "statuses count" do
|
||||
setup do
|
||||
user = insert(:user)
|
||||
other_user = insert(:user)
|
||||
|
||||
CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
|
||||
|
||||
Enum.each(0..1, fn _ ->
|
||||
CommonAPI.post(user, %{
|
||||
"visibility" => "unlisted",
|
||||
"status" => "hey"
|
||||
})
|
||||
end)
|
||||
|
||||
Enum.each(0..2, fn _ ->
|
||||
CommonAPI.post(user, %{
|
||||
"visibility" => "direct",
|
||||
"status" => "hey @#{other_user.nickname}"
|
||||
})
|
||||
end)
|
||||
|
||||
Enum.each(0..3, fn _ ->
|
||||
CommonAPI.post(user, %{
|
||||
"visibility" => "private",
|
||||
"status" => "hey"
|
||||
})
|
||||
end)
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
test "it returns total number of statuses" do
|
||||
data = Pleroma.Stats.get_stat_data()
|
||||
|
||||
assert data.stats.status_count.all == 10
|
||||
assert data.stats.status_count.public == 1
|
||||
assert data.stats.status_count.unlisted == 2
|
||||
assert data.stats.status_count.direct == 3
|
||||
assert data.stats.status_count.private == 4
|
||||
end
|
||||
end
|
||||
end
|
|
@ -308,6 +308,24 @@ defmodule HttpRequestMock do
|
|||
}}
|
||||
end
|
||||
|
||||
def get("https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39", _, _,
|
||||
Accept: "application/activity+json"
|
||||
) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body: File.read!("test/fixtures/tesla_mock/mobilizon.org-event.json")
|
||||
}}
|
||||
end
|
||||
|
||||
def get("https://mobilizon.org/@tcit", _, _, Accept: "application/activity+json") do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body: File.read!("test/fixtures/tesla_mock/mobilizon.org-user.json")
|
||||
}}
|
||||
end
|
||||
|
||||
def get("https://baptiste.gelez.xyz/@/BaptisteGelez", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
|
|
|
@ -1623,6 +1623,44 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
|
|||
assert follow_info.following_count == 32
|
||||
assert follow_info.hide_follows == true
|
||||
end
|
||||
|
||||
test "doesn't crash when follower and following counters are hidden" do
|
||||
mock(fn env ->
|
||||
case env.url do
|
||||
"http://localhost:4001/users/masto_hidden_counters/following" ->
|
||||
json(%{
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"id" => "http://localhost:4001/users/masto_hidden_counters/followers"
|
||||
})
|
||||
|
||||
"http://localhost:4001/users/masto_hidden_counters/following?page=1" ->
|
||||
%Tesla.Env{status: 403, body: ""}
|
||||
|
||||
"http://localhost:4001/users/masto_hidden_counters/followers" ->
|
||||
json(%{
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"id" => "http://localhost:4001/users/masto_hidden_counters/following"
|
||||
})
|
||||
|
||||
"http://localhost:4001/users/masto_hidden_counters/followers?page=1" ->
|
||||
%Tesla.Env{status: 403, body: ""}
|
||||
end
|
||||
end)
|
||||
|
||||
user =
|
||||
insert(:user,
|
||||
local: false,
|
||||
follower_address: "http://localhost:4001/users/masto_hidden_counters/followers",
|
||||
following_address: "http://localhost:4001/users/masto_hidden_counters/following"
|
||||
)
|
||||
|
||||
{:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
|
||||
|
||||
assert follow_info.hide_followers == true
|
||||
assert follow_info.follower_count == 0
|
||||
assert follow_info.hide_follows == true
|
||||
assert follow_info.following_count == 0
|
||||
end
|
||||
end
|
||||
|
||||
describe "fetch_favourites/3" do
|
||||
|
@ -1639,13 +1677,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
|
|||
|
||||
{:ok, _, _} = CommonAPI.favorite(a4.id, user)
|
||||
{:ok, _, _} = CommonAPI.favorite(a3.id, other_user)
|
||||
Process.sleep(1000)
|
||||
{:ok, _, _} = CommonAPI.favorite(a3.id, user)
|
||||
{:ok, _, _} = CommonAPI.favorite(a5.id, other_user)
|
||||
Process.sleep(1000)
|
||||
{:ok, _, _} = CommonAPI.favorite(a5.id, user)
|
||||
{:ok, _, _} = CommonAPI.favorite(a4.id, other_user)
|
||||
Process.sleep(1000)
|
||||
{:ok, _, _} = CommonAPI.favorite(a1.id, user)
|
||||
{:ok, _, _} = CommonAPI.favorite(a1.id, other_user)
|
||||
result = ActivityPub.fetch_favourites(user)
|
||||
|
|
|
@ -126,7 +126,7 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
|
|||
{:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)
|
||||
assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user})
|
||||
user = Map.merge(user, %{hide_followers_count: true, hide_followers: true})
|
||||
assert %{"totalItems" => 0} = UserView.render("followers.json", %{user: user})
|
||||
refute UserView.render("followers.json", %{user: user}) |> Map.has_key?("totalItems")
|
||||
end
|
||||
|
||||
test "sets correct totalItems when followers are hidden but the follower counter is not" do
|
||||
|
|
|
@ -58,7 +58,15 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do
|
|||
|
||||
assert stats
|
||||
assert stats["user_count"] == 1
|
||||
assert stats["status_count"] == 1
|
||||
|
||||
assert stats["status_count"] == %{
|
||||
"all" => 1,
|
||||
"direct" => 0,
|
||||
"private" => 0,
|
||||
"public" => 1,
|
||||
"unlisted" => 0
|
||||
}
|
||||
|
||||
assert stats["domain_count"] == 2
|
||||
end
|
||||
|
||||
|
|
|
@ -394,6 +394,21 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
|
|||
assert length(represented[:media_attachments]) == 1
|
||||
end
|
||||
|
||||
test "a Mobilizon event" do
|
||||
user = insert(:user)
|
||||
|
||||
{:ok, object} =
|
||||
Pleroma.Object.Fetcher.fetch_object_from_id(
|
||||
"https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39"
|
||||
)
|
||||
|
||||
%Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"])
|
||||
|
||||
represented = StatusView.render("show.json", %{for: user, activity: activity})
|
||||
|
||||
assert represented[:id] == to_string(activity.id)
|
||||
end
|
||||
|
||||
describe "build_tags/1" do
|
||||
test "it returns a a dictionary tags" do
|
||||
object_tags = [
|
||||
|
|
|
@ -26,7 +26,32 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
|
|||
]
|
||||
end
|
||||
|
||||
test "it does not render attachments if post is nsfw" do
|
||||
test "it uses summary twittercard if post has no attachment" do
|
||||
user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994")
|
||||
{:ok, activity} = CommonAPI.post(user, %{"status" => "HI"})
|
||||
|
||||
note =
|
||||
insert(:note, %{
|
||||
data: %{
|
||||
"actor" => user.ap_id,
|
||||
"tag" => [],
|
||||
"id" => "https://pleroma.gov/objects/whatever",
|
||||
"content" => "pleroma in a nutshell"
|
||||
}
|
||||
})
|
||||
|
||||
result = TwitterCard.build_tags(%{object: note, user: user, activity_id: activity.id})
|
||||
|
||||
assert [
|
||||
{:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []},
|
||||
{:meta, [property: "twitter:description", content: "“pleroma in a nutshell”"], []},
|
||||
{:meta, [property: "twitter:image", content: "http://localhost:4001/images/avi.png"],
|
||||
[]},
|
||||
{:meta, [property: "twitter:card", content: "summary"], []}
|
||||
] == result
|
||||
end
|
||||
|
||||
test "it renders avatar not attachment if post is nsfw and unfurl_nsfw is disabled" do
|
||||
Pleroma.Config.put([Pleroma.Web.Metadata, :unfurl_nsfw], false)
|
||||
user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994")
|
||||
{:ok, activity} = CommonAPI.post(user, %{"status" => "HI"})
|
||||
|
@ -67,7 +92,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
|
|||
{:meta, [property: "twitter:description", content: "“pleroma in a nutshell”"], []},
|
||||
{:meta, [property: "twitter:image", content: "http://localhost:4001/images/avi.png"],
|
||||
[]},
|
||||
{:meta, [property: "twitter:card", content: "summary_large_image"], []}
|
||||
{:meta, [property: "twitter:card", content: "summary"], []}
|
||||
] == result
|
||||
end
|
||||
|
||||
|
|
|
@ -16,6 +16,10 @@ defmodule Pleroma.Web.StreamerTest do
|
|||
alias Pleroma.Web.Streamer.Worker
|
||||
|
||||
@moduletag needs_streamer: true, capture_log: true
|
||||
|
||||
@streamer_timeout 150
|
||||
@streamer_start_wait 10
|
||||
|
||||
clear_config_all([:instance, :skip_thread_containment])
|
||||
|
||||
describe "user streams" do
|
||||
|
@ -28,7 +32,7 @@ defmodule Pleroma.Web.StreamerTest do
|
|||
test "it sends notify to in the 'user' stream", %{user: user, notify: notify} do
|
||||
task =
|
||||
Task.async(fn ->
|
||||
assert_receive {:text, _}, 4_000
|
||||
assert_receive {:text, _}, @streamer_timeout
|
||||
end)
|
||||
|
||||
Streamer.add_socket(
|
||||
|
@ -43,7 +47,7 @@ defmodule Pleroma.Web.StreamerTest do
|
|||
test "it sends notify to in the 'user:notification' stream", %{user: user, notify: notify} do
|
||||
task =
|
||||
Task.async(fn ->
|
||||
assert_receive {:text, _}, 4_000
|
||||
assert_receive {:text, _}, @streamer_timeout
|
||||
end)
|
||||
|
||||
Streamer.add_socket(
|
||||
|
@ -61,7 +65,7 @@ defmodule Pleroma.Web.StreamerTest do
|
|||
blocked = insert(:user)
|
||||
{:ok, _user_relationship} = User.block(user, blocked)
|
||||
|
||||
task = Task.async(fn -> refute_receive {:text, _}, 4_000 end)
|
||||
task = Task.async(fn -> refute_receive {:text, _}, @streamer_timeout end)
|
||||
|
||||
Streamer.add_socket(
|
||||
"user:notification",
|
||||
|
@ -79,7 +83,7 @@ defmodule Pleroma.Web.StreamerTest do
|
|||
user: user
|
||||
} do
|
||||
user2 = insert(:user)
|
||||
task = Task.async(fn -> refute_receive {:text, _}, 4_000 end)
|
||||
task = Task.async(fn -> refute_receive {:text, _}, @streamer_timeout end)
|
||||
|
||||
Streamer.add_socket(
|
||||
"user:notification",
|
||||
|
@ -97,7 +101,7 @@ defmodule Pleroma.Web.StreamerTest do
|
|||
user: user
|
||||
} do
|
||||
user2 = insert(:user, %{ap_id: "https://hecking-lewd-place.com/user/meanie"})
|
||||
task = Task.async(fn -> refute_receive {:text, _}, 4_000 end)
|
||||
task = Task.async(fn -> refute_receive {:text, _}, @streamer_timeout end)
|
||||
|
||||
Streamer.add_socket(
|
||||
"user:notification",
|
||||
|
@ -116,7 +120,9 @@ defmodule Pleroma.Web.StreamerTest do
|
|||
user: user
|
||||
} do
|
||||
user2 = insert(:user)
|
||||
task = Task.async(fn -> assert_receive {:text, _}, 4_000 end)
|
||||
task = Task.async(fn -> assert_receive {:text, _}, @streamer_timeout end)
|
||||
|
||||
Process.sleep(@streamer_start_wait)
|
||||
|
||||
Streamer.add_socket(
|
||||
"user:notification",
|
||||
|
@ -137,7 +143,7 @@ defmodule Pleroma.Web.StreamerTest do
|
|||
|
||||
task =
|
||||
Task.async(fn ->
|
||||
assert_receive {:text, _}, 4_000
|
||||
assert_receive {:text, _}, @streamer_timeout
|
||||
end)
|
||||
|
||||
fake_socket = %StreamerSocket{
|
||||
|
@ -164,7 +170,7 @@ defmodule Pleroma.Web.StreamerTest do
|
|||
}
|
||||
|> Jason.encode!()
|
||||
|
||||
assert_receive {:text, received_event}, 4_000
|
||||
assert_receive {:text, received_event}, @streamer_timeout
|
||||
assert received_event == expected_event
|
||||
end)
|
||||
|
||||
|
@ -458,9 +464,7 @@ defmodule Pleroma.Web.StreamerTest do
|
|||
|
||||
{:ok, activity} = CommonAPI.add_mute(user2, activity)
|
||||
|
||||
task = Task.async(fn -> refute_receive {:text, _}, 4_000 end)
|
||||
|
||||
Process.sleep(4000)
|
||||
task = Task.async(fn -> refute_receive {:text, _}, @streamer_timeout end)
|
||||
|
||||
Streamer.add_socket(
|
||||
"user",
|
||||
|
@ -482,7 +486,7 @@ defmodule Pleroma.Web.StreamerTest do
|
|||
|
||||
task =
|
||||
Task.async(fn ->
|
||||
assert_receive {:text, received_event}, 4_000
|
||||
assert_receive {:text, received_event}, @streamer_timeout
|
||||
|
||||
assert %{"event" => "conversation", "payload" => received_payload} =
|
||||
Jason.decode!(received_event)
|
||||
|
@ -518,13 +522,13 @@ defmodule Pleroma.Web.StreamerTest do
|
|||
|
||||
task =
|
||||
Task.async(fn ->
|
||||
assert_receive {:text, received_event}, 4_000
|
||||
assert_receive {:text, received_event}, @streamer_timeout
|
||||
assert %{"event" => "delete", "payload" => _} = Jason.decode!(received_event)
|
||||
|
||||
refute_receive {:text, _}, 4_000
|
||||
refute_receive {:text, _}, @streamer_timeout
|
||||
end)
|
||||
|
||||
Process.sleep(1000)
|
||||
Process.sleep(@streamer_start_wait)
|
||||
|
||||
Streamer.add_socket(
|
||||
"direct",
|
||||
|
@ -555,10 +559,10 @@ defmodule Pleroma.Web.StreamerTest do
|
|||
|
||||
task =
|
||||
Task.async(fn ->
|
||||
assert_receive {:text, received_event}, 4_000
|
||||
assert_receive {:text, received_event}, @streamer_timeout
|
||||
assert %{"event" => "delete", "payload" => _} = Jason.decode!(received_event)
|
||||
|
||||
assert_receive {:text, received_event}, 4_000
|
||||
assert_receive {:text, received_event}, @streamer_timeout
|
||||
|
||||
assert %{"event" => "conversation", "payload" => received_payload} =
|
||||
Jason.decode!(received_event)
|
||||
|
@ -567,7 +571,7 @@ defmodule Pleroma.Web.StreamerTest do
|
|||
assert last_status["id"] == to_string(create_activity.id)
|
||||
end)
|
||||
|
||||
Process.sleep(1000)
|
||||
Process.sleep(@streamer_start_wait)
|
||||
|
||||
Streamer.add_socket(
|
||||
"direct",
|
||||
|
|
|
@ -898,8 +898,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
|||
|> post("/api/pleroma/delete_account", %{"password" => "test"})
|
||||
|
||||
assert json_response(conn, 200) == %{"status" => "success"}
|
||||
# Wait a second for the started task to end
|
||||
:timer.sleep(1000)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue