diff options
-rw-r--r-- | README.md | 15 | ||||
-rw-r--r-- | docs/Clients.md | 83 | ||||
-rw-r--r-- | lib/pleroma/object.ex | 22 | ||||
-rw-r--r-- | lib/pleroma/user.ex | 17 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/utils.ex | 10 | ||||
-rw-r--r-- | lib/pleroma/web/twitter_api/twitter_api.ex | 12 | ||||
-rw-r--r-- | test/object_test.exs | 28 | ||||
-rw-r--r-- | test/user_test.exs | 6 |
8 files changed, 149 insertions, 44 deletions
@@ -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 |