Skip to content

Commit

Permalink
Merge branch 'pbock-main'
Browse files Browse the repository at this point in the history
  • Loading branch information
pbock committed Dec 16, 2023
2 parents 54e1d36 + 04cb153 commit 1e4d34f
Show file tree
Hide file tree
Showing 11 changed files with 2,769 additions and 3,781 deletions.
32 changes: 15 additions & 17 deletions find-orphaned-files.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
'use strict';

import path = require('path');
import _ = require('lodash');
import TalkModel from './models/talks';
import { resolve } from 'path';
import * as config from './config';
import TalkModel from './models/talks';

const schedulePath = path.resolve(__dirname, 'schedule.json');
const filesBase = path.resolve(__dirname, 'files/');
const schedulePath = resolve(__dirname, 'schedule.json');
const filesBase = resolve(__dirname, 'files/');

const Talk = TalkModel(config, filesBase);

Promise.all([ Talk.all(), Talk._getAllFiles() ])
.then(([ talks, files ]) => {
_(files)
.each((meta, filePath) => {
if (!meta.isDir) return;
Promise.all([Talk.all(), Talk._getAllFiles()])
.then(([talks, files]) => {
Object.entries(files).forEach(([filePath, meta]) => {
if (!meta.isDir) return;
// Ignore root-level directory
const nestLevel = filePath.split('/').length - schedulePath.split('/').length;
if (nestLevel < 1) return;

const matchingTalk = _(talks).find(t => t.filePath === filePath);
if (!matchingTalk) {
console.warn(filePath);
}
})
})
.then(() => process.exit())
const matchingTalk = talks.find((t) => t.filePath === filePath);
if (!matchingTalk) {
console.warn(filePath);
}
});
})
.then(() => process.exit());
122 changes: 53 additions & 69 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import path = require('path');
import bunyan = require('bunyan');
import express = require('express');
import multer = require('multer');
import i18n = require('i18n');
import URL = require('url');
import moment = require('moment');
import _ = require('lodash');
import archiver = require('archiver');
import * as archiver from 'archiver';
import * as bunyan from 'bunyan';
import * as express from 'express';
import * as i18n from 'i18n';
import * as _ from 'lodash';
import * as moment from 'moment';
import * as multer from 'multer';
import * as path from 'path';
import * as URL from 'url';

// Middleware
import cookieParser = require('cookie-parser');
import helmet = require('helmet');
import basicAuth = require('basic-auth');
import * as basicAuth from 'basic-auth';
import * as cookieParser from 'cookie-parser';
import helmet from 'helmet';

// Models
import TalkModel, { TalkFile } from './models/talks';
Expand Down Expand Up @@ -108,7 +108,7 @@ function checkAuth(
return authorized;
}

app.use(cookieParser());
app.use(cookieParser() as any);
app.use(checkAuth);

