Generate members list (#354)
continuous-integration/drone/push Build is passing Details

#301

https://csclub.uwaterloo.ca/~a3thakra/csc/j285he-ldap/about/members/

Co-authored-by: Jared He <66887902+jaredjhe@users.noreply.github.com>
Co-authored-by: Jared He <j285he@uwaterloo.ca>
Reviewed-on: #354
Reviewed-by: n3parikh <n3parikh@csclub.uwaterloo.ca>
Co-authored-by: j285he <j285he@localhost>
Co-committed-by: j285he <j285he@localhost>
This commit is contained in:
Jared He 2021-11-22 12:47:00 -05:00
parent 85e5080012
commit e6315cf906
8 changed files with 280 additions and 8 deletions

View File

@ -42,7 +42,7 @@ steps:
depends_on: depends_on:
- optimize-images - optimize-images
commands: commands:
- npm run build:web - USE_LDAP=true npm run build:web
- name: export - name: export
image: node:16 image: node:16

View File

@ -32,6 +32,10 @@ const menu: Menu = [
name: "Meet the Team", name: "Meet the Team",
route: "/about/team", route: "/about/team",
}, },
{
name: "Members",
route: "/about/members",
},
{ {
name: "Constitution", name: "Constitution",
route: "/about/constitution", route: "/about/constitution",

View File

@ -4,6 +4,8 @@ set -ex
ulimit -u 512 ulimit -u 512
DIR=$(mktemp --directory) DIR=$(mktemp --directory)
# set USE_LDAP to true to generate member list using LDAP database
export USE_LDAP=true
pushd $DIR pushd $DIR

61
lib/members.ts Normal file
View File

@ -0,0 +1,61 @@
import { Client } from "ldapts";
export interface Member {
name: string;
id: string;
program: string;
}
export async function getMembers(
year: string,
term: string
): Promise<Member[]> {
if (term !== "winter" && term !== "spring" && term !== "fall") {
throw new Error(`[getMembers] Not a valid term: "${term}"`);
}
if (process.env.USE_LDAP?.toLowerCase() !== "true") {
return dummyMembers;
}
let members: Member[] = [];
const url = "ldap://ldap1.csclub.uwaterloo.ca";
const searchDN = "ou=People,dc=csclub,dc=uwaterloo,dc=ca";
const client = new Client({ url });
try {
await client.bind("", "");
const { searchEntries } = await client.search(searchDN, {
scope: "sub",
filter: `(&(objectClass=member)(term=${term.slice(0, 1)}${year}))`,
});
members = searchEntries
.map((item) => {
return {
name: item.cn as string,
id: item.uid as string,
program: item.program === undefined ? "" : (item.program as string),
};
})
.sort((item1: Member, item2: Member) => item1.id.localeCompare(item2.id));
} finally {
await client.unbind();
}
return members;
}
const dummyMembers: Member[] = [
{
name: "John Smith",
id: "j12smith",
program: "MAT/Mathematics Computer Science",
},
{
name: "Jane Smith",
id: "j34smith",
program: "MAT/Mathematics Computer Science",
},
];

147
package-lock.json generated
View File

@ -1,5 +1,5 @@
{ {
"name": "website", "name": "www-new",
"version": "0.1.0", "version": "0.1.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
@ -15,6 +15,7 @@
"date-fns-tz": "^1.1.6", "date-fns-tz": "^1.1.6",
"fs-extra": "^10.0.0", "fs-extra": "^10.0.0",
"image-size": "^1.0.0", "image-size": "^1.0.0",
"ldapts": "^3.1.0",
"next": "11.0.1", "next": "11.0.1",
"next-mdx-remote": "3.0.4", "next-mdx-remote": "3.0.4",
"prettier": "^2.3.0", "prettier": "^2.3.0",
@ -1030,6 +1031,14 @@
"integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
"dev": true "dev": true
}, },
"node_modules/@types/asn1": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@types/asn1/-/asn1-0.2.0.tgz",
"integrity": "sha512-5TMxIpYbIA9c1J0hYQjQDX3wr+rTgQEAXaW2BI8ECM8FO53wSW4HFZplTalrKSHuZUc76NtXcePRhwuOHqGD5g==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/fs-extra": { "node_modules/@types/fs-extra": {
"version": "9.0.13", "version": "9.0.13",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz",
@ -1071,9 +1080,9 @@
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "16.9.1", "version": "16.11.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.7.tgz",
"integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==" "integrity": "sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw=="
}, },
"node_modules/@types/parse5": { "node_modules/@types/parse5": {
"version": "5.0.3", "version": "5.0.3",
@ -1108,6 +1117,11 @@
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz",
"integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==" "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ=="
}, },
"node_modules/@types/uuid": {
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.1.tgz",
"integrity": "sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg=="
},
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "4.28.4", "version": "4.28.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.4.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.4.tgz",
@ -1555,6 +1569,14 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/asn1": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
"dependencies": {
"safer-buffer": "~2.1.0"
}
},
"node_modules/asn1.js": { "node_modules/asn1.js": {
"version": "5.4.1", "version": "5.4.1",
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
@ -4620,6 +4642,44 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/ldapts": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/ldapts/-/ldapts-3.1.1.tgz",
"integrity": "sha512-RNxTlfiPS4fTN0b7oY0OE4d+E/uVg1nNlK1ZLPFyVsp4Gr8qSclJUWjdJ5W7PUtuiWh7kEEdNq1YAA+abERZZA==",
"dependencies": {
"@types/asn1": "~0.2.0",
"@types/node": "^16.11.6",
"@types/uuid": "~8.3.1",
"asn1": "~0.2.4",
"debug": "~4.3.2",
"strict-event-emitter-types": "~2.0.0",
"uuid": "~8.3.2"
},
"engines": {
"node": ">=12"
}
},
"node_modules/ldapts/node_modules/debug": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/ldapts/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/levn": { "node_modules/levn": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@ -8398,6 +8458,11 @@
"debug": "2" "debug": "2"
} }
}, },
"node_modules/strict-event-emitter-types": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strict-event-emitter-types/-/strict-event-emitter-types-2.0.0.tgz",
"integrity": "sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA=="
},
"node_modules/string_decoder": { "node_modules/string_decoder": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@ -9097,6 +9162,14 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
}, },
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/uuid-random": { "node_modules/uuid-random": {
"version": "1.3.2", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/uuid-random/-/uuid-random-1.3.2.tgz", "resolved": "https://registry.npmjs.org/uuid-random/-/uuid-random-1.3.2.tgz",
@ -10155,6 +10228,14 @@
"integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
"dev": true "dev": true
}, },
"@types/asn1": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@types/asn1/-/asn1-0.2.0.tgz",
"integrity": "sha512-5TMxIpYbIA9c1J0hYQjQDX3wr+rTgQEAXaW2BI8ECM8FO53wSW4HFZplTalrKSHuZUc76NtXcePRhwuOHqGD5g==",
"requires": {
"@types/node": "*"
}
},
"@types/fs-extra": { "@types/fs-extra": {
"version": "9.0.13", "version": "9.0.13",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz",
@ -10196,9 +10277,9 @@
} }
}, },
"@types/node": { "@types/node": {
"version": "16.9.1", "version": "16.11.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.7.tgz",
"integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==" "integrity": "sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw=="
}, },
"@types/parse5": { "@types/parse5": {
"version": "5.0.3", "version": "5.0.3",
@ -10233,6 +10314,11 @@
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz",
"integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==" "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ=="
}, },
"@types/uuid": {
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.1.tgz",
"integrity": "sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg=="
},
"@typescript-eslint/eslint-plugin": { "@typescript-eslint/eslint-plugin": {
"version": "4.28.4", "version": "4.28.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.4.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.4.tgz",
@ -10521,6 +10607,14 @@
"function-bind": "^1.1.1" "function-bind": "^1.1.1"
} }
}, },
"asn1": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
"requires": {
"safer-buffer": "~2.1.0"
}
},
"asn1.js": { "asn1.js": {
"version": "5.4.1", "version": "5.4.1",
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
@ -12773,6 +12867,35 @@
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"dev": true "dev": true
}, },
"ldapts": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/ldapts/-/ldapts-3.1.1.tgz",
"integrity": "sha512-RNxTlfiPS4fTN0b7oY0OE4d+E/uVg1nNlK1ZLPFyVsp4Gr8qSclJUWjdJ5W7PUtuiWh7kEEdNq1YAA+abERZZA==",
"requires": {
"@types/asn1": "~0.2.0",
"@types/node": "^16.11.6",
"@types/uuid": "~8.3.1",
"asn1": "~0.2.4",
"debug": "~4.3.2",
"strict-event-emitter-types": "~2.0.0",
"uuid": "~8.3.2"
},
"dependencies": {
"debug": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
"requires": {
"ms": "2.1.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"levn": { "levn": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@ -15640,6 +15763,11 @@
"debug": "2" "debug": "2"
} }
}, },
"strict-event-emitter-types": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strict-event-emitter-types/-/strict-event-emitter-types-2.0.0.tgz",
"integrity": "sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA=="
},
"string_decoder": { "string_decoder": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@ -16156,6 +16284,11 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
}, },
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
},
"uuid-random": { "uuid-random": {
"version": "1.3.2", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/uuid-random/-/uuid-random-1.3.2.tgz", "resolved": "https://registry.npmjs.org/uuid-random/-/uuid-random-1.3.2.tgz",

View File

@ -24,6 +24,7 @@
"@squoosh/lib": "^0.4.0", "@squoosh/lib": "^0.4.0",
"date-fns": "^2.11.1", "date-fns": "^2.11.1",
"date-fns-tz": "^1.1.6", "date-fns-tz": "^1.1.6",
"ldapts": "^3.1.0",
"fs-extra": "^10.0.0", "fs-extra": "^10.0.0",
"image-size": "^1.0.0", "image-size": "^1.0.0",
"next": "11.0.1", "next": "11.0.1",

View File

@ -0,0 +1,6 @@
.table {
display: table;
width: 100%;
margin-top: calc(20rem / 16);
margin-bottom: calc(60rem / 16);
}

65
pages/about/members.tsx Normal file
View File

@ -0,0 +1,65 @@
import { GetStaticProps } from "next";
import React from "react";
import { Link } from "@/components/Link";
import { Table } from "@/components/Table";
import { getCurrentTerm } from "@/lib/events";
import { getMembers, Member } from "@/lib/members";
import { capitalize } from "@/utils";
import styles from "./members.module.css";
interface Props {
members: Member[];
year: string;
term: string;
}
export default function Members(props: Props) {
return (
<>
<h1>Members</h1>
<p>
{`The members for ${capitalize(props.term)} ${
props.year
} are listed here. We currently
have ${props.members.length} members. Use of this list for solicitation
of any form is prohibited, if you wish to get in touch with the
membership as a whole please contact the Executive.`}
</p>
<Table className={styles.table}>
<thead>
<tr>
<th>Name / Webpage</th>
<th>Program</th>
<th>Userid</th>
</tr>
</thead>
<tbody>
{props.members.map((member) => (
<tr key={member.id}>
<td>
<Link href={`https://csclub.uwaterloo.ca/~${member.id}/`}>
{member.name}
</Link>
</td>
<td>{member.program}</td>
<td>{member.id}</td>
</tr>
))}
</tbody>
</Table>
</>
);
}
export const getStaticProps: GetStaticProps<Props> = async () => {
const curTerm = getCurrentTerm();
return {
props: {
year: curTerm.year,
term: curTerm.term,
members: await getMembers(curTerm.year, curTerm.term),
},
};
};