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

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

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

@ -1,6 +1,7 @@
import {Pool} from "pg";
import globals from "../globals";
import {QueryHelper} from "../QueryHelper";
import {Chatroom} from "./Chatroom";
import {Post} from "./Post";
import {Profile} from "./Profile";
import {User} from "./User";
@ -89,6 +90,22 @@ namespace dataaccess {
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
* @param content
@ -115,6 +132,35 @@ namespace dataaccess {
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.
*/

@ -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 {
"returns the user object for a given user id"
getUser(userId: ID): User
"returns the user object for a given user id or a handle (only one required)"
getUser(userId: ID, handle: String): User
"returns the logged in user"
getSelf: User
"returns the post object for a post id"
getPost(postId: ID): Post
getPost(postId: ID!): Post
"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"
getRequest(requestId: ID): Request
getRequest(requestId: ID!): Request
"find a post by the posted date or content"
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 {Post} from "../lib/dataaccess/Post";
import {Profile} from "../lib/dataaccess/Profile";
import {is} from "../lib/regex";
import Route from "../lib/Route";
/**
@ -50,13 +51,31 @@ class HomeRoute extends Route {
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() {
req.session.cookiesAccepted = true;
return true;
},
async login(args: {email: string, passwordHash: string}) {
if (args.email && args.passwordHash) {
const user = await dataaccess.getUserByLogin(args.email, args.passwordHash);
async login({email, passwordHash}: {email: string, passwordHash: string}) {
if (email && passwordHash) {
const user = await dataaccess.getUserByLogin(email, passwordHash);
if (user && user.id) {
req.session.userId = user.id;
return user;
@ -75,12 +94,16 @@ class HomeRoute extends Route {
return true;
} else {
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}) {
if (args.username && args.email && args.passwordHash) {
const user = await dataaccess.registerUser(args.username, args.email, args.passwordHash);
async register({username, email, passwordHash}: {username: string, email: string, passwordHash: string}) {
if (username && email && 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) {
req.session.userId = user.id;
return user;
@ -93,10 +116,10 @@ class HomeRoute extends Route {
return new GraphQLError("No username, email or password given.");
}
},
async vote(args: {postId: number, type: dataaccess.VoteType}) {
if (args.postId && args.type) {
async vote({postId, type}: {postId: number, type: dataaccess.VoteType}) {
if (postId && type) {
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 {
res.status(status.UNAUTHORIZED);
return new GraphQLError("Not logged in.");
@ -106,10 +129,10 @@ class HomeRoute extends Route {
return new GraphQLError("No postId or type given.");
}
},
async createPost(args: {content: string}) {
if (args.content) {
async createPost({content}: {content: string}) {
if (content) {
if (req.session.userId) {
return await dataaccess.createPost(args.content, req.session.userId);
return await dataaccess.createPost(content, req.session.userId);
} else {
res.status(status.UNAUTHORIZED);
return new GraphQLError("Not logged in.");
@ -119,9 +142,9 @@ class HomeRoute extends Route {
return new GraphQLError("Can't create empty post.");
}
},
async deletePost(args: {postId: number}) {
if (args.postId) {
const post = new Post(args.postId);
async deletePost({postId}: {postId: number}) {
if (postId) {
const post = new Post(postId);
if ((await post.author()).id === req.session.userId) {
return await dataaccess.deletePost(post.id);
} else {
@ -132,6 +155,19 @@ class HomeRoute extends Route {
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