Add all resolvers and help types to classes
- Add resolvers to Mutation class - Add reslovers to Query class - Add helper classes for several types and errorspull/4/head
parent
164ecb77c6
commit
57091e522c
@ -0,0 +1,17 @@
|
||||
import {NotLoggedInGqlError} from "../lib/errors/graphqlErrors";
|
||||
|
||||
/**
|
||||
* Base resolver class to provide common methods to all resolver classes
|
||||
*/
|
||||
export abstract class BaseResolver {
|
||||
|
||||
/**
|
||||
* Checks if the user is logged in and throws an exception if not
|
||||
* @param request
|
||||
*/
|
||||
protected ensureLoggedIn(request: any) {
|
||||
if (!request.session.userId) {
|
||||
throw new NotLoggedInGqlError();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
export class BlacklistedResult {
|
||||
constructor(
|
||||
public blacklisted: boolean,
|
||||
public phrases: string[],
|
||||
) {}
|
||||
}
|
@ -1,6 +1,467 @@
|
||||
import {GraphQLError} from "graphql";
|
||||
import * as yaml from "js-yaml";
|
||||
import isEmail from "validator/lib/isEmail";
|
||||
import dataaccess from "../lib/dataAccess";
|
||||
import {BlacklistedError} from "../lib/errors/BlacklistedError";
|
||||
import {GroupNotFoundError} from "../lib/errors/GroupNotFoundError";
|
||||
import {InvalidEmailError} from "../lib/errors/InvalidEmailError";
|
||||
import {NotAGroupAdminError} from "../lib/errors/NotAGroupAdminError";
|
||||
import {NotAnAdminError} from "../lib/errors/NotAnAdminError";
|
||||
import {NotTheGroupCreatorError} from "../lib/errors/NotTheGroupCreatorError";
|
||||
import {PostNotFoundError} from "../lib/errors/PostNotFoundError";
|
||||
import globals from "../lib/globals";
|
||||
import {InternalEvents} from "../lib/InternalEvents";
|
||||
import {Activity, BlacklistedPhrase, ChatMessage, ChatRoom, Event, Group, Post, Request, User} from "../lib/models";
|
||||
import {BaseResolver} from "./BaseResolver";
|
||||
|
||||
const legit = require("legit");
|
||||
|
||||
/**
|
||||
* A class that provides methods to resolve mutations
|
||||
*/
|
||||
export class MutationResolver {
|
||||
export class MutationResolver extends BaseResolver {
|
||||
|
||||
/**
|
||||
* Accepts the usage of cookies and stores the session
|
||||
* @param args
|
||||
* @param request
|
||||
*/
|
||||
public acceptCookies(args: null, request: any): boolean {
|
||||
request.session.cookiesAccepted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loggs in and appends the user id to the session
|
||||
* @param email
|
||||
* @param passwordHash
|
||||
* @param request
|
||||
*/
|
||||
public async login({email, passwordHash}: { email: string, passwordHash: string }, request: any): Promise<User> {
|
||||
const user = await dataaccess.getUserByLogin(email, passwordHash);
|
||||
request.session.userId = user.id;
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loggs out by removing the user from the session
|
||||
* @param args
|
||||
* @param request
|
||||
*/
|
||||
public logout(args: null, request: any) {
|
||||
this.ensureLoggedIn(request);
|
||||
delete request.session.userId;
|
||||
request.session.save((err: any) => {
|
||||
if (err) {
|
||||
globals.logger.error(err.message);
|
||||
globals.logger.debug(err.stack);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new user account
|
||||
* @param username
|
||||
* @param email
|
||||
* @param passwordHash
|
||||
* @param request
|
||||
*/
|
||||
public async register({username, email, passwordHash}: { username: string, email: string, passwordHash: string },
|
||||
request: any): Promise<User> {
|
||||
let mailValid = isEmail(email);
|
||||
if (mailValid) {
|
||||
try {
|
||||
mailValid = (await legit(email)).isValid;
|
||||
} catch (err) {
|
||||
globals.logger.warn(`Mail legit check returned: ${err.message}`);
|
||||
globals.logger.debug(err.stack);
|
||||
mailValid = false;
|
||||
}
|
||||
}
|
||||
if (!mailValid) {
|
||||
throw new InvalidEmailError(email);
|
||||
}
|
||||
const user = await dataaccess.registerUser(username, email, passwordHash);
|
||||
request.session.userId = user.id;
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the frontend settings for the logged in user
|
||||
* @param settings
|
||||
* @param request
|
||||
*/
|
||||
public async setUserSettings({settings}: { settings: string }, request: any): Promise<string> {
|
||||
this.ensureLoggedIn(request);
|
||||
const user = await User.findByPk(request.session.userId);
|
||||
try {
|
||||
user.frontendSettings = yaml.safeLoad(settings);
|
||||
await user.save();
|
||||
return user.settings;
|
||||
} catch (err) {
|
||||
throw new GraphQLError("Invalid settings json.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles a vote of a specific type on a post and returns the post and the result
|
||||
* @param postId
|
||||
* @param type
|
||||
* @param request
|
||||
*/
|
||||
public async vote({postId, type}: { postId: number, type: dataaccess.VoteType }, request: any):
|
||||
Promise<{ post: Post, voteType: dataaccess.VoteType }> {
|
||||
this.ensureLoggedIn(request);
|
||||
const post = await Post.findByPk(postId);
|
||||
if (post) {
|
||||
const voteType = await post.vote(request.session.userId, type);
|
||||
return {
|
||||
post,
|
||||
voteType,
|
||||
};
|
||||
} else {
|
||||
throw new PostNotFoundError(postId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new post
|
||||
* @param content
|
||||
* @param activityId
|
||||
* @param request
|
||||
*/
|
||||
public async createPost({content, activityId}: { content: string, activityId?: number }, request: any):
|
||||
Promise<Post> {
|
||||
this.ensureLoggedIn(request);
|
||||
if (content.length > 2048) {
|
||||
throw new GraphQLError("Content too long.");
|
||||
}
|
||||
const post = await dataaccess.createPost(content, request.session.userId, activityId);
|
||||
globals.internalEmitter.emit(InternalEvents.GQLPOSTCREATE, post);
|
||||
return post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a post if the user is either the author or a site admin.
|
||||
* @param postId
|
||||
* @param request
|
||||
*/
|
||||
public async deletePost({postId}: { postId: number }, request: any): Promise<boolean> {
|
||||
this.ensureLoggedIn(request);
|
||||
const post = await Post.findByPk(postId, {
|
||||
include: [{
|
||||
as: "rAuthor",
|
||||
model: User,
|
||||
}],
|
||||
});
|
||||
const isAdmin = (await User.findOne({where: {id: request.session.userId}})).isAdmin;
|
||||
if (post.rAuthor.id === request.session.userId || isAdmin) {
|
||||
return await dataaccess.deletePost(post.id);
|
||||
} else {
|
||||
throw new GraphQLError("User is not author of the post.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a chat with several members
|
||||
* @param members
|
||||
* @param request
|
||||
*/
|
||||
public async createChat({members}: { members?: number[] }, request: any): Promise<ChatRoom> {
|
||||
this.ensureLoggedIn(request);
|
||||
const chatMembers = [request.session.userId];
|
||||
if (members) {
|
||||
chatMembers.push(...members);
|
||||
}
|
||||
return await dataaccess.createChat(...chatMembers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message into a chat the user has joined
|
||||
* @param chatId
|
||||
* @param content
|
||||
* @param request
|
||||
*/
|
||||
public async sendMessage({chatId, content}: { chatId: number, content: string }, request: any):
|
||||
Promise<ChatMessage> {
|
||||
this.ensureLoggedIn(request);
|
||||
const message = await dataaccess.sendChatMessage(request.session.userId, chatId, content);
|
||||
globals.internalEmitter.emit(InternalEvents.GQLCHATMESSAGE, message);
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request to a specific user
|
||||
* @param receiver
|
||||
* @param type
|
||||
* @param request
|
||||
*/
|
||||
public async sendRequest({receiver, type}: { receiver: number, type: dataaccess.RequestType }, request: any):
|
||||
Promise<Request> {
|
||||
this.ensureLoggedIn(request);
|
||||
return dataaccess.createRequest(request.session.userId, receiver, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Denies a request
|
||||
* @param sender
|
||||
* @param type
|
||||
* @param request
|
||||
*/
|
||||
public async denyRequest({sender, type}: { sender: number, type: dataaccess.RequestType }, request: any) {
|
||||
this.ensureLoggedIn(request);
|
||||
const user = await User.findByPk(request.session.userId);
|
||||
await user.acceptRequest(sender, type);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a request
|
||||
* @param sender
|
||||
* @param type
|
||||
* @param request
|
||||
*/
|
||||
public async acceptRequest({sender, type}: { sender: number, type: dataaccess.RequestType }, request: any) {
|
||||
this.ensureLoggedIn(request);
|
||||
const user = await User.findByPk(request.session.userId);
|
||||
await user.acceptRequest(sender, type);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a friend
|
||||
* @param friendId
|
||||
* @param request
|
||||
*/
|
||||
public async removeFriend({friendId}: { friendId: number }, request: any): Promise<boolean> {
|
||||
this.ensureLoggedIn(request);
|
||||
const user = await User.findByPk(request.session.userId);
|
||||
return user.removeFriend(friendId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new group
|
||||
* @param name
|
||||
* @param members
|
||||
* @param request
|
||||
*/
|
||||
public async createGroup({name, members}: { name: string, members: number[] }, request: any): Promise<Group> {
|
||||
this.ensureLoggedIn(request);
|
||||
return await dataaccess.createGroup(name, request.session.userId, members);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a group if the user is either the creator or a site admin
|
||||
* @param groupId
|
||||
* @param request
|
||||
*/
|
||||
public async deleteGroup({groupId}: { groupId: number }, request: any): Promise<boolean> {
|
||||
this.ensureLoggedIn(request);
|
||||
const user = await User.findByPk(request.session.userId);
|
||||
const group = await Group.findByPk(groupId);
|
||||
if (group) {
|
||||
if (user.isAdmin || group.creatorId === user.id) {
|
||||
await group.destroy();
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
throw new GroupNotFoundError(groupId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins a group
|
||||
* @param groupId
|
||||
* @param request
|
||||
*/
|
||||
public async joinGroup({groupId}: { groupId: number }, request: any): Promise<Group> {
|
||||
this.ensureLoggedIn(request);
|
||||
return dataaccess.changeGroupMembership(groupId, request.session.userId,
|
||||
dataaccess.MembershipChangeAction.ADD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaves a group
|
||||
* @param groupId
|
||||
* @param request
|
||||
*/
|
||||
public async leaveGroup({groupId}: { groupId: number }, request: any): Promise<Group> {
|
||||
this.ensureLoggedIn(request);
|
||||
return dataaccess.changeGroupMembership(groupId, request.session.userId,
|
||||
dataaccess.MembershipChangeAction.REMOVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a user to the group admins
|
||||
* @param groupId
|
||||
* @param userId
|
||||
* @param request
|
||||
*/
|
||||
public async addGroupAdmin({groupId, userId}: { groupId: number, userId: number }, request: any): Promise<Group> {
|
||||
this.ensureLoggedIn(request);
|
||||
const group = await Group.findByPk(groupId);
|
||||
const user: User = await User.findByPk(request.session.userId);
|
||||
if (group && !(await group.$has("rAdmins", user)) && (await group.creator()) !== user.id) {
|
||||
throw new NotAGroupAdminError(groupId);
|
||||
}
|
||||
return dataaccess.changeGroupMembership(groupId, userId,
|
||||
dataaccess.MembershipChangeAction.OP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an admin from a group
|
||||
* @param groupId
|
||||
* @param userId
|
||||
* @param request
|
||||
*/
|
||||
public async removeGroupAdmin({groupId, userId}: { groupId: number, userId: number },
|
||||
request: any): Promise<Group> {
|
||||
this.ensureLoggedIn(request);
|
||||
const group = await Group.findByPk(groupId);
|
||||
const isCreator = Number(group.creatorId) === Number(request.session.userId);
|
||||
const userIsCreator = Number(group.creatorId) === Number(userId);
|
||||
if (group && !isCreator && Number(userId) !== Number(request.session.userId)) {
|
||||
throw new NotTheGroupCreatorError(groupId);
|
||||
} else if (userIsCreator) {
|
||||
throw new GraphQLError(
|
||||
"You are not allowed to remove a creator as an admin.");
|
||||
}
|
||||
return await dataaccess.changeGroupMembership(groupId, userId,
|
||||
dataaccess.MembershipChangeAction.DEOP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new event for a specific group
|
||||
* @param name
|
||||
* @param dueDate
|
||||
* @param groupId
|
||||
* @param request
|
||||
*/
|
||||
public async createEvent({name, dueDate, groupId}: { name: string, dueDate: string, groupId: number },
|
||||
request: any): Promise<Event> {
|
||||
this.ensureLoggedIn(request);
|
||||
const date = new Date(Number(dueDate));
|
||||
const user: User = await User.findByPk(request.session.userId);
|
||||
const group = await Group.findByPk(groupId, {include: [{association: "rAdmins"}]});
|
||||
if (!(await group.$has("rAdmins", user))) {
|
||||
throw new NotAGroupAdminError(groupId);
|
||||
}
|
||||
const blacklisted = await dataaccess.checkBlacklisted(name);
|
||||
if (blacklisted.length > 0) {
|
||||
throw new BlacklistedError(blacklisted.map((p) => p.phrase), "event name");
|
||||
}
|
||||
return group.$create<Event>("rEvent", {name, dueDate: date});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an event
|
||||
* @param eventId
|
||||
* @param request
|
||||
*/
|
||||
public async deleteEvent({eventId}: { eventId: number }, request: any): Promise<boolean> {
|
||||
this.ensureLoggedIn(request);
|
||||
const event = await Event.findByPk(eventId, {include: [Group]});
|
||||
const user = await User.findByPk(request.session.userId);
|
||||
const group = await event.group();
|
||||
if (await group.$has("rAdmins", user)) {
|
||||
await event.destroy();
|
||||
return true;
|
||||
} else {
|
||||
throw new NotAGroupAdminError(group.id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins an event
|
||||
* @param eventId
|
||||
* @param request
|
||||
*/
|
||||
public async joinEvent({eventId}: { eventId: number }, request: any): Promise<Event> {
|
||||
this.ensureLoggedIn(request);
|
||||
const event = await Event.findByPk(eventId);
|
||||
const self = await User.findByPk(request.session.userId);
|
||||
await event.$add("rParticipants", self);
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaves an event
|
||||
* @param eventId
|
||||
* @param request
|
||||
*/
|
||||
public async leaveEvent({eventId}: { eventId: number }, request: any): Promise<Event> {
|
||||
this.ensureLoggedIn(request);
|
||||
const event = await Event.findByPk(eventId);
|
||||
const self = await User.findByPk(request.session.userId);
|
||||
await event.$remove("rParticipants", self);
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new activity or throws an error if the activity already exists
|
||||
* @param name
|
||||
* @param description
|
||||
* @param points
|
||||
* @param request
|
||||
*/
|
||||
public async createActivity({name, description, points}: { name: string, description: string, points: number },
|
||||
request: any): Promise<Activity> {
|
||||
this.ensureLoggedIn(request.session.userId);
|
||||
const user = await User.findByPk(request.session.userId);
|
||||
if (!user.isAdmin) {
|
||||
throw new NotAnAdminError();
|
||||
}
|
||||
const nameExists = await Activity.findOne({where: {name}});
|
||||
if (!nameExists) {
|
||||
return Activity.create({name, description, points});
|
||||
} else {
|
||||
throw new GraphQLError(`An activity with the name '${name}' already exists.`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a phrase to the blaclist
|
||||
* @param phrase
|
||||
* @param languageCode
|
||||
* @param request
|
||||
*/
|
||||
public async addToBlacklist({phrase, languageCode}: {phrase: string, languageCode?: string}, request: any):
|
||||
Promise<boolean> {
|
||||
this.ensureLoggedIn(request);
|
||||
const user = await User.findByPk(request.session.userId);
|
||||
if (!user.isAdmin) {
|
||||
throw new NotAnAdminError();
|
||||
}
|
||||
const phraseExists = await BlacklistedPhrase.findOne(
|
||||
{where: {phrase, language: languageCode}});
|
||||
if (!phraseExists) {
|
||||
await BlacklistedPhrase.create({phrase, language: languageCode});
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a phrase from the blacklist
|
||||
* @param phrase
|
||||
* @param languageCode
|
||||
* @param request
|
||||
*/
|
||||
public async removeFromBlacklist({phrase, languageCode}: {phrase: string, languageCode: string}, request: any):
|
||||
Promise<boolean> {
|
||||
this.ensureLoggedIn(request);
|
||||
const user = await User.findByPk(request.session.userId);
|
||||
if (!user.isAdmin) {
|
||||
throw new NotAnAdminError();
|
||||
}
|
||||
const phraseEntry = await BlacklistedPhrase.findOne(
|
||||
{where: {phrase, language: languageCode}});
|
||||
if (phraseEntry) {
|
||||
await phraseEntry.destroy();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,196 @@
|
||||
import {GraphQLError} from "graphql";
|
||||
import {Op} from "sequelize";
|
||||
import dataaccess from "../lib/dataAccess";
|
||||
import {ChatNotFoundError} from "../lib/errors/ChatNotFoundError";
|
||||
import {PostNotFoundGqlError} from "../lib/errors/graphqlErrors";
|
||||
import {GroupNotFoundError} from "../lib/errors/GroupNotFoundError";
|
||||
import {InvalidLoginError} from "../lib/errors/InvalidLoginError";
|
||||
import {RequestNotFoundError} from "../lib/errors/RequestNotFoundError";
|
||||
import {UserNotFoundError} from "../lib/errors/UserNotFoundError";
|
||||
import {
|
||||
Activity,
|
||||
BlacklistedPhrase,
|
||||
ChatRoom,
|
||||
Event,
|
||||
Group,
|
||||
Post,
|
||||
Request,
|
||||
User,
|
||||
} from "../lib/models";
|
||||
import {BaseResolver} from "./BaseResolver";
|
||||
import {BlacklistedResult} from "./BlacklistedResult";
|
||||
import {SearchResult} from "./SearchResult";
|
||||
import {Token} from "./Token";
|
||||
|
||||
/**
|
||||
* A class that provides functions to resolve queries
|
||||
*/
|
||||
export class QueryResolver {
|
||||
export class QueryResolver extends BaseResolver {
|
||||
|
||||
/**
|
||||
* Gets a user by id or handle
|
||||
* @param userId
|
||||
* @param handle
|
||||
*/
|
||||
public async getUser({userId, handle}: {userId?: number, handle?: string}): Promise<User> {
|
||||
let user: User;
|
||||
if (userId) {
|
||||
user = await User.findByPk(userId);
|
||||
} else if (handle) {
|
||||
user = await User.findOne({where: {handle}});
|
||||
} else {
|
||||
throw new GraphQLError("No handle or userId provided");
|
||||
}
|
||||
if (user) {
|
||||
return user;
|
||||
} else {
|
||||
throw new UserNotFoundError(userId ?? handle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the instance of the currently logged in user
|
||||
* @param args
|
||||
* @param request
|
||||
*/
|
||||
public async getSelf(args: null, request: any): Promise<User> {
|
||||
this.ensureLoggedIn(request);
|
||||
return User.findByPk(request.session.userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a post for a given post id.
|
||||
* @param postId
|
||||
*/
|
||||
public async getPost({postId}: {postId: number}): Promise<Post> {
|
||||
const post = await Post.findByPk(postId);
|
||||
if (post) {
|
||||
return post;
|
||||
} else {
|
||||
throw new PostNotFoundGqlError(postId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a chat for a given chat id
|
||||
* @param chatId
|
||||
*/
|
||||
public async getChat({chatId}: {chatId: number}): Promise<ChatRoom> {
|
||||
const chat = await ChatRoom.findByPk(chatId);
|
||||
if (chat) {
|
||||
return chat;
|
||||
} else {
|
||||
throw new ChatNotFoundError(chatId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a group for a given group id.
|
||||
* @param groupId
|
||||
*/
|
||||
public async getGroup({groupId}: {groupId: number}): Promise<Group> {
|
||||
const group = await Group.findByPk(groupId);
|
||||
if (group) {
|
||||
return group;
|
||||
} else {
|
||||
throw new GroupNotFoundError(groupId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request for a given id.
|
||||
* @param requestId
|
||||
*/
|
||||
public async getRequest({requestId}: {requestId: number}): Promise<Request> {
|
||||
const request = await Request.findByPk(requestId);
|
||||
if (request) {
|
||||
return request;
|
||||
} else {
|
||||
throw new RequestNotFoundError(requestId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for posts, groups, users, events and returns a search result.
|
||||
* @param query
|
||||
* @param first
|
||||
* @param offset
|
||||
*/
|
||||
public async search({query, first, offset}: {query: number, first: number, offset: number}): Promise<SearchResult> {
|
||||
const limit = first;
|
||||
const users = await User.findAll({
|
||||
limit,
|
||||
offset,
|
||||
where: {
|
||||
[Op.or]: [
|
||||
{handle: {[Op.iRegexp]: query}},
|
||||
{username: {[Op.iRegexp]: query}},
|
||||
],
|
||||
},
|
||||
});
|
||||
const groups = await Group.findAll({
|
||||
limit,
|
||||
offset,
|
||||
where: {name: {[Op.iRegexp]: query}},
|
||||
});
|
||||
const posts = await Post.findAll({
|
||||
limit,
|
||||
offset,
|
||||
where: {content: {[Op.iRegexp]: query}},
|
||||
});
|
||||
const events = await Event.findAll({
|
||||
limit,
|
||||
offset,
|
||||
where: {name: {[Op.iRegexp]: query}},
|
||||
});
|
||||
return new SearchResult(users, groups, posts, events);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the posts with a specific sorting
|
||||
* @param first
|
||||
* @param offset
|
||||
* @param sort
|
||||
*/
|
||||
public async getPosts({first, offset, sort}: {first: number, offset: number, sort: dataaccess.SortType}):
|
||||
Promise<Post[]> {
|
||||
return await dataaccess.getPosts(first, offset, sort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all activities
|
||||
*/
|
||||
public async getActivities(): Promise<Activity[]> {
|
||||
return Activity.findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the token for a user by login
|
||||
* @param email
|
||||
* @param passwordHash
|
||||
*/
|
||||
public async getToken({email, passwordHash}: {email: string, passwordHash: string}): Promise<Token> {
|
||||
const user = await dataaccess.getUserByLogin(email, passwordHash);
|
||||
return new Token(await user.token(), Number(user.authExpire).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a input phrase contains blacklisted phrases and which one
|
||||
* @param phrase
|
||||
*/
|
||||
public async blacklisted({phrase}: {phrase: string}): Promise<BlacklistedResult> {
|
||||
const phrases = await dataaccess.checkBlacklisted(phrase);
|
||||
return new BlacklistedResult(phrases.length > 0, phrases
|
||||
.map((p) => p.phrase));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all blacklisted phrases with pagination
|
||||
* @param first
|
||||
* @param offset
|
||||
*/
|
||||
public async getBlacklistedPhrases({first, offset}: {first: number, offset: number}): Promise<string[]> {
|
||||
return (await BlacklistedPhrase.findAll({limit: first, offset}))
|
||||
.map((p) => p.phrase);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
import {Group, Post, User, Event} from "../lib/models";
|
||||
|
||||
/**
|
||||
* A class to wrap search results returned by the search resolver
|
||||
*/
|
||||
export class SearchResult {
|
||||
constructor(
|
||||
public users: User[],
|
||||
public groups: Group[],
|
||||
public posts: Post[],
|
||||
public events: Event[],
|
||||
) {}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* A class representing a token that can be used with bearer authentication
|
||||
*/
|
||||
export class Token {
|
||||
constructor(
|
||||
public value: string,
|
||||
public expires: string,
|
||||
) {}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
import {BaseError} from "./BaseError";
|
||||
|
||||
/**
|
||||
* An error that is thrown when a user tries to register with an invalid email
|
||||
*/
|
||||
export class InvalidEmailError extends BaseError {
|
||||
constructor(email: string) {
|
||||
super(`'${email}' is not a valid email address!`);
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
import * as status from "http-status";
|
||||
import {BaseError} from "./BaseError";
|
||||
|
||||
/**
|
||||
* An error that is thrown when a non-admin tries to perform an admin action
|
||||
*/
|
||||
export class NotAGroupAdminError extends BaseError {
|
||||
public readonly statusCode = status.FORBIDDEN;
|
||||
|
||||
constructor(groupId: number) {
|
||||
super(`You are not an admin of '${groupId}'`);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
import {BaseError} from "./BaseError";
|
||||
|
||||
/**
|
||||
* An error that is thrown when a non admin tries to perform an admin action
|
||||
*/
|
||||
export class NotAnAdminError extends BaseError {
|
||||
|
||||
public readonly statusCode = httpStatus.FORBIDDEN;
|
||||
|
||||
constructor() {
|
||||
super("You are not a site admin!");
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
import * as status from "http-status";
|
||||
import {BaseError} from "./BaseError";
|
||||
|
||||
/**
|
||||
* An error that is thrown when a non-admin tries to perform an admin action
|
||||
*/
|
||||
export class NotTheGroupCreatorError extends BaseError {
|
||||
public readonly statusCode = status.FORBIDDEN;
|
||||
|
||||
constructor(groupId: number) {
|
||||
super(`You are not the creator of '${groupId}'`);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
import {BaseError} from "./BaseError";
|
||||
|
||||
/**
|
||||
* An error that is thrown when a post was not found
|
||||
*/
|
||||
export class PostNotFoundError extends BaseError {
|
||||
constructor(postId: number) {
|
||||
super(`Post '${postId}' not found!`);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue