feat(v3.3.1): bug fixes and new features

This commit is contained in:
diced 2022-02-19 20:17:02 -08:00
parent e786482902
commit d9561f3b12
No known key found for this signature in database
GPG key ID: 85AB64C74535D76E
23 changed files with 2231 additions and 509 deletions

View file

@ -1,25 +0,0 @@
module.exports = {
'extends': ['next', 'next/core-web-vitals'],
'rules': {
'indent': ['error', 2],
'linebreak-style': ['error', 'unix'],
'quotes': ['error', 'single'],
'semi': ['error', 'always'],
'comma-dangle': ['error', 'always-multiline'],
'jsx-quotes': ['error', 'prefer-single'],
'react/prop-types': 'off',
'react-hooks/rules-of-hooks': 'off',
'react-hooks/exhaustive-deps': 'off',
'react/jsx-uses-react': 'warn',
'react/jsx-uses-vars': 'warn',
'react/no-danger-with-children': 'warn',
'react/no-deprecated': 'warn',
'react/no-direct-mutation-state': 'warn',
'react/no-is-mounted': 'warn',
'react/no-typos': 'error',
'react/react-in-jsx-scope': 'error',
'react/require-render-return': 'error',
'react/style-prop-object': 'warn',
'@next/next/no-img-element': 'off',
},
};

25
.eslintrc.json Normal file
View file

@ -0,0 +1,25 @@
{
"extends": ["next", "next/core-web-vitals"],
"rules": {
"indent": ["error", 2],
"linebreak-style": ["error", "unix"],
"quotes": ["error", "single"],
"semi": ["error", "always"],
"comma-dangle": ["error", "always-multiline"],
"jsx-quotes": ["error", "prefer-single"],
"react/prop-types": "off",
"react-hooks/rules-of-hooks": "off",
"react-hooks/exhaustive-deps": "off",
"react/jsx-uses-react": "warn",
"react/jsx-uses-vars": "warn",
"react/no-danger-with-children": "warn",
"react/no-deprecated": "warn",
"react/no-direct-mutation-state": "warn",
"react/no-is-mounted": "warn",
"react/no-typos": "error",
"react/react-in-jsx-scope": "error",
"react/require-render-return": "error",
"react/style-prop-object": "warn",
"@next/next/no-img-element": "off"
}
}

View file

@ -1,33 +1,46 @@
FROM node:16-alpine3.11 AS builder
FROM node:16-alpine AS deps
WORKDIR /build
ENV NEXT_TELEMETRY_DISABLED=1
COPY package.json yarn.lock ./
RUN apk add --no-cache libc6-compat
RUN yarn install --frozen-lockfile
FROM node:16-alpine AS builder
WORKDIR /build
COPY --from=deps /build/node_modules ./node_modules
COPY src ./src
COPY server ./server
COPY scripts ./scripts
COPY prisma ./prisma
COPY package.json yarn.lock next.config.js next-env.d.ts zip-env.d.ts tsconfig.json ./
# create a mock config.toml to spoof next build!
RUN echo -e "[core]\nsecret = '12345678'\ndatabase_url = 'postgres://postgres:postgres@postgres/postgres'\n[uploader]\nroute = '/u'\ndirectory = './uploads'\n[urls]\nroute = '/go'" > config.toml
RUN yarn install
ENV ZIPLINE_DOCKER_BUILD 1
ENV NEXT_TELEMETRY_DISABLED 1
RUN yarn build
FROM node:16-alpine3.11 AS runner
FROM node:16-alpine AS runner
WORKDIR /zipline
COPY --from=builder /build/node_modules ./node_modules
ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 zipline
RUN adduser --system --uid 1001 zipline
COPY --from=builder --chown=zipline:zipline /build/.next ./.next
COPY --from=builder --chown=zipline:zipline /build/node_modules ./node_modules
COPY --from=builder /build/next.config.js ./next.config.js
COPY --from=builder /build/src ./src
COPY --from=builder /build/server ./server
COPY --from=builder /build/scripts ./scripts
COPY --from=builder /build/prisma ./prisma
COPY --from=builder /build/.next ./.next
COPY --from=builder /build/tsconfig.json ./tsconfig.json
COPY --from=builder /build/package.json ./package.json
USER zipline
CMD ["node", "server"]

