Merge remote-tracking branch 'remotes/origin/develop' into 1478-oauth-admin-scopes-tweaks
This commit is contained in:
commit
5304c8cd21
|
@ -10,14 +10,16 @@ variables: &global_variables
|
||||||
cache: &global_cache_policy
|
cache: &global_cache_policy
|
||||||
key: ${CI_COMMIT_REF_SLUG}
|
key: ${CI_COMMIT_REF_SLUG}
|
||||||
paths:
|
paths:
|
||||||
- deps
|
- deps
|
||||||
- _build
|
- _build
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- build
|
- build
|
||||||
- test
|
- test
|
||||||
- benchmark
|
- benchmark
|
||||||
- deploy
|
- deploy
|
||||||
- release
|
- release
|
||||||
|
- docker
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- mix local.hex --force
|
- mix local.hex --force
|
||||||
|
@ -264,3 +266,50 @@ arm64-musl:
|
||||||
variables: *release-variables
|
variables: *release-variables
|
||||||
before_script: *before-release-musl
|
before_script: *before-release-musl
|
||||||
script: *release
|
script: *release
|
||||||
|
|
||||||
|
docker:
|
||||||
|
stage: docker
|
||||||
|
image: docker:latest
|
||||||
|
cache: {}
|
||||||
|
dependencies: []
|
||||||
|
variables: &docker-variables
|
||||||
|
DOCKER_DRIVER: overlay2
|
||||||
|
DOCKER_HOST: unix:///var/run/docker.sock
|
||||||
|
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
|
||||||
|
IMAGE_TAG_SLUG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
|
||||||
|
IMAGE_TAG_LATEST: $CI_REGISTRY_IMAGE:latest
|
||||||
|
IMAGE_TAG_LATEST_STABLE: $CI_REGISTRY_IMAGE:latest-stable
|
||||||
|
before_script: &before-docker
|
||||||
|
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||||
|
- export CI_JOB_TIMESTAMP=$(date --utc -Iseconds)
|
||||||
|
- export CI_VCS_REF=$CI_COMMIT_SHORT_SHA
|
||||||
|
allow_failure: true
|
||||||
|
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 push $IMAGE_TAG
|
||||||
|
- docker push $IMAGE_TAG_SLUG
|
||||||
|
- docker push $IMAGE_TAG_LATEST
|
||||||
|
tags:
|
||||||
|
- dind
|
||||||
|
only:
|
||||||
|
- develop
|
||||||
|
|
||||||
|
docker-stable:
|
||||||
|
stage: docker
|
||||||
|
image: docker:latest
|
||||||
|
cache: {}
|
||||||
|
dependencies: []
|
||||||
|
variables: *docker-variables
|
||||||
|
before_script: *before-docker
|
||||||
|
allow_failure: true
|
||||||
|
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 push $IMAGE_TAG
|
||||||
|
- docker push $IMAGE_TAG_SLUG
|
||||||
|
- docker push $IMAGE_TAG_LATEST_STABLE
|
||||||
|
tags:
|
||||||
|
- dind
|
||||||
|
only:
|
||||||
|
- stable
|
||||||
|
|
|
@ -7,8 +7,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
### Removed
|
### Removed
|
||||||
- **Breaking**: Removed 1.0+ deprecated configurations `Pleroma.Upload, :strip_exif` and `:instance, :dedupe_media`
|
- **Breaking**: Removed 1.0+ deprecated configurations `Pleroma.Upload, :strip_exif` and `:instance, :dedupe_media`
|
||||||
- **Breaking**: OStatus protocol support
|
- **Breaking**: OStatus protocol support
|
||||||
|
- **Breaking**: MDII uploader
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
- **Breaking:** attachments are removed along with statuses when there are no other references to it
|
||||||
- **Breaking:** Elixir >=1.8 is now required (was >= 1.7)
|
- **Breaking:** Elixir >=1.8 is now required (was >= 1.7)
|
||||||
- **Breaking:** attachment links (`config :pleroma, :instance, no_attachment_links` and `config :pleroma, Pleroma.Upload, link_name`) disabled by default
|
- **Breaking:** attachment links (`config :pleroma, :instance, no_attachment_links` and `config :pleroma, Pleroma.Upload, link_name`) disabled by default
|
||||||
- **Breaking:** OAuth: defaulted `[:auth, :enforce_oauth_admin_scope_usage]` setting to `true` which demands `admin` OAuth scope to perform admin actions (in addition to `is_admin` flag on User); make sure to use bundled or newer versions of AdminFE & PleromaFE to access admin / moderator features.
|
- **Breaking:** OAuth: defaulted `[:auth, :enforce_oauth_admin_scope_usage]` setting to `true` which demands `admin` OAuth scope to perform admin actions (in addition to `is_admin` flag on User); make sure to use bundled or newer versions of AdminFE & PleromaFE to access admin / moderator features.
|
||||||
|
@ -89,6 +91,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Mastodon API: `/api/v1/update_credentials` accepts `actor_type` field.
|
- Mastodon API: `/api/v1/update_credentials` accepts `actor_type` field.
|
||||||
- Captcha: Support native provider
|
- Captcha: Support native provider
|
||||||
- Captcha: Enable by default
|
- Captcha: Enable by default
|
||||||
|
- Mastodon API: Add support for `account_id` param to filter notifications by the account
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
@ -105,6 +108,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Mastodon API: Inability to get some local users by nickname in `/api/v1/accounts/:id_or_nickname`
|
- Mastodon API: Inability to get some local users by nickname in `/api/v1/accounts/:id_or_nickname`
|
||||||
- AdminAPI: If some status received reports both in the "new" format and "old" format it was considered reports on two different statuses (in the context of grouped reports)
|
- AdminAPI: If some status received reports both in the "new" format and "old" format it was considered reports on two different statuses (in the context of grouped reports)
|
||||||
- Admin API: Error when trying to update reports in the "old" format
|
- Admin API: Error when trying to update reports in the "old" format
|
||||||
|
- Mastodon API: Marking a conversation as read (`POST /api/v1/conversations/:id/read`) now no longer brings it to the top in the user's direct conversation list
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## [1.1.6] - 2019-11-19
|
## [1.1.6] - 2019-11-19
|
||||||
|
|
14
Dockerfile
14
Dockerfile
|
@ -14,6 +14,20 @@ RUN apk add git gcc g++ musl-dev make &&\
|
||||||
|
|
||||||
FROM alpine:3.9
|
FROM alpine:3.9
|
||||||
|
|
||||||
|
ARG BUILD_DATE
|
||||||
|
ARG VCS_REF
|
||||||
|
|
||||||
|
LABEL maintainer="ops@pleroma.social" \
|
||||||
|
org.opencontainers.image.title="pleroma" \
|
||||||
|
org.opencontainers.image.description="Pleroma for Docker" \
|
||||||
|
org.opencontainers.image.authors="ops@pleroma.social" \
|
||||||
|
org.opencontainers.image.vendor="pleroma.social" \
|
||||||
|
org.opencontainers.image.documentation="https://git.pleroma.social/pleroma/pleroma" \
|
||||||
|
org.opencontainers.image.licenses="AGPL-3.0" \
|
||||||
|
org.opencontainers.image.url="https://pleroma.social" \
|
||||||
|
org.opencontainers.image.revision=$VCS_REF \
|
||||||
|
org.opencontainers.image.created=$BUILD_DATE
|
||||||
|
|
||||||
ARG HOME=/opt/pleroma
|
ARG HOME=/opt/pleroma
|
||||||
ARG DATA=/var/lib/pleroma
|
ARG DATA=/var/lib/pleroma
|
||||||
|
|
||||||
|
|
|
@ -82,3 +82,11 @@
|
||||||
IO.puts("RUM enabled: #{rum_enabled}")
|
IO.puts("RUM enabled: #{rum_enabled}")
|
||||||
|
|
||||||
config :pleroma, Pleroma.ReverseProxy.Client, Pleroma.ReverseProxy.ClientMock
|
config :pleroma, Pleroma.ReverseProxy.Client, Pleroma.ReverseProxy.ClientMock
|
||||||
|
|
||||||
|
if File.exists?("./config/benchmark.secret.exs") do
|
||||||
|
import_config "benchmark.secret.exs"
|
||||||
|
else
|
||||||
|
IO.puts(
|
||||||
|
"You may want to create benchmark.secret.exs to declare custom database connection parameters."
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
|
@ -108,10 +108,6 @@
|
||||||
streaming_enabled: true,
|
streaming_enabled: true,
|
||||||
public_endpoint: "https://s3.amazonaws.com"
|
public_endpoint: "https://s3.amazonaws.com"
|
||||||
|
|
||||||
config :pleroma, Pleroma.Uploaders.MDII,
|
|
||||||
cgi: "https://mdii.sakura.ne.jp/mdii-post.cgi",
|
|
||||||
files: "https://mdii.sakura.ne.jp"
|
|
||||||
|
|
||||||
config :pleroma, :emoji,
|
config :pleroma, :emoji,
|
||||||
shortcode_globs: ["/emoji/custom/**/*.png"],
|
shortcode_globs: ["/emoji/custom/**/*.png"],
|
||||||
pack_extensions: [".png", ".gif"],
|
pack_extensions: [".png", ".gif"],
|
||||||
|
|
|
@ -2557,23 +2557,6 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
%{
|
|
||||||
group: :pleroma,
|
|
||||||
key: Pleroma.Uploaders.MDII,
|
|
||||||
type: :group,
|
|
||||||
children: [
|
|
||||||
%{
|
|
||||||
key: :cgi,
|
|
||||||
type: :string,
|
|
||||||
suggestions: ["https://mdii.sakura.ne.jp/mdii-post.cgi"]
|
|
||||||
},
|
|
||||||
%{
|
|
||||||
key: :files,
|
|
||||||
type: :string,
|
|
||||||
suggestions: ["https://mdii.sakura.ne.jp"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
%{
|
%{
|
||||||
group: :pleroma,
|
group: :pleroma,
|
||||||
key: :http,
|
key: :http,
|
||||||
|
|
|
@ -46,7 +46,7 @@ The `id` parameter can also be the `nickname` of the user. This only works in th
|
||||||
Has these additional fields under the `pleroma` object:
|
Has these additional fields under the `pleroma` object:
|
||||||
|
|
||||||
- `tags`: Lists an array of tags for the user
|
- `tags`: Lists an array of tags for the user
|
||||||
- `relationship{}`: Includes fields as documented for Mastodon API https://docs.joinmastodon.org/api/entities/#relationship
|
- `relationship{}`: Includes fields as documented for Mastodon API https://docs.joinmastodon.org/entities/relationship/
|
||||||
- `is_moderator`: boolean, nullable, true if user is a moderator
|
- `is_moderator`: boolean, nullable, true if user is a moderator
|
||||||
- `is_admin`: boolean, nullable, true if user is an admin
|
- `is_admin`: boolean, nullable, true if user is an admin
|
||||||
- `confirmation_pending`: boolean, true if a new user account is waiting on email confirmation to be activated
|
- `confirmation_pending`: boolean, true if a new user account is waiting on email confirmation to be activated
|
||||||
|
|
|
@ -64,11 +64,13 @@ def mark_as_read(%User{} = user, %Conversation{} = conversation) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def mark_as_read(participation) do
|
def mark_as_read(participation) do
|
||||||
participation
|
__MODULE__
|
||||||
|> read_cng(%{read: true})
|
|> where(id: ^participation.id)
|
||||||
|> Repo.update()
|
|> update(set: [read: true])
|
||||||
|
|> select([p], p)
|
||||||
|
|> Repo.update_all([])
|
||||||
|> case do
|
|> case do
|
||||||
{:ok, participation} ->
|
{1, [participation]} ->
|
||||||
participation = Repo.preload(participation, :user)
|
participation = Repo.preload(participation, :user)
|
||||||
User.set_unread_conversation_count(participation.user)
|
User.set_unread_conversation_count(participation.user)
|
||||||
{:ok, participation}
|
{:ok, participation}
|
||||||
|
|
|
@ -17,6 +17,8 @@ defmodule Pleroma.Object do
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
@type t() :: %__MODULE__{}
|
||||||
|
|
||||||
schema "objects" do
|
schema "objects" do
|
||||||
field(:data, :map)
|
field(:data, :map)
|
||||||
|
|
||||||
|
@ -79,6 +81,20 @@ def get_by_ap_id(ap_id) do
|
||||||
Repo.one(from(object in Object, where: fragment("(?)->>'id' = ?", object.data, ^ap_id)))
|
Repo.one(from(object in Object, where: fragment("(?)->>'id' = ?", object.data, ^ap_id)))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Get a single attachment by it's name and href
|
||||||
|
"""
|
||||||
|
@spec get_attachment_by_name_and_href(String.t(), String.t()) :: Object.t() | nil
|
||||||
|
def get_attachment_by_name_and_href(name, href) do
|
||||||
|
query =
|
||||||
|
from(o in Object,
|
||||||
|
where: fragment("(?)->>'name' = ?", o.data, ^name),
|
||||||
|
where: fragment("(?)->>'href' = ?", o.data, ^href)
|
||||||
|
)
|
||||||
|
|
||||||
|
Repo.one(query)
|
||||||
|
end
|
||||||
|
|
||||||
defp warn_on_no_object_preloaded(ap_id) do
|
defp warn_on_no_object_preloaded(ap_id) do
|
||||||
"Object.normalize() called without preloaded object (#{inspect(ap_id)}). Consider preloading the object"
|
"Object.normalize() called without preloaded object (#{inspect(ap_id)}). Consider preloading the object"
|
||||||
|> Logger.debug()
|
|> Logger.debug()
|
||||||
|
@ -164,6 +180,7 @@ def swap_object_with_tombstone(object) do
|
||||||
|
|
||||||
def delete(%Object{data: %{"id" => id}} = object) do
|
def delete(%Object{data: %{"id" => id}} = object) do
|
||||||
with {:ok, _obj} = swap_object_with_tombstone(object),
|
with {:ok, _obj} = swap_object_with_tombstone(object),
|
||||||
|
:ok <- delete_attachments(object),
|
||||||
deleted_activity = Activity.delete_all_by_object_ap_id(id),
|
deleted_activity = Activity.delete_all_by_object_ap_id(id),
|
||||||
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}"),
|
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}"),
|
||||||
{:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do
|
{:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do
|
||||||
|
@ -171,6 +188,77 @@ def delete(%Object{data: %{"id" => id}} = object) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp delete_attachments(%{data: %{"attachment" => [_ | _] = attachments, "actor" => actor}}) do
|
||||||
|
hrefs =
|
||||||
|
Enum.flat_map(attachments, fn attachment ->
|
||||||
|
Enum.map(attachment["url"], & &1["href"])
|
||||||
|
end)
|
||||||
|
|
||||||
|
names = Enum.map(attachments, & &1["name"])
|
||||||
|
|
||||||
|
uploader = Pleroma.Config.get([Pleroma.Upload, :uploader])
|
||||||
|
|
||||||
|
# find all objects for copies of the attachments, name and actor doesn't matter here
|
||||||
|
delete_ids =
|
||||||
|
from(o in Object,
|
||||||
|
where:
|
||||||
|
fragment(
|
||||||
|
"to_jsonb(array(select jsonb_array_elements((?)#>'{url}') ->> 'href'))::jsonb \\?| (?)",
|
||||||
|
o.data,
|
||||||
|
^hrefs
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|> Repo.all()
|
||||||
|
# we should delete 1 object for any given attachment, but don't delete files if
|
||||||
|
# there are more than 1 object for it
|
||||||
|
|> Enum.reduce(%{}, fn %{
|
||||||
|
id: id,
|
||||||
|
data: %{
|
||||||
|
"url" => [%{"href" => href}],
|
||||||
|
"actor" => obj_actor,
|
||||||
|
"name" => name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
acc ->
|
||||||
|
Map.update(acc, href, %{id: id, count: 1}, fn val ->
|
||||||
|
case obj_actor == actor and name in names do
|
||||||
|
true ->
|
||||||
|
# set id of the actor's object that will be deleted
|
||||||
|
%{val | id: id, count: val.count + 1}
|
||||||
|
|
||||||
|
false ->
|
||||||
|
# another actor's object, just increase count to not delete file
|
||||||
|
%{val | count: val.count + 1}
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|> Enum.map(fn {href, %{id: id, count: count}} ->
|
||||||
|
# only delete files that have single instance
|
||||||
|
with 1 <- count do
|
||||||
|
prefix =
|
||||||
|
case Pleroma.Config.get([Pleroma.Upload, :base_url]) do
|
||||||
|
nil -> "media"
|
||||||
|
_ -> ""
|
||||||
|
end
|
||||||
|
|
||||||
|
base_url = Pleroma.Config.get([__MODULE__, :base_url], Pleroma.Web.base_url())
|
||||||
|
|
||||||
|
file_path = String.trim_leading(href, "#{base_url}/#{prefix}")
|
||||||
|
|
||||||
|
uploader.delete_file(file_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
id
|
||||||
|
end)
|
||||||
|
|
||||||
|
from(o in Object, where: o.id in ^delete_ids)
|
||||||
|
|> Repo.delete_all()
|
||||||
|
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
|
defp delete_attachments(%{data: _data}), do: :ok
|
||||||
|
|
||||||
def prune(%Object{data: %{"id" => id}} = object) do
|
def prune(%Object{data: %{"id" => id}} = object) do
|
||||||
with {:ok, object} <- Repo.delete(object),
|
with {:ok, object} <- Repo.delete(object),
|
||||||
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}"),
|
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}"),
|
||||||
|
|
|
@ -5,10 +5,12 @@
|
||||||
defmodule Pleroma.Uploaders.Local do
|
defmodule Pleroma.Uploaders.Local do
|
||||||
@behaviour Pleroma.Uploaders.Uploader
|
@behaviour Pleroma.Uploaders.Uploader
|
||||||
|
|
||||||
|
@impl true
|
||||||
def get_file(_) do
|
def get_file(_) do
|
||||||
{:ok, {:static_dir, upload_path()}}
|
{:ok, {:static_dir, upload_path()}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
def put_file(upload) do
|
def put_file(upload) do
|
||||||
{local_path, file} =
|
{local_path, file} =
|
||||||
case Enum.reverse(Path.split(upload.path)) do
|
case Enum.reverse(Path.split(upload.path)) do
|
||||||
|
@ -33,4 +35,15 @@ def put_file(upload) do
|
||||||
def upload_path do
|
def upload_path do
|
||||||
Pleroma.Config.get!([__MODULE__, :uploads])
|
Pleroma.Config.get!([__MODULE__, :uploads])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def delete_file(path) do
|
||||||
|
upload_path()
|
||||||
|
|> Path.join(path)
|
||||||
|
|> File.rm()
|
||||||
|
|> case do
|
||||||
|
:ok -> :ok
|
||||||
|
{:error, posix_error} -> {:error, to_string(posix_error)}
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Uploaders.MDII do
|
|
||||||
@moduledoc "Represents uploader for https://github.com/hakaba-hitoyo/minimal-digital-image-infrastructure"
|
|
||||||
|
|
||||||
alias Pleroma.Config
|
|
||||||
alias Pleroma.HTTP
|
|
||||||
|
|
||||||
@behaviour Pleroma.Uploaders.Uploader
|
|
||||||
|
|
||||||
# MDII-hosted images are never passed through the MediaPlug; only local media.
|
|
||||||
# Delegate to Pleroma.Uploaders.Local
|
|
||||||
def get_file(file) do
|
|
||||||
Pleroma.Uploaders.Local.get_file(file)
|
|
||||||
end
|
|
||||||
|
|
||||||
def put_file(upload) do
|
|
||||||
cgi = Config.get([Pleroma.Uploaders.MDII, :cgi])
|
|
||||||
files = Config.get([Pleroma.Uploaders.MDII, :files])
|
|
||||||
|
|
||||||
{:ok, file_data} = File.read(upload.tempfile)
|
|
||||||
|
|
||||||
extension = String.split(upload.name, ".") |> List.last()
|
|
||||||
query = "#{cgi}?#{extension}"
|
|
||||||
|
|
||||||
with {:ok, %{status: 200, body: body}} <-
|
|
||||||
HTTP.post(query, file_data, [], adapter: [pool: :default]) do
|
|
||||||
remote_file_name = String.split(body) |> List.first()
|
|
||||||
public_url = "#{files}/#{remote_file_name}.#{extension}"
|
|
||||||
{:ok, {:url, public_url}}
|
|
||||||
else
|
|
||||||
_ -> Pleroma.Uploaders.Local.put_file(upload)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -10,6 +10,7 @@ defmodule Pleroma.Uploaders.S3 do
|
||||||
|
|
||||||
# The file name is re-encoded with S3's constraints here to comply with previous
|
# The file name is re-encoded with S3's constraints here to comply with previous
|
||||||
# links with less strict filenames
|
# links with less strict filenames
|
||||||
|
@impl true
|
||||||
def get_file(file) do
|
def get_file(file) do
|
||||||
config = Config.get([__MODULE__])
|
config = Config.get([__MODULE__])
|
||||||
bucket = Keyword.fetch!(config, :bucket)
|
bucket = Keyword.fetch!(config, :bucket)
|
||||||
|
@ -35,6 +36,7 @@ def get_file(file) do
|
||||||
])}}
|
])}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
def put_file(%Pleroma.Upload{} = upload) do
|
def put_file(%Pleroma.Upload{} = upload) do
|
||||||
config = Config.get([__MODULE__])
|
config = Config.get([__MODULE__])
|
||||||
bucket = Keyword.get(config, :bucket)
|
bucket = Keyword.get(config, :bucket)
|
||||||
|
@ -69,6 +71,18 @@ def put_file(%Pleroma.Upload{} = upload) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def delete_file(file) do
|
||||||
|
[__MODULE__, :bucket]
|
||||||
|
|> Config.get()
|
||||||
|
|> ExAws.S3.delete_object(file)
|
||||||
|
|> ExAws.request()
|
||||||
|
|> case do
|
||||||
|
{:ok, %{status_code: 204}} -> :ok
|
||||||
|
error -> {:error, inspect(error)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@regex Regex.compile!("[^0-9a-zA-Z!.*/'()_-]")
|
@regex Regex.compile!("[^0-9a-zA-Z!.*/'()_-]")
|
||||||
def strict_encode(name) do
|
def strict_encode(name) do
|
||||||
String.replace(name, @regex, "-")
|
String.replace(name, @regex, "-")
|
||||||
|
|
|
@ -36,6 +36,8 @@ defmodule Pleroma.Uploaders.Uploader do
|
||||||
@callback put_file(Pleroma.Upload.t()) ::
|
@callback put_file(Pleroma.Upload.t()) ::
|
||||||
:ok | {:ok, file_spec()} | {:error, String.t()} | :wait_callback
|
:ok | {:ok, file_spec()} | {:error, String.t()} | :wait_callback
|
||||||
|
|
||||||
|
@callback delete_file(file :: String.t()) :: :ok | {:error, String.t()}
|
||||||
|
|
||||||
@callback http_callback(Plug.Conn.t(), Map.t()) ::
|
@callback http_callback(Plug.Conn.t(), Map.t()) ::
|
||||||
{:ok, Plug.Conn.t()}
|
{:ok, Plug.Conn.t()}
|
||||||
| {:ok, Plug.Conn.t(), file_spec()}
|
| {:ok, Plug.Conn.t(), file_spec()}
|
||||||
|
@ -43,7 +45,6 @@ defmodule Pleroma.Uploaders.Uploader do
|
||||||
@optional_callbacks http_callback: 2
|
@optional_callbacks http_callback: 2
|
||||||
|
|
||||||
@spec put_file(module(), Pleroma.Upload.t()) :: {:ok, file_spec()} | {:error, String.t()}
|
@spec put_file(module(), Pleroma.Upload.t()) :: {:ok, file_spec()} | {:error, String.t()}
|
||||||
|
|
||||||
def put_file(uploader, upload) do
|
def put_file(uploader, upload) do
|
||||||
case uploader.put_file(upload) do
|
case uploader.put_file(upload) do
|
||||||
:ok -> {:ok, {:file, upload.path}}
|
:ok -> {:ok, {:file, upload.path}}
|
||||||
|
|
|
@ -264,6 +264,10 @@ def gather_webfinger_links(%User{} = user) do
|
||||||
"rel" => "self",
|
"rel" => "self",
|
||||||
"type" => "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"",
|
"type" => "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"",
|
||||||
"href" => user.ap_id
|
"href" => user.ap_id
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"rel" => "http://ostatus.org/schema/1.0/subscribe",
|
||||||
|
"template" => "#{Pleroma.Web.base_url()}/ostatus_subscribe?acct={uri}"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,6 +23,23 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
|
||||||
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
|
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
|
||||||
|
|
||||||
# GET /api/v1/notifications
|
# GET /api/v1/notifications
|
||||||
|
def index(conn, %{"account_id" => account_id} = params) do
|
||||||
|
case Pleroma.User.get_cached_by_id(account_id) do
|
||||||
|
%{ap_id: account_ap_id} ->
|
||||||
|
params =
|
||||||
|
params
|
||||||
|
|> Map.delete("account_id")
|
||||||
|
|> Map.put("account_ap_id", account_ap_id)
|
||||||
|
|
||||||
|
index(conn, params)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
conn
|
||||||
|
|> put_status(:not_found)
|
||||||
|
|> json(%{"error" => "Account is not found"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def index(%{assigns: %{user: user}} = conn, params) do
|
def index(%{assigns: %{user: user}} = conn, params) do
|
||||||
notifications = MastodonAPI.get_notifications(user, params)
|
notifications = MastodonAPI.get_notifications(user, params)
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ def get_notifications(user, params \\ %{}) do
|
||||||
user
|
user
|
||||||
|> Notification.for_user_query(options)
|
|> Notification.for_user_query(options)
|
||||||
|> restrict(:exclude_types, options)
|
|> restrict(:exclude_types, options)
|
||||||
|
|> restrict(:account_ap_id, options)
|
||||||
|> Pagination.fetch_paginated(params)
|
|> Pagination.fetch_paginated(params)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -71,7 +72,8 @@ defp cast_params(params) do
|
||||||
exclude_visibilities: {:array, :string},
|
exclude_visibilities: {:array, :string},
|
||||||
reblogs: :boolean,
|
reblogs: :boolean,
|
||||||
with_muted: :boolean,
|
with_muted: :boolean,
|
||||||
with_move: :boolean
|
with_move: :boolean,
|
||||||
|
account_ap_id: :string
|
||||||
}
|
}
|
||||||
|
|
||||||
changeset = cast({%{}, param_types}, params, Map.keys(param_types))
|
changeset = cast({%{}, param_types}, params, Map.keys(param_types))
|
||||||
|
@ -88,5 +90,9 @@ defp restrict(query, :exclude_types, %{exclude_types: mastodon_types = [_ | _]})
|
||||||
|> where([q, a], not fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data))
|
|> where([q, a], not fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp restrict(query, :account_ap_id, %{account_ap_id: account_ap_id}) do
|
||||||
|
where(query, [n, a], a.actor == ^account_ap_id)
|
||||||
|
end
|
||||||
|
|
||||||
defp restrict(query, _, _), do: query
|
defp restrict(query, _, _), do: query
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,6 +15,7 @@ def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do
|
||||||
|> String.replace(~r/<br\s?\/?>/, " ")
|
|> String.replace(~r/<br\s?\/?>/, " ")
|
||||||
|> HTML.get_cached_stripped_html_for_activity(object, "metadata")
|
|> HTML.get_cached_stripped_html_for_activity(object, "metadata")
|
||||||
|> Emoji.Formatter.demojify()
|
|> Emoji.Formatter.demojify()
|
||||||
|
|> HtmlEntities.decode()
|
||||||
|> Formatter.truncate()
|
|> Formatter.truncate()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -25,6 +26,7 @@ def scrub_html_and_truncate(content, max_length \\ 200) when is_binary(content)
|
||||||
|> String.replace(~r/<br\s?\/?>/, " ")
|
|> String.replace(~r/<br\s?\/?>/, " ")
|
||||||
|> HTML.strip_tags()
|
|> HTML.strip_tags()
|
||||||
|> Emoji.Formatter.demojify()
|
|> Emoji.Formatter.demojify()
|
||||||
|
|> HtmlEntities.decode()
|
||||||
|> Formatter.truncate(max_length)
|
|> Formatter.truncate(max_length)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -229,9 +229,9 @@ defmodule Pleroma.Web.Router do
|
||||||
pipe_through(:pleroma_html)
|
pipe_through(:pleroma_html)
|
||||||
|
|
||||||
post("/main/ostatus", UtilController, :remote_subscribe)
|
post("/main/ostatus", UtilController, :remote_subscribe)
|
||||||
get("/ostatus_subscribe", UtilController, :remote_follow)
|
get("/ostatus_subscribe", RemoteFollowController, :follow)
|
||||||
|
|
||||||
post("/ostatus_subscribe", UtilController, :do_remote_follow)
|
post("/ostatus_subscribe", RemoteFollowController, :do_follow)
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/api/pleroma", Pleroma.Web.TwitterAPI do
|
scope "/api/pleroma", Pleroma.Web.TwitterAPI do
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<%= if @error == :error do %>
|
||||||
|
<h2>Error fetching user</h2>
|
||||||
|
<% else %>
|
||||||
|
<h2>Remote follow</h2>
|
||||||
|
<img height="128" width="128" src="<%= avatar_url(@followee) %>">
|
||||||
|
<p><%= @followee.nickname %></p>
|
||||||
|
<%= form_for @conn, remote_follow_path(@conn, :do_follow), [as: "user"], fn f -> %>
|
||||||
|
<%= hidden_input f, :id, value: @followee.id %>
|
||||||
|
<%= submit "Authorize" %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<%= if @error do %>
|
||||||
|
<h2><%= @error %></h2>
|
||||||
|
<% end %>
|
||||||
|
<h2>Log in to follow</h2>
|
||||||
|
<p><%= @followee.nickname %></p>
|
||||||
|
<img height="128" width="128" src="<%= avatar_url(@followee) %>">
|
||||||
|
<%= form_for @conn, remote_follow_path(@conn, :do_follow), [as: "authorization"], fn f -> %>
|
||||||
|
<%= text_input f, :name, placeholder: "Username", required: true %>
|
||||||
|
<br>
|
||||||
|
<%= password_input f, :password, placeholder: "Password", required: true %>
|
||||||
|
<br>
|
||||||
|
<%= hidden_input f, :id, value: @followee.id %>
|
||||||
|
<%= submit "Authorize" %>
|
||||||
|
<% end %>
|
|
@ -1,11 +0,0 @@
|
||||||
<%= if @error == :error do %>
|
|
||||||
<h2>Error fetching user</h2>
|
|
||||||
<% else %>
|
|
||||||
<h2>Remote follow</h2>
|
|
||||||
<img width="128" height="128" src="<%= @avatar %>">
|
|
||||||
<p><%= @name %></p>
|
|
||||||
<%= form_for @conn, util_path(@conn, :do_remote_follow), [as: "user"], fn f -> %>
|
|
||||||
<%= hidden_input f, :id, value: @id %>
|
|
||||||
<%= submit "Authorize" %>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
|
@ -1,14 +0,0 @@
|
||||||
<%= if @error do %>
|
|
||||||
<h2><%= @error %></h2>
|
|
||||||
<% end %>
|
|
||||||
<h2>Log in to follow</h2>
|
|
||||||
<p><%= @name %></p>
|
|
||||||
<img height="128" width="128" src="<%= @avatar %>">
|
|
||||||
<%= form_for @conn, util_path(@conn, :do_remote_follow), [as: "authorization"], fn f -> %>
|
|
||||||
<%= text_input f, :name, placeholder: "Username" %>
|
|
||||||
<br>
|
|
||||||
<%= password_input f, :password, placeholder: "Password" %>
|
|
||||||
<br>
|
|
||||||
<%= hidden_input f, :id, value: @id %>
|
|
||||||
<%= submit "Authorize" %>
|
|
||||||
<% end %>
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do
|
||||||
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
|
require Logger
|
||||||
|
|
||||||
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Object.Fetcher
|
||||||
|
alias Pleroma.Plugs.OAuthScopesPlug
|
||||||
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.Auth.Authenticator
|
||||||
|
alias Pleroma.Web.CommonAPI
|
||||||
|
|
||||||
|
@status_types ["Article", "Event", "Note", "Video", "Page", "Question"]
|
||||||
|
|
||||||
|
# Note: follower can submit the form (with password auth) not being signed in (having no token)
|
||||||
|
plug(
|
||||||
|
OAuthScopesPlug,
|
||||||
|
%{fallback: :proceed_unauthenticated, scopes: ["follow", "write:follows"]}
|
||||||
|
when action in [:do_follow]
|
||||||
|
)
|
||||||
|
|
||||||
|
# GET /ostatus_subscribe
|
||||||
|
#
|
||||||
|
def follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
|
||||||
|
case is_status?(acct) do
|
||||||
|
true -> follow_status(conn, user, acct)
|
||||||
|
_ -> follow_account(conn, user, acct)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp follow_status(conn, _user, acct) do
|
||||||
|
with {:ok, object} <- Fetcher.fetch_object_from_id(acct),
|
||||||
|
%Activity{id: activity_id} <- Activity.get_create_by_object_ap_id(object.data["id"]) do
|
||||||
|
redirect(conn, to: o_status_path(conn, :notice, activity_id))
|
||||||
|
else
|
||||||
|
error ->
|
||||||
|
handle_follow_error(conn, error)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp follow_account(conn, user, acct) do
|
||||||
|
with {:ok, followee} <- User.get_or_fetch(acct) do
|
||||||
|
render(conn, follow_template(user), %{error: false, followee: followee, acct: acct})
|
||||||
|
else
|
||||||
|
{:error, _reason} ->
|
||||||
|
render(conn, follow_template(user), %{error: :error})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp follow_template(%User{} = _user), do: "follow.html"
|
||||||
|
defp follow_template(_), do: "follow_login.html"
|
||||||
|
|
||||||
|
defp is_status?(acct) do
|
||||||
|
case Fetcher.fetch_and_contain_remote_object_from_id(acct) do
|
||||||
|
{:ok, %{"type" => type}} when type in @status_types ->
|
||||||
|
true
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /ostatus_subscribe
|
||||||
|
#
|
||||||
|
def do_follow(%{assigns: %{user: %User{} = user}} = conn, %{"user" => %{"id" => id}}) do
|
||||||
|
with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
|
||||||
|
{:ok, _, _, _} <- CommonAPI.follow(user, followee) do
|
||||||
|
render(conn, "followed.html", %{error: false})
|
||||||
|
else
|
||||||
|
error ->
|
||||||
|
handle_follow_error(conn, error)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def do_follow(conn, %{"authorization" => %{"name" => _, "password" => _, "id" => id}}) do
|
||||||
|
with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
|
||||||
|
{_, {:ok, user}, _} <- {:auth, Authenticator.get_user(conn), followee},
|
||||||
|
{:ok, _, _, _} <- CommonAPI.follow(user, followee) do
|
||||||
|
render(conn, "followed.html", %{error: false})
|
||||||
|
else
|
||||||
|
error ->
|
||||||
|
handle_follow_error(conn, error)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def do_follow(%{assigns: %{user: nil}} = conn, _) do
|
||||||
|
Logger.debug("Insufficient permissions: follow | write:follows.")
|
||||||
|
render(conn, "followed.html", %{error: "Insufficient permissions: follow | write:follows."})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_follow_error(conn, {:auth, _, followee} = _) do
|
||||||
|
render(conn, "follow_login.html", %{error: "Wrong username or password", followee: followee})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_follow_error(conn, {:fetch_user, error} = _) do
|
||||||
|
Logger.debug("Remote follow failed with error #{inspect(error)}")
|
||||||
|
render(conn, "followed.html", %{error: "Could not find user"})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_follow_error(conn, {:error, "Could not follow user:" <> _} = _) do
|
||||||
|
render(conn, "followed.html", %{error: "Error following account"})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_follow_error(conn, error) do
|
||||||
|
Logger.debug("Remote follow failed with error #{inspect(error)}")
|
||||||
|
render(conn, "followed.html", %{error: "Something went wrong."})
|
||||||
|
end
|
||||||
|
end
|
|
@ -7,12 +7,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
alias Pleroma.Activity
|
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
alias Pleroma.Emoji
|
alias Pleroma.Emoji
|
||||||
alias Pleroma.Healthcheck
|
alias Pleroma.Healthcheck
|
||||||
alias Pleroma.Notification
|
alias Pleroma.Notification
|
||||||
alias Pleroma.Plugs.AuthenticationPlug
|
|
||||||
alias Pleroma.Plugs.OAuthScopesPlug
|
alias Pleroma.Plugs.OAuthScopesPlug
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web
|
alias Pleroma.Web
|
||||||
|
@ -84,105 +82,6 @@ def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
|
|
||||||
if is_status?(acct) do
|
|
||||||
{:ok, object} = Pleroma.Object.Fetcher.fetch_object_from_id(acct)
|
|
||||||
%Activity{id: activity_id} = Activity.get_create_by_object_ap_id(object.data["id"])
|
|
||||||
redirect(conn, to: "/notice/#{activity_id}")
|
|
||||||
else
|
|
||||||
with {:ok, followee} <- User.get_or_fetch(acct) do
|
|
||||||
conn
|
|
||||||
|> render(follow_template(user), %{
|
|
||||||
error: false,
|
|
||||||
acct: acct,
|
|
||||||
avatar: User.avatar_url(followee),
|
|
||||||
name: followee.nickname,
|
|
||||||
id: followee.id
|
|
||||||
})
|
|
||||||
else
|
|
||||||
{:error, _reason} ->
|
|
||||||
render(conn, follow_template(user), %{error: :error})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp follow_template(%User{} = _user), do: "follow.html"
|
|
||||||
defp follow_template(_), do: "follow_login.html"
|
|
||||||
|
|
||||||
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", "Event", "Note", "Video", "Page", "Question"] ->
|
|
||||||
true
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}})
|
|
||||||
when not is_nil(user) do
|
|
||||||
with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
|
|
||||||
{:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do
|
|
||||||
conn
|
|
||||||
|> render("followed.html", %{error: false})
|
|
||||||
else
|
|
||||||
# Was already following user
|
|
||||||
{:error, "Could not follow user:" <> _rest} ->
|
|
||||||
render(conn, "followed.html", %{error: "Error following account"})
|
|
||||||
|
|
||||||
{:fetch_user, error} ->
|
|
||||||
Logger.debug("Remote follow failed with error #{inspect(error)}")
|
|
||||||
render(conn, "followed.html", %{error: "Could not find user"})
|
|
||||||
|
|
||||||
e ->
|
|
||||||
Logger.debug("Remote follow failed with error #{inspect(e)}")
|
|
||||||
render(conn, "followed.html", %{error: "Something went wrong."})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Note: "id" is the id of followee user, disregard incorrect placing under "authorization"
|
|
||||||
def do_remote_follow(conn, %{
|
|
||||||
"authorization" => %{"name" => username, "password" => password, "id" => id}
|
|
||||||
}) do
|
|
||||||
with %User{} = followee <- User.get_cached_by_id(id),
|
|
||||||
{_, %User{} = user, _} <- {:auth, User.get_cached_by_nickname(username), followee},
|
|
||||||
{_, true, _} <- {
|
|
||||||
:auth,
|
|
||||||
AuthenticationPlug.checkpw(password, user.password_hash),
|
|
||||||
followee
|
|
||||||
},
|
|
||||||
{:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do
|
|
||||||
conn
|
|
||||||
|> render("followed.html", %{error: false})
|
|
||||||
else
|
|
||||||
# Was already following user
|
|
||||||
{:error, "Could not follow user:" <> _rest} ->
|
|
||||||
render(conn, "followed.html", %{error: "Error following account"})
|
|
||||||
|
|
||||||
{:auth, _, followee} ->
|
|
||||||
conn
|
|
||||||
|> render("follow_login.html", %{
|
|
||||||
error: "Wrong username or password",
|
|
||||||
id: id,
|
|
||||||
name: followee.nickname,
|
|
||||||
avatar: User.avatar_url(followee)
|
|
||||||
})
|
|
||||||
|
|
||||||
e ->
|
|
||||||
Logger.debug("Remote follow failed with error #{inspect(e)}")
|
|
||||||
render(conn, "followed.html", %{error: "Something went wrong."})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def do_remote_follow(%{assigns: %{user: nil}} = conn, _) do
|
|
||||||
render(conn, "followed.html", %{error: "Insufficient permissions: follow | write:follows."})
|
|
||||||
end
|
|
||||||
|
|
||||||
def do_remote_follow(conn, _) do
|
|
||||||
render(conn, "followed.html", %{error: "Something went wrong."})
|
|
||||||
end
|
|
||||||
|
|
||||||
def notifications_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
|
def notifications_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
|
||||||
with {:ok, _} <- Notification.read_one(user, notification_id) do
|
with {:ok, _} <- Notification.read_one(user, notification_id) do
|
||||||
json(conn, %{status: "success"})
|
json(conn, %{status: "success"})
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.TwitterAPI.RemoteFollowView do
|
||||||
|
use Pleroma.Web, :view
|
||||||
|
import Phoenix.HTML.Form
|
||||||
|
|
||||||
|
defdelegate avatar_url(user), to: Pleroma.User
|
||||||
|
end
|
|
@ -125,9 +125,10 @@ test "recreating an existing participations sets it to unread" do
|
||||||
|
|
||||||
test "it marks a participation as read" do
|
test "it marks a participation as read" do
|
||||||
participation = insert(:participation, %{read: false})
|
participation = insert(:participation, %{read: false})
|
||||||
{:ok, participation} = Participation.mark_as_read(participation)
|
{:ok, updated_participation} = Participation.mark_as_read(participation)
|
||||||
|
|
||||||
assert participation.read
|
assert updated_participation.read
|
||||||
|
assert updated_participation.updated_at == participation.updated_at
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it marks a participation as unread" do
|
test "it marks a participation as unread" do
|
||||||
|
|
|
@ -71,6 +71,74 @@ test "ensures cache is cleared for the object" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "delete attachments" do
|
||||||
|
clear_config([Pleroma.Upload])
|
||||||
|
|
||||||
|
test "in subdirectories" do
|
||||||
|
Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
|
||||||
|
|
||||||
|
file = %Plug.Upload{
|
||||||
|
content_type: "image/jpg",
|
||||||
|
path: Path.absname("test/fixtures/image.jpg"),
|
||||||
|
filename: "an_image.jpg"
|
||||||
|
}
|
||||||
|
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, %Object{} = attachment} =
|
||||||
|
Pleroma.Web.ActivityPub.ActivityPub.upload(file, actor: user.ap_id)
|
||||||
|
|
||||||
|
%{data: %{"attachment" => [%{"url" => [%{"href" => href}]}]}} =
|
||||||
|
note = insert(:note, %{user: user, data: %{"attachment" => [attachment.data]}})
|
||||||
|
|
||||||
|
uploads_dir = Pleroma.Config.get!([Pleroma.Uploaders.Local, :uploads])
|
||||||
|
|
||||||
|
path = href |> Path.dirname() |> Path.basename()
|
||||||
|
|
||||||
|
assert {:ok, ["an_image.jpg"]} == File.ls("#{uploads_dir}/#{path}")
|
||||||
|
|
||||||
|
Object.delete(note)
|
||||||
|
|
||||||
|
assert Object.get_by_id(attachment.id) == nil
|
||||||
|
|
||||||
|
assert {:ok, []} == File.ls("#{uploads_dir}/#{path}")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "with dedupe enabled" do
|
||||||
|
Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
|
||||||
|
Pleroma.Config.put([Pleroma.Upload, :filters], [Pleroma.Upload.Filter.Dedupe])
|
||||||
|
|
||||||
|
uploads_dir = Pleroma.Config.get!([Pleroma.Uploaders.Local, :uploads])
|
||||||
|
|
||||||
|
File.mkdir_p!(uploads_dir)
|
||||||
|
|
||||||
|
file = %Plug.Upload{
|
||||||
|
content_type: "image/jpg",
|
||||||
|
path: Path.absname("test/fixtures/image.jpg"),
|
||||||
|
filename: "an_image.jpg"
|
||||||
|
}
|
||||||
|
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, %Object{} = attachment} =
|
||||||
|
Pleroma.Web.ActivityPub.ActivityPub.upload(file, actor: user.ap_id)
|
||||||
|
|
||||||
|
%{data: %{"attachment" => [%{"url" => [%{"href" => href}]}]}} =
|
||||||
|
note = insert(:note, %{user: user, data: %{"attachment" => [attachment.data]}})
|
||||||
|
|
||||||
|
filename = Path.basename(href)
|
||||||
|
|
||||||
|
assert {:ok, files} = File.ls(uploads_dir)
|
||||||
|
assert filename in files
|
||||||
|
|
||||||
|
Object.delete(note)
|
||||||
|
|
||||||
|
assert Object.get_by_id(attachment.id) == nil
|
||||||
|
assert {:ok, files} = File.ls(uploads_dir)
|
||||||
|
refute filename in files
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "normalizer" do
|
describe "normalizer" do
|
||||||
test "fetches unknown objects by default" do
|
test "fetches unknown objects by default" do
|
||||||
%Object{} =
|
%Object{} =
|
||||||
|
|
|
@ -29,4 +29,25 @@ test "put file to local folder" do
|
||||||
|> File.exists?()
|
|> File.exists?()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "delete_file/1" do
|
||||||
|
test "deletes local file" do
|
||||||
|
file_path = "local_upload/files/image.jpg"
|
||||||
|
|
||||||
|
file = %Pleroma.Upload{
|
||||||
|
name: "image.jpg",
|
||||||
|
content_type: "image/jpg",
|
||||||
|
path: file_path,
|
||||||
|
tempfile: Path.absname("test/fixtures/image_tmp.jpg")
|
||||||
|
}
|
||||||
|
|
||||||
|
:ok = Local.put_file(file)
|
||||||
|
local_path = Path.join([Local.upload_path(), file_path])
|
||||||
|
assert File.exists?(local_path)
|
||||||
|
|
||||||
|
Local.delete_file(file_path)
|
||||||
|
|
||||||
|
refute File.exists?(local_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Uploaders.MDIITest do
|
|
||||||
use Pleroma.DataCase
|
|
||||||
alias Pleroma.Uploaders.MDII
|
|
||||||
import Tesla.Mock
|
|
||||||
|
|
||||||
describe "get_file/1" do
|
|
||||||
test "it returns path to local folder for files" do
|
|
||||||
assert MDII.get_file("") == {:ok, {:static_dir, "test/uploads"}}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "put_file/1" do
|
|
||||||
setup do
|
|
||||||
file_upload = %Pleroma.Upload{
|
|
||||||
name: "mdii-image.jpg",
|
|
||||||
content_type: "image/jpg",
|
|
||||||
path: "test_folder/mdii-image.jpg",
|
|
||||||
tempfile: Path.absname("test/fixtures/image_tmp.jpg")
|
|
||||||
}
|
|
||||||
|
|
||||||
[file_upload: file_upload]
|
|
||||||
end
|
|
||||||
|
|
||||||
test "save file", %{file_upload: file_upload} do
|
|
||||||
mock(fn
|
|
||||||
%{method: :post, url: "https://mdii.sakura.ne.jp/mdii-post.cgi?jpg"} ->
|
|
||||||
%Tesla.Env{status: 200, body: "mdii-image"}
|
|
||||||
end)
|
|
||||||
|
|
||||||
assert MDII.put_file(file_upload) ==
|
|
||||||
{:ok, {:url, "https://mdii.sakura.ne.jp/mdii-image.jpg"}}
|
|
||||||
end
|
|
||||||
|
|
||||||
test "save file to local if MDII isn`t available", %{file_upload: file_upload} do
|
|
||||||
mock(fn
|
|
||||||
%{method: :post, url: "https://mdii.sakura.ne.jp/mdii-post.cgi?jpg"} ->
|
|
||||||
%Tesla.Env{status: 500}
|
|
||||||
end)
|
|
||||||
|
|
||||||
assert MDII.put_file(file_upload) == :ok
|
|
||||||
|
|
||||||
assert Path.join([Pleroma.Uploaders.Local.upload_path(), file_upload.path])
|
|
||||||
|> File.exists?()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -79,4 +79,11 @@ test "returns error", %{file_upload: file_upload} do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "delete_file/1" do
|
||||||
|
test_with_mock "deletes file", ExAws, request: fn _req -> {:ok, %{status_code: 204}} end do
|
||||||
|
assert :ok = S3.delete_file("image.jpg")
|
||||||
|
assert_called(ExAws.request(:_))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,6 +23,27 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "gather_webfinger_links/1" do
|
||||||
|
test "it returns links" do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
expected_links = [
|
||||||
|
%{"href" => user.ap_id, "rel" => "self", "type" => "application/activity+json"},
|
||||||
|
%{
|
||||||
|
"href" => user.ap_id,
|
||||||
|
"rel" => "self",
|
||||||
|
"type" => "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"rel" => "http://ostatus.org/schema/1.0/subscribe",
|
||||||
|
"template" => "#{Pleroma.Web.base_url()}/ostatus_subscribe?acct={uri}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
assert expected_links == Publisher.gather_webfinger_links(user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "determine_inbox/2" do
|
describe "determine_inbox/2" do
|
||||||
test "it returns sharedInbox for messages involving as:Public in to" do
|
test "it returns sharedInbox for messages involving as:Public in to" do
|
||||||
user =
|
user =
|
||||||
|
|
|
@ -457,6 +457,30 @@ test "preserves parameters in link headers" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "from specified user" do
|
||||||
|
test "account_id" do
|
||||||
|
%{user: user, conn: conn} = oauth_access(["read:notifications"])
|
||||||
|
|
||||||
|
%{id: account_id} = other_user1 = insert(:user)
|
||||||
|
other_user2 = insert(:user)
|
||||||
|
|
||||||
|
{:ok, _activity} = CommonAPI.post(other_user1, %{"status" => "hi @#{user.nickname}"})
|
||||||
|
{:ok, _activity} = CommonAPI.post(other_user2, %{"status" => "bye @#{user.nickname}"})
|
||||||
|
|
||||||
|
assert [%{"account" => %{"id" => ^account_id}}] =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> get("/api/v1/notifications", %{account_id: account_id})
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
assert %{"error" => "Account is not found"} =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> get("/api/v1/notifications", %{account_id: "cofe"})
|
||||||
|
|> json_response(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp get_notification_id_by_activity(%{id: id}) do
|
defp get_notification_id_by_activity(%{id: id}) do
|
||||||
Notification
|
Notification
|
||||||
|> Repo.get_by(activity_id: id)
|
|> Repo.get_by(activity_id: id)
|
||||||
|
|
|
@ -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.Metadata.UtilsTest do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
import Pleroma.Factory
|
||||||
|
alias Pleroma.Web.Metadata.Utils
|
||||||
|
|
||||||
|
describe "scrub_html_and_truncate/1" do
|
||||||
|
test "it returns text without encode HTML" do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
note =
|
||||||
|
insert(:note, %{
|
||||||
|
data: %{
|
||||||
|
"actor" => user.ap_id,
|
||||||
|
"id" => "https://pleroma.gov/objects/whatever",
|
||||||
|
"content" => "Pleroma's really cool!"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
assert Utils.scrub_html_and_truncate(note) == "Pleroma's really cool!"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "scrub_html_and_truncate/2" do
|
||||||
|
test "it returns text without encode HTML" do
|
||||||
|
assert Utils.scrub_html_and_truncate("Pleroma's really cool!") == "Pleroma's really cool!"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,235 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
|
||||||
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.CommonAPI
|
||||||
|
import ExUnit.CaptureLog
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
setup do
|
||||||
|
Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
|
clear_config([:instance])
|
||||||
|
clear_config([:frontend_configurations, :pleroma_fe])
|
||||||
|
clear_config([:user, :deny_follow_blocked])
|
||||||
|
|
||||||
|
describe "GET /ostatus_subscribe - remote_follow/2" do
|
||||||
|
test "adds status to pleroma instance if the `acct` is a status", %{conn: conn} do
|
||||||
|
assert conn
|
||||||
|
|> get(
|
||||||
|
remote_follow_path(conn, :follow, %{
|
||||||
|
acct: "https://mastodon.social/users/emelie/statuses/101849165031453009"
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|> redirected_to() =~ "/notice/"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "show follow account page if the `acct` is a account link", %{conn: conn} do
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> get(remote_follow_path(conn, :follow, %{acct: "https://mastodon.social/users/emelie"}))
|
||||||
|
|> html_response(200)
|
||||||
|
|
||||||
|
assert response =~ "Log in to follow"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "show follow page if the `acct` is a account link", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> get(remote_follow_path(conn, :follow, %{acct: "https://mastodon.social/users/emelie"}))
|
||||||
|
|> html_response(200)
|
||||||
|
|
||||||
|
assert response =~ "Remote follow"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "show follow page with error when user cannot fecth by `acct` link", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
assert capture_log(fn ->
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> get(
|
||||||
|
remote_follow_path(conn, :follow, %{
|
||||||
|
acct: "https://mastodon.social/users/not_found"
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|> html_response(200)
|
||||||
|
|
||||||
|
assert response =~ "Error fetching user"
|
||||||
|
end) =~ "Object has been deleted"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "POST /ostatus_subscribe - do_follow/2 with assigned user " do
|
||||||
|
test "required `follow | write:follows` scope", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
user2 = insert(:user)
|
||||||
|
read_token = insert(:oauth_token, user: user, scopes: ["read"])
|
||||||
|
|
||||||
|
assert capture_log(fn ->
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> assign(:token, read_token)
|
||||||
|
|> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}})
|
||||||
|
|> response(200)
|
||||||
|
|
||||||
|
assert response =~ "Error following account"
|
||||||
|
end) =~ "Insufficient permissions: follow | write:follows."
|
||||||
|
end
|
||||||
|
|
||||||
|
test "follows user", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
user2 = insert(:user)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"]))
|
||||||
|
|> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}})
|
||||||
|
|> response(200)
|
||||||
|
|
||||||
|
assert response =~ "Account followed!"
|
||||||
|
assert user2.follower_address in User.following(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns error when user is deactivated", %{conn: conn} do
|
||||||
|
user = insert(:user, deactivated: true)
|
||||||
|
user2 = insert(:user)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}})
|
||||||
|
|> response(200)
|
||||||
|
|
||||||
|
assert response =~ "Error following account"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns error when user is blocked", %{conn: conn} do
|
||||||
|
Pleroma.Config.put([:user, :deny_follow_blocked], true)
|
||||||
|
user = insert(:user)
|
||||||
|
user2 = insert(:user)
|
||||||
|
|
||||||
|
{:ok, _user_block} = Pleroma.User.block(user2, user)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}})
|
||||||
|
|> response(200)
|
||||||
|
|
||||||
|
assert response =~ "Error following account"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns error when followee not found", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => "jimm"}})
|
||||||
|
|> response(200)
|
||||||
|
|
||||||
|
assert response =~ "Error following account"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns success result when user already in followers", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
user2 = insert(:user)
|
||||||
|
{:ok, _, _, _} = CommonAPI.follow(user, user2)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> assign(:user, refresh_record(user))
|
||||||
|
|> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"]))
|
||||||
|
|> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}})
|
||||||
|
|> response(200)
|
||||||
|
|
||||||
|
assert response =~ "Account followed!"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "POST /ostatus_subscribe - follow/2 without assigned user " do
|
||||||
|
test "follows", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
user2 = insert(:user)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> post(remote_follow_path(conn, :do_follow), %{
|
||||||
|
"authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id}
|
||||||
|
})
|
||||||
|
|> response(200)
|
||||||
|
|
||||||
|
assert response =~ "Account followed!"
|
||||||
|
assert user2.follower_address in User.following(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns error when followee not found", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> post(remote_follow_path(conn, :do_follow), %{
|
||||||
|
"authorization" => %{"name" => user.nickname, "password" => "test", "id" => "jimm"}
|
||||||
|
})
|
||||||
|
|> response(200)
|
||||||
|
|
||||||
|
assert response =~ "Error following account"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns error when login invalid", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> post(remote_follow_path(conn, :do_follow), %{
|
||||||
|
"authorization" => %{"name" => "jimm", "password" => "test", "id" => user.id}
|
||||||
|
})
|
||||||
|
|> response(200)
|
||||||
|
|
||||||
|
assert response =~ "Wrong username or password"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns error when password invalid", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
user2 = insert(:user)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> post(remote_follow_path(conn, :do_follow), %{
|
||||||
|
"authorization" => %{"name" => user.nickname, "password" => "42", "id" => user2.id}
|
||||||
|
})
|
||||||
|
|> response(200)
|
||||||
|
|
||||||
|
assert response =~ "Wrong username or password"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns error when user is blocked", %{conn: conn} do
|
||||||
|
Pleroma.Config.put([:user, :deny_follow_blocked], true)
|
||||||
|
user = insert(:user)
|
||||||
|
user2 = insert(:user)
|
||||||
|
{:ok, _user_block} = Pleroma.User.block(user2, user)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> post(remote_follow_path(conn, :do_follow), %{
|
||||||
|
"authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id}
|
||||||
|
})
|
||||||
|
|> response(200)
|
||||||
|
|
||||||
|
assert response =~ "Error following account"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -8,9 +8,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
||||||
|
|
||||||
alias Pleroma.Tests.ObanHelpers
|
alias Pleroma.Tests.ObanHelpers
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.CommonAPI
|
|
||||||
|
|
||||||
import ExUnit.CaptureLog
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
import Mock
|
import Mock
|
||||||
|
|
||||||
|
@ -319,204 +317,6 @@ test "returns json with custom emoji with tags", %{conn: conn} do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "GET /ostatus_subscribe - remote_follow/2" do
|
|
||||||
test "adds status to pleroma instance if the `acct` is a status", %{conn: conn} do
|
|
||||||
conn =
|
|
||||||
get(
|
|
||||||
conn,
|
|
||||||
"/ostatus_subscribe?acct=https://mastodon.social/users/emelie/statuses/101849165031453009"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert redirected_to(conn) =~ "/notice/"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "show follow account page if the `acct` is a account link", %{conn: conn} do
|
|
||||||
response =
|
|
||||||
get(
|
|
||||||
conn,
|
|
||||||
"/ostatus_subscribe?acct=https://mastodon.social/users/emelie"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert html_response(response, 200) =~ "Log in to follow"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "show follow page if the `acct` is a account link", %{conn: conn} do
|
|
||||||
user = insert(:user)
|
|
||||||
|
|
||||||
response =
|
|
||||||
conn
|
|
||||||
|> assign(:user, user)
|
|
||||||
|> get("/ostatus_subscribe?acct=https://mastodon.social/users/emelie")
|
|
||||||
|
|
||||||
assert html_response(response, 200) =~ "Remote follow"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "show follow page with error when user cannot fecth by `acct` link", %{conn: conn} do
|
|
||||||
user = insert(:user)
|
|
||||||
|
|
||||||
assert capture_log(fn ->
|
|
||||||
response =
|
|
||||||
conn
|
|
||||||
|> assign(:user, user)
|
|
||||||
|> get("/ostatus_subscribe?acct=https://mastodon.social/users/not_found")
|
|
||||||
|
|
||||||
assert html_response(response, 200) =~ "Error fetching user"
|
|
||||||
end) =~ "Object has been deleted"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "POST /ostatus_subscribe - do_remote_follow/2 with assigned user" do
|
|
||||||
setup do: oauth_access(["follow"])
|
|
||||||
|
|
||||||
test "follows user", %{user: user, conn: conn} do
|
|
||||||
user2 = insert(:user)
|
|
||||||
|
|
||||||
response =
|
|
||||||
conn
|
|
||||||
|> post("/ostatus_subscribe", %{"user" => %{"id" => user2.id}})
|
|
||||||
|> response(200)
|
|
||||||
|
|
||||||
assert response =~ "Account followed!"
|
|
||||||
assert user2.follower_address in User.following(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns error when user is deactivated" do
|
|
||||||
user = insert(:user, deactivated: true)
|
|
||||||
user2 = insert(:user)
|
|
||||||
|
|
||||||
response =
|
|
||||||
build_conn()
|
|
||||||
|> assign(:user, user)
|
|
||||||
|> assign(:token, insert(:oauth_token, user: user, scopes: ["follow"]))
|
|
||||||
|> post("/ostatus_subscribe", %{"user" => %{"id" => user2.id}})
|
|
||||||
|> response(200)
|
|
||||||
|
|
||||||
assert response =~ "Error following account"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns error when user is blocked", %{user: user, conn: conn} do
|
|
||||||
Pleroma.Config.put([:user, :deny_follow_blocked], true)
|
|
||||||
user2 = insert(:user)
|
|
||||||
|
|
||||||
{:ok, _user_block} = Pleroma.User.block(user2, user)
|
|
||||||
|
|
||||||
response =
|
|
||||||
conn
|
|
||||||
|> post("/ostatus_subscribe", %{"user" => %{"id" => user2.id}})
|
|
||||||
|> response(200)
|
|
||||||
|
|
||||||
assert response =~ "Error following account"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns error on insufficient permissions", %{user: user, conn: conn} do
|
|
||||||
user2 = insert(:user)
|
|
||||||
|
|
||||||
for token <- [nil, insert(:oauth_token, user: user, scopes: ["read"])] do
|
|
||||||
response =
|
|
||||||
conn
|
|
||||||
|> assign(:token, token)
|
|
||||||
|> post("/ostatus_subscribe", %{"user" => %{"id" => user2.id}})
|
|
||||||
|> response(200)
|
|
||||||
|
|
||||||
assert response =~ "Error following account"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns error when followee not found", %{conn: conn} do
|
|
||||||
response =
|
|
||||||
conn
|
|
||||||
|> post("/ostatus_subscribe", %{"user" => %{"id" => "jimm"}})
|
|
||||||
|> response(200)
|
|
||||||
|
|
||||||
assert response =~ "Error following account"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns success result when user already in followers", %{user: user, conn: conn} do
|
|
||||||
user2 = insert(:user)
|
|
||||||
{:ok, _, _, _} = CommonAPI.follow(user, user2)
|
|
||||||
|
|
||||||
response =
|
|
||||||
conn
|
|
||||||
|> post("/ostatus_subscribe", %{"user" => %{"id" => user2.id}})
|
|
||||||
|> response(200)
|
|
||||||
|
|
||||||
assert response =~ "Account followed!"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "POST /ostatus_subscribe - do_remote_follow/2 without assigned user" do
|
|
||||||
test "follows", %{conn: conn} do
|
|
||||||
user = insert(:user)
|
|
||||||
user2 = insert(:user)
|
|
||||||
|
|
||||||
response =
|
|
||||||
conn
|
|
||||||
|> post("/ostatus_subscribe", %{
|
|
||||||
"authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id}
|
|
||||||
})
|
|
||||||
|> response(200)
|
|
||||||
|
|
||||||
assert response =~ "Account followed!"
|
|
||||||
assert user2.follower_address in User.following(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns error when followee not found", %{conn: conn} do
|
|
||||||
user = insert(:user)
|
|
||||||
|
|
||||||
response =
|
|
||||||
conn
|
|
||||||
|> post("/ostatus_subscribe", %{
|
|
||||||
"authorization" => %{"name" => user.nickname, "password" => "test", "id" => "jimm"}
|
|
||||||
})
|
|
||||||
|> response(200)
|
|
||||||
|
|
||||||
assert response =~ "Error following account"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns error when login invalid", %{conn: conn} do
|
|
||||||
user = insert(:user)
|
|
||||||
|
|
||||||
response =
|
|
||||||
conn
|
|
||||||
|> post("/ostatus_subscribe", %{
|
|
||||||
"authorization" => %{"name" => "jimm", "password" => "test", "id" => user.id}
|
|
||||||
})
|
|
||||||
|> response(200)
|
|
||||||
|
|
||||||
assert response =~ "Wrong username or password"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns error when password invalid", %{conn: conn} do
|
|
||||||
user = insert(:user)
|
|
||||||
user2 = insert(:user)
|
|
||||||
|
|
||||||
response =
|
|
||||||
conn
|
|
||||||
|> post("/ostatus_subscribe", %{
|
|
||||||
"authorization" => %{"name" => user.nickname, "password" => "42", "id" => user2.id}
|
|
||||||
})
|
|
||||||
|> response(200)
|
|
||||||
|
|
||||||
assert response =~ "Wrong username or password"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns error when user is blocked", %{conn: conn} do
|
|
||||||
Pleroma.Config.put([:user, :deny_follow_blocked], true)
|
|
||||||
user = insert(:user)
|
|
||||||
user2 = insert(:user)
|
|
||||||
{:ok, _user_block} = Pleroma.User.block(user2, user)
|
|
||||||
|
|
||||||
response =
|
|
||||||
conn
|
|
||||||
|> post("/ostatus_subscribe", %{
|
|
||||||
"authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id}
|
|
||||||
})
|
|
||||||
|> response(200)
|
|
||||||
|
|
||||||
assert response =~ "Error following account"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "GET /api/pleroma/healthcheck" do
|
describe "GET /api/pleroma/healthcheck" do
|
||||||
clear_config([:instance, :healthcheck])
|
clear_config([:instance, :healthcheck])
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue