From c5840770145bf53201b08c6017faa737f5cb16cf Mon Sep 17 00:00:00 2001 From: Florrie Date: Wed, 14 Nov 2018 22:29:06 -0400 Subject: Do cleaner, slightly less regex-y URL handling --- index.js | 203 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 101 insertions(+), 102 deletions(-) diff --git a/index.js b/index.js index 1ad3e1f..2e5202a 100755 --- a/index.js +++ b/index.js @@ -75,6 +75,7 @@ const getUser = function(username) { } const last = arr => arr[arr.length - 1] +const compareArr = (a1, a2) => a1.length === a2.length && a1.every((x, i) => typeof a2[i] === 'function' ? a2[i](x) : a2[i] === x) const filterHTML = text => text.replace(//g, '>') const pluralize = (word, n) => n === 1 ? word : word + 's' @@ -225,6 +226,8 @@ const handleRequest = async (request, response) => { const queryData = qs.parse(query) const cookie = parseCookies(request) + const urlParts = pathname.split('/').filter(Boolean) + // Not used by nearly all paths, but available to all for convenience. let { page: pageNumber = 1 } = queryData pageNumber = parseInt(pageNumber) @@ -234,69 +237,68 @@ const handleRequest = async (request, response) => { pageNumber = Math.max(1, pageNumber) } + if (compareArr(urlParts, ['login'])) { + if (request.method === 'GET') { + await page(request, response, fixWS` +

Login

+
+

+

+

+

+

+
+ `) - if (request.url === '/login') { - await page(request, response, fixWS` -

Login

-
-

-

-

-

-

-
- `) - - return - } - - if (request.url === '/post-login') { - const { username, token, sessionid, csrftoken } = await getData(request) + return + } else if (request.method === 'POST') { + const { username, token, sessionid, csrftoken } = await getData(request) - response.setHeader('Set-Cookie', [ - `username=${username}; HttpOnly`, - `token=${token}; HttpOnly`, - `sessionid=${sessionid}; HttpOnly`, - `csrftoken=${csrftoken}; HttpOnly` - ]) + response.setHeader('Set-Cookie', [ + `username=${username}; HttpOnly`, + `token=${token}; HttpOnly`, + `sessionid=${sessionid}; HttpOnly`, + `csrftoken=${csrftoken}; HttpOnly` + ]) - request.headers.cookie = response.getHeader('Set-Cookie').join(';') // Cheating! To make the header show right. + request.headers.cookie = response.getHeader('Set-Cookie').join(';') // Cheating! To make the header show right. - await page(request, response, fixWS` -

Okay, you're logged in.

- `) + await page(request, response, fixWS` +

Okay, you're logged in.

+ `) - return + return + } } - if (request.url === '/logout') { - await page(request, response, fixWS` -

Log Out

-
-

Are you sure you want to log out?

-

-
- `) - - return - } + if (compareArr(urlParts, ['logout'])) { + if (request.method === 'GET') { + await page(request, response, fixWS` +

Log Out

+
+

Are you sure you want to log out?

+

+
+ `) - if (request.url === '/post-logout') { - const { username, token, sessionid, csrftoken } = await getData(request) + return + } else if (request.method === 'POST') { + const { username, token, sessionid, csrftoken } = await getData(request) - const clearCookie = name => `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT` + const clearCookie = name => `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT` - request.headers.cookie = '' // Cheating, kind of, but to make the header print right :) - response.setHeader('Set-Cookie', ['username', 'token', 'sessionid', 'csrftoken'].map(clearCookie)) + request.headers.cookie = '' // Cheating, kind of, but to make the header print right :) + response.setHeader('Set-Cookie', ['username', 'token', 'sessionid', 'csrftoken'].map(clearCookie)) - await page(request, response, fixWS` -

Okay, you've been logged out.

- `) + await page(request, response, fixWS` +

Okay, you've been logged out.

+ `) - return + return + } } - if (pathname === '/notifications') { + if (compareArr(urlParts, ['notifications'])) { if (!cookie.username) { await page(request, response, fixWS`

Sorry, you can't view your notifications until you've logged in.

@@ -318,7 +320,7 @@ const handleRequest = async (request, response) => { -
+

` @@ -342,21 +344,22 @@ const handleRequest = async (request, response) => { return } - if (pathname === '/mark-notifications-as-read') { - await markNotificationsAsRead(cookie.sessionid, cookie.csrftoken) + if (compareArr(urlParts, ['notifications', 'mark-as-read'])) { + if (request.method === 'POST') { + await markNotificationsAsRead(cookie.sessionid, cookie.csrftoken) - response.writeHead(302, { - 'Location': '/notifications' - }) + response.writeHead(302, { + 'Location': '/notifications' + }) - response.end() + response.end() - return + return + } } - const projectMatch = pathname.match(/^\/projects\/([0-9]*)\/?/) - if (projectMatch) { - const projectID = projectMatch[1] + if (compareArr(urlParts, ['projects', id => /^[0-9]*$/.test(id)])) { + const projectID = urlParts[1] const project = await getProject(projectID, cookie.token) if (project.code === 'NotFound') { @@ -398,13 +401,44 @@ const handleRequest = async (request, response) => { return } - const userMatch = pathname.match(/^\/users\/([a-zA-Z0-9\-_]*)(\/[^/]*$)?/) - if (userMatch) buildUserPage: { - const username = userMatch[1] + if (compareArr(urlParts.slice(0, 2), ['users', name => /^[a-zA-Z0-9\-_]*$/.test(name)])) { + const username = urlParts[1] const user = await getUser(username) - const path = userMatch[2] - if (path === '/projects') { + if (user.code === 'NotFound') { + await page(request, response, fixWS` + 404. Sorry, that user doesn't exist. + `) + return + } + + if (urlParts.length === 2) { + const projects = await fetch(`https://api.scratch.mit.edu/users/${username}/projects?limit=5`).then(res => res.json()) + const projectsText = projects.map(templates.projectThumbnail).join('\n') + + await page(request, response, fixWS` +

This user's profile picture ${user.username}

+ ${user.profile.bio ? fixWS` +

About Me

+ ${templates.longField(user.profile.bio)} + ` : fixWS` +

(No "about me".)

+ `} + ${user.profile.status ? fixWS` +

What I'm Working On

+ ${templates.longField(user.profile.status)} + ` : fixWS` +

(No "what I'm working on".)

+ `} +

Projects

+ +

See all!

+ `) + + return + } else if (compareArr(urlParts.slice(2), ['projects'])) { const offset = (pageNumber - 1) * limit const projects = await fetch(`https://api.scratch.mit.edu/users/${username}/projects?limit=${limit}&offset=${offset}`).then(res => res.json()) const projectsText = projects.map(templates.projectThumbnail).join('\n') @@ -420,45 +454,10 @@ const handleRequest = async (request, response) => { `) return - } else if (path && path !== '/') { - break buildUserPage // 404 } - - if (username.code === 'NotFound') { - await page(request, response, fixWS` - Sorry, that user doesn't exist. - `) - return - } - - const projects = await fetch(`https://api.scratch.mit.edu/users/${username}/projects?limit=5`).then(res => res.json()) - const projectsText = projects.map(templates.projectThumbnail).join('\n') - - await page(request, response, fixWS` -

This user's profile picture ${user.username}

- ${user.profile.bio ? fixWS` -

About Me

- ${templates.longField(user.profile.bio)} - ` : fixWS` -

(No "about me".)

- `} - ${user.profile.status ? fixWS` -

What I'm Working On

- ${templates.longField(user.profile.status)} - ` : fixWS` -

(No "what I'm working on".)

- `} -

Projects

- -

See all!

- `) - - return } - if (pathname === '/style.css') { + if (compareArr(urlParts, ['style.css'])) { response.writeHead(200, { 'Content-Type': 'text/css' }) @@ -468,7 +467,7 @@ const handleRequest = async (request, response) => { return } - if (pathname === '/') { + if (urlParts.length === 0) { await page(request, response, fixWS` You are at the homepage. Sorry, I haven't implmented any content for it yet. `) -- cgit 1.3.0-6-gf8a5