Refactored user-related functionality

This commit is contained in:
dtluna 2017-05-10 21:50:44 +03:00
parent 118c572006
commit 6e66de0fae
13 changed files with 169 additions and 204 deletions

5
lib/pleroma/misc.ex Normal file
View File

@ -0,0 +1,5 @@
defmodule Pleroma.Misc do
def make_date do
DateTime.utc_now() |> DateTime.to_iso8601
end
end

View File

@ -1,5 +1,5 @@
defmodule Pleroma.Web.ActivityPub.ActivityPub do
alias Pleroma.{Activity, Repo, Object, Upload, User, Web}
alias Pleroma.{Activity, Repo, Object, Upload, User, Web, Misc}
alias Ecto.{Changeset, UUID}
import Ecto.Query
require Logger
@ -7,7 +7,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
def insert(map, local \\ true) when is_map(map) do
map = map
|> Map.put_new_lazy("id", &generate_activity_id/0)
|> Map.put_new_lazy("published", &make_date/0)
|> Map.put_new_lazy("published", &Misc.make_date/0)
with %Activity{} = activity <- Activity.get_by_ap_id(map["id"]) do
Logger.debug(fn -> "Already have activity, #{activity.id}, not inserting." end)
@ -26,7 +26,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
def create(to, actor, context, object, additional \\ %{}, published \\ nil, local \\ true) do
published = published || make_date()
published = published || Misc.make_date()
activity = %{
"type" => "Create",
@ -224,7 +224,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
"actor" => follower_id,
"to" => [followed_id],
"object" => followed_id,
"published" => make_date()
"published" => Misc.make_date()
}
with {:ok, activity} <- insert(data, local) do
@ -243,7 +243,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
"actor" => follower.ap_id,
"to" => [followed.ap_id],
"object" => follow_activity.data["id"],
"published" => make_date()
"published" => Misc.make_date()
}
with {:ok, activity} <- insert(data, local) do
@ -276,8 +276,4 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
data = Upload.store(file)
Repo.insert(%Object{data: data})
end
defp make_date do
DateTime.utc_now() |> DateTime.to_iso8601
end
end

View File

@ -37,14 +37,14 @@ defmodule Pleroma.Web.Router do
get "/statuses/show/:id", TwitterAPI.Controller, :fetch_status
get "/statusnet/conversation/:id", TwitterAPI.Controller, :fetch_conversation
post "/account/register", TwitterAPI.Controller, :register
post "/account/register", TwitterAPI.UserController, :register
end
scope "/api", Pleroma.Web do
pipe_through :authenticated_api
get "/account/verify_credentials", TwitterAPI.Controller, :verify_credentials
post "/account/verify_credentials", TwitterAPI.Controller, :verify_credentials
get "/account/verify_credentials", TwitterAPI.UserController, :verify_credentials
post "/account/verify_credentials", TwitterAPI.UserController, :verify_credentials
get "/statuses/home_timeline", TwitterAPI.Controller, :friends_timeline
get "/statuses/friends_timeline", TwitterAPI.Controller, :friends_timeline
@ -54,8 +54,8 @@ defmodule Pleroma.Web.Router do
post "/statuses/update", TwitterAPI.Controller, :status_update
post "/statuses/retweet/:id", TwitterAPI.Controller, :retweet
post "/friendships/create", TwitterAPI.Controller, :follow
post "/friendships/destroy", TwitterAPI.Controller, :unfollow
post "/friendships/create", TwitterAPI.UserController, :follow
post "/friendships/destroy", TwitterAPI.UserController, :unfollow
post "/statusnet/media/upload", TwitterAPI.Controller, :upload
post "/media/upload", TwitterAPI.Controller, :upload_json
@ -64,7 +64,7 @@ defmodule Pleroma.Web.Router do
post "/favorites/create", TwitterAPI.Controller, :favorite
post "/favorites/destroy/:id", TwitterAPI.Controller, :unfavorite
post "/qvitter/update_avatar", TwitterAPI.Controller, :update_avatar
post "/qvitter/update_avatar", TwitterAPI.UserController, :update_avatar
end
pipeline :ostatus do

View File

@ -0,0 +1,102 @@
defmodule Pleroma.Web.TwitterAPI.UserController do
use Pleroma.Web, :controller
alias Ecto.Changeset
alias Pleroma.{Repo, User, Misc}
alias Pleroma.Web.ActivityPub.ActivityPub
def verify_credentials(%{assigns: %{user: user}} = conn, _params) do
render conn, "show.json", %{user: user, for: user}
end
def follow(%{assigns: %{user: follower}} = conn, params) do
with {:ok, %User{} = followed} <- get_user(params),
{:ok, follower} <- User.follow(follower, followed),
{:ok, activity} <- ActivityPub.follow(follower, followed)
do
render conn, "show.json", %{user: followed, for: follower}
else
{:error, message} ->
conn
|> put_status(:not_found)
|> render(Pleroma.Web.TwitterAPI.ErrorView, "error.json",
%{request_path: conn.request_path, message: message})
end
end
def unfollow(%{assigns: %{user: follower}} = conn, params) do
with { :ok, %User{} = unfollowed } <- get_user(params),
{ :ok, follower, follow_activity } <- User.unfollow(follower, unfollowed),
{ :ok, _activity } <- ActivityPub.insert(%{
"type" => "Undo",
"actor" => follower.ap_id,
"object" => follow_activity.data["id"], # get latest Follow for these users
"published" => Misc.make_date()
})
do
render conn, "show.json", %{user: unfollowed, for: follower}
else
{:error, message} ->
conn
|> put_status(:not_found)
|> render(Pleroma.Web.TwitterAPI.ErrorView, "error.json",
%{request_path: conn.request_path, message: message})
end
end
def register(conn, params) do
params = %{
nickname: params["nickname"],
name: params["fullname"],
bio: params["bio"],
email: params["email"],
password: params["password"],
password_confirmation: params["confirm"]
}
changeset = User.register_changeset(%User{}, params)
with {:ok, user} <- Repo.insert(changeset) do
render conn, "show.json", %{user: user}
else
{:error, changeset} ->
errors = Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end)
conn
|> put_status(:bad_request)
|> render(Pleroma.Web.TwitterAPI.ErrorView, "error.json",
%{request_path: conn.request_path, message: errors})
end
end
def update_avatar(%{assigns: %{user: user}} = conn, params) do
{:ok, object} = ActivityPub.upload(params)
change = Changeset.change(user, %{avatar: object.data})
{:ok, user} = Repo.update(change)
render conn, "show.json", %{user: user}
end
defp get_user(user \\ nil, params) do
case params do
%{"user_id" => user_id} ->
case target = Repo.get(User, user_id) do
nil ->
{:error, "No user with such user_id"}
_ ->
{:ok, target}
end
%{"screen_name" => nickname} ->
case target = Repo.get_by(User, nickname: nickname) do
nil ->
{:error, "No user with such screen_name"}
_ ->
{:ok, target}
end
_ ->
if user do
{:ok, user}
else
{:error, "You need to specify screen_name or user_id"}
end
end
end
end

View File

@ -1,5 +1,5 @@
defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
alias Pleroma.{User, Activity, Repo, Object}
alias Pleroma.{User, Activity, Repo, Object, Misc}
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.TwitterAPI.Representers.{ActivityRepresenter, UserRepresenter}
@ -50,7 +50,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|> add_attachments(attachments)
to = to_for_user_and_mentions(user, mentions)
date = make_date()
date = Misc.make_date()
inReplyTo = get_replied_to_activity(data["in_reply_to_status_id"])
@ -133,33 +133,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
end
end
def follow(%User{} = follower, params) do
with {:ok, %User{} = followed} <- get_user(params),
{:ok, follower} <- User.follow(follower, followed),
{:ok, activity} <- ActivityPub.follow(follower, followed)
do
{:ok, follower, followed, activity}
else
err -> err
end
end
def unfollow(%User{} = follower, params) do
with { :ok, %User{} = unfollowed } <- get_user(params),
{ :ok, follower, follow_activity } <- User.unfollow(follower, unfollowed),
{ :ok, _activity } <- ActivityPub.insert(%{
"type" => "Undo",
"actor" => follower.ap_id,
"object" => follow_activity.data["id"], # get latest Follow for these users
"published" => make_date()
})
do
{ :ok, follower, unfollowed }
else
err -> err
end
end
def favorite(%User{} = user, %Activity{data: %{"object" => object}} = activity) do
object = Object.get_by_ap_id(object["id"])
@ -245,28 +218,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
Enum.reduce(mentions, text, fn ({match, %User{ap_id: ap_id}}, text) -> String.replace(text, match, "<a href='#{ap_id}'>#{match}</a>") end)
end
def register_user(params) do
params = %{
nickname: params["nickname"],
name: params["fullname"],
bio: params["bio"],
email: params["email"],
password: params["password"],
password_confirmation: params["confirm"]
}
changeset = User.register_changeset(%User{}, params)
with {:ok, user} <- Repo.insert(changeset) do
{:ok, UserRepresenter.to_map(user)}
else
{:error, changeset} ->
errors = Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end)
|> Poison.encode!
{:error, %{error: errors}}
end
end
def get_user(user \\ nil, params) do
case params do
%{"user_id" => user_id} ->
@ -329,10 +280,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
ActivityRepresenter.to_map(activity, Map.merge(opts, %{user: user, mentioned: mentioned_users}))
end
defp make_date do
DateTime.utc_now() |> DateTime.to_iso8601
end
def context_to_conversation_id(context) do
with %Object{id: id} <- Object.get_cached_by_ap_id(context) do
id

