More graphql implementation stuff

- implemented methods to get user and post information
- implemented methods to create chatrooms
pull/1/head
Trivernis 5 years ago
parent 84b683db11
commit d7f819e02e

41
package-lock.json generated

@ -2532,8 +2532,7 @@
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
@ -2554,14 +2553,12 @@
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -2576,20 +2573,17 @@
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@ -2706,8 +2700,7 @@
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
@ -2719,7 +2712,6 @@
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
@ -2734,7 +2726,6 @@
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
@ -2742,14 +2733,12 @@
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.3.5", "version": "2.3.5",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"yallist": "^3.0.0" "yallist": "^3.0.0"
@ -2768,7 +2757,6 @@
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
@ -2849,8 +2837,7 @@
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@ -2862,7 +2849,6 @@
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -2948,8 +2934,7 @@
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
@ -2985,7 +2970,6 @@
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
@ -3005,7 +2989,6 @@
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
@ -3049,14 +3032,12 @@
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.0.3", "version": "3.0.3",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
} }
} }
}, },

@ -10,7 +10,7 @@ import {importSchema} from "graphql-import";
import * as http from "http"; import * as http from "http";
import * as path from "path"; import * as path from "path";
import * as socketIo from "socket.io"; import * as socketIo from "socket.io";
import dataaccess from "./lib/dataaccess"; import dataaccess, {queryHelper} from "./lib/dataaccess";
import globals from "./lib/globals"; import globals from "./lib/globals";
import routes from "./routes"; import routes from "./routes";

@ -54,7 +54,7 @@ export class SqlTransaction {
/** /**
* Releases the client back to the pool. * Releases the client back to the pool.
*/ */
public async release() { public release() {
this.client.release(); this.client.release();
} }
} }

@ -1,6 +1,7 @@
import {Pool} from "pg"; import {Pool} from "pg";
import globals from "../globals"; import globals from "../globals";
import {QueryHelper} from "../QueryHelper"; import {QueryHelper} from "../QueryHelper";
import {Chatroom} from "./Chatroom";
import {Post} from "./Post"; import {Post} from "./Post";
import {Profile} from "./Profile"; import {Profile} from "./Profile";
import {User} from "./User"; import {User} from "./User";
@ -89,6 +90,22 @@ namespace dataaccess {
return new Profile(result.id, result); return new Profile(result.id, result);
} }
/**
* Returns a post for a given postId.s
* @param postId
*/
export async function getPost(postId: number) {
const result = await queryHelper.first({
text: "SELECT * FROM posts WHERE id = $1",
values: [postId],
});
if (result) {
return new Post(result.id, result);
} else {
return null;
}
}
/** /**
* Creates a post * Creates a post
* @param content * @param content
@ -115,6 +132,35 @@ namespace dataaccess {
return true; return true;
} }
/**
* Creates a chatroom containing two users
* @param members
*/
export async function createChat(...members: number[]) {
const idResult = await queryHelper.first({
text: "INSERT INTO chats (id) values (nextval('chats_id_seq'::regclass)) RETURNING *;",
});
const id = idResult.id;
const transaction = await queryHelper.createTransaction();
try {
await transaction.begin();
for (const member of members) {
await transaction.query({
name: "chat-member-insert",
text: "INSERT INTO chat_members (ABSOLUTE chat, member) VALUES ($1, $2);",
values: [member],
});
}
await transaction.commit();
} catch (err) {
globals.logger.warn(`Failed to insert chatmember into database: ${err.message}`);
globals.logger.debug(err.stack);
} finally {
transaction.release();
}
return new Chatroom(id);
}
/** /**
* Enum representing the types of votes that can be performed on a post. * Enum representing the types of votes that can be performed on a post.
*/ */

@ -0,0 +1,11 @@
export namespace is {
const emailRegex = /\S+?@\S+?(\.\S+?)?\.\w{2,3}(.\w{2-3})?/g
/**
* Tests if a string is a valid email.
* @param testString
*/
export function email(testString: string) {
return emailRegex.test(testString)
}
}