View file

@ -15,15 +15,25 @@ services:
retries: 5
zipline:
build:
context: .
dockerfile: Dockerfile
image: ghcr.io/diced/zipline/zipline:trunk
ports:
- '3000:3000'
restart: unless-stopped
environment:
- SECURE=false
- SECRET=changethis
- HOST=0.0.0.0
- PORT=3000
- DATABASE_URL=postgresql://postgres:postgres@postgres/postgres/
- UPLOADER_ROUTE=/u
- UPLOADER_EMBED_ROUTE=/a
- UPLOADER_LENGTH=6
- UPLOADER_DIRECTORY=./uploads
- UPLOADER_ADMIN_LIMIT=104900000
- UPLOADER_USER_LIMIT=104900000
- UPLOADER_DISABLED_EXTS=
- URLS_ROUTE=/go
- URLS_LENGTH=6
volumes:
- '$PWD/uploads:/zipline/uploads'
- '$PWD/public:/zipline/public'

View file

@ -1,4 +1,3 @@
module.exports = {
reactStrictMode: true,
};
};

View file

@ -1,6 +1,7 @@
{
"name": "zip3",
"version": "3.3.1",
"license": "MIT",
"scripts": {
"prepare": "husky install",
"dev": "NODE_ENV=development node server",
@ -19,6 +20,8 @@
"@mui/material": "^5.0.2",
"@mui/styles": "^5.0.1",
"@prisma/client": "^3.9.2",
"@prisma/migrate": "^3.9.2",
"@prisma/sdk": "^3.9.2",
"@reduxjs/toolkit": "^1.6.0",
"argon2": "^0.28.2",
"colorette": "^1.2.2",
@ -27,7 +30,7 @@
"fecha": "^4.2.1",
"formik": "^2.2.9",
"multer": "^1.4.2",
"next": "^12.0.10",
"next": "^12.1.0",
"prisma": "^3.9.2",
"react": "17.0.2",
"react-color": "^2.19.3",

View file

@ -9,8 +9,8 @@ async function main() {
username: 'administrator',
password: await hashPassword('password'),
token: createToken(),
administrator: true
}
administrator: true,
},
});
console.log(`

View file

@ -1,13 +0,0 @@
const Logger = require('../src/lib/logger');
const prismaRun = require('./prisma-run');
module.exports = async (config) => {
try {
await prismaRun(config.core.database_url, ['migrate', 'deploy']);
await prismaRun(config.core.database_url, ['generate'], true);
} catch (e) {
console.log(e);
Logger.get('db').error('there was an error.. exiting..');
process.exit(1);
}
};

View file

@ -20,7 +20,7 @@ const { PrismaClient } = require('@prisma/client');
return {
file: x,
mimetype: mime,
userId: 1
userId: 1,
};
});
@ -28,7 +28,7 @@ const { PrismaClient } = require('@prisma/client');
Logger.get('migrator').info('starting migrations...');
await prisma.image.createMany({
data
data,
});
Logger.get('migrator').info('finished migrations! It is recomended to move your old uploads folder (' + process.argv[2] + ') to the current one which is ' + config.uploader.directory);
process.exit();

View file

@ -74,5 +74,5 @@ module.exports = {
'.zip': 'application/zip',
'.3gp': 'video/3gpp',
'.3g2': 'video/3gpp2',
'.7z': 'application/x-7z-compressed'
'.7z': 'application/x-7z-compressed',
};

View file

@ -1,26 +0,0 @@
const { spawn } = require('child_process');
const { join } = require('path');
module.exports = (url, args, nostdout = false) => {
return new Promise((res, rej) => {
const proc = spawn(join(process.cwd(), 'node_modules', '.bin', 'prisma'), args, {
env: {
DATABASE_URL: url,
...process.env
},
});
let a = '';
proc.stdout.on('data', d => {
if (!nostdout) console.log(d.toString());
a += d.toString();
});
proc.stderr.on('data', d => {
if (!nostdout) console.log(d.toString());
rej(d.toString());
});
proc.stdout.on('end', () => res(a));
proc.stdout.on('close', () => res(a));
});
};

View file

@ -1,260 +1,171 @@
const next = require('next');
const NextServer = require('next/dist/server/next-server').default;
const defaultConfig = require('next/dist/server/config-shared').defaultConfig;
const { createServer } = require('http');
const { stat, mkdir, readdir } = require('fs/promises');
const { execSync } = require('child_process');
const { extname, join } = require('path');
const { PrismaClient } = require('@prisma/client');
const { stat, mkdir } = require('fs/promises');
const { extname } = require('path');
const validateConfig = require('./validateConfig');
const Logger = require('../src/lib/logger');
const getFile = require('./static');
const prismaRun = require('../scripts/prisma-run');
const readConfig = require('../src/lib/readConfig');
const mimes = require('../scripts/mimes');
const deployDb = require('../scripts/deploy-db');
const { log, getStats, shouldUseYarn, getFile, migrations } = require('./util');
const { PrismaClient } = require('@prisma/client');
const { version } = require('../package.json');
const nextConfig = require('../next.config');
const serverLog = Logger.get('server');
const webLog = Logger.get('web');
Logger.get('server').info(`starting zipline@${version} server`);
serverLog.info(`starting zipline@${version} server`);
const dev = process.env.NODE_ENV === 'development';
function log(url, status) {
if (url.startsWith('/_next') || url.startsWith('/__nextjs')) return;
return Logger.get('url').info(url);
}
function shouldUseYarn() {
try {
execSync('yarnpkg --version', { stdio: 'ignore' });
return true;
} catch (e) {
return false;
}
}
(async () => {
try {
const a = readConfig();
const config = await validateConfig(a);
const data = await prismaRun(config.core.database_url, ['migrate', 'status'], true);
if (data.match(/Following migrations? have not yet been applied/)) {
Logger.get('database').info('some migrations are not applied, applying them now...');
await deployDb(config);
Logger.get('database').info('finished applying migrations');
} else Logger.get('database').info('migrations up to date');
process.env.DATABASE_URL = config.core.database_url;
await mkdir(config.uploader.directory, { recursive: true });
const app = next({
dir: '.',
dev,
quiet: dev,
}, config.core.port, config.core.host);
await app.prepare();
await stat('./.next');
const handle = app.getRequestHandler();
const prisma = new PrismaClient();
const srv = createServer(async (req, res) => {
if (req.url.startsWith('/r')) {
const parts = req.url.split('/');
if (!parts[2] || parts[2] === '') return;
let image = await prisma.image.findFirst({
where: {
OR: [
{ file: parts[2] },
{ invisible:{ invis: decodeURI(parts[2]) } },
],
},
select: {
mimetype: true,
id: true,
file: true,
invisible: true,
},
});
if (!image) {
const data = await getFile(config.uploader.directory, parts[2]);
if (!data) return app.render404(req, res);
const mimetype = mimes[extname(parts[2])] ?? 'application/octet-stream';
res.setHeader('Content-Type', mimetype);
res.end(data);
} else {
const data = await getFile(config.uploader.directory, image.file);
if (!data) return app.render404(req, res);
await prisma.image.update({
where: { id: image.id },
data: { views: { increment: 1 } },
});
res.setHeader('Content-Type', image.mimetype);
res.end(data);
}
} else if (req.url.startsWith(config.uploader.route)) {
const parts = req.url.split('/');
if (!parts[2] || parts[2] === '') return;
let image = await prisma.image.findFirst({
where: {
OR: [
{ file: parts[2] },
{ invisible:{ invis: decodeURI(parts[2]) } },
],
},
select: {
mimetype: true,
id: true,
file: true,
invisible: true,
embed: true,
},
});
if (!image) {
const data = await getFile(config.uploader.directory, parts[2]);
if (!data) return app.render404(req, res);
const mimetype = mimes[extname(parts[2])] ?? 'application/octet-stream';
res.setHeader('Content-Type', mimetype);
res.end(data);
} else if (image.embed) {
handle(req, res);
} else {
const data = await getFile(config.uploader.directory, image.file);
if (!data) return app.render404(req, res);
await prisma.image.update({
where: { id: image.id },
data: { views: { increment: 1 } },
});
res.setHeader('Content-Type', image.mimetype);
res.end(data);
}
} else {
handle(req, res);
}
if (config.core.logger) log(req.url, res.statusCode);
});
srv.on('error', (e) => {
Logger.get('server').error(e);
await run();
} catch (e) {
if (e.message && e.message.startsWith('Could not find a production')) {
webLog.error(`there is no production build - run \`${shouldUseYarn() ? 'yarn build' : 'npm build'}\``);
} else if (e.code && e.code === 'ENOENT') {
if (e.path === './.next') webLog.error(`there is no production build - run \`${shouldUseYarn() ? 'yarn build' : 'npm build'}\``);
} else {
serverLog.error(e);
process.exit(1);
});
srv.on('listening', () => {
Logger.get('server').info(`listening on ${config.core.host}:${config.core.port}`);
if (process.platform === 'linux' && dev) execSync(`xdg-open ${config.core.secure ? 'https' : 'http'}://${config.core.host === '0.0.0.0' ? 'localhost' : config.core.host}:${config.core.port}`);
});
}
}
})();
srv.listen(config.core.port, config.core.host ?? '0.0.0.0');
async function run() {
const a = readConfig();
const config = validateConfig(a);
process.env.DATABASE_URL = config.core.database_url;
await migrations();
await mkdir(config.uploader.directory, { recursive: true });
const app = new NextServer({
dir: '.',
dev,
quiet: dev,
customServer: false,
host: config.core.host,
port: config.core.port,
conf: Object.assign(defaultConfig, nextConfig),
});
await app.prepare();
await stat('./.next');
const handle = app.getRequestHandler();
const prisma = new PrismaClient();
const srv = createServer(async (req, res) => {
if (req.url.startsWith('/r')) {
const parts = req.url.split('/');
if (!parts[2] || parts[2] === '') return;
let image = await prisma.image.findFirst({
where: {
OR: [
{ file: parts[2] },
{ invisible: { invis: decodeURI(parts[2]) } },
],
},
select: {
mimetype: true,
id: true,
file: true,
invisible: true,
},
});
if (!image) {
const data = await getFile(config.uploader.directory, parts[2]);
if (!data) return app.render404(req, res);
const mimetype = mimes[extname(parts[2])] ?? 'application/octet-stream';
res.setHeader('Content-Type', mimetype);
res.end(data);
} else {
const data = await getFile(config.uploader.directory, image.file);
if (!data) return app.render404(req, res);
await prisma.image.update({
where: { id: image.id },
data: { views: { increment: 1 } },
});
res.setHeader('Content-Type', image.mimetype);
res.end(data);
}
} else if (req.url.startsWith(config.uploader.route)) {
const parts = req.url.split('/');
if (!parts[2] || parts[2] === '') return;
let image = await prisma.image.findFirst({
where: {
OR: [
{ file: parts[2] },
{ invisible: { invis: decodeURI(parts[2]) } },
],
},
select: {
mimetype: true,
id: true,
file: true,
invisible: true,
embed: true,
},
});
if (!image) {
const data = await getFile(config.uploader.directory, parts[2]);
if (!data) return app.render404(req, res);
const mimetype = mimes[extname(parts[2])] ?? 'application/octet-stream';
res.setHeader('Content-Type', mimetype);
res.end(data);
} else if (image.embed) {
handle(req, res);
} else {
const data = await getFile(config.uploader.directory, image.file);
if (!data) return app.render404(req, res);
await prisma.image.update({
where: { id: image.id },
data: { views: { increment: 1 } },
});
res.setHeader('Content-Type', image.mimetype);
res.end(data);
}
} else {
handle(req, res);
}
if (config.core.logger) log(req.url, res.statusCode);
});
srv.on('error', (e) => {
serverLog.error(e);
process.exit(1);
});
srv.on('listening', () => {
serverLog.info(`listening on ${config.core.host}:${config.core.port}`);
});
srv.listen(config.core.port, config.core.host ?? '0.0.0.0');
const stats = await getStats(prisma, config);
await prisma.stats.create({
data: {
data: stats,
},
});
setInterval(async () => {
const stats = await getStats(prisma, config);
await prisma.stats.create({
data: {
data: stats,
},
});
setInterval(async () => {
const stats = await getStats(prisma, config);
await prisma.stats.create({
data: {
data: stats,
},
});
if (config.core.logger) Logger.get('server').info('stats updated');
}, config.core.stats_interval * 1000);
} catch (e) {
if (e.message && e.message.startsWith('Could not find a production')) {
Logger.get('web').error(`there is no production build - run \`${shouldUseYarn() ? 'yarn build' : 'npm build'}\``);
} else if (e.code && e.code === 'ENOENT') {
if (e.path === './.next') Logger.get('web').error(`there is no production build - run \`${shouldUseYarn() ? 'yarn build' : 'npm build'}\``);
} else {
Logger.get('server').error(e);
process.exit(1);
}
}
})();
async function sizeOfDir(directory) {
const files = await readdir(directory);
let size = 0;
for (let i = 0, L = files.length; i !== L; ++i) {
const sta = await stat(join(directory, files[i]));
size += sta.size;
}
return size;
}
function bytesToRead(bytes) {
const units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB'];
let num = 0;
while (bytes > 1024) {
bytes /= 1024;
++num;
}
return `${bytes.toFixed(1)} ${units[num]}`;
}
async function getStats(prisma, config) {
const size = await sizeOfDir(join(process.cwd(), config.uploader.directory));
const byUser = await prisma.image.groupBy({
by: ['userId'],
_count: {
_all: true,
},
});
const count_users = await prisma.user.count();
const count_by_user = [];
for (let i = 0, L = byUser.length; i !== L; ++i) {
const user = await prisma.user.findFirst({
where: {
id: byUser[i].userId,
},
});
count_by_user.push({
username: user.username,
count: byUser[i]._count._all,
});
}
const count = await prisma.image.count();
const viewsCount = await prisma.image.groupBy({
by: ['views'],
_sum: {
views: true,
},
});
const typesCount = await prisma.image.groupBy({
by: ['mimetype'],
_count: {
mimetype: true,
},
});
const types_count = [];
for (let i = 0, L = typesCount.length; i !== L; ++i) types_count.push({ mimetype: typesCount[i].mimetype, count: typesCount[i]._count.mimetype });
return {
size: bytesToRead(size),
size_num: size,
count,
count_by_user: count_by_user.sort((a,b) => b.count-a.count),
count_users,
views_count: (viewsCount[0]?._sum?.views ?? 0),
types_count: types_count.sort((a,b) => b.count-a.count),
};
if (config.core.logger) serverLog.info('stats updated');
}, config.core.stats_interval * 1000);
}

View file

@ -1,11 +0,0 @@
const { readFile } = require('fs/promises');
const { join } = require('path');
module.exports = async (dir, file) => {
try {
const data = await readFile(join(process.cwd(), dir, file));
return data;
} catch (e) {
return null;
}
};

129
server/util.js Normal file
View file

@ -0,0 +1,129 @@
const { readFile, readdir, stat } = require('fs/promises');
const { join } = require('path');
const { Migrate } = require('@prisma/migrate/dist/Migrate.js');
const Logger = require('../src/lib/logger.js');
async function migrations() {
const migrate = new Migrate('./prisma/schema.prisma');
const diagnose = await migrate.diagnoseMigrationHistory({
optInToShadowDatabase: false,
});
if (diagnose.history?.diagnostic === 'databaseIsBehind') {
Logger.get('database').info('migrating database');
await migrate.applyMigrations();
Logger.get('database').info('finished migrating database');
}
migrate.stop();
}
function log(url) {
if (url.startsWith('/_next') || url.startsWith('/__nextjs')) return;
return Logger.get('url').info(url);
}
function shouldUseYarn() {
try {
execSync('yarnpkg --version', { stdio: 'ignore' });
return true;
} catch (e) {
return false;
}
}
async function getFile(dir, file) {
try {
const data = await readFile(join(process.cwd(), dir, file));
return data;
} catch (e) {
return null;
}
}
async function sizeOfDir(directory) {
const files = await readdir(directory);
let size = 0;
for (let i = 0, L = files.length; i !== L; ++i) {
const sta = await stat(join(directory, files[i]));
size += sta.size;
}
return size;
}
function bytesToRead(bytes) {
const units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB'];
let num = 0;
while (bytes > 1024) {
bytes /= 1024;
++num;
}
return `${bytes.toFixed(1)} ${units[num]}`;
}
async function getStats(prisma, config) {
const size = await sizeOfDir(join(process.cwd(), config.uploader.directory));
const byUser = await prisma.image.groupBy({
by: ['userId'],
_count: {
_all: true,
},
});
const count_users = await prisma.user.count();
const count_by_user = [];
for (let i = 0, L = byUser.length; i !== L; ++i) {
const user = await prisma.user.findFirst({
where: {
id: byUser[i].userId,
},
});
count_by_user.push({
username: user.username,
count: byUser[i]._count._all,
});
}
const count = await prisma.image.count();
const viewsCount = await prisma.image.groupBy({
by: ['views'],
_sum: {
views: true,
},
});
const typesCount = await prisma.image.groupBy({
by: ['mimetype'],
_count: {
mimetype: true,
},
});
const types_count = [];
for (let i = 0, L = typesCount.length; i !== L; ++i) types_count.push({ mimetype: typesCount[i].mimetype, count: typesCount[i]._count.mimetype });
return {
size: bytesToRead(size),
size_num: size,
count,
count_by_user: count_by_user.sort((a,b) => b.count-a.count),
count_users,
views_count: (viewsCount[0]?._sum?.views ?? 0),
types_count: types_count.sort((a,b) => b.count-a.count),
};
}
module.exports = {
migrations,
bytesToRead,
getFile,
getStats,
log,
sizeOfDir,
};

