Commit graph

312 commits

Author SHA1 Message Date
Mark Felder
a9aa810d3d Change imports to generate an Oban job per each task 2024-08-22 13:24:07 -04:00
Mark Felder
8f285a787f Refactor backups to be fully controlled by Oban 2024-07-23 10:30:40 -04:00
Mark Felder
d07d49227f PleromaAPI: marking notifications as read no longer returns notifications 2024-05-18 18:17:35 +00:00
Mark Felder
ede414094f RichMedia refactor
Rich Media parsing was previously handled on-demand with a 2 second HTTP request timeout and retained only in Cachex. Every time a Pleroma instance is restarted it will have to request and parse the data for each status with a URL detected. When fetching a batch of statuses they were processed in parallel to attempt to keep the maximum latency at 2 seconds, but often resulted in a timeline appearing to hang during loading due to a URL that could not be successfully reached. URLs which had images links that expire (Amazon AWS) were parsed and inserted with a TTL to ensure the image link would not break.

Rich Media data is now cached in the database and fetched asynchronously. Cachex is used as a read-through cache. When the data becomes available we stream an update to the clients. If the result is returned quickly the experience is almost seamless. Activities were already processed for their Rich Media data during ingestion to warm the cache, so users should not normally encounter the asynchronous loading of the Rich Media data.

Implementation notes:

- The async worker is a Task with a globally unique process name to prevent duplicate processing of the same URL
- The Task will attempt to fetch the data 3 times with increasing sleep time between attempts
- The HTTP request obeys the default HTTP request timeout value instead of 2 seconds
- URLs that cannot be successfully parsed due to an unexpected error receives a negative cache entry for 15 minutes
- URLs that fail with an expected error will receive a negative cache with no TTL
- Activities that have no detected URLs insert a nil value in the Cachex :scrubber_cache so we do not repeat parsing the object content with Floki every time the activity is rendered
- Expiring image URLs are handled with an Oban job
- There is no automatic cleanup of the Rich Media data in the database, but it is safe to delete at any time
- The post draft/preview feature makes the URL processing synchronous so the rendered post preview will have an accurate rendering

Overall performance of timelines and creating new posts which contain URLs is greatly improved.
2024-05-07 19:54:56 -04:00
marcin mikołajczak
37ec645ff2 Fix BookmarkFolderView, add test
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2024-03-20 13:24:43 +01:00
marcin mikołajczak
d415686bb9 Allow to group bookmarks in folders
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2024-03-01 11:04:01 +01:00
Mark Felder
5e8bedcca0 Pleroma.Web.PleromaAPI.MascotController: fix dialyzer error due to bad error match
lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:37:pattern_match
The pattern can never match the type.

Pattern:
{:content_type, _}

Type:
{:error, _}

________________________________________________________________________________
lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:40:pattern_match
The pattern can never match the type.

Pattern:
{:upload, {:error, _}}

