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

pull/5/head
Trivernis 5 years ago committed by Gitea
commit 5969c6a576

@ -35,13 +35,6 @@ secret = "REPLACE WITH SAFE RANDOM GENERATED SECRET"
cookieMaxAge = 6048e+5 # 7 days cookieMaxAge = 6048e+5 # 7 days
# Configuration for markdown rendering
[markdown]
# The plugins used in the markdown parser
plugins = ["markdown-it-emoji"]
# Configuration for logging # Configuration for logging
[logging] [logging]

@ -81,6 +81,7 @@
"legit": "^1.0.7", "legit": "^1.0.7",
"markdown-it": "^10.0.0", "markdown-it": "^10.0.0",
"markdown-it-emoji": "^1.4.0", "markdown-it-emoji": "^1.4.0",
"markdown-it-html5-media": "^0.6.0",
"pg": "^7.12.1", "pg": "^7.12.1",
"pug": "^2.0.4", "pug": "^2.0.4",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",

@ -6,6 +6,7 @@ import isEmail from "validator/lib/isEmail";
import dataaccess from "../lib/dataAccess"; import dataaccess from "../lib/dataAccess";
import {BlacklistedError} from "../lib/errors/BlacklistedError"; import {BlacklistedError} from "../lib/errors/BlacklistedError";
import {NotAnAdminGqlError, NotLoggedInGqlError, PostNotFoundGqlError} from "../lib/errors/graphqlErrors"; import {NotAnAdminGqlError, NotLoggedInGqlError, PostNotFoundGqlError} from "../lib/errors/graphqlErrors";
import {GroupNotFoundError} from "../lib/errors/GroupNotFoundError";
import {InvalidLoginError} from "../lib/errors/InvalidLoginError"; import {InvalidLoginError} from "../lib/errors/InvalidLoginError";
import globals from "../lib/globals"; import globals from "../lib/globals";
import {InternalEvents} from "../lib/InternalEvents"; import {InternalEvents} from "../lib/InternalEvents";
@ -409,6 +410,25 @@ export function resolver(req: any, res: any): any {
return new NotLoggedInGqlError(); return new NotLoggedInGqlError();
} }
}, },
async deleteGroup({groupId}: {groupId: number}) {
if (req.session.userId) {
const group = await models.Group.findByPk(groupId);
if (!group) {
res.status(status.BAD_REQUEST);
return new GroupNotFoundError(groupId).graphqlError;
}
if (group.creatorId === req.session.userId) {
await group.destroy();
return true;
} else {
res.status(status.FORBIDDEN);
return new GraphQLError("You are not the group admin.");
}
} else {
res.status(status.UNAUTHORIZED);
return new NotLoggedInGqlError();
}
},
async joinGroup({id}: { id: number }) { async joinGroup({id}: { id: number }) {
if (req.session.userId) { if (req.session.userId) {
try { try {
@ -502,6 +522,27 @@ export function resolver(req: any, res: any): any {
return new NotLoggedInGqlError(); return new NotLoggedInGqlError();
} }
}, },
async deleteEvent({eventId}: {eventId: number}) {
if (req.session.userId) {
const event = await models.Event.findByPk(eventId, {include: [models.Group]});
const user = await models.User.findByPk(req.session.userId);
if (!event) {
res.status(status.BAD_REQUEST);
return new GraphQLError(`No event with id '${eventId}' found.`);
}
const group = await event.group();
if (await group.$has("rAdmins", user)) {
await event.destroy();
return true;
} else {
res.status(status.FORBIDDEN);
return new NotAnAdminGqlError();
}
} else {
res.status(status.UNAUTHORIZED);
return new NotLoggedInGqlError();
}
},
async joinEvent({eventId}: { eventId: number }) { async joinEvent({eventId}: { eventId: number }) {
if (req.session.userId) { if (req.session.userId) {
const event = await models.Event.findByPk(eventId); const event = await models.Event.findByPk(eventId);

@ -94,6 +94,9 @@ type Mutation {
"Creates a new group with a given name and additional members" "Creates a new group with a given name and additional members"
createGroup(name: String!, members: [ID!]): Group! createGroup(name: String!, members: [ID!]): Group!
"Deletes a group."
deleteGroup(groupId: ID!): Boolean!
"Joins a group with the given id" "Joins a group with the given id"
joinGroup(id: ID!): Group joinGroup(id: ID!): Group
@ -109,6 +112,9 @@ type Mutation {
"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!
"Deletes an event."
deleteEvent(eventId: ID!): Boolean!
"Joins a event." "Joins a event."
joinEvent(eventId: ID!): Event joinEvent(eventId: ID!): Event
@ -411,7 +417,10 @@ type Group {
events(first: Int=10, offset: Int=0): [Event!]! @complexity(value: 1, multipliers: ["first"]) events(first: Int=10, offset: Int=0): [Event!]! @complexity(value: 1, multipliers: ["first"])
"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: ID): Boolean!
"If the group is deletable by the specified or logged in user."
deletable(userId: ID): Boolean!
} }
type Event { type Event {
@ -431,7 +440,10 @@ type Event {
participants(first: Int=10, offset: Int=0): [User!]! @complexity(value: 1, multipliers: ["first"]) participants(first: Int=10, offset: Int=0): [User!]! @complexity(value: 1, multipliers: ["first"])
"Returns if the user with the specified id has joined the event" "Returns if the user with the specified id has joined the event"
joined(userId: Int): Boolean joined(userId: ID): Boolean!
"Returns if the Event is deletable by the logged in or specified user"
deletable(userId: ID): Boolean!
} }
"respresents an access token entry with the value as the acutal token and expires as the date the token expires." "respresents an access token entry with the value as the acutal token and expires as the date the token expires."

@ -5,6 +5,6 @@ import {BaseError} from "./BaseError";
*/ */
export class BlacklistedError extends BaseError { export class BlacklistedError extends BaseError {
constructor(public phrases: string[], field: string = "input") { constructor(public phrases: string[], field: string = "input") {
super(`The ${field} contains the blacklisted words: ${phrases.join(",")}`); super(`The ${field} contains the blacklisted words: ${phrases.join(", ")}`);
} }
} }

@ -1,21 +1,13 @@
import * as config from "config";
import * as MarkdownIt from "markdown-it/lib"; import * as MarkdownIt from "markdown-it/lib";
import globals from "./globals";
namespace markdown { const { html5Media } = require("markdown-it-html5-media");
const mdEmoji = require("markdown-it-emoji");
const md = new MarkdownIt(); namespace markdown {
for (const pluginName of config.get("markdown.plugins") as string[]) { const md = new MarkdownIt()
try { .use(html5Media)
const plugin = require(pluginName); .use(mdEmoji);
if (plugin) {
md.use(plugin);
}
} catch (err) {
globals.logger.warn(`Markdown-it plugin '${pluginName}' not found!`);
}
}
/** /**
* Renders the markdown string inline (without blocks). * Renders the markdown string inline (without blocks).

@ -55,7 +55,7 @@ export class Event extends Model<Event> {
* @param first * @param first
* @param offset * @param offset
*/ */
public async participants({first, offset}: { first: number, offset: number }): Promise<User[]> { public async participants({first, offset}: { first?: number, offset?: number }): Promise<User[]> {
const limit = first ?? 10; const limit = first ?? 10;
offset = offset ?? 0; offset = offset ?? 0;
return await this.$get("rParticipants", {limit, offset}) as User[]; return await this.$get("rParticipants", {limit, offset}) as User[];
@ -75,4 +75,20 @@ export class Event extends Model<Event> {
return false; return false;
} }
} }
/**
* Returns if the event is deletable by the specified user
* @param userId
* @param request
*/
public async deletable({userId}: {userId: number}, request: any): Promise<boolean> {
userId = userId ?? request.session.userId;
if (userId) {
const group = await this.$get<Group>("rGroup") as Group;
const user = await User.findByPk(userId);
return group.$has("rAdmins", user);
} else {
return false;
}
}
} }

@ -135,7 +135,7 @@ export class Group extends Model<Group> {
* @param userId * @param userId
* @param request * @param request
*/ */
public async joined({userId}: { userId: number }, request: any): Promise<boolean> { public async joined({userId}: { userId?: number }, request: any): Promise<boolean> {
userId = userId ?? request.session.userId; userId = userId ?? request.session.userId;
if (userId) { if (userId) {
const members = await this.$get("rMembers", {where: {id: userId}}) as User[]; const members = await this.$get("rMembers", {where: {id: userId}}) as User[];
@ -144,4 +144,18 @@ export class Group extends Model<Group> {
return false; return false;
} }
} }
/**
* Returns if the group is deletable by the given user
* @param userId
* @param request
*/
public async deletable({userId}: {userId?: number}, request: any): Promise<boolean> {
userId = userId ?? request.session.userId;
if (userId) {
return this.creatorId === userId;
} else {
return false;
}
}
} }

@ -193,6 +193,7 @@ export class UploadRoute extends Route {
private async processAndStoreImage(data: Buffer, width = 512, height = 512, private async processAndStoreImage(data: Buffer, width = 512, height = 512,
fit: ImageFit = "cover"): Promise<string> { fit: ImageFit = "cover"): Promise<string> {
const fileBasename = UploadRoute.getFileName() + "." + config.get("api.imageFormat"); const fileBasename = UploadRoute.getFileName() + "." + config.get("api.imageFormat");
await fsx.ensureDir(this.dataDir);
const filePath = path.join(this.dataDir, fileBasename); const filePath = path.join(this.dataDir, fileBasename);
let image = await sharp(data) let image = await sharp(data)
.resize(width, height, { .resize(width, height, {

@ -1,5 +1,5 @@
Arguments: Arguments:
/usr/bin/node /usr/bin/yarn add @types/legit --dev /usr/bin/node /usr/bin/yarn add @types/markdown-it-html5-media --dev
PATH: PATH:
/home/trivernis/Documents/Programming/node/greenvironment-server/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/opt/cuda/bin:/opt/intel/mediasdk/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl /home/trivernis/Documents/Programming/node/greenvironment-server/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/opt/cuda/bin:/opt/intel/mediasdk/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl
@ -14,7 +14,7 @@ Platform:
linux x64 linux x64
Trace: Trace:
Error: https://registry.yarnpkg.com/@types%2flegit: Not found Error: https://registry.yarnpkg.com/@types%2fmarkdown-it-html5-media: Not found
at Request.params.callback [as _callback] (/usr/lib/node_modules/yarn/lib/cli.js:66947:18) at Request.params.callback [as _callback] (/usr/lib/node_modules/yarn/lib/cli.js:66947:18)
at Request.self.callback (/usr/lib/node_modules/yarn/lib/cli.js:140665:22) at Request.self.callback (/usr/lib/node_modules/yarn/lib/cli.js:140665:22)
at Request.emit (events.js:321:20) at Request.emit (events.js:321:20)
@ -88,6 +88,8 @@ npm manifest:
"typescript": "^3.7.2" "typescript": "^3.7.2"
}, },
"dependencies": { "dependencies": {
"@types/body-parser": "^1.17.1",
"body-parser": "^1.19.0",
"compression": "^1.7.4", "compression": "^1.7.4",
"config": "^3.2.4", "config": "^3.2.4",
"connect-session-sequelize": "^6.0.0", "connect-session-sequelize": "^6.0.0",
@ -108,6 +110,7 @@ npm manifest:
"legit": "^1.0.7", "legit": "^1.0.7",
"markdown-it": "^10.0.0", "markdown-it": "^10.0.0",
"markdown-it-emoji": "^1.4.0", "markdown-it-emoji": "^1.4.0",
"markdown-it-html5-media": "^0.6.0",
"pg": "^7.12.1", "pg": "^7.12.1",
"pug": "^2.0.4", "pug": "^2.0.4",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
@ -165,7 +168,7 @@ Lockfile:
resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.29.tgz#7cd933c902c4fc83046517a1bef973886d00bdb6" resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.29.tgz#7cd933c902c4fc83046517a1bef973886d00bdb6"
integrity sha512-kmVtnxTuUuhCET669irqQmPAez4KFnFVKvpleVRyfC3g+SHD1hIkFZcWLim9BVcwUBLO59o8VZE4yGCmTif8Yw== integrity sha512-kmVtnxTuUuhCET669irqQmPAez4KFnFVKvpleVRyfC3g+SHD1hIkFZcWLim9BVcwUBLO59o8VZE4yGCmTif8Yw==
"@types/body-parser@*": "@types/body-parser@*", "@types/body-parser@^1.17.1":
version "1.17.1" version "1.17.1"
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.1.tgz#18fcf61768fb5c30ccc508c21d6fd2e8b3bf7897" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.1.tgz#18fcf61768fb5c30ccc508c21d6fd2e8b3bf7897"
integrity sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w== integrity sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w==
@ -879,7 +882,7 @@ Lockfile:
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.1.tgz#df70e302b471d7473489acf26a93d63b53f874de" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.1.tgz#df70e302b471d7473489acf26a93d63b53f874de"
integrity sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg== integrity sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==
body-parser@1.19.0: body-parser@1.19.0, body-parser@^1.19.0:
version "1.19.0" version "1.19.0"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
@ -1743,6 +1746,11 @@ Lockfile:
engine.io-parser "~2.2.0" engine.io-parser "~2.2.0"
ws "^7.1.2" ws "^7.1.2"
entities@~1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
entities@~2.0.0: entities@~2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4"
@ -3246,6 +3254,13 @@ Lockfile:
resolved "https://registry.yarnpkg.com/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz#9bee0e9a990a963ba96df6980c4fddb05dfb4dcc" resolved "https://registry.yarnpkg.com/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz#9bee0e9a990a963ba96df6980c4fddb05dfb4dcc"
integrity sha1-m+4OmpkKljupbfaYDE/dsF37Tcw= integrity sha1-m+4OmpkKljupbfaYDE/dsF37Tcw=
markdown-it-html5-media@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/markdown-it-html5-media/-/markdown-it-html5-media-0.6.0.tgz#ed82bbdaec0545ba0879f0454c5a9d73171d3a76"
integrity sha512-3zxk00H5adz5n/LaC+yncTfZhSxa7igVKsKNfegUJw7gNAxMEA7D6YLHzSM+isJSnTLbiqU7663hfitv/ybzeg==
dependencies:
markdown-it "^8.4.0"
markdown-it@^10.0.0: markdown-it@^10.0.0:
version "10.0.0" version "10.0.0"
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-10.0.0.tgz#abfc64f141b1722d663402044e43927f1f50a8dc" resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-10.0.0.tgz#abfc64f141b1722d663402044e43927f1f50a8dc"
@ -3257,6 +3272,17 @@ Lockfile:
mdurl "^1.0.1" mdurl "^1.0.1"
uc.micro "^1.0.5" uc.micro "^1.0.5"
markdown-it@^8.4.0:
version "8.4.2"
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54"
integrity sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==
dependencies:
argparse "^1.0.7"
entities "~1.1.1"
linkify-it "^2.0.0"
mdurl "^1.0.1"
uc.micro "^1.0.5"
matchdep@^2.0.0: matchdep@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-2.0.0.tgz#c6f34834a0d8dbc3b37c27ee8bbcb27c7775582e" resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-2.0.0.tgz#c6f34834a0d8dbc3b37c27ee8bbcb27c7775582e"

@ -1613,6 +1613,11 @@ engine.io@~3.4.0:
engine.io-parser "~2.2.0" engine.io-parser "~2.2.0"
ws "^7.1.2" ws "^7.1.2"
entities@~1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
entities@~2.0.0: entities@~2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4"
@ -3116,6 +3121,13 @@ markdown-it-emoji@^1.4.0:
resolved "https://registry.yarnpkg.com/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz#9bee0e9a990a963ba96df6980c4fddb05dfb4dcc" resolved "https://registry.yarnpkg.com/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz#9bee0e9a990a963ba96df6980c4fddb05dfb4dcc"
integrity sha1-m+4OmpkKljupbfaYDE/dsF37Tcw= integrity sha1-m+4OmpkKljupbfaYDE/dsF37Tcw=
markdown-it-html5-media@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/markdown-it-html5-media/-/markdown-it-html5-media-0.6.0.tgz#ed82bbdaec0545ba0879f0454c5a9d73171d3a76"
integrity sha512-3zxk00H5adz5n/LaC+yncTfZhSxa7igVKsKNfegUJw7gNAxMEA7D6YLHzSM+isJSnTLbiqU7663hfitv/ybzeg==
dependencies:
markdown-it "^8.4.0"
markdown-it@^10.0.0: markdown-it@^10.0.0:
version "10.0.0" version "10.0.0"
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-10.0.0.tgz#abfc64f141b1722d663402044e43927f1f50a8dc" resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-10.0.0.tgz#abfc64f141b1722d663402044e43927f1f50a8dc"
@ -3127,6 +3139,17 @@ markdown-it@^10.0.0:
mdurl "^1.0.1" mdurl "^1.0.1"
uc.micro "^1.0.5" uc.micro "^1.0.5"
markdown-it@^8.4.0:
version "8.4.2"
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54"
integrity sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==
dependencies:
argparse "^1.0.7"
entities "~1.1.1"
linkify-it "^2.0.0"
mdurl "^1.0.1"
uc.micro "^1.0.5"
matchdep@^2.0.0: matchdep@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-2.0.0.tgz#c6f34834a0d8dbc3b37c27ee8bbcb27c7775582e" resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-2.0.0.tgz#c6f34834a0d8dbc3b37c27ee8bbcb27c7775582e"

Loading…
Cancel
Save