feat(v3.2.4): url shortenning
This commit is contained in:
parent
a9d0be8aae
commit
3451bd8762
19 changed files with 300 additions and 110 deletions
|
@ -5,6 +5,7 @@ module.exports = {
|
|||
'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',
|
||||
|
@ -19,6 +20,6 @@ module.exports = {
|
|||
'react/react-in-jsx-scope': 'error',
|
||||
'react/require-render-return': 'error',
|
||||
'react/style-prop-object': 'warn',
|
||||
'@next/next/no-img-element': 'off'
|
||||
}
|
||||
'@next/next/no-img-element': 'off',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -13,7 +13,7 @@ COPY package.json yarn.lock next.config.js next-env.d.ts zip-env.d.ts tsconfig.j
|
|||
RUN yarn install
|
||||
|
||||
# create a mock config.toml to spoof next build!
|
||||
RUN echo -e "[uploader]\nroute = '/u'" > config.toml
|
||||
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 build
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "zip3",
|
||||
"version": "3.2.3",
|
||||
"version": "3.2.4",
|
||||
"scripts": {
|
||||
"prepare": "husky install",
|
||||
"dev": "NODE_ENV=development node server",
|
||||
|
@ -9,7 +9,7 @@
|
|||
"build:schema": "prisma generate --schema=prisma/schema.prisma",
|
||||
"start": "node server",
|
||||
"lint": "next lint",
|
||||
"ts-node": "ts-node --compiler-options \"{\\\"module\\\":\\\"commonjs\\\"}\" --transpile-only",
|
||||
"seed": "ts-node --compiler-options \"{\\\"module\\\":\\\"commonjs\\\"}\" --transpile-only prisma/seed.ts",
|
||||
"semantic-release": "semantic-release"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -19,7 +19,7 @@
|
|||
"@material-ui/core": "^5.0.0-alpha.37",
|
||||
"@material-ui/icons": "^5.0.0-alpha.37",
|
||||
"@material-ui/styles": "^5.0.0-alpha.35",
|
||||
"@prisma/client": "^3.0.2",
|
||||
"@prisma/client": "^3.1.1",
|
||||
"@reduxjs/toolkit": "^1.6.0",
|
||||
"argon2": "^0.28.2",
|
||||
"colorette": "^1.2.2",
|
||||
|
@ -29,7 +29,7 @@
|
|||
"formik": "^2.2.9",
|
||||
"multer": "^1.4.2",
|
||||
"next": "11.1.1",
|
||||
"prisma": "^3.0.2",
|
||||
"prisma": "^3.1.1",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-dropzone": "^11.3.2",
|
||||
|
|
39
prisma/migrations/20210924045900_delete_url/migration.sql
Normal file
39
prisma/migrations/20210924045900_delete_url/migration.sql
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the `InvisibleUrl` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `Url` table. If the table is not empty, all the data it contains will be lost.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "Image" DROP CONSTRAINT "Image_userId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "InvisibleImage" DROP CONSTRAINT "InvisibleImage_imageId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "InvisibleUrl" DROP CONSTRAINT "InvisibleUrl_id_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "Theme" DROP CONSTRAINT "Theme_userId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "Url" DROP CONSTRAINT "Url_userId_fkey";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "InvisibleUrl";
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE "Url";
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Theme" ADD CONSTRAINT "Theme_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Image" ADD CONSTRAINT "Image_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "InvisibleImage" ADD CONSTRAINT "InvisibleImage_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "Image"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- RenameIndex
|
||||
ALTER INDEX "InvisibleImage.invis_unique" RENAME TO "InvisibleImage_invis_key";
|
34
prisma/migrations/20210924050753_new_url/migration.sql
Normal file
34
prisma/migrations/20210924050753_new_url/migration.sql
Normal file
|
@ -0,0 +1,34 @@
|
|||
-- CreateTable
|
||||
CREATE TABLE "Url" (
|
||||
"id" TEXT NOT NULL,
|
||||
"destination" TEXT NOT NULL,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"views" INTEGER NOT NULL DEFAULT 0,
|
||||
"userId" INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT "Url_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "InvisibleUrl" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"invis" TEXT NOT NULL,
|
||||
"urlId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "InvisibleUrl_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Url_id_key" ON "Url"("id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "InvisibleUrl_invis_key" ON "InvisibleUrl"("invis");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "InvisibleUrl_urlId_unique" ON "InvisibleUrl"("urlId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Url" ADD CONSTRAINT "Url_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "InvisibleUrl" ADD CONSTRAINT "InvisibleUrl_urlId_fkey" FOREIGN KEY ("urlId") REFERENCES "Url"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
@ -0,0 +1,2 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "Url" ADD COLUMN "vanity" TEXT;
|
|
@ -57,17 +57,19 @@ model InvisibleImage {
|
|||
}
|
||||
|
||||
model Url {
|
||||
id Int @id @default(autoincrement())
|
||||
to String
|
||||
created_at DateTime @default(now())
|
||||
views Int @default(0)
|
||||
invisible InvisibleUrl?
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
userId Int
|
||||
id String @id @unique
|
||||
destination String
|
||||
vanity String?
|
||||
created_at DateTime @default(now())
|
||||
views Int @default(0)
|
||||
invisible InvisibleUrl?
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
userId Int
|
||||
}
|
||||
|
||||
model InvisibleUrl {
|
||||
id Int
|
||||
url Url @relation(fields: [id], references: [id])
|
||||
id Int @id @default(autoincrement())
|
||||
invis String @unique
|
||||
urlId String
|
||||
url Url @relation(fields: [urlId], references: [id])
|
||||
}
|
||||
|
|
|
@ -34,10 +34,11 @@ function shouldUseYarn() {
|
|||
|
||||
(async () => {
|
||||
try {
|
||||
const config = await validateConfig(readConfig());
|
||||
const a = readConfig();
|
||||
const config = await validateConfig(a);
|
||||
|
||||
const data = await prismaRun(config.core.database_url, ['migrate', 'status'], true);
|
||||
if (data.includes('Following migration have not yet been applied:')) {
|
||||
if (data.includes('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');
|
||||
|
@ -49,7 +50,7 @@ function shouldUseYarn() {
|
|||
const app = next({
|
||||
dir: '.',
|
||||
dev,
|
||||
quiet: dev
|
||||
quiet: dev,
|
||||
}, config.core.port, config.core.host);
|
||||
|
||||
await app.prepare();
|
||||
|
@ -67,15 +68,15 @@ function shouldUseYarn() {
|
|||
where: {
|
||||
OR: [
|
||||
{ file: parts[2] },
|
||||
{ invisible:{ invis: decodeURI(parts[2]) } }
|
||||
]
|
||||
{ invisible:{ invis: decodeURI(parts[2]) } },
|
||||
],
|
||||
},
|
||||
select: {
|
||||
mimetype: true,
|
||||
id: true,
|
||||
file: true,
|
||||
invisible: true
|
||||
}
|
||||
invisible: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!image) {
|
||||
|
@ -92,7 +93,7 @@ function shouldUseYarn() {
|
|||
|
||||
await prisma.image.update({
|
||||
where: { id: image.id },
|
||||
data: { views: { increment: 1 } }
|
||||
data: { views: { increment: 1 } },
|
||||
});
|
||||
res.setHeader('Content-Type', image.mimetype);
|
||||
res.end(data);
|
||||
|
|
|
@ -18,11 +18,16 @@ const validator = yup.object({
|
|||
user_limit: yup.number().default(104900000),
|
||||
disabled_extensions: yup.array().default([]),
|
||||
}).required(),
|
||||
urls: yup.object({
|
||||
route: yup.string().required(),
|
||||
length: yup.number().default(6),
|
||||
}).required(),
|
||||
});
|
||||
|
||||
module.exports = async config => {
|
||||
|
||||
module.exports = config => {
|
||||
try {
|
||||
return await validator.validate(config, { abortEarly: false });
|
||||
return validator.validateSync(config, { abortEarly: false });
|
||||
} catch (e) {
|
||||
throw `${e.errors.length} errors occured\n${e.errors.map(x => '\t' + x).join('\n')}`;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import type { Config } from './types';
|
||||
import readConfig from './readConfig';
|
||||
import validateConfig from '../../server/validateConfig';
|
||||
|
||||
if (!global.config) global.config = readConfig() as Config;
|
||||
if (!global.config) global.config = validateConfig(readConfig()) as unknown as Config;
|
||||
|
||||
export default global.config;
|
|
@ -1,5 +1,5 @@
|
|||
const { format } = require('fecha');
|
||||
const { yellow, blueBright, magenta, red, cyan } = require('colorette');
|
||||
const { blueBright, red, cyan } = require('colorette');
|
||||
|
||||
class Logger {
|
||||
static get(clas) {
|
||||
|
|
|
@ -10,12 +10,16 @@ const envValues = [
|
|||
e('HOST', 'string', (c, v) => c.core.host = v),
|
||||
e('PORT', 'number', (c, v) => c.core.port = v),
|
||||
e('DATABASE_URL', 'string', (c, v) => c.core.database_url = v),
|
||||
|
||||
e('UPLOADER_ROUTE', 'string', (c, v) => c.uploader.route = v),
|
||||
e('UPLOADER_LENGTH', 'number', (c, v) => c.uploader.length = v),
|
||||
e('UPLOADER_DIRECTORY', 'string', (c, v) => c.uploader.directory = v),
|
||||
e('UPLOADER_ADMIN_LIMIT', 'number', (c, v) => c.uploader.admin_limit = v),
|
||||
e('UPLOADER_USER_LIMIT', 'number', (c, v) => c.uploader.user_limit = v),
|
||||
e('UPLOADER_DISABLED_EXTS', 'array', (c, v) => v ? c.uploader.disabled_extentions = v : c.uploader.disabled_extentions = []),
|
||||
|
||||
e('URLS_ROUTE', 'string', (c, v) => c.urls.route = v),
|
||||
e('URLS_LENGTH', 'number', (c, v) => c.urls.length = v),
|
||||
];
|
||||
|
||||
module.exports = () => {
|
||||
|
@ -46,8 +50,12 @@ function tryReadEnv() {
|
|||
directory: undefined,
|
||||
admin_limit: undefined,
|
||||
user_limit: undefined,
|
||||
disabled_extentions: undefined
|
||||
}
|
||||
disabled_extentions: undefined,
|
||||
},
|
||||
urls: {
|
||||
route: undefined,
|
||||
length: undefined,
|
||||
},
|
||||
};
|
||||
|
||||
for (let i = 0, L = envValues.length; i !== L; ++i) {
|
||||
|
|
|
@ -35,7 +35,16 @@ export interface ConfigUploader {
|
|||
disabled_extentions: string[];
|
||||
}
|
||||
|
||||
export interface ConfigUrls {
|
||||
// The route urls will be served on
|
||||
route: string;
|
||||
|
||||
// Length of random chars to generate for urls
|
||||
length: number;
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
core: ConfigCore;
|
||||
uploader: ConfigUploader;
|
||||
urls: ConfigUrls;
|
||||
}
|
|
@ -3,7 +3,7 @@ import { hash, verify } from 'argon2';
|
|||
import { readdir, stat } from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
import prisma from './prisma';
|
||||
import { InvisibleImage } from '@prisma/client';
|
||||
import { InvisibleImage, InvisibleUrl } from '@prisma/client';
|
||||
|
||||
export async function hashPassword(s: string): Promise<string> {
|
||||
return await hash(s);
|
||||
|
@ -89,21 +89,21 @@ export function bytesToRead(bytes: number) {
|
|||
return `${bytes.toFixed(1)} ${units[num]}`;
|
||||
}
|
||||
|
||||
export function createInvisURL(length: number) {
|
||||
export function randomInvis(length: number) {
|
||||
// some parts from https://github.com/tycrek/ass/blob/master/generators/lengthGen.js
|
||||
const invisibleCharset = ['\u200B', '\u2060', '\u200C', '\u200D'];
|
||||
|
||||
return [...randomBytes(length)].map((byte) => invisibleCharset[Number(byte) % invisibleCharset.length]).join('').slice(1).concat(invisibleCharset[0]);
|
||||
}
|
||||
|
||||
export function createInvis(length: number, imageId: number) {
|
||||
export function createInvisImage(length: number, imageId: number) {
|
||||
const retry = async (): Promise<InvisibleImage> => {
|
||||
const invis = createInvisURL(length);
|
||||
const invis = randomInvis(length);
|
||||
|
||||
const existing = await prisma.invisibleImage.findUnique({
|
||||
where: {
|
||||
invis
|
||||
}
|
||||
invis,
|
||||
},
|
||||
});
|
||||
|
||||
if (existing) return retry();
|
||||
|
@ -111,12 +111,37 @@ export function createInvis(length: number, imageId: number) {
|
|||
const inv = await prisma.invisibleImage.create({
|
||||
data: {
|
||||
invis,
|
||||
imageId
|
||||
}
|
||||
imageId,
|
||||
},
|
||||
});
|
||||
|
||||
return inv;
|
||||
};
|
||||
|
||||
return retry();
|
||||
}
|
||||
|
||||
export function createInvisURL(length: number, urlId: string) {
|
||||
const retry = async (): Promise<InvisibleUrl> => {
|
||||
const invis = randomInvis(length);
|
||||
|
||||
const existing = await prisma.invisibleUrl.findUnique({
|
||||
where: {
|
||||
invis,
|
||||
},
|
||||
});
|
||||
|
||||
if (existing) return retry();
|
||||
|
||||
const ur = await prisma.invisibleUrl.create({
|
||||
data: {
|
||||
invis,
|
||||
urlId,
|
||||
},
|
||||
});
|
||||
|
||||
return ur;
|
||||
};
|
||||
|
||||
return retry();
|
||||
}
|
|
@ -58,62 +58,86 @@ export default function EmbeddedImage({ image, title, username, color, normal, e
|
|||
export const getServerSideProps: GetServerSideProps = async (context) => {
|
||||
const id = context.params.id[1];
|
||||
const route = context.params.id[0];
|
||||
if (route !== config.uploader.route.substring(1)) return { notFound: true };
|
||||
const routes = [config.uploader.route.substring(1), config.urls.route.substring(1)];
|
||||
if (!routes.includes(route)) return { notFound: true };
|
||||
|
||||
const image = await prisma.image.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{ file: id },
|
||||
{ invisible: { invis: id } }
|
||||
]
|
||||
},
|
||||
select: {
|
||||
mimetype: true,
|
||||
id: true,
|
||||
file: true,
|
||||
invisible: true,
|
||||
userId: true,
|
||||
embed: true
|
||||
}
|
||||
});
|
||||
if (route === routes[1]) {
|
||||
const url = await prisma.url.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{ id },
|
||||
{ vanity: id },
|
||||
{ invisible: { invis: id } },
|
||||
],
|
||||
},
|
||||
select: {
|
||||
destination: true,
|
||||
},
|
||||
});
|
||||
if (!url) return { notFound: true };
|
||||
|
||||
if (!image) return { notFound: true };
|
||||
return {
|
||||
props: {},
|
||||
redirect: {
|
||||
destination: url.destination,
|
||||
},
|
||||
};
|
||||
|
||||
if (!image.embed) {
|
||||
const data = await getFile(config.uploader.directory, id);
|
||||
if (!data) return { notFound: true };
|
||||
} else {
|
||||
const image = await prisma.image.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{ file: id },
|
||||
{ invisible: { invis: id } },
|
||||
],
|
||||
},
|
||||
select: {
|
||||
mimetype: true,
|
||||
id: true,
|
||||
file: true,
|
||||
invisible: true,
|
||||
userId: true,
|
||||
embed: true,
|
||||
},
|
||||
});
|
||||
if (!image) return { notFound: true };
|
||||
|
||||
context.res.end(data);
|
||||
return { props: {} };
|
||||
};
|
||||
if (!image.embed) {
|
||||
const data = await getFile(config.uploader.directory, id);
|
||||
if (!data) return { notFound: true };
|
||||
|
||||
const user = await prisma.user.findFirst({
|
||||
select: {
|
||||
embedTitle: true,
|
||||
embedColor: true,
|
||||
username: true
|
||||
},
|
||||
where: {
|
||||
id: image.userId
|
||||
}
|
||||
});
|
||||
context.res.end(data);
|
||||
return { props: {} };
|
||||
};
|
||||
|
||||
const user = await prisma.user.findFirst({
|
||||
select: {
|
||||
embedTitle: true,
|
||||
embedColor: true,
|
||||
username: true,
|
||||
},
|
||||
where: {
|
||||
id: image.userId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!image.mimetype.startsWith('image')) {
|
||||
const data = await getFile(config.uploader.directory, id);
|
||||
if (!data) return { notFound: true };
|
||||
if (!image.mimetype.startsWith('image')) {
|
||||
const data = await getFile(config.uploader.directory, id);
|
||||
if (!data) return { notFound: true };
|
||||
|
||||
context.res.end(data);
|
||||
return { props: {} };
|
||||
};
|
||||
context.res.end(data);
|
||||
return { props: {} };
|
||||
};
|
||||
|
||||
return {
|
||||
props: {
|
||||
image,
|
||||
title: user.embedTitle,
|
||||
color: user.embedColor,
|
||||
username: user.username,
|
||||
normal: config.uploader.route,
|
||||
embed: image.embed
|
||||
}
|
||||
};
|
||||
return {
|
||||
props: {
|
||||
image,
|
||||
title: user.embedTitle,
|
||||
color: user.embedColor,
|
||||
username: user.username,
|
||||
normal: config.uploader.route,
|
||||
embed: image.embed,
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
39
src/pages/api/shorten.ts
Normal file
39
src/pages/api/shorten.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import prisma from 'lib/prisma';
|
||||
import zconfig from 'lib/config';
|
||||
import { NextApiReq, NextApiRes, withZipline } from 'lib/middleware/withZipline';
|
||||
import { createInvisURL, randomChars } from 'lib/util';
|
||||
import Logger from 'lib/logger';
|
||||
|
||||
async function handler(req: NextApiReq, res: NextApiRes) {
|
||||
if (req.method !== 'POST') return res.forbid('no allow');
|
||||
if (!req.headers.authorization) return res.forbid('no authorization');
|
||||
|
||||
const user = await prisma.user.findFirst({
|
||||
where: {
|
||||
token: req.headers.authorization,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) return res.forbid('authorization incorect');
|
||||
if (!req.body) return res.error('no body');
|
||||
if (!req.body.url) return res.error('no url');
|
||||
const rand = randomChars(zconfig.urls.length);
|
||||
|
||||
let invis;
|
||||
const url = await prisma.url.create({
|
||||
data: {
|
||||
id: rand,
|
||||
vanity: req.body.vanity ?? null,
|
||||
destination: req.body.url,
|
||||
userId: user.id,
|
||||
},
|
||||
});
|
||||
|
||||
if (req.headers.zws) invis = await createInvisURL(zconfig.urls.length, url.id);
|
||||
|
||||
Logger.get('url').info(`User ${user.username} (${user.id}) shortenned a url ${url.destination} (${url.id})`);
|
||||
|
||||
return res.json({ url: `${zconfig.core.secure ? 'https' : 'http'}://${req.headers.host}${zconfig.urls.route}/${req.body.vanity ? req.body.vanity : invis ? invis.invis : url.id}` });
|
||||
}
|
||||
|
||||
export default withZipline(handler);
|
|
@ -2,7 +2,7 @@ import multer from 'multer';
|
|||
import prisma from 'lib/prisma';
|
||||
import zconfig from 'lib/config';
|
||||
import { NextApiReq, NextApiRes, withZipline } from 'lib/middleware/withZipline';
|
||||
import { createInvis, randomChars } from 'lib/util';
|
||||
import { createInvisImage, randomChars } from 'lib/util';
|
||||
import { writeFile } from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
import Logger from 'lib/logger';
|
||||
|
@ -46,7 +46,7 @@ async function handler(req: NextApiReq, res: NextApiRes) {
|
|||
}
|
||||
});
|
||||
|
||||
if (req.headers.zws) invis = await createInvis(zconfig.uploader.length, image.id);
|
||||
if (req.headers.zws) invis = await createInvisImage(zconfig.uploader.length, image.id);
|
||||
|
||||
await writeFile(join(process.cwd(), zconfig.uploader.directory, image.file), file.buffer);
|
||||
Logger.get('image').info(`User ${user.username} (${user.id}) uploaded an image ${image.file} (${image.id})`);
|
||||
|
|
|
@ -24,8 +24,8 @@ export default function UploadPage({ route }) {
|
|||
export const getStaticProps: GetStaticProps = async (context) => {
|
||||
return {
|
||||
props: {
|
||||
route: config.uploader.route
|
||||
}
|
||||
route: config.uploader.route,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
|
36
yarn.lock
36
yarn.lock
|
@ -602,22 +602,22 @@
|
|||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.2.tgz#adea7b6953cbb34651766b0548468e743c6a2353"
|
||||
integrity sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q==
|
||||
|
||||
"@prisma/client@^3.0.2":
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.0.2.tgz#f04d9b252f3d0c6918df43ad228eac27d03f6db1"
|
||||
integrity sha512-6SrDYY2Yr5AmYpVB3XAXFqfzxKMdDTemXR7FmfXthnxWhQHoBwRLNZ3B3GyI/MmWa5tr+kaaGDJjp1LU0vuYvQ==
|
||||
"@prisma/client@^3.1.1":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.1.1.tgz#f4012631528049c22d12b212846dcf503db33cfe"
|
||||
integrity sha512-8ud8vVFMIg37yrkZ4wPpjKoMxFbCL0Pesq5eyLnag/s0LTKsVEN7ZBIQq9JzWW+AUqOzGKXr2Jt4Sl8xdGI99w==
|
||||
dependencies:
|
||||
"@prisma/engines-version" "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db"
|
||||
"@prisma/engines-version" "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f"
|
||||
|
||||
"@prisma/engines-version@2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db":
|
||||
version "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db.tgz#c45323e420f47dd950b22c873bdcf38f75e65779"
|
||||
integrity sha512-iArSApZZImVmT9oC/rGOjzvpG2AOqlIeqYcVnop9poA3FxD4zfVPbNPH9DTgOWhc06OkBHujJZeAcsNddVabIQ==
|
||||
"@prisma/engines-version@3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f":
|
||||
version "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f.tgz#f9908eb7808f2a546634398063942eaecb2474ef"
|
||||
integrity sha512-EuEMKLuwIcBO7uInZQHeG1yaywcfl32Tq8TDf5tgLvblk+ka70sej7S67lh3BV5gXMLTc3GdthSHPfDqZEK5uA==
|
||||
|
||||
"@prisma/engines@2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db":
|
||||
version "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db.tgz#b6cf70bc05dd2a62168a16f3ea58a1b011074621"
|
||||
integrity sha512-Q9CwN6e5E5Abso7J3A1fHbcF4NXGRINyMnf7WQ07fXaebxTTARY5BNUzy2Mo5uH82eRVO5v7ImNuR044KTjLJg==
|
||||
"@prisma/engines@3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f":
|
||||
version "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f.tgz#7b45708e6a42523dc9bc2214e5c62781f608dc3a"
|
||||
integrity sha512-6NEp0VlLho3hVtIvj2P4h0e19AYqQSXtFGts8gSIXDnV+l5pRFZaDMfGo2RiLMR0Kfrs8c3ZYxYX0sWmVL0tWw==
|
||||
|
||||
"@reduxjs/toolkit@^1.6.0":
|
||||
version "1.6.0"
|
||||
|
@ -4434,12 +4434,12 @@ prepend-http@^1.0.1:
|
|||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
|
||||
integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
|
||||
|
||||
prisma@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.0.2.tgz#e86cb6abf4a815c7ac97b9d0ed383f01c253ce34"
|
||||
integrity sha512-TyOCbtWGDVdWvsM1RhUzJXoGClXGalHhyYWIc5eizSF8T1ScGiOa34asBUdTnXOUBFSErbsqMNw40DHAteBm1A==
|
||||
prisma@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.1.1.tgz#4c13c35dd3a58af9134008c8ed0fdc21a632802c"
|
||||
integrity sha512-+eZtWIL6hnOKUOvqq9WLBzSw2d/EbTmOx1Td1LI8/0XE40ctXMLG2N1p6NK5/+yivGaoNJ9PDpPsPL9lO4nJrQ==
|
||||
dependencies:
|
||||
"@prisma/engines" "2.31.0-32.2452cc6313d52b8b9a96999ac0e974d0aedf88db"
|
||||
"@prisma/engines" "3.1.0-24.c22652b7e418506fab23052d569b85d3aec4883f"
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.1"
|
||||
|
|
Loading…
Reference in a new issue