feat: implement album links endpoints

This commit is contained in:
Pitu 2021-08-18 01:12:50 +09:00
parent 858f0ae4b0
commit b0ab951a98
10 changed files with 148 additions and 182 deletions

View File

@ -66,7 +66,7 @@ model links {
id Int @id @default(autoincrement())
userId Int
albumId Int
identifier String
identifier String @unique
views Int @default(0)
enabled Boolean @default(true)
enableDownload Boolean @default(false)
@ -74,7 +74,7 @@ model links {
createdAt DateTime @default(now())
editedAt DateTime?
@@unique([userId, albumId, identifier], name: "links_userid_albumid_identifier_unique")
@@unique([userId, identifier], name: "links_userid_identifier_unique")
}
model settings {
@ -107,15 +107,13 @@ model tags {
model users {
id Int @id @default(autoincrement())
username String
username String @unique
password String
enabled Boolean @default(true)
isAdmin Boolean @default(false)
apiKey String?
apiKey String? @unique
passwordEditedAt DateTime?
apiKeyEditedAt DateTime?
createdAt DateTime @default(now())
editedAt DateTime?
@@unique([username, apiKey], name: "users_username_apikey_unique")
}

View File

@ -4,7 +4,9 @@ import prisma from '../../../../structures/database';
interface body {
ip: string;
}
export const middlewares = ['auth', 'admin'];
export const run = async (req: FastifyRequest, res: FastifyReply) => {
if (!req.body) return res.status(400).send({ message: 'No body provided' });
// const { username, password }: { username: string; password: string } = req.body;

View File

@ -0,0 +1,26 @@
import type { FastifyReply } from 'fastify';
import type { RequestWithUser } from '../../../../structures/interfaces';
import prisma from '../../../../structures/database';
interface params {
id: number;
}
export const middlewares = ['auth'];
export const run = async (req: RequestWithUser, res: FastifyReply) => {
const { id } = req.params as params;
if (!id) return res.status(400).send({ message: 'Invalid id supplied' });
const links = await prisma.links.findMany({
where: {
albumId: id,
userId: req.user.id
}
});
return res.send({
message: 'Successfully retrieved links',
links
});
};

View File

@ -5,41 +5,39 @@ 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' });
if (!identifier) return res.status(400).send({ message: 'No identifier provided' });
const link = await prisma.links.findFirst({
where: {
identifier,
userId: req.user.id
userId: req.user.id,
identifier
}
});
if (!link) return res.status(400).send({ message: 'No link found' });
await prisma.links.delete({
where: {
links_userid_albumid_identifier_unique: {
links_userid_identifier_unique: {
userId: req.user.id,
identifier
}
}
});
const albumLink = await prisma.albumsLinks.findFirst({
where: {
linkId: link.id
}
});
await prisma.albumsLinks.delete({
where: {
id: albumLink.id
linkId: link.id
}
});
return res.send({
message: 'Successfully banned the ip'
message: 'Successfully deleted the link'
});
};

View File

@ -0,0 +1,44 @@
import type { FastifyReply } from 'fastify';
import type { RequestWithUser } from '../../../../structures/interfaces';
import prisma from '../../../../structures/database';
interface body {
identifier: string;
enableDownload: boolean;
expiresAt: Date;
}
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, enableDownload, expiresAt } = req.body as body;
if (!identifier) return res.status(400).send({ message: 'No identifier provided' });
const link = await prisma.links.findFirst({
where: {
userId: req.user.id,
identifier
}
});
if (!link) return res.status(400).send({ message: 'No link found' });
const updateObj = {
enableDownload: enableDownload || false,
expiresAt // This one should be null if not supplied
};
await prisma.links.update({
where: {
identifier
},
data: {
...updateObj
}
});
return res.send({
message: 'Successfully edited link'
});
};

View File

@ -0,0 +1,61 @@
import type { FastifyReply } from 'fastify';
import prisma from '../../../../structures/database';
import { RequestWithUser } from '../../../../structures/interfaces';
import { getUniqueAlbumIdentifier } from '../../../../utils/Util';
interface body {
albumId: number;
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 { albumId } = req.body as body;
if (!albumId) return res.status(400).send({ message: 'No albumId provided' });
const exists = await prisma.albums.findFirst({
where: {
id: albumId,
userId: req.user.id
}
});
if (!exists) return res.status(400).send({ message: 'Album doesn\t exist' });
let { identifier } = req.body as body;
if (identifier) {
if (!req.user.isAdmin) return res.status(401).send({ message: 'Only administrators can create custom links' });
if (!(/^[a-zA-Z0-9-_]+$/.test(identifier))) return res.status(400).send({ message: 'Only alphanumeric, dashes, and underscore characters are allowed' });
const identifierExists = await prisma.links.findFirst({
where: {
identifier
}
});
if (identifierExists) return res.status(400).send({ message: 'Album with this identifier already exists' });
} else {
identifier = await getUniqueAlbumIdentifier();
if (!identifier) return res.status(500).send({ message: 'There was a problem allocating a link for your album' });
}
const insertObj = {
identifier,
userId: req.user.id,
albumId,
enabled: true,
enableDownload: true,
expiresAt: null,
views: 0
};
await prisma.links.create({
data: insertObj
});
return res.send({
message: 'Successfully created link',
data: insertObj
});
};

View File

@ -1,35 +0,0 @@
const Route = require('../../../structures/Route');
class linkDELETE extends Route {
constructor() {
super('/album/link/delete/:identifier', 'delete');
}
async run(req, res, db, user) {
const { identifier } = req.params;
if (!identifier) return res.status(400).json({ message: 'Invalid identifier supplied' });
try {
const link = await db.table('links')
.where({ identifier, userId: user.id })
.first();
if (!link) return res.status(400).json({ message: 'Identifier doesn\'t exist or doesnt\'t belong to the user' });
await db.table('links')
.where({ id: link.id })
.delete();
await db.table('albumsLinks')
.where({ linkId: link.id })
.delete();
} catch (error) {
return super.error(res, error);
}
return res.json({
message: 'Successfully deleted link'
});
}
}
module.exports = linkDELETE;

View File

@ -1,38 +0,0 @@
const Route = require('../../../structures/Route');
class linkEditPOST extends Route {
constructor() {
super('/album/link/edit', 'post');
}
async run(req, res, db, user) {
if (!req.body) return res.status(400).json({ message: 'No body provided' });
const { identifier, enableDownload, expiresAt } = req.body;
if (!identifier) return res.status(400).json({ message: 'Invalid album identifier supplied' });
/*
Make sure the link exists
*/
const link = await db
.table('links')
.where({ identifier, userId: user.id })
.first();
if (!link) return res.status(400).json({ message: "The link doesn't exist or doesn't belong to the user" });
try {
const updateObj = {
enableDownload: enableDownload || false,
expiresAt // This one should be null if not supplied
};
await db
.table('links')
.where({ identifier })
.update(updateObj);
return res.json({ message: 'Editing the link was successful', data: updateObj });
} catch (error) {
return super.error(res, error);
}
}
}
module.exports = linkEditPOST;

View File

@ -1,68 +0,0 @@
const Route = require('../../../structures/Route');
const Util = require('../../../utils/Util');
class linkPOST extends Route {
constructor() {
super('/album/link/new', 'post');
}
async run(req, res, db, user) {
if (!req.body) return res.status(400).json({ message: 'No body provided' });
const { albumId } = req.body;
if (!albumId) return res.status(400).json({ message: 'No album provided' });
/*
Make sure the album exists
*/
const exists = await db
.table('albums')
.where({ id: albumId, userId: user.id })
.first();
if (!exists) return res.status(400).json({ message: 'Album doesn\t exist' });
let { identifier } = req.body;
if (identifier) {
if (!user.isAdmin) return res.status(401).json({ message: 'Only administrators can create custom links' });
if (!(/^[a-zA-Z0-9-_]+$/.test(identifier))) return res.status(400).json({ message: 'Only alphanumeric, dashes, and underscore characters are allowed' });
/*
Make sure that the id doesn't already exists in the database
*/
const idExists = await db
.table('links')
.where({ identifier })
.first();
if (idExists) return res.status(400).json({ message: 'Album with this identifier already exists' });
} else {
/*
Try to allocate a new identifier in the database
*/
identifier = await Util.getUniqueAlbumIdentifier();
if (!identifier) return res.status(500).json({ message: 'There was a problem allocating a link for your album' });
}
try {
const insertObj = {
identifier,
userId: user.id,
albumId,
enabled: true,
enableDownload: true,
expiresAt: null,
views: 0
};
await db.table('links').insert(insertObj).wasMutated();
return res.json({
message: 'The link was created successfully',
data: insertObj
});
} catch (error) {
return super.error(res, error);
}
}
}
module.exports = linkPOST;

View File

@ -1,22 +0,0 @@
const Route = require('../../../structures/Route');
class linkPOST extends Route {
constructor() {
super('/album/:id/links', 'get');
}
async run(req, res, db, user) {
const { id } = req.params;
if (!id) return res.status(400).json({ message: 'Invalid id supplied' });
const links = await db.table('links')
.where({ albumId: id, userId: user.id });
return res.json({
message: 'Successfully retrieved links',
links
});
}
}
module.exports = linkPOST;