Skip to content

Commit

Permalink
delete lists by group
Browse files Browse the repository at this point in the history
  • Loading branch information
cmintey committed Nov 27, 2023
1 parent 87412ab commit 9e6a816
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 88 deletions.
20 changes: 20 additions & 0 deletions src/lib/api/items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,23 @@ export class ItemAPI {
return await this._makeRequest("PATCH", { purchased: false });
};
}

export class ItemsAPI {
_makeRequest = async (method: string, path: string, body?: Record<string, unknown>) => {
const options: RequestInit = {
method,
headers: {
"content-type": "application/json",
accept: "application/json"
}
};

if (body) options.body = JSON.stringify(body);

return await fetch(`/api/items${path}`, options);
};

delete = async (groupId?: string) => {
return await this._makeRequest("DELETE", groupId ? `?groupId=${groupId}` : "");
};
}
49 changes: 49 additions & 0 deletions src/lib/components/admin/Actions/ClearListsButton.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<script lang="ts">
import { invalidateAll } from "$app/navigation";
import { ItemsAPI } from "$lib/api/items";
import { getModalStore, getToastStore, type ModalSettings } from "@skeletonlabs/skeleton";
export let groupId: string | undefined = undefined;
const modalStore = getModalStore();
const toastStore = getToastStore();
const itemsAPI = new ItemsAPI();
const handleDelete = async () => {
const settings: ModalSettings = {
type: "confirm",
title: "Please Confirm",
body: `Are you sure you wish to clear all wishlists ${
groupId ? "" : "across <b>all groups</b>"
}? <b>This action is irreversible!</b>`,
// confirm = TRUE | cancel = FALSE
response: async (r: boolean) => {
if (r) {
const resp = await itemsAPI.delete(groupId);
if (resp.ok) {
invalidateAll();
toastStore.trigger({
message: "Wishlists cleared.",
autohide: true,
timeout: 5000
});
} else {
toastStore.trigger({
message: `Oops! Something went wrong.`,
background: "variant-filled-warning",
autohide: true,
timeout: 5000
});
}
}
}
};
modalStore.trigger(settings);
};
</script>

<button class="variant-filled-error btn w-fit" type="button" on:click={handleDelete}>
Clear {groupId ? "" : "All"} Lists
</button>
48 changes: 2 additions & 46 deletions src/lib/components/admin/ActionsForm.svelte
Original file line number Diff line number Diff line change
@@ -1,51 +1,7 @@
<script lang="ts">
import { invalidateAll } from "$app/navigation";
import { getModalStore, getToastStore, type ModalSettings } from "@skeletonlabs/skeleton";
const modalStore = getModalStore();
const toastStore = getToastStore();
const handleDelete = async () => {
const settings: ModalSettings = {
type: "confirm",
title: "Please Confirm",
body: `Are you sure you wish to clear all wishlists? <b>This action is irreversible!</b>`,
// confirm = TRUE | cancel = FALSE
response: async (r: boolean) => {
if (r) {
const resp = await fetch(`/api/items`, {
method: "DELETE",
headers: {
"content-type": "application/json",
accept: "application/json"
}
});
if (resp.ok) {
invalidateAll();
toastStore.trigger({
message: "All wishlists cleared.",
autohide: true,
timeout: 5000
});
} else {
toastStore.trigger({
message: `Oops! Something went wrong.`,
background: "variant-filled-warning",
autohide: true,
timeout: 5000
});
}
}
}
};
modalStore.trigger(settings);
};
import ClearListsButton from "./Actions/ClearListsButton.svelte";
</script>

