Merge branch 'julius-dev' of Software_Engineering_I/greenvironment-server into develop

pull/2/head
Trivernis 5 years ago committed by Gitea
commit 1300d8ed05

@ -1,12 +1,11 @@
import {AggregateError} from "bluebird";
import {GraphQLError} from "graphql";
import * as status from "http-status";
import dataaccess from "../lib/dataaccess";
import {UserNotFoundError} from "../lib/errors/UserNotFoundError";
import {Group} from "../lib/models";
import * as models from "../lib/models";
import {GroupNotFoundGqlError, NotLoggedInGqlError, PostNotFoundGqlError} from "../lib/errors/graphqlErrors";
import {NotLoggedInGqlError, PostNotFoundGqlError} from "../lib/errors/graphqlErrors";
import globals from "../lib/globals";
import {InternalEvents} from "../lib/InternalEvents";
import * as models from "../lib/models";
import {is} from "../lib/regex";
/**
@ -228,6 +227,15 @@ export function resolver(req: any, res: any): any {
return new GraphQLError("No sender or type given.");
}
},
async removeFriend({friendId}: {friendId: number}) {
if (req.session.userId) {
const self = await models.User.findByPk(req.session.userId);
return await self.removeFriend(friendId);
} else {
res.status(status.UNAUTHORIZED);
return new NotLoggedInGqlError();
}
},
async getPosts({first, offset, sort}: {first: number, offset: number, sort: dataaccess.SortType}) {
return await dataaccess.getPosts(first, offset, sort);
},
@ -240,15 +248,12 @@ export function resolver(req: any, res: any): any {
},
async joinGroup({id}: {id: number}) {
if (req.session.userId) {
const group = await models.Group.findByPk(id);
if (group) {
const user = await models.User.findByPk(req.session.userId);
await group.$add("rMembers", user);
await (await group.chat()).$add("rMembers", user);
return group;
} else {
try {
return await dataaccess
.changeGroupMembership(id, req.session.userId, dataaccess.MembershipChangeAction.ADD);
} catch (err) {
res.status(status.BAD_REQUEST);
return new GroupNotFoundGqlError(id);
return err.graphqlError;
}
} else {
res.status(status.UNAUTHORIZED);
@ -257,15 +262,12 @@ export function resolver(req: any, res: any): any {
},
async leaveGroup({id}: {id: number}) {
if (req.session.userId) {
const group = await models.Group.findByPk(id);
if (group) {
const user = await models.User.findByPk(req.session.userId);
await group.$remove("rMembers", user);
await (await group.chat()).$remove("rMembers", user);
return group;
} else {
try {
return await dataaccess
.changeGroupMembership(id, req.session.userId, dataaccess.MembershipChangeAction.REMOVE);
} catch (err) {
res.status(status.BAD_REQUEST);
return new GroupNotFoundGqlError(id);
return err.graphqlError;
}
} else {
res.status(status.UNAUTHORIZED);
@ -275,22 +277,18 @@ export function resolver(req: any, res: any): any {
async addGroupAdmin({groupId, userId}: {groupId: number, userId: number}) {
if (req.session.userId) {
const group = await models.Group.findByPk(groupId);
const user = await models.User.findByPk(userId);
const self = await models.User.findByPk(req.session.userId);
if (!group) {
res.status(status.BAD_REQUEST);
return new GroupNotFoundGqlError(groupId);
}
if (!user) {
res.status(status.BAD_REQUEST);
return new UserNotFoundError(userId.toString()).graphqlError;
}
if (!(await group.$has("rAdmins", self)) && (await group.creator()) !== self.id) {
if (group && !(await group.$has("rAdmins", self)) && (await group.creator()) !== self.id) {
res.status(status.FORBIDDEN);
return new GraphQLError("You are not a group admin!");
}
await group.$add("rAdmins", user);
return group;
try {
return await dataaccess
.changeGroupMembership(groupId, userId, dataaccess.MembershipChangeAction.OP);
} catch (err) {
res.status(status.BAD_REQUEST);
return err.graphqlError;
}
} else {
res.status(status.UNAUTHORIZED);
@ -300,25 +298,23 @@ export function resolver(req: any, res: any): any {
async removeGroupAdmin({groupId, userId}: {groupId: number, userId: number}) {
if (req.session.userId) {
const group = await models.Group.findByPk(groupId);
const user = await models.User.findByPk(userId);
if (!group) {
res.status(status.BAD_REQUEST);
return new GroupNotFoundGqlError(groupId);
}
if (!user) {
res.status(status.BAD_REQUEST);
return new UserNotFoundError(userId.toString()).graphqlError;
}
if ((await group.creator()).id === userId) {
const isCreator = Number(group.creatorId) === Number(req.session.userId);
const userIsCreator = Number(group.creatorId) === Number(userId) ;
if (group && !isCreator && Number(userId) !== Number(req.session.userId)) {
res.status(status.FORBIDDEN);
return new GraphQLError("You can't remove the creator of a group.");
}
if ((await group.creator()).id !== req.session.userId) {
return new GraphQLError("You are not the group creator!");
} else if (userIsCreator) {
res.status(status.FORBIDDEN);
return new GraphQLError("You are not a group admin!");
return new GraphQLError("You are not allowed to remove a creator as an admin.");
}
try {
return await dataaccess
.changeGroupMembership(groupId, userId, dataaccess.MembershipChangeAction.DEOP);
} catch (err) {
res.status(status.BAD_REQUEST);
return err.graphqlError;
}
await group.$remove("rAdmins", user);
return group;
} else {
res.status(status.UNAUTHORIZED);

@ -49,6 +49,9 @@ type Mutation {
"lets you deny a request for a given request id"
denyRequest(requestId: ID!): Boolean
"removes a friend"
removeFriend(friendId: ID!): Boolean
"send a message in a Chatroom"
sendMessage(chatId: ID!, content: String!): ChatMessage
@ -101,6 +104,12 @@ interface UserData {
"all friends of the user"
friends: [User]
"the points of the user"
points: Int
"the levels of the user depending on the points"
level: Int
}
"represents a single user account"
@ -128,6 +137,15 @@ type User implements UserData{
"all friends of the user"
friends: [User]
"the points of the user"
points: Int
"the groups the user has joined"
groups: [Group]
"the levels of the user depending on the points"
level: Int
}
type Profile implements UserData {
@ -173,6 +191,11 @@ type Profile implements UserData {
"all groups the user has joined"
groups: [Group]
"the points of the user"
points: Int
"the levels of the user depending on the points"
level: Int
}
"represents a single user post"

@ -1,7 +1,11 @@
import * as crypto from "crypto";
import * as status from "http-status";
import {Sequelize} from "sequelize-typescript";
import {ChatNotFoundError} from "./errors/ChatNotFoundError";
import {EmailAlreadyRegisteredError} from "./errors/EmailAlreadyRegisteredError";
import {GroupNotFoundGqlError, NotLoggedInGqlError} from "./errors/graphqlErrors";
import {GroupNotFoundError} from "./errors/GroupNotFoundError";
import {NoActionSpecifiedError} from "./errors/NoActionSpecifiedError";
import {UserNotFoundError} from "./errors/UserNotFoundError";
import globals from "./globals";
import {InternalEvents} from "./InternalEvents";
@ -40,6 +44,8 @@ namespace dataaccess {
models.Group,
models.GroupAdmin,
models.GroupMember,
models.EventParticipant,
models.Event,
]);
} catch (err) {
globals.logger.error(err.message);
@ -207,7 +213,7 @@ namespace dataaccess {
requestType = requestType || RequestType.FRIENDREQUEST;
const request = await models.Request.create({senderId: sender, receiverId: receiver, requestType});
globals.internalEmitter.emit(InternalEvents.REQUESTCREATE, Request);
globals.internalEmitter.emit(InternalEvents.REQUESTCREATE, request);
return request;
}
@ -232,6 +238,38 @@ namespace dataaccess {
});
}
/**
* Changes the membership of a user
* @param groupId
* @param userId
* @param action
*/
export async function changeGroupMembership(groupId: number, userId: number, action: MembershipChangeAction):
Promise<models.Group> {
const group = await models.Group.findByPk(groupId);
if (group) {
const user = await models.User.findByPk(userId);
if (user) {
if (action === MembershipChangeAction.ADD) {
await group.$add("rMembers", user);
} else if (action === MembershipChangeAction.REMOVE) {
await group.$remove("rMembers", user);
} else if (action === MembershipChangeAction.OP) {
await group.$add("rAdmins", user);
} else if (action === MembershipChangeAction.DEOP) {
await group.$remove("rAdmins", user);
} else {
throw new NoActionSpecifiedError(MembershipChangeAction);
}
return group;
} else {
throw new UserNotFoundError(userId);
}
} else {
throw new GroupNotFoundError(groupId);
}
}
/**
* Enum representing the types of votes that can be performed on a post.
*/
@ -256,6 +294,13 @@ namespace dataaccess {
TOP = "TOP",
NEW = "NEW",
}
export enum MembershipChangeAction {
ADD,
REMOVE,
OP,
DEOP,
}
}
export default dataaccess;