@ -1,18 +1,21 @@
type Query { type Query {
"returns the user object for a given user id" "returns the user object for a given user id or a handle (only one required)"
getUser(userId: ID): User getUser(userId: ID, handle: String): User
"returns the logged in user" "returns the logged in user"
getSelf: User getSelf: User
"returns the post object for a post id" "returns the post object for a post id"
getPost(postId: ID): Post getPost(postId: ID!): Post
"returns the chat object for a chat id" "returns the chat object for a chat id"
getChat(chatId: ID): ChatRoom getChat(chatId: ID!): ChatRoom
"Creates a chat between the user (and optional an other user)"
createChat(members: [ID!]): ChatRoom
"returns the request object for a request id" "returns the request object for a request id"
getRequest(requestId: ID): Request getRequest(requestId: ID!): Request
"find a post by the posted date or content" "find a post by the posted date or content"
findPost(first: Int, offset: Int, text: String!, postedDate: String): [Post] findPost(first: Int, offset: Int, text: String!, postedDate: String): [Post]

@ -5,6 +5,7 @@ import {Server} from "socket.io";
import dataaccess from "../lib/dataaccess"; import dataaccess from "../lib/dataaccess";
import {Post} from "../lib/dataaccess/Post"; import {Post} from "../lib/dataaccess/Post";
import {Profile} from "../lib/dataaccess/Profile"; import {Profile} from "../lib/dataaccess/Profile";
import {is} from "../lib/regex";
import Route from "../lib/Route"; import Route from "../lib/Route";
/** /**
@ -50,13 +51,31 @@ class HomeRoute extends Route {
return new GraphQLError("Not logged in"); return new GraphQLError("Not logged in");
} }
}, },
async getUser({userId, handle}: {userId: number, handle: string}) {
if (handle) {
return await dataaccess.getUserByHandle(handle);
} else if (userId) {
return dataaccess.getUser(userId);
} else {
res.status(status.BAD_REQUEST);
return new GraphQLError("No userId or handle provided.");
}
},
async getPost({postId}: {postId: number}) {
if (postId) {
return await dataaccess.getPost(postId);
} else {
res.status(status.BAD_REQUEST);
return new GraphQLError("No postId given.");
}
},
acceptCookies() { acceptCookies() {
req.session.cookiesAccepted = true; req.session.cookiesAccepted = true;
return true; return true;
}, },
async login(args: {email: string, passwordHash: string}) { async login({email, passwordHash}: {email: string, passwordHash: string}) {
if (args.email && args.passwordHash) { if (email && passwordHash) {
const user = await dataaccess.getUserByLogin(args.email, args.passwordHash); const user = await dataaccess.getUserByLogin(email, passwordHash);
if (user && user.id) { if (user && user.id) {
req.session.userId = user.id; req.session.userId = user.id;
return user; return user;
@ -75,12 +94,16 @@ class HomeRoute extends Route {
return true; return true;
} else { } else {
res.status(status.UNAUTHORIZED); res.status(status.UNAUTHORIZED);
return new GraphQLError("User is not logged in."); return new GraphQLError("Not logged in.");
} }
}, },
async register(args: {username: string, email: string, passwordHash: string}) { async register({username, email, passwordHash}: {username: string, email: string, passwordHash: string}) {
if (args.username && args.email && args.passwordHash) { if (username && email && passwordHash) {
const user = await dataaccess.registerUser(args.username, args.email, args.passwordHash); if (!is.email(email)) {
res.status(status.BAD_REQUEST);
return new GraphQLError(`'${email}' is not a valid email address!`);
}
const user = await dataaccess.registerUser(username, email, passwordHash);
if (user) { if (user) {
req.session.userId = user.id; req.session.userId = user.id;
return user; return user;
@ -93,10 +116,10 @@ class HomeRoute extends Route {
return new GraphQLError("No username, email or password given."); return new GraphQLError("No username, email or password given.");
} }
}, },
async vote(args: {postId: number, type: dataaccess.VoteType}) { async vote({postId, type}: {postId: number, type: dataaccess.VoteType}) {
if (args.postId && args.type) { if (postId && type) {
if (req.session.userId) { if (req.session.userId) {
return await (new Post(args.postId)).vote(req.session.userId, args.type); return await (new Post(postId)).vote(req.session.userId, type);
} else { } else {
res.status(status.UNAUTHORIZED); res.status(status.UNAUTHORIZED);
return new GraphQLError("Not logged in."); return new GraphQLError("Not logged in.");
@ -106,10 +129,10 @@ class HomeRoute extends Route {
return new GraphQLError("No postId or type given."); return new GraphQLError("No postId or type given.");
} }
}, },
async createPost(args: {content: string}) { async createPost({content}: {content: string}) {
if (args.content) { if (content) {
if (req.session.userId) { if (req.session.userId) {
return await dataaccess.createPost(args.content, req.session.userId); return await dataaccess.createPost(content, req.session.userId);
} else { } else {
res.status(status.UNAUTHORIZED); res.status(status.UNAUTHORIZED);
return new GraphQLError("Not logged in."); return new GraphQLError("Not logged in.");
@ -119,9 +142,9 @@ class HomeRoute extends Route {
return new GraphQLError("Can't create empty post."); return new GraphQLError("Can't create empty post.");
} }
}, },
async deletePost(args: {postId: number}) { async deletePost({postId}: {postId: number}) {
if (args.postId) { if (postId) {
const post = new Post(args.postId); const post = new Post(postId);
if ((await post.author()).id === req.session.userId) { if ((await post.author()).id === req.session.userId) {
return await dataaccess.deletePost(post.id); return await dataaccess.deletePost(post.id);
} else { } else {
@ -132,6 +155,19 @@ class HomeRoute extends Route {
return new GraphQLError("No postId given."); return new GraphQLError("No postId given.");
} }
}, },
async createChat({members}: {members: number[]}) {
if (req.session.userId) {
const chatMembers = [req.session.userId];
if (members) {
chatMembers.push(...members);
}
return await dataaccess.createChat(...chatMembers);
} else {
res.status(status.UNAUTHORIZED);
return new GraphQLError("Not logged in.");
}
},
}; };
} }
} }

Loading…
Cancel
Save