summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md15
-rw-r--r--docs/Clients.md83
-rw-r--r--lib/pleroma/object.ex22
-rw-r--r--lib/pleroma/user.ex17
-rw-r--r--lib/pleroma/web/activity_pub/utils.ex10
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api.ex12
-rw-r--r--test/object_test.exs28
-rw-r--r--test/user_test.exs6
8 files changed, 149 insertions, 44 deletions
diff --git a/README.md b/README.md
index d39731ef4..4f22445d0 100644
--- a/README.md
+++ b/README.md
@@ -8,20 +8,7 @@ Pleroma is written in Elixir, high-performance and can run on small devices like
For clients it supports both the [GNU Social API with Qvitter extensions](https://twitter-api.readthedocs.io/en/latest/index.html) and the [Mastodon client API](https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md).
-Client applications that are committed to supporting Pleroma:
-
-* Mastalab (Android, Streaming Ready)
-* nekonium (Android, Streaming Ready)
-* Tusky (Android, No Streaming)
-* Twidere (Android, No Streaming)
-* Mast (iOS, Paid)
-* Amaroq (iOS, No Streaming)
-
-Client applications that are known to work well:
-
-* Tootdon (Android + iOS, No Streaming)
-* Tootle (iOS, No Streaming)
-* Whalebird (Windows + Mac + Linux)
+- [Client Applications for Pleroma](docs/Clients.md)
No release has been made yet, but several servers have been online for months already. If you want to run your own server, feel free to contact us at @lain@pleroma.soykaf.com or in our dev chat at #pleroma on freenode or via matrix at <https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org>.
diff --git a/docs/Clients.md b/docs/Clients.md
new file mode 100644
index 000000000..28f8afafd
--- /dev/null
+++ b/docs/Clients.md
@@ -0,0 +1,83 @@
+# Pleroma Clients
+Note: Additionnal clients may be working but theses are officially supporting Pleroma.
+Feel free to contact us to be added to this list!
+
+## Desktop
+### Roma for Desktop
+- Homepage: <http://www.pleroma.com/desktop-app/>
+- Source Code: ???
+- Platforms: Windows, Mac, (Linux?)
+
+### Social
+- Source Code: <https://gitlab.gnome.org/BrainBlasted/Social>
+- Contact: [@brainblasted@social.libre.fi](https://social.libre.fi/users/brainblasted)
+- Platforms: Linux (GNOME)
+- Note(2019-01-28): Not at a pre-alpha stage yet
+
+### Whalebird
+- Homepage: <https://whalebird.org/>
+- Source Code: <https://github.com/h3poteto/whalebird-desktop>
+- Contact: [@h3poteto@pleroma.io](https://pleroma.io/users/h3poteto)
+- Platforms: Windows, Mac, Linux
+
+## Handheld
+### Amaroq
+- Homepage: <https://itunes.apple.com/us/app/amaroq-for-mastodon/id1214116200>
+- Source Code: <https://github.com/ReticentJohn/Amaroq>
+- Contact: [@eurasierboy@mastodon.social](https://mastodon.social/users/eurasierboy)
+- Platforms: iOS
+
+### Nekonium
+- Homepage: [F-Droid Repository](https://repo.gdgd.jp.net/), [Google Play](https://play.google.com/store/apps/details?id=com.apps.nekonium), [Amazon](https://www.amazon.co.jp/dp/B076FXPRBC/)
+- Source: <https://git.gdgd.jp.net/lin/nekonium/>
+- Contact: [@lin@pleroma.gdgd.jp.net](https://pleroma.gdgd.jp.net/users/lin)
+- Platforms: Android
+
+### Mastalab
+- Source Code: <https://gitlab.com/tom79/mastalab/>
+- Contact: [@tom79@mastodon.social](https://mastodon.social/users/tom79)
+- Platforms: Android
+
+### Roma
+- Homepage: <http://www.pleroma.com/>
+- Source Code: ???
+- Platforms: iOS, Android
+
+### Tootdon
+- Homepage: <http://tootdon.club/>, <http://blog.mastodon-tootdon.com/>
+- Source Code: ???
+- Contact: [@tootdon@mstdn.jp](https://mstdn.jp/users/tootdon)
+- Platforms: Android, iOS
+
+### Tusky
+- Homepage: <https://tuskyapp.github.io/>
+- Source Code: <https://github.com/tuskyapp/Tusky>
+- Contact: [@ConnyDuck@mastodon.social](https://mastodon.social/users/ConnyDuck)
+- Platforms: Android
+
+### Twidere
+- Homepage: <https://twidere.mariotaku.org/>
+- Source Code: <https://github.com/TwidereProject/Twidere-Android/>, <https://github.com/TwidereProject/Twidere-iOS/>
+- Contact: <me@mariotaku.org>
+- Platform: Android, iOS
+
+## Alternative Web Interfaces
+### Brutaldon
+- Homepage: <https://jfm.carcosa.net/projects/software/brutaldon/>
+- Source Code: <https://github.com/jfmcbrayer/brutaldon>
+- Contact: [@gcupc@glitch.social](https://glitch.social/users/gcupc)
+
+### Halcyon
+- Source Code: <https://notabug.org/halcyon-suite/halcyon>
+- Contact: [@halcyon@social.csswg.org](https://social.csswg.org/users/halcyon)
+
+### Pinafore
+- Homepage: <https://pinafore.social/>
+- Source Code: <https://github.com/nolanlawson/pinafore>
+- Contact: [@pinafore@mastodon.technology](https://mastodon.technology/users/pinafore)
+- Note: Pleroma support is a secondary goal
+
+### Sengi
+- Source Code: <https://github.com/NicolasConstant/sengi>
+- Contact: [@sengi_app@mastodon.social](https://mastodon.social/users/sengi_app)
+- Note(2019-01-28): The development is currently in a early stage.
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index 7b46a3b05..96079cf22 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -13,9 +13,29 @@ defmodule Pleroma.Object do
timestamps()
end
+ def insert_or_get(cng) do
+ {_, data} = fetch_field(cng, :data)
+ id = data["id"] || data[:id]
+ key = "object:#{id}"
+
+ fetcher = fn _ ->
+ with nil <- get_by_ap_id(id),
+ {:ok, object} <- Repo.insert(cng) do
+ {:commit, object}
+ else
+ %Object{} = object -> {:commit, object}
+ e -> {:ignore, e}
+ end
+ end
+
+ with {state, object} when state in [:commit, :ok] <- Cachex.fetch(:object_cache, key, fetcher) do
+ {:ok, object}
+ end
+ end
+
def create(data) do
Object.change(%Object{}, %{data: data})
- |> Repo.insert()
+ |> insert_or_get()
end
def change(struct, params \\ %{}) do
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 33630ac7c..361034887 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -96,12 +96,6 @@ defmodule Pleroma.User do
"#{ap_id(user)}/followers"
end
- def follow_changeset(struct, params \\ %{}) do
- struct
- |> cast(params, [:following])
- |> validate_required([:following])
- end
-
def user_info(%User{} = user) do
oneself = if user.local, do: 1, else: 0
@@ -256,8 +250,8 @@ defmodule Pleroma.User do
@doc "Inserts provided changeset, performs post-registration actions (confirmation email sending etc.)"
def register(%Ecto.Changeset{} = changeset) do
with {:ok, user} <- Repo.insert(changeset),
- {:ok, _} <- try_send_confirmation_email(user),
- {:ok, user} <- autofollow_users(user) do
+ {:ok, user} <- autofollow_users(user),
+ {:ok, _} <- try_send_confirmation_email(user) do
{:ok, user}
end
end
@@ -307,10 +301,13 @@ defmodule Pleroma.User do
end
end
- @doc "A mass follow for local users. Ignores blocks and has no side effects"
+ @doc "A mass follow for local users. Respects blocks but does not create activities."
@spec follow_all(User.t(), list(User.t())) :: {atom(), User.t()}
def follow_all(follower, followeds) do
- followed_addresses = Enum.map(followeds, fn %{follower_address: fa} -> fa end)
+ followed_addresses =
+ followeds
+ |> Enum.reject(fn %{ap_id: ap_id} -> ap_id in follower.info.blocks end)
+ |> Enum.map(fn %{follower_address: fa} -> fa end)
q =
from(u in User,
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index 4a2cc6738..134701e80 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -134,14 +134,8 @@ defmodule Pleroma.Web.ActivityPub.Utils do
context = context || generate_id("contexts")
changeset = Object.context_mapping(context)
- case Repo.insert(changeset) do
- {:ok, object} ->
- object
-
- # This should be solved by an upsert, but it seems ecto
- # has problems accessing the constraint inside the jsonb.
- {:error, _} ->
- Object.get_cached_by_ap_id(context)
+ with {:ok, object} <- Object.insert_or_get(changeset) do
+ object
end
end
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index 7d00c01a1..ddd5c5cfb 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -305,16 +305,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
else
_e ->
changeset = Object.context_mapping(context)
-
- case Repo.insert(changeset) do
- {:ok, %{id: id}} ->
- id
-
- # This should be solved by an upsert, but it seems ecto
- # has problems accessing the constraint inside the jsonb.
- {:error, _} ->
- Object.get_cached_by_ap_id(context).id
- end
+ {:ok, object} = Object.insert_or_get(changeset)
+ object.id
end
end
diff --git a/test/object_test.exs b/test/object_test.exs
index 72194975d..ab6431012 100644
--- a/test/object_test.exs
+++ b/test/object_test.exs
@@ -57,4 +57,32 @@ defmodule Pleroma.ObjectTest do
assert cached_object.data["type"] == "Tombstone"
end
end
+
+ describe "insert_or_get" do
+ test "inserting the same object twice (by id) just returns the original object" do
+ data = %{data: %{"id" => Ecto.UUID.generate()}}
+ cng = Object.change(%Object{}, data)
+ {:ok, object} = Object.insert_or_get(cng)
+ {:ok, second_object} = Object.insert_or_get(cng)
+
+ Cachex.clear(:object_cache)
+ {:ok, third_object} = Object.insert_or_get(cng)
+
+ assert object == second_object
+ assert object == third_object
+ end
+ end
+
+ describe "create" do
+ test "inserts an object for a given data set" do
+ data = %{"id" => Ecto.UUID.generate()}
+
+ {:ok, object} = Object.create(data)
+ assert object.data["id"] == data["id"]
+
+ # Works when doing it twice.
+ {:ok, object} = Object.create(data)
+ assert object.data["id"] == data["id"]
+ end
+ end
end
diff --git a/test/user_test.exs b/test/user_test.exs
index 98d3bc464..523ab1ea4 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -53,16 +53,20 @@ defmodule Pleroma.UserTest do
followed_zero = insert(:user)
followed_one = insert(:user)
followed_two = insert(:user)
+ blocked = insert(:user)
not_followed = insert(:user)
+ {:ok, user} = User.block(user, blocked)
+
{:ok, user} = User.follow(user, followed_zero)
- {:ok, user} = User.follow_all(user, [followed_one, followed_two])
+ {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked])
assert User.following?(user, followed_one)
assert User.following?(user, followed_two)
assert User.following?(user, followed_zero)
refute User.following?(user, not_followed)
+ refute User.following?(user, blocked)
end
test "follow_all follows mutliple users without duplicating" do