Merge branch 'develop' of Software_Engineering_I/greenvironment-server into master

pull/5/head
Trivernis 5 years ago committed by Gitea
commit ef6202907e

@ -24,12 +24,39 @@ import {UploadRoute} from "./routes/UploadRoute";
const SequelizeStore = require("connect-session-sequelize")(session.Store); const SequelizeStore = require("connect-session-sequelize")(session.Store);
const logger = globals.logger; const logger = globals.logger;
/**
* The main entry class for each cluster worker
*/
class App { class App {
/**
* The corresponding express application
*/
public app: express.Application; public app: express.Application;
/**
* An instance of the socket.io server for websockets
*/
public io: socketIo.Server; public io: socketIo.Server;
/**
* An instance of the http server where the site is served
*/
public server: http.Server; public server: http.Server;
/**
* The path to the public folder that is served statically
*/
public readonly publicPath: string; public readonly publicPath: string;
/**
* The id of the worker
*/
public readonly id?: number; public readonly id?: number;
/**
* The instance of sequelize for ORM
*/
public readonly sequelize: Sequelize; public readonly sequelize: Sequelize;
constructor(id?: number) { constructor(id?: number) {

@ -10,9 +10,7 @@ import {InternalEvents} from "../lib/InternalEvents";
import * as models from "../lib/models"; import * as models from "../lib/models";
import {is} from "../lib/regex"; import {is} from "../lib/regex";
class Resolver { // tslint:disable:completed-docs
}
/** /**
* Returns the resolvers for the graphql api. * Returns the resolvers for the graphql api.
@ -212,7 +210,11 @@ export function resolver(req: any, res: any): any {
if (req.session.userId) { if (req.session.userId) {
const post = await models.Post.findByPk(postId); const post = await models.Post.findByPk(postId);
if (post) { if (post) {
return await post.vote(req.session.userId, type); const voteType = await post.vote(req.session.userId, type);
return {
post,
voteType,
};
} else { } else {
res.status(status.BAD_REQUEST); res.status(status.BAD_REQUEST);
return new PostNotFoundGqlError(postId); return new PostNotFoundGqlError(postId);

@ -17,14 +17,11 @@ type Query {
"returns the request object for its id" "returns the request object for its id"
getRequest(requestId: ID!): Request getRequest(requestId: ID!): Request
"DEPRECATED! Find a user by user name or handle"
findUser(first: Int = 20, offset: Int = 0, name: String, handle: String): [User]
"searches for users, groups, events, posts and returns a search result" "searches for users, groups, events, posts and returns a search result"
search(query: String!, first: Int = 20, offset: Int = 0): SearchResult! search(query: String!, first: Int = 20, offset: Int = 0): SearchResult!
"returns the post filtered by the sort type with pagination." "returns the post filtered by the sort type with pagination."
getPosts(first: Int=20, offset: Int=0, sort: SortType = NEW): [Post] getPosts(first: Int=20, offset: Int=0, sort: SortType = NEW): [Post!]!
"returns all activities" "returns all activities"
getActivities: [Activity] getActivities: [Activity]
@ -38,10 +35,10 @@ type Mutation {
acceptCookies: Boolean acceptCookies: Boolean
"Login of the user. The passwordHash should be a sha512 hash of the password." "Login of the user. The passwordHash should be a sha512 hash of the password."
login(email: String!, passwordHash: String!): Profile login(email: String!, passwordHash: String!): Profile!
"Registers the user." "Registers the user."
register(username: String, email: String, passwordHash: String): Profile register(username: String, email: String, passwordHash: String): Profile!
"Sets the user settings to the specified settings string. The settings parameter should be a valid yaml." "Sets the user settings to the specified settings string. The settings parameter should be a valid yaml."
setUserSettings(settings: String!): String! setUserSettings(settings: String!): String!
@ -50,22 +47,22 @@ type Mutation {
logout: Boolean logout: Boolean
"Upvote/downvote a Post" "Upvote/downvote a Post"
vote(postId: ID!, type: VoteType!): VoteType vote(postId: ID!, type: VoteType!): VoteResult
"Report the post" "Report the post"
report(postId: ID!): Boolean report(postId: ID!): Boolean!
"send a request" "send a request"
sendRequest(receiver: ID!, type: RequestType): Request sendRequest(receiver: ID!, type: RequestType): Request
"lets you accept a request for a given request id" "lets you accept a request for a given request id"
acceptRequest(sender: ID!, type: RequestType): Boolean acceptRequest(sender: ID!, type: RequestType): Boolean!
"lets you deny a request for a given request id" "lets you deny a request for a given request id"
denyRequest(sender: ID!, type: RequestType): Boolean denyRequest(sender: ID!, type: RequestType): Boolean!
"removes a friend" "removes a friend"
removeFriend(friendId: ID!): Boolean removeFriend(friendId: ID!): Boolean!
"send a message in a Chatroom" "send a message in a Chatroom"
sendMessage(chatId: ID!, content: String!): ChatMessage sendMessage(chatId: ID!, content: String!): ChatMessage
@ -95,7 +92,7 @@ type Mutation {
removeGroupAdmin(groupId: ID!, userId: ID!): Group removeGroupAdmin(groupId: ID!, userId: ID!): Group
"Creates a new event with a epoch due date on a group." "Creates a new event with a epoch due date on a group."
createEvent(name: String, dueDate: String, groupId: ID!): Event createEvent(name: String, dueDate: String, groupId: ID!): Event!
"Joins a event." "Joins a event."
joinEvent(eventId: ID!): Event joinEvent(eventId: ID!): Event
@ -124,25 +121,25 @@ interface UserData {
postCount: Int! postCount: Int!
"returns a given number of posts of a user" "returns a given number of posts of a user"
posts(first: Int=10, offset: Int=0): [Post] posts(first: Int=10, offset: Int=0): [Post!]!
"creation date of the user account" "creation date of the user account"
joinedAt: String! joinedAt: String!
"all friends of the user" "all friends of the user"
friends(first: Int=10, offset: Int=0): [User] friends(first: Int=10, offset: Int=0): [User!]!
"The number of friends the user has" "The number of friends the user has"
friendCount: Int! friendCount: Int!
"The groups the user has joined" "The groups the user has joined"
groups(first: Int=10, offset: Int=0): [Group] groups(first: Int=10, offset: Int=0): [Group!]!
"The number of groups the user has joined" "The number of groups the user has joined"
groupCount: Int! groupCount: Int!
"The events the user is participating in" "The events the user is participating in"
events(first: Int=10, offset: Int=0): [Event] events(first: Int=10, offset: Int=0): [Event!]!
"The number of events the user is participating in" "The number of events the user is participating in"
eventCount: Int! eventCount: Int!
@ -172,7 +169,7 @@ type User implements UserData{
numberOfPosts: Int! numberOfPosts: Int!
"returns a given number of posts of a user" "returns a given number of posts of a user"
posts(first: Int=10, offset: Int): [Post] posts(first: Int=10, offset: Int): [Post!]!
"the number of posts the user has created" "the number of posts the user has created"
postCount: Int! postCount: Int!
@ -181,7 +178,7 @@ type User implements UserData{
joinedAt: String! joinedAt: String!
"all friends of the user" "all friends of the user"
friends(first: Int=10, offset: Int=0): [User] friends(first: Int=10, offset: Int=0): [User!]!
"The number of friends the user has" "The number of friends the user has"
friendCount: Int! friendCount: Int!
@ -190,13 +187,13 @@ type User implements UserData{
points: Int! points: Int!
"the groups the user has joined" "the groups the user has joined"
groups(first: Int=10, offset: Int=0): [Group] groups(first: Int=10, offset: Int=0): [Group!]!
"The numbef of groups the user has joined" "The numbef of groups the user has joined"
groupCount: Int! groupCount: Int!
"The events the user is participating in" "The events the user is participating in"
events(first: Int=10, offset: Int=0): [Event] events(first: Int=10, offset: Int=0): [Event!]!
"The number of events the user is participating in" "The number of events the user is participating in"
eventCount: Int! eventCount: Int!
@ -264,7 +261,7 @@ type Profile implements UserData {
groupCount: Int! groupCount: Int!
"The events the user is participating in" "The events the user is participating in"
events(first: Int=10, offset: Int=0): [Event] events(first: Int=10, offset: Int=0): [Event!]!
"The number of events the user is participating in" "The number of events the user is participating in"
eventCount: Int! eventCount: Int!
@ -310,7 +307,7 @@ type Post {
userVote(userId: ID!): VoteType userVote(userId: ID!): VoteType
"if the post can be deleted by the specified user" "if the post can be deleted by the specified user"
deletable(userId: ID!): Boolean deletable(userId: ID!): Boolean!
"the activity that belongs to the post" "the activity that belongs to the post"
activity: Activity activity: Activity
@ -338,10 +335,10 @@ type ChatRoom {
namespace: String namespace: String
"the members of the chatroom" "the members of the chatroom"
members(first: Int=10, offset: Int=0): [User!] members(first: Int=10, offset: Int=0): [User!]!
"return a specfic range of messages posted in the chat" "return a specfic range of messages posted in the chat"
messages(first: Int = 10, offset: Int, containing: String): [ChatMessage]! messages(first: Int = 10, offset: Int): [ChatMessage!]!
"id of the chat" "id of the chat"
id: ID! id: ID!
@ -375,22 +372,22 @@ type Group {
name: String! name: String!
"the creator of the group" "the creator of the group"
creator: User creator: User!
"all admins of the group" "all admins of the group"
admins(first: Int=10, offset: Int=0): [User]! admins(first: Int=10, offset: Int=0): [User!]!
"the members of the group with pagination" "the members of the group with pagination"
members(first: Int = 10, offset: Int = 0): [User]! members(first: Int = 10, offset: Int = 0): [User!]!
"the groups chat" "the groups chat"
chat: ChatRoom chat: ChatRoom!
"the events of the group" "the events of the group"
events(first: Int=10, offset: Int=0): [Event!]! events(first: Int=10, offset: Int=0): [Event!]!
"If the user with the specified id has joined the group" "If the user with the specified id has joined the group"
joined(userId: Int!): Boolean joined(userId: Int!): Boolean!
} }
type Event { type Event {
@ -437,6 +434,16 @@ type SearchResult {
events: [Event!]! events: [Event!]!
} }
"The result of voting on a post"
type VoteResult {
"The type of vote that was performed"
voteType: VoteType
"The post the vote was performed on"
post: Post!
}
"An activity that grants points" "An activity that grants points"
type Activity { type Activity {

@ -3,17 +3,6 @@ import * as cluster from "cluster";
import App from "./app"; import App from "./app";
const numCPUs = require("os").cpus().length; const numCPUs = require("os").cpus().length;
interface IResourceUsage {
mem: {rss: number, heapTotal: number, heapUsed: number, external: number};
cpu: {user: number, system: number};
}
interface IClusterData {
reqCount: number;
workerCount: () => number;
workerRes: {[key: string]: IResourceUsage};
}
if (cluster.isMaster) { if (cluster.isMaster) {
console.log(`[CLUSTER-M] Master ${process.pid} is running`); console.log(`[CLUSTER-M] Master ${process.pid} is running`);

@ -8,12 +8,31 @@ import {Namespace, Server} from "socket.io";
*/ */
abstract class Route { abstract class Route {
/**
* The express router belonging to the route
*/
public router?: Router; public router?: Router;
/**
* An instance of socket io for the route
*/
protected io?: Server; protected io?: Server;
/**
* The namespace of the websocket for the route
*/
protected ions?: Namespace; protected ions?: Namespace;
/**
* An asynchronous init function
* @param params
*/
public abstract async init(...params: any): Promise<any>; public abstract async init(...params: any): Promise<any>;
/**
* An asynchronous destroy function
* @param params
*/
public abstract async destroy(...params: any): Promise<any>; public abstract async destroy(...params: any): Promise<any>;
} }

@ -17,6 +17,8 @@ import {InternalEvents} from "./InternalEvents";
import {Activity} from "./models"; import {Activity} from "./models";
import * as models from "./models"; import * as models from "./models";
// tslint:disable:completed-docs
/** /**
* Generates a new handle from the username and a base64 string of the current time. * Generates a new handle from the username and a base64 string of the current time.
* @param username * @param username
@ -39,7 +41,8 @@ namespace dataaccess {
let sequelize: Sequelize; let sequelize: Sequelize;
/** /**
* Initializes everything that needs to be initialized asynchronous. * An asynchronous init method for sequelize
* @param seq
*/ */
export async function init(seq: Sequelize): Promise<void> { export async function init(seq: Sequelize): Promise<void> {
sequelize = seq; sequelize = seq;

@ -1,5 +1,8 @@
import {BaseError} from "./BaseError"; import {BaseError} from "./BaseError";
/**
* An error that is thrown when an activity was not found.
*/
export class ActivityNotFoundError extends BaseError { export class ActivityNotFoundError extends BaseError {
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 {GraphQLError} from "graphql";
* Base error class. * Base error class.
*/ */
export class BaseError extends Error { export class BaseError extends Error {
/**
* The graphql error with a frontend error message
*/
public readonly graphqlError: GraphQLError; public readonly graphqlError: GraphQLError;
constructor(message?: string, friendlyMessage?: string) { constructor(message?: string, friendlyMessage?: string) {

@ -1,5 +1,8 @@
import {BaseError} from "./BaseError"; import {BaseError} from "./BaseError";
/**
* An error that is thrown when the chatroom doesn't exist
*/
export class ChatNotFoundError extends BaseError { export class ChatNotFoundError extends BaseError {
constructor(chatId: number) { constructor(chatId: number) {
super(`Chat with id ${chatId} not found.`); super(`Chat with id ${chatId} not found.`);

@ -1,5 +1,8 @@
import {BaseError} from "./BaseError"; import {BaseError} from "./BaseError";
/**
* An error that is thrown when a request of a specific type already exists
*/
export class DuplicatedRequestError extends BaseError { export class DuplicatedRequestError extends BaseError {
constructor() { constructor() {
super(`Request already exists.`); super(`Request already exists.`);

@ -1,5 +1,8 @@
import {BaseError} from "./BaseError"; import {BaseError} from "./BaseError";
/**
* An error that is thrown when the provided email for registering is already registered with a user
*/
export class EmailAlreadyRegisteredError extends BaseError { export class EmailAlreadyRegisteredError extends BaseError {
constructor(email: string) { constructor(email: string) {
super(`A user for '${email}' does already exist.`); super(`A user for '${email}' does already exist.`);

@ -1,5 +1,8 @@
import {BaseError} from "./BaseError"; import {BaseError} from "./BaseError";
/**
* An error that is thrown when a group already exists on creation request
*/
export class GroupAlreadyExistsError extends BaseError { export class GroupAlreadyExistsError extends BaseError {
constructor(name: string) { constructor(name: string) {
super(`A group with the name "${name}" already exists.`); super(`A group with the name "${name}" already exists.`);

@ -1,8 +1,10 @@
import {BaseError} from "./BaseError"; import {BaseError} from "./BaseError";
/**
* 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 {
constructor(groupId: number) { constructor(groupId: number) {
super(`Group ${groupId} not found!`); super(`Group ${groupId} not found!`);
} }
} }

@ -1,5 +1,8 @@
import {BaseError} from "./BaseError"; import {BaseError} from "./BaseError";
/**
* An error that is thrown when a user provides invalid login data for a login request
*/
export class InvalidLoginError extends BaseError { export class InvalidLoginError extends BaseError {
constructor(email: (string)) { constructor(email: (string)) {
super(`Invalid login data for ${email}.`); super(`Invalid login data for ${email}.`);

@ -1,5 +1,8 @@
import {BaseError} from "./BaseError"; import {BaseError} from "./BaseError";
/**
* 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 {
constructor(actions?: any) { constructor(actions?: any) {
if (actions) { if (actions) {

@ -1,9 +1,11 @@
import dataaccess from "../dataAccess"; import dataaccess from "../dataAccess";
import {BaseError} from "./BaseError"; import {BaseError} from "./BaseError";
/**
* 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 {
constructor(sender: number, receiver: number, type: dataaccess.RequestType) { constructor(sender: number, receiver: number, type: dataaccess.RequestType) {
super(`Request with sender '${sender}' and receiver '${receiver}' of type '${type}' not found.`); super(`Request with sender '${sender}' and receiver '${receiver}' of type '${type}' not found.`);
} }
} }

@ -1,5 +1,8 @@
import {BaseError} from "./BaseError"; import {BaseError} from "./BaseError";
/**
* An error that is thrown when a specified user was not found
*/
export class UserNotFoundError extends BaseError { export class UserNotFoundError extends BaseError {
constructor(username: (string|number)) { constructor(username: (string|number)) {
super(`User ${username} not found!`); super(`User ${username} not found!`);

@ -1,17 +1,26 @@
import {GraphQLError} from "graphql"; import {GraphQLError} from "graphql";
/**
* An error for the frontend that is thrown when the user is not logged in
*/
export class NotLoggedInGqlError extends GraphQLError { export class NotLoggedInGqlError extends GraphQLError {
constructor() { constructor() {
super("Not logged in"); super("Not logged in");
} }
} }
/**
* An error for the frontend that is thrown when a post was not found
*/
export class PostNotFoundGqlError extends GraphQLError { export class PostNotFoundGqlError extends GraphQLError {
constructor(postId: number) { constructor(postId: number) {
super(`Post '${postId}' not found!`); super(`Post '${postId}' not found!`);
} }
} }
/**
* An error for the forntend that is thrown when a group was not found
*/
export class GroupNotFoundGqlError extends GraphQLError { export class GroupNotFoundGqlError extends GraphQLError {
constructor(groupId: number) { constructor(groupId: number) {
super(`Group '${groupId}' not found!`); super(`Group '${groupId}' not found!`);

@ -1,18 +1,30 @@
import * as sqz from "sequelize"; import * as sqz from "sequelize";
import {Column, ForeignKey, Model, NotNull, Table, Unique} from "sequelize-typescript"; import {Column, Model, NotNull, Table, Unique} from "sequelize-typescript";
/**
* Represents an environmental friendly activity that provides points to level up
*/
@Table({underscored: true}) @Table({underscored: true})
export class Activity extends Model { export class Activity extends Model {
/**
* The name of the Activity
*/
@Unique @Unique
@NotNull @NotNull
@Column({type: sqz.STRING(128), allowNull: false, unique: true}) @Column({type: sqz.STRING(128), allowNull: false, unique: true})
public name: string; public name: string;
/**
* The description of the activity to describe what exactly has to be done
*/
@NotNull @NotNull
@Column({type: sqz.TEXT, allowNull: false}) @Column({type: sqz.TEXT, allowNull: false})
public description: string; public description: string;
/**
* The points one can get by completing the activity
*/
@Column @Column
public points: number; public points: number;
} }

@ -2,13 +2,22 @@ import {Column, ForeignKey, Model, NotNull, Table} from "sequelize-typescript";
import {ChatRoom} from "./ChatRoom"; import {ChatRoom} from "./ChatRoom";
import {User} from "./User"; import {User} from "./User";
/**
* Represents a member of a chat
*/
@Table({underscored: true}) @Table({underscored: true})
export class ChatMember extends Model<ChatMember> { export class ChatMember extends Model<ChatMember> {
/**
* The id of the user
*/
@ForeignKey(() => User) @ForeignKey(() => User)
@NotNull @NotNull
@Column({allowNull: false}) @Column({allowNull: false})
public userId: number; public userId: number;
/**
* The id of the chatroom
*/
@ForeignKey(() => ChatRoom) @ForeignKey(() => ChatRoom)
@NotNull @NotNull
@Column({allowNull: false}) @Column({allowNull: false})

@ -4,40 +4,71 @@ import markdown from "../markdown";
import {ChatRoom} from "./ChatRoom"; import {ChatRoom} from "./ChatRoom";
import {User} from "./User"; import {User} from "./User";
/**
* A single chat message in a chatroom
*/
@Table({underscored: true}) @Table({underscored: true})
export class ChatMessage extends Model<ChatMessage> { export class ChatMessage extends Model<ChatMessage> {
/**
* The content of a message in markdown utf-8 format
*/
@NotNull @NotNull
@Column({type: sqz.STRING(512), allowNull: false}) @Column({type: sqz.STRING(512), allowNull: false})
public content: string; public content: string;
/**
* The id of the chatroom the message was sent in
*/
@ForeignKey(() => ChatRoom) @ForeignKey(() => ChatRoom)
@NotNull @NotNull
@Column({allowNull: false}) @Column({allowNull: false})
public chatId: number; public chatId: number;
/**
* The id of the author of the message
*/
@ForeignKey(() => User) @ForeignKey(() => User)
@NotNull @NotNull
@Column({allowNull: false}) @Column({allowNull: false})
public authorId: number; public authorId: number;
/**
* The chatroom the message belongs to
*/
@BelongsTo(() => ChatRoom, "chatId") @BelongsTo(() => ChatRoom, "chatId")
public rChat: ChatRoom; public rChat: ChatRoom;
/**
* The author the message belongs to
*/
@BelongsTo(() => User, "authorId") @BelongsTo(() => User, "authorId")
public rAuthor: User; public rAuthor: User;
/**
* The date when the message was created
*/
@CreatedAt @CreatedAt
public createdAt: Date; public createdAt: Date;
/**
* Returns the chatroom of the message
*/
public async chat(): Promise<ChatRoom> { public async chat(): Promise<ChatRoom> {
return await this.$get("rChat") as ChatRoom; return await this.$get("rChat") as ChatRoom;
} }
/**
* Returns the author of the message
*/
public async author(): Promise<User> { public async author(): Promise<User> {
return await this.$get("rAuthor") as User; return await this.$get("rAuthor") as User;
} }
/**
* Returns the rendered html content of the message.
* Rendered by markdown.it
*/
public get htmlContent(): string { public get htmlContent(): string {
return markdown.renderInline(this.getDataValue("content")); return markdown.renderInline(this.getDataValue("content"));
} }

@ -3,25 +3,49 @@ import {ChatMember} from "./ChatMember";
import {ChatMessage} from "./ChatMessage"; import {ChatMessage} from "./ChatMessage";
import {User} from "./User"; import {User} from "./User";
/**
* The chatroom model
*/
@Table({underscored: true}) @Table({underscored: true})
export class ChatRoom extends Model<ChatRoom> { export class ChatRoom extends Model<ChatRoom> {
/**
* The members of the chatroom
*/
@BelongsToMany(() => User, () => ChatMember) @BelongsToMany(() => User, () => ChatMember)
public rMembers: User[]; public rMembers: User[];
/**
* The messages in the chatroom
*/
@HasMany(() => ChatMessage, "chatId") @HasMany(() => ChatMessage, "chatId")
public rMessages: ChatMessage[]; public rMessages: ChatMessage[];
/**
* The date the chatroom was created at
*/
@CreatedAt @CreatedAt
public readonly createdAt!: Date; public readonly createdAt!: Date;
/**
* Returns the members of the chatroom
*/
public async members(): Promise<User[]> { public async members(): Promise<User[]> {
return await this.$get("rMembers") as User[]; return await this.$get("rMembers") as User[];
} }
public async messages(): Promise<ChatMessage[]> { /**
return await this.$get("rMessages") as ChatMessage[]; * Returns the messages that have been sent in the chatroom
*/
public async messages({first, offset}: {first: number, offset: number}): Promise<ChatMessage[]> {
const limit = first ?? 10;
offset = offset ?? 0;
return await this.$get("rMessages", {limit, offset}) as ChatMessage[];
} }
/**
* Returns the namespace of the websocket of the chatroom
*/
public get namespace(): string { public get namespace(): string {
return "/chats/" + this.getDataValue("id"); return "/chats/" + this.getDataValue("id");
} }

@ -3,24 +3,43 @@ import {EventParticipant} from "./EventParticipant";
import {Group} from "./Group"; import {Group} from "./Group";
import {User} from "./User"; import {User} from "./User";
/**
* Represents an event
*/
@Table({underscored: true}) @Table({underscored: true})
export class Event extends Model<Event> { export class Event extends Model<Event> {
/**
* The name of the event
*/
@NotNull @NotNull
@Column({allowNull: false}) @Column({allowNull: false})
public name: string; public name: string;
/**
* The date the event takes place
*/
@NotNull @NotNull
@Column({allowNull: false}) @Column({allowNull: false})
public dueDate: Date; public dueDate: Date;
/**
* The group id the event belongs to
*/
@NotNull @NotNull
@ForeignKey(() => Group) @ForeignKey(() => Group)
@Column({allowNull: false}) @Column({allowNull: false})
public groupId: number; public groupId: number;
/**
* The group the event belongs to
*/
@BelongsTo(() => Group, "groupId") @BelongsTo(() => Group, "groupId")
public rGroup: Group; public rGroup: Group;
/**
* The participants in the event
*/
@BelongsToMany(() => User, () => EventParticipant) @BelongsToMany(() => User, () => EventParticipant)
public rParticipants: User[]; public rParticipants: User[];

@ -1,14 +1,24 @@
import {BelongsTo, BelongsToMany, Column, ForeignKey, Model, NotNull, Table} from "sequelize-typescript"; import {Column, ForeignKey, Model, NotNull, Table} from "sequelize-typescript";
import {Event} from "./Event"; import {Event} from "./Event";
import {User} from "./User"; import {User} from "./User";
/**
* A single participant in an event
*/
@Table({underscored: true}) @Table({underscored: true})
export class EventParticipant extends Model<EventParticipant> { export class EventParticipant extends Model<EventParticipant> {
/**
* The id of the participating user
*/
@NotNull @NotNull
@ForeignKey(() => User) @ForeignKey(() => User)
@Column({allowNull: false}) @Column({allowNull: false})
public userId: number; public userId: number;
/**
* The id of the event
*/
@NotNull @NotNull
@ForeignKey(() => Event) @ForeignKey(() => Event)
@Column({allowNull: false}) @Column({allowNull: false})

@ -1,15 +1,24 @@
import {Column, ForeignKey, Model, NotNull, PrimaryKey, Table} from "sequelize-typescript"; import {Column, ForeignKey, Model, NotNull, PrimaryKey, Table} from "sequelize-typescript";
import {User} from "./User"; import {User} from "./User";
/**
* A friendship between two users
*/
@Table({underscored: true}) @Table({underscored: true})
export class Friendship extends Model<Friendship> { export class Friendship extends Model<Friendship> {
/**
* The id of the first user
*/
@ForeignKey(() => User) @ForeignKey(() => User)
@PrimaryKey @PrimaryKey
@NotNull @NotNull
@Column({allowNull: false}) @Column({allowNull: false})
public userId: number; public userId: number;
/**
* The id of the second user
*/
@ForeignKey(() => User) @ForeignKey(() => User)
@PrimaryKey @PrimaryKey
@NotNull @NotNull

@ -15,35 +15,63 @@ import {GroupAdmin} from "./GroupAdmin";
import {GroupMember} from "./GroupMember"; import {GroupMember} from "./GroupMember";
import {User} from "./User"; import {User} from "./User";
/**
* A single group with members
*/
@Table({underscored: true}) @Table({underscored: true})
export class Group extends Model<Group> { export class Group extends Model<Group> {
/**
* The name of the group
*/
@NotNull @NotNull
@Unique @Unique
@Column({allowNull: false, unique: true}) @Column({allowNull: false, unique: true})
public name: string; public name: string;
/**
* The id of the user who created the group
*/
@NotNull @NotNull
@ForeignKey(() => User) @ForeignKey(() => User)
@Column({allowNull: false}) @Column({allowNull: false})
public creatorId: number; public creatorId: number;
/**
* The id of the chat that belongs to the group
*/
@NotNull @NotNull
@ForeignKey(() => ChatRoom) @ForeignKey(() => ChatRoom)
@Column({allowNull: false}) @Column({allowNull: false})
public chatId: number; public chatId: number;
/**
* The creator of the group
*/
@BelongsTo(() => User, "creatorId") @BelongsTo(() => User, "creatorId")
public rCreator: User; public rCreator: User;
/**
* The admins of the group
*/
@BelongsToMany(() => User, () => GroupAdmin) @BelongsToMany(() => User, () => GroupAdmin)
public rAdmins: User[]; public rAdmins: User[];
/**
* The members of the group
*/
@BelongsToMany(() => User, () => GroupMember) @BelongsToMany(() => User, () => GroupMember)
public rMembers: User[]; public rMembers: User[];
/**
* The chatroom of the group
*/
@BelongsTo(() => ChatRoom) @BelongsTo(() => ChatRoom)
public rChat: ChatRoom; public rChat: ChatRoom;
/**
* The events that were created for the group
*/
@HasMany(() => Event, "groupId") @HasMany(() => Event, "groupId")
public rEvents: Event[]; public rEvents: Event[];

@ -2,13 +2,23 @@ import {Column, ForeignKey, Model, NotNull, Table} from "sequelize-typescript";
import {Group} from "./Group"; import {Group} from "./Group";
import {User} from "./User"; import {User} from "./User";
/**
* A single admin of a group
*/
@Table({underscored: true}) @Table({underscored: true})
export class GroupAdmin extends Model<GroupAdmin> { export class GroupAdmin extends Model<GroupAdmin> {
/**
* The id of the user
*/
@NotNull @NotNull
@ForeignKey(() => User) @ForeignKey(() => User)
@Column({allowNull: false}) @Column({allowNull: false})
public userId: number; public userId: number;
/**
* The id of the group
*/
@NotNull @NotNull
@ForeignKey(() => Group) @ForeignKey(() => Group)
@Column({allowNull: false}) @Column({allowNull: false})

@ -2,13 +2,23 @@ import {Column, ForeignKey, Model, NotNull, Table} from "sequelize-typescript";
import {Group} from "./Group"; import {Group} from "./Group";
import {User} from "./User"; import {User} from "./User";
/**
* A single member of a group
*/
@Table({underscored: true}) @Table({underscored: true})
export class GroupMember extends Model<GroupMember> { export class GroupMember extends Model<GroupMember> {
/**
* The id of the user
*/
@NotNull @NotNull
@ForeignKey(() => User) @ForeignKey(() => User)
@Column({allowNull: false}) @Column({allowNull: false})
public userId: number; public userId: number;
/**
* The id of the group
*/
@NotNull @NotNull
@ForeignKey(() => Group) @ForeignKey(() => Group)
@Column({allowNull: false}) @Column({allowNull: false})

@ -5,30 +5,56 @@ import {Activity} from "./Activity";
import {PostVote, VoteType} from "./PostVote"; import {PostVote, VoteType} from "./PostVote";
import {User} from "./User"; import {User} from "./User";
/**
* A single post of a user
*/
@Table({underscored: true}) @Table({underscored: true})
export class Post extends Model<Post> { export class Post extends Model<Post> {
/**
* The markdown formatted utf-8 content of the post
*/
@NotNull @NotNull
@Column({type: sqz.STRING(2048), allowNull: false}) @Column({type: sqz.STRING(2048), allowNull: false})
public content: string; public content: string;
/**
* The id of the post author
*/
@ForeignKey(() => User) @ForeignKey(() => User)
@NotNull @NotNull
@Column({allowNull: false}) @Column({allowNull: false})
public authorId: number; public authorId: number;
/**
* The id of the activiy of the post if one was provided during creation
*/
@ForeignKey(() => Activity) @ForeignKey(() => Activity)
@Column({allowNull: true}) @Column({allowNull: true})
public activityId: number; public activityId: number;
/**
* The author of the post
*/
@BelongsTo(() => User, "authorId") @BelongsTo(() => User, "authorId")
public rAuthor: User; public rAuthor: User;
/**
* The activiy of the post
*/
@BelongsTo(() => Activity, "activityId") @BelongsTo(() => Activity, "activityId")
public rActivity?: Activity; public rActivity?: Activity;
/**
* The votes that were performed on the post
*/
@BelongsToMany(() => User, () => PostVote) @BelongsToMany(() => User, () => PostVote)
// tslint:disable-next-line:completed-docs
public rVotes: Array<User & {PostVote: PostVote}>; public rVotes: Array<User & {PostVote: PostVote}>;
/**
* The date the post was created at
*/
@CreatedAt @CreatedAt
public readonly createdAt!: Date; public readonly createdAt!: Date;

@ -3,22 +3,38 @@ import {Column, ForeignKey, Model, NotNull, Table} from "sequelize-typescript";
import {Post} from "./Post"; import {Post} from "./Post";
import {User} from "./User"; import {User} from "./User";
/**
* An enum that represents all possible types of votes
*/
export enum VoteType { export enum VoteType {
UPVOTE = "UPVOTE", UPVOTE = "UPVOTE",
DOWNVOTE = "DOWNVOTE", DOWNVOTE = "DOWNVOTE",
} }
/**
* A single vote on a post
*/
@Table({underscored: true}) @Table({underscored: true})
export class PostVote extends Model<PostVote> { export class PostVote extends Model<PostVote> {
/**
* The type of vote (UPVOTE/DOWNVOTE)
*/
@NotNull @NotNull
@Column({type: sqz.ENUM, values: ["UPVOTE", "DOWNVOTE"], defaultValue: "UPVOTE", allowNull: false}) @Column({type: sqz.ENUM, values: ["UPVOTE", "DOWNVOTE"], defaultValue: "UPVOTE", allowNull: false})
public voteType: VoteType; public voteType: VoteType;
/**
* The id of the user that performed the vote
*/
@ForeignKey(() => User) @ForeignKey(() => User)
@NotNull @NotNull
@Column({allowNull: false}) @Column({allowNull: false})
public userId: number; public userId: number;
/**
* The id of the post the vote was performed on
*/
@ForeignKey(() => Post) @ForeignKey(() => Post)
@NotNull @NotNull
@Column({allowNull: false}) @Column({allowNull: false})

@ -2,14 +2,24 @@ import * as sqz from "sequelize";
import {BelongsTo, Column, ForeignKey, Model, NotNull, Table} from "sequelize-typescript"; import {BelongsTo, Column, ForeignKey, Model, NotNull, Table} from "sequelize-typescript";
import {User} from "./User"; import {User} from "./User";
/**
* An enum that represents all possible types of requests
*/
export enum RequestType { export enum RequestType {
FRIENDREQUEST = "FRIENDREQUEST", FRIENDREQUEST = "FRIENDREQUEST",
GROUPINVITE = "GROUPINVITE", GROUPINVITE = "GROUPINVITE",
EVENTINVITE = "EVENTINVITE", EVENTINVITE = "EVENTINVITE",
} }
/**
* A single request for a friendship, group invide, event invite
*/
@Table({underscored: true}) @Table({underscored: true})
export class Request extends Model<Request> { export class Request extends Model<Request> {
/**
* The type of the request
*/
@NotNull @NotNull
@Column({ @Column({
allowNull: false, allowNull: false,
@ -19,19 +29,31 @@ export class Request extends Model<Request> {
}) })
public requestType: RequestType; public requestType: RequestType;
/**
* The id of the user who sent the request
*/
@ForeignKey(() => User) @ForeignKey(() => User)
@NotNull @NotNull
@Column({allowNull: false}) @Column({allowNull: false})
public senderId: number; public senderId: number;
/**
* The user who sent the request
*/
@BelongsTo(() => User, "senderId") @BelongsTo(() => User, "senderId")
public rSender: User; public rSender: User;
/**
* The id of the user who received the request
*/
@ForeignKey(() => User) @ForeignKey(() => User)
@NotNull @NotNull
@Column({allowNull: false}) @Column({allowNull: false})
public receiverId: number; public receiverId: number;
/**
* The user who received the request
*/
@BelongsTo(() => User, "receiverId") @BelongsTo(() => User, "receiverId")
public rReceiver: User; public rReceiver: User;

@ -26,87 +26,163 @@ import {Post} from "./Post";
import {PostVote} from "./PostVote"; import {PostVote} from "./PostVote";
import {Request, RequestType} from "./Request"; import {Request, RequestType} from "./Request";
/**
* A single user
*/
@Table({underscored: true}) @Table({underscored: true})
export class User extends Model<User> { export class User extends Model<User> {
/**
* The name of the user
*/
@NotNull @NotNull
@Column({type: sqz.STRING(128), allowNull: false}) @Column({type: sqz.STRING(128), allowNull: false})
public username: string; public username: string;
/**
* The handle of the user
*/
@NotNull @NotNull
@Unique @Unique
@Column({type: sqz.STRING(128), allowNull: false, unique: true}) @Column({type: sqz.STRING(128), allowNull: false, unique: true})
public handle: string; public handle: string;
/**
* The email address of the user
*/
@Unique @Unique
@NotNull @NotNull
@Column({type: sqz.STRING(128), allowNull: false, unique: true}) @Column({type: sqz.STRING(128), allowNull: false, unique: true})
public email: string; public email: string;
/**
* The password hash of the user
*/
@NotNull @NotNull
@Column({type: sqz.STRING(128), allowNull: false}) @Column({type: sqz.STRING(128), allowNull: false})
public password: string; public password: string;
/**
* The ranking points of the user
*/
@NotNull @NotNull
@Column({defaultValue: 0, allowNull: false}) @Column({defaultValue: 0, allowNull: false})
public rankpoints: number; public rankpoints: number;
/**
* The JSON-Frontend settings of the user to provide a way to store custom settings in the backend
*/
@NotNull @NotNull
@Column({defaultValue: {}, allowNull: false, type: sqz.JSON}) @Column({defaultValue: {}, allowNull: false, type: sqz.JSON})
public frontendSettings: any; public frontendSettings: any;
/**
* The auth token for bearer authentication
*/
@Unique @Unique
@Column({defaultValue: uuidv4, unique: true}) @Column({defaultValue: uuidv4, unique: true})
public authToken: string; public authToken: string;
/**
* The date and time the auth token expires
*/
@Column({defaultValue: () => Date.now() + 7200000}) @Column({defaultValue: () => Date.now() + 7200000})
public authExpire: Date; public authExpire: Date;
/**
* A flag if the user is a site admin
*/
@NotNull @NotNull
@Column({defaultValue: false, allowNull: false}) @Column({defaultValue: false, allowNull: false})
public isAdmin: boolean; public isAdmin: boolean;
/**
* The url of the users profile picture
*/
@Column({type: sqz.STRING(512)}) @Column({type: sqz.STRING(512)})
public profilePicture: string; public profilePicture: string;
/**
* The friends of the user
*/
@BelongsToMany(() => User, () => Friendship, "userId") @BelongsToMany(() => User, () => Friendship, "userId")
public rFriends: User[]; public rFriends: User[];
/**
* The friends of the user
*/
@BelongsToMany(() => User, () => Friendship, "friendId") @BelongsToMany(() => User, () => Friendship, "friendId")
public rFriendOf: User[]; public rFriendOf: User[];
/**
* The votes the user performed
*/
@BelongsToMany(() => Post, () => PostVote) @BelongsToMany(() => Post, () => PostVote)
public votes: Array<Post & { PostVote: PostVote }>; public votes: Array<Post & { PostVote: PostVote }>;
/**
* The chatrooms the user has joined
*/
@BelongsToMany(() => ChatRoom, () => ChatMember) @BelongsToMany(() => ChatRoom, () => ChatMember)
public rChats: ChatRoom[]; public rChats: ChatRoom[];
/**
* The group the user is an admin in
*/
@BelongsToMany(() => Group, () => GroupAdmin) @BelongsToMany(() => Group, () => GroupAdmin)
public rAdministratedGroups: Group[]; public rAdministratedGroups: Group[];
/**
* The events the user has joined
*/
@BelongsToMany(() => Event, () => EventParticipant) @BelongsToMany(() => Event, () => EventParticipant)
public rEvents: Event[]; public rEvents: Event[];
/**
* The groups the user has joined
*/
@BelongsToMany(() => Group, () => GroupMember) @BelongsToMany(() => Group, () => GroupMember)
public rGroups: Group[]; public rGroups: Group[];
/**
* The posts the user has created
*/
@HasMany(() => Post, "authorId") @HasMany(() => Post, "authorId")
public rPosts: Post[]; public rPosts: Post[];
/**
* The requests the user has sent
*/
@HasMany(() => Request, "senderId") @HasMany(() => Request, "senderId")
public rSentRequests: Request[]; public rSentRequests: Request[];
/**
* The requests the user has received
*/
@HasMany(() => Request, "receiverId") @HasMany(() => Request, "receiverId")
public rReceivedRequests: Request[]; public rReceivedRequests: Request[];
/**
* The messages the user has sent in a chatroom
*/
@HasMany(() => ChatMessage, "authorId") @HasMany(() => ChatMessage, "authorId")
public messages: ChatMessage[]; public messages: ChatMessage[];
/**
* The groups the user has created
*/
@HasMany(() => Group, "creatorId") @HasMany(() => Group, "creatorId")
public rCreatedGroups: Group[]; public rCreatedGroups: Group[];
/**
* The date the account was created
*/
@CreatedAt @CreatedAt
public readonly createdAt!: Date; public readonly createdAt!: Date;
/**
* The date of the last change to the user
*/
@UpdatedAt @UpdatedAt
public readonly updatedAt!: Date; public readonly updatedAt!: Date;

@ -43,6 +43,9 @@ export class UploadRoute extends Route {
return hash.digest("hex"); return hash.digest("hex");
} }
/**
* The directory where the uploaded data will be saved in
*/
public readonly dataDir: string; public readonly dataDir: string;
constructor(private publicPath: string) { constructor(private publicPath: string) {

@ -22,7 +22,14 @@
"no-namespace": false, "no-namespace": false,
"no-internal-module": false, "no-internal-module": false,
"max-classes-per-file": false, "max-classes-per-file": false,
"no-var-requires": false "no-var-requires": false,
"jsdoc-format": [true, "check-multiline-start"],
"completed-docs": [true, "classes", "enums", "methods", {
"properties": {
"privacies": "all",
"locations": "instance"
}
}]
}, },
"jsRules": { "jsRules": {
"max-line-length": { "max-line-length": {

Loading…
Cancel
Save