feat: add mod action notice to login page
This commit is contained in:
parent
f02e64fca7
commit
ab77fab0ea
10 changed files with 110 additions and 54 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 @@
|
|||
</div>
|
||||
<Button type="submit" color="primary">Sign up</Button>
|
||||
</form>
|
||||
{:else if isDeleted && token}
|
||||
<p>Your account is pending deletion since {deletedAt}.</p>
|
||||
{:else if isDeleted && token && selfDelete && deletedAt}
|
||||
<p>
|
||||
Your account is pending deletion since {DateTime.fromISO(deletedAt)
|
||||
.toLocal()
|
||||
.toLocaleString(DateTime.DATETIME_MED)}.
|
||||
</p>
|
||||
<p>If you wish to cancel deletion, press the button below.</p>
|
||||
<p>
|
||||
<Button color="primary" on:click={cancelDelete} disabled={deleteCancelled}
|
||||
|
@ -152,34 +159,6 @@
|
|||
<p>
|
||||
<Button color="link" on:click={toggleForceDeleteModal}>Force delete account</Button>
|
||||
</p>
|
||||
<Modal
|
||||
header="Force delete account"
|
||||
isOpen={forceDeleteModalOpen}
|
||||
toggle={toggleForceDeleteModal}
|
||||
>
|
||||
<ModalBody>
|
||||
<p>
|
||||
If you want to delete your account, type your username below:
|
||||
<br />
|
||||
<b>
|
||||
This is irreversible! Your account <i>cannot</i> be recovered after you press "Force delete
|
||||
account".
|
||||
</b>
|
||||
</p>
|
||||
<p>
|
||||
<input type="text" class="form-control" bind:value={forceDeleteName} />
|
||||
</p>
|
||||
{#if deleteError}
|
||||
<ErrorAlert error={deleteError} />
|
||||
{/if}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="danger" on:click={forceDeleteAccount} disabled={forceDeleteName !== user?.name}
|
||||
>Force delete account</Button
|
||||
>
|
||||
<Button color="secondary" on:click={toggleForceDeleteModal}>Cancel delete</Button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
{#if deleteCancelled}
|
||||
<Alert color="secondary" fade={false}>
|
||||
Account deletion cancelled! You can now <a href="/auth/login">log in</a> again.
|
||||
|
@ -188,6 +167,50 @@
|
|||
{#if deleteError}
|
||||
<ErrorAlert error={deleteError} />
|
||||
{/if}
|
||||
{:else if isDeleted && token && !selfDelete && deletedAt}
|
||||
<p>
|
||||
Your account is pending deletion since {DateTime.fromISO(deletedAt)
|
||||
.toLocal()
|
||||
.toLocaleString(DateTime.DATETIME_MED)}.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Your account was deactivated by a moderator.</strong> You cannot cancel deletion. The moderator
|
||||
gave the following reason:
|
||||
</p>
|
||||
<blockquote class="blockquote">
|
||||
{deleteReason}
|
||||
</blockquote>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
<Button color="link" on:click={toggleForceDeleteModal}>Force delete account</Button>
|
||||
</p>
|
||||
{:else}
|
||||
Loading...
|
||||
{/if}
|
||||
|
||||
<Modal header="Force delete account" isOpen={forceDeleteModalOpen} toggle={toggleForceDeleteModal}>
|
||||
<ModalBody>
|
||||
<p>
|
||||
If you want to delete your account, type your username (<code>{user.name}</code>) below:
|
||||
<br />
|
||||
<b>
|
||||
This is irreversible! Your account <i>cannot</i> be recovered after you press "Force delete account".
|
||||
</b>
|
||||
</p>
|
||||
<p>
|
||||
<input type="text" class="form-control" bind:value={forceDeleteName} />
|
||||
</p>
|
||||
{#if deleteError}
|
||||
<ErrorAlert error={deleteError} />
|
||||
{/if}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="danger" on:click={forceDeleteAccount} disabled={forceDeleteName !== user?.name}
|
||||
>Force delete account</Button
|
||||
>
|
||||
<Button color="secondary" on:click={toggleForceDeleteModal}>Cancel delete</Button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
|
|
|
@ -33,4 +33,6 @@ interface CallbackResponse {
|
|||
|
||||
is_deleted: boolean;
|
||||
deleted_at?: string;
|
||||
self_delete?: boolean;
|
||||
delete_reason?: string;
|
||||
}
|
||||
|
|
|
@ -57,6 +57,8 @@
|
|||
token={data.token}
|
||||
user={data.user}
|
||||
deletedAt={data.deleted_at}
|
||||
selfDelete={data.self_delete}
|
||||
deleteReason={data.delete_reason}
|
||||
{linkAccount}
|
||||
{signupForm}
|
||||
/>
|
||||
|
|
|
@ -33,4 +33,6 @@ interface CallbackResponse {
|
|||
|
||||
is_deleted: boolean;
|
||||
deleted_at?: string;
|
||||
self_delete?: boolean;
|
||||
delete_reason?: string;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@
|
|||
token={data.token}
|
||||
user={data.user}
|
||||
deletedAt={data.deleted_at}
|
||||
selfDelete={data.self_delete}
|
||||
deleteReason={data.delete_reason}
|
||||
{linkAccount}
|
||||
{signupForm}
|
||||
/>
|
||||
|
|
|
@ -48,14 +48,16 @@
|
|||
|
||||
<div>
|
||||
{#each data.reports as report, index}
|
||||
<ReportCard {report}>
|
||||
•
|
||||
<Button outline color="warning" size="sm" on:click={() => openWarnModalFor(index)}
|
||||
>Warn user</Button
|
||||
>
|
||||
<Button outline color="danger" size="sm">Deactivate user</Button>
|
||||
<Button outline color="secondary" size="sm">Ignore report</Button>
|
||||
</ReportCard>
|
||||
<div class="my-2">
|
||||
<ReportCard {report}>
|
||||
•
|
||||
<Button outline color="warning" size="sm" on:click={() => openWarnModalFor(index)}
|
||||
>Warn user</Button
|
||||
>
|
||||
<Button outline color="danger" size="sm">Deactivate user</Button>
|
||||
<Button outline color="secondary" size="sm">Ignore report</Button>
|
||||
</ReportCard>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
|
|
Loading…
Reference in a new issue