diff --git a/backend/routes/auth/discord.go b/backend/routes/auth/discord.go index 63a08c1..f0f37c7 100644 --- a/backend/routes/auth/discord.go +++ b/backend/routes/auth/discord.go @@ -43,8 +43,10 @@ type discordCallbackResponse struct { Ticket string `json:"ticket,omitempty"` RequireInvite bool `json:"require_invite"` // require an invite for signing up - IsDeleted bool `json:"is_deleted"` - DeletedAt *time.Time `json:"deleted_at,omitempty"` + IsDeleted bool `json:"is_deleted"` + DeletedAt *time.Time `json:"deleted_at,omitempty"` + SelfDelete *bool `json:"self_delete,omitempty"` + DeleteReason *string `json:"delete_reason,omitempty"` } func (s *Server) discordCallback(w http.ResponseWriter, r *http.Request) error { @@ -81,7 +83,7 @@ func (s *Server) discordCallback(w http.ResponseWriter, r *http.Request) error { u, err := s.DB.DiscordUser(ctx, du.ID) if err == nil { - if u.DeletedAt != nil && *u.SelfDelete { + if u.DeletedAt != nil { // store cancel delete token token := undeleteToken() err = s.saveUndeleteToken(ctx, u.ID, token) @@ -91,11 +93,13 @@ func (s *Server) discordCallback(w http.ResponseWriter, r *http.Request) error { } render.JSON(w, r, discordCallbackResponse{ - HasAccount: true, - Token: token, - User: dbUserToUserResponse(u, []db.Field{}), - IsDeleted: true, - DeletedAt: u.DeletedAt, + HasAccount: true, + Token: token, + User: dbUserToUserResponse(u, []db.Field{}), + IsDeleted: true, + DeletedAt: u.DeletedAt, + SelfDelete: u.SelfDelete, + DeleteReason: u.DeleteReason, }) return nil } diff --git a/backend/routes/auth/fedi_mastodon.go b/backend/routes/auth/fedi_mastodon.go index 581fa32..0f40d4d 100644 --- a/backend/routes/auth/fedi_mastodon.go +++ b/backend/routes/auth/fedi_mastodon.go @@ -31,8 +31,10 @@ type fediCallbackResponse struct { Ticket string `json:"ticket,omitempty"` RequireInvite bool `json:"require_invite"` // require an invite for signing up - IsDeleted bool `json:"is_deleted"` - DeletedAt *time.Time `json:"deleted_at,omitempty"` + IsDeleted bool `json:"is_deleted"` + DeletedAt *time.Time `json:"deleted_at,omitempty"` + SelfDelete *bool `json:"self_delete,omitempty"` + DeleteReason *string `json:"delete_reason,omitempty"` } type partialMastodonAccount struct { @@ -102,7 +104,7 @@ func (s *Server) mastodonCallback(w http.ResponseWriter, r *http.Request) error u, err := s.DB.FediverseUser(ctx, mu.ID, app.ID) if err == nil { - if u.DeletedAt != nil && *u.SelfDelete { + if u.DeletedAt != nil { // store cancel delete token token := undeleteToken() err = s.saveUndeleteToken(ctx, u.ID, token) @@ -112,11 +114,13 @@ func (s *Server) mastodonCallback(w http.ResponseWriter, r *http.Request) error } render.JSON(w, r, fediCallbackResponse{ - HasAccount: true, - Token: token, - User: dbUserToUserResponse(u, []db.Field{}), - IsDeleted: true, - DeletedAt: u.DeletedAt, + HasAccount: true, + Token: token, + User: dbUserToUserResponse(u, []db.Field{}), + IsDeleted: true, + DeletedAt: u.DeletedAt, + SelfDelete: u.SelfDelete, + DeleteReason: u.DeleteReason, }) return nil } diff --git a/backend/routes/auth/undelete.go b/backend/routes/auth/undelete.go index 236b4ce..6bc2314 100644 --- a/backend/routes/auth/undelete.go +++ b/backend/routes/auth/undelete.go @@ -27,6 +27,16 @@ func (s *Server) cancelDelete(w http.ResponseWriter, r *http.Request) error { return server.APIError{Code: server.ErrNotFound} // assume invalid token } + // only self deleted users can undelete themselves + u, err := s.DB.User(ctx, id) + if err != nil { + log.Errorf("getting user: %v", err) + return errors.Wrap(err, "getting user") + } + if !*u.SelfDelete { + return server.APIError{Code: server.ErrForbidden} + } + err = s.DB.UndoDeleteUser(ctx, id) if err != nil { log.Errorf("executing undelete query: %v", err) diff --git a/backend/routes/mod/resolve_report.go b/backend/routes/mod/resolve_report.go index f9a91a9..bf7730c 100644 --- a/backend/routes/mod/resolve_report.go +++ b/backend/routes/mod/resolve_report.go @@ -77,6 +77,11 @@ func (s *Server) resolveReport(w http.ResponseWriter, r *http.Request) error { } if req.Delete { + err = s.DB.InvalidateAllTokens(ctx, tx, report.UserID) + if err != nil { + return errors.Wrap(err, "invalidating tokens") + } + err = s.DB.CleanUser(ctx, report.UserID) if err != nil { log.Errorf("cleaning user data: %v", err) diff --git a/frontend/src/routes/auth/login/CallbackPage.svelte b/frontend/src/routes/auth/login/CallbackPage.svelte index b20f111..efc80a0 100644 --- a/frontend/src/routes/auth/login/CallbackPage.svelte +++ b/frontend/src/routes/auth/login/CallbackPage.svelte @@ -5,6 +5,7 @@ import ErrorAlert from "$lib/components/ErrorAlert.svelte"; import { userStore } from "$lib/store"; import { addToast } from "$lib/toast"; + import { DateTime } from "luxon"; import { onMount } from "svelte"; import { Alert, @@ -26,6 +27,8 @@ export let token: string | undefined; export let user: MeUser | undefined; export let deletedAt: string | undefined; + export let selfDelete: boolean | undefined; + export let deleteReason: string | undefined; onMount(() => { if (!isDeleted && token && user) { @@ -136,8 +139,12 @@ -{:else if isDeleted && token} -

Your account is pending deletion since {deletedAt}.

+{:else if isDeleted && token && selfDelete && deletedAt} +

+ Your account is pending deletion since {DateTime.fromISO(deletedAt) + .toLocal() + .toLocaleString(DateTime.DATETIME_MED)}. +

If you wish to cancel deletion, press the button below.

- - -

- If you want to delete your account, type your username below: -
- - This is irreversible! Your account cannot be recovered after you press "Force delete - account". - -

-

- -

- {#if deleteError} - - {/if} -
- - - - -
{#if deleteCancelled} Account deletion cancelled! You can now log in again. @@ -188,6 +167,50 @@ {#if deleteError} {/if} +{:else if isDeleted && token && !selfDelete && deletedAt} +

+ Your account is pending deletion since {DateTime.fromISO(deletedAt) + .toLocal() + .toLocaleString(DateTime.DATETIME_MED)}. +

+

+ Your account was deactivated by a moderator. You cannot cancel deletion. The moderator + gave the following reason: +

+
+ {deleteReason} +
+

+ Your account will be fully deleted 180 days after being deactivated. If you want your data wiped + immediately instead, press the force delete link below. +

+

+ +

{:else} Loading... {/if} + + + +

+ If you want to delete your account, type your username ({user.name}) below: +
+ + This is irreversible! Your account cannot be recovered after you press "Force delete account". + +

+

+ +

+ {#if deleteError} + + {/if} +
+ + + + +
diff --git a/frontend/src/routes/auth/login/discord/+page.server.ts b/frontend/src/routes/auth/login/discord/+page.server.ts index 5e66447..b1df685 100644 --- a/frontend/src/routes/auth/login/discord/+page.server.ts +++ b/frontend/src/routes/auth/login/discord/+page.server.ts @@ -33,4 +33,6 @@ interface CallbackResponse { is_deleted: boolean; deleted_at?: string; + self_delete?: boolean; + delete_reason?: string; } diff --git a/frontend/src/routes/auth/login/discord/+page.svelte b/frontend/src/routes/auth/login/discord/+page.svelte index 5cd3926..e7336ec 100644 --- a/frontend/src/routes/auth/login/discord/+page.svelte +++ b/frontend/src/routes/auth/login/discord/+page.svelte @@ -57,6 +57,8 @@ token={data.token} user={data.user} deletedAt={data.deleted_at} + selfDelete={data.self_delete} + deleteReason={data.delete_reason} {linkAccount} {signupForm} /> diff --git a/frontend/src/routes/auth/login/mastodon/[instance]/+page.server.ts b/frontend/src/routes/auth/login/mastodon/[instance]/+page.server.ts index 36d5220..f4e3c1c 100644 --- a/frontend/src/routes/auth/login/mastodon/[instance]/+page.server.ts +++ b/frontend/src/routes/auth/login/mastodon/[instance]/+page.server.ts @@ -33,4 +33,6 @@ interface CallbackResponse { is_deleted: boolean; deleted_at?: string; + self_delete?: boolean; + delete_reason?: string; } diff --git a/frontend/src/routes/auth/login/mastodon/[instance]/+page.svelte b/frontend/src/routes/auth/login/mastodon/[instance]/+page.svelte index 596f727..4570320 100644 --- a/frontend/src/routes/auth/login/mastodon/[instance]/+page.svelte +++ b/frontend/src/routes/auth/login/mastodon/[instance]/+page.svelte @@ -59,6 +59,8 @@ token={data.token} user={data.user} deletedAt={data.deleted_at} + selfDelete={data.self_delete} + deleteReason={data.delete_reason} {linkAccount} {signupForm} /> diff --git a/frontend/src/routes/reports/+page.svelte b/frontend/src/routes/reports/+page.svelte index 1fc6262..5d0e44f 100644 --- a/frontend/src/routes/reports/+page.svelte +++ b/frontend/src/routes/reports/+page.svelte @@ -48,14 +48,16 @@
{#each data.reports as report, index} - - • - - - - +
+ + • + + + + +
{/each}