117 lines
4.0 KiB
TypeScript
117 lines
4.0 KiB
TypeScript
|
|
import { format } from 'date-fns'
|
|
import * as jdenticon from 'jdenticon'
|
|
import { Role } from '../../generated/prisma'
|
|
import { isModerator, hasRole } from './privs'
|
|
import { signUrl } from './cdn'
|
|
import { extractBasePath } from './filesystem'
|
|
import { formatDuration, truncate } from './formatters.ts'
|
|
import { icons } from './icons.ts'
|
|
import logger from './logger.ts'
|
|
import HandlebarsLib, { HelperOptions, SafeString } from 'handlebars';
|
|
import { env } from '../config/env.ts'
|
|
import { basename } from 'node:path'
|
|
import { constants } from '../config/constants.ts'
|
|
|
|
export function registerHbsHelpers(Handlebars: typeof HandlebarsLib) {
|
|
|
|
Handlebars.registerHelper('formatDate', function (dateString) {
|
|
if (!dateString) return ''
|
|
return format(new Date(dateString), 'yyyy-MM-dd')
|
|
})
|
|
Handlebars.registerHelper('formatDuration', function (duration) {
|
|
return formatDuration(duration)
|
|
})
|
|
Handlebars.registerHelper('identicon', function (str, size = 48) {
|
|
return jdenticon.toSvg(str, size)
|
|
})
|
|
Handlebars.registerHelper('safeJson', function (context) {
|
|
return new Handlebars.SafeString(JSON.stringify(context));
|
|
});
|
|
Handlebars.registerHelper('json', function (context) {
|
|
return JSON.stringify(context)
|
|
})
|
|
Handlebars.registerHelper('patron', function (user) {
|
|
if (!user.roles) {
|
|
throw new Error(
|
|
'patron hbs helper was called without roles. This usually means you forgot to include roles relationship in the query.'
|
|
);
|
|
}
|
|
return user.roles.some((r: Role) => r.name.startsWith('supporter'));
|
|
});
|
|
Handlebars.registerHelper('notEqual', function (a, b) {
|
|
return a !== b;
|
|
});
|
|
Handlebars.registerHelper('isEqual', function (a, b) {
|
|
logger.trace(`isEqual a=${a} b=${b}`)
|
|
return a == b
|
|
});
|
|
Handlebars.registerHelper('isModerator', function (user) {
|
|
return isModerator(user)
|
|
})
|
|
Handlebars.registerHelper('hasRole', hasRole)
|
|
Handlebars.registerHelper('breaklines', function (text) {
|
|
text = Handlebars.Utils.escapeExpression(text);
|
|
text = text.replace(/(\r\n|\n|\r)/gm, '<br>');
|
|
return new Handlebars.SafeString(text);
|
|
});
|
|
Handlebars.registerHelper('getCdnUrl', function (s3Key) {
|
|
// Before you remove this log, find a way to memoize this function!
|
|
logger.info(`getCdnUrl called with CDN_ORIGIN=${env.CDN_ORIGIN} and CDN_TOKEN_SECRET=${env.CDN_TOKEN_SECRET}`)
|
|
return signUrl(`${env.CDN_ORIGIN}/${s3Key}`, {
|
|
securityKey: env.CDN_TOKEN_SECRET,
|
|
expirationTime: constants.timeUnits.sevenDaysInSeconds,
|
|
})
|
|
})
|
|
/**
|
|
* @see https://github.com/video-dev/hls.js/issues/2152
|
|
*/
|
|
Handlebars.registerHelper('signedHlsUrl', function (s3Key) {
|
|
if (!s3Key) throw new Error(`signedHlsUrl called with falsy s3Key=${s3Key}`);
|
|
const pathAllowed = extractBasePath(s3Key)
|
|
const url = signUrl(`${env.CDN_ORIGIN}/${s3Key}`, {
|
|
securityKey: env.CDN_TOKEN_SECRET,
|
|
pathAllowed,
|
|
isDirectory: true,
|
|
expirationTime: constants.timeUnits.sevenDaysInSeconds,
|
|
})
|
|
logger.debug(`pathAllowed=${pathAllowed} url=${url}`)
|
|
return url
|
|
})
|
|
Handlebars.registerHelper('basename', function (url: string) {
|
|
return basename(url)
|
|
})
|
|
Handlebars.registerHelper('trunc', function (str, length = 6) {
|
|
return truncate(str, length)
|
|
});
|
|
Handlebars.registerHelper('icon', function (
|
|
name: string,
|
|
size = 20,
|
|
color?: string,
|
|
options?: any
|
|
) {
|
|
// Handle case where color is omitted but options object is passed
|
|
if (typeof color === 'object' && color !== null && 'hash' in color) {
|
|
options = color;
|
|
color = undefined;
|
|
}
|
|
|
|
const svg = icons[name];
|
|
|
|
if (!svg) {
|
|
return new Handlebars.SafeString(`<!-- icon "${name}" not found -->`);
|
|
}
|
|
|
|
const finalColor = color || 'currentColor';
|
|
|
|
// Remove any existing width, height, and fill attributes
|
|
let sizedSvg = svg
|
|
.replace(/\s(width|height|fill)="[^"]*"/g, '')
|
|
// Inject our width, height, and fill
|
|
.replace(/<svg([^>]*)>/, `<svg$1 width="${size}" height="${size}" fill="${finalColor}">`);
|
|
|
|
return new Handlebars.SafeString(sizedSvg);
|
|
});
|
|
|
|
|
|
} |