forked from mirrors/pronouns.cc
feat: add hidden member list
This commit is contained in:
parent
8433a1523a
commit
5bdb25866c
5 changed files with 58 additions and 4 deletions
|
@ -19,9 +19,10 @@ type memberListResponse struct {
|
||||||
Links []string `json:"links"`
|
Links []string `json:"links"`
|
||||||
Names []db.FieldEntry `json:"names"`
|
Names []db.FieldEntry `json:"names"`
|
||||||
Pronouns []db.PronounEntry `json:"pronouns"`
|
Pronouns []db.PronounEntry `json:"pronouns"`
|
||||||
|
Unlisted bool `json:"unlisted"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func membersToMemberList(ms []db.Member) []memberListResponse {
|
func membersToMemberList(ms []db.Member, isSelf bool) []memberListResponse {
|
||||||
resps := make([]memberListResponse, len(ms))
|
resps := make([]memberListResponse, len(ms))
|
||||||
for i := range ms {
|
for i := range ms {
|
||||||
resps[i] = memberListResponse{
|
resps[i] = memberListResponse{
|
||||||
|
@ -33,6 +34,10 @@ func membersToMemberList(ms []db.Member) []memberListResponse {
|
||||||
Names: db.NotNull(ms[i].Names),
|
Names: db.NotNull(ms[i].Names),
|
||||||
Pronouns: db.NotNull(ms[i].Pronouns),
|
Pronouns: db.NotNull(ms[i].Pronouns),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isSelf {
|
||||||
|
resps[i].Unlisted = ms[i].Unlisted
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return resps
|
return resps
|
||||||
|
@ -66,7 +71,7 @@ func (s *Server) getUserMembers(w http.ResponseWriter, r *http.Request) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
render.JSON(w, r, membersToMemberList(ms))
|
render.JSON(w, r, membersToMemberList(ms, isSelf))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +84,6 @@ func (s *Server) getMeMembers(w http.ResponseWriter, r *http.Request) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
render.JSON(w, r, membersToMemberList(ms))
|
render.JSON(w, r, membersToMemberList(ms, true))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
import { apiFetchClient } from "$lib/api/fetch";
|
import { apiFetchClient } from "$lib/api/fetch";
|
||||||
import ErrorAlert from "$lib/components/ErrorAlert.svelte";
|
import ErrorAlert from "$lib/components/ErrorAlert.svelte";
|
||||||
import { goto } from "$app/navigation";
|
import { goto } from "$app/navigation";
|
||||||
import {renderMarkdown} from "$lib/utils"
|
import { renderMarkdown } from "$lib/utils";
|
||||||
import ReportButton from "./ReportButton.svelte";
|
import ReportButton from "./ReportButton.svelte";
|
||||||
import ProfileLink from "./ProfileLink.svelte";
|
import ProfileLink from "./ProfileLink.svelte";
|
||||||
import { memberNameRegex } from "$lib/api/regex";
|
import { memberNameRegex } from "$lib/api/regex";
|
||||||
|
@ -212,6 +212,9 @@
|
||||||
You don't have any members yet.
|
You don't have any members yet.
|
||||||
<br />
|
<br />
|
||||||
Members are sub-profiles that can have their own avatar, names, pronouns, and preferred terms.
|
Members are sub-profiles that can have their own avatar, names, pronouns, and preferred terms.
|
||||||
|
<br />
|
||||||
|
If you were expecting to see members here, check your
|
||||||
|
<a href="/settings/members">list of hidden members</a>.
|
||||||
<span class="text-muted">(only you can see this)</span>
|
<span class="text-muted">(only you can see this)</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -31,6 +31,9 @@
|
||||||
|
|
||||||
let unreadWarnings: number;
|
let unreadWarnings: number;
|
||||||
$: unreadWarnings = data.warnings.filter((w) => !w.read).length;
|
$: unreadWarnings = data.warnings.filter((w) => !w.read).length;
|
||||||
|
|
||||||
|
let hasHiddenMembers: boolean;
|
||||||
|
$: hasHiddenMembers = data.user.list_private || data.members.some((m) => m.unlisted);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
@ -53,6 +56,15 @@
|
||||||
>
|
>
|
||||||
Authentication
|
Authentication
|
||||||
</ListGroupItem>
|
</ListGroupItem>
|
||||||
|
<!--{#if hasHiddenMembers}-->
|
||||||
|
<ListGroupItem
|
||||||
|
tag="a"
|
||||||
|
active={$page.url.pathname === "/settings/members"}
|
||||||
|
href="/settings/members"
|
||||||
|
>
|
||||||
|
Hidden members
|
||||||
|
</ListGroupItem>
|
||||||
|
<!--{/if}-->
|
||||||
{#if data.invitesEnabled}
|
{#if data.invitesEnabled}
|
||||||
<ListGroupItem
|
<ListGroupItem
|
||||||
tag="a"
|
tag="a"
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {
|
||||||
type APIError,
|
type APIError,
|
||||||
type Invite,
|
type Invite,
|
||||||
type MeUser,
|
type MeUser,
|
||||||
|
type Member,
|
||||||
} from "$lib/api/entities";
|
} from "$lib/api/entities";
|
||||||
import { apiFetchClient } from "$lib/api/fetch";
|
import { apiFetchClient } from "$lib/api/fetch";
|
||||||
import { redirect } from "@sveltejs/kit";
|
import { redirect } from "@sveltejs/kit";
|
||||||
|
@ -14,6 +15,7 @@ export const ssr = false;
|
||||||
export const load = (async ({ parent }) => {
|
export const load = (async ({ parent }) => {
|
||||||
try {
|
try {
|
||||||
const user = await apiFetchClient<MeUser>("/users/@me");
|
const user = await apiFetchClient<MeUser>("/users/@me");
|
||||||
|
const members = await apiFetchClient<Member[]>("/users/@me/members");
|
||||||
const warnings = await apiFetchClient<Warning[]>("/auth/warnings?all=true");
|
const warnings = await apiFetchClient<Warning[]>("/auth/warnings?all=true");
|
||||||
|
|
||||||
let invites: Invite[] = [];
|
let invites: Invite[] = [];
|
||||||
|
@ -31,6 +33,7 @@ export const load = (async ({ parent }) => {
|
||||||
return {
|
return {
|
||||||
...data,
|
...data,
|
||||||
user,
|
user,
|
||||||
|
members,
|
||||||
invites,
|
invites,
|
||||||
invitesEnabled,
|
invitesEnabled,
|
||||||
warnings,
|
warnings,
|
||||||
|
|
31
frontend/src/routes/settings/members/+page.svelte
Normal file
31
frontend/src/routes/settings/members/+page.svelte
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import type { Member } from "$lib/api/entities";
|
||||||
|
import { Alert, ListGroup, ListGroupItem } from "sveltestrap";
|
||||||
|
import type { PageData } from "./$types";
|
||||||
|
|
||||||
|
export let data: PageData;
|
||||||
|
|
||||||
|
let members: Member[];
|
||||||
|
$: members = data.user.list_private ? data.members : data.members.filter((m) => m.unlisted);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1>Hidden members ({members.length})</h1>
|
||||||
|
|
||||||
|
{#if data.user.list_private}
|
||||||
|
<Alert color="secondary" fade={false}>
|
||||||
|
Note that your member list is hidden, so <em>all</em> of your members are shown here.
|
||||||
|
</Alert>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if members.length > 0}
|
||||||
|
<ListGroup>
|
||||||
|
{#each members as member}
|
||||||
|
<ListGroupItem tag="a" href="/@{data.user.name}/{member.name}">
|
||||||
|
<strong>{member.display_name ?? member.name}</strong>
|
||||||
|
<span class="text-body-secondary">({member.name})</span>
|
||||||
|
</ListGroupItem>
|
||||||
|
{/each}
|
||||||
|
</ListGroup>
|
||||||
|
{:else}
|
||||||
|
<Alert color="secondary" fade={false}>You have no unlisted members!</Alert>
|
||||||
|
{/if}
|
Loading…
Reference in a new issue