Computer Science Club of the University of Waterloo's website.
https://csclub.uwaterloo.ca
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
4.8 KiB
181 lines
4.8 KiB
import { readFile, access } from "fs/promises";
|
|
import path from "path";
|
|
|
|
import matter from "gray-matter";
|
|
import { Client } from "ldapts";
|
|
import { serialize } from "next-mdx-remote/serialize";
|
|
|
|
import { capitalize, getCurrentTermYear, getTermYear, TermYear } from "@/utils";
|
|
|
|
const EXECS_PATH = path.join("content", "team", "execs");
|
|
const FILETYPE = ".md";
|
|
|
|
const execPositions: { [position: string]: string } = {
|
|
president: "President",
|
|
"vice-president": "Vice-President",
|
|
secretary: "Assistant Vice-President",
|
|
treasurer: "Treasurer",
|
|
sysadmin: "Systems Administrator",
|
|
};
|
|
|
|
const orderedExecPositions: string[] = [
|
|
"president",
|
|
"vice-president",
|
|
"secretary",
|
|
"treasurer",
|
|
"sysadmin",
|
|
];
|
|
|
|
export interface Metadata {
|
|
name: string;
|
|
role?: string;
|
|
image: string;
|
|
}
|
|
|
|
export async function getExecs() {
|
|
const execNamePosPairs = await getExecNamePosPairs();
|
|
|
|
return await Promise.all(
|
|
execNamePosPairs.map((namePosPair) =>
|
|
getExec(namePosPair[0], namePosPair[1])
|
|
)
|
|
);
|
|
}
|
|
|
|
async function getExec(name: string, pos: string) {
|
|
let content, metadata;
|
|
|
|
try {
|
|
const raw = await readFile(path.join(EXECS_PATH, `${name}${FILETYPE}`));
|
|
({ content, data: metadata } = matter(raw));
|
|
|
|
const image = await getMemberImagePath(metadata.name as string);
|
|
|
|
return {
|
|
content: await serialize(content),
|
|
metadata: { ...metadata, image } as Metadata,
|
|
};
|
|
} catch (err) {
|
|
// Capitalize the first letter of the first name and last name
|
|
const firstName = capitalize(name.split("-")[0]);
|
|
const lastName = capitalize(name.split("-")[1]);
|
|
|
|
const posName = execPositions[pos];
|
|
content = "Coming Soon!";
|
|
metadata = {
|
|
name: `${firstName} ${lastName}`,
|
|
role: `${posName}`,
|
|
};
|
|
|
|
const image = await getMemberImagePath(metadata.name);
|
|
|
|
return {
|
|
content: await serialize(content),
|
|
metadata: { ...metadata, image } as Metadata,
|
|
};
|
|
}
|
|
}
|
|
|
|
async function getExecNamePosPairs(): Promise<
|
|
[person: string, position: string][]
|
|
> {
|
|
if (process.env.USE_LDAP?.toLowerCase() !== "true") {
|
|
return [["codey", "mascot"]];
|
|
}
|
|
|
|
const url = "ldap://ldap1.csclub.uwaterloo.ca";
|
|
const searchDN = "ou=People,dc=csclub,dc=uwaterloo,dc=ca";
|
|
const client = new Client({ url });
|
|
|
|
// position: name
|
|
const execMembers: { [position: string]: string } = {};
|
|
let formattedExec: [person: string, position: string][] = [];
|
|
|
|
try {
|
|
await client.bind("", "");
|
|
|
|
const terms: TermYear[] = [];
|
|
|
|
// check members from last two terms (including current term)
|
|
for (const termYear of getTermYear(getCurrentTermYear(), {
|
|
goBackwards: true,
|
|
})) {
|
|
if (terms.length >= 2) {
|
|
break;
|
|
}
|
|
terms.push(termYear);
|
|
}
|
|
|
|
const termsFilters = terms
|
|
.map(
|
|
({ term, year }: TermYear) =>
|
|
`(term=${(term as string).slice(0, 1)}${year})`
|
|
)
|
|
.join("");
|
|
|
|
const { searchEntries } = await client.search(searchDN, {
|
|
scope: "sub",
|
|
filter: `(&(objectClass=member)(|${termsFilters}))`,
|
|
});
|
|
|
|
// item.position might be an array if the member has more than one position
|
|
searchEntries.forEach((item) => {
|
|
if (typeof item.position === "string" && item.position in execPositions) {
|
|
execMembers[item.position] = item.cn as string;
|
|
} else if (item.position instanceof Array) {
|
|
item.position.forEach((p) => {
|
|
if ((p as string) in execPositions) {
|
|
execMembers[p as string] = item.cn as string;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
formattedExec = orderedExecPositions
|
|
.map((position) => {
|
|
const fullName = execMembers[position];
|
|
if (fullName == undefined) {
|
|
return null;
|
|
}
|
|
const firstName = fullName.split(" ")[0].toLowerCase();
|
|
const lastName = fullName.split(" ")[1].toLowerCase();
|
|
return [`${firstName}-${lastName}`, position];
|
|
})
|
|
.filter((pair) => pair != null) as [person: string, position: string][];
|
|
|
|
formattedExec = [...formattedExec, ["codey", "mascot"]];
|
|
} finally {
|
|
await client.unbind();
|
|
}
|
|
|
|
return formattedExec;
|
|
}
|
|
|
|
async function getImage(imgPath: string) {
|
|
try {
|
|
await access(path.join("public", imgPath));
|
|
return imgPath;
|
|
} catch {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
export async function getMemberImagePath(name: string) {
|
|
const imgPath = path.join("images", "team", name.replace(" ", ""));
|
|
const placeholder = path.join(
|
|
"images",
|
|
"team",
|
|
"team-member-placeholder.svg"
|
|
);
|
|
const img =
|
|
(await getImage(imgPath + ".jpg")) ??
|
|
(await getImage(imgPath + ".png")) ??
|
|
(await getImage(imgPath + ".gif")) ??
|
|
(await getImage(imgPath + ".jpeg")) ??
|
|
(await getImage(imgPath + ".JPG")) ??
|
|
(await getImage(imgPath + ".PNG")) ??
|
|
(await getImage(imgPath + ".GIF")) ??
|
|
(await getImage(imgPath + ".JPEG")) ??
|
|
placeholder;
|
|
return img;
|
|
}
|
|
|