Ask for a reason when reporting assistants (#825)
Browse files* Show modal asking for assistant report reason
* fix disabled button styling
* parse with zod
* Update src/routes/settings/assistants/[assistantId]/ReportModal.svelte
Co-authored-by: Victor Muštar <victor.mustar@gmail.com>
* use a text area with max-w
---------
Co-authored-by: Victor Muštar <victor.mustar@gmail.com>
src/lib/components/Modal.svelte
CHANGED
@@ -46,7 +46,7 @@
|
|
46 |
role="presentation"
|
47 |
tabindex="-1"
|
48 |
bind:this={backdropEl}
|
49 |
-
on:click={handleBackdropClick}
|
50 |
transition:fade|global={{ easing: cubicOut, duration: 300 }}
|
51 |
class="fixed inset-0 z-40 flex items-center justify-center bg-black/80 p-8 backdrop-blur-sm dark:bg-black/50"
|
52 |
>
|
|
|
46 |
role="presentation"
|
47 |
tabindex="-1"
|
48 |
bind:this={backdropEl}
|
49 |
+
on:click|stopPropagation={handleBackdropClick}
|
50 |
transition:fade|global={{ easing: cubicOut, duration: 300 }}
|
51 |
class="fixed inset-0 z-40 flex items-center justify-center bg-black/80 p-8 backdrop-blur-sm dark:bg-black/50"
|
52 |
>
|
src/lib/types/Report.ts
CHANGED
@@ -7,4 +7,5 @@ export interface Report extends Timestamps {
|
|
7 |
_id: ObjectId;
|
8 |
createdBy: User["_id"] | string;
|
9 |
assistantId: Assistant["_id"];
|
|
|
10 |
}
|
|
|
7 |
_id: ObjectId;
|
8 |
createdBy: User["_id"] | string;
|
9 |
assistantId: Assistant["_id"];
|
10 |
+
reason?: string;
|
11 |
}
|
src/routes/settings/assistants/[assistantId]/+page.server.ts
CHANGED
@@ -5,7 +5,7 @@ import { authCondition } from "$lib/server/auth";
|
|
5 |
import { base } from "$app/paths";
|
6 |
import { PUBLIC_ORIGIN, PUBLIC_SHARE_PREFIX } from "$env/static/public";
|
7 |
import { WEBHOOK_URL_REPORT_ASSISTANT } from "$env/static/private";
|
8 |
-
|
9 |
async function assistantOnlyIfAuthor(locals: App.Locals, assistantId?: string) {
|
10 |
const assistant = await collections.assistants.findOne({ _id: new ObjectId(assistantId) });
|
11 |
|
@@ -53,7 +53,7 @@ export const actions: Actions = {
|
|
53 |
|
54 |
throw redirect(302, `${base}/settings`);
|
55 |
},
|
56 |
-
report: async ({ params, locals, url }) => {
|
57 |
// is there already a report from this user for this model ?
|
58 |
const report = await collections.reports.findOne({
|
59 |
assistantId: new ObjectId(params.assistantId),
|
@@ -64,12 +64,20 @@ export const actions: Actions = {
|
|
64 |
return fail(400, { error: true, message: "Already reported" });
|
65 |
}
|
66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
const { acknowledged } = await collections.reports.insertOne({
|
68 |
_id: new ObjectId(),
|
69 |
assistantId: new ObjectId(params.assistantId),
|
70 |
createdBy: locals.user?._id ?? locals.sessionId,
|
71 |
createdAt: new Date(),
|
72 |
updatedAt: new Date(),
|
|
|
73 |
});
|
74 |
|
75 |
if (!acknowledged) {
|
@@ -91,7 +99,7 @@ export const actions: Actions = {
|
|
91 |
"Content-type": "application/json",
|
92 |
},
|
93 |
body: JSON.stringify({
|
94 |
-
text: `Assistant <${assistantUrl}|${assistant?.name}> reported by <http://hf.co/${locals.user?.username}|${locals.user?.username}
|
95 |
}),
|
96 |
});
|
97 |
|
|
|
5 |
import { base } from "$app/paths";
|
6 |
import { PUBLIC_ORIGIN, PUBLIC_SHARE_PREFIX } from "$env/static/public";
|
7 |
import { WEBHOOK_URL_REPORT_ASSISTANT } from "$env/static/private";
|
8 |
+
import { z } from "zod";
|
9 |
async function assistantOnlyIfAuthor(locals: App.Locals, assistantId?: string) {
|
10 |
const assistant = await collections.assistants.findOne({ _id: new ObjectId(assistantId) });
|
11 |
|
|
|
53 |
|
54 |
throw redirect(302, `${base}/settings`);
|
55 |
},
|
56 |
+
report: async ({ request, params, locals, url }) => {
|
57 |
// is there already a report from this user for this model ?
|
58 |
const report = await collections.reports.findOne({
|
59 |
assistantId: new ObjectId(params.assistantId),
|
|
|
64 |
return fail(400, { error: true, message: "Already reported" });
|
65 |
}
|
66 |
|
67 |
+
const formData = await request.formData();
|
68 |
+
const result = z.string().min(1).max(128).safeParse(formData?.get("reportReason"));
|
69 |
+
|
70 |
+
if (!result.success) {
|
71 |
+
return fail(400, { error: true, message: "Invalid report reason" });
|
72 |
+
}
|
73 |
+
|
74 |
const { acknowledged } = await collections.reports.insertOne({
|
75 |
_id: new ObjectId(),
|
76 |
assistantId: new ObjectId(params.assistantId),
|
77 |
createdBy: locals.user?._id ?? locals.sessionId,
|
78 |
createdAt: new Date(),
|
79 |
updatedAt: new Date(),
|
80 |
+
reason: result.data,
|
81 |
});
|
82 |
|
83 |
if (!acknowledged) {
|
|
|
99 |
"Content-type": "application/json",
|
100 |
},
|
101 |
body: JSON.stringify({
|
102 |
+
text: `Assistant <${assistantUrl}|${assistant?.name}> reported by <http://hf.co/${locals.user?.username}|${locals.user?.username}>. The following reason was given \n\n> ${result.data}`,
|
103 |
}),
|
104 |
});
|
105 |
|
src/routes/settings/assistants/[assistantId]/+page.svelte
CHANGED
@@ -12,6 +12,7 @@
|
|
12 |
import CarbonFlag from "~icons/carbon/flag";
|
13 |
import CarbonLink from "~icons/carbon/link";
|
14 |
import CopyToClipBoardBtn from "$lib/components/CopyToClipBoardBtn.svelte";
|
|
|
15 |
|
16 |
export let data: PageData;
|
17 |
|
@@ -24,8 +25,13 @@
|
|
24 |
const prefix = PUBLIC_SHARE_PREFIX || `${PUBLIC_ORIGIN || $page.url.origin}${base}`;
|
25 |
|
26 |
$: shareUrl = `${prefix}/assistant/${assistant?._id}`;
|
|
|
|
|
27 |
</script>
|
28 |
|
|
|
|
|
|
|
29 |
<div class="flex h-full flex-col gap-2">
|
30 |
<div class="flex gap-6">
|
31 |
{#if assistant?.avatar}
|
@@ -102,11 +108,15 @@
|
|
102 |
>
|
103 |
</form>
|
104 |
{#if !assistant?.reported}
|
105 |
-
<
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
|
|
|
|
|
|
|
|
110 |
{:else}
|
111 |
<button type="button" disabled class="text-gray-700">
|
112 |
<CarbonFlag class="mr-1.5 inline text-xs" />Reported</button
|
|
|
12 |
import CarbonFlag from "~icons/carbon/flag";
|
13 |
import CarbonLink from "~icons/carbon/link";
|
14 |
import CopyToClipBoardBtn from "$lib/components/CopyToClipBoardBtn.svelte";
|
15 |
+
import ReportModal from "./ReportModal.svelte";
|
16 |
|
17 |
export let data: PageData;
|
18 |
|
|
|
25 |
const prefix = PUBLIC_SHARE_PREFIX || `${PUBLIC_ORIGIN || $page.url.origin}${base}`;
|
26 |
|
27 |
$: shareUrl = `${prefix}/assistant/${assistant?._id}`;
|
28 |
+
|
29 |
+
let displayReportModal = false;
|
30 |
</script>
|
31 |
|
32 |
+
{#if displayReportModal}
|
33 |
+
<ReportModal on:close={() => (displayReportModal = false)} />
|
34 |
+
{/if}
|
35 |
<div class="flex h-full flex-col gap-2">
|
36 |
<div class="flex gap-6">
|
37 |
{#if assistant?.avatar}
|
|
|
108 |
>
|
109 |
</form>
|
110 |
{#if !assistant?.reported}
|
111 |
+
<button
|
112 |
+
type="button"
|
113 |
+
on:click={() => {
|
114 |
+
displayReportModal = true;
|
115 |
+
}}
|
116 |
+
class="underline"
|
117 |
+
>
|
118 |
+
<CarbonFlag class="mr-1.5 inline text-xs" />Report
|
119 |
+
</button>
|
120 |
{:else}
|
121 |
<button type="button" disabled class="text-gray-700">
|
122 |
<CarbonFlag class="mr-1.5 inline text-xs" />Reported</button
|
src/routes/settings/assistants/[assistantId]/ReportModal.svelte
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import { applyAction, enhance } from "$app/forms";
|
3 |
+
import { invalidateAll } from "$app/navigation";
|
4 |
+
import Modal from "$lib/components/Modal.svelte";
|
5 |
+
import { createEventDispatcher } from "svelte";
|
6 |
+
|
7 |
+
const dispatch = createEventDispatcher<{ close: void }>();
|
8 |
+
|
9 |
+
let reason = "";
|
10 |
+
</script>
|
11 |
+
|
12 |
+
<Modal on:close>
|
13 |
+
<form
|
14 |
+
method="POST"
|
15 |
+
action="?/report"
|
16 |
+
use:enhance={() => {
|
17 |
+
return async ({ result }) => {
|
18 |
+
await applyAction(result);
|
19 |
+
dispatch("close");
|
20 |
+
invalidateAll();
|
21 |
+
};
|
22 |
+
}}
|
23 |
+
class="w-full min-w-64 p-4"
|
24 |
+
>
|
25 |
+
<span class="mb-1 text-sm font-semibold">Report an assistant</span>
|
26 |
+
|
27 |
+
<p class="text-sm text-gray-500">
|
28 |
+
Please provide a brief description of why you are reporting this assistant.
|
29 |
+
</p>
|
30 |
+
|
31 |
+
<textarea
|
32 |
+
name="reportReason"
|
33 |
+
class="mt-6 max-h-48 w-full resize-y rounded-lg border-2 border-gray-200 bg-gray-100 p-2 text-smd"
|
34 |
+
placeholder="Reason(s) for the report"
|
35 |
+
maxlength="128"
|
36 |
+
bind:value={reason}
|
37 |
+
/>
|
38 |
+
|
39 |
+
<div class="flex w-full flex-row justify-between px-2 pt-4">
|
40 |
+
<button
|
41 |
+
type="button"
|
42 |
+
class="text-sm text-gray-700 hover:underline"
|
43 |
+
on:click={() => dispatch("close")}>Cancel</button
|
44 |
+
>
|
45 |
+
|
46 |
+
<button
|
47 |
+
type="submit"
|
48 |
+
class="rounded-full bg-black px-4 py-2 text-sm font-semibold text-white md:px-8"
|
49 |
+
disabled={!reason}
|
50 |
+
class:bg-gray-200={!reason}
|
51 |
+
class:!text-gray-400={!reason}
|
52 |
+
>
|
53 |
+
Submit report
|
54 |
+
</button>
|
55 |
+
</div>
|
56 |
+
</form>
|
57 |
+
</Modal>
|