Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

delete lists by group #74

Merged
merged 1 commit into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading