forked from AkkomaGang/akkoma
Merge branch 'develop' of ssh.gitgud.io:lambadalambda/pleroma into feature/unfollow-by-screen-name
This commit is contained in:
commit
f6547f7b7f
22 changed files with 145 additions and 49 deletions
|
@ -18,6 +18,31 @@ def store(%Plug.Upload{} = file) do
|
|||
}
|
||||
end
|
||||
|
||||
def store(%{"img" => "data:image/" <> image_data}) do
|
||||
parsed = Regex.named_captures(~r/(?<filetype>jpeg|png|gif);base64,(?<data>.*)/, image_data)
|
||||
data = Base.decode64!(parsed["data"])
|
||||
uuid = Ecto.UUID.generate
|
||||
upload_folder = Path.join(upload_path(), uuid)
|
||||
File.mkdir_p!(upload_folder)
|
||||
filename = Base.encode16(:crypto.hash(:sha256, data)) <> ".#{parsed["filetype"]}"
|
||||
result_file = Path.join(upload_folder, filename)
|
||||
|
||||
File.write!(result_file, data)
|
||||
|
||||
content_type = "image/#{parsed["filetype"]}"
|
||||
|
||||
%{
|
||||
"type" => "Image",
|
||||
"url" => [%{
|
||||
"type" => "Link",
|
||||
"mediaType" => content_type,
|
||||
"href" => url_for(Path.join(uuid, filename))
|
||||
}],
|
||||
"name" => filename,
|
||||
"uuid" => uuid
|
||||
}
|
||||
end
|
||||
|
||||
defp upload_path do
|
||||
Application.get_env(:pleroma, Pleroma.Upload)
|
||||
|> Keyword.fetch!(:uploads)
|
||||
|
|
|
@ -13,6 +13,7 @@ defmodule Pleroma.User do
|
|||
field :password_confirmation, :string, virtual: true
|
||||
field :following, { :array, :string }, default: []
|
||||
field :ap_id, :string
|
||||
field :avatar, :map
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
|
|
@ -167,7 +167,7 @@ def fetch_activities_for_context(context) do
|
|||
Repo.all(query)
|
||||
end
|
||||
|
||||
def upload(%Plug.Upload{} = file) do
|
||||
def upload(file) do
|
||||
data = Upload.store(file)
|
||||
Repo.insert(%Object{data: data})
|
||||
end
|
||||
|
|
|
@ -45,5 +45,6 @@ def user_fetcher(username) do
|
|||
post "/favorites/create", TwitterAPI.Controller, :favorite
|
||||
post "/favorites/destroy/:id", TwitterAPI.Controller, :unfavorite
|
||||
post "/statuses/retweet/:id", TwitterAPI.Controller, :retweet
|
||||
post "/qvitter/update_avatar", TwitterAPI.Controller, :update_avatar
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,8 +4,10 @@ defmodule Pleroma.Web.TwitterAPI.Representers.UserRepresenter do
|
|||
alias Pleroma.User
|
||||
|
||||
def to_map(user, opts) do
|
||||
|
||||
image = "https://placehold.it/48x48"
|
||||
image = case user.avatar do
|
||||
%{"url" => [%{"href" => href} | _]} -> href
|
||||
_ -> "https://placehold.it/48x48"
|
||||
end
|
||||
|
||||
following = if opts[:for] do
|
||||
User.following?(opts[:for], user)
|
||||
|
|
|
@ -3,6 +3,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
||||
alias Pleroma.Web.TwitterAPI.Representers.{UserRepresenter, ActivityRepresenter}
|
||||
alias Pleroma.{Repo, Activity}
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
|
||||
def verify_credentials(%{assigns: %{user: user}} = conn, _params) do
|
||||
response = user |> UserRepresenter.to_json(%{for: user})
|
||||
|
@ -142,6 +143,18 @@ def register(conn, params) do
|
|||
end
|
||||
end
|
||||
|
||||
def update_avatar(%{assigns: %{user: user}} = conn, params) do
|
||||
{:ok, object} = ActivityPub.upload(params)
|
||||
change = Ecto.Changeset.change(user, %{avatar: object.data})
|
||||
{:ok, user} = Repo.update(change)
|
||||
|
||||
response = UserRepresenter.to_map(user, %{for: user})
|
||||
|> Poison.encode!
|
||||
|
||||
conn
|
||||
|> json_reply(200, response)
|
||||
end
|
||||
|
||||
defp json_reply(conn, status, json) do
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
defmodule Pleroma.Repo.Migrations.AddAvatarObjectToUsers do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
alter table(:users) do
|
||||
add :avatar, :map
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1 +1 @@
|
|||
<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>Pleroma</title><link rel=stylesheet href=/static/font/css/fontello.css><link rel=stylesheet href=/static/font/css/animation.css><link href=/static/css/app.a86c13eb46180b1b975a1acd59b52cc6.css rel=stylesheet></head><body style="display: none"><div id=app></div><script type=text/javascript src=/static/js/manifest.da7ea91e505330123f38.js></script><script type=text/javascript src=/static/js/vendor.d7d8813599feb765b152.js></script><script type=text/javascript src=/static/js/app.dcc60205ebdef9eb3d87.js></script></body></html>
|
||||
<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>Pleroma</title><link rel=stylesheet href=/static/font/css/fontello.css><link rel=stylesheet href=/static/font/css/animation.css><link href=/static/css/app.a86c13eb46180b1b975a1acd59b52cc6.css rel=stylesheet></head><body style="display: none"><div id=app></div><script type=text/javascript src=/static/js/manifest.66d994092e61600982a8.js></script><script type=text/javascript src=/static/js/vendor.d7d8813599feb765b152.js></script><script type=text/javascript src=/static/js/app.d4e0a640b375c4b52997.js></script></body></html>
|
4
priv/static/static/js/app.d4e0a640b375c4b52997.js
Normal file
4
priv/static/static/js/app.d4e0a640b375c4b52997.js
Normal file
File diff suppressed because one or more lines are too long
1
priv/static/static/js/app.d4e0a640b375c4b52997.js.map
Normal file
1
priv/static/static/js/app.d4e0a640b375c4b52997.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
priv/static/static/js/manifest.66d994092e61600982a8.js
Normal file
2
priv/static/static/js/manifest.66d994092e61600982a8.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
!function(e){function t(n){if(r[n])return r[n].exports;var a=r[n]={exports:{},id:n,loaded:!1};return e[n].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n=window.webpackJsonp;window.webpackJsonp=function(o,c){for(var p,s,l=0,i=[];l<o.length;l++)s=o[l],a[s]&&i.push.apply(i,a[s]),a[s]=0;for(p in c)e[p]=c[p];for(n&&n(o,c);i.length;)i.shift().call(null,t);if(c[0])return r[0]=0,t(0)};var r={},a={0:0};t.e=function(e,n){if(0===a[e])return n.call(null,t);if(void 0!==a[e])a[e].push(n);else{a[e]=[n];var r=document.getElementsByTagName("head")[0],o=document.createElement("script");o.type="text/javascript",o.charset="utf-8",o.async=!0,o.src=t.p+"static/js/"+e+"."+{1:"d7d8813599feb765b152",2:"d4e0a640b375c4b52997"}[e]+".js",r.appendChild(o)}},t.m=e,t.c=r,t.p="/"}([]);
|
||||
//# sourceMappingURL=manifest.66d994092e61600982a8.js.map
|
File diff suppressed because one or more lines are too long
|
@ -1,2 +0,0 @@
|
|||
!function(e){function t(n){if(r[n])return r[n].exports;var a=r[n]={exports:{},id:n,loaded:!1};return e[n].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n=window.webpackJsonp;window.webpackJsonp=function(c,o){for(var p,s,l=0,d=[];l<c.length;l++)s=c[l],a[s]&&d.push.apply(d,a[s]),a[s]=0;for(p in o)e[p]=o[p];for(n&&n(c,o);d.length;)d.shift().call(null,t);if(o[0])return r[0]=0,t(0)};var r={},a={0:0};t.e=function(e,n){if(0===a[e])return n.call(null,t);if(void 0!==a[e])a[e].push(n);else{a[e]=[n];var r=document.getElementsByTagName("head")[0],c=document.createElement("script");c.type="text/javascript",c.charset="utf-8",c.async=!0,c.src=t.p+"static/js/"+e+"."+{1:"d7d8813599feb765b152",2:"dcc60205ebdef9eb3d87"}[e]+".js",r.appendChild(c)}},t.m=e,t.c=r,t.p="/"}([]);
|
||||
//# sourceMappingURL=manifest.da7ea91e505330123f38.js.map
|
|
@ -3,7 +3,7 @@ defmodule Pleroma.Builders.ActivityBuilder do
|
|||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
|
||||
def build(data \\ %{}, opts \\ %{}) do
|
||||
user = opts[:user] || UserBuilder.build
|
||||
user = opts[:user] || Pleroma.Factory.insert(:user)
|
||||
activity = %{
|
||||
"id" => 1,
|
||||
"actor" => user.ap_id,
|
||||
|
@ -29,7 +29,7 @@ def insert_list(times, data \\ %{}, opts \\ %{}) do
|
|||
end
|
||||
|
||||
def public_and_non_public do
|
||||
{:ok, user} = UserBuilder.insert
|
||||
user = Pleroma.Factory.insert(:user)
|
||||
|
||||
public = build(%{"id" => 1}, %{user: user})
|
||||
non_public = build(%{"id" => 2, "to" => []}, %{user: user})
|
||||
|
|
|
@ -3,6 +3,8 @@ defmodule Pleroma.UserTest do
|
|||
alias Pleroma.User
|
||||
use Pleroma.DataCase
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
test "ap_id returns the activity pub id for the user" do
|
||||
host =
|
||||
Application.get_env(:pleroma, Pleroma.Web.Endpoint)
|
||||
|
@ -25,21 +27,21 @@ test "ap_followers returns the followers collection for the user" do
|
|||
end
|
||||
|
||||
test "follow takes a user and another user" do
|
||||
{ :ok, user } = UserBuilder.insert
|
||||
{ :ok, following } = UserBuilder.insert(%{nickname: "guy"})
|
||||
user = insert(:user)
|
||||
followed = insert(:user)
|
||||
|
||||
{:ok, user } = User.follow(user, following)
|
||||
{:ok, user } = User.follow(user, followed)
|
||||
|
||||
user = Repo.get(User, user.id)
|
||||
|
||||
assert user.following == [User.ap_followers(following)]
|
||||
assert user.following == [User.ap_followers(followed)]
|
||||
end
|
||||
|
||||
test "unfollow takes a user and another user" do
|
||||
{ :ok, following } = UserBuilder.insert(%{nickname: "guy"})
|
||||
{ :ok, user } = UserBuilder.insert(%{following: [User.ap_followers(following)]})
|
||||
followed = insert(:user)
|
||||
user = insert(:user, %{following: [User.ap_followers(followed)]})
|
||||
|
||||
{:ok, user } = User.unfollow(user, following)
|
||||
{:ok, user } = User.unfollow(user, followed)
|
||||
|
||||
user = Repo.get(User, user.id)
|
||||
|
||||
|
@ -47,8 +49,8 @@ test "unfollow takes a user and another user" do
|
|||
end
|
||||
|
||||
test "test if a user is following another user" do
|
||||
{ :ok, followed } = UserBuilder.insert(%{nickname: "guy"})
|
||||
{ :ok, user } = UserBuilder.insert(%{following: [User.ap_followers(followed)]})
|
||||
followed = insert(:user)
|
||||
user = insert(:user, %{following: [User.ap_followers(followed)]})
|
||||
|
||||
assert User.following?(user, followed)
|
||||
refute User.following?(followed, user)
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -45,8 +45,11 @@ test "a like activity" do
|
|||
|
||||
test "an activity" do
|
||||
{:ok, user} = UserBuilder.insert
|
||||
{:ok, mentioned_user } = UserBuilder.insert(%{nickname: "shp", ap_id: "shp"})
|
||||
{:ok, follower} = UserBuilder.insert(%{following: [User.ap_followers(user)]})
|
||||
# {:ok, mentioned_user } = UserBuilder.insert(%{nickname: "shp", ap_id: "shp"})
|
||||
mentioned_user = insert(:user, %{nickname: "shp"})
|
||||
|
||||
# {:ok, follower} = UserBuilder.insert(%{following: [User.ap_followers(user)]})
|
||||
follower = insert(:user, %{following: [User.ap_followers(user)]})
|
||||
|
||||
object = %Object{
|
||||
data: %{
|
||||
|
@ -62,7 +65,7 @@ test "an activity" do
|
|||
}
|
||||
}
|
||||
|
||||
content_html = "Some content mentioning <a href='shp'>@shp</shp>"
|
||||
content_html = "Some content mentioning <a href='#{mentioned_user.ap_id}'>@shp</shp>"
|
||||
content = HtmlSanitizeEx.strip_tags(content_html)
|
||||
date = DateTime.from_naive!(~N[2016-05-24 13:26:08.003], "Etc/UTC") |> DateTime.to_iso8601
|
||||
|
||||
|
|
|
@ -5,13 +5,23 @@ defmodule Pleroma.Web.TwitterAPI.Representers.UserRepresenterTest do
|
|||
alias Pleroma.Web.TwitterAPI.Representers.UserRepresenter
|
||||
alias Pleroma.Builders.UserBuilder
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
setup do
|
||||
{:ok, user} = UserBuilder.insert
|
||||
user = insert(:user)
|
||||
[user: user]
|
||||
end
|
||||
|
||||
test "A user with an avatar object", %{user: user} do
|
||||
image = "image"
|
||||
user = %{ user | avatar: %{ "url" => [%{"href" => image}] }}
|
||||
represented = UserRepresenter.to_map(user)
|
||||
assert represented["profile_image_url"] == image
|
||||
end
|
||||
|
||||
test "A user", %{user: user} do
|
||||
image = "https://placehold.it/48x48"
|
||||
|
||||
represented = %{
|
||||
"id" => user.id,
|
||||
"name" => user.name,
|
||||
|
|
|
@ -94,10 +94,10 @@ test "without valid credentials", %{conn: conn} do
|
|||
end
|
||||
|
||||
test "with credentials", %{conn: conn, user: current_user} do
|
||||
{:ok, user} = UserBuilder.insert
|
||||
user = insert(:user)
|
||||
activities = ActivityBuilder.insert_list(30, %{"to" => [User.ap_followers(user)]}, %{user: user})
|
||||
returned_activities = ActivityBuilder.insert_list(10, %{"to" => [User.ap_followers(user)]}, %{user: user})
|
||||
{:ok, other_user} = UserBuilder.insert(%{ap_id: "glimmung", nickname: "nockame"})
|
||||
other_user = insert(:user)
|
||||
ActivityBuilder.insert_list(10, %{}, %{user: other_user})
|
||||
since_id = List.last(activities).id
|
||||
|
||||
|
@ -110,7 +110,7 @@ test "with credentials", %{conn: conn, user: current_user} do
|
|||
response = json_response(conn, 200)
|
||||
|
||||
assert length(response) == 10
|
||||
assert response == Enum.map(returned_activities, fn (activity) -> ActivityRepresenter.to_map(activity, %{user: user, for: current_user}) end)
|
||||
assert response == Enum.map(returned_activities, fn (activity) -> ActivityRepresenter.to_map(activity, %{user: User.get_cached_by_ap_id(activity.data["actor"]), for: current_user}) end)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -122,7 +122,7 @@ test "without valid credentials", %{conn: conn} do
|
|||
end
|
||||
|
||||
test "with credentials", %{conn: conn, user: current_user} do
|
||||
{:ok, followed } = UserBuilder.insert(%{name: "some guy"})
|
||||
followed = insert(:user)
|
||||
|
||||
conn = conn
|
||||
|> with_credentials(current_user.nickname, "test")
|
||||
|
@ -142,7 +142,7 @@ test "without valid credentials", %{conn: conn} do
|
|||
end
|
||||
|
||||
test "with credentials", %{conn: conn, user: current_user} do
|
||||
{:ok, followed } = UserBuilder.insert(%{name: "some guy"})
|
||||
followed = insert(:user)
|
||||
|
||||
{:ok, current_user} = User.follow(current_user, followed)
|
||||
assert current_user.following == [User.ap_followers(followed)]
|
||||
|
@ -157,6 +157,24 @@ test "with credentials", %{conn: conn, user: current_user} do
|
|||
end
|
||||
end
|
||||
|
||||
describe "POST /api/qvitter/update_avatar.json" do
|
||||
setup [:valid_user]
|
||||
test "without valid credentials", %{conn: conn} do
|
||||
conn = post conn, "/api/qvitter/update_avatar.json"
|
||||
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
|
||||
end
|
||||
|
||||
test "with credentials", %{conn: conn, user: current_user} do
|
||||
conn = conn
|
||||
|> with_credentials(current_user.nickname, "test")
|
||||
|> post("/api/qvitter/update_avatar.json", %{img: Pleroma.Web.ActivityPub.ActivityPubTest.data_uri})
|
||||
|
||||
current_user = Repo.get(User, current_user.id)
|
||||
assert is_map(current_user.avatar)
|
||||
assert json_response(conn, 200) == UserRepresenter.to_map(current_user, %{for: current_user})
|
||||
end
|
||||
end
|
||||
|
||||
describe "POST /api/favorites/create/:id" do
|
||||
setup [:valid_user]
|
||||
test "without valid credentials", %{conn: conn} do
|
||||
|
|
|
@ -78,7 +78,8 @@ test "create a status that is a reply" do
|
|||
|
||||
test "fetch public statuses" do
|
||||
%{ public: activity, user: user } = ActivityBuilder.public_and_non_public
|
||||
{:ok, follower } = UserBuilder.insert(%{name: "dude", ap_id: "idididid", following: [User.ap_followers(user)]})
|
||||
|
||||
follower = insert(:user, following: [User.ap_followers(user)])
|
||||
|
||||
statuses = TwitterAPI.fetch_public_statuses(follower)
|
||||
|
||||
|
@ -87,19 +88,18 @@ test "fetch public statuses" do
|
|||
end
|
||||
|
||||
test "fetch friends' statuses" do
|
||||
ActivityBuilder.public_and_non_public
|
||||
|
||||
user = insert(:user, %{following: ["someguy/followers"]})
|
||||
{:ok, activity} = ActivityBuilder.insert(%{"to" => ["someguy/followers"]})
|
||||
{:ok, direct_activity} = ActivityBuilder.insert(%{"to" => ["some other id"]})
|
||||
{:ok, user} = UserBuilder.insert(%{ap_id: "some other id", following: ["someguy/followers"]})
|
||||
{:ok, direct_activity} = ActivityBuilder.insert(%{"to" => [user.ap_id]})
|
||||
|
||||
statuses = TwitterAPI.fetch_friend_statuses(user)
|
||||
|
||||
activity_user = Repo.get_by(User, ap_id: activity.data["actor"])
|
||||
direct_activity_user = Repo.get_by(User, ap_id: direct_activity.data["actor"])
|
||||
|
||||
assert length(statuses) == 2
|
||||
assert Enum.at(statuses, 0) == ActivityRepresenter.to_map(activity, %{user: activity_user})
|
||||
assert Enum.at(statuses, 1) == ActivityRepresenter.to_map(direct_activity, %{user: activity_user, mentioned: [user]})
|
||||
assert Enum.at(statuses, 1) == ActivityRepresenter.to_map(direct_activity, %{user: direct_activity_user, mentioned: [user]})
|
||||
end
|
||||
|
||||
test "fetch a single status" do
|
||||
|
@ -113,8 +113,8 @@ test "fetch a single status" do
|
|||
end
|
||||
|
||||
test "Follow another user" do
|
||||
{ :ok, user } = UserBuilder.insert
|
||||
{ :ok, following } = UserBuilder.insert(%{nickname: "guy"})
|
||||
user = insert(:user)
|
||||
following = insert(:user)
|
||||
|
||||
{:ok, user, following, activity } = TwitterAPI.follow(user, following.id)
|
||||
|
||||
|
@ -126,8 +126,8 @@ test "Follow another user" do
|
|||
end
|
||||
|
||||
test "Unfollow another user using user_id" do
|
||||
{ :ok, following } = UserBuilder.insert(%{nickname: "guy"})
|
||||
{ :ok, user } = UserBuilder.insert(%{following: [User.ap_followers(following)]})
|
||||
following = insert(:user)
|
||||
user = insert(:user, %{following: [User.ap_followers(following)]})
|
||||
|
||||
{:ok, user, _following } = TwitterAPI.unfollow(user, %{"user_id" => following.id})
|
||||
|
||||
|
@ -137,8 +137,8 @@ test "Unfollow another user using user_id" do
|
|||
end
|
||||
|
||||
test "Unfollow another user using screen_name" do
|
||||
{ :ok, following } = UserBuilder.insert(%{nickname: "guy"})
|
||||
{ :ok, user } = UserBuilder.insert(%{following: [User.ap_followers(following)]})
|
||||
following = insert(:user)
|
||||
user = insert(:user, %{following: [User.ap_followers(following)]})
|
||||
|
||||
{:ok, user, _following } = TwitterAPI.unfollow(user, %{"screen_name" => following.nickname})
|
||||
|
||||
|
@ -171,8 +171,8 @@ test "upload a file" do
|
|||
test "it can parse mentions and return the relevant users" do
|
||||
text = "@gsimg According to @archaeme , that is @daggsy."
|
||||
|
||||
{:ok, gsimg} = UserBuilder.insert(%{nickname: "gsimg"})
|
||||
{:ok, archaeme} = UserBuilder.insert(%{nickname: "archaeme"})
|
||||
gsimg = insert(:user, %{nickname: "gsimg"})
|
||||
archaeme = insert(:user, %{nickname: "archaeme"})
|
||||
|
||||
expected_result = [
|
||||
{"@gsimg", gsimg},
|
||||
|
@ -185,11 +185,11 @@ test "it can parse mentions and return the relevant users" do
|
|||
test "it adds user links to an existing text" do
|
||||
text = "@gsimg According to @archaeme , that is @daggsy."
|
||||
|
||||
{:ok, _gsimg} = UserBuilder.insert(%{nickname: "gsimg", ap_id: "first_link" })
|
||||
{:ok, _archaeme} = UserBuilder.insert(%{nickname: "archaeme", ap_id: "second_link"})
|
||||
gsimg = insert(:user, %{nickname: "gsimg"})
|
||||
archaeme = insert(:user, %{nickname: "archaeme"})
|
||||
|
||||
mentions = TwitterAPI.parse_mentions(text)
|
||||
expected_text = "<a href='first_link'>@gsimg</a> According to <a href='second_link'>@archaeme</a> , that is @daggsy."
|
||||
expected_text = "<a href='#{gsimg.ap_id}'>@gsimg</a> According to <a href='#{archaeme.ap_id}'>@archaeme</a> , that is @daggsy."
|
||||
|
||||
assert TwitterAPI.add_user_links(text, mentions) == expected_text
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue