This commit is contained in:
1 parent
5d52405353
commit
b40665c2d7
12 files changed
+200
-112
No files matched your search
@@ -87,6 +87,9 @@ export const signup = {
|
|||||||
if (input.code) {
|
if (input.code) {
|
||||||
await tx.setDirectSignupUser({ code: input.code, userId: user.id });
|
await tx.setDirectSignupUser({ code: input.code, userId: user.id });
|
||||||
}
|
}
|
||||||
|
if (uuid) {
|
||||||
|
await tx.linkDirectSignupUserByUuid({ uuid: uuid, userId: user.id });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
sendWebhook(WebhookAction.Signup, {
|
sendWebhook(WebhookAction.Signup, {
|
||||||
|
|||||||
+27
-2
@@ -35,6 +35,10 @@ export const user = {
|
|||||||
uuid: input.uuid
|
uuid: input.uuid
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (input.uuid) {
|
||||||
|
await db.linkDirectSignupUserByUuid({ uuid: input.uuid, userId: id });
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: id
|
id: id
|
||||||
};
|
};
|
||||||
@@ -146,10 +150,31 @@ export const user = {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
addDirectInvitation: defineAction({
|
addDirectInvitation: defineAction({
|
||||||
handler: async (_, context) => {
|
input: z
|
||||||
|
.object({
|
||||||
|
uuid: z.string().nullable(),
|
||||||
|
comment: z.string().nullable()
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
handler: async (input, context) => {
|
||||||
Session.actionSessionFromCookies(context.cookies, Permissions.Users);
|
Session.actionSessionFromCookies(context.cookies, Permissions.Users);
|
||||||
|
|
||||||
return await db.addDirectSignup({});
|
return await db.addDirectSignup({
|
||||||
|
uuid: input?.uuid ?? null,
|
||||||
|
comment: input?.comment ?? null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
editDirectInvitation: defineAction({
|
||||||
|
input: z.object({
|
||||||
|
code: z.string(),
|
||||||
|
uuid: z.string().nullable(),
|
||||||
|
comment: z.string().nullable()
|
||||||
|
}),
|
||||||
|
handler: async (input, context) => {
|
||||||
|
Session.actionSessionFromCookies(context.cookies, Permissions.Users);
|
||||||
|
|
||||||
|
await db.editDirectSignup(input);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
deleteDirectInvitation: defineAction({
|
deleteDirectInvitation: defineAction({
|
||||||
|
|||||||
@@ -1,13 +1,38 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import DataTable from '@components/admin/table/DataTable.svelte';
|
import DataTable from '@components/admin/table/DataTable.svelte';
|
||||||
|
import CrudPopup from '@components/admin/popup/CrudPopup.svelte';
|
||||||
import { confirmPopupState } from '@components/popup/ConfirmPopup.ts';
|
import { confirmPopupState } from '@components/popup/ConfirmPopup.ts';
|
||||||
import {
|
import {
|
||||||
deleteDirectInvitation,
|
deleteDirectInvitation,
|
||||||
|
editDirectInvitation,
|
||||||
type DirectInvitation,
|
type DirectInvitation,
|
||||||
directInvitations
|
directInvitations
|
||||||
} from '@app/admin/directInvitations/directInvitations.ts';
|
} from '@app/admin/directInvitations/directInvitations.ts';
|
||||||
|
|
||||||
// callback
|
// state
|
||||||
|
let directInvitationEditPopupDirectInvitation = $state(null);
|
||||||
|
let directInvitationEditPopupOpen = $derived(!!directInvitationEditPopupDirectInvitation);
|
||||||
|
let copiedCode = $state<string | null>(null);
|
||||||
|
|
||||||
|
// lifecycle
|
||||||
|
$effect(() => {
|
||||||
|
if (!directInvitationEditPopupOpen) directInvitationEditPopupDirectInvitation = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
// callbacks
|
||||||
|
async function copyLink(directInvitation: DirectInvitation) {
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(directInvitation.url);
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
copiedCode = directInvitation.code;
|
||||||
|
setTimeout(() => {
|
||||||
|
if (copiedCode === directInvitation.code) copiedCode = null;
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
function onDirectInvitationDelete(directInvitation: DirectInvitation) {
|
function onDirectInvitationDelete(directInvitation: DirectInvitation) {
|
||||||
$confirmPopupState = {
|
$confirmPopupState = {
|
||||||
title: 'Direkte Einladung löschen?',
|
title: 'Direkte Einladung löschen?',
|
||||||
@@ -21,8 +46,46 @@
|
|||||||
data={directInvitations}
|
data={directInvitations}
|
||||||
count={true}
|
count={true}
|
||||||
keys={[
|
keys={[
|
||||||
{ key: 'url', label: 'Link' },
|
{ key: 'code', label: 'Code', sortable: true, transform: codeTransform },
|
||||||
|
{ key: 'uuid', label: 'UUID', sortable: true },
|
||||||
|
{ key: 'comment', label: 'Kommentar' },
|
||||||
{ key: 'user.username', label: 'Registrierter Nutzer', sortable: true }
|
{ key: 'user.username', label: 'Registrierter Nutzer', sortable: true }
|
||||||
]}
|
]}
|
||||||
|
onEdit={(directInvitation) => (directInvitationEditPopupDirectInvitation = directInvitation)}
|
||||||
onDelete={onDirectInvitationDelete}
|
onDelete={onDirectInvitationDelete}
|
||||||
|
>
|
||||||
|
{#snippet codeTransform(code: string)}
|
||||||
|
<span class="font-mono text-xs">{code}</span>
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
|
{#snippet extraActions(directInvitation)}
|
||||||
|
<button
|
||||||
|
class="cursor-pointer"
|
||||||
|
title={copiedCode === directInvitation.code ? 'Link kopiert' : 'Link kopieren'}
|
||||||
|
onclick={() => copyLink(directInvitation)}
|
||||||
|
>
|
||||||
|
{#if copiedCode === directInvitation.code}
|
||||||
|
<span class="iconify iconify-[heroicons--clipboard-document-check]"></span>
|
||||||
|
{:else}
|
||||||
|
<span class="iconify iconify-[heroicons--clipboard]"></span>
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
{/snippet}
|
||||||
|
</DataTable>
|
||||||
|
|
||||||
|
<CrudPopup
|
||||||
|
texts={{
|
||||||
|
title: 'Direkte Einladung bearbeiten',
|
||||||
|
submitButtonTitle: 'Speichern',
|
||||||
|
confirmPopupTitle: 'Änderungen speichern',
|
||||||
|
confirmPopupMessage: 'Sollen die Änderungen gespeichert werden?'
|
||||||
|
}}
|
||||||
|
target={directInvitationEditPopupDirectInvitation}
|
||||||
|
keys={[
|
||||||
|
[{ key: 'code', type: 'text', label: 'Code', options: { required: true, readonly: true, dynamicWidth: true } }],
|
||||||
|
[{ key: 'uuid', type: 'text', label: 'UUID', options: { dynamicWidth: true } }],
|
||||||
|
[{ key: 'comment', type: 'textarea', label: 'Kommentar', options: { dynamicWidth: true } }]
|
||||||
|
]}
|
||||||
|
onSubmit={editDirectInvitation}
|
||||||
|
bind:open={directInvitationEditPopupOpen}
|
||||||
/>
|
/>
|
||||||
@@ -26,6 +26,10 @@
|
|||||||
confirmPopupMessage: 'Bist du sicher, dass die direkte Einladung erstellt werden soll?.'
|
confirmPopupMessage: 'Bist du sicher, dass die direkte Einladung erstellt werden soll?.'
|
||||||
}}
|
}}
|
||||||
target={null}
|
target={null}
|
||||||
|
keys={[
|
||||||
|
[{ key: 'uuid', type: 'text', label: 'UUID (optional)', default: null, options: { dynamicWidth: true } }],
|
||||||
|
[{ key: 'comment', type: 'textarea', label: 'Kommentar', default: null, options: { dynamicWidth: true } }]
|
||||||
|
]}
|
||||||
onSubmit={addDirectInvitation}
|
onSubmit={addDirectInvitation}
|
||||||
bind:open={createPopupOpen}
|
bind:open={createPopupOpen}
|
||||||
/>
|
/>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { type ActionReturnType, actions } from 'astro:actions';
|
import { type ActionReturnType, actions } from 'astro:actions';
|
||||||
import { writable } from 'svelte/store';
|
import { get, writable } from 'svelte/store';
|
||||||
import { actionErrorPopup } from '@util/action.ts';
|
import { actionErrorPopup } from '@util/action.ts';
|
||||||
import { addToWritableArray, deleteFromWritableArray } from '@util/state.ts';
|
import { addToWritableArray, deleteFromWritableArray, updateWritableArray } from '@util/state.ts';
|
||||||
|
|
||||||
// types
|
// types
|
||||||
export type DirectInvitations = Exclude<
|
export type DirectInvitations = Exclude<
|
||||||
@@ -9,6 +9,11 @@ export type DirectInvitations = Exclude<
|
|||||||
undefined
|
undefined
|
||||||
>['directInvitations'];
|
>['directInvitations'];
|
||||||
export type DirectInvitation = DirectInvitations[0];
|
export type DirectInvitation = DirectInvitations[0];
|
||||||
|
export type DirectInvitationInput = {
|
||||||
|
code?: string;
|
||||||
|
uuid: string | null;
|
||||||
|
comment: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
// state
|
// state
|
||||||
export const directInvitations = writable<DirectInvitations>([]);
|
export const directInvitations = writable<DirectInvitations>([]);
|
||||||
@@ -24,18 +29,41 @@ export async function fetchDirectInvitations() {
|
|||||||
directInvitations.set(data.directInvitations);
|
directInvitations.set(data.directInvitations);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function addDirectInvitation() {
|
export async function addDirectInvitation(directInvitation: DirectInvitationInput) {
|
||||||
const { data, error } = await actions.user.addDirectInvitation();
|
const { data, error } = await actions.user.addDirectInvitation({
|
||||||
|
uuid: directInvitation.uuid,
|
||||||
|
comment: directInvitation.comment
|
||||||
|
});
|
||||||
if (error) {
|
if (error) {
|
||||||
actionErrorPopup(error);
|
actionErrorPopup(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
addToWritableArray(directInvitations, data);
|
addToWritableArray(directInvitations, { ...data, user: null });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function editDirectInvitation(directInvitation: DirectInvitationInput) {
|
||||||
|
const { error } = await actions.user.editDirectInvitation({
|
||||||
|
code: directInvitation.code!,
|
||||||
|
uuid: directInvitation.uuid,
|
||||||
|
comment: directInvitation.comment
|
||||||
|
});
|
||||||
|
if (error) {
|
||||||
|
actionErrorPopup(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const existing = get(directInvitations).find((t) => t.code === directInvitation.code);
|
||||||
|
|
||||||
|
updateWritableArray(
|
||||||
|
directInvitations,
|
||||||
|
{ ...existing, ...directInvitation } as DirectInvitation,
|
||||||
|
(t) => t.code === directInvitation.code
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteDirectInvitation(directInvitation: DirectInvitation) {
|
export async function deleteDirectInvitation(directInvitation: DirectInvitation) {
|
||||||
const { error } = await actions.user.deleteDirectInvitation(directInvitation);
|
const { error } = await actions.user.deleteDirectInvitation({ code: directInvitation.code });
|
||||||
if (error) {
|
if (error) {
|
||||||
actionErrorPopup(error);
|
actionErrorPopup(error);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -89,6 +89,7 @@
|
|||||||
convert?: (value: KeyInputTypeOptionsConvert<T>) => V;
|
convert?: (value: KeyInputTypeOptionsConvert<T>) => V;
|
||||||
validate?: (value: V) => boolean;
|
validate?: (value: V) => boolean;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
|
readonly?: boolean;
|
||||||
dynamicWidth?: boolean;
|
dynamicWidth?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -193,6 +194,7 @@
|
|||||||
bind:value={() => target[k.key] ?? k.default, (v) => onBindChange(k.key, v, k.options)}
|
bind:value={() => target[k.key] ?? k.default, (v) => onBindChange(k.key, v, k.options)}
|
||||||
label={k.label}
|
label={k.label}
|
||||||
required={k.options?.required}
|
required={k.options?.required}
|
||||||
|
readonly={k.options?.readonly}
|
||||||
dynamicWidth={k.options?.dynamicWidth}
|
dynamicWidth={k.options?.dynamicWidth}
|
||||||
/>
|
/>
|
||||||
{:else if k.type === 'textarea'}
|
{:else if k.type === 'textarea'}
|
||||||
@@ -230,6 +232,7 @@
|
|||||||
onSubmit={(user) => onBindChange(k.key, user, k.options)}
|
onSubmit={(user) => onBindChange(k.key, user, k.options)}
|
||||||
label={k.label}
|
label={k.label}
|
||||||
required={k.options?.required}
|
required={k.options?.required}
|
||||||
|
readonly={k.options?.readonly}
|
||||||
mustMatch={k.options?.mustMatch}
|
mustMatch={k.options?.mustMatch}
|
||||||
/>
|
/>
|
||||||
{:else if k.type === 'password'}
|
{:else if k.type === 'password'}
|
||||||
|
|||||||
+3
-9
@@ -28,16 +28,10 @@ CREATE TABLE IF NOT EXISTS blocked_user (
|
|||||||
-- direct signup
|
-- direct signup
|
||||||
CREATE TABLE IF NOT EXISTS direct_signup (
|
CREATE TABLE IF NOT EXISTS direct_signup (
|
||||||
code CHAR(255) NOT NULL UNIQUE,
|
code CHAR(255) NOT NULL UNIQUE,
|
||||||
user_id INT,
|
uuid VARCHAR(36) UNIQUE,
|
||||||
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
-- whitelist user
|
|
||||||
CREATE TABLE IF NOT EXISTS whitelist_user (
|
|
||||||
uuid VARCHAR(36) NOT NULL PRIMARY KEY,
|
|
||||||
comment TINYTEXT,
|
comment TINYTEXT,
|
||||||
user_id INT UNIQUE,
|
user_id INT,
|
||||||
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE SET NULL
|
FOREIGN KEY (user_id) REFERENCES user(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
-- report
|
-- report
|
||||||
|
|||||||
+6
-19
@@ -125,24 +125,17 @@ import {
|
|||||||
deleteDirectSignup,
|
deleteDirectSignup,
|
||||||
type DeleteDirectSignupReq,
|
type DeleteDirectSignupReq,
|
||||||
directSignup,
|
directSignup,
|
||||||
|
editDirectSignup,
|
||||||
|
type EditDirectSignupReq,
|
||||||
getDirectSignupByCode,
|
getDirectSignupByCode,
|
||||||
type GetDirectSignupByCodeReq,
|
type GetDirectSignupByCodeReq,
|
||||||
getDirectSignups,
|
getDirectSignups,
|
||||||
type GetDirectSignupsReq,
|
type GetDirectSignupsReq,
|
||||||
|
linkDirectSignupUserByUuid,
|
||||||
|
type LinkDirectSignupUserByUuidReq,
|
||||||
setDirectSignupUser,
|
setDirectSignupUser,
|
||||||
type SetDirectSignupUserReq
|
type SetDirectSignupUserReq
|
||||||
} from '@db/schema/directSignup.ts';
|
} from '@db/schema/directSignup.ts';
|
||||||
import {
|
|
||||||
addWhitelistUser,
|
|
||||||
type AddWhitelistUserReq,
|
|
||||||
deleteWhitelistUser,
|
|
||||||
type DeleteWhitelistUserReq,
|
|
||||||
editWhitelistUser,
|
|
||||||
type EditWhitelistUserReq,
|
|
||||||
getWhitelistUsers,
|
|
||||||
type GetWhitelistUsersReq,
|
|
||||||
whitelistUser
|
|
||||||
} from '@db/schema/whitelistUser.ts';
|
|
||||||
|
|
||||||
export class Database {
|
export class Database {
|
||||||
protected readonly db: MySql2Database<{
|
protected readonly db: MySql2Database<{
|
||||||
@@ -150,7 +143,6 @@ export class Database {
|
|||||||
user: typeof user;
|
user: typeof user;
|
||||||
blockedUser: typeof blockedUser;
|
blockedUser: typeof blockedUser;
|
||||||
directSignup: typeof directSignup;
|
directSignup: typeof directSignup;
|
||||||
whitelistUser: typeof whitelistUser;
|
|
||||||
report: typeof report;
|
report: typeof report;
|
||||||
reportAttachment: typeof reportAttachment;
|
reportAttachment: typeof reportAttachment;
|
||||||
reportStatus: typeof reportStatus;
|
reportStatus: typeof reportStatus;
|
||||||
@@ -176,7 +168,6 @@ export class Database {
|
|||||||
user,
|
user,
|
||||||
blockedUser,
|
blockedUser,
|
||||||
directSignup,
|
directSignup,
|
||||||
whitelistUser,
|
|
||||||
report,
|
report,
|
||||||
reportAttachment,
|
reportAttachment,
|
||||||
reportStatus,
|
reportStatus,
|
||||||
@@ -223,14 +214,10 @@ export class Database {
|
|||||||
addDirectSignup = (values: AddDirectSignupReq) => addDirectSignup(this.db, values);
|
addDirectSignup = (values: AddDirectSignupReq) => addDirectSignup(this.db, values);
|
||||||
setDirectSignupUser = (values: SetDirectSignupUserReq) => setDirectSignupUser(this.db, values);
|
setDirectSignupUser = (values: SetDirectSignupUserReq) => setDirectSignupUser(this.db, values);
|
||||||
deleteDirectSignup = (values: DeleteDirectSignupReq) => deleteDirectSignup(this.db, values);
|
deleteDirectSignup = (values: DeleteDirectSignupReq) => deleteDirectSignup(this.db, values);
|
||||||
|
editDirectSignup = (values: EditDirectSignupReq) => editDirectSignup(this.db, values);
|
||||||
getDirectSignups = (values: GetDirectSignupsReq) => getDirectSignups(this.db, values);
|
getDirectSignups = (values: GetDirectSignupsReq) => getDirectSignups(this.db, values);
|
||||||
getDirectSignupByCode = (values: GetDirectSignupByCodeReq) => getDirectSignupByCode(this.db, values);
|
getDirectSignupByCode = (values: GetDirectSignupByCodeReq) => getDirectSignupByCode(this.db, values);
|
||||||
|
linkDirectSignupUserByUuid = (values: LinkDirectSignupUserByUuidReq) => linkDirectSignupUserByUuid(this.db, values);
|
||||||
/* whitelist */
|
|
||||||
addWhitelistUser = (values: AddWhitelistUserReq) => addWhitelistUser(this.db, values);
|
|
||||||
editWhitelistUser = (values: EditWhitelistUserReq) => editWhitelistUser(this.db, values);
|
|
||||||
deleteWhitelistUser = (values: DeleteWhitelistUserReq) => deleteWhitelistUser(this.db, values);
|
|
||||||
getWhitelistUsers = (values: GetWhitelistUsersReq) => getWhitelistUsers(this.db, values);
|
|
||||||
|
|
||||||
/* report */
|
/* report */
|
||||||
addReport = (values: AddReportReq) => addReport(this.db, values);
|
addReport = (values: AddReportReq) => addReport(this.db, values);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { MySql2Database } from 'drizzle-orm/mysql2';
|
import type { MySql2Database } from 'drizzle-orm/mysql2';
|
||||||
import { int, mysqlTable, varchar } from 'drizzle-orm/mysql-core';
|
import { int, mysqlTable, text, varchar } from 'drizzle-orm/mysql-core';
|
||||||
import { user } from '@db/schema/user.ts';
|
import { user } from '@db/schema/user.ts';
|
||||||
import { eq } from 'drizzle-orm';
|
import { and, eq, isNull } from 'drizzle-orm';
|
||||||
import { generateRandomString } from '@util/random.ts';
|
import { generateRandomString } from '@util/random.ts';
|
||||||
import { siteUrl } from '@util/url.ts';
|
import { siteUrl } from '@util/url.ts';
|
||||||
|
|
||||||
@@ -9,16 +9,32 @@ type Database = MySql2Database<{ directSignup: typeof directSignup }>;
|
|||||||
|
|
||||||
export const directSignup = mysqlTable('direct_signup', {
|
export const directSignup = mysqlTable('direct_signup', {
|
||||||
code: varchar('code', { length: 255 }).unique().notNull(),
|
code: varchar('code', { length: 255 }).unique().notNull(),
|
||||||
|
uuid: varchar('uuid', { length: 36 }).unique(),
|
||||||
|
comment: text('comment'),
|
||||||
userId: int('user_id').references(() => user.id)
|
userId: int('user_id').references(() => user.id)
|
||||||
});
|
});
|
||||||
|
|
||||||
export type AddDirectSignupReq = {};
|
export type AddDirectSignupReq = {
|
||||||
|
uuid?: string | null;
|
||||||
|
comment?: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type EditDirectSignupReq = {
|
||||||
|
code: string;
|
||||||
|
uuid?: string | null;
|
||||||
|
comment?: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
export type SetDirectSignupUserReq = {
|
export type SetDirectSignupUserReq = {
|
||||||
code: string;
|
code: string;
|
||||||
userId: number;
|
userId: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type LinkDirectSignupUserByUuidReq = {
|
||||||
|
uuid: string;
|
||||||
|
userId: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type DeleteDirectSignupReq = {
|
export type DeleteDirectSignupReq = {
|
||||||
code: string;
|
code: string;
|
||||||
};
|
};
|
||||||
@@ -29,14 +45,28 @@ export type GetDirectSignupByCodeReq = {
|
|||||||
code: string;
|
code: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function addDirectSignup(db: Database, _values: AddDirectSignupReq) {
|
export async function addDirectSignup(db: Database, values: AddDirectSignupReq) {
|
||||||
const code = generateRandomString(16);
|
const code = generateRandomString(16);
|
||||||
|
const uuid = values.uuid ?? null;
|
||||||
|
const comment = values.comment ?? null;
|
||||||
|
|
||||||
await db.insert(directSignup).values({
|
await db.insert(directSignup).values({
|
||||||
code: code
|
code: code,
|
||||||
|
uuid: uuid,
|
||||||
|
comment: comment
|
||||||
});
|
});
|
||||||
|
|
||||||
return { code: code, url: siteUrl(`signup/${code}`) };
|
return { code: code, url: siteUrl(`signup/${code}`), uuid: uuid, comment: comment };
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function editDirectSignup(db: Database, values: EditDirectSignupReq) {
|
||||||
|
await db
|
||||||
|
.update(directSignup)
|
||||||
|
.set({
|
||||||
|
uuid: values.uuid ?? null,
|
||||||
|
comment: values.comment ?? null
|
||||||
|
})
|
||||||
|
.where(eq(directSignup.code, values.code));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setDirectSignupUser(db: Database, values: SetDirectSignupUserReq) {
|
export async function setDirectSignupUser(db: Database, values: SetDirectSignupUserReq) {
|
||||||
@@ -48,6 +78,15 @@ export async function setDirectSignupUser(db: Database, values: SetDirectSignupU
|
|||||||
.where(eq(directSignup.code, values.code));
|
.where(eq(directSignup.code, values.code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function linkDirectSignupUserByUuid(db: Database, values: LinkDirectSignupUserByUuidReq) {
|
||||||
|
await db
|
||||||
|
.update(directSignup)
|
||||||
|
.set({
|
||||||
|
userId: values.userId
|
||||||
|
})
|
||||||
|
.where(and(eq(directSignup.uuid, values.uuid), isNull(directSignup.userId)));
|
||||||
|
}
|
||||||
|
|
||||||
export async function deleteDirectSignup(db: Database, values: DeleteDirectSignupReq) {
|
export async function deleteDirectSignup(db: Database, values: DeleteDirectSignupReq) {
|
||||||
return db.delete(directSignup).where(eq(directSignup.code, values.code));
|
return db.delete(directSignup).where(eq(directSignup.code, values.code));
|
||||||
}
|
}
|
||||||
@@ -56,7 +95,13 @@ export async function getDirectSignups(db: Database, _values: GetDirectSignupsRe
|
|||||||
const directSignups = await db
|
const directSignups = await db
|
||||||
.select({
|
.select({
|
||||||
code: directSignup.code,
|
code: directSignup.code,
|
||||||
user: user
|
uuid: directSignup.uuid,
|
||||||
|
comment: directSignup.comment,
|
||||||
|
user: {
|
||||||
|
id: user.id,
|
||||||
|
uuid: user.uuid,
|
||||||
|
username: user.username
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.from(directSignup)
|
.from(directSignup)
|
||||||
.leftJoin(user, eq(directSignup.userId, user.id));
|
.leftJoin(user, eq(directSignup.userId, user.id));
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
import { int, mysqlTable, text, varchar } from 'drizzle-orm/mysql-core';
|
|
||||||
import type { MySql2Database } from 'drizzle-orm/mysql2';
|
|
||||||
import { eq } from 'drizzle-orm';
|
|
||||||
import { user } from '@db/schema/user.ts';
|
|
||||||
|
|
||||||
type Database = MySql2Database<{ whitelistUser: typeof whitelistUser }>;
|
|
||||||
|
|
||||||
export const whitelistUser = mysqlTable('whitelist_user', {
|
|
||||||
uuid: varchar('uuid', { length: 36 }).primaryKey(),
|
|
||||||
comment: text('comment'),
|
|
||||||
userId: int('user_id')
|
|
||||||
.unique()
|
|
||||||
.references(() => user.id, { onDelete: 'set null' })
|
|
||||||
});
|
|
||||||
|
|
||||||
export type AddWhitelistUserReq = {
|
|
||||||
uuid: string;
|
|
||||||
comment?: string | null;
|
|
||||||
userId?: number | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type EditWhitelistUserReq = {
|
|
||||||
uuid: string;
|
|
||||||
comment?: string | null;
|
|
||||||
userId?: number | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type DeleteWhitelistUserReq = {
|
|
||||||
uuid: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type GetWhitelistUsersReq = {};
|
|
||||||
|
|
||||||
export async function addWhitelistUser(db: Database, values: AddWhitelistUserReq) {
|
|
||||||
await db.insert(whitelistUser).values(values);
|
|
||||||
|
|
||||||
return { uuid: values.uuid };
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function editWhitelistUser(db: Database, values: EditWhitelistUserReq) {
|
|
||||||
await db
|
|
||||||
.update(whitelistUser)
|
|
||||||
.set({
|
|
||||||
comment: values.comment,
|
|
||||||
userId: values.userId
|
|
||||||
})
|
|
||||||
.where(eq(whitelistUser.uuid, values.uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function deleteWhitelistUser(db: Database, values: DeleteWhitelistUserReq) {
|
|
||||||
return db.delete(whitelistUser).where(eq(whitelistUser.uuid, values.uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getWhitelistUsers(db: Database, _values: GetWhitelistUsersReq) {
|
|
||||||
return db
|
|
||||||
.select({
|
|
||||||
uuid: whitelistUser.uuid,
|
|
||||||
comment: whitelistUser.comment,
|
|
||||||
user: {
|
|
||||||
id: user.id,
|
|
||||||
uuid: user.uuid
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.from(whitelistUser)
|
|
||||||
.leftJoin(user, eq(whitelistUser.userId, user.id));
|
|
||||||
}
|
|
||||||
@@ -45,6 +45,8 @@ export const POST = externalApi({
|
|||||||
if (input.code) {
|
if (input.code) {
|
||||||
await tx.setDirectSignupUser({ code: input.code, userId: user.id });
|
await tx.setDirectSignupUser({ code: input.code, userId: user.id });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await tx.linkDirectSignupUserByUuid({ uuid: input.uuid, userId: user.id });
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Response(null, { status: 201 });
|
return new Response(null, { status: 201 });
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { db } from '@db/database.ts';
|
|||||||
export const GET = externalApi({
|
export const GET = externalApi({
|
||||||
auth: true,
|
auth: true,
|
||||||
handler: async () => {
|
handler: async () => {
|
||||||
const whitelist = await db.getWhitelistUsers({});
|
const whitelist = (await db.getDirectSignups({})).filter((entry) => entry.uuid != null);
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|||||||
Reference in new issue
Block a user