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

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

@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added `deletable' field on post - Added `deletable' field on post
- Admin field that for admin users - Admin field that for admin users
- ability for admins to delete posts - ability for admins to delete posts
- ability to upload file at `/upload` with the name profilePicture
- publicPath to config file to configure the directory for public files
### Removed ### Removed
@ -26,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- changed the running behaviour to run in cluster threads via node.js cluster api - changed the running behaviour to run in cluster threads via node.js cluster api
- gql field userVote requires a userId - gql field userVote requires a userId
- default findUser param limit to 20 - default findUser param limit to 20
- only group admins can create group events
### Fixed ### Fixed

@ -27,6 +27,7 @@
"@types/cookie-parser": "^1.4.2", "@types/cookie-parser": "^1.4.2",
"@types/cors": "^2.8.6", "@types/cors": "^2.8.6",
"@types/express": "^4.17.1", "@types/express": "^4.17.1",
"@types/express-fileupload": "^1.1.0",
"@types/express-graphql": "^0.8.0", "@types/express-graphql": "^0.8.0",
"@types/express-session": "^1.15.14", "@types/express-session": "^1.15.14",
"@types/express-socket.io-session": "^1.3.2", "@types/express-socket.io-session": "^1.3.2",
@ -38,8 +39,10 @@
"@types/node": "^12.7.12", "@types/node": "^12.7.12",
"@types/pg": "^7.11.0", "@types/pg": "^7.11.0",
"@types/sequelize": "^4.28.5", "@types/sequelize": "^4.28.5",
"@types/sharp": "^0.23.1",
"@types/socket.io": "^2.1.2", "@types/socket.io": "^2.1.2",
"@types/socket.io-redis": "^1.0.25", "@types/socket.io-redis": "^1.0.25",
"@types/uuid": "^3.4.6",
"@types/validator": "^10.11.3", "@types/validator": "^10.11.3",
"chai": "^4.2.0", "chai": "^4.2.0",
"delete": "^1.1.0", "delete": "^1.1.0",
@ -54,12 +57,12 @@
"typescript": "^3.7.2" "typescript": "^3.7.2"
}, },
"dependencies": { "dependencies": {
"@types/uuid": "^3.4.6",
"compression": "^1.7.4", "compression": "^1.7.4",
"connect-session-sequelize": "^6.0.0", "connect-session-sequelize": "^6.0.0",
"cookie-parser": "^1.4.4", "cookie-parser": "^1.4.4",
"cors": "^2.8.5", "cors": "^2.8.5",
"express": "^4.17.1", "express": "^4.17.1",
"express-fileupload": "^1.1.6",
"express-graphql": "^0.9.0", "express-graphql": "^0.9.0",
"express-session": "^1.16.2", "express-session": "^1.16.2",
"express-socket.io-session": "^1.3.5", "express-socket.io-session": "^1.3.5",
@ -75,6 +78,7 @@
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"sequelize": "^5.19.6", "sequelize": "^5.19.6",
"sequelize-typescript": "^1.0.0", "sequelize-typescript": "^1.0.0",
"sharp": "^0.23.4",
"socket.io": "^2.2.0", "socket.io": "^2.2.0",
"socket.io-redis": "^5.2.0", "socket.io-redis": "^5.2.0",
"sqlite3": "^4.1.0", "sqlite3": "^4.1.0",

@ -3,6 +3,8 @@ import * as cookieParser from "cookie-parser";
import * as cors from "cors"; import * as cors from "cors";
import {Request, Response} from "express"; import {Request, Response} from "express";
import * as express from "express"; import * as express from "express";
import {UploadedFile} from "express-fileupload";
import * as fileUpload from "express-fileupload";
import * as graphqlHTTP from "express-graphql"; import * as graphqlHTTP from "express-graphql";
import * as session from "express-session"; import * as session from "express-session";
import sharedsession = require("express-socket.io-session"); import sharedsession = require("express-socket.io-session");
@ -13,6 +15,7 @@ import * as http from "http";
import * as httpStatus from "http-status"; import * as httpStatus from "http-status";
import * as path from "path"; import * as path from "path";
import {Sequelize} from "sequelize-typescript"; import {Sequelize} from "sequelize-typescript";
import * as sharp from "sharp";
import * as socketIo from "socket.io"; import * as socketIo from "socket.io";
import * as socketIoRedis from "socket.io-redis"; import * as socketIoRedis from "socket.io-redis";
import {resolver} from "./graphql/resolvers"; import {resolver} from "./graphql/resolvers";
@ -27,6 +30,7 @@ class App {
public app: express.Application; public app: express.Application;
public io: socketIo.Server; public io: socketIo.Server;
public server: http.Server; public server: http.Server;
public readonly publicPath: string;
public readonly id?: number; public readonly id?: number;
public readonly sequelize: Sequelize; public readonly sequelize: Sequelize;
@ -36,6 +40,10 @@ class App {
this.server = new http.Server(this.app); this.server = new http.Server(this.app);
this.io = socketIo(this.server); this.io = socketIo(this.server);
this.sequelize = new Sequelize(globals.config.database.connectionUri); this.sequelize = new Sequelize(globals.config.database.connectionUri);
this.publicPath = globals.config.frontend.publicPath;
if (!path.isAbsolute(this.publicPath)) {
this.publicPath = path.normalize(path.join(__dirname, this.publicPath));
}
} }
/** /**
@ -62,7 +70,12 @@ class App {
this.sequelize.options.logging = (msg) => logger.silly(msg); this.sequelize.options.logging = (msg) => logger.silly(msg);
logger.info("Setting up socket.io"); logger.info("Setting up socket.io");
await routes.ioListeners(this.io); await routes.ioListeners(this.io);
try {
this.io.adapter(socketIoRedis()); this.io.adapter(socketIoRedis());
} catch (err) {
logger.error(err.message);
logger.debug(err.stack);
}
this.io.use(sharedsession(appSession, {autoSave: true})); this.io.use(sharedsession(appSession, {autoSave: true}));
logger.info("Configuring express app."); logger.info("Configuring express app.");
@ -73,7 +86,7 @@ class App {
this.app.use(compression()); this.app.use(compression());
this.app.use(express.json()); this.app.use(express.json());
this.app.use(express.urlencoded({extended: false})); this.app.use(express.urlencoded({extended: false}));
this.app.use(express.static(path.join(__dirname, "public"))); this.app.use(express.static(this.publicPath));
this.app.use(cookieParser()); this.app.use(cookieParser());
this.app.use(appSession); this.app.use(appSession);
// enable cross origin requests if enabled in the config // enable cross origin requests if enabled in the config
@ -112,6 +125,29 @@ class App {
schema: buildSchema(importSchema(path.join(__dirname, "./graphql/schema.graphql"))), schema: buildSchema(importSchema(path.join(__dirname, "./graphql/schema.graphql"))),
}; };
})); }));
this.app.use("/upload", fileUpload());
this.app.use("/upload", async (req, res) => {
const profilePic = req.files.profilePicture as UploadedFile;
let success = false;
let fileName;
if (profilePic && req.session.userId) {
const dir = path.join(this.publicPath, "data/profilePictures");
await fsx.ensureDir(dir);
await sharp(profilePic.data)
.resize(512, 512)
.normalise()
.png()
.toFile(path.join(dir, req.session.userId + ".png"));
success = true;
fileName = `/data/profilePictures/${req.session.userId}.png`;
} else {
res.status(400);
}
res.json({
fileName,
success,
});
});
// allow access to cluster information // allow access to cluster information
this.app.use("/cluster-info", (req: Request, res: Response) => { this.app.use("/cluster-info", (req: Request, res: Response) => {
res.json({ res.json({
@ -121,7 +157,7 @@ class App {
// redirect all request to the angular file // redirect all request to the angular file
this.app.use((req: any, res: Response) => { this.app.use((req: any, res: Response) => {
if (globals.config.frontend.angularIndex) { if (globals.config.frontend.angularIndex) {
const angularIndex = path.join(__dirname, globals.config.frontend.angularIndex); const angularIndex = path.join(this.publicPath, globals.config.frontend.angularIndex);
if (fsx.existsSync(path.join(angularIndex))) { if (fsx.existsSync(path.join(angularIndex))) {
res.sendFile(angularIndex); res.sendFile(angularIndex);
} else { } else {

@ -22,4 +22,5 @@ logging:
level: info level: info
frontend: frontend:
angularIndex: angularIndex: index.html
publicPath: ./public

@ -4,6 +4,8 @@ import * as yaml from "js-yaml";
import {Op} from "sequelize"; import {Op} from "sequelize";
import dataaccess from "../lib/dataAccess"; import dataaccess from "../lib/dataAccess";
import {NotLoggedInGqlError, PostNotFoundGqlError} from "../lib/errors/graphqlErrors"; import {NotLoggedInGqlError, PostNotFoundGqlError} from "../lib/errors/graphqlErrors";
import {InvalidLoginError} from "../lib/errors/InvalidLoginError";
import {UserNotFoundError} from "../lib/errors/UserNotFoundError";
import globals from "../lib/globals"; import globals from "../lib/globals";
import {InternalEvents} from "../lib/InternalEvents"; import {InternalEvents} from "../lib/InternalEvents";
import * as models from "../lib/models"; import * as models from "../lib/models";
@ -151,10 +153,15 @@ export function resolver(req: any, res: any): any {
if (email && passwordHash) { if (email && passwordHash) {
try { try {
const user = await dataaccess.getUserByLogin(email, passwordHash); const user = await dataaccess.getUserByLogin(email, passwordHash);
if (!user) {
res.status(status.BAD_REQUEST);
return new InvalidLoginError(email);
} else {
return { return {
expires: Number(user.authExpire), expires: Number(user.authExpire),
value: user.token(), value: user.token(),
}; };
}
} catch (err) { } catch (err) {
res.status(status.BAD_REQUEST); res.status(status.BAD_REQUEST);
return err.graphqlError ?? new GraphQLError(err.message); return err.graphqlError ?? new GraphQLError(err.message);
@ -441,8 +448,13 @@ export function resolver(req: any, res: any): any {
async createEvent({name, dueDate, groupId}: { name: string, dueDate: string, groupId: number }) { async createEvent({name, dueDate, groupId}: { name: string, dueDate: string, groupId: number }) {
if (req.session.userId) { if (req.session.userId) {
const date = new Date(Number(dueDate)); const date = new Date(Number(dueDate));
const group = await models.Group.findByPk(groupId); const group = await models.Group.findByPk(groupId, {include: [{association: "rAdmins"}]});
if (group.rAdmins.find((x) => x.id === req.session.userId)) {
return group.$create<models.Event>("rEvent", {name, dueDate: date}); return group.$create<models.Event>("rEvent", {name, dueDate: date});
} else {
res.status(status.FORBIDDEN);
return new GraphQLError("You are not a group admin!");
}
} else { } else {
res.status(status.UNAUTHORIZED); res.status(status.UNAUTHORIZED);
return new NotLoggedInGqlError(); return new NotLoggedInGqlError();

@ -63,5 +63,10 @@ interface IConfig {
* Points to the index.html which is loaded as a fallback for angular to work * Points to the index.html which is loaded as a fallback for angular to work
*/ */
angularIndex?: string; angularIndex?: string;
/**
* The path of the public folder
*/
publicPath?: string;
}; };
} }

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save