View File

@ -6,13 +6,6 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
alias Pleroma.Web.ActivityPub.ActivityPub
alias Ecto.Changeset
def verify_credentials(%{assigns: %{user: user}} = conn, _params) do
response = user |> UserRepresenter.to_json(%{for: user})
conn
|> json_reply(200, response)
end
def status_update(%{assigns: %{user: user}} = conn, %{"status" => status_text} = status_data) do
l = status_text |> String.trim |> String.length
if l > 0 && l < 5000 do
@ -87,26 +80,6 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|> json_reply(200, json)
end
def follow(%{assigns: %{user: user}} = conn, params) do
case TwitterAPI.follow(user, params) do
{:ok, user, followed, _activity} ->
response = followed |> UserRepresenter.to_json(%{for: user})
conn
|> json_reply(200, response)
{:error, msg} -> forbidden_json_reply(conn, msg)
end
end
def unfollow(%{assigns: %{user: user}} = conn, params) do
case TwitterAPI.unfollow(user, params) do
{:ok, user, unfollowed} ->
response = unfollowed |> UserRepresenter.to_json(%{for: user})
conn
|> json_reply(200, response)
{:error, msg} -> forbidden_json_reply(conn, msg)
end
end
def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
response = Poison.encode!(TwitterAPI.fetch_status(user, id))
@ -185,28 +158,6 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
end
def register(conn, params) do
with {:ok, user} <- TwitterAPI.register_user(params) do
conn
|> json_reply(200, Poison.encode!(user))
else
{:error, errors} ->
conn
|> json_reply(400, Poison.encode!(errors))
end
end
def update_avatar(%{assigns: %{user: user}} = conn, params) do
{:ok, object} = ActivityPub.upload(params)
change = Changeset.change(user, %{avatar: object.data})
{:ok, user} = Repo.update(change)
response = Poison.encode!(UserRepresenter.to_map(user, %{for: user}))
conn
|> json_reply(200, response)
end
defp bad_request_reply(conn, error_message) do
json = error_json(conn, error_message)
json_reply(conn, 400, json)

View File

@ -0,0 +1,7 @@
defmodule Pleroma.Web.TwitterAPI.ErrorView do
use Pleroma.Web, :view
def render("error.json", %{request_path: request_path, message: message}) do
%{error: message, request: request_path}
end
end

View File

@ -0,0 +1,34 @@
defmodule Pleroma.Web.TwitterAPI.UserView do
use Pleroma.Web, :view
alias Pleroma.User
def render("show.json", opts = %{user: user = %User{}}) do
image = User.avatar_url(user)
following = if opts[:for] do
User.following?(opts[:for], user)
else
false
end
user_info = User.get_cached_user_info(user)
%{
"id" => user.id,
"name" => user.name,
"screen_name" => user.nickname,
"description" => user.bio,
"following" => following,
# Fake fields
"favourites_count" => 0,
"statuses_count" => user_info[:note_count],
"friends_count" => user_info[:following_count],
"followers_count" => user_info[:follower_count],
"profile_image_url" => image,
"profile_image_url_https" => image,
"profile_image_url_profile_size" => image,
"profile_image_url_original" => image,
"rights" => %{},
"statusnet_profile_url" => user.ap_id
}
end
end

View File

