Merge branch 'main' into unix101-1
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
commit
0b4d6bb953
|
@ -31,6 +31,10 @@
|
|||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.content > h1 a {
|
||||
color: var(--primary-heading);
|
||||
}
|
||||
|
||||
.content,
|
||||
.content > h2 {
|
||||
font-weight: 400;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
.name a {
|
||||
color: var(--primary-heading);
|
||||
}
|
||||
|
||||
.nameSpacer {
|
||||
width: calc(140rem / 16);
|
||||
}
|
||||
|
|
|
@ -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}>
|
||||
|
|
|
@ -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.
|
|
@ -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? You’ve come to the right place! ✍ CSC’s 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 |
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
|
123
lib/team.ts
123
lib/team.ts
|
@ -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) {
|
||||
|
|
|
@ -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 [
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue