X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fuser.ex;h=8c1c524ffff8f8a60cbb28f61278c74860f75943;hb=82e34cae95a204475f4419758c980ddd922be095;hp=f80c0ae338f54f3ed4714f6d877bcb2846a7edfa;hpb=690085158184e6ab216ac11b316191a7cb5ebafc;p=akkoma diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index f80c0ae33..8c1c524ff 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -5,7 +5,7 @@ defmodule Pleroma.User do alias Pleroma.{Repo, User, Object, Web, Activity, Notification} alias Comeonin.Pbkdf2 alias Pleroma.Web.{OStatus, Websub} - alias Pleroma.Web.ActivityPub.Utils + alias Pleroma.Web.ActivityPub.{Utils, ActivityPub} schema "users" do field :bio, :string @@ -29,14 +29,14 @@ defmodule Pleroma.User do def avatar_url(user) do case user.avatar do %{"url" => [%{"href" => href} | _]} -> href - _ -> "https://placehold.it/48x48" + _ -> "#{Web.base_url()}/images/avi.png" end end def banner_url(user) do case user.info["banner"] do %{"url" => [%{"href" => href} | _]} -> href - _ -> nil + _ -> "#{Web.base_url()}/images/banner.png" end end @@ -80,9 +80,15 @@ defmodule Pleroma.User do |> validate_length(:name, max: 100) |> put_change(:local, false) if changes.valid? do - followers = User.ap_followers(%User{nickname: changes.changes[:nickname]}) - changes - |> put_change(:follower_address, followers) + case changes.changes[:info]["source_data"] do + %{"followers" => followers} -> + changes + |> put_change(:follower_address, followers) + _ -> + followers = User.ap_followers(%User{nickname: changes.changes[:nickname]}) + changes + |> put_change(:follower_address, followers) + end else changes end @@ -97,6 +103,15 @@ defmodule Pleroma.User do |> validate_length(:name, min: 1, max: 100) end + def upgrade_changeset(struct, params \\ %{}) do + struct + |> cast(params, [:bio, :name, :info, :follower_address, :avatar]) + |> unique_constraint(:nickname) + |> validate_format(:nickname, ~r/^[a-zA-Z\d]+$/) + |> validate_length(:bio, min: 1, max: 1000) + |> validate_length(:name, min: 1, max: 100) + end + def password_update_changeset(struct, params) do changeset = struct |> cast(params, [:password, :password_confirmation]) @@ -113,7 +128,7 @@ defmodule Pleroma.User do end def reset_password(user, data) do - Repo.update(password_update_changeset(user, data)) + update_and_set_cache(password_update_changeset(user, data)) end def register_changeset(struct, params \\ %{}) do @@ -142,13 +157,14 @@ defmodule Pleroma.User do end end - def follow(%User{} = follower, %User{} = followed) do + def follow(%User{} = follower, %User{info: info} = followed) do ap_followers = followed.follower_address - if following?(follower, followed) do + + if following?(follower, followed) or info["deactivated"] do {:error, "Could not follow user: #{followed.nickname} is already on your list."} else - if !followed.local && follower.local do + if !followed.local && follower.local && !ap_enabled?(followed) do Websub.subscribe(follower, followed) end @@ -157,7 +173,7 @@ defmodule Pleroma.User do follower = follower |> follow_changeset(%{following: following}) - |> Repo.update + |> update_and_set_cache {:ok, _} = update_follower_count(followed) @@ -173,7 +189,7 @@ defmodule Pleroma.User do { :ok, follower } = follower |> follow_changeset(%{following: following}) - |> Repo.update + |> update_and_set_cache {:ok, followed} = update_follower_count(followed) @@ -191,6 +207,17 @@ defmodule Pleroma.User do Repo.get_by(User, ap_id: ap_id) end + def update_and_set_cache(changeset) do + with {:ok, user} <- Repo.update(changeset) do + Cachex.set(:user_cache, "ap_id:#{user.ap_id}", user) + Cachex.set(:user_cache, "nickname:#{user.nickname}", user) + Cachex.set(:user_cache, "user_info:#{user.id}", user_info(user)) + {:ok, user} + else + e -> e + end + end + def get_cached_by_ap_id(ap_id) do key = "ap_id:#{ap_id}" Cachex.get!(:user_cache, key, fallback: fn(_) -> get_by_ap_id(ap_id) end) @@ -210,22 +237,30 @@ defmodule Pleroma.User do Cachex.get!(:user_cache, key, fallback: fn(_) -> user_info(user) end) end + def fetch_by_nickname(nickname) do + ap_try = ActivityPub.make_user_from_nickname(nickname) + + case ap_try do + {:ok, user} -> {:ok, user} + _ -> OStatus.make_user(nickname) + end + end + def get_or_fetch_by_nickname(nickname) do with %User{} = user <- get_by_nickname(nickname) do user else _e -> with [_nick, _domain] <- String.split(nickname, "@"), - {:ok, user} <- OStatus.make_user(nickname) do + {:ok, user} <- fetch_by_nickname(nickname) do user else _e -> nil end end end - # TODO: these queries could be more efficient if the type in postgresql wasn't map, but array. def get_followers(%User{id: id, follower_address: follower_address}) do q = from u in User, - where: fragment("? @> ?", u.following, ^follower_address ), + where: ^follower_address in u.following, where: u.id != ^id {:ok, Repo.all(q)} @@ -245,7 +280,7 @@ defmodule Pleroma.User do cs = info_changeset(user, %{info: new_info}) - Repo.update(cs) + update_and_set_cache(cs) end def update_note_count(%User{} = user) do @@ -259,12 +294,13 @@ defmodule Pleroma.User do cs = info_changeset(user, %{info: new_info}) - Repo.update(cs) + update_and_set_cache(cs) end def update_follower_count(%User{} = user) do follower_count_query = from u in User, - where: fragment("? @> ?", u.following, ^user.follower_address), + where: ^user.follower_address in u.following, + where: u.id != ^user.id, select: count(u.id) follower_count = Repo.one(follower_count_query) @@ -273,10 +309,10 @@ defmodule Pleroma.User do cs = info_changeset(user, %{info: new_info}) - Repo.update(cs) + update_and_set_cache(cs) end - def get_notified_from_activity(%Activity{data: %{"to" => to}}) do + def get_notified_from_activity(%Activity{recipients: to}) do query = from u in User, where: u.ap_id in ^to, where: u.local == true @@ -284,10 +320,10 @@ defmodule Pleroma.User do Repo.all(query) end - def get_recipients_from_activity(%Activity{data: %{"to" => to}}) do + def get_recipients_from_activity(%Activity{recipients: to}) do query = from u in User, where: u.ap_id in ^to, - or_where: fragment("? \\\?| ?", u.following, ^to) + or_where: fragment("? && ?", u.following, ^to) query = from u in query, where: u.local == true @@ -311,7 +347,7 @@ defmodule Pleroma.User do new_info = Map.put(user.info, "blocks", new_blocks) cs = User.info_changeset(user, %{info: new_info}) - Repo.update(cs) + update_and_set_cache(cs) end def unblock(user, %{ap_id: ap_id}) do @@ -320,7 +356,7 @@ defmodule Pleroma.User do new_info = Map.put(user.info, "blocks", new_blocks) cs = User.info_changeset(user, %{info: new_info}) - Repo.update(cs) + update_and_set_cache(cs) end def blocks?(user, %{ap_id: ap_id}) do @@ -328,4 +364,85 @@ defmodule Pleroma.User do Enum.member?(blocks, ap_id) end + def local_user_query() do + from u in User, + where: u.local == true + end + + def deactivate (%User{} = user) do + new_info = Map.put(user.info, "deactivated", true) + cs = User.info_changeset(user, %{info: new_info}) + update_and_set_cache(cs) + end + + def delete (%User{} = user) do + {:ok, user} = User.deactivate(user) + + # Remove all relationships + {:ok, followers } = User.get_followers(user) + followers + |> Enum.each(fn (follower) -> User.unfollow(follower, user) end) + + {:ok, friends} = User.get_friends(user) + friends + |> Enum.each(fn (followed) -> User.unfollow(user, followed) end) + + query = from a in Activity, + where: a.actor == ^user.ap_id + + Repo.all(query) + |> Enum.each(fn (activity) -> + case activity.data["type"] do + "Create" -> ActivityPub.delete(Object.get_by_ap_id(activity.data["object"]["id"])) + _ -> "Doing nothing" # TODO: Do something with likes, follows, repeats. + end + end) + + :ok + end + + def get_or_fetch_by_ap_id(ap_id) do + if user = get_by_ap_id(ap_id) do + user + else + with {:ok, user} <- ActivityPub.make_user_from_ap_id(ap_id) do + user + end + end + end + + # AP style + def public_key_from_info(%{"source_data" => %{"publicKey" => %{"publicKeyPem" => public_key_pem}}}) do + key = :public_key.pem_decode(public_key_pem) + |> hd() + |> :public_key.pem_entry_decode() + + {:ok, key} + end + + # OStatus Magic Key + def public_key_from_info(%{"magic_key" => magic_key}) do + {:ok, Pleroma.Web.Salmon.decode_key(magic_key)} + end + + def get_public_key_for_ap_id(ap_id) do + with %User{} = user <- get_or_fetch_by_ap_id(ap_id), + {:ok, public_key} <- public_key_from_info(user.info) do + {:ok, public_key} + else + _ -> :error + end + end + + defp blank?(""), do: nil + defp blank?(n), do: n + + def insert_or_update_user(data) do + data = data + |> Map.put(:name, blank?(data[:name]) || data[:nickname]) + cs = User.remote_user_creation(data) + Repo.insert(cs, on_conflict: :replace_all, conflict_target: :nickname) + end + + def ap_enabled?(%User{info: info}), do: info["ap_enabled"] end