Merge branch 'develop' into issue/941

This commit is contained in:
Maksim Pechnikov 2019-06-04 09:49:08 +03:00
commit 4f2e359687
45 changed files with 1456 additions and 149 deletions

View file

@ -0,0 +1,64 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"toot": "http://joinmastodon.org/ns#",
"featured": {
"@id": "toot:featured",
"@type": "@id"
},
"alsoKnownAs": {
"@id": "as:alsoKnownAs",
"@type": "@id"
},
"movedTo": {
"@id": "as:movedTo",
"@type": "@id"
},
"schema": "http://schema.org#",
"PropertyValue": "schema:PropertyValue",
"value": "schema:value",
"Hashtag": "as:Hashtag",
"Emoji": "toot:Emoji",
"IdentityProof": "toot:IdentityProof",
"focalPoint": {
"@container": "@list",
"@id": "toot:focalPoint"
}
}
],
"id": "https://mastodon.sdf.org/users/rinpatch",
"type": "Person",
"following": "https://mastodon.sdf.org/users/rinpatch/following",
"followers": "https://mastodon.sdf.org/users/rinpatch/followers",
"inbox": "https://mastodon.sdf.org/users/rinpatch/inbox",
"outbox": "https://mastodon.sdf.org/users/rinpatch/outbox",
"featured": "https://mastodon.sdf.org/users/rinpatch/collections/featured",
"preferredUsername": "rinpatch",
"name": "rinpatch",
"summary": "<p>umu</p>",
"url": "https://mastodon.sdf.org/@rinpatch",
"manuallyApprovesFollowers": false,
"publicKey": {
"id": "https://mastodon.sdf.org/users/rinpatch#main-key",
"owner": "https://mastodon.sdf.org/users/rinpatch",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1vbhYKDopb5xzfJB2TZY\n0ZvgxqdAhbSKKkQC5Q2b0ofhvueDy2AuZTnVk1/BbHNlqKlwhJUSpA6LiTZVvtcc\nMn6cmSaJJEg30gRF5GARP8FMcuq8e2jmceiW99NnUX17MQXsddSf2JFUwD0rUE8H\nBsgD7UzE9+zlA/PJOTBO7fvBEz9PTQ3r4sRMTJVFvKz2MU/U+aRNTuexRKMMPnUw\nfp6VWh1F44VWJEQOs4tOEjGiQiMQh5OfBk1w2haT3vrDbQvq23tNpUP1cRomLUtx\nEBcGKi5DMMBzE1RTVT1YUykR/zLWlA+JSmw7P6cWtsHYZovs8dgn8Po3X//6N+ng\nTQIDAQAB\n-----END PUBLIC KEY-----\n"
},
"tag": [],
"attachment": [],
"endpoints": {
"sharedInbox": "https://mastodon.sdf.org/inbox"
},
"icon": {
"type": "Image",
"mediaType": "image/jpeg",
"url": "https://mastodon.sdf.org/system/accounts/avatars/000/067/580/original/bf05521bf711b7a0.jpg?1533238802"
},
"image": {
"type": "Image",
"mediaType": "image/gif",
"url": "https://mastodon.sdf.org/system/accounts/headers/000/067/580/original/a99b987e798f7063.gif?1533278217"
}
}

View file