Type:
{:error, _}
2024-01-31 11:15:48 -05:00
Mark Felder
9760149886 Pleroma.Web.PleromaAPI.UserImportController: fix dialyzer errors with replace_params: false 2024-01-31 10:13:02 -05:00
Mark Felder
c39e4dd214 Pleroma.Web.PleromaAPI.NotificationController: fix dialyzer errors with replace_params: false 2024-01-31 10:13:02 -05:00
Mark Felder
e157fd60ee Pleroma.Web.PleromaAPI.MascotController: fix dialyzer errors with replace_params: false 2024-01-31 10:13:02 -05:00
Mark Felder
9d16393d8b Pleroma.Web.PleromaAPI.EmojiPackController: fix dialyzer errors with replace_params: false 2024-01-31 10:13:02 -05:00
Mark Felder
f1aeb80518 Pleroma.Web.PleromaAPI.EmojiFileController: fix dialyzer errors with replace_params: false 2024-01-31 10:13:02 -05:00
Mark Felder
4d20fbc6d9 Pleroma.Web.PleromaAPI.ChatController: fix dialyzer errors with replace_params: false 2024-01-31 10:12:59 -05:00
Mark Felder
674ae51d6a Revert "Pleroma.Web.PleromaAPI.UserImportController: Dialyzer errors"
This reverts commit 52e18a6249.
2024-01-30 14:19:41 -05:00
Mark Felder
4a80a285d1 Revert "Pleroma.Web.PleromaAPI.NotificationController: dialyzer errors"
This reverts commit 26a95e5787.
2024-01-30 14:19:32 -05:00
Mark Felder
2c8e4f32c6 Revert "Pleroma.Web.PleromaAPI.MascotController: dialyzer errors"
This reverts commit 9c8055d4b3.
2024-01-30 14:18:36 -05:00
Mark Felder
b1a6102a85 Revert "Pleroma.Web.PleromaAPI.EmojiPackController: dialyzer errors"
This reverts commit 77bf617c4b.
2024-01-30 14:15:40 -05:00
Mark Felder
4a9ed4682a Revert "Pleroma.Web.PleromaAPI.EmojiFileController: dialyzer errors"
This reverts commit dc912dc590.
2024-01-30 14:15:17 -05:00
Mark Felder
b709fc4dfe Revert "Pleroma.Web.PleromaAPI.ChatController: Dialyzer error"
This reverts commit 8d64eedbec.
2024-01-30 14:15:05 -05:00
Mark Felder
8d64eedbec Pleroma.Web.PleromaAPI.ChatController: Dialyzer error
lib/pleroma/web/pleroma_api/controllers/chat_controller.ex:128:call
The function call will not succeed.

Phoenix.Controller.render(
  _conn :: %{
    :assigns => %{:user => _, _ => _},
    :body_params => %{:last_read_id => _, _ => _},
    _ => _
  },
  <<115, 104, 111, 119, 46, 106, 115, 111, 110>>,
  [
    {:chat,
     %Pleroma.Chat{
       :__meta__ => _,
       :id => _,
       :inserted_at => _,
       :recipient => _,
       :updated_at => _,
       :user => _,
       :user_id => _
     }},
    ...
  ]
)

will never return since the success typing is:
(
  %Plug.Conn{
    :adapter => {atom(), _},
    :assigns => %{atom() => _},
    :body_params => %Plug.Conn.Unfetched{:aspect => atom(), binary() => _},
    :cookies => %Plug.Conn.Unfetched{:aspect => atom(), binary() => _},
    :halted => boolean(),
    :host => binary(),
    :method => binary(),
    :owner => pid(),
    :params => %Plug.Conn.Unfetched{:aspect => atom(), binary() => _},
    :path_info => [binary()],
    :path_params => %{binary() => binary() | [any()] | map()},
    :port => char(),
    :private => %{atom() => _},
    :query_params => %Plug.Conn.Unfetched{
      :aspect => atom(),
      binary() => binary() | [any()] | map()
    },
    :query_string => binary(),
    :remote_ip =>
      {byte(), byte(), byte(), byte()}
      | {char(), char(), char(), char(), char(), char(), char(), char()},
    :req_cookies => %Plug.Conn.Unfetched{:aspect => atom(), binary() => binary()},
    :req_headers => [{_, _}],
    :request_path => binary(),
    :resp_body =>
      nil
      | binary()
      | maybe_improper_list(
          binary() | maybe_improper_list(any(), binary() | []) | byte(),
          binary() | []
        ),
    :resp_cookies => %{binary() => map()},
    :resp_headers => [{_, _}],
    :scheme => :http | :https,
    :script_name => [binary()],
    :secret_key_base => nil | binary(),
    :state =>
      :chunked | :file | :sent | :set | :set_chunked | :set_file | :unset | :upgraded,
    :status => nil | non_neg_integer()
  },
  atom() | binary(),
  atom() | binary() | [{_, _}] | map()
) :: %Plug.Conn{
  :adapter => {atom(), _},
  :assigns => %{atom() => _},
  :body_params => %Plug.Conn.Unfetched{:aspect => atom(), binary() => _},
  :cookies => %Plug.Conn.Unfetched{:aspect => atom(), binary() => _},
  :halted => boolean(),
  :host => binary(),
  :method => binary(),
  :owner => pid(),
  :params => %Plug.Conn.Unfetched{:aspect => atom(), binary() => _},
  :path_info => [binary()],
  :path_params => %{binary() => binary() | [any()] | map()},
  :port => char(),
  :private => %{atom() => _},
  :query_params => %Plug.Conn.Unfetched{
    :aspect => atom(),
    binary() => binary() | [any()] | map()
  },
  :query_string => binary(),
  :remote_ip =>
    {byte(), byte(), byte(), byte()}
    | {char(), char(), char(), char(), char(), char(), char(), char()},
  :req_cookies => %Plug.Conn.Unfetched{:aspect => atom(), binary() => binary()},
  :req_headers => [{_, _}],
  :request_path => binary(),
  :resp_body =>
    nil
    | binary()
    | maybe_improper_list(
        binary() | maybe_improper_list(any(), binary() | []) | byte(),
        binary() | []
      ),
  :resp_cookies => %{binary() => map()},
  :resp_headers => [{_, _}],
  :scheme => :http | :https,
  :script_name => [binary()],
  :secret_key_base => nil | binary(),
  :state => :sent,
  :status => nil | non_neg_integer()
}

