f9ace00d7e3b1f481a5b429fe28ddc4ccc77eed6
[akkoma] / lib / pleroma / web / admin_api / admin_api_controller.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.AdminAPI.AdminAPIController do
6 use Pleroma.Web, :controller
7 alias Pleroma.Activity
8 alias Pleroma.ModerationLog
9 alias Pleroma.Plugs.OAuthScopesPlug
10 alias Pleroma.User
11 alias Pleroma.UserInviteToken
12 alias Pleroma.Web.ActivityPub.ActivityPub
13 alias Pleroma.Web.ActivityPub.Relay
14 alias Pleroma.Web.ActivityPub.Utils
15 alias Pleroma.Web.AdminAPI.AccountView
16 alias Pleroma.Web.AdminAPI.Config
17 alias Pleroma.Web.AdminAPI.ConfigView
18 alias Pleroma.Web.AdminAPI.ModerationLogView
19 alias Pleroma.Web.AdminAPI.Report
20 alias Pleroma.Web.AdminAPI.ReportView
21 alias Pleroma.Web.AdminAPI.Search
22 alias Pleroma.Web.CommonAPI
23 alias Pleroma.Web.Endpoint
24 alias Pleroma.Web.MastodonAPI.StatusView
25 alias Pleroma.Web.Router
26
27 import Pleroma.Web.ControllerHelper, only: [json_response: 3]
28
29 require Logger
30
31 plug(
32 OAuthScopesPlug,
33 %{scopes: Pleroma.Config.oauth_admin_scopes("read:accounts")}
34 when action in [:list_users, :user_show, :right_get, :invites]
35 )
36
37 plug(
38 OAuthScopesPlug,
39 %{scopes: Pleroma.Config.oauth_admin_scopes("write:accounts")}
40 when action in [
41 :get_invite_token,
42 :revoke_invite,
43 :email_invite,
44 :get_password_reset,
45 :user_follow,
46 :user_unfollow,
47 :user_delete,
48 :users_create,
49 :user_toggle_activation,
50 :user_activate,
51 :user_deactivate,
52 :tag_users,
53 :untag_users,
54 :right_add,
55 :right_delete
56 ]
57 )
58
59 plug(
60 OAuthScopesPlug,
61 %{scopes: Pleroma.Config.oauth_admin_scopes("read:reports")}
62 when action in [:list_reports, :report_show]
63 )
64
65 plug(
66 OAuthScopesPlug,
67 %{scopes: Pleroma.Config.oauth_admin_scopes("write:reports")}
68 when action in [:report_update_state, :report_respond]
69 )
70
71 plug(
72 OAuthScopesPlug,
73 %{scopes: Pleroma.Config.oauth_admin_scopes("read:statuses")}
74 when action == :list_user_statuses
75 )
76
77 plug(
78 OAuthScopesPlug,
79 %{scopes: Pleroma.Config.oauth_admin_scopes("write:statuses")}
80 when action in [:status_update, :status_delete]
81 )
82
83 plug(
84 OAuthScopesPlug,
85 %{scopes: Pleroma.Config.oauth_admin_scopes("read")}
86 when action in [:config_show, :migrate_to_db, :migrate_from_db, :list_log]
87 )
88
89 plug(
90 OAuthScopesPlug,
91 %{scopes: Pleroma.Config.oauth_admin_scopes("write")}
92 when action in [:relay_follow, :relay_unfollow, :config_update]
93 )
94
95 @users_page_size 50
96
97 action_fallback(:errors)
98
99 def user_delete(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
100 user = User.get_cached_by_nickname(nickname)
101 User.delete(user)
102
103 ModerationLog.insert_log(%{
104 actor: admin,
105 subject: [user],
106 action: "delete"
107 })
108
109 conn
110 |> json(nickname)
111 end
112
113 def user_delete(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
114 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
115 User.delete(users)
116
117 ModerationLog.insert_log(%{
118 actor: admin,
119 subject: users,
120 action: "delete"
121 })
122
123 conn
124 |> json(nicknames)
125 end
126
127 def user_follow(%{assigns: %{user: admin}} = conn, %{
128 "follower" => follower_nick,
129 "followed" => followed_nick
130 }) do
131 with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
132 %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
133 User.follow(follower, followed)
134
135 ModerationLog.insert_log(%{
136 actor: admin,
137 followed: followed,
138 follower: follower,
139 action: "follow"
140 })
141 end
142
143 conn
144 |> json("ok")
145 end
146
147 def user_unfollow(%{assigns: %{user: admin}} = conn, %{
148 "follower" => follower_nick,
149 "followed" => followed_nick
150 }) do
151 with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
152 %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
153 User.unfollow(follower, followed)
154
155 ModerationLog.insert_log(%{
156 actor: admin,
157 followed: followed,
158 follower: follower,
159 action: "unfollow"
160 })
161 end
162
163 conn
164 |> json("ok")
165 end
166
167 def users_create(%{assigns: %{user: admin}} = conn, %{"users" => users}) do
168 changesets =
169 Enum.map(users, fn %{"nickname" => nickname, "email" => email, "password" => password} ->
170 user_data = %{
171 nickname: nickname,
172 name: nickname,
173 email: email,
174 password: password,
175 password_confirmation: password,
176 bio: "."
177 }
178
179 User.register_changeset(%User{}, user_data, need_confirmation: false)
180 end)
181 |> Enum.reduce(Ecto.Multi.new(), fn changeset, multi ->
182 Ecto.Multi.insert(multi, Ecto.UUID.generate(), changeset)
183 end)
184
185 case Pleroma.Repo.transaction(changesets) do
186 {:ok, users} ->
187 res =
188 users
189 |> Map.values()
190 |> Enum.map(fn user ->
191 {:ok, user} = User.post_register_action(user)
192
193 user
194 end)
195 |> Enum.map(&AccountView.render("created.json", %{user: &1}))
196
197 ModerationLog.insert_log(%{
198 actor: admin,
199 subjects: Map.values(users),
200 action: "create"
201 })
202
203 conn
204 |> json(res)
205
206 {:error, id, changeset, _} ->
207 res =
208 Enum.map(changesets.operations, fn
209 {current_id, {:changeset, _current_changeset, _}} when current_id == id ->
210 AccountView.render("create-error.json", %{changeset: changeset})
211
212 {_, {:changeset, current_changeset, _}} ->
213 AccountView.render("create-error.json", %{changeset: current_changeset})
214 end)
215
216 conn
217 |> put_status(:conflict)
218 |> json(res)
219 end
220 end
221
222 def user_show(conn, %{"nickname" => nickname}) do
223 with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
224 conn
225 |> put_view(AccountView)
226 |> render("show.json", %{user: user})
227 else
228 _ -> {:error, :not_found}
229 end
230 end
231
232 def list_user_statuses(conn, %{"nickname" => nickname} = params) do
233 godmode = params["godmode"] == "true" || params["godmode"] == true
234
235 with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
236 {_, page_size} = page_params(params)
237
238 activities =
239 ActivityPub.fetch_user_activities(user, nil, %{
240 "limit" => page_size,
241 "godmode" => godmode
242 })
243
244 conn
245 |> put_view(StatusView)
246 |> render("index.json", %{activities: activities, as: :activity})
247 else
248 _ -> {:error, :not_found}
249 end
250 end
251
252 def user_toggle_activation(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
253 user = User.get_cached_by_nickname(nickname)
254
255 {:ok, updated_user} = User.deactivate(user, !user.deactivated)
256
257 action = if user.deactivated, do: "activate", else: "deactivate"
258
259 ModerationLog.insert_log(%{
260 actor: admin,
261 subject: [user],
262 action: action
263 })
264
265 conn
266 |> put_view(AccountView)
267 |> render("show.json", %{user: updated_user})
268 end
269
270 def user_activate(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
271 users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
272 {:ok, updated_users} = User.deactivate(users, false)
273
274 ModerationLog.insert_log(%{
275 actor: admin,
276 subject: users,
277 action: "activate"
278 })
279
280 conn
281 |> put_view(AccountView)
282 |> render("index.json", %{users: Keyword.values(updated_users)})
283 end
284
285 def user_deactivate(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
286 users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
287 {:ok, updated_users} = User.deactivate(users, true)
288
289 ModerationLog.insert_log(%{
290 actor: admin,
291 subject: users,
292 action: "deactivate"
293 })
294
295 conn
296 |> put_view(AccountView)
297 |> render("index.json", %{users: Keyword.values(updated_users)})
298 end
299
300 def tag_users(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do
301 with {:ok, _} <- User.tag(nicknames, tags) do
302 ModerationLog.insert_log(%{
303 actor: admin,
304 nicknames: nicknames,
305 tags: tags,
306 action: "tag"
307 })
308
309 json_response(conn, :no_content, "")
310 end
311 end
312
313 def untag_users(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do
314 with {:ok, _} <- User.untag(nicknames, tags) do
315 ModerationLog.insert_log(%{
316 actor: admin,
317 nicknames: nicknames,
318 tags: tags,
319 action: "untag"
320 })
321
322 json_response(conn, :no_content, "")
323 end
324 end
325
326 def list_users(conn, params) do
327 {page, page_size} = page_params(params)
328 filters = maybe_parse_filters(params["filters"])
329
330 search_params = %{
331 query: params["query"],
332 page: page,
333 page_size: page_size,
334 tags: params["tags"],
335 name: params["name"],
336 email: params["email"]
337 }
338
339 with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)),
340 {:ok, users, count} <- filter_relay_user(users, count),
341 do:
342 conn
343 |> json(
344 AccountView.render("index.json",
345 users: users,
346 count: count,
347 page_size: page_size
348 )
349 )
350 end
351
352 defp filter_relay_user(users, count) do
353 filtered_users = Enum.reject(users, &relay_user?/1)
354 count = if Enum.any?(users, &relay_user?/1), do: length(filtered_users), else: count
355
356 {:ok, filtered_users, count}
357 end
358
359 defp relay_user?(user) do
360 user.ap_id == Relay.relay_ap_id()
361 end
362
363 @filters ~w(local external active deactivated is_admin is_moderator)
364
365 @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
366 defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
367
368 defp maybe_parse_filters(filters) do
369 filters
370 |> String.split(",")
371 |> Enum.filter(&Enum.member?(@filters, &1))
372 |> Enum.map(&String.to_atom(&1))
373 |> Enum.into(%{}, &{&1, true})
374 end
375
376 def right_add_multiple(%{assigns: %{user: admin}} = conn, %{
377 "permission_group" => permission_group,
378 "nicknames" => nicknames
379 })
380 when permission_group in ["moderator", "admin"] do
381 update = %{:"is_#{permission_group}" => true}
382
383 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
384
385 for u <- users, do: User.admin_api_update(u, update)
386
387 ModerationLog.insert_log(%{
388 action: "grant",
389 actor: admin,
390 subject: users,
391 permission: permission_group
392 })
393
394 json(conn, update)
395 end
396
397 def right_add_multiple(conn, _) do
398 render_error(conn, :not_found, "No such permission_group")
399 end
400
401 def right_add(%{assigns: %{user: admin}} = conn, %{
402 "permission_group" => permission_group,
403 "nickname" => nickname
404 })
405 when permission_group in ["moderator", "admin"] do
406 fields = %{:"is_#{permission_group}" => true}
407
408 {:ok, user} =
409 nickname
410 |> User.get_cached_by_nickname()
411 |> User.admin_api_update(fields)
412
413 ModerationLog.insert_log(%{
414 action: "grant",
415 actor: admin,
416 subject: [user],
417 permission: permission_group
418 })
419
420 json(conn, fields)
421 end
422
423 def right_add(conn, _) do
424 render_error(conn, :not_found, "No such permission_group")
425 end
426
427 def right_get(conn, %{"nickname" => nickname}) do
428 user = User.get_cached_by_nickname(nickname)
429
430 conn
431 |> json(%{
432 is_moderator: user.is_moderator,
433 is_admin: user.is_admin
434 })
435 end
436
437 def right_delete_multiple(
438 %{assigns: %{user: %{nickname: admin_nickname} = admin}} = conn,
439 %{
440 "permission_group" => permission_group,
441 "nicknames" => nicknames
442 }
443 )
444 when permission_group in ["moderator", "admin"] do
445 with false <- Enum.member?(nicknames, admin_nickname) do
446 update = %{:"is_#{permission_group}" => false}
447
448 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
449
450 for u <- users, do: User.admin_api_update(u, update)
451
452 ModerationLog.insert_log(%{
453 action: "revoke",
454 actor: admin,
455 subject: users,
456 permission: permission_group
457 })
458
459 json(conn, update)
460 else
461 _ -> render_error(conn, :forbidden, "You can't revoke your own admin/moderator status.")
462 end
463 end
464
465 def right_delete_multiple(conn, _) do
466 render_error(conn, :not_found, "No such permission_group")
467 end
468
469 def right_delete(
470 %{assigns: %{user: admin}} = conn,
471 %{
472 "permission_group" => permission_group,
473 "nickname" => nickname
474 }
475 )
476 when permission_group in ["moderator", "admin"] do
477 fields = %{:"is_#{permission_group}" => false}
478
479 {:ok, user} =
480 nickname
481 |> User.get_cached_by_nickname()
482 |> User.admin_api_update(fields)
483
484 ModerationLog.insert_log(%{
485 action: "revoke",
486 actor: admin,
487 subject: [user],
488 permission: permission_group
489 })
490
491 json(conn, fields)
492 end
493
494 def right_delete(%{assigns: %{user: %{nickname: nickname}}} = conn, %{"nickname" => nickname}) do
495 render_error(conn, :forbidden, "You can't revoke your own admin status.")
496 end
497
498 def relay_list(conn, _params) do
499 with {:ok, list} <- Relay.list() do
500 json(conn, %{relays: list})
501 else
502 _ ->
503 conn
504 |> put_status(500)
505 end
506 end
507
508 def relay_follow(%{assigns: %{user: admin}} = conn, %{"relay_url" => target}) do
509 with {:ok, _message} <- Relay.follow(target) do
510 ModerationLog.insert_log(%{
511 action: "relay_follow",
512 actor: admin,
513 target: target
514 })
515
516 json(conn, target)
517 else
518 _ ->
519 conn
520 |> put_status(500)
521 |> json(target)
522 end
523 end
524
525 def relay_unfollow(%{assigns: %{user: admin}} = conn, %{"relay_url" => target}) do
526 with {:ok, _message} <- Relay.unfollow(target) do
527 ModerationLog.insert_log(%{
528 action: "relay_unfollow",
529 actor: admin,
530 target: target
531 })
532
533 json(conn, target)
534 else
535 _ ->
536 conn
537 |> put_status(500)
538 |> json(target)
539 end
540 end
541
542 @doc "Sends registration invite via email"
543 def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) do
544 with true <-
545 Pleroma.Config.get([:instance, :invites_enabled]) &&
546 !Pleroma.Config.get([:instance, :registrations_open]),
547 {:ok, invite_token} <- UserInviteToken.create_invite(),
548 email <-
549 Pleroma.Emails.UserEmail.user_invitation_email(
550 user,
551 invite_token,
552 email,
553 params["name"]
554 ),
555 {:ok, _} <- Pleroma.Emails.Mailer.deliver(email) do
556 json_response(conn, :no_content, "")
557 end
558 end
559
560 @doc "Create an account registration invite token"
561 def create_invite_token(conn, params) do
562 opts = %{}
563
564 opts =
565 if params["max_use"],
566 do: Map.put(opts, :max_use, params["max_use"]),
567 else: opts
568
569 opts =
570 if params["expires_at"],
571 do: Map.put(opts, :expires_at, params["expires_at"]),
572 else: opts
573
574 {:ok, invite} = UserInviteToken.create_invite(opts)
575
576 json(conn, AccountView.render("invite.json", %{invite: invite}))
577 end
578
579 @doc "Get list of created invites"
580 def invites(conn, _params) do
581 invites = UserInviteToken.list_invites()
582
583 conn
584 |> put_view(AccountView)
585 |> render("invites.json", %{invites: invites})
586 end
587
588 @doc "Revokes invite by token"
589 def revoke_invite(conn, %{"token" => token}) do
590 with {:ok, invite} <- UserInviteToken.find_by_token(token),
591 {:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true}) do
592 conn
593 |> put_view(AccountView)
594 |> render("invite.json", %{invite: updated_invite})
595 else
596 nil -> {:error, :not_found}
597 end
598 end
599
600 @doc "Get a password reset token (base64 string) for given nickname"
601 def get_password_reset(conn, %{"nickname" => nickname}) do
602 (%User{local: true} = user) = User.get_cached_by_nickname(nickname)
603 {:ok, token} = Pleroma.PasswordResetToken.create_token(user)
604
605 conn
606 |> json(%{
607 token: token.token,
608 link: Router.Helpers.reset_password_url(Endpoint, :reset, token.token)
609 })
610 end
611
612 @doc "Force password reset for a given user"
613 def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
614 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
615
616 Enum.map(users, &User.force_password_reset_async/1)
617
618 ModerationLog.insert_log(%{
619 actor: admin,
620 subject: users,
621 action: "force_password_reset"
622 })
623
624 json_response(conn, :no_content, "")
625 end
626
627 def list_reports(conn, params) do
628 {page, page_size} = page_params(params)
629
630 conn
631 |> put_view(ReportView)
632 |> render("index.json", %{reports: Utils.get_reports(params, page, page_size)})
633 end
634
635 def list_grouped_reports(conn, _params) do
636 reports = Utils.get_reported_activities()
637
638 conn
639 |> put_view(ReportView)
640 |> render("index_grouped.json", Utils.get_reports_grouped_by_status(reports))
641 end
642
643 def report_show(conn, %{"id" => id}) do
644 with %Activity{} = report <- Activity.get_by_id(id) do
645 conn
646 |> put_view(ReportView)
647 |> render("show.json", Report.extract_report_info(report))
648 else
649 _ -> {:error, :not_found}
650 end
651 end
652
653 def reports_update(%{assigns: %{user: admin}} = conn, %{"reports" => reports}) do
654 result =
655 reports
656 |> Enum.map(fn report ->
657 with {:ok, activity} <- CommonAPI.update_report_state(report["id"], report["state"]) do
658 ModerationLog.insert_log(%{
659 action: "report_update",
660 actor: admin,
661 subject: activity
662 })
663
664 activity
665 else
666 {:error, message} -> %{id: report["id"], error: message}
667 end
668 end)
669
670 case Enum.any?(result, &Map.has_key?(&1, :error)) do
671 true -> json_response(conn, :bad_request, result)
672 false -> json_response(conn, :no_content, "")
673 end
674 end
675
676 def report_respond(%{assigns: %{user: user}} = conn, %{"id" => id} = params) do
677 with false <- is_nil(params["status"]),
678 %Activity{} <- Activity.get_by_id(id) do
679 params =
680 params
681 |> Map.put("in_reply_to_status_id", id)
682 |> Map.put("visibility", "direct")
683
684 {:ok, activity} = CommonAPI.post(user, params)
685
686 ModerationLog.insert_log(%{
687 action: "report_response",
688 actor: user,
689 subject: activity,
690 text: params["status"]
691 })
692
693 conn
694 |> put_view(StatusView)
695 |> render("show.json", %{activity: activity})
696 else
697 true ->
698 {:param_cast, nil}
699
700 nil ->
701 {:error, :not_found}
702 end
703 end
704
705 def status_update(%{assigns: %{user: admin}} = conn, %{"id" => id} = params) do
706 with {:ok, activity} <- CommonAPI.update_activity_scope(id, params) do
707 {:ok, sensitive} = Ecto.Type.cast(:boolean, params["sensitive"])
708
709 ModerationLog.insert_log(%{
710 action: "status_update",
711 actor: admin,
712 subject: activity,
713 sensitive: sensitive,
714 visibility: params["visibility"]
715 })
716
717 conn
718 |> put_view(StatusView)
719 |> render("show.json", %{activity: activity})
720 end
721 end
722
723 def status_delete(%{assigns: %{user: user}} = conn, %{"id" => id}) do
724 with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
725 ModerationLog.insert_log(%{
726 action: "status_delete",
727 actor: user,
728 subject_id: id
729 })
730
731 json(conn, %{})
732 end
733 end
734
735 def list_log(conn, params) do
736 {page, page_size} = page_params(params)
737
738 log =
739 ModerationLog.get_all(%{
740 page: page,
741 page_size: page_size,
742 start_date: params["start_date"],
743 end_date: params["end_date"],
744 user_id: params["user_id"],
745 search: params["search"]
746 })
747
748 conn
749 |> put_view(ModerationLogView)
750 |> render("index.json", %{log: log})
751 end
752
753 def migrate_to_db(conn, _params) do
754 Mix.Tasks.Pleroma.Config.run(["migrate_to_db"])
755 json(conn, %{})
756 end
757
758 def migrate_from_db(conn, _params) do
759 Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env), "true"])
760 json(conn, %{})
761 end
762
763 def config_show(conn, _params) do
764 configs = Pleroma.Repo.all(Config)
765
766 conn
767 |> put_view(ConfigView)
768 |> render("index.json", %{configs: configs})
769 end
770
771 def config_update(conn, %{"configs" => configs}) do
772 updated =
773 if Pleroma.Config.get([:instance, :dynamic_configuration]) do
774 updated =
775 Enum.map(configs, fn
776 %{"group" => group, "key" => key, "delete" => "true"} = params ->
777 {:ok, config} = Config.delete(%{group: group, key: key, subkeys: params["subkeys"]})
778 config
779
780 %{"group" => group, "key" => key, "value" => value} ->
781 {:ok, config} = Config.update_or_create(%{group: group, key: key, value: value})
782 config
783 end)
784 |> Enum.reject(&is_nil(&1))
785
786 Pleroma.Config.TransferTask.load_and_update_env()
787 Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env), "false"])
788 updated
789 else
790 []
791 end
792
793 conn
794 |> put_view(ConfigView)
795 |> render("index.json", %{configs: updated})
796 end
797
798 def reload_emoji(conn, _params) do
799 Pleroma.Emoji.reload()
800
801 conn |> json("ok")
802 end
803
804 def errors(conn, {:error, :not_found}) do
805 conn
806 |> put_status(:not_found)
807 |> json(dgettext("errors", "Not found"))
808 end
809
810 def errors(conn, {:error, reason}) do
811 conn
812 |> put_status(:bad_request)
813 |> json(reason)
814 end
815
816 def errors(conn, {:param_cast, _}) do
817 conn
818 |> put_status(:bad_request)
819 |> json(dgettext("errors", "Invalid parameters"))
820 end
821
822 def errors(conn, _) do
823 conn
824 |> put_status(:internal_server_error)
825 |> json(dgettext("errors", "Something went wrong"))
826 end
827
828 defp page_params(params) do
829 {get_page(params["page"]), get_page_size(params["page_size"])}
830 end
831
832 defp get_page(page_string) when is_nil(page_string), do: 1
833
834 defp get_page(page_string) do
835 case Integer.parse(page_string) do
836 {page, _} -> page
837 :error -> 1
838 end
839 end
840
841 defp get_page_size(page_size_string) when is_nil(page_size_string), do: @users_page_size
842
843 defp get_page_size(page_size_string) do
844 case Integer.parse(page_size_string) do
845 {page_size, _} -> page_size
846 :error -> @users_page_size
847 end
848 end
849 end