@ -0,0 +1,8 @@
import {BaseError} from "./BaseError";
export class GroupNotFoundError extends BaseError {
constructor(groupId: number) {
super(`Group ${groupId} not found!`);
}
}

@ -0,0 +1,11 @@
import {BaseError} from "./BaseError";
export class NoActionSpecifiedError extends BaseError {
constructor(actions?: any) {
if (actions) {
super(`No action of '${Object.keys(actions).join(", ")}'`);
} else {
super("No action specified!");
}
}
}

@ -1,7 +1,7 @@
import {BaseError} from "./BaseError";
export class UserNotFoundError extends BaseError {
constructor(username: string) {
constructor(username: (string|number)) {
super(`User ${username} not found!`);
}
}

@ -0,0 +1,34 @@
import {BelongsTo, BelongsToMany, Column, ForeignKey, Model, NotNull, Table} from "sequelize-typescript";
import {EventParticipant} from "./EventParticipant";
import {Group} from "./Group";
import {User} from "./User";
@Table({underscored: true})
export class Event extends Model<Event> {
@NotNull
@Column({allowNull: false})
public name: string;
@NotNull
@Column({allowNull: false})
public dueDate: Date;
@NotNull
@ForeignKey(() => Group)
@Column({allowNull: false})
public groupId: number;
@BelongsTo(() => Group, "groupId")
public rGroup: Group;
@BelongsToMany(() => User, () => EventParticipant)
public rParticipants: User[];
public async group(): Promise<Group> {
return await this.$get("rGroup") as Group;
}
public async participants({first, offset}: {first: number, offset: number}): Promise<User[]> {
return await this.$get("rParticipants") as User[];
}
}

@ -0,0 +1,16 @@
import {BelongsTo, BelongsToMany, Column, ForeignKey, Model, NotNull, Table} from "sequelize-typescript";
import {Event} from "./Event";
import {User} from "./User";
@Table({underscored: true})
export class EventParticipant extends Model<EventParticipant> {
@NotNull
@ForeignKey(() => User)
@Column({allowNull: false})
public userId: number;
@NotNull
@ForeignKey(() => Event)
@Column({allowNull: false})
public eventId: number;
}

@ -1,15 +1,17 @@
import {Column, ForeignKey, Model, NotNull, Table} from "sequelize-typescript";
import {Column, ForeignKey, Model, NotNull, PrimaryKey, Table} from "sequelize-typescript";
import {User} from "./User";
@Table({underscored: true})
export class Friendship extends Model<Friendship> {
@ForeignKey(() => User)
@PrimaryKey
@NotNull
@Column({allowNull: false})
public userId: number;
@ForeignKey(() => User)
@PrimaryKey
@NotNull
@Column({allowNull: false})
public friendId: number;

@ -1,18 +1,6 @@
import * as sqz from "sequelize";
import {
BelongsTo,
BelongsToMany,
Column,
CreatedAt, ForeignKey,
HasMany,
Model,
NotNull,
Table,
Unique,
UpdatedAt,
} from "sequelize-typescript";
import {ChatMessage} from "./ChatMessage";
import {BelongsTo, BelongsToMany, Column, ForeignKey, HasMany, Model, NotNull, Table} from "sequelize-typescript";
import {ChatRoom} from "./ChatRoom";
import {Event} from "./Event";
import {GroupAdmin} from "./GroupAdmin";
import {GroupMember} from "./GroupMember";
import {User} from "./User";
@ -20,7 +8,7 @@ import {User} from "./User";
@Table({underscored: true})
export class Group extends Model<Group> {
@NotNull
@Column( {allowNull: false})
@Column({allowNull: false})
public name: string;
@NotNull
@ -45,6 +33,9 @@ export class Group extends Model<Group> {
@BelongsTo(() => ChatRoom)
public rChat: ChatRoom;
@HasMany(() => Event, "groupId")
public rEvents: Event[];
public async creator(): Promise<User> {
return await this.$get("rCreator") as User;
}
@ -53,7 +44,7 @@ export class Group extends Model<Group> {
return await this.$get("rAdmins") as User[];
}
public async members({first, offset}: {first: number, offset: number}): Promise<User[]> {
public async members({first, offset}: { first: number, offset: number }): Promise<User[]> {
const limit = first || 10;
offset = offset || 0;
return await this.$get("rMembers", {limit, offset}) as User[];
@ -62,4 +53,8 @@ export class Group extends Model<Group> {
public async chat(): Promise<ChatRoom> {
return await this.$get("rChat") as ChatRoom;
}
public async events(): Promise<Event[]> {
return await this.$get("rEvents") as Event[];
}
}

@ -1,16 +1,4 @@
import * as sqz from "sequelize";
import {
BelongsTo,
BelongsToMany,
Column,
CreatedAt, ForeignKey,
HasMany,
Model, Not,
NotNull,
Table,
Unique,
UpdatedAt,
} from "sequelize-typescript";
import {Column, ForeignKey, Model, NotNull, Table,} from "sequelize-typescript";
import {Group} from "./Group";
import {User} from "./User";

@ -1,16 +1,4 @@
import * as sqz from "sequelize";
import {
BelongsTo,
BelongsToMany,
Column,
CreatedAt, ForeignKey,
HasMany,
Model, Not,
NotNull,
Table,
Unique,
UpdatedAt,
} from "sequelize-typescript";
import {Column, ForeignKey, Model, NotNull, Table,} from "sequelize-typescript";
import {Group} from "./Group";
import {User} from "./User";

@ -1,5 +1,6 @@
import * as sqz from "sequelize";
import {
BelongsTo,
BelongsToMany,
Column,
CreatedAt,
@ -11,9 +12,12 @@ import {
UpdatedAt,
} from "sequelize-typescript";
import {RequestNotFoundError} from "../errors/RequestNotFoundError";
import {UserNotFoundError} from "../errors/UserNotFoundError";
import {ChatMember} from "./ChatMember";
import {ChatMessage} from "./ChatMessage";
import {ChatRoom} from "./ChatRoom";
import {Event} from "./Event";
import {EventParticipant} from "./EventParticipant";
import {Friendship} from "./Friendship";
import {Group} from "./Group";
import {GroupAdmin} from "./GroupAdmin";
@ -46,9 +50,12 @@ export class User extends Model<User> {
@Column({defaultValue: 0, allowNull: false})
public rankpoints: number;
@BelongsToMany(() => User, () => Friendship)
@BelongsToMany(() => User, () => Friendship, "userId")
public rFriends: User[];
@BelongsToMany(() => User, () => Friendship, "friendId")
public rFriendOf: User[];
@BelongsToMany(() => Post, () => PostVote)
public votes: Array<Post & {PostVote: PostVote}>;
@ -58,13 +65,16 @@ export class User extends Model<User> {
@BelongsToMany(() => Group, () => GroupAdmin)
public rAdministratedGroups: Group[];
@BelongsToMany(() => Event, () => EventParticipant)
public rEvents: Event[];
@BelongsToMany(() => Group, () => GroupMember)
public rGroups: Group[];
@HasMany(() => Post, "authorId")
public rPosts: Post[];
@HasMany(() => Request, "receiverId")
@HasMany(() => Request, "senderId")
public rSentRequests: Request[];
@HasMany(() => Request, "receiverId")
@ -90,8 +100,16 @@ export class User extends Model<User> {
return this.getDataValue("createdAt");
}
public get points(): number {
return this.rankpoints;
}
public get level(): number {
return Math.ceil(this.rankpoints / 100);
}
public async friends(): Promise<User[]> {
return await this.$get("rFriends") as User[];
return await this.$get("rFriendOf") as User[];
}
public async chats(): Promise<ChatRoom[]> {
@ -126,6 +144,10 @@ export class User extends Model<User> {
return await this.$get("rGroups") as Group[];
}
public async events(): Promise<Event[]> {
return await this.$get("rEvents") as Event[];
}
public async denyRequest(sender: number, type: RequestType) {
const request = await this.$get("rReceivedRequests",
{where: {senderId: sender, requestType: type}}) as Request[];
@ -140,11 +162,25 @@ export class User extends Model<User> {
if (requests.length > 0) {
const request = requests[0];
if (request.requestType === RequestType.FRIENDREQUEST) {
await this.$add("friends", sender);
await Friendship.bulkCreate([
{userId: this.id, friendId: sender},
{userId: sender, friendId: this.id},
], {ignoreDuplicates: true});
await request.destroy();
}
} else {
throw new RequestNotFoundError(sender, this.id, type);
}
}
public async removeFriend(friendId: number) {
const friend = await User.findByPk(friendId);
if (friend) {
await this.$remove("rFriends", friend);
await this.$remove("rFriendOf", friend);
return true;
} else {
throw new UserNotFoundError(friendId);
}
}
}

@ -9,3 +9,5 @@ export {User} from "./User";
export {Group} from "./Group";
export {GroupAdmin} from "./GroupAdmin";
export {GroupMember} from "./GroupMember";
export {Event} from "./Event";
export {EventParticipant} from "./EventParticipant";

Loading…
Cancel
Save