Cleanup code and http 404 for not found

- Add 404 status code return for all not found errors
pull/4/head
trivernis 5 years ago
parent b27ed1def2
commit aafbbb5d52

@ -1,6 +1,10 @@
/**
* A result of a query to check if a phrase contains blacklisted phrases
*/
export class BlacklistedResult { export class BlacklistedResult {
constructor( constructor(
public blacklisted: boolean, public blacklisted: boolean,
public phrases: string[], public phrases: string[],
) {} ) {
}
} }

@ -425,7 +425,7 @@ export class MutationResolver extends BaseResolver {
* @param languageCode * @param languageCode
* @param request * @param request
*/ */
public async addToBlacklist({phrase, languageCode}: {phrase: string, languageCode?: string}, request: any): public async addToBlacklist({phrase, languageCode}: { phrase: string, languageCode?: string }, request: any):
Promise<boolean> { Promise<boolean> {
this.ensureLoggedIn(request); this.ensureLoggedIn(request);
const user = await User.findByPk(request.session.userId); const user = await User.findByPk(request.session.userId);
@ -448,7 +448,7 @@ export class MutationResolver extends BaseResolver {
* @param languageCode * @param languageCode
* @param request * @param request
*/ */
public async removeFromBlacklist({phrase, languageCode}: {phrase: string, languageCode: string}, request: any): public async removeFromBlacklist({phrase, languageCode}: { phrase: string, languageCode: string }, request: any):
Promise<boolean> { Promise<boolean> {
this.ensureLoggedIn(request); this.ensureLoggedIn(request);
const user = await User.findByPk(request.session.userId); const user = await User.findByPk(request.session.userId);

@ -6,16 +6,7 @@ import {PostNotFoundGqlError} from "../lib/errors/graphqlErrors";
import {GroupNotFoundError} from "../lib/errors/GroupNotFoundError"; import {GroupNotFoundError} from "../lib/errors/GroupNotFoundError";
import {RequestNotFoundError} from "../lib/errors/RequestNotFoundError"; import {RequestNotFoundError} from "../lib/errors/RequestNotFoundError";
import {UserNotFoundError} from "../lib/errors/UserNotFoundError"; import {UserNotFoundError} from "../lib/errors/UserNotFoundError";
import { import {Activity, BlacklistedPhrase, ChatRoom, Event, Group, Post, Request, User} from "../lib/models";
Activity,
BlacklistedPhrase,
ChatRoom,
Event,
Group,
Post,
Request,
User,
} from "../lib/models";
import {BlacklistedResult} from "./BlacklistedResult"; import {BlacklistedResult} from "./BlacklistedResult";
import {MutationResolver} from "./MutationResolver"; import {MutationResolver} from "./MutationResolver";
import {SearchResult} from "./SearchResult"; import {SearchResult} from "./SearchResult";
@ -31,7 +22,7 @@ export class QueryResolver extends MutationResolver {
* @param userId * @param userId
* @param handle * @param handle
*/ */
public async getUser({userId, handle}: {userId?: number, handle?: string}): Promise<User> { public async getUser({userId, handle}: { userId?: number, handle?: string }): Promise<User> {
let user: User; let user: User;
if (userId) { if (userId) {
user = await User.findByPk(userId); user = await User.findByPk(userId);
@ -52,7 +43,7 @@ export class QueryResolver extends MutationResolver {
* @param args * @param args
* @param request * @param request
*/ */
public async getSelf(args: null, request: any): Promise<User> { public async getSelf(args: null, request: any): Promise<User> {
this.ensureLoggedIn(request); this.ensureLoggedIn(request);
return User.findByPk(request.session.userId); return User.findByPk(request.session.userId);
} }
@ -61,7 +52,7 @@ export class QueryResolver extends MutationResolver {
* Returns a post for a given post id. * Returns a post for a given post id.
* @param postId * @param postId
*/ */
public async getPost({postId}: {postId: number}): Promise<Post> { public async getPost({postId}: { postId: number }): Promise<Post> {
const post = await Post.findByPk(postId); const post = await Post.findByPk(postId);
if (post) { if (post) {
return post; return post;
@ -74,7 +65,7 @@ export class QueryResolver extends MutationResolver {
* Returns a chat for a given chat id * Returns a chat for a given chat id
* @param chatId * @param chatId
*/ */
public async getChat({chatId}: {chatId: number}): Promise<ChatRoom> { public async getChat({chatId}: { chatId: number }): Promise<ChatRoom> {
const chat = await ChatRoom.findByPk(chatId); const chat = await ChatRoom.findByPk(chatId);
if (chat) { if (chat) {
return chat; return chat;
@ -87,7 +78,7 @@ export class QueryResolver extends MutationResolver {
* Returns a group for a given group id. * Returns a group for a given group id.
* @param groupId * @param groupId
*/ */
public async getGroup({groupId}: {groupId: number}): Promise<Group> { public async getGroup({groupId}: { groupId: number }): Promise<Group> {
const group = await Group.findByPk(groupId); const group = await Group.findByPk(groupId);
if (group) { if (group) {
return group; return group;
@ -100,7 +91,7 @@ export class QueryResolver extends MutationResolver {
* Returns the request for a given id. * Returns the request for a given id.
* @param requestId * @param requestId
*/ */
public async getRequest({requestId}: {requestId: number}): Promise<Request> { public async getRequest({requestId}: { requestId: number }): Promise<Request> {
const request = await Request.findByPk(requestId); const request = await Request.findByPk(requestId);
if (request) { if (request) {
return request; return request;
@ -115,7 +106,7 @@ export class QueryResolver extends MutationResolver {
* @param first * @param first
* @param offset * @param offset
*/ */
public async search({query, first, offset}: {query: number, first: number, offset: number}): Promise<SearchResult> { public async search({query, first, offset}: { query: number, first: number, offset: number }): Promise<SearchResult> {
const limit = first; const limit = first;
const users = await User.findAll({ const users = await User.findAll({
limit, limit,
@ -151,7 +142,7 @@ export class QueryResolver extends MutationResolver {
* @param offset * @param offset
* @param sort * @param sort
*/ */
public async getPosts({first, offset, sort}: {first: number, offset: number, sort: dataaccess.SortType}): public async getPosts({first, offset, sort}: { first: number, offset: number, sort: dataaccess.SortType }):
Promise<Post[]> { Promise<Post[]> {
return await dataaccess.getPosts(first, offset, sort); return await dataaccess.getPosts(first, offset, sort);
} }
@ -160,7 +151,7 @@ export class QueryResolver extends MutationResolver {
* Returns all activities * Returns all activities
*/ */
public async getActivities(): Promise<Activity[]> { public async getActivities(): Promise<Activity[]> {
return Activity.findAll(); return Activity.findAll();
} }
/** /**
@ -168,7 +159,7 @@ export class QueryResolver extends MutationResolver {
* @param email * @param email
* @param passwordHash * @param passwordHash
*/ */
public async getToken({email, passwordHash}: {email: string, passwordHash: string}): Promise<Token> { public async getToken({email, passwordHash}: { email: string, passwordHash: string }): Promise<Token> {
const user = await dataaccess.getUserByLogin(email, passwordHash); const user = await dataaccess.getUserByLogin(email, passwordHash);
return new Token(await user.token(), Number(user.authExpire).toString()); return new Token(await user.token(), Number(user.authExpire).toString());
} }
@ -177,7 +168,7 @@ export class QueryResolver extends MutationResolver {
* Returns if a input phrase contains blacklisted phrases and which one * Returns if a input phrase contains blacklisted phrases and which one
* @param phrase * @param phrase
*/ */
public async blacklisted({phrase}: {phrase: string}): Promise<BlacklistedResult> { public async blacklisted({phrase}: { phrase: string }): Promise<BlacklistedResult> {
const phrases = await dataaccess.checkBlacklisted(phrase); const phrases = await dataaccess.checkBlacklisted(phrase);
return new BlacklistedResult(phrases.length > 0, phrases return new BlacklistedResult(phrases.length > 0, phrases
.map((p) => p.phrase)); .map((p) => p.phrase));
@ -188,7 +179,7 @@ export class QueryResolver extends MutationResolver {
* @param first * @param first
* @param offset * @param offset
*/ */
public async getBlacklistedPhrases({first, offset}: {first: number, offset: number}): Promise<string[]> { public async getBlacklistedPhrases({first, offset}: { first: number, offset: number }): Promise<string[]> {
return (await BlacklistedPhrase.findAll({limit: first, offset})) return (await BlacklistedPhrase.findAll({limit: first, offset}))
.map((p) => p.phrase); .map((p) => p.phrase);
} }

@ -1,4 +1,4 @@
import {Group, Post, User, Event} from "../lib/models"; import {Event, Group, Post, User} from "../lib/models";
/** /**
* A class to wrap search results returned by the search resolver * A class to wrap search results returned by the search resolver
@ -9,5 +9,6 @@ export class SearchResult {
public groups: Group[], public groups: Group[],
public posts: Post[], public posts: Post[],
public events: Event[], public events: Event[],
) {} ) {
}
} }

@ -5,5 +5,6 @@ export class Token {
constructor( constructor(
public value: string, public value: string,
public expires: string, public expires: string,
) {} ) {
}
} }

@ -1,5 +1,4 @@
import * as crypto from "crypto"; import * as crypto from "crypto";
import {GraphQLError} from "graphql";
import * as sqz from "sequelize"; import * as sqz from "sequelize";
import {Sequelize} from "sequelize-typescript"; import {Sequelize} from "sequelize-typescript";
import {ActivityNotFoundError} from "./errors/ActivityNotFoundError"; import {ActivityNotFoundError} from "./errors/ActivityNotFoundError";
@ -166,11 +165,20 @@ namespace dataaccess {
} else { } else {
// more performant way to get the votes with plain sql // more performant way to get the votes with plain sql
return await sequelize.query( return await sequelize.query(
`SELECT * FROM ( `SELECT *
SELECT *, FROM (
(SELECT count(*) FROM post_votes WHERE vote_type = 'UPVOTE' AND post_id = posts.id) AS upvotes , SELECT *,
(SELECT count(*) FROM post_votes WHERE vote_type = 'DOWNVOTE' AND post_id = posts.id) AS downvotes (SELECT count(*)
FROM posts) AS a ORDER BY (a.upvotes - a.downvotes) DESC, a.upvotes DESC, a.id LIMIT ? OFFSET ?`, FROM post_votes
WHERE vote_type = 'UPVOTE' AND post_id = posts.id) AS upvotes,
(SELECT count(*)
FROM post_votes
WHERE vote_type = 'DOWNVOTE' AND post_id = posts.id) AS downvotes
FROM posts) AS a
ORDER BY (a.upvotes - a.downvotes) DESC, a.upvotes DESC, a.id
LIMIT ?
OFFSET
?`,
{replacements: [first, offset], mapToModel: true, model: models.Post}) as models.Post[]; {replacements: [first, offset], mapToModel: true, model: models.Post}) as models.Post[];
} }
} }
@ -359,7 +367,10 @@ namespace dataaccess {
export async function checkBlacklisted(phrase: string, language: string = "en"): export async function checkBlacklisted(phrase: string, language: string = "en"):
Promise<models.BlacklistedPhrase[]> { Promise<models.BlacklistedPhrase[]> {
return sequelize.query<BlacklistedPhrase>(` return sequelize.query<BlacklistedPhrase>(`
SELECT * FROM blacklisted_phrases WHERE ? ~* phrase AND language = ?`, SELECT *
FROM blacklisted_phrases
WHERE ? ~* phrase
AND language = ?`,
{replacements: [phrase, language], mapToModel: true, model: BlacklistedPhrase}); {replacements: [phrase, language], mapToModel: true, model: BlacklistedPhrase});
} }

@ -4,6 +4,9 @@ import {BaseError} from "./BaseError";
* An error that is thrown when an activity was not found. * An error that is thrown when an activity was not found.
*/ */
export class ActivityNotFoundError extends BaseError { export class ActivityNotFoundError extends BaseError {
public readonly statusCode = httpStatus.NOT_FOUND;
constructor(id: number) { constructor(id: number) {
super(`The activity with the id ${id} could not be found.`); super(`The activity with the id ${id} could not be found.`);
} }

@ -4,6 +4,9 @@ import {BaseError} from "./BaseError";
* Represents an error that is thrown when a blacklisted phrase is used. * Represents an error that is thrown when a blacklisted phrase is used.
*/ */
export class BlacklistedError extends BaseError { export class BlacklistedError extends BaseError {
public readonly statusCode = httpStatus.NOT_ACCEPTABLE;
constructor(public phrases: string[], field: string = "input") { constructor(public phrases: string[], field: string = "input") {
super(`The ${field} contains the blacklisted words: ${phrases.join(", ")}`); super(`The ${field} contains the blacklisted words: ${phrases.join(", ")}`);
} }

@ -4,6 +4,9 @@ import {BaseError} from "./BaseError";
* An error that is thrown when the chatroom doesn't exist * An error that is thrown when the chatroom doesn't exist
*/ */
export class ChatNotFoundError extends BaseError { export class ChatNotFoundError extends BaseError {
public readonly statusCode = httpStatus.NOT_FOUND;
constructor(chatId: number) { constructor(chatId: number) {
super(`Chat with id ${chatId} not found.`); super(`Chat with id ${chatId} not found.`);
} }

@ -4,6 +4,9 @@ import {BaseError} from "./BaseError";
* An error that is thrown when a group was not found for a specified id * An error that is thrown when a group was not found for a specified id
*/ */
export class GroupNotFoundError extends BaseError { export class GroupNotFoundError extends BaseError {
public readonly statusCode = httpStatus.NOT_FOUND;
constructor(groupId: number) { constructor(groupId: number) {
super(`Group ${groupId} not found!`); super(`Group ${groupId} not found!`);
} }

@ -4,6 +4,10 @@ import {BaseError} from "./BaseError";
* An error that is thrown when no action was specified on a group membership change * An error that is thrown when no action was specified on a group membership change
*/ */
export class NoActionSpecifiedError extends BaseError { export class NoActionSpecifiedError extends BaseError {
public readonly statusCode = httpStatus.NO_CONTENT;
// @ts-ignore
constructor(actions?: any) { constructor(actions?: any) {
if (actions) { if (actions) {
super(`No action of '${Object.keys(actions).join(", ")}'`); super(`No action of '${Object.keys(actions).join(", ")}'`);

@ -1,11 +1,11 @@
import * as status from "http-status"; import * as httpStatus from "http-status";
import {BaseError} from "./BaseError"; import {BaseError} from "./BaseError";
/** /**
* An error that is thrown when a non-admin tries to perform an admin action * An error that is thrown when a non-admin tries to perform an admin action
*/ */
export class NotAGroupAdminError extends BaseError { export class NotAGroupAdminError extends BaseError {
public readonly statusCode = status.FORBIDDEN; public readonly statusCode = httpStatus.FORBIDDEN;
constructor(groupId: number) { constructor(groupId: number) {
super(`You are not an admin of '${groupId}'`); super(`You are not an admin of '${groupId}'`);

@ -10,5 +10,4 @@ export class NotTheGroupCreatorError extends BaseError {
constructor(groupId: number) { constructor(groupId: number) {
super(`You are not the creator of '${groupId}'`); super(`You are not the creator of '${groupId}'`);
} }
} }

@ -4,6 +4,9 @@ import {BaseError} from "./BaseError";
* An error that is thrown when a post was not found * An error that is thrown when a post was not found
*/ */
export class PostNotFoundError extends BaseError { export class PostNotFoundError extends BaseError {
public readonly statusCode = httpStatus.NOT_FOUND;
constructor(postId: number) { constructor(postId: number) {
super(`Post '${postId}' not found!`); super(`Post '${postId}' not found!`);
} }

@ -5,6 +5,9 @@ import {BaseError} from "./BaseError";
* An error that is thrown when a request for a sender, receiver and type was not found * An error that is thrown when a request for a sender, receiver and type was not found
*/ */
export class RequestNotFoundError extends BaseError { export class RequestNotFoundError extends BaseError {
public readonly statusCode = httpStatus.NOT_FOUND;
// @ts-ignore
constructor(sender: number, receiver?: number, type?: dataaccess.RequestType) { constructor(sender: number, receiver?: number, type?: dataaccess.RequestType) {
if (!receiver) { if (!receiver) {
super(`Request with id '${sender} not found.'`); super(`Request with id '${sender} not found.'`);

@ -4,6 +4,9 @@ import {BaseError} from "./BaseError";
* An error that is thrown when a specified user was not found * An error that is thrown when a specified user was not found
*/ */
export class UserNotFoundError extends BaseError { export class UserNotFoundError extends BaseError {
public readonly statusCode = httpStatus.NOT_FOUND;
constructor(username: (string | number)) { constructor(username: (string | number)) {
super(`User ${username} not found!`); super(`User ${username} not found!`);
} }

@ -17,21 +17,3 @@ export class PostNotFoundGqlError extends GraphQLError {
super(`Post '${postId}' not found!`); super(`Post '${postId}' not found!`);
} }
} }
/**
* An error for the frontend that is thrown when a group was not found
*/
export class GroupNotFoundGqlError extends GraphQLError {
constructor(groupId: number) {
super(`Group '${groupId}' not found!`);
}
}
/**
* An error for the frontend that is thrown when a nonadmin tries to perform an admin operation.
*/
export class NotAnAdminGqlError extends GraphQLError {
constructor() {
super("You are not an admin.");
}
}

@ -1,6 +1,6 @@
import * as MarkdownIt from "markdown-it/lib"; import * as MarkdownIt from "markdown-it/lib";
const { html5Media } = require("markdown-it-html5-media"); const {html5Media} = require("markdown-it-html5-media");
const mdEmoji = require("markdown-it-emoji"); const mdEmoji = require("markdown-it-emoji");
namespace markdown { namespace markdown {

@ -1,15 +1,5 @@
import * as sqz from "sequelize"; import * as sqz from "sequelize";
import { import {Column, Model, NotNull, Table, Unique} from "sequelize-typescript";
BelongsTo,
BelongsToMany,
Column,
ForeignKey,
HasMany,
Model,
NotNull,
Table,
Unique,
} from "sequelize-typescript";
/** /**
* Represents a blacklisted phrase * Represents a blacklisted phrase

@ -81,7 +81,7 @@ export class Event extends Model<Event> {
* @param userId * @param userId
* @param request * @param request
*/ */
public async deletable({userId}: {userId: number}, request: any): Promise<boolean> { public async deletable({userId}: { userId: number }, request: any): Promise<boolean> {
userId = userId ?? request.session.userId; userId = userId ?? request.session.userId;
if (userId) { if (userId) {
const group = await this.$get<Group>("rGroup") as Group; const group = await this.$get<Group>("rGroup") as Group;

@ -150,7 +150,7 @@ export class Group extends Model<Group> {
* @param userId * @param userId
* @param request * @param request
*/ */
public async deletable({userId}: {userId?: number}, request: any): Promise<boolean> { public async deletable({userId}: { userId?: number }, request: any): Promise<boolean> {
userId = userId ?? request.session.userId; userId = userId ?? request.session.userId;
if (userId) { if (userId) {
return this.creatorId === userId; return this.creatorId === userId;

@ -1,6 +1,5 @@
import * as sqz from "sequelize"; import * as sqz from "sequelize";
import {BelongsTo, BelongsToMany, Column, CreatedAt, ForeignKey, Model, NotNull, Table} from "sequelize-typescript"; import {BelongsTo, BelongsToMany, Column, CreatedAt, ForeignKey, Model, NotNull, Table} from "sequelize-typescript";
import globals from "../globals";
import markdown from "../markdown"; import markdown from "../markdown";
import {Activity} from "./Activity"; import {Activity} from "./Activity";
import {PostVote, VoteType} from "./PostVote"; import {PostVote, VoteType} from "./PostVote";

@ -5,7 +5,6 @@ import {Router} from "express";
import * as fileUpload from "express-fileupload"; import * as fileUpload from "express-fileupload";
import {UploadedFile} from "express-fileupload"; import {UploadedFile} from "express-fileupload";
import * as fsx from "fs-extra"; import * as fsx from "fs-extra";
import {IncomingMessage} from "http";
import * as status from "http-status"; import * as status from "http-status";
import * as path from "path"; import * as path from "path";
import * as sharp from "sharp"; import * as sharp from "sharp";

Loading…
Cancel
Save