add image router
This commit is contained in:
parent
21bcf5c5ac
commit
2b79aff2c7
16
src/models/Image.ts
Normal file
16
src/models/Image.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { UUID } from "https://deno.land/x/mongo@v0.31.2/mod.ts";
|
||||||
|
|
||||||
|
export enum Visibility {
|
||||||
|
Public,
|
||||||
|
Unlisted,
|
||||||
|
Private,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default interface Image {
|
||||||
|
_id: UUID;
|
||||||
|
backingURL: string;
|
||||||
|
name: string;
|
||||||
|
visibility: Visibility;
|
||||||
|
created: Date;
|
||||||
|
author: UUID;
|
||||||
|
}
|
38
src/routers/ImageRouter.ts
Normal file
38
src/routers/ImageRouter.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { Collection } from "https://deno.land/x/mongo@v0.31.2/mod.ts";
|
||||||
|
import { UUID } from "https://deno.land/x/web_bson@v0.3.0/mod.js";
|
||||||
|
|
||||||
|
import { auth, jwt, rest, schema, uuid } from "../server/decorators.ts";
|
||||||
|
import { JWTPayload } from "../utils/JWT.ts";
|
||||||
|
import AppRouter from "./AppRouter.ts";
|
||||||
|
import HttpError from "../server/HttpError.ts";
|
||||||
|
import User from "../models/User.ts";
|
||||||
|
import Image, { Visibility } from "../models/Image.ts";
|
||||||
|
|
||||||
|
export default class ImageRouter extends AppRouter {
|
||||||
|
public static serialize(image: Image) {
|
||||||
|
return {
|
||||||
|
author: image.author,
|
||||||
|
created: image.created.getTime() / 1000,
|
||||||
|
name: image.name,
|
||||||
|
visibility: image.visibility,
|
||||||
|
id: image._id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@rest('GET', '/')
|
||||||
|
async get(@uuid() @schema('string') id: string, @jwt(v => v.salt, false) @auth() jwt?: JWTPayload) {
|
||||||
|
const image = await this.images.findOne({ _id: new UUID(id) });
|
||||||
|
|
||||||
|
if (
|
||||||
|
!image ||
|
||||||
|
image.visibility === Visibility.Private && image.author !== jwt?.name
|
||||||
|
) throw new HttpError("Image doesn't exist.");
|
||||||
|
|
||||||
|
return ImageRouter.serialize(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
public constructor(private salt: string, private images: Collection<Image>, private users: Collection<User>) {
|
||||||
|
super();
|
||||||
|
users.createIndexes({ indexes: [ { key: { username: 1 }, name: 'Username Index' } ] });
|
||||||
|
}
|
||||||
|
}
|
@ -1,20 +1,28 @@
|
|||||||
import { Collection } from "https://deno.land/x/mongo@v0.31.2/mod.ts";
|
import { Database } from "https://deno.land/x/mongo@v0.31.2/mod.ts";
|
||||||
import UserRouter from "../routers/UserRouter.ts";
|
import UserRouter from "../routers/UserRouter.ts";
|
||||||
import User from "../models/User.ts";
|
import ImageRouter from "./ImageRouter.ts";
|
||||||
import Response from "../server/RestResponse.ts";
|
import AppRouter from "./AppRouter.ts";
|
||||||
import Router from "../server/Router.ts";
|
import RestResponse from "../server/RestResponse.ts";
|
||||||
import { rest, route } from "../server/decorators.ts";
|
import { rest, route } from "../server/decorators.ts";
|
||||||
|
import User from "../models/User.ts";
|
||||||
|
import Image from "../models/Image.ts";
|
||||||
|
|
||||||
export class RootRouter extends Router {
|
export class RootRouter extends AppRouter {
|
||||||
@route('users/*') users;
|
@route('users/*') users;
|
||||||
|
@route('images/*') images;
|
||||||
|
|
||||||
@rest('*', '*')
|
@rest('*', '*')
|
||||||
default() {
|
default() {
|
||||||
return new Response().body(new Blob(['Page not found :/'])).status(404);
|
return new RestResponse().body(new Blob(['Page not found :/'])).status(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(salt: string, users: Collection<User>) {
|
constructor(salt: string, db: Database) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
const users = db.collection<User>('users');
|
||||||
|
const images = db.collection<Image>('images');
|
||||||
|
|
||||||
this.users = new UserRouter(salt, users);
|
this.users = new UserRouter(salt, users);
|
||||||
|
this.images = new ImageRouter(salt, images, users);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ export default class UserRouter extends AppRouter {
|
|||||||
) {
|
) {
|
||||||
const res = await this.users.findOne({ username: body.username });
|
const res = await this.users.findOne({ username: body.username });
|
||||||
if (!res) throw new HttpError('Incorrect username or password.');
|
if (!res) throw new HttpError('Incorrect username or password.');
|
||||||
const hashed = await bcrypt.hash(res.password, this.salt);
|
const hashed = await bcrypt.hash(body.password, this.salt);
|
||||||
|
|
||||||
if (res.password !== hashed) throw new HttpError('Incorrect username or password.');
|
if (res.password !== hashed) throw new HttpError('Incorrect username or password.');
|
||||||
|
|
||||||
|
@ -3,5 +3,7 @@ import rest from "./decorators/rest.ts";
|
|||||||
import auth from "./decorators/auth.ts";
|
import auth from "./decorators/auth.ts";
|
||||||
import route from "./decorators/route.ts";
|
import route from "./decorators/route.ts";
|
||||||
import schema from "./decorators/schema.ts";
|
import schema from "./decorators/schema.ts";
|
||||||
|
import jwt from "./decorators/jwt.ts";
|
||||||
|
import uuid from "./decorators/uuid.ts";
|
||||||
|
|
||||||
export { body, schema, rest, route, auth };
|
export { body, schema, rest, route, auth , jwt, uuid };
|
14
src/server/decorators/uuid.ts
Normal file
14
src/server/decorators/uuid.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { UUID } from "https://deno.land/x/mongo@v0.31.2/mod.ts";
|
||||||
|
import { makeParameterModifier } from "../Router.ts";
|
||||||
|
import HttpError from "../HttpError.ts";
|
||||||
|
|
||||||
|
export default function uuid() {
|
||||||
|
return makeParameterModifier((_req, val) => {
|
||||||
|
try {
|
||||||
|
return new UUID(val);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
throw new HttpError("Invalid UUID given.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
@ -2,12 +2,12 @@ const undefinedBuff = new Blob([new TextEncoder().encode('undefined')]);
|
|||||||
const nullBuff = new Blob([new TextEncoder().encode('null')]);
|
const nullBuff = new Blob([new TextEncoder().encode('null')]);
|
||||||
|
|
||||||
export default async function serialize(val: unknown, depth = 16): Promise<Blob> {
|
export default async function serialize(val: unknown, depth = 16): Promise<Blob> {
|
||||||
while(true) {
|
while (true) {
|
||||||
if(depth <= 0) throw new Error("Call depth exceeded limit.");
|
if (depth <= 0) throw new Error("Call depth exceeded limit.");
|
||||||
|
|
||||||
if(val instanceof Promise) val = await val;
|
if (val instanceof Promise) val = await val;
|
||||||
else if(val instanceof Function) {
|
else if (val instanceof Function) {
|
||||||
if(val.length !== 0) throw new Error('Can\'t serialize an argument-accepting function');
|
if (val.length !== 0) throw new Error('Can\'t serialize an argument-accepting function');
|
||||||
val = val();
|
val = val();
|
||||||
}
|
}
|
||||||
else break;
|
else break;
|
||||||
@ -15,11 +15,12 @@ export default async function serialize(val: unknown, depth = 16): Promise<Blob>
|
|||||||
depth--;
|
depth--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(val === undefined) return undefinedBuff;
|
if (val === undefined) return undefinedBuff;
|
||||||
if(val === null) return nullBuff;
|
if (val === null) return nullBuff;
|
||||||
if(val instanceof Blob) return val;
|
if (typeof val === 'string') return new Blob([val]);
|
||||||
|
if (val instanceof Blob) return val;
|
||||||
|
|
||||||
while(typeof val !== 'string' && val && val.toString !== Object.prototype.toString && val.toString instanceof Function) {
|
if (val.toString !== Object.prototype.toString && val.toString instanceof Function) {
|
||||||
val = val.toString();
|
val = val.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user