@ -1,5 +1,6 @@
defmodule Pleroma.Factory do
use ExMachina.Ecto, repo: Pleroma.Repo
alias Pleroma.Misc
def user_factory do
user = %Pleroma.User{
@ -22,7 +23,7 @@ defmodule Pleroma.Factory do
"id" => Pleroma.Web.ActivityPub.ActivityPub.generate_object_id,
"actor" => user.ap_id,
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"published_at" => DateTime.utc_now() |> DateTime.to_iso8601,
"published_at" => Misc.make_date(),
"likes" => [],
"like_count" => 0,
"context" => "2hu"
@ -41,7 +42,7 @@ defmodule Pleroma.Factory do
"actor" => note.data["actor"],
"to" => note.data["to"],
"object" => note.data,
"published_at" => DateTime.utc_now() |> DateTime.to_iso8601,
"published_at" => Misc.make_date(),
"context" => note.data["context"]
}
@ -59,7 +60,7 @@ defmodule Pleroma.Factory do
"actor" => user.ap_id,
"type" => "Like",
"object" => note_activity.data["object"]["id"],
"published_at" => DateTime.utc_now() |> DateTime.to_iso8601
"published_at" => Misc.make_date()
}
%Pleroma.Activity{
@ -76,7 +77,7 @@ defmodule Pleroma.Factory do
"actor" => follower.ap_id,
"type" => "Follow",
"object" => followed.ap_id,
"published_at" => DateTime.utc_now() |> DateTime.to_iso8601
"published_at" => Misc.make_date()
}
%Pleroma.Activity{

View File

@ -1,7 +1,7 @@
defmodule Pleroma.Web.Salmon.SalmonTest do
use Pleroma.DataCase
alias Pleroma.Web.Salmon
alias Pleroma.{Repo, Activity, User}
alias Pleroma.{Repo, Activity, User, Misc}
import Pleroma.Factory
@magickey "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwQhh-1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAB"
@ -76,7 +76,7 @@ defmodule Pleroma.Web.Salmon.SalmonTest do
"actor" => note.data["actor"],
"to" => note.data["to"] ++ [mentioned_user.ap_id],
"object" => note.data,
"published_at" => DateTime.utc_now() |> DateTime.to_iso8601,
"published_at" => Misc.make_date(),
"context" => note.data["context"]
}

View File

@ -385,7 +385,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
errors = json_response(conn, 400)
assert is_binary(errors["error"])
assert errors["error"]
end
end

View File

@ -165,53 +165,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
assert status == ActivityRepresenter.to_map(activity, %{for: user, user: actor})
end
test "Follow another user using user_id" do
user = insert(:user)
followed = insert(:user)
{:ok, user, followed, _activity } = TwitterAPI.follow(user, %{"user_id" => followed.id})
assert user.following == [User.ap_followers(followed)]
{ :error, msg } = TwitterAPI.follow(user, %{"user_id" => followed.id})
assert msg == "Could not follow user: #{followed.nickname} is already on your list."
end
test "Follow another user using screen_name" do
user = insert(:user)
followed = insert(:user)
{:ok, user, followed, _activity } = TwitterAPI.follow(user, %{"screen_name" => followed.nickname})
assert user.following == [User.ap_followers(followed)]
{ :error, msg } = TwitterAPI.follow(user, %{"screen_name" => followed.nickname})
assert msg == "Could not follow user: #{followed.nickname} is already on your list."
end
test "Unfollow another user using user_id" do
unfollowed = insert(:user)
user = insert(:user, %{following: [User.ap_followers(unfollowed)]})
ActivityPub.follow(user, unfollowed)
{:ok, user, unfollowed } = TwitterAPI.unfollow(user, %{"user_id" => unfollowed.id})
assert user.following == []
{ :error, msg } = TwitterAPI.unfollow(user, %{"user_id" => unfollowed.id})
assert msg == "Not subscribed!"
end
test "Unfollow another user using screen_name" do
unfollowed = insert(:user)
user = insert(:user, %{following: [User.ap_followers(unfollowed)]})
ActivityPub.follow(user, unfollowed)
{:ok, user, unfollowed } = TwitterAPI.unfollow(user, %{"screen_name" => unfollowed.nickname})
assert user.following == []
{ :error, msg } = TwitterAPI.unfollow(user, %{"screen_name" => unfollowed.nickname})
assert msg == "Not subscribed!"
end
test "fetch statuses in a context using the conversation id" do
{:ok, user} = UserBuilder.insert()
{:ok, activity} = ActivityBuilder.insert(%{"context" => "2hu"})
@ -298,37 +251,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
assert status == ActivityRepresenter.to_map(updated_activity, %{user: activity_user, for: user})
end
test "it registers a new user and returns the user." do
data = %{
"nickname" => "lain",
"email" => "lain@wired.jp",
"fullname" => "lain iwakura",
"bio" => "close the world.",
"password" => "bear",
"confirm" => "bear"
}
{:ok, user} = TwitterAPI.register_user(data)
fetched_user = Repo.get_by(User, nickname: "lain")
assert user == UserRepresenter.to_map(fetched_user)
end
test "it returns the error on registration problems" do
data = %{
"nickname" => "lain",
"email" => "lain@wired.jp",
"fullname" => "lain iwakura",
"bio" => "close the world.",
"password" => "bear"
}
{:error, error_object} = TwitterAPI.register_user(data)
assert is_binary(error_object[:error])
refute Repo.get_by(User, nickname: "lain")
end
test "it assigns an integer conversation_id" do
note_activity = insert(:note_activity)
user = User.get_cached_by_ap_id(note_activity.data["actor"])