@ -0,0 +1,99 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
{
"ostatus": "http://ostatus.org#",
"atomUri": "ostatus:atomUri",
"inReplyToAtomUri": "ostatus:inReplyToAtomUri",
"conversation": "ostatus:conversation",
"sensitive": "as:sensitive",
"Hashtag": "as:Hashtag",
"toot": "http://joinmastodon.org/ns#",
"Emoji": "toot:Emoji",
"focalPoint": {
"@container": "@list",
"@id": "toot:focalPoint"
}
}
],
"id": "https://mastodon.sdf.org/users/rinpatch/statuses/102070944809637304/activity",
"type": "Create",
"actor": "https://mastodon.sdf.org/users/rinpatch",
"published": "2019-05-10T09:03:36Z",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [
"https://mastodon.sdf.org/users/rinpatch/followers"
],
"object": {
"id": "https://mastodon.sdf.org/users/rinpatch/statuses/102070944809637304",
"type": "Question",
"summary": null,
"inReplyTo": null,
"published": "2019-05-10T09:03:36Z",
"url": "https://mastodon.sdf.org/@rinpatch/102070944809637304",
"attributedTo": "https://mastodon.sdf.org/users/rinpatch",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [
"https://mastodon.sdf.org/users/rinpatch/followers"
],
"sensitive": false,
"atomUri": "https://mastodon.sdf.org/users/rinpatch/statuses/102070944809637304",
"inReplyToAtomUri": null,
"conversation": "tag:mastodon.sdf.org,2019-05-10:objectId=15095122:objectType=Conversation",
"content": "<p>Why is Tenshi eating a corndog so cute?</p>",
"contentMap": {
"en": "<p>Why is Tenshi eating a corndog so cute?</p>"
},
"endTime": "2019-05-11T09:03:36Z",
"closed": "2019-05-11T09:03:36Z",
"attachment": [],
"tag": [],
"replies": {
"id": "https://mastodon.sdf.org/users/rinpatch/statuses/102070944809637304/replies",
"type": "Collection",
"first": {
"type": "CollectionPage",
"partOf": "https://mastodon.sdf.org/users/rinpatch/statuses/102070944809637304/replies",
"items": []
}
},
"oneOf": [
{
"type": "Note",
"name": "Dunno",
"replies": {
"type": "Collection",
"totalItems": 0
}
},
{
"type": "Note",
"name": "Everyone knows that!",
"replies": {
"type": "Collection",
"totalItems": 1
}
},
{
"type": "Note",
"name": "25 char limit is dumb",
"replies": {
"type": "Collection",
"totalItems": 0
}
},
{
"type": "Note",
"name": "I can't even fit a funny",
"replies": {
"type": "Collection",
"totalItems": 1
}
}
]
}
}

16
test/fixtures/mastodon-vote.json vendored Normal file
View file

@ -0,0 +1,16 @@
{
"@context": "https://www.w3.org/ns/activitystreams",
"actor": "https://mastodon.sdf.org/users/rinpatch",
"id": "https://mastodon.sdf.org/users/rinpatch#votes/387/activity",
"nickname": "rin",
"object": {
"attributedTo": "https://mastodon.sdf.org/users/rinpatch",
"id": "https://mastodon.sdf.org/users/rinpatch#votes/387",
"inReplyTo": "https://testing.uguu.ltd/objects/9d300947-2dcb-445d-8978-9a3b4b84fa14",
"name": "suya..",
"to": "https://testing.uguu.ltd/users/rin",
"type": "Note"
},
"to": "https://testing.uguu.ltd/users/rin",
"type": "Create"
}

View file

@ -78,33 +78,6 @@ defmodule Pleroma.NotificationTest do
assert nil == Notification.create_notification(activity, muter)
end
test "it disables notifications from people on remote instances" do
user = insert(:user, info: %{notification_settings: %{"remote" => false}})
other_user = insert(:user)
create_activity = %{
"@context" => "https://www.w3.org/ns/activitystreams",
"type" => "Create",
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"actor" => other_user.ap_id,
"object" => %{
"type" => "Note",
"content" => "Hi @#{user.nickname}",
"attributedTo" => other_user.ap_id
}
}
{:ok, %{local: false} = activity} = Transmogrifier.handle_incoming(create_activity)
assert nil == Notification.create_notification(activity, user)
end
test "it disables notifications from people on the local instance" do
user = insert(:user, info: %{notification_settings: %{"local" => false}})
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
assert nil == Notification.create_notification(activity, user)
end
test "it disables notifications from followers" do
follower = insert(:user)
followed = insert(:user, info: %{notification_settings: %{"followers" => false}})
@ -113,6 +86,13 @@ defmodule Pleroma.NotificationTest do
assert nil == Notification.create_notification(activity, followed)
end
test "it disables notifications from non-followers" do
follower = insert(:user)
followed = insert(:user, info: %{notification_settings: %{"non_followers" => false}})
{:ok, activity} = CommonAPI.post(follower, %{"status" => "hey @#{followed.nickname}"})
assert nil == Notification.create_notification(activity, followed)
end
test "it disables notifications from people the user follows" do
follower = insert(:user, info: %{notification_settings: %{"follows" => false}})
followed = insert(:user)
@ -122,6 +102,13 @@ defmodule Pleroma.NotificationTest do
assert nil == Notification.create_notification(activity, follower)
end
test "it disables notifications from people the user does not follow" do
follower = insert(:user, info: %{notification_settings: %{"non_follows" => false}})
followed = insert(:user)
{:ok, activity} = CommonAPI.post(followed, %{"status" => "hey @#{follower.nickname}"})
assert nil == Notification.create_notification(activity, follower)
end
test "it doesn't create a notification for user if he is the activity author" do
activity = insert(:note_activity)
author = User.get_cached_by_ap_id(activity.data["actor"])

