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 logger = globals.logger;
/**
* The main entry class for each cluster worker
*/
class App {
/**
* The corresponding express application
*/
public app: express.Application;
/**
* An instance of the socket.io server for websockets
*/
public io: socketIo.Server;
/**
* An instance of the http server where the site is served
*/
public server: http.Server;
/**
* The path to the public folder that is served statically
*/
public readonly publicPath: string;
/**
* The id of the worker
*/
public readonly id?: number;
/**
* The instance of sequelize for ORM
*/
public readonly sequelize: Sequelize;
constructor(id?: number) {

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

@ -17,14 +17,11 @@ type Query {
"returns the request object for its id"
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"
search(query: String!, first: Int = 20, offset: Int = 0): SearchResult!
"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"
getActivities: [Activity]
@ -38,10 +35,10 @@ type Mutation {
acceptCookies: Boolean
"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."
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."
setUserSettings(settings: String!): String!
@ -50,22 +47,22 @@ type Mutation {
logout: Boolean
"Upvote/downvote a Post"
vote(postId: ID!, type: VoteType!): VoteType
vote(postId: ID!, type: VoteType!): VoteResult
"Report the post"
report(postId: ID!): Boolean
report(postId: ID!): Boolean!
"send a request"
sendRequest(receiver: ID!, type: RequestType): Request
"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"
denyRequest(sender: ID!, type: RequestType): Boolean
denyRequest(sender: ID!, type: RequestType): Boolean!
"removes a friend"
removeFriend(friendId: ID!): Boolean
removeFriend(friendId: ID!): Boolean!
"send a message in a Chatroom"
sendMessage(chatId: ID!, content: String!): ChatMessage
@ -95,7 +92,7 @@ type Mutation {
removeGroupAdmin(groupId: ID!, userId: ID!): 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."
joinEvent(eventId: ID!): Event
@ -124,25 +121,25 @@ interface UserData {
postCount: Int!
"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"
joinedAt: String!
"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"
friendCount: Int!
"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"
groupCount: Int!
"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"
eventCount: Int!
@ -172,7 +169,7 @@ type User implements UserData{
numberOfPosts: Int!
"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"
postCount: Int!
@ -181,7 +178,7 @@ type User implements UserData{
joinedAt: String!
"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"
friendCount: Int!
@ -190,13 +187,13 @@ type User implements UserData{
points: Int!
"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"
groupCount: Int!
"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"
eventCount: Int!
@ -264,7 +261,7 @@ type Profile implements UserData {
groupCount: Int!
"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"
eventCount: Int!
@ -310,7 +307,7 @@ type Post {
userVote(userId: ID!): VoteType
"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"
activity: Activity
@ -338,10 +335,10 @@ type ChatRoom {
namespace: String
"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"
messages(first: Int = 10, offset: Int, containing: String): [ChatMessage]!
messages(first: Int = 10, offset: Int): [ChatMessage!]!
"id of the chat"
id: ID!
@ -375,22 +372,22 @@ type Group {
name: String!
"the creator of the group"
creator: User
creator: User!
"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"
members(first: Int = 10, offset: Int = 0): [User]!
members(first: Int = 10, offset: Int = 0): [User!]!
"the groups chat"
chat: ChatRoom
chat: ChatRoom!
"the events of the group"
events(first: Int=10, offset: Int=0): [Event!]!
"If the user with the specified id has joined the group"
joined(userId: Int!): Boolean
joined(userId: Int!): Boolean!
}
type Event {
@ -437,6 +434,16 @@ type SearchResult {
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"
type Activity {

@ -3,17 +3,6 @@ import * as cluster from "cluster";
import App from "./app";
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) {
console.log(`[CLUSTER-M] Master ${process.pid} is running`);

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

@ -17,6 +17,8 @@ import {InternalEvents} from "./InternalEvents";
import {Activity} 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.
* @param username
@ -39,7 +41,8 @@ namespace dataaccess {
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> {
sequelize = seq;

@ -1,5 +1,8 @@
import {BaseError} from "./BaseError";
/**
* An error that is thrown when an activity was not found.
*/
export class ActivityNotFoundError extends BaseError {
constructor(id: number) {
super(`The activity with the id ${id} could not be found.`);

@ -4,6 +4,9 @@ import {GraphQLError} from "graphql";
* Base error class.
*/
export class BaseError extends Error {
/**
* The graphql error with a frontend error message
*/
public readonly graphqlError: GraphQLError;
constructor(message?: string, friendlyMessage?: string) {

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

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

@ -1,5 +1,8 @@
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 {
constructor(email: string) {
super(`A user for '${email}' does already exist.`);

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

@ -1,8 +1,10 @@
import {BaseError} from "./BaseError";
/**
* An error that is thrown when a group was not found for a specified id
*/
export class GroupNotFoundError extends BaseError {
constructor(groupId: number) {
super(`Group ${groupId} not found!`);
}
}

@ -1,5 +1,8 @@
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 {
constructor(email: (string)) {
super(`Invalid login data for ${email}.`);

@ -1,5 +1,8 @@
import {BaseError} from "./BaseError";
/**
* An error that is thrown when no action was specified on a group membership change
*/
export class NoActionSpecifiedError extends BaseError {
constructor(actions?: any) {
if (actions) {

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

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

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

@ -1,18 +1,30 @@
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})
export class Activity extends Model {
/**
* The name of the Activity
*/
@Unique
@NotNull
@Column({type: sqz.STRING(128), allowNull: false, unique: true})
public name: string;
/**
* The description of the activity to describe what exactly has to be done
*/
@NotNull
@Column({type: sqz.TEXT, allowNull: false})
public description: string;
/**
* The points one can get by completing the activity
*/
@Column
public points: number;
}

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

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

@ -3,25 +3,49 @@ import {ChatMember} from "./ChatMember";
import {ChatMessage} from "./ChatMessage";
import {User} from "./User";
/**
* The chatroom model
*/
@Table({underscored: true})
export class ChatRoom extends Model<ChatRoom> {
/**
* The members of the chatroom
*/
@BelongsToMany(() => User, () => ChatMember)
public rMembers: User[];
/**
* The messages in the chatroom
*/
@HasMany(() => ChatMessage, "chatId")
public rMessages: ChatMessage[];
/**
* The date the chatroom was created at
*/
@CreatedAt
public readonly createdAt!: Date;
/**
* Returns the members of the chatroom
*/
public async members(): Promise<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 {
return "/chats/" + this.getDataValue("id");
}

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

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

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

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

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

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

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

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

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

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

@ -22,7 +22,14 @@
"no-namespace": false,
"no-internal-module": 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": {
"max-line-length": {

Loading…
Cancel
Save