wip
This commit is contained in:
parent
7114830582
commit
9321750461
Binary file not shown.
|
@ -1,92 +0,0 @@
|
|||
import autoprefixer from 'autoprefixer';
|
||||
|
||||
const Util = require('./src/api/utils/Util');
|
||||
|
||||
export default {
|
||||
ssr: true,
|
||||
srcDir: 'src/site/',
|
||||
head: {
|
||||
title: Util.config.serviceName,
|
||||
titleTemplate: `%s | ${Util.config.serviceName}`,
|
||||
// TODO: Add the directory with pictures for favicon and stuff
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{ hid: 'theme-color', name: 'theme-color', content: `${Util.config.metaThemeColor}` },
|
||||
{ hid: 'description', name: 'description', content: `${Util.config.metaDescription}` },
|
||||
{ hid: 'keywords', name: 'keywords', content: `${Util.config.metaKeywords}` },
|
||||
{
|
||||
hid: 'apple-mobile-web-app-title',
|
||||
name: 'apple-mobile-web-app-title',
|
||||
content: `${Util.config.serviceName}`
|
||||
},
|
||||
{ hid: 'application-name', name: 'application-name', content: `${Util.config.serviceName}` },
|
||||
{ hid: 'twitter:card', name: 'twitter:card', content: 'summary' },
|
||||
{ hid: 'twitter:site', name: 'twitter:site', content: `${Util.config.metaTwitterHandle}` },
|
||||
{ hid: 'twitter:creator', name: 'twitter:creator', content: `${Util.config.metaTwitterHandle}` },
|
||||
{ hid: 'twitter:title', name: 'twitter:title', content: `${Util.config.serviceName}` },
|
||||
{ hid: 'twitter:description', name: 'twitter:description', content: `${Util.config.metaDescription}` },
|
||||
{ hid: 'twitter:image', name: 'twitter:image', content: `/logo.png` },
|
||||
{ hid: 'og:url', property: 'og:url', content: `/` },
|
||||
{ hid: 'og:type', property: 'og:type', content: 'website' },
|
||||
{ hid: 'og:title', property: 'og:title', content: `${Util.config.serviceName}` },
|
||||
{ hid: 'og:description', property: 'og:description', content: `${Util.config.metaDescription}` },
|
||||
{ hid: 'og:image', property: 'og:image', content: `/logo.png` },
|
||||
{ hid: 'og:image:secure_url', property: 'og:image:secure_url', content: `/logo.png` },
|
||||
{ hid: 'og:site_name', property: 'og:site_name', content: `${Util.config.serviceName}` }
|
||||
],
|
||||
link: [
|
||||
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Nunito:300,400,600,700', },
|
||||
|
||||
// This one is a pain in the ass to make it customizable, so you should edit it manually
|
||||
{ type: 'application/json+oembed', href: `/oembed.json` }
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
'~/plugins/axios',
|
||||
'~/plugins/buefy',
|
||||
'~/plugins/v-clipboard',
|
||||
'~/plugins/vue-isyourpasswordsafe',
|
||||
'~/plugins/vue-timeago',
|
||||
'~/plugins/vuebar',
|
||||
'~/plugins/notifier',
|
||||
'~/plugins/handler',
|
||||
],
|
||||
css: [],
|
||||
modules: ['@nuxtjs/axios', 'cookie-universal-nuxt',],
|
||||
router: {
|
||||
linkActiveClass: 'is-active',
|
||||
linkExactActiveClass: 'is-active',
|
||||
},
|
||||
env: {
|
||||
development: process.env.NODE_ENV !== 'production'
|
||||
},
|
||||
axios: {
|
||||
baseURL: `${process.env.NODE_ENV === 'production' ? process.env.DOMAIN : 'http://localhost:5000'}/api`
|
||||
},
|
||||
build: {
|
||||
extractCSS: process.env.NODE_ENV === 'production',
|
||||
postcss: {
|
||||
preset: {
|
||||
autoprefixer,
|
||||
},
|
||||
},
|
||||
axios: {
|
||||
baseURL: `${process.env.NODE_ENV === 'production' ? process.env.DOMAIN : 'http://localhost:5000'}/api`
|
||||
},
|
||||
build: {
|
||||
extractCSS: process.env.NODE_ENV === 'production',
|
||||
postcss: {
|
||||
preset: {
|
||||
autoprefixer
|
||||
}
|
||||
},
|
||||
extend(config, { isDev }) {
|
||||
// Extend only webpack config for client-bundle
|
||||
if (isDev) {
|
||||
config.devtool = 'source-map';
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
|
@ -9,7 +9,8 @@
|
|||
"url": "https://github.com/Pitu"
|
||||
},
|
||||
"scripts": {
|
||||
"setup": "node src/setup.js && npm run migrate && npm run seed",
|
||||
"setup": "node src/api/scripts/setup.ts && npm run migrate && npm run seed",
|
||||
"build": "tsc --noEmit",
|
||||
"start": "npm run migrate && nuxt build && cross-env NODE_ENV=production node src/api/main.ts",
|
||||
"dev": "nodemon src/api/main.ts",
|
||||
"migrate": "knex migrate:latest",
|
||||
|
|
|
@ -9,7 +9,8 @@ import rateLimit from 'fastify-rate-limit';
|
|||
import jetpack from 'fs-jetpack';
|
||||
// import cron from 'cron';
|
||||
// @ts-ignore - nuxt types can't be found - https://github.com/nuxt/nuxt.js/issues/7651
|
||||
// import { loadNuxt, build } from 'nuxt';
|
||||
import { Nuxt, Builder } from 'nuxt';
|
||||
import nuxtDefaults from './structures/nuxt';
|
||||
|
||||
import Routes from './structures/routes';
|
||||
|
||||
|
@ -91,7 +92,19 @@ const start = async () => {
|
|||
root: path.join(__dirname, '../../uploads')
|
||||
});
|
||||
|
||||
// TODO: Enable this after Utils is ported to TypeScript
|
||||
const nuxtConfig = await nuxtDefaults();
|
||||
nuxtConfig.dev = !(process.env.NODE_ENV === 'production');
|
||||
const nuxt = new Nuxt(nuxtConfig);
|
||||
if (nuxtConfig.dev) {
|
||||
const builder = new Builder(nuxt);
|
||||
await builder.build();
|
||||
} else {
|
||||
await nuxt.ready();
|
||||
}
|
||||
|
||||
void server.register(nuxt.render);
|
||||
|
||||
|
||||
/*
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
const nuxt = await loadNuxt(isProd ? 'start' : 'dev');
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { FastifyReply, HookHandlerDoneFunction } from 'fastify';
|
||||
import type { RequestWithUser } from './auth';
|
||||
import type { RequestWithUser } from '../structures/interfaces';
|
||||
|
||||
export default (req: RequestWithUser, res: FastifyReply, next: HookHandlerDoneFunction) => {
|
||||
if (!req.user.isAdmin) return res.status(401).send({ message: 'Permission denied' });
|
||||
|
|
|
@ -1,13 +1,7 @@
|
|||
import type { FastifyRequest, FastifyReply, HookHandlerDoneFunction } from 'fastify';
|
||||
import type { FastifyReply, HookHandlerDoneFunction } from 'fastify';
|
||||
import type { RequestWithUser } from '../structures/interfaces';
|
||||
import prisma from '../structures/database';
|
||||
|
||||
export interface RequestWithUser extends FastifyRequest {
|
||||
user: {
|
||||
id: number;
|
||||
username: string | null;
|
||||
isAdmin: boolean | null;
|
||||
};
|
||||
}
|
||||
|
||||
export default async (req: RequestWithUser, res: FastifyReply, next: HookHandlerDoneFunction) => {
|
||||
// TODO: Search for canApiKey in the codebase and add this file as middleware on those, before auth
|
||||
|
|
|
@ -11,12 +11,12 @@ datasource db {
|
|||
|
||||
model albums {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int?
|
||||
name String?
|
||||
userId Int
|
||||
name String
|
||||
zippedAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
editedAt DateTime?
|
||||
nsfw Boolean? @default(false)
|
||||
nsfw Boolean @default(false)
|
||||
|
||||
@@unique([userId, name], name: "albums_userid_name_unique")
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@ interface params {
|
|||
interface UserWithFileCount extends User {
|
||||
fileCount?: number;
|
||||
}
|
||||
|
||||
export const middlewares = ['auth', 'admin'];
|
||||
|
||||
export const run = async (req: FastifyRequest, res: FastifyReply) => {
|
||||
const { id } = req.params as params;
|
||||
if (!id) return res.status(400).send({ message: 'Invalid file ID supplied' });
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import type { FastifyRequest, FastifyReply } from 'fastify';
|
||||
import prisma from '../../../../structures/database';
|
||||
import { constructFilePublicLink } from '../../../../utils/Util';
|
||||
|
||||
export const middlewares = ['auth', 'admin'];
|
||||
|
||||
interface params {
|
||||
id: number;
|
||||
}
|
||||
export const run = async (req: FastifyRequest, res: FastifyReply) => {
|
||||
const { id } = req.params as params;
|
||||
if (!id) return res.status(400).send({ message: 'Invalid user ID supplied' });
|
||||
|
||||
const { page = 1, limit = 100 } = req.query as { page: number; limit: number };
|
||||
|
||||
const user = await prisma.users.findUnique({
|
||||
where: {
|
||||
id
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
enabled: true,
|
||||
isAdmin: true,
|
||||
createdAt: true,
|
||||
editedAt: true,
|
||||
apiKeyEditedAt: true
|
||||
}
|
||||
});
|
||||
|
||||
if (!user) return res.status(404).send({ message: 'User not found' });
|
||||
|
||||
const count = await prisma.files.count({
|
||||
where: {
|
||||
userId: user.id
|
||||
}
|
||||
});
|
||||
|
||||
const files = await prisma.files.findMany({
|
||||
take: limit,
|
||||
skip: (page - 1) * limit,
|
||||
where: {
|
||||
userId: user.id
|
||||
}
|
||||
});
|
||||
|
||||
const readyFiles = [];
|
||||
for (const file of files) {
|
||||
readyFiles.push(constructFilePublicLink(req, file));
|
||||
}
|
||||
|
||||
return res.send({
|
||||
message: 'Successfully retrieved users',
|
||||
user,
|
||||
files: readyFiles,
|
||||
count
|
||||
});
|
||||
};
|
|
@ -1,55 +0,0 @@
|
|||
const Route = require('../../structures/Route');
|
||||
const Util = require('../../utils/Util');
|
||||
|
||||
class usersGET extends Route {
|
||||
constructor() {
|
||||
super('/admin/users/:id', 'get', { adminOnly: true });
|
||||
}
|
||||
|
||||
async run(req, res, db) {
|
||||
const { id } = req.params;
|
||||
if (!id) return res.status(400).json({ message: 'Invalid user ID supplied' });
|
||||
|
||||
try {
|
||||
const user = await db.table('users')
|
||||
.select('id', 'username', 'enabled', 'createdAt', 'editedAt', 'apiKeyEditedAt', 'isAdmin')
|
||||
.where({ id })
|
||||
.first();
|
||||
|
||||
let count = 0;
|
||||
let files = db.table('files')
|
||||
.where({ userId: user.id })
|
||||
.orderBy('id', 'desc');
|
||||
|
||||
const { page, limit = 100 } = req.query;
|
||||
if (page && page >= 0) {
|
||||
files = await files.offset((page - 1) * limit).limit(limit);
|
||||
|
||||
const dbRes = await db.table('files')
|
||||
.count('* as count')
|
||||
.where({ userId: user.id })
|
||||
.first();
|
||||
|
||||
count = dbRes.count;
|
||||
} else {
|
||||
files = await files; // execute the query
|
||||
count = files.length;
|
||||
}
|
||||
|
||||
for (let file of files) {
|
||||
file = Util.constructFilePublicLink(req, file);
|
||||
}
|
||||
|
||||
return res.json({
|
||||
message: 'Successfully retrieved user',
|
||||
user,
|
||||
files,
|
||||
count
|
||||
});
|
||||
} catch (error) {
|
||||
return super.error(res, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = usersGET;
|
|
@ -0,0 +1,45 @@
|
|||
import type { FastifyReply } from 'fastify';
|
||||
import prisma from '../../../../../structures/database';
|
||||
import { RequestWithUser } from '../../../../../structures/interfaces';
|
||||
|
||||
interface body {
|
||||
identifier: string;
|
||||
}
|
||||
export const middlewares = ['auth'];
|
||||
|
||||
export const run = async (req: RequestWithUser, res: FastifyReply) => {
|
||||
if (!req.params) return res.status(400).send({ message: 'No body provided' });
|
||||
const { identifier } = req.body as body;
|
||||
if (!identifier) return res.status(400).send({ message: 'No ip provided' });
|
||||
|
||||
const link = await prisma.links.findFirst({
|
||||
where: {
|
||||
identifier,
|
||||
userId: req.user.id
|
||||
}
|
||||
});
|
||||
|
||||
await prisma.links.delete({
|
||||
where: {
|
||||
links_userid_albumid_identifier_unique: {
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const albumLink = await prisma.albumsLinks.findFirst({
|
||||
where: {
|
||||
linkId: link.id
|
||||
}
|
||||
});
|
||||
|
||||
await prisma.albumsLinks.delete({
|
||||
where: {
|
||||
id: albumLink.id
|
||||
}
|
||||
});
|
||||
|
||||
return res.send({
|
||||
message: 'Successfully banned the ip'
|
||||
});
|
||||
};
|
|
@ -1,21 +0,0 @@
|
|||
const Route = require('../structures/Route');
|
||||
|
||||
class verifyGET extends Route {
|
||||
constructor() {
|
||||
super('/verify', 'get');
|
||||
}
|
||||
|
||||
run(req, res, db, user) {
|
||||
return res.json({
|
||||
message: 'Successfully verified token',
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
isAdmin: user.isAdmin,
|
||||
apiKey: user.apiKey
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = verifyGET;
|
|
@ -5,7 +5,7 @@ export interface RequestWithUser extends FastifyRequest {
|
|||
id: number;
|
||||
username: string;
|
||||
isAdmin: boolean;
|
||||
apiKey?: string;
|
||||
apiKey?: string | null | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -24,15 +24,15 @@ export interface User {
|
|||
|
||||
export interface File {
|
||||
id: number;
|
||||
userId?: number;
|
||||
userId?: number | null;
|
||||
name: string;
|
||||
original: string;
|
||||
type: string;
|
||||
size: number;
|
||||
hash: string;
|
||||
ip: string;
|
||||
createdAt: string;
|
||||
editedAt: string;
|
||||
createdAt: Date;
|
||||
editedAt: Date | null;
|
||||
}
|
||||
|
||||
export interface ExtendedFile extends File {
|
||||
|
@ -56,8 +56,35 @@ export interface Album {
|
|||
id: number;
|
||||
userId: number;
|
||||
name: string;
|
||||
zippedAt: string;
|
||||
createdAt: string;
|
||||
editedAt: string;
|
||||
zippedAt: Date | null;
|
||||
createdAt: Date;
|
||||
editedAt: Date | null;
|
||||
nsfw: boolean;
|
||||
}
|
||||
|
||||
export interface Settings {
|
||||
domain: string;
|
||||
routePrefix: string;
|
||||
rateLimitWindow: number;
|
||||
rateLimitMax: number;
|
||||
secret: string;
|
||||
serviceName: string;
|
||||
chunkSize: number;
|
||||
maxSize: number;
|
||||
generateZips: boolean;
|
||||
generatedFilenameLength: number;
|
||||
generatedAlbumLength: number;
|
||||
blockedExtensions: string[];
|
||||
publicMode: boolean;
|
||||
userAccounts: boolean;
|
||||
metaThemeColor: string;
|
||||
metaDescription: string;
|
||||
metaKeywords: string;
|
||||
metaTwitterHandle: string;
|
||||
backgroundImageURL: string;
|
||||
logoURL: string;
|
||||
statisticsCron: string;
|
||||
enabledStatistics: string[];
|
||||
savedStatistics: string[];
|
||||
[key: string]: string | number | string[] | boolean;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
import { NuxtConfig } from '@nuxt/types';
|
||||
import { getConfig } from '../utils/Util';
|
||||
import autoprefixer from 'autoprefixer';
|
||||
|
||||
export default async () => {
|
||||
const settings = await getConfig();
|
||||
const config: NuxtConfig = {
|
||||
ssr: true,
|
||||
srcDir: 'src/site/',
|
||||
head: {
|
||||
title: settings.serviceName,
|
||||
titleTemplate: `%s | ${settings.serviceName}`,
|
||||
// TODO: Add the directory with pictures for favicon and stuff
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{ hid: 'theme-color', name: 'theme-color', content: `${settings.metaThemeColor}` },
|
||||
{ hid: 'description', name: 'description', content: `${settings.metaDescription}` },
|
||||
{ hid: 'keywords', name: 'keywords', content: `${settings.metaKeywords}` },
|
||||
{
|
||||
hid: 'apple-mobile-web-app-title',
|
||||
name: 'apple-mobile-web-app-title',
|
||||
content: `${settings.serviceName}`
|
||||
},
|
||||
{ hid: 'application-name', name: 'application-name', content: `${settings.serviceName}` },
|
||||
{ hid: 'twitter:card', name: 'twitter:card', content: 'summary' },
|
||||
{ hid: 'twitter:site', name: 'twitter:site', content: `${settings.metaTwitterHandle}` },
|
||||
{ hid: 'twitter:creator', name: 'twitter:creator', content: `${settings.metaTwitterHandle}` },
|
||||
{ hid: 'twitter:title', name: 'twitter:title', content: `${settings.serviceName}` },
|
||||
{ hid: 'twitter:description', name: 'twitter:description', content: `${settings.metaDescription}` },
|
||||
{ hid: 'twitter:image', name: 'twitter:image', content: `/logo.png` },
|
||||
{ hid: 'og:url', property: 'og:url', content: `/` },
|
||||
{ hid: 'og:type', property: 'og:type', content: 'website' },
|
||||
{ hid: 'og:title', property: 'og:title', content: `${settings.serviceName}` },
|
||||
{ hid: 'og:description', property: 'og:description', content: `${settings.metaDescription}` },
|
||||
{ hid: 'og:image', property: 'og:image', content: `/logo.png` },
|
||||
{ hid: 'og:image:secure_url', property: 'og:image:secure_url', content: `/logo.png` },
|
||||
{ hid: 'og:site_name', property: 'og:site_name', content: `${settings.serviceName}` }
|
||||
],
|
||||
link: [
|
||||
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Nunito:300,400,600,700' },
|
||||
|
||||
// This one is a pain in the ass to make it customizable, so you should edit it manually
|
||||
// @ts-ignore
|
||||
{ type: 'application/json+oembed', href: `/oembed.json` }
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
'~/plugins/axios',
|
||||
'~/plugins/buefy',
|
||||
'~/plugins/v-clipboard',
|
||||
'~/plugins/vue-isyourpasswordsafe',
|
||||
'~/plugins/vue-timeago',
|
||||
'~/plugins/vuebar',
|
||||
'~/plugins/notifier',
|
||||
'~/plugins/handler'
|
||||
],
|
||||
css: [],
|
||||
modules: ['@nuxtjs/axios', 'cookie-universal-nuxt'],
|
||||
router: {
|
||||
linkActiveClass: 'is-active',
|
||||
linkExactActiveClass: 'is-active'
|
||||
},
|
||||
env: {
|
||||
development: Boolean(process.env.NODE_ENV !== 'production').toString()
|
||||
},
|
||||
axios: {
|
||||
baseURL: `${process.env.NODE_ENV === 'production' ? process.env.DOMAIN as string : 'http://localhost:5000'}/api`
|
||||
},
|
||||
build: {
|
||||
extractCSS: process.env.NODE_ENV === 'production',
|
||||
// @ts-ignore
|
||||
postcss: {
|
||||
preset: {
|
||||
autoprefixer
|
||||
}
|
||||
},
|
||||
extend(config, { isDev }) {
|
||||
// Extend only webpack config for client-bundle
|
||||
if (isDev) {
|
||||
config.devtool = 'source-map';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return config;
|
||||
};
|
|
@ -54,7 +54,7 @@ export const getSystemInfo = async () => {
|
|||
};
|
||||
|
||||
export const getFileSystemsInfo = async () => {
|
||||
const stats = {};
|
||||
const stats: Record<string, { value: { total: number; used: number }; type: string }> = {};
|
||||
|
||||
const fsSize = await si.fsSize();
|
||||
for (const fs of fsSize) {
|
||||
|
|
|
@ -5,9 +5,9 @@ import prisma from '../structures/database';
|
|||
import { utc } from 'moment';
|
||||
import Zip from 'adm-zip';
|
||||
import { generateThumbnails, getFileThumbnail, removeThumbs } from './ThumbUtil';
|
||||
import { getStats } from './StatsGenerator';
|
||||
// import { getStats } from './StatsGenerator';
|
||||
import type { FastifyRequest, FastifyReply } from 'fastify';
|
||||
import type { File, ExtendedFile, ExtendedFileWithData, Album, User } from '../structures/interfaces';
|
||||
import type { File, ExtendedFile, ExtendedFileWithData, Album, User, Settings } from '../structures/interfaces';
|
||||
|
||||
// TODO: Check that importing the log function works for routes and CLI (generateThumbs.ts)
|
||||
import { log } from '../main';
|
||||
|
@ -21,6 +21,11 @@ export const uploadPath = path.join(__dirname, '../../../', 'uploads');
|
|||
export const statsLastSavedTime = null;
|
||||
export const _config = null;
|
||||
|
||||
/*
|
||||
TODO: Ask crawl how to properly type this.
|
||||
I want that if I call getConfig() to know the properties that will come back and their types
|
||||
to use them in nuxt.ts for example
|
||||
*/
|
||||
export const getConfig = async () => {
|
||||
const config = await prisma.settings.findMany();
|
||||
return config.reduce((conf, item) => {
|
||||
|
@ -30,9 +35,10 @@ export const getConfig = async () => {
|
|||
conf[item.key] = item.value;
|
||||
}
|
||||
return config;
|
||||
}, {} as Record<string, any>);
|
||||
}, {} as Record<string, any>) as Settings;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
export const getEnvironmentDefaults = () => ({
|
||||
domain: process.env.DOMAIN,
|
||||
routePrefix: '/api',
|
||||
|
@ -60,7 +66,7 @@ export const getEnvironmentDefaults = () => ({
|
|||
statisticsCron: process.env.STATISTICS_CRON ?? '0 0 * * * *',
|
||||
enabledStatistics: process.env.ENABLED_STATISTICS ? process.env.ENABLED_STATISTICS.split(',') : ['system', 'fileSystems', 'uploads', 'users', 'albums'],
|
||||
savedStatistics: process.env.SAVED_STATISTICS ? process.env.SAVED_STATISTICS.split(',') : ['system', 'fileSystems', 'uploads', 'users', 'albums']
|
||||
});
|
||||
} as Settings);
|
||||
|
||||
export const wipeConfigDb = async () => {
|
||||
try {
|
||||
|
@ -70,12 +76,15 @@ export const wipeConfigDb = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
export const writeConfigToDb = async (config: { key: string; value: string }) => {
|
||||
export const writeConfigToDb = async (config: { key: string; value: string | number | string[] | boolean }) => {
|
||||
if (!config.key) return;
|
||||
try {
|
||||
config.value = JSON.stringify(config.value);
|
||||
const data = {
|
||||
key: config.key,
|
||||
value: JSON.stringify(config.value)
|
||||
};
|
||||
await prisma.settings.create({
|
||||
data: config
|
||||
data
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
@ -85,23 +94,6 @@ export const writeConfigToDb = async (config: { key: string; value: string }) =>
|
|||
export const isExtensionBlocked = async (extension: string) => (await getConfig()).blockedExtensions.includes(extension);
|
||||
export const getMimeFromType = (fileTypeMimeObj: Record<string, null>) => fileTypeMimeObj.mime;
|
||||
|
||||
export const constructFilePublicLink = (req: FastifyRequest, file: File) => {
|
||||
/*
|
||||
TODO: This wont work without a reverse proxy serving both
|
||||
the site and the API under the same domain. Pls fix.
|
||||
*/
|
||||
const extended = file as ExtendedFile;
|
||||
const host = getHost(req);
|
||||
extended.url = `${host}/${extended.name}`;
|
||||
const { thumb, preview } = getFileThumbnail(extended.name) ?? {};
|
||||
if (thumb) {
|
||||
extended.thumb = `${host}/thumbs/${thumb}`;
|
||||
extended.thumbSquare = `${host}/thumbs/square/${thumb}`;
|
||||
extended.preview = preview && `${host}/thumbs/preview/${preview}`;
|
||||
}
|
||||
return extended;
|
||||
};
|
||||
|
||||
export const getUniqueFilename = (extension: string) => {
|
||||
const retry: any = async (i = 0) => {
|
||||
const filename = randomstring.generate({
|
||||
|
@ -243,6 +235,23 @@ export const createZip = (files: string[], album: Album) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const constructFilePublicLink = (req: FastifyRequest, file: File) => {
|
||||
/*
|
||||
TODO: This wont work without a reverse proxy serving both
|
||||
the site and the API under the same domain. Pls fix.
|
||||
*/
|
||||
const extended: ExtendedFile = { ...file };
|
||||
const host = getHost(req);
|
||||
extended.url = `${host}/${extended.name}`;
|
||||
const { thumb, preview } = getFileThumbnail(extended.name) ?? {};
|
||||
if (thumb) {
|
||||
extended.thumb = `${host}/thumbs/${thumb}`;
|
||||
extended.thumbSquare = `${host}/thumbs/square/${thumb}`;
|
||||
extended.preview = preview && `${host}/thumbs/preview/${preview}`;
|
||||
}
|
||||
return extended;
|
||||
};
|
||||
|
||||
export const fileExists = (req: FastifyRequest, res: FastifyReply, exists: File, filename: string) => {
|
||||
const file = constructFilePublicLink(req, exists);
|
||||
void res.send({
|
||||
|
|
Loading…
Reference in New Issue