app.use((req, res, next) => {
Expand All @@ -130,16 +130,16 @@ app.set('view engine', 'pug');

app.use(
'/vendor/bootstrap',
express.static(path.resolve(__dirname, 'node_modules/bootstrap/dist/'))
express.static(path.resolve(__dirname, 'node_modules/bootstrap/dist/')) as any
);
app.use('/static', express.static(path.resolve(__dirname, 'static/')));
app.use('/static', express.static(path.resolve(__dirname, 'static/')) as any);

app.locals.moment = moment;

app.get('/', (req: PotentiallyAuthenticatedRequest, res) => {
const { isAuthorized } = req;
const scheduleVersion = Talk.getScheduleVersion();
return Talk.allSorted().then(talks =>
return Talk.allSorted().then((talks) =>
res.render('index', { talks, isAuthorized, eventName, scheduleVersion })
);
});
Expand All @@ -157,80 +157,70 @@ function ensureExistence<T>(thing?: T | null): T {
return thing;
}

app.get('/talks/:slug', (req: PotentiallyAuthenticatedRequest, res, next) => {
app.get('/talks/:id', (req: PotentiallyAuthenticatedRequest, res, next) => {
const { uploadCount, commentCount, nothingReceived } = req.query;
const { isAuthorized } = req;
return (
Talk.findBySlug(req.params.slug)
.then(ensureExistence)
.then(async talk => {
if (req.isAuthorized) {
const comments = await talk.getComments();
// FIXME: This destroys the getter
return { talk, comments };
}
return { talk };
})
.then(({ talk, comments }) => {
res.render('talk', {
eventName,
talk,
comments,
uploadCount,
commentCount,
nothingReceived,
isAuthorized,
});
})
// If that failed, try looking the talk up by ID instead
.catch(() =>
Talk.findById(req.params.slug)
.then(ensureExistence)
.then(talk => res.redirect(`/talks/${talk.slug}/`))
)
.catch(next)
);
return Talk.findById(req.params.id)
.then(ensureExistence)
.then(async (talk) => {
if (req.isAuthorized) {
const comments = await talk.getComments();
// FIXME: This destroys the getter
return { talk, comments };
}
return { talk };
})
.then(({ talk, comments }) => {
res.render('talk', {
talk,
comments,
uploadCount,
commentCount,
nothingReceived,
isAuthorized,
});
})
.catch(next);
});

app.get('/sign-in', forceAuth, (req, res) => {
res.redirect('/');
});

app.post('/talks/:slug/files/', upload.any(), (req, res, next) => {
app.post('/talks/:id/files/', upload.any() as any, (req, res, next) => {
let requestTalk;
const { body } = req;
const files = req.files as Express.Multer.File[];
if (!files.length && !body.comment) {
log.info('Form submitted, but no files and no comment received');
res.redirect(`/talks/${req.params.slug}/?nothingReceived=true`);
res.redirect(`/talks/${req.params.id}/?nothingReceived=true`);
return;
}
log.info({ files, body }, 'Files received');
const findTalk = body.id ? Talk.findById(body.id) : Talk.findBySlug(req.params.slug);
return findTalk
return Talk.findById(req.params.id)
.then(ensureExistence)
.then(talk => {
.then((talk) => {
requestTalk = talk;
const tasks = [];
if (files.length) tasks.push(talk.addFiles(files));
if (body.comment) tasks.push(talk.addComment(body.comment));
return Promise.all(tasks).then(() => talk);
})
.then(talk => {
.then((talk) => {
res.redirect(
`/talks/${talk.slug}/?uploadCount=${files.length}&commentCount=${body.comment ? '1' : '0'}`
`/talks/${talk.id}/?uploadCount=${files.length}&commentCount=${body.comment ? '1' : '0'}`
);
})
.catch(err => {
.catch((err) => {
log.error(err, 'Failed to add files');
next(err);
});
});

app.get('/talks/:slug/files.zip', forceAuth, (req, res, next) => {
return Talk.findBySlug(req.params.slug)
app.get('/talks/:id/files.zip', forceAuth, (req, res, next) => {
return Talk.findById(req.params.id)
.then(ensureExistence)
.then(talk => {
.then((talk) => {
const archive = archiver('zip');
archive.directory(talk.filePath, '/');
archive.on('error', next);
Expand All @@ -244,10 +234,10 @@ app.get('/talks/:slug/files.zip', forceAuth, (req, res, next) => {
.catch(next);
});

app.get('/talks/:slug/files/:filename', forceAuth, (req, res, next) => {
return Talk.findBySlug(req.params.slug)
app.get('/talks/:id/files/:filename', forceAuth, (req, res, next) => {
return Talk.findById(req.params.id)
.then(ensureExistence)
.then(talk => {
.then((talk) => {
const file = _.find(talk.files, { name: req.params.filename }) as TalkFile;
if (!file) {
const error = new Error404('File not found');
Expand All @@ -258,16 +248,10 @@ app.get('/talks/:slug/files/:filename', forceAuth, (req, res, next) => {
.catch(next);
});

app.get('/talks/:slug/files/', (req, res) => {
res.redirect(`/${req.params.slug}/`);
app.get('/talks/:id/files/', (req, res) => {
res.redirect(`/talks/${req.params.id}/`);
});

// app.get('/:slug/files/:file', (req, res, next) => {
// return Talk.findBySlug(req.params.slug)
// .then(talk => { talk.readFile(req.params.file).pipe(res) })
// .catch(next)
// })

app.use((req, res, next) => {
log.info(`%s %s Request didn't match a route`, req.method, req.url);
res.status(404).render('error', { status: 404 });
Expand Down
2 changes: 1 addition & 1 deletion lib/__tests__/redact-filename.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import redactFilename from '../react-filename';
import redactFilename from '../redact-filename';

describe('redactFilename', () => {
it('only shows the extension and the first and last two characters', () => {
Expand Down
6 changes: 3 additions & 3 deletions lib/react-filename.ts → lib/redact-filename.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import path = require('path');
import { extname, basename } from 'path';

export default function redactFilename(filename: string): string {
const extension = path.extname(filename);
const base = path.basename(filename, extension);
const extension = extname(filename);
const base = basename(filename, extension);
if (base.length < 5) return base + extension;
return `${base.substr(0, 2)}[…]${base.substr(-2)}${extension}`;
}
13 changes: 6 additions & 7 deletions lib/stream-hash.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
'use strict';

import crypto = require('crypto');
import fs = require('fs');
import { createHash, type Encoding } from 'crypto';
import { createReadStream } from 'fs';
import { Stream } from 'stream';
import { Utf8AsciiLatin1Encoding } from 'crypto';

export default function streamHash(
firstParam: Stream | string,
algorithm = 'sha1',
encoding: Utf8AsciiLatin1Encoding = 'utf8'
encoding: Encoding = 'utf8'
): Promise<string> {
const stream = typeof firstParam === 'string' ? fs.createReadStream(firstParam) : firstParam;
const hash = crypto.createHash(algorithm);
const stream = typeof firstParam === 'string' ? createReadStream(firstParam) : firstParam;
const hash = createHash(algorithm);
return new Promise((resolve, reject) => {
stream.on('data', chunk => hash.update(chunk, encoding));
stream.on('data', (chunk) => hash.update(chunk, encoding));
stream.on('end', () => resolve(hash.digest('hex')));
stream.on('error', reject);
});
Expand Down
6 changes: 4 additions & 2 deletions lib/wait-promise.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export default function wait(timeout: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, timeout));
export default function wait(timeout: number) {
return function <T>(arg?: T): Promise<T> {
return new Promise((resolve) => setTimeout(() => resolve(arg as T), timeout));
};
}
Loading

0 comments on commit 1e4d34f

Please sign in to comment.