Merge branch 'main' into unix101-1
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Shahan Nedadahandeh 2022-03-26 01:17:42 -04:00
commit 0b4d6bb953
19 changed files with 189 additions and 23 deletions

View File

@ -31,6 +31,10 @@
margin-bottom: 0;
}
.content > h1 a {
color: var(--primary-heading);
}
.content,
.content > h2 {
font-weight: 400;

View File

@ -18,6 +18,10 @@ interface EventCardProps {
permaLink: string;
showDescription?: boolean;
children: ReactNode;
year: string;
term: string;
slug: string;
titleLinked: boolean;
}
export function EventCard({
@ -30,6 +34,10 @@ export function EventCard({
registerLink,
children,
showDescription = false,
year,
term,
slug,
titleLinked,
}: EventCardProps) {
return (
<article className={styles.card}>
@ -54,7 +62,13 @@ export function EventCard({
showDescription ? styles.mobileShowDescriptionContent : "",
].join(" ")}
>
<h1>{name}</h1>
<h1>
{titleLinked ? (
<Link href={`/events/${year}/${term}/${slug}`}>{name}</Link>
) : (
name
)}
</h1>
<h2>
<EventSetting date={date} online={online} location={location} />
</h2>

View File

@ -14,6 +14,10 @@
margin: 0;
}
.name a {
color: var(--primary-heading);
}
.nameSpacer {
width: calc(140rem / 16);
}

View File

@ -1,32 +1,39 @@
import React, { ReactNode } from "react";
import { EventSetting } from "./EventSetting";
import { Link } from "./Link";
import styles from "./MiniEventCard.module.css";
interface Props {
interface MiniEventCardProps {
name: string;
description: ReactNode;
short: string;
online: boolean;
location: string;
date: Date;
year: string;
term: string;
slug: string;
}
export const MiniEventCard: React.FC<Props> = ({
export const MiniEventCard: React.FC<MiniEventCardProps> = ({
name,
short,
description,
location,
date,
online,
year,
term,
slug,
}) => {
return (
<details className={styles.card}>
<summary>
<div onClick={(event) => event.preventDefault()}>
<h2 className={styles.name}>
<div>{name}</div>
<Link href={`/events/${year}/${term}/${slug}`}>{name}</Link>
<div className={styles.nameSpacer}></div>
</h2>
<div className={styles.info}>

View File

@ -0,0 +1,17 @@
---
name: "Code Party"
short: "CS Club is hosting our first Code Party since the pandemic started. Come code and chill (in-person!) with us!"
date: "March 25 2022 18:00"
online: false
location: "STC 0060"
poster: "images/events/2022/winter/Code-Party.png"
registerLink: "https://forms.gle/M4YzJeHpt2RiY1HHA"
---
CS Club is hosting our first Code Party since the pandemic started, from 6 pm until 9 pm in STC 0060, on Friday, March 25. Come code and chill (in-person!) with us!
Personal projects you want to work on? Homework assignments you need to finish? Or want some time to explore new technology and meet new people in a casual, minimal-stress environment? You can do all this and more at our Code Party! All experience levels are welcome.
Come any time after 6 pm. Food will be provided.
Registration is not required, but it is highly recommended. Register at https://forms.gle/M4YzJeHpt2RiY1HHA. Alternatively, you can also email us at exec@csclub.uwaterloo.ca to let us know you're interested.

View File

@ -0,0 +1,19 @@
---
name: "Unix 101: FS/Perms & vim"
short: "Join CSC's Systems Committee (syscom) for the second session of an introductory series on GNU/Linux!"
date: "March 26 2022 14:00"
online: true
location: "Twitch"
poster: 'images/events/2022/winter/Unix-101-2.png'
---
Do you want to start editing with vim? Looking to learn about the Unix file system? Youve come to the right place! ✍ CSCs Systems Committee (syscom) is back with a workshop on File Systems, Permissions, and a tutorial on vim for our 2nd session of Unix 101! 💻
🙆‍♂️ Unix 101 is a 4-part, beginner-friendly series on the Unix operating system. Attendance in previous sessions is not required to understand the proceeding ones, but is strongly encouraged to make sure you get the most out of our workshops! ✨
👆 We additionally recommend joining CSC to access our machines for more hands-on activity. Learn more about how you can do so at https://csclub.uwaterloo.ca/get-involved/!
🧠 Head over to our Twitch on March 26th from 2-3PM ET for our second session of Unix 101!
📅 Event Date: Saturday March 26th @ 2-3PM ET on Twitch
🔗 Twitch: https://www.twitch.tv/uwcsclub

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

View File

@ -53,6 +53,9 @@ interface Metadata {
location: string;
permaLink: string;
registerLink?: string;
year: string;
term: string;
slug: string;
}
export interface Event {
@ -82,6 +85,9 @@ export async function getEventBySlug(
).toString(),
// permaLink is based on the directory structure in /pages
permaLink: `/events/${year}/${term}/${slug}`,
year: year,
term: term,
slug: slug,
} as Metadata,
};
}

View File

@ -1,11 +1,32 @@
import { readFile, readdir, access } from "fs/promises";
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 { getCurrentTerm } from "@/lib/events";
import { capitalize } from "@/utils";
const EXECS_PATH = path.join("content", "team", "execs");
const fileType = ".md";
const FILETYPE = ".md";
const { year, term } = getCurrentTerm();
const execPositions: { [position: string]: string } = {
president: "President",
"vice-president": "Vice President",
secretary: "Assistant Vice President",
treasurer: "Treasurer",
sysadmin: "System Administrator",
};
const orderedExecPositions: string[] = [
"president",
"vice-president",
"secretary",
"treasurer",
"sysadmin",
];
export interface Metadata {
name: string;
@ -13,23 +34,93 @@ export interface Metadata {
image: string;
}
export async function getExecNames() {
return (await readdir(EXECS_PATH))
.filter((name) => name.endsWith(fileType))
.map((name) => name.slice(0, -1 * fileType.length));
export async function getExecNamePosPairs() {
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: [string, string][] = [];
try {
await client.bind("", "");
const { searchEntries } = await client.search(searchDN, {
scope: "sub",
filter: `(&(objectClass=member)(term=${(term as string).slice(
0,
1
)}${year}))`,
});
// 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) => {
return [
`${execMembers[position].split(" ")[0].toLowerCase()}-${execMembers[
position
]
.split(" ")[1]
.toLowerCase()}`,
position,
];
});
formattedExec = [...formattedExec, ["codey", "mascot"]];
} finally {
await client.unbind();
}
return formattedExec;
}
export async function getExec(fileName: string, convert = true) {
const raw = await readFile(path.join(EXECS_PATH, `${fileName}${fileType}`));
const { content, data: metadata } = matter(raw);
const image =
(metadata.image as string | undefined) ??
(await getMemberImagePath(metadata.name));
export async function getExec(name: string, pos: string, convert = true) {
let content, metadata;
return {
content: convert ? await serialize(content) : content,
metadata: { ...metadata, image } as Metadata,
};
try {
const raw = await readFile(path.join(EXECS_PATH, `${name}${FILETYPE}`));
({ content, data: metadata } = matter(raw));
const image = await getMemberImagePath(metadata.name);
return {
content: convert ? await serialize(content) : 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: convert ? await serialize(content) : content,
metadata: { ...metadata, image } as Metadata,
};
}
}
async function getImage(imgPath: string) {

View File

@ -11,7 +11,7 @@ import { TeamMemberCard } from "@/components/TeamMemberCard";
import { Title } from "@/components/Title";
import {
getExec,
getExecNames,
getExecNamePosPairs,
Metadata,
getMemberImagePath,
} from "@/lib/team";
@ -208,10 +208,12 @@ async function getTeamWithImages(team: TeamMember[]) {
}
export const getStaticProps: GetStaticProps<Props> = async () => {
const execNames = await getExecNames();
const execNamePosPairs = await getExecNamePosPairs();
const execs = (await Promise.all(
execNames.map((name) => getExec(name))
execNamePosPairs.map((namePosPair) =>
getExec(namePosPair[0], namePosPair[1])
)
)) as SerializedExec[];
const [

View File

@ -28,6 +28,7 @@ export default function EventInfoPage({ year, term, event }: Props) {
{...event.metadata}
date={new Date(event.metadata.date)}
showDescription
titleLinked={false}
>
<MDXRemote {...event.content} />
</EventCard>

View File

@ -75,6 +75,7 @@ export default function TermPage(props: Props) {
{...metadata}
date={new Date(metadata.date)}
key={metadata.name + metadata.date.toString()}
titleLinked={true}
>
<MDXRemote {...content} />
</EventCard>