diff --git a/src/models/partyplaner/PartyPlaner.router.ts b/src/models/partyplaner/PartyPlaner.router.ts index ffabc40..951bd46 100644 --- a/src/models/partyplaner/PartyPlaner.router.ts +++ b/src/models/partyplaner/PartyPlaner.router.ts @@ -2,10 +2,14 @@ * Required External Modules and Interfaces */ import express, {Request, Response} from 'express'; -import {dataRouter} from './data/Data.router'; import {registerRouter} from './register/Register.router'; import logger from '../../middleware/logger'; import {loginRouter} from './login/Login.router'; +import {userRouter} from './user/User.router'; +import {eventRouter} from './event/Event.router'; +import {friendshipRouter} from './friendship/Friendship.router'; +import {inviteRouter} from './invite/Invite.router'; +import {sessionRouter} from './session/Session.router'; /** * Router Definition @@ -13,9 +17,13 @@ import {loginRouter} from './login/Login.router'; export const partyPlanerRouter = express.Router(); // Sub-Endpoints -partyPlanerRouter.use('/data', dataRouter); -partyPlanerRouter.use('/register', registerRouter); +partyPlanerRouter.use('/event', eventRouter); +partyPlanerRouter.use('/friendship', friendshipRouter); +partyPlanerRouter.use('/invite', inviteRouter); partyPlanerRouter.use('/login', loginRouter); +partyPlanerRouter.use('/register', registerRouter); +partyPlanerRouter.use('/session', sessionRouter); +partyPlanerRouter.use('/user', userRouter); partyPlanerRouter.get('/', async (req: Request, res: Response) => { try { diff --git a/src/models/partyplaner/data/Data.router.ts b/src/models/partyplaner/data/Data.router.ts deleted file mode 100644 index 0ec41bf..0000000 --- a/src/models/partyplaner/data/Data.router.ts +++ /dev/null @@ -1,172 +0,0 @@ -/** - * Required External Modules and Interfaces - */ -import express, {Request, Response} from 'express'; -import * as DataService from './data.service'; -import * as UserService from '../userService/user.service'; -import logger from '../../../middleware/logger'; - -/** - * Router Definition - */ -export const dataRouter = express.Router(); - -dataRouter.get('/user/:isDevCall', async (req: Request, res: Response) => { - try { - let userId = (req.query.userId ?? '').toString(); - let sessionId = (req.query.sessionId ?? '').toString(); - let sessionKey = (req.query.sessionKey ?? '').toString(); - let useDev: boolean = (req.params.isDevCall ?? '') === 'dev'; // TBD - - if (userId === '' || sessionId === '' || sessionKey === '') { - res.status(400).send({ - 'status': 'WRONG_PARAMS', - 'message': 'Missing or wrong parameters' - }); - return; - } - - if (!await UserService.checkSession(useDev, userId, sessionId, sessionKey)) { - res.status(403).send({ - 'status': 'INVALID_SESSION', - 'message': 'The user or session could not be found or the session is invalid' - }); - return; - } - - let data = await DataService.getUserData(useDev, userId); - - res.status(200).send(data); - } catch (e) { - logger.error('Error handling a request: ' + e.message); - res.status(500).send({'message': 'Internal Server Error. Try again later.'}); - } -}); - -dataRouter.get('/session/:isDevCall', async (req: Request, res: Response) => { - try { - let userId = (req.query.userId ?? '').toString(); - let sessionId = (req.query.sessionId ?? '').toString(); - let sessionKey = (req.query.sessionKey ?? '').toString(); - let useDev: boolean = (req.params.isDevCall ?? '') === 'dev'; // TBD - - if (userId === '' || sessionId === '' || sessionKey === '') { - res.status(400).send({ - 'status': 'WRONG_PARAMS', - 'message': 'Missing or wrong parameters' - }); - return; - } - - if (!await UserService.checkSession(useDev, userId, sessionId, sessionKey)) { - res.status(403).send({ - 'status': 'INVALID_SESSION', - 'message': 'The user or session could not be found or the session is invalid' - }); - return; - } - - let data = await DataService.getSessionData(useDev, userId); - - res.status(200).send(data); - } catch (e) { - logger.error('Error handling a request: ' + e.message); - res.status(500).send({'message': 'Internal Server Error. Try again later.'}); - } -}); - -dataRouter.get('/friendship/:isDevCall', async (req: Request, res: Response) => { - try { - let userId = (req.query.userId ?? '').toString(); - let sessionId = (req.query.sessionId ?? '').toString(); - let sessionKey = (req.query.sessionKey ?? '').toString(); - let useDev: boolean = (req.params.isDevCall ?? '') === 'dev'; // TBD - - if (userId === '' || sessionId === '' || sessionKey === '') { - res.status(400).send({ - 'status': 'WRONG_PARAMS', - 'message': 'Missing or wrong parameters' - }); - return; - } - - if (!await UserService.checkSession(useDev, userId, sessionId, sessionKey)) { - res.status(403).send({ - 'status': 'INVALID_SESSION', - 'message': 'The user or session could not be found or the session is invalid' - }); - return; - } - - let data = await DataService.getFriendshipData(useDev, userId); - - res.status(200).send(data); - } catch (e) { - logger.error('Error handling a request: ' + e.message); - res.status(500).send({'message': 'Internal Server Error. Try again later.'}); - } -}); - -dataRouter.get('/event/:isDevCall', async (req: Request, res: Response) => { - try { - let userId = (req.query.userId ?? '').toString(); - let sessionId = (req.query.sessionId ?? '').toString(); - let sessionKey = (req.query.sessionKey ?? '').toString(); - let useDev: boolean = (req.params.isDevCall ?? '') === 'dev'; // TBD - - if (userId === '' || sessionId === '' || sessionKey === '') { - res.status(400).send({ - 'status': 'WRONG_PARAMS', - 'message': 'Missing or wrong parameters' - }); - return; - } - - if (!await UserService.checkSession(useDev, userId, sessionId, sessionKey)) { - res.status(403).send({ - 'status': 'INVALID_SESSION', - 'message': 'The user or session could not be found or the session is invalid' - }); - return; - } - - let data = await DataService.getEventData(useDev, userId); - - res.status(200).send(data); - } catch (e) { - logger.error('Error handling a request: ' + e.message); - res.status(500).send({'message': 'Internal Server Error. Try again later.'}); - } -}); - -dataRouter.get('/invite/:isDevCall', async (req: Request, res: Response) => { - try { - let userId = (req.query.userId ?? '').toString(); - let sessionId = (req.query.sessionId ?? '').toString(); - let sessionKey = (req.query.sessionKey ?? '').toString(); - let useDev: boolean = (req.params.isDevCall ?? '') === 'dev'; // TBD - - if (userId === '' || sessionId === '' || sessionKey === '') { - res.status(400).send({ - 'status': 'WRONG_PARAMS', - 'message': 'Missing or wrong parameters' - }); - return; - } - - if (!await UserService.checkSession(useDev, userId, sessionId, sessionKey)) { - res.status(403).send({ - 'status': 'INVALID_SESSION', - 'message': 'The user or session could not be found or the session is invalid' - }); - return; - } - - let data = await DataService.getInvitesData(useDev, userId); - - res.status(200).send(data); - } catch (e) { - logger.error('Error handling a request: ' + e.message); - res.status(500).send({'message': 'Internal Server Error. Try again later.'}); - } -}); diff --git a/src/models/partyplaner/data/data.service.ts b/src/models/partyplaner/data/data.service.ts deleted file mode 100644 index 3c1962c..0000000 --- a/src/models/partyplaner/data/data.service.ts +++ /dev/null @@ -1,349 +0,0 @@ -import * as dotenv from 'dotenv'; - -dotenv.config(); - -const mariadb = require('mariadb'); -const prod_pool = mariadb.createPool({ - host: process.env.DB_HOST, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: process.env.PARTYPLANER_PROD_DATABASE, - connectionLimit: 5 -}); -const dev_pool = mariadb.createPool({ - host: process.env.DB_HOST, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: process.env.PARTYPLANER_DEV_DATABASE, - connectionLimit: 5 -}); - -/** - * Used in the getUserData method as return value - */ -export interface UserData { - username: string; - email: string; - firstName: string; - lastName: string; - lastLogin: string; - emailIsVerified: string; - isPremiumUser: string; -} - -/** - * Used in the getSessionData method as return value - */ -export interface SessionData { - sessionId: string; - type: string; - lastLogin: string; - lastIp: string; -} - -/** - * Used in the getFriendshipData method as a return value - */ -export interface Friendship { - friendshipId: string; - friendId: string; - friendFirstName: string; - friendLastName: string; - friendUsername: string; -} - -/** - * Used in the getEventData method - */ -export interface Invite { - inviteId: string; - inviteKey: string; - validUntil: Date; - alreadyUsed: boolean; - invitedPersonName: string; -} - -/** - * Used in the getEventData method - */ -export interface Registration { - registrationId: string; - name: string; - registeredDate: Date; - takesPart: boolean; - comment: string; -} - -/** - * Used in the getEventData method as a return value - */ -export interface Event { - eventId: string; - name: string; - description: string; - takesPlaceDate: Date; - registrationUntilDate: Date; - maxParticipants: number; - invites: Invite[]; - registrations: Registration[]; -} - -/** - * Used in the getInvitesData method as a return value - */ -export interface ReceivedInvite { - inviteId: string; - validUntil: Date; - alreadyUsed: boolean; - inviteKey: string; - eventName: string; - eventDescription: string; - takesPlaceDate: Date; - registrationUntilDate: Date; - maxParticipants: number; - eventCreatorId: string; - creatorFirstName: string; - creatorLastName: string; -} - -/** - * Returns all data about the given user - * @param useDev If the dev or prod database should be used - * @param userId The userId of the user to return the data for - * @return UserData An object containing the user data - */ -export const getUserData = async (useDev: boolean, userId: string): Promise => { - let conn; - try { - if (useDev) { - conn = await dev_pool.getConnection(); - } else { - conn = await prod_pool.getConnection(); - } - - let rows = await conn.query('SELECT username, email, first_name, last_Name, last_login, email_is_verified, is_premium_user FROM users WHERE user_id = ?', userId); - - let user: UserData = {} as UserData; - - for (let row of rows) { - user = { - username: row.username, - email: row.email, - firstName: row.first_name, - lastName: row.last_name, - lastLogin: row.last_login, - emailIsVerified: row.email_is_verified, - isPremiumUser: row.is_premium_user - }; - } - - return user; - } catch (err) { - throw err; - } finally { - if (conn) { - conn.end(); - } - } -}; - -/** - * Returns all active sessions of the given user - * @param useDev If the dev or prod database should be used - * @param userId The userId of the user to return the sessions for - * @return SessionData[] A list containing objects with the session data - */ -export const getSessionData = async (useDev: boolean, userId: string): Promise => { - let conn; - try { - if (useDev) { - conn = await dev_pool.getConnection(); - } else { - conn = await prod_pool.getConnection(); - } - - let rows = await conn.query('SELECT session_id, type, last_login, last_ip FROM sessions WHERE user_id = ? AND valid_until > NOW()', userId); - - let sessions: SessionData[] = []; - - for (let row of rows) { - sessions.push({ - sessionId: row.session_id, - type: row.type, - lastLogin: row.last_login, - lastIp: row.last_ip - }); - } - - return sessions; - } catch (err) { - throw err; - } finally { - if (conn) { - conn.end(); - } - } -}; - -/** - * Returns all friends of the given user - * @param useDev If the dev or prod database should be used - * @param userId The userId of the user to fetch the friends for - * @return Friendship[] A list of friends - */ -export const getFriendshipData = async (useDev: boolean, userId: string): Promise => { - let conn; - try { - if (useDev) { - conn = await dev_pool.getConnection(); - } else { - conn = await prod_pool.getConnection(); - } - - let rows = await conn.query('SELECT f.friendship_id, f.friend_id, u.first_name as friend_first_name, u.last_name as friend_last_name, u.username as friend_username FROM friendships f LEFT OUTER JOIN users u ON f.friend_id = u.user_id WHERE f.user_id = ?', userId); - - let friends: Friendship[] = []; - - for (let row of rows) { - friends.push({ - friendshipId: row.friendship_id, - friendId: row.friend_id, - friendFirstName: row.friend_first_name, - friendLastName: row.friend_last_name, - friendUsername: row.friend_username - }); - } - - return friends; - } catch (err) { - throw err; - } finally { - if (conn) { - conn.end(); - } - } -}; - -/** - * Returns all events of the given user - * @param useDev If the dev or prod database should be used - * @param userId The userId of the user to fetch the friends for - * @return Event[] A list of events - */ -export const getEventData = async (useDev: boolean, userId: string): Promise => { - let conn; - try { - if (useDev) { - conn = await dev_pool.getConnection(); - } else { - conn = await prod_pool.getConnection(); - } - - let eventRows = await conn.query('SELECT event_id, name, description, takes_place_date, registration_until_date, max_participants FROM events WHERE creator_id = ?', userId); - - let eventsMap = new Map(); - let eventIds: string[] = []; - - for (let row of eventRows) { - eventIds.push(row.event_id); - let event = { - eventId: row.event_id, - name: row.name, - description: row.description, - takesPlaceDate: row.takes_place_date, - registrationUntilDate: row.registration_until_date, - maxParticipants: row.max_participants, - invites: [], - registrations: [] - }; - eventsMap.set(row.event_id, event); - } - - let registrationRows = await conn.query('SELECT registration_id, name, registered_date, takes_part, comment, event_id FROM event_registration WHERE event_id IN (?)', eventIds); - - for (let row of registrationRows) { - let event = eventsMap.get(row.event_id); - if (!event) continue; - event.registrations.push({ - registrationId: row.registration_id, - name: row.name, - registeredDate: row.registered_date, - takesPart: row.takes_part, - comment: row.comment - }); - } - - let inviteRows = await conn.query('SELECT invite_id, invite_key, valid_until, already_used, invited_person_name, event_id FROM invitations WHERE event_id IN (?)', eventIds); - - for (let row of inviteRows) { - let event = eventsMap.get(row.event_id); - if (!event) continue; - event.invites.push({ - inviteId: row.invite_id, - inviteKey: row.invite_key, - validUntil: row.valid_until, - alreadyUsed: row.already_used, - invitedPersonName: row.invited_person_name - }); - } - - let eventsList: Event[] = []; - for (let event of eventsMap.values()) { - eventsList.push(event); - } - - return eventsList; - } catch (err) { - throw err; - } finally { - if (conn) { - conn.end(); - } - } -}; - -/** - * Returns all events the user is invited to - * @param useDev If the dev or prod database should be used - * @param userId The userId of the user to fetch the friends for - * @return ReceivedInvite[] A list of invites - */ -export const getInvitesData = async (useDev: boolean, userId: string): Promise => { - let conn; - try { - if (useDev) { - conn = await dev_pool.getConnection(); - } else { - conn = await prod_pool.getConnection(); - } - - let rows = await conn.query('SELECT i.invite_id, i.valid_until, i.already_used, i.invite_key, e.name as event_name, e.description as event_description, e.takes_place_date, e.registration_until_date, e.max_participants, e.creator_id, u.first_name, u.last_name FROM invitations i LEFT OUTER JOIN events e ON e.event_id = i.event_id LEFT OUTER JOIN users u ON u.user_id = e.creator_id WHERE i.user_id = ?', userId); - - let invites: ReceivedInvite[] = []; - - for (let row of rows) { - invites.push({ - inviteId: row.invite_id, - validUntil: row.valid_until, - alreadyUsed: row.already_used, - inviteKey: row.invite_key, - eventName: row.event_name, - eventDescription: row.event_description, - takesPlaceDate: row.takes_place_date, - registrationUntilDate: row.registration_until_date, - maxParticipants: row.max_participants, - eventCreatorId: row.creator_id, - creatorFirstName: row.first_name, - creatorLastName: row.last_name - }); - } - - return invites; - } catch (err) { - throw err; - } finally { - if (conn) { - conn.end(); - } - } -}; diff --git a/src/models/partyplaner/event/Event.interface.ts b/src/models/partyplaner/event/Event.interface.ts new file mode 100644 index 0000000..14c3a7d --- /dev/null +++ b/src/models/partyplaner/event/Event.interface.ts @@ -0,0 +1,16 @@ +import {Invite} from './Invite.interface'; +import {Registration} from './Registration.interface'; + +/** + * Used in the getEventData method as a return value + */ +export interface Event { + eventId: string; + name: string; + description: string; + takesPlaceDate: Date; + registrationUntilDate: Date; + maxParticipants: number; + invites: Invite[]; + registrations: Registration[]; +} diff --git a/src/models/partyplaner/event/Event.router.ts b/src/models/partyplaner/event/Event.router.ts new file mode 100644 index 0000000..e3dd304 --- /dev/null +++ b/src/models/partyplaner/event/Event.router.ts @@ -0,0 +1,44 @@ +/** + * Required External Modules and Interfaces + */ +import express, {Request, Response} from 'express'; +import * as EventService from './event.service'; +import * as UserService from '../user/user.service'; +import logger from '../../../middleware/logger'; + +/** + * Router Definition + */ +export const eventRouter = express.Router(); + +eventRouter.get('/:isDevCall', async (req: Request, res: Response) => { + try { + let userId = (req.query.userId ?? '').toString(); + let sessionId = (req.query.sessionId ?? '').toString(); + let sessionKey = (req.query.sessionKey ?? '').toString(); + let useDev: boolean = (req.params.isDevCall ?? '') === 'dev'; // TBD + + if (userId === '' || sessionId === '' || sessionKey === '') { + res.status(400).send({ + 'status': 'WRONG_PARAMS', + 'message': 'Missing or wrong parameters' + }); + return; + } + + if (!await UserService.checkSession(useDev, userId, sessionId, sessionKey)) { + res.status(403).send({ + 'status': 'INVALID_SESSION', + 'message': 'The user or session could not be found or the session is invalid' + }); + return; + } + + let data = await EventService.getEventData(useDev, userId); + + res.status(200).send(data); + } catch (e) { + logger.error('Error handling a request: ' + e.message); + res.status(500).send({'message': 'Internal Server Error. Try again later.'}); + } +}); diff --git a/src/models/partyplaner/event/Invite.interface.ts b/src/models/partyplaner/event/Invite.interface.ts new file mode 100644 index 0000000..e4ecd8c --- /dev/null +++ b/src/models/partyplaner/event/Invite.interface.ts @@ -0,0 +1,10 @@ +/** + * Used in the getEventData method + */ +export interface Invite { + inviteId: string; + inviteKey: string; + validUntil: Date; + alreadyUsed: boolean; + invitedPersonName: string; +} diff --git a/src/models/partyplaner/event/Registration.interface.ts b/src/models/partyplaner/event/Registration.interface.ts new file mode 100644 index 0000000..207b40e --- /dev/null +++ b/src/models/partyplaner/event/Registration.interface.ts @@ -0,0 +1,10 @@ +/** + * Used in the getEventData method + */ +export interface Registration { + registrationId: string; + name: string; + registeredDate: Date; + takesPart: boolean; + comment: string; +} diff --git a/src/models/partyplaner/event/event.service.ts b/src/models/partyplaner/event/event.service.ts new file mode 100644 index 0000000..a32f31f --- /dev/null +++ b/src/models/partyplaner/event/event.service.ts @@ -0,0 +1,98 @@ +import * as dotenv from 'dotenv'; +import {Event} from './event.interface'; + +dotenv.config(); + +const mariadb = require('mariadb'); +const prod_pool = mariadb.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.PARTYPLANER_PROD_DATABASE, + connectionLimit: 5 +}); +const dev_pool = mariadb.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.PARTYPLANER_DEV_DATABASE, + connectionLimit: 5 +}); + +/** + * Returns all events of the given user + * @param useDev If the dev or prod database should be used + * @param userId The userId of the user to fetch the friends for + * @return Event[] A list of events + */ +export const getEventData = async (useDev: boolean, userId: string): Promise => { + let conn; + try { + if (useDev) { + conn = await dev_pool.getConnection(); + } else { + conn = await prod_pool.getConnection(); + } + + let eventRows = await conn.query('SELECT event_id, name, description, takes_place_date, registration_until_date, max_participants FROM events WHERE creator_id = ?', userId); + + let eventsMap = new Map(); + let eventIds: string[] = []; + + for (let row of eventRows) { + eventIds.push(row.event_id); + let event = { + eventId: row.event_id, + name: row.name, + description: row.description, + takesPlaceDate: row.takes_place_date, + registrationUntilDate: row.registration_until_date, + maxParticipants: row.max_participants, + invites: [], + registrations: [] + }; + eventsMap.set(row.event_id, event); + } + + let registrationRows = await conn.query('SELECT registration_id, name, registered_date, takes_part, comment, event_id FROM event_registration WHERE event_id IN (?)', eventIds); + + for (let row of registrationRows) { + let event = eventsMap.get(row.event_id); + if (!event) continue; + event.registrations.push({ + registrationId: row.registration_id, + name: row.name, + registeredDate: row.registered_date, + takesPart: row.takes_part, + comment: row.comment + }); + } + + let inviteRows = await conn.query('SELECT invite_id, invite_key, valid_until, already_used, invited_person_name, event_id FROM invitations WHERE event_id IN (?)', eventIds); + + for (let row of inviteRows) { + let event = eventsMap.get(row.event_id); + if (!event) continue; + event.invites.push({ + inviteId: row.invite_id, + inviteKey: row.invite_key, + validUntil: row.valid_until, + alreadyUsed: row.already_used, + invitedPersonName: row.invited_person_name + }); + } + + let eventsList: Event[] = []; + for (let event of eventsMap.values()) { + eventsList.push(event); + } + + return eventsList; + } catch (err) { + throw err; + } finally { + if (conn) { + conn.end(); + } + } +}; diff --git a/src/models/partyplaner/friendship/Friendship.interface.ts b/src/models/partyplaner/friendship/Friendship.interface.ts new file mode 100644 index 0000000..5d4e6ca --- /dev/null +++ b/src/models/partyplaner/friendship/Friendship.interface.ts @@ -0,0 +1,10 @@ +/** + * Used in the getFriendshipData method as a return value + */ +export interface Friendship { + friendshipId: string; + friendId: string; + friendFirstName: string; + friendLastName: string; + friendUsername: string; +} diff --git a/src/models/partyplaner/friendship/Friendship.router.ts b/src/models/partyplaner/friendship/Friendship.router.ts new file mode 100644 index 0000000..e172418 --- /dev/null +++ b/src/models/partyplaner/friendship/Friendship.router.ts @@ -0,0 +1,44 @@ +/** + * Required External Modules and Interfaces + */ +import express, {Request, Response} from 'express'; +import * as FriendshipService from './friendship.service'; +import * as UserService from '../user/user.service'; +import logger from '../../../middleware/logger'; + +/** + * Router Definition + */ +export const friendshipRouter = express.Router(); + +friendshipRouter.get('/:isDevCall', async (req: Request, res: Response) => { + try { + let userId = (req.query.userId ?? '').toString(); + let sessionId = (req.query.sessionId ?? '').toString(); + let sessionKey = (req.query.sessionKey ?? '').toString(); + let useDev: boolean = (req.params.isDevCall ?? '') === 'dev'; // TBD + + if (userId === '' || sessionId === '' || sessionKey === '') { + res.status(400).send({ + 'status': 'WRONG_PARAMS', + 'message': 'Missing or wrong parameters' + }); + return; + } + + if (!await UserService.checkSession(useDev, userId, sessionId, sessionKey)) { + res.status(403).send({ + 'status': 'INVALID_SESSION', + 'message': 'The user or session could not be found or the session is invalid' + }); + return; + } + + let data = await FriendshipService.getFriendshipData(useDev, userId); + + res.status(200).send(data); + } catch (e) { + logger.error('Error handling a request: ' + e.message); + res.status(500).send({'message': 'Internal Server Error. Try again later.'}); + } +}); diff --git a/src/models/partyplaner/friendship/friendship.service.ts b/src/models/partyplaner/friendship/friendship.service.ts new file mode 100644 index 0000000..9a2a8fe --- /dev/null +++ b/src/models/partyplaner/friendship/friendship.service.ts @@ -0,0 +1,59 @@ +import * as dotenv from 'dotenv'; +import {Friendship} from './Friendship.interface'; + +dotenv.config(); + +const mariadb = require('mariadb'); +const prod_pool = mariadb.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.PARTYPLANER_PROD_DATABASE, + connectionLimit: 5 +}); +const dev_pool = mariadb.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.PARTYPLANER_DEV_DATABASE, + connectionLimit: 5 +}); + +/** + * Returns all friends of the given user + * @param useDev If the dev or prod database should be used + * @param userId The userId of the user to fetch the friends for + * @return Friendship[] A list of friends + */ +export const getFriendshipData = async (useDev: boolean, userId: string): Promise => { + let conn; + try { + if (useDev) { + conn = await dev_pool.getConnection(); + } else { + conn = await prod_pool.getConnection(); + } + + let rows = await conn.query('SELECT f.friendship_id, f.friend_id, u.first_name as friend_first_name, u.last_name as friend_last_name, u.username as friend_username FROM friendships f LEFT OUTER JOIN users u ON f.friend_id = u.user_id WHERE f.user_id = ?', userId); + + let friends: Friendship[] = []; + + for (let row of rows) { + friends.push({ + friendshipId: row.friendship_id, + friendId: row.friend_id, + friendFirstName: row.friend_first_name, + friendLastName: row.friend_last_name, + friendUsername: row.friend_username + }); + } + + return friends; + } catch (err) { + throw err; + } finally { + if (conn) { + conn.end(); + } + } +}; diff --git a/src/models/partyplaner/invite/Invite.router.ts b/src/models/partyplaner/invite/Invite.router.ts new file mode 100644 index 0000000..e006f80 --- /dev/null +++ b/src/models/partyplaner/invite/Invite.router.ts @@ -0,0 +1,44 @@ +/** + * Required External Modules and Interfaces + */ +import express, {Request, Response} from 'express'; +import * as InviteService from './invite.service'; +import * as UserService from '../user/user.service'; +import logger from '../../../middleware/logger'; + +/** + * Router Definition + */ +export const inviteRouter = express.Router(); + +inviteRouter.get('/:isDevCall', async (req: Request, res: Response) => { + try { + let userId = (req.query.userId ?? '').toString(); + let sessionId = (req.query.sessionId ?? '').toString(); + let sessionKey = (req.query.sessionKey ?? '').toString(); + let useDev: boolean = (req.params.isDevCall ?? '') === 'dev'; // TBD + + if (userId === '' || sessionId === '' || sessionKey === '') { + res.status(400).send({ + 'status': 'WRONG_PARAMS', + 'message': 'Missing or wrong parameters' + }); + return; + } + + if (!await UserService.checkSession(useDev, userId, sessionId, sessionKey)) { + res.status(403).send({ + 'status': 'INVALID_SESSION', + 'message': 'The user or session could not be found or the session is invalid' + }); + return; + } + + let data = await InviteService.getInvitesData(useDev, userId); + + res.status(200).send(data); + } catch (e) { + logger.error('Error handling a request: ' + e.message); + res.status(500).send({'message': 'Internal Server Error. Try again later.'}); + } +}); diff --git a/src/models/partyplaner/invite/ReceivedInvite.interface.ts b/src/models/partyplaner/invite/ReceivedInvite.interface.ts new file mode 100644 index 0000000..322ce68 --- /dev/null +++ b/src/models/partyplaner/invite/ReceivedInvite.interface.ts @@ -0,0 +1,17 @@ +/** + * Used in the getInvitesData method as a return value + */ +export interface ReceivedInvite { + inviteId: string; + validUntil: Date; + alreadyUsed: boolean; + inviteKey: string; + eventName: string; + eventDescription: string; + takesPlaceDate: Date; + registrationUntilDate: Date; + maxParticipants: number; + eventCreatorId: string; + creatorFirstName: string; + creatorLastName: string; +} diff --git a/src/models/partyplaner/invite/invite.service.ts b/src/models/partyplaner/invite/invite.service.ts new file mode 100644 index 0000000..c7934bf --- /dev/null +++ b/src/models/partyplaner/invite/invite.service.ts @@ -0,0 +1,66 @@ +import * as dotenv from 'dotenv'; +import {ReceivedInvite} from './ReceivedInvite.interface'; + +dotenv.config(); + +const mariadb = require('mariadb'); +const prod_pool = mariadb.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.PARTYPLANER_PROD_DATABASE, + connectionLimit: 5 +}); +const dev_pool = mariadb.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.PARTYPLANER_DEV_DATABASE, + connectionLimit: 5 +}); + +/** + * Returns all events the user is invited to + * @param useDev If the dev or prod database should be used + * @param userId The userId of the user to fetch the friends for + * @return ReceivedInvite[] A list of invites + */ +export const getInvitesData = async (useDev: boolean, userId: string): Promise => { + let conn; + try { + if (useDev) { + conn = await dev_pool.getConnection(); + } else { + conn = await prod_pool.getConnection(); + } + + let rows = await conn.query('SELECT i.invite_id, i.valid_until, i.already_used, i.invite_key, e.name as event_name, e.description as event_description, e.takes_place_date, e.registration_until_date, e.max_participants, e.creator_id, u.first_name, u.last_name FROM invitations i LEFT OUTER JOIN events e ON e.event_id = i.event_id LEFT OUTER JOIN users u ON u.user_id = e.creator_id WHERE i.user_id = ?', userId); + + let invites: ReceivedInvite[] = []; + + for (let row of rows) { + invites.push({ + inviteId: row.invite_id, + validUntil: row.valid_until, + alreadyUsed: row.already_used, + inviteKey: row.invite_key, + eventName: row.event_name, + eventDescription: row.event_description, + takesPlaceDate: row.takes_place_date, + registrationUntilDate: row.registration_until_date, + maxParticipants: row.max_participants, + eventCreatorId: row.creator_id, + creatorFirstName: row.first_name, + creatorLastName: row.last_name + }); + } + + return invites; + } catch (err) { + throw err; + } finally { + if (conn) { + conn.end(); + } + } +}; diff --git a/src/models/partyplaner/login/Login.router.ts b/src/models/partyplaner/login/Login.router.ts index 191127a..46537d0 100644 --- a/src/models/partyplaner/login/Login.router.ts +++ b/src/models/partyplaner/login/Login.router.ts @@ -2,7 +2,7 @@ * Required External Modules and Interfaces */ import express, {Request, Response} from 'express'; -import * as UserService from '../userService/user.service'; +import * as UserService from '../user/user.service'; import logger from '../../../middleware/logger'; /** diff --git a/src/models/partyplaner/register/Register.router.ts b/src/models/partyplaner/register/Register.router.ts index 25ddd21..786c1c1 100644 --- a/src/models/partyplaner/register/Register.router.ts +++ b/src/models/partyplaner/register/Register.router.ts @@ -2,7 +2,7 @@ * Required External Modules and Interfaces */ import express, {Request, Response} from 'express'; -import * as UserService from '../userService/user.service'; +import * as UserService from '../user/user.service'; import logger from '../../../middleware/logger'; /** diff --git a/src/models/partyplaner/session/Session.router.ts b/src/models/partyplaner/session/Session.router.ts new file mode 100644 index 0000000..73dd3cb --- /dev/null +++ b/src/models/partyplaner/session/Session.router.ts @@ -0,0 +1,44 @@ +/** + * Required External Modules and Interfaces + */ +import express, {Request, Response} from 'express'; +import * as SessionService from './session.service'; +import * as UserService from '../user/user.service'; +import logger from '../../../middleware/logger'; + +/** + * Router Definition + */ +export const sessionRouter = express.Router(); + +sessionRouter.get('/:isDevCall', async (req: Request, res: Response) => { + try { + let userId = (req.query.userId ?? '').toString(); + let sessionId = (req.query.sessionId ?? '').toString(); + let sessionKey = (req.query.sessionKey ?? '').toString(); + let useDev: boolean = (req.params.isDevCall ?? '') === 'dev'; // TBD + + if (userId === '' || sessionId === '' || sessionKey === '') { + res.status(400).send({ + 'status': 'WRONG_PARAMS', + 'message': 'Missing or wrong parameters' + }); + return; + } + + if (!await UserService.checkSession(useDev, userId, sessionId, sessionKey)) { + res.status(403).send({ + 'status': 'INVALID_SESSION', + 'message': 'The user or session could not be found or the session is invalid' + }); + return; + } + + let data = await SessionService.getSessionData(useDev, userId); + + res.status(200).send(data); + } catch (e) { + logger.error('Error handling a request: ' + e.message); + res.status(500).send({'message': 'Internal Server Error. Try again later.'}); + } +}); diff --git a/src/models/partyplaner/session/SessionData.interface.ts b/src/models/partyplaner/session/SessionData.interface.ts new file mode 100644 index 0000000..8c8cbd2 --- /dev/null +++ b/src/models/partyplaner/session/SessionData.interface.ts @@ -0,0 +1,9 @@ +/** + * Used in the getSessionData method as return value + */ +export interface SessionData { + sessionId: string; + type: string; + lastLogin: string; + lastIp: string; +} diff --git a/src/models/partyplaner/session/session.service.ts b/src/models/partyplaner/session/session.service.ts new file mode 100644 index 0000000..327e270 --- /dev/null +++ b/src/models/partyplaner/session/session.service.ts @@ -0,0 +1,58 @@ +import * as dotenv from 'dotenv'; +import {SessionData} from './SessionData.interface'; + +dotenv.config(); + +const mariadb = require('mariadb'); +const prod_pool = mariadb.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.PARTYPLANER_PROD_DATABASE, + connectionLimit: 5 +}); +const dev_pool = mariadb.createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.PARTYPLANER_DEV_DATABASE, + connectionLimit: 5 +}); + +/** + * Returns all active sessions of the given user + * @param useDev If the dev or prod database should be used + * @param userId The userId of the user to return the sessions for + * @return SessionData[] A list containing objects with the session data + */ +export const getSessionData = async (useDev: boolean, userId: string): Promise => { + let conn; + try { + if (useDev) { + conn = await dev_pool.getConnection(); + } else { + conn = await prod_pool.getConnection(); + } + + let rows = await conn.query('SELECT session_id, type, last_login, last_ip FROM sessions WHERE user_id = ? AND valid_until > NOW()', userId); + + let sessions: SessionData[] = []; + + for (let row of rows) { + sessions.push({ + sessionId: row.session_id, + type: row.type, + lastLogin: row.last_login, + lastIp: row.last_ip + }); + } + + return sessions; + } catch (err) { + throw err; + } finally { + if (conn) { + conn.end(); + } + } +}; diff --git a/src/models/partyplaner/user/Session.interface.ts b/src/models/partyplaner/user/Session.interface.ts new file mode 100644 index 0000000..048c6ec --- /dev/null +++ b/src/models/partyplaner/user/Session.interface.ts @@ -0,0 +1,8 @@ +/** + * Used in the registerUser and loginUser methods as return value + */ +export interface Session { + userId: string; + sessionId: string; + sessionKey: string; +} diff --git a/src/models/partyplaner/user/Status.interface.ts b/src/models/partyplaner/user/Status.interface.ts new file mode 100644 index 0000000..8b0e3f8 --- /dev/null +++ b/src/models/partyplaner/user/Status.interface.ts @@ -0,0 +1,8 @@ +/** + * Used in the checkUsernameAndEmail method as return value + */ +export interface Status { + hasProblems: boolean; + messages: string[]; + status: string[]; +} diff --git a/src/models/partyplaner/user/User.router.ts b/src/models/partyplaner/user/User.router.ts new file mode 100644 index 0000000..c7173e0 --- /dev/null +++ b/src/models/partyplaner/user/User.router.ts @@ -0,0 +1,43 @@ +/** + * Required External Modules and Interfaces + */ +import express, {Request, Response} from 'express'; +import * as UserService from './user.service'; +import logger from '../../../middleware/logger'; + +/** + * Router Definition + */ +export const userRouter = express.Router(); + +userRouter.get('/:isDevCall', async (req: Request, res: Response) => { + try { + let userId = (req.query.userId ?? '').toString(); + let sessionId = (req.query.sessionId ?? '').toString(); + let sessionKey = (req.query.sessionKey ?? '').toString(); + let useDev: boolean = (req.params.isDevCall ?? '') === 'dev'; // TBD + + if (userId === '' || sessionId === '' || sessionKey === '') { + res.status(400).send({ + 'status': 'WRONG_PARAMS', + 'message': 'Missing or wrong parameters' + }); + return; + } + + if (!await UserService.checkSession(useDev, userId, sessionId, sessionKey)) { + res.status(403).send({ + 'status': 'INVALID_SESSION', + 'message': 'The user or session could not be found or the session is invalid' + }); + return; + } + + let data = await UserService.getUserData(useDev, userId); + + res.status(200).send(data); + } catch (e) { + logger.error('Error handling a request: ' + e.message); + res.status(500).send({'message': 'Internal Server Error. Try again later.'}); + } +}); diff --git a/src/models/partyplaner/user/UserData.interface.ts b/src/models/partyplaner/user/UserData.interface.ts new file mode 100644 index 0000000..9c8b27c --- /dev/null +++ b/src/models/partyplaner/user/UserData.interface.ts @@ -0,0 +1,12 @@ +/** + * Used in the getUserData method as return value + */ +export interface UserData { + username: string; + email: string; + firstName: string; + lastName: string; + lastLogin: string; + emailIsVerified: string; + isPremiumUser: string; +} diff --git a/src/models/partyplaner/userService/user.service.ts b/src/models/partyplaner/user/user.service.ts similarity index 88% rename from src/models/partyplaner/userService/user.service.ts rename to src/models/partyplaner/user/user.service.ts index c31d09c..55f2236 100644 --- a/src/models/partyplaner/userService/user.service.ts +++ b/src/models/partyplaner/user/user.service.ts @@ -1,6 +1,9 @@ import * as dotenv from 'dotenv'; import * as bcrypt from 'bcrypt'; import {Guid} from 'guid-typescript'; +import {UserData} from './UserData.interface'; +import {Session} from './Session.interface'; +import {Status} from './Status.interface'; dotenv.config(); @@ -21,22 +24,45 @@ const dev_pool = mariadb.createPool({ }); /** - * Used in the registerUser and loginUser methods as return value + * Returns all data about the given user + * @param useDev If the dev or prod database should be used + * @param userId The userId of the user to return the data for + * @return UserData An object containing the user data */ -export interface Session { - userId: string; - sessionId: string; - sessionKey: string; -} +export const getUserData = async (useDev: boolean, userId: string): Promise => { + let conn; + try { + if (useDev) { + conn = await dev_pool.getConnection(); + } else { + conn = await prod_pool.getConnection(); + } -/** - * Used in the checkUsernameAndEmail method as return value - */ -export interface Status { - hasProblems: boolean; - messages: string[]; - status: string[]; -} + let rows = await conn.query('SELECT username, email, first_name, last_Name, last_login, email_is_verified, is_premium_user FROM users WHERE user_id = ?', userId); + + let user: UserData = {} as UserData; + + for (let row of rows) { + user = { + username: row.username, + email: row.email, + firstName: row.first_name, + lastName: row.last_name, + lastLogin: row.last_login, + emailIsVerified: row.email_is_verified, + isPremiumUser: row.is_premium_user + }; + } + + return user; + } catch (err) { + throw err; + } finally { + if (conn) { + conn.end(); + } + } +}; /** * Fetches all usernames and emails from the database and returns them in an object