and the contract is
(Plug.Conn.t(), binary() | atom(), Keyword.t() | map()) :: Plug.Conn.t()
2024-01-28 15:52:09 -05:00
Mark Felder
456f7cab3e Pleroma.Web.PleromaAPI.ChatController: Dialyzer errors
lib/pleroma/web/pleroma_api/controllers/chat_controller.ex:91:pattern_match
The pattern can never match the type.

Pattern:
{:reject, _message}

Type:
nil

________________________________________________________________________________
lib/pleroma/web/pleroma_api/controllers/chat_controller.ex:96:pattern_match
The pattern can never match the type.

Pattern:
{:error, _message}

Type:
nil
2024-01-28 15:52:09 -05:00
Mark Felder
dc912dc590 Pleroma.Web.PleromaAPI.EmojiFileController: dialyzer errors
lib/pleroma/web/pleroma_api/controllers/emoji_file_controller.ex:52:no_return
Function update/2 has no local return.
________________________________________________________________________________
lib/pleroma/web/pleroma_api/controllers/emoji_file_controller.ex:59:call
The function call will not succeed.

Phoenix.Controller.json(_conn :: %{:body_params => %{:shortcode => _, _ => _}, _ => _}, %{
  binary() =>
    binary()
    | maybe_improper_list(
        binary() | maybe_improper_list(any(), binary() | []) | char(),
        binary() | []
      )
})

breaks the contract
(Plug.Conn.t(), term()) :: Plug.Conn.t()

________________________________________________________________________________
lib/pleroma/web/pleroma_api/controllers/emoji_file_controller.ex:62:call
The function call will not succeed.

Plug.Conn.put_status(_conn :: %{:body_params => %{:shortcode => _, _ => _}, _ => _}, :conflict)

breaks the contract
(t(), status()) :: t()

________________________________________________________________________________
lib/pleroma/web/pleroma_api/controllers/emoji_file_controller.ex:70:call
The function call will not succeed.

Plug.Conn.put_status(_conn :: %{:body_params => %{:shortcode => _, _ => _}, _ => _}, :unprocessable_entity) ::
  :ok
def a() do
  :ok
end

breaks the contract
(t(), status()) :: t()

________________________________________________________________________________
lib/pleroma/web/pleroma_api/controllers/emoji_file_controller.ex:75:call
The function call will not succeed.

Pleroma.Web.PleromaAPI.EmojiFileController.handle_error(
  _conn :: %{:body_params => %{:shortcode => _, _ => _}, _ => _},
  _error :: {:error, atom()},
  %{:code => _, :message => <<_::328>>, :pack_name => binary()}
)

will never return since the 1st arguments differ
from the success typing arguments:

