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

pull/1/head
Tomislav_K 5 years ago committed by Gitea
commit f196ca527a

@ -2,7 +2,7 @@ import * as express from "express";
import * as http from "http";
import * as path from "path";
import * as socketIo from "socket.io";
import {DTO} from "./lib/DTO";
import dataaccess from "./lib/dataaccess";
import globals from "./lib/globals";
import routes from "./routes";
@ -10,20 +10,18 @@ class App {
public app: express.Application;
public io: socketIo.Server;
public server: http.Server;
public dto: DTO;
constructor() {
this.app = express();
this.server = new http.Server(this.app);
this.io = socketIo(this.server);
this.dto = new DTO();
}
/**
* initializes everything that needs to be initialized asynchronous.
*/
public async init() {
await this.dto.init();
await dataaccess.init();
await routes.ioListeners(this.io);
this.app.set("views", path.join(__dirname, "views"));
this.app.set("view engine", "pug");

@ -1,248 +0,0 @@
import {Runtime} from "inspector";
import {Pool} from "pg";
import globals from "./globals";
import {QueryHelper} from "./QueryHelper";
const config = globals.config;
const tableCreationFile = __dirname + "/../sql/create-tables.sql";
const dbClient: Pool = new Pool({
database: config.database.database,
host: config.database.host,
password: config.database.password,
port: config.database.port,
user: config.database.user,
});
const queryHelper = new QueryHelper(dbClient, tableCreationFile);
export class DTO {
private queryHelper: QueryHelper;
constructor() {
this.queryHelper = queryHelper;
}
/**
* Initializes everything that needs to be initialized asynchronous.
*/
public async init() {
await this.queryHelper.createTables();
}
/**
* Returns the user by id
* @param userId
*/
public getUser(userId: number) {
return new User(userId);
}
/**
* Returns the user by handle.
* @param userHandle
*/
public async getUserByHandle(userHandle: string) {
const result = await this.queryHelper.first({
text: "SELECT * FROM users WHERE users.handle = $1",
values: [userHandle],
});
return new User(result.id, result);
}
}
export class User {
public readonly id: number;
private $name: string;
private $handle: string;
private $email: string;
private $greenpoints: number;
private $joinedAt: string;
private dataLoaded: boolean;
/**
* Constructor of the user
* @param id
* @param row
*/
constructor(id: number, private row?: any) {
this.id = id;
}
/**
* The name of the user
*/
public async name(): Promise<string> {
if (!this.dataLoaded) {
await this.loadData();
}
return this.$name;
}
/**
* Sets the username of the user
* @param name
*/
public async setName(name: string): Promise<string> {
const result = await queryHelper.first({
text: "UPDATE TABLE users SET name = $1 WHERE id = $2",
values: [name, this.id],
});
return result.name;
}
/**
* The unique handle of the user.
*/
public async handle(): Promise<string> {
if (!this.dataLoaded) {
await this.loadData();
}
return this.$handle;
}
/**
* Updates the handle of the user
*/
public async setHandle(handle: string): Promise<string> {
const result = await queryHelper.first({
text: "UPDATE TABLE users SET handle = $1 WHERE id = $2",
values: [handle, this.id],
});
return result.handle;
}
/**
* The email of the user
*/
public async email(): Promise<string> {
if (!this.dataLoaded) {
await this.loadData();
}
return this.$email;
}
/**
* Sets the email of the user
* @param email
*/
public async setEmail(email: string): Promise<string> {
const result = await queryHelper.first({
text: "UPDATE TABLE users SET email = $1 WHERE users.id = $2 RETURNING email",
values: [email, this.id],
});
return result.email;
}
/**
* The number of greenpoints of the user
*/
public async greenpoints(): Promise<number> {
if (!this.dataLoaded) {
await this.loadData();
}
return this.$greenpoints;
}
/**
* Sets the greenpoints of a user.
* @param points
*/
public async setGreenpoints(points: number): Promise<number> {
const result = await queryHelper.first({
text: "UPDATE users SET greenpoints = $1 WHERE id = $2 RETURNING greenpoints",
values: [points, this.id],
});
return result.greenpoints;
}
/**
* The date the user joined the platform
*/
public async joinedAt(): Promise<Date> {
if (!this.dataLoaded) {
await this.loadData();
}
return new Date(this.$joinedAt);
}
/**
* Fetches the data for the user.
*/
private async loadData(): Promise<void> {
let result: any;
if (this.row) {
result = this.row;
} else {
result = await queryHelper.first({
text: "SELECT * FROM users WHERE user.id = $1",
values: [this.id],
});
}
if (result) {
this.$name = result.name;
this.$handle = result.handle;
this.$email = result.email;
this.$greenpoints = result.greenpoints;
this.$joinedAt = result.joined_at;
this.dataLoaded = true;
}
}
}
export class Post {
public readonly id: number;
private $upvotes: number;
private $downvotes: number;
private $createdAt: string;
private $content: string;
private $author: number;
private $type: string;
private dataLoaded: boolean = false;
constructor(id: number, private row?: any) {
this.id = id;
}
/**
* Returns the upvotes of a post.
*/
public async upvotes() {
if (!this.dataLoaded) {
await this.loadData();
}
return this.$upvotes;
}
/**
* Returns the downvotes of the post
*/
public async downvotes() {
if (!this.dataLoaded) {
await this.loadData();
}
return this.$downvotes;
}
/**
* Loads the data from the database if needed.
*/
private async loadData(): Promise<void> {
let result: any;
if (this.row) {
result = this.row;
} else {
result = await queryHelper.first({
text: "SELECT * FROM posts WHERE posts.id = $1",
values: [this.id],
});
}
if (result) {
this.$author = result.author;
this.$content = result.content;
this.$downvotes = result.downvotes;
this.$upvotes = result.upvotes;
this.$createdAt = result.created_at;
this.$type = result.type;
this.dataLoaded = true;
}
}
}

@ -0,0 +1,14 @@
abstract class DataObject {
protected dataLoaded: boolean = false;
constructor(public id: number, protected row?: any) {
}
protected abstract loadData(): Promise<void>;
protected loadDataIfNotExists() {
if (this.dataLoaded) {
this.loadData();
}
}
}

@ -0,0 +1,101 @@
import {queryHelper, VoteType} from "./index";
import {User} from "./User";
export class Post extends DataObject {
public readonly id: number;
private $upvotes: number;
private $downvotes: number;
private $createdAt: string;
private $content: string;
private $author: number;
private $type: string;
/**
* Returns the upvotes of a post.
*/
public async upvotes(): Promise<number> {
this.loadDataIfNotExists();
return this.$upvotes;
}
/**
* Returns the downvotes of the post
*/
public async downvotes(): Promise<number> {
this.loadDataIfNotExists();
return this.$downvotes;
}
/**
* The content of the post (markdown)
*/
public async content(): Promise<string> {
this.loadDataIfNotExists();
return this.$content;
}
/**
* The date the post was created at.
*/
public async createdAt(): Promise<string> {
this.loadDataIfNotExists();
return this.$createdAt;
}
/**
* The autor of the post.
*/
public async author(): Promise<User> {
this.loadDataIfNotExists();
return new User(this.$author);
}
/**
* Deletes the post.
*/
public async delete(): Promise<void> {
const query = await queryHelper.first({
text: "DELETE FROM posts WHERE id = $1",
values: [this.id],
});
}
/**
* The type of vote the user performed on the post.
*/
public async userVote(userId: number): Promise<VoteType> {
const result = await queryHelper.first({
text: "SELECT vote_type FROM votes WHERE user_id = $1 AND item_id = $2",
values: [userId, this.id],
});
if (result) {
return result.vote_type;
} else {
return null;
}
}
/**
* Loads the data from the database if needed.
*/
protected async loadData(): Promise<void> {
let result: any;
if (this.row) {
result = this.row;
} else {
result = await queryHelper.first({
text: "SELECT * FROM posts WHERE posts.id = $1",
values: [this.id],
});
}
if (result) {
this.$author = result.author;
this.$content = result.content;
this.$downvotes = result.downvotes;
this.$upvotes = result.upvotes;
this.$createdAt = result.created_at;
this.$type = result.type;
this.dataLoaded = true;
}
}
}

@ -0,0 +1,136 @@
import {queryHelper} from "./index";
import {Post} from "./Post";
export class User extends DataObject {
private $name: string;
private $handle: string;
private $email: string;
private $greenpoints: number;
private $joinedAt: string;
/**
* The name of the user
*/
public async name(): Promise<string> {
this.loadDataIfNotExists();
return this.$name;
}
/**
* Sets the username of the user
* @param name
*/
public async setName(name: string): Promise<string> {
const result = await queryHelper.first({
text: "UPDATE TABLE users SET name = $1 WHERE id = $2",
values: [name, this.id],
});
return result.name;
}
/**
* The unique handle of the user.
*/
public async handle(): Promise<string> {
this.loadDataIfNotExists();
return this.$handle;
}
/**
* Updates the handle of the user
*/
public async setHandle(handle: string): Promise<string> {
const result = await queryHelper.first({
text: "UPDATE TABLE users SET handle = $1 WHERE id = $2",
values: [handle, this.id],
});
return result.handle;
}
/**
* The email of the user
*/
public async email(): Promise<string> {
this.loadDataIfNotExists();
return this.$email;
}
/**
* Sets the email of the user
* @param email
*/
public async setEmail(email: string): Promise<string> {
const result = await queryHelper.first({
text: "UPDATE TABLE users SET email = $1 WHERE users.id = $2 RETURNING email",
values: [email, this.id],
});
return result.email;
}
/**
* The number of greenpoints of the user
*/
public async greenpoints(): Promise<number> {
this.loadDataIfNotExists();
return this.$greenpoints;
}
/**
* Sets the greenpoints of a user.
* @param points
*/
public async setGreenpoints(points: number): Promise<number> {
const result = await queryHelper.first({
text: "UPDATE users SET greenpoints = $1 WHERE id = $2 RETURNING greenpoints",
values: [points, this.id],
});
return result.greenpoints;
}
/**
* The date the user joined the platform
*/
public async joinedAt(): Promise<Date> {
this.loadDataIfNotExists();
return new Date(this.$joinedAt);
}
/**
* Returns all posts for a user.
*/
public async posts(): Promise<Post[]> {
const result = await queryHelper.all({
text: "SELECT * FROM posts WHERE author = $1",
values: [this.id],
});
const posts = [];
for (const row of result) {
posts.push(new Post(row.id, row));
}
return posts;
}
/**
* Fetches the data for the user.
*/
protected async loadData(): Promise<void> {
let result: any;
if (this.row) {
result = this.row;
} else {
result = await queryHelper.first({
text: "SELECT * FROM users WHERE user.id = $1",
values: [this.id],
});
}
if (result) {
this.$name = result.name;
this.$handle = result.handle;
this.$email = result.email;
this.$greenpoints = result.greenpoints;
this.$joinedAt = result.joined_at;
this.dataLoaded = true;
}
}
}

@ -0,0 +1,63 @@
import {Pool} from "pg";
import globals from "../globals";
import {QueryHelper} from "../QueryHelper";
import {User} from "./User";
const config = globals.config;
const tableCreationFile = __dirname + "/../sql/create-tables.sql";
const dbClient: Pool = new Pool({
database: config.database.database,
host: config.database.host,
password: config.database.password,
port: config.database.port,
user: config.database.user,
});
export const queryHelper = new QueryHelper(dbClient, tableCreationFile);
namespace dataaccess {
/**
* Initializes everything that needs to be initialized asynchronous.
*/
export async function init() {
await queryHelper.createTables();
}
/**
* Returns the user by id
* @param userId
*/
export function getUser(userId: number) {
return new User(userId);
}
/**
* Returns the user by handle.
* @param userHandle
*/
export async function getUserByHandle(userHandle: string) {
const result = await this.queryHelper.first({
text: "SELECT * FROM users WHERE users.handle = $1",
values: [userHandle],
});
return new User(result.id, result);
}
/**
* Enum representing the types of votes that can be performed on a post.
*/
export enum VoteType {
UPVOTE = "UPVOTE",
DOWNVOTE = "DOWNVOTE",
}
/**
* Enum representing the types of request that can be created.
*/
export enum RequestType {
FRIENDREQUEST = "FRIENDREQUEST",
GROUPINVITE = "GROUPINVITE",
EVENTINVITE = "EVENTINVITE",
}
}
export default dataaccess;

@ -1,100 +1,129 @@
type Query {
"returns the user object for a given user id"
getUser(userId: ID): User
"returns the post object for a post id"
getPost(postId: ID): Post
"returns the chat object for a chat id"
getChat(chatId: ID): ChatRoom
"returns the request object for a request id"
getRequest(requestId: ID): Request
"find a post by the posted date or content"
findPost(first: Int, offset: Int, text: String!, postedDate: String): [Post]
"find a user by user name or handle"
findUser(first: Int, offset: Int, name: String!, handle: String!): [User]
"returns the user object for a given user id"
getUser(userId: ID): User
"returns the post object for a post id"
getPost(postId: ID): Post
"returns the chat object for a chat id"
getChat(chatId: ID): ChatRoom
"returns the request object for a request id"
getRequest(requestId: ID): Request
"find a post by the posted date or content"
findPost(first: Int, offset: Int, text: String!, postedDate: String): [Post]
"find a user by user name or handle"
findUser(first: Int, offset: Int, name: String!, handle: String!): [User]
}
type Mutation {
"Upvote/downvote a Post"
vote(postId: ID!, type: [VoteType!]!): Boolean
"Report the post"
report(postId: ID!): Boolean
"Upvote/downvote a Post"
vote(postId: ID!, type: [VoteType!]!): Boolean
"Report the post"
report(postId: ID!): Boolean
"lets you accept a request for a given request id"
acceptRequest(requestId: ID!): Boolean
acceptRequest(requestId: ID!): Boolean
"send a message in a Chatroom"
sendMessage(chatId: ID!, content: String!): Boolean
sendMessage(chatId: ID!, content: String!): Boolean
# TODO: createPost, deletePost, sendRequest, denyRequest
}
"represents a single user account"
type User {
"url for the Profile picture of the User"
profilePicture: String!
"name of the User"
name: String!
"unique identifier name from the User"
handle: String!
"Id of the User"
id: ID!
"the total number of posts the user posted"
numberOfPosts: Int
"returns a given number of posts of a user"
getAllPosts(first: Int=10, offset: Int): [Post]
"creation date of the user account"
joinedDate: String!
"returns chats the user pinned"
pinnedChats: [ChatRoom]
"returns all friends of the user"
friends: [User]
"all request for groupChats/friends/events"
requests: [Request]
"url for the Profile picture of the User"
profilePicture: String!
"name of the User"
name: String!
"unique identifier name from the User"
handle: String!
"Id of the User"
id: ID!
"the total number of posts the user posted"
numberOfPosts: Int
"returns a given number of posts of a user"
getAllPosts(first: Int=10, offset: Int): [Post]
"creation date of the user account"
joinedDate: String!
"returns chats the user pinned"
pinnedChats: [ChatRoom]
"returns all friends of the user"
friends: [User]
"all request for groupChats/friends/events"
requests: [Request]
}
"represents a single user post"
type Post {
"returns the path to the posts picture if it has one"
picture: String
"returns the text of the post"
text: String
"upvotes of the Post"
upvotes: Int!
"downvotes of the Post"
downvotes: Int!
"the user that is the author of the Post"
author: User!
"date the post was created"
creationDate: String!
"returns the type of vote the user performed on the post"
alreadyVoted: VoteType
"returns the tags of the post"
tags: [String]
"returns the path to the posts picture if it has one"
picture: String
"returns the text of the post"
text: String
"upvotes of the Post"
upvotes: Int!
"downvotes of the Post"
downvotes: Int!
"the user that is the author of the Post"
author: User!
"date the post was created"
creationDate: String!
"returns the type of vote the user performed on the post"
userVote: VoteType
"returns the tags of the post"
tags: [String]
}
"represents a request of any type"
type Request {
"id of the request"
id: ID!
"type of the request"
requestType: RequestType!
"id of the request"
id: ID!
"type of the request"
requestType: RequestType!
}
"represents a chatroom"
type ChatRoom {
"the members of the chatroom"
members: [User!]
"return a specfic range of messages posted in the chat"
getMessages(first: Int, offset: Int): [String]
"id of the chat"
id: ID!
"the members of the chatroom"
members: [User!]
"return a specfic range of messages posted in the chat"
getMessages(first: Int, offset: Int): [String]
"id of the chat"
id: ID!
}
"represents the type of vote performed on a post"
enum VoteType {
UPVOTE
DOWNVOTE
UPVOTE
DOWNVOTE
}
"represents the type of request that the user has received"
enum RequestType {
FRIENDREQUEST
GROUPINVITE
EVENTINVITE
FRIENDREQUEST
GROUPINVITE
EVENTINVITE
}

@ -20,7 +20,8 @@ CREATE TABLE IF NOT EXISTS posts (
CREATE TABLE IF NOT EXISTS votes (
user_id SERIAL REFERENCES users (id) ON DELETE CASCADE,
item_id BIGSERIAL REFERENCES posts (id) ON DELETE CASCADE
item_id BIGSERIAL REFERENCES posts (id) ON DELETE CASCADE,
vote_type varchar(8) DEFAULT 1
);
CREATE TABLE IF NOT EXISTS events (

Loading…
Cancel
Save