View file

@ -1,41 +1,40 @@
const Logger = require('../src/lib/logger');
const yup = require('yup');
const { object, bool, string, number, boolean, array } = require('yup');
const validator = yup.object({
core: yup.object({
secure: yup.bool().default(false),
secret: yup.string().min(8).required(),
host: yup.string().default('0.0.0.0'),
port: yup.number().default(3000),
database_url: yup.string().required(),
logger: yup.boolean().default(true),
stats_interval: yup.number().default(1800),
const validator = object({
core: object({
secure: bool().default(false),
secret: string().min(8).required(),
host: string().default('0.0.0.0'),
port: number().default(3000),
database_url: string().required(),
logger: boolean().default(true),
stats_interval: number().default(1800),
}).required(),
uploader: yup.object({
route: yup.string().default('/u'),
embed_route: yup.string().default('/a'),
length: yup.number().default(6),
directory: yup.string().default('./uploads'),
admin_limit: yup.number().default(104900000),
user_limit: yup.number().default(104900000),
disabled_extensions: yup.array().default([]),
uploader: object({
route: string().default('/u'),
embed_route: string().default('/a'),
length: number().default(6),
directory: string().default('./uploads'),
admin_limit: number().default(104900000),
user_limit: number().default(104900000),
disabled_extensions: array().default([]),
}).required(),
urls: yup.object({
route: yup.string().default('/go'),
length: yup.number().default(6),
urls: object({
route: string().default('/go'),
length: number().default(6),
}).required(),
ratelimit: yup.object({
user: yup.number().default(0),
admin: yup.number().default(0),
ratelimit: object({
user: number().default(0),
admin: number().default(0),
}),
});
module.exports = config => {
module.exports = function validate(config) {
try {
return validator.validateSync(config, { abortEarly: false });
} catch (e) {
if (process.env.ZIPLINE_DOCKER_BUILD) return {};
throw `${e.errors.length} errors occured\n${e.errors.map(x => '\t' + x).join('\n')}`;
}
};

View file

@ -1,7 +1,7 @@
const { format } = require('fecha');
const { blueBright, red, cyan } = require('colorette');
class Logger {
module.exports = class Logger {
static get(clas) {
if (typeof clas !== 'function') if (typeof clas !== 'string') throw new Error('not string/function');
@ -35,6 +35,4 @@ class Logger {
return red('ERROR');
}
}
}
module.exports = Logger;
};

View file

@ -1,5 +1,7 @@
import { PrismaClient } from '@prisma/client';
if (!global.prisma) global.prisma = new PrismaClient();
if (!global.prisma) {
if (!process.env.ZIPLINE_DOCKER_BUILD) global.prisma = new PrismaClient();
};
export default global.prisma;

View file

@ -1,6 +1,7 @@
const { existsSync, readFileSync } = require('fs');
const { join } = require('path');
const Logger = require('./logger');
const parse = require('@iarna/toml/parse-string.js');
const Logger = require('./logger.js');
const e = (val, type, fn) => ({ val, type, fn });
@ -27,16 +28,16 @@ const envValues = [
e('RATELIMIT_ADMIN', 'number', (c, v) => c.ratelimit.user = v ?? 0),
];
module.exports = () => {
module.exports = function readConfig() {
if (!existsSync(join(process.cwd(), 'config.toml'))) {
Logger.get('config').info('reading environment');
if (!process.env.ZIPLINE_DOCKER_BUILD) Logger.get('config').info('reading environment');
return tryReadEnv();
} else {
if (process.env.JEST_WORKER_ID) return;
if (process.env.ZIPLINE_DOCKER_BUILD) return;
Logger.get('config').info('reading config file');
const str = readFileSync(join(process.cwd(), 'config.toml'), 'utf8');
const parsed = require('@iarna/toml/parse-string')(str);
const parsed = parse(str);
return parsed;
}

View file

@ -4,7 +4,7 @@ import { GetServerSideProps } from 'next';
import { Box } from '@mui/material';
import config from 'lib/config';
import prisma from 'lib/prisma';
import getFile from '../../server/static';
import { getFile } from '../../server/util';
import { parse } from 'lib/clientUtils';
export default function EmbeddedImage({ image, user, normal }) {

View file

@ -1,8 +1,5 @@
import { join } from 'path';
import { NextApiReq, NextApiRes, withZipline } from 'middleware/withZipline';
import prisma from 'lib/prisma';
import { bytesToRead, sizeOfDir } from 'lib/util';
import { tryGetPreviewData } from 'next/dist/server/api-utils';
async function handler(req: NextApiReq, res: NextApiRes) {
const user = await req.user();

View file

@ -21,10 +21,10 @@ export default function UploadPage({ route }) {
);
}
export const getStaticProps: GetStaticProps = async (context) => {
export const getStaticProps: GetStaticProps = async () => {
return {
props: {
route: config.uploader.route,
route: process.env.ZIPLINE_DOCKER_BUILD === '1' ? '/u' : config.uploader.route,
},
};
};

1969
yarn.lock

File diff suppressed because it is too large Load diff

5
zip-env.d.ts vendored
View file

@ -6,7 +6,10 @@ declare global {
interface Global {
prisma: PrismaClient;
config: Config;
ratelimit: Set<string>;
}
interface ProcessEnv {
ZIPLINE_DOCKER_BUILD: string | '1';
}
}
}