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