(
  %Plug.Conn{
    :adapter => {atom(), _},
    :assigns => %{atom() => _},
    :body_params => %Plug.Conn.Unfetched{:aspect => atom(), binary() => _},
    :cookies => %Plug.Conn.Unfetched{:aspect => atom(), binary() => _},
    :halted => boolean(),
    :host => binary(),
    :method => binary(),
    :owner => pid(),
    :params => %Plug.Conn.Unfetched{:aspect => atom(), binary() => _},
    :path_info => [binary()],
    :path_params => %{
      binary() =>
        binary() | [binary() | [any()] | map()] | %{binary() => binary() | [any()] | map()}
    },
    :port => char(),
    :private => %{atom() => _},
    :query_params => %Plug.Conn.Unfetched{
      :aspect => atom(),
      binary() =>
        binary() | [binary() | [any()] | map()] | %{binary() => binary() | [any()] | map()}
    },
    :query_string => binary(),
    :remote_ip =>
      {byte(), byte(), byte(), byte()}
      | {char(), char(), char(), char(), char(), char(), char(), char()},
    :req_cookies => %Plug.Conn.Unfetched{:aspect => atom(), binary() => binary()},
    :req_headers => [{binary(), binary()}],
    :request_path => binary(),
    :resp_body =>
      nil
      | binary()
      | maybe_improper_list(
          binary() | maybe_improper_list(any(), binary() | []) | byte(),
          binary() | []
        ),
    :resp_cookies => %{binary() => map()},
    :resp_headers => [{binary(), binary()}],
    :scheme => :http | :https,
    :script_name => [binary()],
    :secret_key_base => nil | binary(),
    :state =>
      :chunked | :file | :sent | :set | :set_chunked | :set_file | :unset | :upgraded,
    :status => nil | non_neg_integer()
  },
  {:error, atom()},
  %{:message => <<_::328, _::size(88)>>, :pack_name => binary(), :code => _}
)

________________________________________________________________________________
lib/pleroma/web/pleroma_api/controllers/emoji_file_controller.ex:75:call
The function call will not succeed.

Pleroma.Web.PleromaAPI.EmojiFileController.handle_error(
  _conn :: %{:body_params => %{:shortcode => _, _ => _}, _ => _},
  _error :: {:error, atom()},
  %{:code => binary(), :message => <<_::328>>, :pack_name => binary()}
)

will never return since the 1st arguments differ
from the success typing arguments:

(
  %Plug.Conn{
    :adapter => {atom(), _},
    :assigns => %{atom() => _},
    :body_params => %Plug.Conn.Unfetched{:aspect => atom(), binary() => _},
    :cookies => %Plug.Conn.Unfetched{:aspect => atom(), binary() => _},
    :halted => boolean(),
    :host => binary(),
    :method => binary(),
    :owner => pid(),
    :params => %Plug.Conn.Unfetched{:aspect => atom(), binary() => _},
    :path_info => [binary()],
    :path_params => %{
      binary() =>
        binary() | [binary() | [any()] | map()] | %{binary() => binary() | [any()] | map()}
    },
    :port => char(),
    :private => %{atom() => _},
    :query_params => %Plug.Conn.Unfetched{
      :aspect => atom(),
      binary() =>
        binary() | [binary() | [any()] | map()] | %{binary() => binary() | [any()] | map()}
    },
    :query_string => binary(),
    :remote_ip =>
      {byte(), byte(), byte(), byte()}
      | {char(), char(), char(), char(), char(), char(), char(), char()},
    :req_cookies => %Plug.Conn.Unfetched{:aspect => atom(), binary() => binary()},
    :req_headers => [{binary(), binary()}],
    :request_path => binary(),
    :resp_body =>
      nil
      | binary()
      | maybe_improper_list(
          binary() | maybe_improper_list(any(), binary() | []) | byte(),
          binary() | []
        ),
    :resp_cookies => %{binary() => map()},
    :resp_headers => [{binary(), binary()}],
    :scheme => :http | :https,
    :script_name => [binary()],
    :secret_key_base => nil | binary(),
    :state =>
      :chunked | :file | :sent | :set | :set_chunked | :set_file | :unset | :upgraded,
    :status => nil | non_neg_integer()
  },
  {:error, atom()},
  %{:message => <<_::328, _::size(88)>>, :pack_name => binary(), :code => _}
)
2024-01-28 15:52:09 -05:00
Mark Felder
77bf617c4b Pleroma.Web.PleromaAPI.EmojiPackController: dialyzer errors
________________________________________________________________________________
lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:112:no_return
Function download/2 has no local return.
________________________________________________________________________________
lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:114:call
The function call will not succeed.

Phoenix.Controller.json(_conn :: %{:body_params => %{:name => _, :url => _, _ => _}, _ => _}, <<111, 107>>)