<div class="flex space-x-2">
<button class="variant-ghost-error btn w-fit" type="button" on:click={handleDelete}>
Clear Lists
</button>
<ClearListsButton />
</div>
6 changes: 5 additions & 1 deletion src/routes/admin/groups/[groupId]/members/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { getModalStore, type ModalSettings } from "@skeletonlabs/skeleton";
import type { PageData } from "./$types";
import InviteUser from "$lib/components/admin/InviteUser.svelte";
import ClearListsButton from "$lib/components/admin/Actions/ClearListsButton.svelte";
export let data: PageData;
Expand Down Expand Up @@ -125,5 +126,8 @@
</tbody>
</table>
</div>
<button class="variant-filled-error btn w-fit" on:click={deleteGroup}>Delete Group</button>
<div>
<button class="variant-filled-error btn w-fit" on:click={deleteGroup}>Delete Group</button>
<ClearListsButton groupId={$page.params.groupId} />
</div>
</div>
2 changes: 1 addition & 1 deletion src/routes/api/groups/[groupId]/+server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { error } from "@sveltejs/kit";
import type { RequestHandler } from "./$types";
import { _authCheck } from "./users/[userId]/+server";
import { client } from "$lib/server/prisma";
import { _authCheck } from "./auth";

export const DELETE: RequestHandler = async ({ locals, params }) => {
const { authenticated } = await _authCheck(locals.validate, params.groupId);
Expand Down
34 changes: 34 additions & 0 deletions src/routes/api/groups/[groupId]/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Role } from "$lib/schema";
import { client } from "$lib/server/prisma";
import { error } from "@sveltejs/kit";

export const _authCheck = async (validate: App.Locals["validate"], groupId: string) => {
const session = await validate();
if (!session) {
throw error(401, "Must authenticate first");
}

const user = await client.user.findFirstOrThrow({
where: {
id: session.user.userId
},
select: {
id: true,
roleId: true,
UserGroupMembership: {
where: {
groupId: groupId
},
select: {
roleId: true
}
}
}
});

return {
authenticated:
user.roleId === Role.ADMIN || user.UserGroupMembership[0]?.roleId === Role.GROUP_MANAGER,
user
};
};
32 changes: 1 addition & 31 deletions src/routes/api/groups/[groupId]/users/[userId]/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,7 @@ import { Role } from "$lib/schema";
import { client } from "$lib/server/prisma";
import { error } from "@sveltejs/kit";
import type { RequestHandler } from "./$types";

export const _authCheck = async (validate: App.Locals["validate"], groupId: string) => {
const session = await validate();
if (!session) {
throw error(401, "Must authenticate first");
}

const user = await client.user.findFirstOrThrow({
where: {
id: session.user.userId
},
select: {
id: true,
roleId: true,
UserGroupMembership: {
where: {
groupId: groupId
},
select: {
roleId: true
}
}
}
});

return {
authenticated:
user.roleId === Role.ADMIN || user.UserGroupMembership[0]?.roleId === Role.GROUP_MANAGER,
user
};
};
import { _authCheck } from "../../auth";

export const GET: RequestHandler = async ({ locals, params }) => {
const { authenticated, user } = await _authCheck(locals.validate, params.groupId);
Expand Down
32 changes: 23 additions & 9 deletions src/routes/api/items/+server.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
import { Role } from "$lib/schema";
import { client } from "$lib/server/prisma";
import { error, type RequestHandler } from "@sveltejs/kit";
import { error } from "@sveltejs/kit";
import type { RequestHandler } from "./$types";
import { _authCheck } from "../groups/[groupId]/auth";

export const DELETE: RequestHandler = async ({ locals }) => {
const session = await locals.validate();
if (!session) {
throw error(401, "Must authenticate first");
}
if (session.user.roleId !== Role.ADMIN) {
throw error(401, "Not authorized to view admin panel");
export const DELETE: RequestHandler = async ({ locals, request }) => {
const groupId = new URL(request.url).searchParams.get("groupId");
if (groupId) {
const { authenticated } = await _authCheck(locals.validate, groupId);
if (!authenticated) {
throw error(401, "Not authorized to delete items for this group");
}
} else {
const session = await locals.validate();
if (!session) {
throw error(401, "Must authenticate first");
}
if (session.user.roleId !== Role.ADMIN) {
throw error(401, "Not authorized to delete items");
}
}

try {
const items = await client.item.deleteMany();
const items = await client.item.deleteMany({
where: {
groupId: groupId ? groupId : undefined
}
});
return new Response(JSON.stringify(items), { status: 200 });
} catch (e) {
throw error(500, "Unable to delete items");
Expand Down

0 comments on commit 9e6a816

Please sign in to comment.