ℹ Improve docs and documentation (again)

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2019-03-19 11:16:03 +01:00
parent 08a8938a6f
commit 2fe33aa470
12 changed files with 462 additions and 315 deletions

View File

@@ -92,6 +92,10 @@ defmodule Mobilizon.Actors.Actor do
|> unique_constraint(:url, name: :actors_url_index)
end
@doc """
Changeset for person registration
"""
@spec registration_changeset(struct(), map()) :: Ecto.Changeset.t()
def registration_changeset(%Actor{} = actor, attrs) do
actor
|> Ecto.Changeset.cast(attrs, [
@@ -116,6 +120,10 @@ defmodule Mobilizon.Actors.Actor do
# TODO : Use me !
# @email_regex ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
@doc """
Changeset for remote actor creation
"""
@spec remote_actor_creation(map()) :: Ecto.Changeset.t()
def remote_actor_creation(params) do
changes =
%Actor{}
@@ -158,6 +166,10 @@ defmodule Mobilizon.Actors.Actor do
changes
end
@doc """
Changeset for group creation
"""
@spec group_creation(struct(), map()) :: Ecto.Changeset.t()
def group_creation(%Actor{} = actor, params) do
actor
|> Ecto.Changeset.cast(params, [
@@ -260,6 +272,7 @@ defmodule Mobilizon.Actors.Actor do
If actor A and C both follow actor B, actor B's followers are A and C
"""
@spec get_followers(struct(), number(), number()) :: list()
def get_followers(%Actor{id: actor_id} = _actor, page \\ nil, limit \\ nil) do
Repo.all(
from(
@@ -277,6 +290,7 @@ defmodule Mobilizon.Actors.Actor do
If actor A follows actor B and C, actor A's followings are B and B
"""
@spec get_followings(struct(), number(), number()) :: list()
def get_followings(%Actor{id: actor_id} = _actor, page \\ nil, limit \\ nil) do
Repo.all(
from(
@@ -289,6 +303,10 @@ defmodule Mobilizon.Actors.Actor do
)
end
@doc """
Returns the groups an actor is member of
"""
@spec get_groups_member_of(struct()) :: list()
def get_groups_member_of(%Actor{id: actor_id}) do
Repo.all(
from(
@@ -300,6 +318,10 @@ defmodule Mobilizon.Actors.Actor do
)
end
@doc """
Returns the members for a group actor
"""
@spec get_members_for_group(struct()) :: list()
def get_members_for_group(%Actor{id: actor_id}) do
Repo.all(
from(
@@ -311,6 +333,9 @@ defmodule Mobilizon.Actors.Actor do
)
end
@doc """
Make an actor follow another
"""
@spec follow(struct(), struct(), boolean()) :: Follower.t() | {:error, String.t()}
def follow(%Actor{} = followed, %Actor{} = follower, approved \\ true) do
with {:suspended, false} <- {:suspended, followed.suspended},
@@ -327,6 +352,9 @@ defmodule Mobilizon.Actors.Actor do
end
end
@doc """
Unfollow an actor (remove a `Mobilizon.Actors.Follower`)
"""
@spec unfollow(struct(), struct()) :: {:ok, Follower.t()} | {:error, Ecto.Changeset.t()}
def unfollow(%Actor{} = followed, %Actor{} = follower) do
with {:already_following, %Follower{} = follow} <-
@@ -338,6 +366,8 @@ defmodule Mobilizon.Actors.Actor do
end
end
@spec do_follow(struct(), struct(), boolean) ::
{:ok, Follower.t()} | {:error, Ecto.Changeset.t()}
defp do_follow(%Actor{} = follower, %Actor{} = followed, approved) do
Actors.create_follower(%{
"actor_id" => follower.id,
@@ -346,7 +376,10 @@ defmodule Mobilizon.Actors.Actor do
})
end
@spec following?(struct(), struct()) :: boolean()
@doc """
Returns whether an actor is following another
"""
@spec following?(struct(), struct()) :: Follower.t() | false
def following?(
%Actor{} = follower_actor,
%Actor{} = followed_actor
@@ -381,13 +414,34 @@ defmodule Mobilizon.Actors.Actor do
end
end
@doc """
Return display name and username
## Examples
iex> display_name_and_username(%Actor{name: "Thomas C", preferred_username: "tcit", domain: nil})
"Thomas (tcit)"
iex> display_name_and_username(%Actor{name: "Thomas C", preferred_username: "tcit", domain: "framapiaf.org"})
"Thomas (tcit@framapiaf.org)"
iex> display_name_and_username(%Actor{name: nil, preferred_username: "tcit", domain: "framapiaf.org"})
"tcit@framapiaf.org"
"""
@spec display_name_and_username(struct()) :: String.t()
def display_name_and_username(%Actor{name: nil} = actor), do: actor_acct_from_actor(actor)
def display_name_and_username(%Actor{name: ""} = actor), do: actor_acct_from_actor(actor)
def display_name_and_username(%Actor{name: name} = actor),
do: name <> " (" <> actor_acct_from_actor(actor) <> ")"
@doc """
Clear multiple caches for an actor
"""
@spec clear_cache(struct()) :: {:ok, true}
def clear_cache(%Actor{preferred_username: preferred_username, domain: nil}) do
Cachex.del(:activity_pub, "actor_" <> preferred_username)
Cachex.del(:feed, "actor_" <> preferred_username)
Cachex.del(:ics, "actor_" <> preferred_username)
end
end

View File

@@ -56,6 +56,7 @@ defmodule Mobilizon.Actors do
Repo.get!(Actor, id)
end
# Get actor by ID and preload organized events, followers and followings
@spec get_actor_with_everything(integer()) :: Ecto.Query
defp do_get_actor_with_everything(id) do
from(a in Actor, where: a.id == ^id, preload: [:organized_events, :followers, :followings])
@@ -144,6 +145,7 @@ defmodule Mobilizon.Actors do
%Ecto.Changeset{data: %Mobilizon.Actors.Actor{}}
"""
@spec change_actor(Actor.t()) :: Ecto.Changeset.t()
def change_actor(%Actor{} = actor) do
Actor.changeset(actor, %{})
end
@@ -151,6 +153,7 @@ defmodule Mobilizon.Actors do
@doc """
List the groups
"""
@spec list_groups(number(), number()) :: list(Actor.t())
def list_groups(page \\ nil, limit \\ nil) do
Repo.all(
from(
@@ -164,6 +167,7 @@ defmodule Mobilizon.Actors do
@doc """
Get the default member role depending on the actor openness
"""
@spec get_default_member_role(Actor.t()) :: atom()
def get_default_member_role(%Actor{openness: :open}), do: :member
def get_default_member_role(%Actor{}), do: :not_approved
@@ -227,6 +231,12 @@ defmodule Mobilizon.Actors do
Repo.delete!(group)
end
@doc """
Upsert an actor.
Conflicts on actor's URL/AP ID. Replaces keys, avatar and banner, name and summary.
"""
@spec insert_or_update_actor(map(), boolean()) :: {:ok, Actor.t()}
def insert_or_update_actor(data, preload \\ false) do
cs = Actor.remote_actor_creation(data)
@@ -344,24 +354,50 @@ defmodule Mobilizon.Actors do
end
# Get actor by username and domain is nil
@spec do_get_actor_by_name(Ecto.Queryable.t(), String.t()) :: Ecto.Queryable.t()
defp do_get_actor_by_name(query, name) do
from(a in query, where: a.preferred_username == ^name and is_nil(a.domain))
end
# Get actor by username and domain
@spec do_get_actor_by_name(Ecto.Queryable.t(), String.t(), String.t()) :: Ecto.Queryable.t()
defp do_get_actor_by_name(query, name, domain) do
from(a in query, where: a.preferred_username == ^name and a.domain == ^domain)
end
@doc """
Return a local actor by it's preferred username
"""
@spec get_local_actor_by_name(String.t()) :: Actor.t() | nil
def get_local_actor_by_name(name) do
Repo.one(from(a in Actor, where: a.preferred_username == ^name and is_nil(a.domain)))
end
@doc """
Return a local actor by it's preferred username and preload associations
Preloads organized_events, followers and followings
"""
@spec get_local_actor_by_name_with_everything(String.t()) :: Actor.t() | nil
def get_local_actor_by_name_with_everything(name) do
actor = Repo.one(from(a in Actor, where: a.preferred_username == ^name and is_nil(a.domain)))
Repo.preload(actor, [:organized_events, :followers, :followings])
end
@doc """
Returns actor by name and preloads the organized events
## Examples
iex> get_actor_by_name_with_everything("tcit")
%Mobilizon.Actors.Actor{preferred_username: "tcit", domain: nil, organized_events: []}
iex> get_actor_by_name_with_everything("tcit@social.tcit.fr")
%Mobilizon.Actors.Actor{preferred_username: "tcit", domain: "social.tcit.fr", organized_events: []}
iex> get_actor_by_name_with_everything("tcit", :Group)
nil
"""
@spec get_actor_by_name_with_everything(String.t(), atom() | nil) :: Actor.t()
def get_actor_by_name_with_everything(name, type \\ nil) do
name
@@ -403,6 +439,13 @@ defmodule Mobilizon.Actors do
end
end
@doc """
Getting an actor from url, eventually creating it
Returns an error if fetch failed
"""
# TODO: Move this to Mobilizon.Service.ActivityPub
@spec get_or_fetch_by_url!(String.t(), bool()) :: Actor.t()
def get_or_fetch_by_url!(url, preload \\ false) do
with {:ok, actor} <- get_actor_by_url(url, preload) do
actor
@@ -422,6 +465,7 @@ defmodule Mobilizon.Actors do
Find local users by their username
"""
# TODO: This doesn't seem to be used anyway
@spec find_local_by_username(String.t()) :: list(Actor.t())
def find_local_by_username(username) do
actors =
Repo.all(
@@ -507,6 +551,7 @@ defmodule Mobilizon.Actors do
@doc """
Create a new person actor
"""
@spec new_person(map()) :: {:ok, Actor.t()} | any
def new_person(args) do
key = :public_key.generate_key({:rsa, 2048, 65_537})
entry = :public_key.pem_entry_encode(:RSAPrivateKey, key)
@@ -522,6 +567,10 @@ defmodule Mobilizon.Actors do
end
end
@doc """
Register a new bot actor.
"""
@spec register_bot_account(map()) :: Actor.t()
def register_bot_account(%{name: name, summary: summary}) do
key = :public_key.generate_key({:rsa, 2048, 65_537})
entry = :public_key.pem_entry_encode(:RSAPrivateKey, key)
@@ -630,7 +679,11 @@ defmodule Mobilizon.Actors do
Member.changeset(member, %{})
end
def groups_for_actor(%Actor{id: id} = _actor) do
@doc """
Returns the memberships for an actor
"""
@spec groups_memberships_for_actor(Actor.t()) :: list(Member.t())
def groups_memberships_for_actor(%Actor{id: id} = _actor) do
Repo.all(
from(
m in Member,
@@ -640,7 +693,11 @@ defmodule Mobilizon.Actors do
)
end
def members_for_group(%Actor{type: :Group, id: id} = _group) do
@doc """
Returns the memberships for a group
"""
@spec memberships_for_group(Actor.t()) :: list(Member.t())
def memberships_for_group(%Actor{type: :Group, id: id} = _group) do
Repo.all(
from(
m in Member,
@@ -681,6 +738,9 @@ defmodule Mobilizon.Actors do
"""
def get_bot!(id), do: Repo.get!(Bot, id)
@doc """
Get the bot associated to an actor
"""
@spec get_bot_by_actor(Actor.t()) :: Bot.t()
def get_bot_by_actor(%Actor{} = actor) do
Repo.get_by!(Bot, actor_id: actor.id)
@@ -772,6 +832,9 @@ defmodule Mobilizon.Actors do
|> Repo.preload([:actor, :target_actor])
end
@doc """
Get a follower by the followed actor and following actor
"""
@spec get_follower(Actor.t(), Actor.t()) :: Follower.t()
def get_follower(%Actor{id: followed_id}, %Actor{id: follower_id}) do
Repo.one(

View File

@@ -58,7 +58,7 @@ defmodule MobilizonWeb.API.Comments do
@spec get_in_reply_to_comment(nil) :: nil
defp get_in_reply_to_comment(nil), do: nil
@spec get_in_reply_to_comment(String.t()) :: Comment.t()
defp get_in_reply_to_comment(inReplyToCommentURL) do
ActivityPub.fetch_object_from_url(inReplyToCommentURL)
defp get_in_reply_to_comment(in_reply_to_comment_url) do
ActivityPub.fetch_object_from_url(in_reply_to_comment_url)
end
end

View File

@@ -9,6 +9,9 @@ defmodule MobilizonWeb.API.Events do
alias Mobilizon.Service.ActivityPub.Utils, as: ActivityPubUtils
import MobilizonWeb.API.Utils
@doc """
Create an event
"""
@spec create_event(map()) :: {:ok, Activity.t()} | any()
def create_event(
%{

View File

@@ -9,6 +9,9 @@ defmodule MobilizonWeb.API.Groups do
alias Mobilizon.Service.ActivityPub.Utils, as: ActivityPubUtils
import MobilizonWeb.API.Utils
@doc """
Create a group
"""
@spec create_group(map()) :: {:ok, Activity.t()} | any()
def create_group(
%{

View File

@@ -4,8 +4,13 @@ defmodule MobilizonWeb.Resolvers.Address do
"""
require Logger
alias Mobilizon.Addresses
alias Mobilizon.Addresses.Address
alias Mobilizon.Service.Geospatial
@doc """
Search an address
"""
@spec search(map(), map(), map()) :: {:ok, list(Address.t())}
def search(_parent, %{query: query}, %{context: %{ip: ip}}) do
country = Geolix.lookup(ip) |> Map.get(:country, nil)
@@ -18,6 +23,10 @@ defmodule MobilizonWeb.Resolvers.Address do
{:ok, addresses}
end
@doc """
Reverse geocode some coordinates
"""
@spec reverse_geocode(map(), map(), map()) :: {:ok, list(Address.t())}
def reverse_geocode(_parent, %{longitude: longitude, latitude: latitude}, %{context: %{ip: ip}}) do
country = Geolix.lookup(ip) |> Map.get(:country, nil)