View file

@ -6,6 +6,11 @@ defmodule Pleroma.Object.ContainmentTest do
import Pleroma.Factory
setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
:ok
end
describe "general origin containment" do
test "contain_origin_from_id() catches obvious spoofing attempts" do
data = %{

View file

@ -52,6 +52,14 @@ defmodule HttpRequestMock do
}}
end
def get("https://mastodon.sdf.org/users/rinpatch", _, _, _) do
{:ok,
%Tesla.Env{
status: 200,
body: File.read!("test/fixtures/httpoison_mock/rinpatch.json")
}}
end
def get(
"https://mastodon.social/.well-known/webfinger?resource=https://mastodon.social/users/emelie",
_,
@ -235,6 +243,14 @@ defmodule HttpRequestMock do
}}
end
def get("https://n1u.moe/users/rye", _, _, Accept: "application/activity+json") do
{:ok,
%Tesla.Env{
status: 200,
body: File.read!("test/fixtures/httpoison_mock/rye.json")
}}
end
def get("http://mastodon.example.org/users/admin/statuses/100787282858396771", _, _, _) do
{:ok,
%Tesla.Env{
@ -294,6 +310,10 @@ defmodule HttpRequestMock do
}}
end
def get("http://mastodon.example.org/users/gargron", _, _, Accept: "application/activity+json") do
{:error, :nxdomain}
end
def get(
"http://mastodon.example.org/@admin/99541947525187367",
_,
@ -538,6 +558,15 @@ defmodule HttpRequestMock do
}}
end
def get(
"http://gs.example.org:4040/index.php/user/1",
_,
_,
Accept: "application/activity+json"
) do
{:ok, %Tesla.Env{status: 406, body: ""}}
end
def get("http://gs.example.org/index.php/api/statuses/user_timeline/1.atom", _, _, _) do
{:ok,
%Tesla.Env{

View file

@ -0,0 +1,32 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicyTest do
use Pleroma.DataCase
alias Pleroma.Web.ActivityPub.MRF.DropPolicy
alias Pleroma.Web.ActivityPub.MRF.SubchainPolicy
@message %{
"actor" => "https://banned.com",
"type" => "Create",
"object" => %{"content" => "hi"}
}
test "it matches and processes subchains when the actor matches a configured target" do
Pleroma.Config.put([:mrf_subchain, :match_actor], %{
~r/^https:\/\/banned.com/s => [DropPolicy]
})
{:reject, _} = SubchainPolicy.filter(@message)
end
test "it doesn't match and process subchains when the actor doesn't match a configured target" do
Pleroma.Config.put([:mrf_subchain, :match_actor], %{
~r/^https:\/\/borked.com/s => [DropPolicy]
})
{:ok, _message} = SubchainPolicy.filter(@message)
end
end

View file

@ -113,6 +113,55 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert Enum.at(object.data["tag"], 2) == "moo"
end
test "it works for incoming questions" do
data = File.read!("test/fixtures/mastodon-question-activity.json") |> Poison.decode!()
{:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
object = Object.normalize(activity)
assert Enum.all?(object.data["oneOf"], fn choice ->
choice["name"] in [
"Dunno",
"Everyone knows that!",
"25 char limit is dumb",
"I can't even fit a funny"
]
end)
end
test "it rewrites Note votes to Answers and increments vote counters on question activities" do
user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "suya...",
"poll" => %{"options" => ["suya", "suya.", "suya.."], "expires_in" => 10}
})
object = Object.normalize(activity)
data =
File.read!("test/fixtures/mastodon-vote.json")
|> Poison.decode!()
|> Kernel.put_in(["to"], user.ap_id)
|> Kernel.put_in(["object", "inReplyTo"], object.data["id"])
|> Kernel.put_in(["object", "to"], user.ap_id)
{:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
answer_object = Object.normalize(activity)
assert answer_object.data["type"] == "Answer"
object = Object.get_by_ap_id(object.data["id"])
assert Enum.any?(
object.data["oneOf"],
fn
%{"name" => "suya..", "replies" => %{"totalItems" => 1}} -> true
_ -> false
end
)
end
test "it works for incoming notices with contentMap" do
data =
File.read!("test/fixtures/mastodon-post-activity-contentmap.json") |> Poison.decode!()
@ -1210,6 +1259,30 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
end
end
test "Rewrites Answers to Notes" do
user = insert(:user)
{:ok, poll_activity} =
CommonAPI.post(user, %{
"status" => "suya...",
"poll" => %{"options" => ["suya", "suya.", "suya.."], "expires_in" => 10}
})
poll_object = Object.normalize(poll_activity)
# TODO: Replace with CommonAPI vote creation when implemented
data =
File.read!("test/fixtures/mastodon-vote.json")
|> Poison.decode!()
|> Kernel.put_in(["to"], user.ap_id)
|> Kernel.put_in(["object", "inReplyTo"], poll_object.data["id"])
|> Kernel.put_in(["object", "to"], user.ap_id)
{:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
assert data["object"]["type"] == "Note"
end
describe "fix_explicit_addressing" do
setup do
user = insert(:user)

View file

@ -79,10 +79,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
user = insert(:user)
notification_settings = %{
"remote" => true,
"local" => true,
"followers" => true,
"follows" => true
"follows" => true,
"non_follows" => true,
"non_followers" => true
}
privacy = user.info.default_scope
@ -242,4 +242,19 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
assert expected == AccountView.render("account.json", %{user: user, for: other_user})
end
test "returns the settings store if the requesting user is the represented user and it's requested specifically" do
user = insert(:user, %{info: %User.Info{pleroma_settings_store: %{fe: "test"}}})
result =
AccountView.render("account.json", %{user: user, for: user, with_pleroma_settings: true})
assert result.pleroma.settings_store == %{:fe => "test"}
result = AccountView.render("account.json", %{user: user, with_pleroma_settings: true})
assert result.pleroma[:settings_store] == nil
result = AccountView.render("account.json", %{user: user, for: user})
assert result.pleroma[:settings_store] == nil
end
end

View file

@ -146,6 +146,103 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
refute id == third_id
end
describe "posting polls" do
test "posting a poll", %{conn: conn} do
user = insert(:user)
time = NaiveDateTime.utc_now()
conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{
"status" => "Who is the #bestgrill?",
"poll" => %{"options" => ["Rei", "Asuka", "Misato"], "expires_in" => 420}
})
response = json_response(conn, 200)
assert Enum.all?(response["poll"]["options"], fn %{"title" => title} ->
title in ["Rei", "Asuka", "Misato"]
end)
assert NaiveDateTime.diff(NaiveDateTime.from_iso8601!(response["poll"]["expires_at"]), time) in 420..430
refute response["poll"]["expred"]
end
test "option limit is enforced", %{conn: conn} do
user = insert(:user)
limit = Pleroma.Config.get([:instance, :poll_limits, :max_options])
conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{
"status" => "desu~",
"poll" => %{"options" => Enum.map(0..limit, fn _ -> "desu" end), "expires_in" => 1}
})
%{"error" => error} = json_response(conn, 422)
assert error == "Poll can't contain more than #{limit} options"
end
test "option character limit is enforced", %{conn: conn} do
user = insert(:user)
limit = Pleroma.Config.get([:instance, :poll_limits, :max_option_chars])
conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{
"status" => "...",
"poll" => %{
"options" => [Enum.reduce(0..limit, "", fn _, acc -> acc <> "." end)],
"expires_in" => 1
}
})
%{"error" => error} = json_response(conn, 422)
assert error == "Poll options cannot be longer than #{limit} characters each"
end
test "minimal date limit is enforced", %{conn: conn} do
user = insert(:user)
limit = Pleroma.Config.get([:instance, :poll_limits, :min_expiration])
conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{
"status" => "imagine arbitrary limits",
"poll" => %{
"options" => ["this post was made by pleroma gang"],
"expires_in" => limit - 1
}
})
%{"error" => error} = json_response(conn, 422)
assert error == "Expiration date is too soon"
end
test "maximum date limit is enforced", %{conn: conn} do
user = insert(:user)
limit = Pleroma.Config.get([:instance, :poll_limits, :max_expiration])
conn =
conn
|> assign(:user, user)
|> post("/api/v1/statuses", %{
"status" => "imagine arbitrary limits",
"poll" => %{
"options" => ["this post was made by pleroma gang"],
"expires_in" => limit + 1
}
})
%{"error" => error} = json_response(conn, 422)
assert error == "Expiration date is too far in the future"
end
end
test "posting a sensitive status", %{conn: conn} do
user = insert(:user)
@ -317,12 +414,13 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
test "Conversations", %{conn: conn} do
user_one = insert(:user)
user_two = insert(:user)
user_three = insert(:user)
{:ok, user_two} = User.follow(user_two, user_one)
{:ok, direct} =
CommonAPI.post(user_one, %{
"status" => "Hi @#{user_two.nickname}!",
"status" => "Hi @#{user_two.nickname}, @#{user_three.nickname}!",
"visibility" => "direct"
})
@ -348,7 +446,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
}
] = response
account_ids = Enum.map(res_accounts, & &1["id"])
assert length(res_accounts) == 2
assert user_two.id in account_ids
assert user_three.id in account_ids
assert is_binary(res_id)
assert unread == true
assert res_last_status["id"] == direct.id
@ -2322,6 +2423,66 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
end
describe "updating credentials" do
test "sets user settings in a generic way", %{conn: conn} do
user = insert(:user)
res_conn =
conn
|> assign(:user, user)
|> patch("/api/v1/accounts/update_credentials", %{
"pleroma_settings_store" => %{
pleroma_fe: %{
theme: "bla"
}
}
})
assert user = json_response(res_conn, 200)
assert user["pleroma"]["settings_store"] == %{"pleroma_fe" => %{"theme" => "bla"}}
user = Repo.get(User, user["id"])
res_conn =
conn
|> assign(:user, user)
|> patch("/api/v1/accounts/update_credentials", %{
"pleroma_settings_store" => %{
masto_fe: %{
theme: "bla"
}
}
})
assert user = json_response(res_conn, 200)
assert user["pleroma"]["settings_store"] ==
%{
"pleroma_fe" => %{"theme" => "bla"},
"masto_fe" => %{"theme" => "bla"}
}
user = Repo.get(User, user["id"])
res_conn =
conn
|> assign(:user, user)
|> patch("/api/v1/accounts/update_credentials", %{
"pleroma_settings_store" => %{
masto_fe: %{
theme: "blub"
}
}
})
assert user = json_response(res_conn, 200)
assert user["pleroma"]["settings_store"] ==
%{
"pleroma_fe" => %{"theme" => "bla"},
"masto_fe" => %{"theme" => "blub"}
}
end
test "updates the user's bio", %{conn: conn} do
user = insert(:user)
user2 = insert(:user)
@ -2551,7 +2712,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
"stats" => _,
"thumbnail" => _,
"languages" => _,
"registrations" => _
"registrations" => _,
"poll_limits" => _
} = result
assert email == from_config_email
@ -3450,4 +3612,124 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert json_response(conn, 403) == %{"error" => "Rate limit exceeded."}
end
end
describe "GET /api/v1/polls/:id" do
test "returns poll entity for object id", %{conn: conn} do
user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "Pleroma does",
"poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20}
})
object = Object.normalize(activity)
conn =
conn
|> assign(:user, user)
|> get("/api/v1/polls/#{object.id}")
response = json_response(conn, 200)
id = object.id
assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
end
test "does not expose polls for private statuses", %{conn: conn} do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "Pleroma does",
"poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20},
"visibility" => "private"
})
object = Object.normalize(activity)
conn =
conn
|> assign(:user, other_user)
|> get("/api/v1/polls/#{object.id}")
assert json_response(conn, 404)
end
end
describe "POST /api/v1/polls/:id/votes" do
test "votes are added to the poll", %{conn: conn} do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "A very delicious sandwich",
"poll" => %{
"options" => ["Lettuce", "Grilled Bacon", "Tomato"],
"expires_in" => 20,
"multiple" => true
}
})
object = Object.normalize(activity)
conn =
conn
|> assign(:user, other_user)
|> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
assert json_response(conn, 200)
object = Object.get_by_id(object.id)
assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
total_items == 1
end)
end
test "author can't vote", %{conn: conn} do
user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "Am I cute?",
"poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
})
object = Object.normalize(activity)
assert conn
|> assign(:user, user)
|> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]})
|> json_response(422) == %{"error" => "Poll's author can't vote"}
object = Object.get_by_id(object.id)
refute Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 1
end
test "does not allow multiple choices on a single-choice question", %{conn: conn} do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "The glass is",
"poll" => %{"options" => ["half empty", "half full"], "expires_in" => 20}
})
object = Object.normalize(activity)
assert conn
|> assign(:user, other_user)
|> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]})
|> json_response(422) == %{"error" => "Too many choices"}
object = Object.get_by_id(object.id)
refute Enum.any?(object.data["oneOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
total_items == 1
end)
end
end
end

View file

@ -103,6 +103,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
muted: false,
pinned: false,
sensitive: false,
poll: nil,
spoiler_text: HtmlSanitizeEx.basic_html(note.data["object"]["summary"]),
visibility: "public",
media_attachments: [],
@ -341,4 +342,106 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
StatusView.render("card.json", %{page_url: page_url, rich_media: card})
end
end
describe "poll view" do
test "renders a poll" do
user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "Is Tenshi eating a corndog cute?",
"poll" => %{
"options" => ["absolutely!", "sure", "yes", "why are you even asking?"],
"expires_in" => 20
}
})
object = Object.normalize(activity)
expected = %{
emojis: [],
expired: false,
id: object.id,
multiple: false,
options: [
%{title: "absolutely!", votes_count: 0},
%{title: "sure", votes_count: 0},
%{title: "yes", votes_count: 0},
%{title: "why are you even asking?", votes_count: 0}
],
voted: false,
votes_count: 0
}
result = StatusView.render("poll.json", %{object: object})
expires_at = result.expires_at
result = Map.delete(result, :expires_at)
assert result == expected
expires_at = NaiveDateTime.from_iso8601!(expires_at)
assert NaiveDateTime.diff(expires_at, NaiveDateTime.utc_now()) in 15..20
end
test "detects if it is multiple choice" do
user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "Which Mastodon developer is your favourite?",
"poll" => %{
"options" => ["Gargron", "Eugen"],
"expires_in" => 20,
"multiple" => true
}
})
object = Object.normalize(activity)
assert %{multiple: true} = StatusView.render("poll.json", %{object: object})
end
test "detects emoji" do
user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "What's with the smug face?",
"poll" => %{
"options" => [":blank: sip", ":blank::blank: sip", ":blank::blank::blank: sip"],
"expires_in" => 20
}
})
object = Object.normalize(activity)
assert %{emojis: [%{shortcode: "blank"}]} =
StatusView.render("poll.json", %{object: object})
end
test "detects vote status" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
"status" => "Which input devices do you use?",
"poll" => %{
"options" => ["mouse", "trackball", "trackpoint"],
"multiple" => true,
"expires_in" => 20
}
})
object = Object.normalize(activity)
{:ok, _, object} = CommonAPI.vote(other_user, object, [1, 2])
result = StatusView.render("poll.json", %{object: object, for: other_user})
assert result[:voted] == true
assert Enum.at(result[:options], 1)[:votes_count] == 1
assert Enum.at(result[:options], 2)[:votes_count] == 1
end
end
end

View file

@ -102,7 +102,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
conn
|> assign(:user, user)
|> put("/api/pleroma/notification_settings", %{
"remote" => false,
"followers" => false,
"bar" => 1
})
@ -110,8 +109,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
user = Repo.get(User, user.id)
assert %{"remote" => false, "local" => true, "followers" => false, "follows" => true} ==
user.info.notification_settings
assert %{
"followers" => false,
"follows" => true,
"non_follows" => true,
"non_followers" => true
} == user.info.notification_settings
end
end

View file

@ -113,9 +113,11 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
as_user = UserView.render("show.json", %{user: user, for: user})
assert as_user["default_scope"] == user.info.default_scope
assert as_user["no_rich_text"] == user.info.no_rich_text
assert as_user["pleroma"]["notification_settings"] == user.info.notification_settings
as_stranger = UserView.render("show.json", %{user: user})
refute as_stranger["default_scope"]
refute as_stranger["no_rich_text"]
refute as_stranger["pleroma"]["notification_settings"]
end
test "A user for a given other follower", %{user: user} do