Skip to content

Commit

Permalink
Refactor door access query and fix overflow design
Browse files Browse the repository at this point in the history
  • Loading branch information
Macludde authored and Isak-Kallini committed Apr 16, 2024
1 parent f897744 commit 57b62d6
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 125 deletions.
210 changes: 117 additions & 93 deletions src/lib/utils/member.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { PrismaClient } from "@prisma/client";
import { getDerivedRoles } from "./authorization";
import { error } from "@sveltejs/kit";
import { getDerivedRoles } from "./authorization";

export const getCustomAuthorOptions = async (
prisma: PrismaClient,
Expand Down Expand Up @@ -39,117 +39,141 @@ export const getCustomAuthorOptions = async (
});
};

export type MemberDoorPolicies = {
name: string;
roles: string[];
startDate: Date | null;
endDate: Date | null;
}[];

export const getCurrentDoorPoliciesForMember = async (
prisma: PrismaClient,
memberId: string,
studentId: string,
) => {
const [memberResult] = await Promise.allSettled([
prisma.member.findUnique({
where: {
id: memberId,
const memberPositionIds = await prisma.position
.findMany({
select: {
id: true,
name: true,
boardMember: true,
},
include: {
where: {
mandates: {
where: {
some: {
member: {
studentId,
},
startDate: {
lte: new Date(),
},
endDate: {
gte: new Date(),
},
},
include: {
position: {},
},
},
doorAccessPolicies: {},
},
}),
]);

if (memberResult.status === "rejected") {
throw error(500, "Could not fetch member");
}
if (!memberResult.value) {
throw error(404, "Member not found");
}

const member = memberResult.value;
const allDoorPolicies = await prisma.doorAccessPolicy.findMany();

const roles = member.doorAccessPolicies.map((d) => d.role).filter(notEmpty);
const positions = (
await prisma.position.findMany({
})
.catch(() => {
throw error(500, "Could not fetch member positions");
});
const userDoorPolicies = await prisma.doorAccessPolicy
.findMany({
where: {
id: {
in: roles,
},
AND: [
{
// is active, or indefinite
OR: [
{
startDatetime: null,
},
{
startDatetime: {
lte: new Date(),
},
},
],
},
{
// is active, or indefinite
OR: [
{
endDatetime: null,
},
{
endDatetime: {
gte: new Date(),
},
},
],
},
{
OR: [
{
studentId, // is for this user
},
{
role: {
in: getDerivedRoles(
memberPositionIds.map((pos) => pos.id),
true,
).concat(
memberPositionIds.some((pos) => pos.boardMember)
? ["dsek.styr"]
: [],
),
},
},
],
},
],
},
})
).concat(member.mandates.map((m) => m.position));

// Map a doorname to roles, startDate and endDate
const allMemberDoors = new Map<
string,
{
roles: string[];
startDate: Date | null;
endDate: Date | null;
}
>();
.catch(() => {
throw error(500, "Could not fetch door access");
});

allDoorPolicies
.filter((doorPolicy) =>
member.mandates.some(
(mandate) =>
// A doorpolicy is associated with either a role or a specific member
(doorPolicy.role && mandate.positionId.startsWith(doorPolicy.role)) ||
doorPolicy.studentId === member.studentId,
),
)
.forEach((doorPolicy) => {
// Get a nice name for a position instead of using the id
const positionNamesFromMandates = positions
.filter(
(position) =>
doorPolicy.role && position.id.startsWith(doorPolicy.role),
const policiesByDoor: MemberDoorPolicies = userDoorPolicies.reduce(
(acc, policy) => {
const role = policy.role ?? "Du";
const duplicate = acc.find(
(p) =>
p.name === policy.doorName &&
p.startDate === policy.startDatetime &&
p.endDate === policy.endDatetime,
);
if (duplicate) {
duplicate.roles.push(role);
return acc;
}
acc.push({
name: policy.doorName,
roles: [role],
startDate: policy.startDatetime,
endDate: policy.endDatetime,
});
return acc;
},
[] as MemberDoorPolicies,
);
const memberDoorPolicies: MemberDoorPolicies = policiesByDoor.map(
(policy) => {
const positionsMappedToThisDoor = memberPositionIds
.filter((pos) =>
policy.roles.some(
(role) =>
pos.id.startsWith(role) ||
(pos.boardMember && role === "dsek.styr"),
),
)
.map((position) => position.name);
const positionNames: string[] =
positionNamesFromMandates.length > 0
? positionNamesFromMandates
: ["Du"];

const oldData = allMemberDoors.get(doorPolicy.doorName);
const newData = oldData ?? {
roles: [...positionNames],
startDate: doorPolicy.startDatetime,
endDate: doorPolicy.endDatetime,
.map((pos) => pos.name);
positionsMappedToThisDoor.sort();
return {
...policy,
roles: positionsMappedToThisDoor || ["Du"],
};
if (oldData) {
// Remove duplicates
newData.roles = [...new Set(oldData.roles.concat(...positionNames))];

if (doorPolicy.startDatetime) {
newData.startDate =
oldData.startDate === null ||
doorPolicy.startDatetime > oldData.startDate
? oldData.startDate
: doorPolicy.startDatetime;
}
if (doorPolicy.endDatetime) {
newData.endDate =
oldData.endDate === null || doorPolicy.endDatetime < oldData.endDate
? oldData.endDate
: doorPolicy.endDatetime;
}
}
allMemberDoors.set(doorPolicy.doorName, newData);
});
},
);
memberDoorPolicies.sort((a, b) => a.name.localeCompare(b.name));

return allMemberDoors;
return memberDoorPolicies;
};

function notEmpty<TValue>(value: TValue | null | undefined): value is TValue {
return value !== null && value !== undefined;
}
21 changes: 13 additions & 8 deletions src/routes/(app)/members/[studentId]/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import { sendPing } from "./pings";
import { getCurrentDoorPoliciesForMember } from "$lib/utils/member";

export const load: PageServerLoad = async ({ locals, params }) => {
const { user, prisma } = locals;
const { prisma, user } = locals;
const { studentId } = params;
const [memberResult, publishedArticlesResult] = await Promise.allSettled([
prisma.member.findUnique({
where: {
studentId: params.studentId,
studentId: studentId,
},
include: {
mandates: {
Expand Down Expand Up @@ -42,7 +43,7 @@ export const load: PageServerLoad = async ({ locals, params }) => {
where: {
author: {
member: {
studentId: params.studentId,
studentId: studentId,
},
},
removedAt: null,
Expand All @@ -63,16 +64,20 @@ export const load: PageServerLoad = async ({ locals, params }) => {
throw error(404, "Member not found");
}
const member = memberResult.value;
const allMemberDoors = await getCurrentDoorPoliciesForMember(
prisma,
member.id,
);

const doorAccess =
member.id === user?.memberId
? await getCurrentDoorPoliciesForMember(prisma, studentId)
: (new Map() as unknown as Awaited<
ReturnType<typeof getCurrentDoorPoliciesForMember>
>);

try {
return {
form: await superValidate(member, memberSchema),
pingForm: await superValidate(emptySchema),
member,
allMemberDoors,
doorAccess,
publishedArticles: publishedArticlesResult.value ?? [],
ping: user
? await prisma.ping.findFirst({
Expand Down
27 changes: 3 additions & 24 deletions src/routes/(app)/members/[studentId]/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import DoorAccess from "./DoorAccess.svelte";
import HeldPositionsYear from "./HeldPositionsYear.svelte";
import PublishedArticles from "./PublishedArticles.svelte";
import PublishedEvents from "./PublishedEvents.svelte";
Expand Down Expand Up @@ -134,30 +135,8 @@
<div
class="col-span-5 sm:col-span-3 sm:col-start-3 md:col-start-1 lg:col-span-2 lg:col-start-1 xl:col-span-1 xl:col-start-1"
>
{#if isMe && data.allMemberDoors.size > 0}
<br />
<div class="my-2 text-xl font-bold">Dörrar</div>
{#each Array.from(data.allMemberDoors.entries()) as [doorName, doorData]}
<div class="my-2 flex justify-between rounded-lg bg-base-200 p-3">
<div class="my-auto font-bold">
{doorName}
</div>
<div class="flex flex-col text-right">
<span class="text-xs font-bold opacity-50">
{doorData.roles.join(" ")}
</span>
{#if doorData.startDate != null || doorData.endDate != null}
<div>
<span class="text-xs font-bold opacity-50">
{doorData.startDate?.toLocaleDateString() ?? ""}
-
{doorData.endDate?.toLocaleDateString() ?? ""}
</span>
</div>
{/if}
</div>
</div>
{/each}
{#if data.doorAccess.length > 0}
<DoorAccess doorAccess={data.doorAccess} />
{/if}
</div>
</article>
31 changes: 31 additions & 0 deletions src/routes/(app)/members/[studentId]/DoorAccess.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script lang="ts">
import type { MemberDoorPolicies } from "$lib/utils/member";
export let doorAccess: MemberDoorPolicies;
</script>

<div class="my-2 text-xl font-bold">Dörraccess</div>
{#each doorAccess as doorPolicy (doorPolicy.name + doorPolicy.startDate + doorPolicy.endDate)}
<div
class="my-2 flex items-center justify-between gap-4 rounded-lg bg-base-200 p-3"
>
<div class="flex flex-col">
<span class="font-semibold">{doorPolicy.name}</span>
{#if doorPolicy.startDate != null || doorPolicy.endDate != null}
<span class="text-nowrap text-[0.5rem] font-semibold opacity-50">
{doorPolicy.startDate?.toLocaleDateString("sv-SE") ?? ""}
-
{doorPolicy.endDate?.toLocaleDateString("sv-SE") ?? ""}
</span>
{/if}
</div>
<div class="flex flex-1 flex-col items-stretch overflow-hidden text-right">
<div class="flex flex-col text-xs font-bold opacity-50">
{#each doorPolicy.roles as role (role)}
<span class="overflow-hidden text-ellipsis whitespace-nowrap"
>{role}</span
>
{/each}
</div>
</div>
</div>
{/each}

0 comments on commit 57b62d6

Please sign in to comment.