breaks the contract
(Plug.Conn.t(), term()) :: Plug.Conn.t()

________________________________________________________________________________
lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:117:call
The function call will not succeed.

Plug.Conn.put_status(
  _conn :: %{:body_params => %{:name => _, :url => _, _ => _}, _ => _},
  :internal_server_error
)

breaks the contract
(t(), status()) :: t()

________________________________________________________________________________
lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:122:call
The function call will not succeed.

Plug.Conn.put_status(
  _conn :: %{:body_params => %{:name => _, :url => _, _ => _}, _ => _},
  :internal_server_error
)

breaks the contract
(t(), status()) :: t()

________________________________________________________________________________
lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:127:call
The function call will not succeed.

Plug.Conn.put_status(
  _conn :: %{:body_params => %{:name => _, :url => _, _ => _}, _ => _},
  :internal_server_error
)

breaks the contract
(t(), status()) :: t()

________________________________________________________________________________
lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:187:no_return
Function update/2 has no local return.
________________________________________________________________________________
lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:189:call
The function call will not succeed.

Phoenix.Controller.json(_conn :: %{:body_params => %{:metadata => _, _ => _}, _ => _}, map())

breaks the contract
(Plug.Conn.t(), term()) :: Plug.Conn.t()

________________________________________________________________________________
lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:192:call
The function call will not succeed.

Plug.Conn.put_status(_conn :: %{:body_params => %{:metadata => _, _ => _}, _ => _}, :bad_request)

breaks the contract
(t(), status()) :: t()

________________________________________________________________________________
lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:203:call
The function call will not succeed.

Plug.Conn.put_status(_conn :: %{:body_params => %{:metadata => _, _ => _}, _ => _}, :internal_server_error) ::
  :ok
def a() do
  :ok
end

breaks the contract
(t(), status()) :: t()
2024-01-28 15:52:09 -05:00
Mark Felder
a32d6b3aa4 Pleroma.Web.PleromaAPI.MascotController: dialyzer error
lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:33:pattern_match
The pattern can never match the type.

Pattern:
{:content_type, _}

Type:
{:error, _}
2024-01-28 15:52:09 -05:00
Mark Felder
9c8055d4b3 Pleroma.Web.PleromaAPI.MascotController: dialyzer errors
lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:25:no_return
Function update/2 has no local return.

lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:27:call
The function call will not succeed.

Pleroma.Web.ActivityPub.ActivityPub.upload(_file :: atom() | %{:content_type => _, _ => _}, [{:actor, <<_::56, _::size(8)>>}, ...]) ::
  :ok
def a() do
  :ok
end

will never return since the 2nd arguments differ
from the success typing arguments:

(any(), [
  {:activity_type | :description | :filters | :size_limit | :type | :uploader,
   atom() | binary() | [atom()] | non_neg_integer()}
])

lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:31:call
The function call will not succeed.

Phoenix.Controller.json(
  _conn :: %{
    :assigns => %{:user => _, _ => _},
    :body_params => %{:file => _, _ => _},
    _ => _
  },
  _attachment :: any()
)

breaks the contract
(Plug.Conn.t(), term()) :: Plug.Conn.t()

lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:34:call
The function call will not succeed.

Plug.Conn.put_status(
  _conn :: %{
    :assigns => %{:user => _, _ => _},
    :body_params => %{:file => _, _ => _},
    _ => _
  },
  :unsupported_media_type
)

breaks the contract
(t(), status()) :: t()

lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:34:call
The function call will not succeed.

Plug.Conn.put_status(
  _conn :: %{
    :assigns => %{:user => _, _ => _},
    :body_params => %{:file => _, _ => _},
    _ => _
  },
  :unsupported_media_type
)

breaks the contract
(t(), status()) :: t()

lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:38:unused_fun
Function render_attachment/1 will never be called.
2024-01-28 15:52:09 -05:00
Mark Felder
26a95e5787 Pleroma.Web.PleromaAPI.NotificationController: dialyzer errors
lib/pleroma/web/pleroma_api/controllers/user_import_controller.ex:53:call
The function call will not succeed.

Phoenix.Controller.json(
  _conn :: %{
    :assigns => %{:user => _, _ => _},
    :body_params => %{:list => _, _ => _},
    _ => _
  },
  <<106, 111, 98, 32, 115, 116, 97, 114, 116, 101, 100>>
)

breaks the contract
(Plug.Conn.t(), term()) :: Plug.Conn.t()
2024-01-27 16:15:03 -05:00
Mark Felder
52e18a6249 Pleroma.Web.PleromaAPI.UserImportController: Dialyzer errors
lib/pleroma/web/pleroma_api/controllers/user_import_controller.ex:53:call
The function call will not succeed.

Phoenix.Controller.json(
  _conn :: %{
    :assigns => %{:user => _, _ => _},
    :body_params => %{:list => _, _ => _},
    _ => _
  },
  <<106, 111, 98, 32, 115, 116, 97, 114, 116, 101, 100>>
)

breaks the contract
(Plug.Conn.t(), term()) :: Plug.Conn.t()
2024-01-27 15:57:21 -05:00
NEETzsche
e216603477 Change url to externalLink as requested by hj here: https://shigusegubu.club/notice/AcIjZjackKAt6e522a 2023-11-29 07:55:44 -07:00
NEETzsche
510a7b64f1 Add optional URL value for scrobbles 2023-11-23 04:51:51 -07:00
marcin mikołajczak
9a063deacc Count and display post quotes 2023-11-12 13:38:08 +00:00
Haelwenn
41f2ee69a8 Merge branch 'from/upstream-develop/tusooa/backup-status' into 'develop'
Detail backup states

Closes #3024

See merge request pleroma/pleroma!3809
2023-06-27 12:08:11 +00:00
tusooa
c5d946bc92
Fix emoji reactions for legacy 2-tuple formats 2023-03-26 15:12:40 -04:00
Alexander Tumin
2c2ea16b50 Allow custom emoji reactions: Add pleroma_custom_emoji_reactions feature, review changes 2023-03-12 11:39:17 +03:00
floatingghost
787e30c5fd Allow reacting with remote emoji when they exist on the post (#200)
Co-authored-by: FloatingGhost <hannah@coffee-and-dreams.uk>
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/200
2023-03-02 11:18:16 +03:00
lain
e853cfe7c3 Revert "Merge branch 'copyright-bump' into 'develop'"
This reverts merge request !3825
2023-01-02 20:38:50 +00:00
marcin mikołajczak
10886eeaa2 Bump copyright year
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-01-01 12:13:06 +01:00
tusooa
070fbb89e1
Lint 2022-12-24 00:04:51 -05:00
tusooa
bdd63d2a3a
Expose backup status via Pleroma API 2022-12-24 00:04:50 -05:00
tusooa
9874b4c985 Merge branch 'develop' into 'from/upstream-develop/tusooa/2892-backup-scope'
# Conflicts:
#   CHANGELOG.md
2022-09-05 15:00:19 +00:00
Tusooa Zhu
a7f01ffc1d
Make backups require its own scope 2022-08-09 00:34:04 -04:00
Tusooa Zhu
8371fd8ca2
Implement settings api 2022-07-16 01:20:25 -04:00
Sean King
17aa3644be
Copyright bump for 2022 2022-02-25 23:11:42 -07:00
marcin mikołajczak
0266bc3c96 Birthdays: hide_birthday -> show_birthday
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2022-01-23 09:13:33 +01:00
marcin mikołajczak
dfb2808535 Birth dates: Add tests
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2022-01-18 23:15:31 +01:00
marcin mikołajczak
397f67fef8 Format code, expose instance configuration related to birth dates
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2022-01-18 18:18:38 +01:00
marcin mikołajczak
b108b05650 Birth dates, birthday reminders API, allow instance admins to require minimum age
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2022-01-18 14:57:48 +01:00
marcin mikołajczak
eedf551eed Add more tests
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2022-01-12 22:41:34 +01:00
marcin mikołajczak
0f90fd5805 WIP account endorsements
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2022-01-12 18:15:10 +01:00
marcin mikołajczak
9032d065e6 wip
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2021-12-28 18:07:19 +01:00
Alex Gleason
f5c3d45120
Merge remote-tracking branch 'origin/develop' into apps-api-endpoint 2021-12-27 18:01:25 -06:00