diff --git a/backend-services/friend-service/.gitignore b/backend-services/friend-service/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..6a7d6d8ef6a9e8c5a09da8ab3584a96b189d5260 --- /dev/null +++ b/backend-services/friend-service/.gitignore @@ -0,0 +1,130 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* \ No newline at end of file diff --git a/backend-services/friend-service/Dockerfile b/backend-services/friend-service/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..01857fe963326120b00df52bb2da47e9aeb93149 --- /dev/null +++ b/backend-services/friend-service/Dockerfile @@ -0,0 +1,14 @@ +FROM node:latest as base + +# Create app directory +WORKDIR /friend-service/app + +COPY package*.json ./ +RUN npm install + +# Bundle app source +COPY . . + +EXPOSE 9000 + +CMD [ "npm", "run", "start:dev" ] \ No newline at end of file diff --git a/backend-services/friend-service/config.ts b/backend-services/friend-service/config.ts new file mode 100644 index 0000000000000000000000000000000000000000..ecc626d212477add7a2710e71cc5736f5197322e --- /dev/null +++ b/backend-services/friend-service/config.ts @@ -0,0 +1,3 @@ +export default { + JWT_SECRET: "" +} diff --git a/backend-services/friend-service/index.ts b/backend-services/friend-service/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..f2a430088ea0145d98e2536610217c2abb9e9d2c --- /dev/null +++ b/backend-services/friend-service/index.ts @@ -0,0 +1,23 @@ +import express, { Application } from 'express' +import { initializeRoutes } from './src/Startup/routes' +import { MongoConnectionProvider } from './src/Database/MongoConnectionProvider' +import jwt from 'jsonwebtoken' + +// Server configuration +const server:Application = express(); + +// InitaliseRoutes +initializeRoutes(server) + +// Database configuration +export const MongoClient = new MongoConnectionProvider(process.env.MONGO_DBNAME as string, process.env.MONGO_HOST as string, Number(process.env.MONGO_PORT as string)) +MongoClient.Connect() + +// MongoClient.Connection.dropDatabase() +console.log(jwt.sign('a', "abcdefg12345")) +console.log(jwt.sign('b', "abcdefg12345")) +console.log(jwt.sign('c', "abcdefg12345")) + +server.listen(9000, ():void => { + console.log('Service: Running here 👉 https://localhost:9000') +}) \ No newline at end of file diff --git a/backend-services/friend-service/package.json b/backend-services/friend-service/package.json new file mode 100644 index 0000000000000000000000000000000000000000..8b54eab2863a8410473ec8c3972aa59c7c452573 --- /dev/null +++ b/backend-services/friend-service/package.json @@ -0,0 +1,25 @@ +{ + "name": "friend-service", + "version": "1.0.0", + "description": "", + "main": "index.ts", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "npm run build && node app.ts", + "start:dev": "nodemon" + }, + "author": "", + "license": "ISC", + "dependencies": { + "express": "^4.18.2", + "jsonwebtoken": "^9.0.0", + "mongoose": "^7.0.3", + "typescript": "^5.0.4" + }, + "devDependencies": { + "@types/express": "^4.17.17", + "@types/jsonwebtoken": "^9.0.1", + "nodemon": "^2.0.22", + "ts-node": "^10.9.1" + } +} diff --git a/backend-services/friend-service/src/Database/MongoConnectionProvider.ts b/backend-services/friend-service/src/Database/MongoConnectionProvider.ts new file mode 100644 index 0000000000000000000000000000000000000000..202f97911ffcf1d3670da03c273df24fc5071a74 --- /dev/null +++ b/backend-services/friend-service/src/Database/MongoConnectionProvider.ts @@ -0,0 +1,60 @@ +import mongoose from "mongoose"; + +/** + * Useful utilities for connection to a mongo database + */ +export class MongoConnectionProvider { + + /** + * Mongo db name + */ + public DatabaseName: string; + + /** + * Mongo db path + */ + public DatabasePath: string; + + /** + * Mongo db port + */ + public DatabasePort: number; + + /** + * Mongo db connection + */ + public Connection: mongoose.Connection = mongoose.connection; + + constructor(name: string, path: string, port: number) { + this.DatabaseName = name; + this.DatabasePath = path; + this.DatabasePort = port; + } + + /** + * Defines connection event functionality + * @param connectionUri + */ + private initializeConnectionEvents = (connectionUri: string) => { + this.Connection + .on('error', () => console.log(`Error connecting to database on: ${connectionUri}`)) + .once('open', () => console.log(`Successful connection to database on: ${connectionUri}`)) + } + + /** + * Constructs the MongoDb connection URI + * @returns + */ + public ConnectionUri = (): string => `mongodb://${this.DatabasePath}:${this.DatabasePort}/${this.DatabaseName}` + + /** + * Initalises a new mongo connection. + */ + public Connect = async (): Promise<void> => { + const connectionUri = this.ConnectionUri() + this.initializeConnectionEvents(connectionUri) + await mongoose.connect(connectionUri).catch((err) => { + console.log(err) + }) + } +} \ No newline at end of file diff --git a/backend-services/friend-service/src/Database/Schemas/FriendSchema.ts b/backend-services/friend-service/src/Database/Schemas/FriendSchema.ts new file mode 100644 index 0000000000000000000000000000000000000000..b471c43e4d6e37220d2f3112e9011e1e923f670e --- /dev/null +++ b/backend-services/friend-service/src/Database/Schemas/FriendSchema.ts @@ -0,0 +1,17 @@ +import mongoose, { Schema } from 'mongoose' + +/** + * Schema for representing an a friend + */ +const FriendSchema = new Schema({ + User1: { + type: String, + required: true + }, + User2: { + type: String, + required: true + } +}) + +export default FriendSchema; \ No newline at end of file diff --git a/backend-services/friend-service/src/Database/Schemas/RequestSchema.ts b/backend-services/friend-service/src/Database/Schemas/RequestSchema.ts new file mode 100644 index 0000000000000000000000000000000000000000..89a6a506119d4ce9757a75431ca6c21f87c8750c --- /dev/null +++ b/backend-services/friend-service/src/Database/Schemas/RequestSchema.ts @@ -0,0 +1,17 @@ +import mongoose, { Schema } from 'mongoose' + +/** + * Schema for representing an a request + */ +const RequestSchema = new Schema({ + SourceUser: { + type: String, + required: true + }, + TargetUser: { + type: String, + required: true + } +}) + +export default RequestSchema; \ No newline at end of file diff --git a/backend-services/friend-service/src/Datastores/DataStore.ts b/backend-services/friend-service/src/Datastores/DataStore.ts new file mode 100644 index 0000000000000000000000000000000000000000..63cf51dd12e8b289a2418a4435c37720b29802c5 --- /dev/null +++ b/backend-services/friend-service/src/Datastores/DataStore.ts @@ -0,0 +1,25 @@ +import mongoose, { Model, Schema } from 'mongoose' + +/** + * Defines common datastore functionality + */ +export abstract class DataStore<T> { + + /** + * Mongoose model pertaining to the datastore type + */ + public Model: Model<any> + + constructor (modelName: string, schema: Schema) { + this.Model = mongoose.model(modelName, schema) + } + + /** + * Finds a single item matching a given query + * @param query + * @returns + */ + public GetItem = async (query: any): Promise<T | null> => { + return await this.Model.findOne(query) + } +} \ No newline at end of file diff --git a/backend-services/friend-service/src/Datastores/FriendDataStore.ts b/backend-services/friend-service/src/Datastores/FriendDataStore.ts new file mode 100644 index 0000000000000000000000000000000000000000..b185c814dba611eb00227e1784bb7e34f7e1667c --- /dev/null +++ b/backend-services/friend-service/src/Datastores/FriendDataStore.ts @@ -0,0 +1,61 @@ +import FriendSchema from '../Database/Schemas/FriendSchema'; +import RequestSchema from '../Database/Schemas/RequestSchema'; +import { Friend } from '../Types/Friend'; +import { DataStore } from './DataStore'; + +/** + * Contains actions pertaining to storing and accessing Friends + */ +class FriendDataStore extends DataStore<any>{ + + /** + * Create a new friend relation between two users. + * @param u1 + * @param u2 + * @returns + */ + public newFriend = async (u1: string, u2: string): Promise<Friend> => { + if(await this.Model.findOne({User1: u1, User2: u2}) !== null || await this.Model.findOne({User1: u2, User2: u1}) !== null){ + throw new Error(`${u1} and ${u2} are already friends!`); + } + + return await this.Model.create({ + User1: u1, + User2: u2 + }); + }; + + /** + * Store action for getting a users friends + * @param itemCount + * @returns + */ + public getFriends = async (userId: string): Promise<{friends1: Friend[], friends2: Friend[]}> => { + const friends1 = await this.Model.find({User1: userId}) + const friends2 = await this.Model.find({User2: userId}) + + return {friends1, friends2} + } + + /** + * Method to removes a friend relation + * @param user1 + * @param user2 + */ + public RemoveFriend = async (user1: string, user2: string): Promise<void> => { + await this.Model.findOneAndDelete({User1: user1, User2: user2}) + await this.Model.findOneAndDelete({User1: user2, User2: user1}) + } + + /** + * Get the friend item by its id. + * @param id + * @returns + */ + public GetFriendByUsers = async (user1: string, user2: string): Promise<Friend | null> => { + const result = await this.Model.findOne({User1: user1, User2: user2}) || await this.Model.findOne({User1: user2, User2: user1}); + return result; + } +} + +export default new FriendDataStore('Friend', FriendSchema) \ No newline at end of file diff --git a/backend-services/friend-service/src/Datastores/RequestDataStore.ts b/backend-services/friend-service/src/Datastores/RequestDataStore.ts new file mode 100644 index 0000000000000000000000000000000000000000..839e9ddf898a26c4099fd07b600ef50048308b2b --- /dev/null +++ b/backend-services/friend-service/src/Datastores/RequestDataStore.ts @@ -0,0 +1,56 @@ +import RequestSchema from '../Database/Schemas/RequestSchema'; +import { FriendRequest } from '../Types/Request'; +import { DataStore } from './DataStore'; + +/** + * Contains actions pertaining to storing and accessing Requests + */ +class RequestDataStore extends DataStore<any>{ + + public newRequest = async (sourceUserId: string, targetUserId: string): Promise<FriendRequest> => { + return await this.Model.create({ + SourceUser: sourceUserId, + TargetUser: targetUserId + }); + }; + + /** + * Store action for getting requests for a user + * @param itemCount + * @returns + */ + public getRequests = async (userId: string): Promise<FriendRequest[]> => { + return await this.Model.find({TargetUser: userId}).sort({$natural: -1}) + } + + /** + * Find and delete a request if it exists. + * @param requestId + * @returns + */ + public handleRequestById = async (requestId: string): Promise<FriendRequest> => { + const result = await this.Model.findByIdAndDelete(requestId) + + if (result === null){ + throw new Error ("Invalid request id!") + } + return result; + } + + /** + * Get a request by its id + * @param requestId + * @returns + */ + public GetRequestById = async (requestId: string): Promise<FriendRequest> => { + const result = await this.Model.findById(requestId) + + if(result === null){ + throw new Error ("Invalid request id!") + } + + return result; + } +} + +export default new RequestDataStore('Request', RequestSchema) \ No newline at end of file diff --git a/backend-services/friend-service/src/Friends/FriendManager.ts b/backend-services/friend-service/src/Friends/FriendManager.ts new file mode 100644 index 0000000000000000000000000000000000000000..d92f1912de4add31d5b6dee7b676e30fe7a0b6b9 --- /dev/null +++ b/backend-services/friend-service/src/Friends/FriendManager.ts @@ -0,0 +1,26 @@ +import FriendDataStore from "../Datastores/FriendDataStore"; +import { Friend } from "../Types/Friend"; + +/** + * Class to handle all friend functionality + */ +export class FriendManager { + + public AddFriend = async (user1: string, user2: string): Promise<Friend> => { + return await FriendDataStore.newFriend(user1, user2); + } + + public GetFriendIds = async (userId: string): Promise<string[]> => { + const friends = await FriendDataStore.getFriends(userId); + return friends.friends1.map(f => f.User2).concat(friends.friends2.map(f => f.User1)); + } + + public RemoveFriend = async (user1: string, user2: string): Promise<void> => { + + if(await FriendDataStore.GetFriendByUsers(user1, user2) === null){ + throw new Error("Users are not friends!"); + } + + return await FriendDataStore.RemoveFriend(user1, user2); + } +} \ No newline at end of file diff --git a/backend-services/friend-service/src/Middleware/Auth.ts b/backend-services/friend-service/src/Middleware/Auth.ts new file mode 100644 index 0000000000000000000000000000000000000000..5703ac905ce775684f243303b3de4ebdeefb3f13 --- /dev/null +++ b/backend-services/friend-service/src/Middleware/Auth.ts @@ -0,0 +1,28 @@ +import jwt, { Secret, JwtPayload } from 'jsonwebtoken'; +import { Request, Response, NextFunction } from 'express'; +import Config from '../../config' + +export const SECRET_KEY: Secret = Config.JWT_SECRET; + +export interface CustomJWTRequest extends Request { + token?: string | JwtPayload; +} + +export const authorize = async (req: Request, res: Response, next: NextFunction) => { + try { + const authHeader = req.headers.authorization; + const token = authHeader?.split(" ")[1]; + + if (!token) { + throw new Error(); + } + + const decoded = jwt.verify(token, SECRET_KEY); + (req as CustomJWTRequest).token = decoded; + + next(); + } catch (err) { + console.log(err) + res.status(401).send('Please authenticate'); + } +}; \ No newline at end of file diff --git a/backend-services/friend-service/src/Requests/RequestManager.ts b/backend-services/friend-service/src/Requests/RequestManager.ts new file mode 100644 index 0000000000000000000000000000000000000000..ad1e184b0480961ba88dc51ac3d1455b00f56bce --- /dev/null +++ b/backend-services/friend-service/src/Requests/RequestManager.ts @@ -0,0 +1,60 @@ +import FriendDataStore from "../Datastores/FriendDataStore"; +import RequestDataStore from "../Datastores/RequestDataStore" +import { FriendManager } from "../Friends/FriendManager"; +import { Friend } from "../Types/Friend"; +import { FriendRequest } from "../Types/Request"; + +/** + * Handles all friend request functionality + */ +export class RequestManager { + + private friendManager: FriendManager + + constructor(friendManager: FriendManager){ + this.friendManager = friendManager; + } + + /** + * Method to create a new friend request + * @param sourceId + * @param targetId + * @returns + */ + public NewRequest = async (sourceId: string, targetId: string):Promise<FriendRequest> => { + if(sourceId === targetId){ + throw new Error("Sorry, can't friend yourself! :("); + } + + if(await RequestDataStore.GetItem({SourceUser: sourceId, TargetUser: targetId}) !== null || await RequestDataStore.GetItem({SourceUser: targetId, TargetUser: sourceId}) !== null){ + throw new Error("Request already exists!"); + } + + if(await FriendDataStore.GetFriendByUsers(sourceId, targetId) !== null){ + throw new Error("Users are already friends!"); + } + return await RequestDataStore.newRequest(sourceId, targetId); + } + + /** + * + * @param targetId Method to get user requests + * @returns + */ + public GetRequests = async (targetId: string):Promise<FriendRequest[]> => { + return await RequestDataStore.getRequests(targetId) + } + + public AcceptRequest = async (requestId: string): Promise<Friend> => { + const request = await RequestDataStore.handleRequestById(requestId) + return await this.friendManager.AddFriend(request.SourceUser, request.TargetUser) + } + + public RejectRequest = async (requestId: string): Promise<FriendRequest> => { + return await RequestDataStore.handleRequestById(requestId); + } + + public GetSingleRequest = async (requestId: string): Promise<FriendRequest> => { + return await RequestDataStore.GetRequestById(requestId); + } +} \ No newline at end of file diff --git a/backend-services/friend-service/src/Routes/FriendsRouter.ts b/backend-services/friend-service/src/Routes/FriendsRouter.ts new file mode 100644 index 0000000000000000000000000000000000000000..cf4be6e6c80141f10fa5aebc497e1063b1677efd --- /dev/null +++ b/backend-services/friend-service/src/Routes/FriendsRouter.ts @@ -0,0 +1,38 @@ +import express, { Response } from 'express' +import { FriendManager } from '../Friends/FriendManager' +import { CustomJWTRequest } from '../Middleware/Auth' + +export const FriendsRouter = express.Router() +const friendManager = new FriendManager(); + +/** + * GET '/' + * Returns a string + */ +FriendsRouter.get('/', async (req:CustomJWTRequest, res:Response): Promise<void> => { + const {token} = req + return friendManager.GetFriendIds(token as string).then(result => { + res.status(200).json({result: result}); + }).catch((error: Error) => { + res.status(400).json({error: error}) + }); +}); + +/** + * Delete '/' + * Returns a string + */ + FriendsRouter.delete('/', async (req:CustomJWTRequest, res:Response): Promise<Response> => { + const {user_id, friend_id} = req.body + const {token} = req + + if(token !== user_id){ + return res.status(400).json({error: 'unauthorised'}) + } + + return friendManager.RemoveFriend(user_id, friend_id).then(result => { + return res.sendStatus(200); + }).catch((error: Error) => { + return res.status(400).json({error: error.message}) + }); +}); \ No newline at end of file diff --git a/backend-services/friend-service/src/Routes/RequestsRouter.ts b/backend-services/friend-service/src/Routes/RequestsRouter.ts new file mode 100644 index 0000000000000000000000000000000000000000..9e0f13e0aed2840135c8c0880453bb6e39aacfa4 --- /dev/null +++ b/backend-services/friend-service/src/Routes/RequestsRouter.ts @@ -0,0 +1,86 @@ +import express, { Request, Response } from 'express' +import { FriendManager } from '../Friends/FriendManager'; +import { CustomJWTRequest } from '../Middleware/Auth'; +import { RequestManager } from '../Requests/RequestManager' + +export const RequestRouter = express.Router(); +const friendManager = new FriendManager(); +const requestManager = new RequestManager(friendManager); + +/** + * GET '/' + * Returns a string + */ +RequestRouter.get('/', async (req:CustomJWTRequest, res:Response): Promise<Response> => { + const {token} = req; + + return requestManager.GetRequests(token as string).then((result) => { + return res.status(200).json({requests: result}) + }).catch((error: Error) => { + return res.status(401).json({error: error.message}) + }); +}); + +/** + * POST '/' + * Creates a friend request + */ +RequestRouter.post('/', async (req:CustomJWTRequest, res:Response): Promise<Response> => { + const {requester_id, receiver_id} = req.body; + const {token} = req + + if(requester_id !== token){ + return res.status(401).json({error: "unathorised"}) + } + + return requestManager.NewRequest(requester_id, receiver_id).then((result) => { + return res.sendStatus(200) + }).catch((error:Error) => { + return res.status(400).json({error: error.message}) + }); +}); + +/** + * PUT '/accept' + */ +RequestRouter.put('/accept', async (req:CustomJWTRequest, res:Response): Promise<Response> => { + const {request_id} = req.body; + const {token} = req; + + return await requestManager.GetSingleRequest(request_id).then(result => { + if(result.TargetUser !== token){ + throw new Error("Unauthorised") + } else { + return requestManager.AcceptRequest(request_id).then((result) => { + return res.sendStatus(200) + }).catch((error: Error) => { + return res.status(400).json({error: error.message}) + }) + } + }).catch((error: Error) => { + return res.status(400).json({error: error.message}) + }) +}); + +/** + * PUT '/reject' + */ +RequestRouter.put('/reject', async (req:CustomJWTRequest, res:Response): Promise<Response> => { + const {request_id} = req.body; + const {token} = req; + + return await requestManager.GetSingleRequest(request_id).then(result => { + if(result.TargetUser !== token){ + throw new Error("Unauthorised") + } else { + return requestManager.RejectRequest(request_id).then((result) => { + return res.sendStatus(200) + }).catch((error: Error) => { + return res.status(400).json({error: error.message}) + }) + } + }).catch((error: Error) => { + return res.status(400).json({error: error.message}) + }) +}); + diff --git a/backend-services/friend-service/src/Routes/index.ts b/backend-services/friend-service/src/Routes/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..31b4f78fae74e011532f2fa2ab1a129277a3a380 --- /dev/null +++ b/backend-services/friend-service/src/Routes/index.ts @@ -0,0 +1,11 @@ +import express, { Request, Response } from 'express' + +export const IndexRouter = express.Router() + +/** + * GET '/' + * Returns a string + */ +IndexRouter.get('/status', (req:Request, res:Response): void => { + res.json({'message': 'Service \'Friend-Service\' is running', statusCode: 200}) +}) \ No newline at end of file diff --git a/backend-services/friend-service/src/Startup/routes.ts b/backend-services/friend-service/src/Startup/routes.ts new file mode 100644 index 0000000000000000000000000000000000000000..846ca55379d01435841d7a381e499845762a4533 --- /dev/null +++ b/backend-services/friend-service/src/Startup/routes.ts @@ -0,0 +1,20 @@ +import express, { Application } from 'express' +import { authorize } from '../Middleware/Auth' +import { IndexRouter } from '../Routes' +import { FriendsRouter } from '../Routes/FriendsRouter' +import { RequestRouter } from '../Routes/RequestsRouter' + +/** + * Load the application endpoints + * @param app + */ +export const initializeRoutes = (app: Application) => { + app.use(express.json()) + + // load index routes + app.use('/', IndexRouter) + + //Other routes + app.use('/friends', authorize, FriendsRouter) + app.use('/friends/requests', authorize, RequestRouter) +} \ No newline at end of file diff --git a/backend-services/friend-service/src/Types/Friend.ts b/backend-services/friend-service/src/Types/Friend.ts new file mode 100644 index 0000000000000000000000000000000000000000..4e85acb138e698fe815c0c54066e22e2454f6fef --- /dev/null +++ b/backend-services/friend-service/src/Types/Friend.ts @@ -0,0 +1,4 @@ +export type Friend = { + User1: string, + User2: string +} \ No newline at end of file diff --git a/backend-services/friend-service/src/Types/Request.ts b/backend-services/friend-service/src/Types/Request.ts new file mode 100644 index 0000000000000000000000000000000000000000..8e57f8bbc163aa981a31fed0f65615031dd20b43 --- /dev/null +++ b/backend-services/friend-service/src/Types/Request.ts @@ -0,0 +1,4 @@ +export type FriendRequest = { + SourceUser: string, + TargetUser: string +} \ No newline at end of file diff --git a/backend-services/friend-service/tsconfig.json b/backend-services/friend-service/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..572ba0f250d7bc9466bb147e8e2c15085bde8e6c --- /dev/null +++ b/backend-services/friend-service/tsconfig.json @@ -0,0 +1,105 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Projects */ + // "incremental": true, /* Enable incremental compilation */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ + // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "resolveJsonModule": true, /* Enable importing .json files */ + // "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./dist", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ + // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "exclude":[ + "./node_modules" + ] + +} diff --git a/docker-compose.yml b/docker-compose.yml index 52ce39430abb560783528340ba58e0a0f6a1d3cf..7394ea73347c0f70224b012431c7724e6618d207 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,15 +10,27 @@ services: # environment: # - MONGO_URI=mongodb://feed-mongo:27017/ - user-service: + # user-service: + # build: + # context: './backend-services/user-service' + # dockerfile: Dockerfile + # restart: unless-stopped + # ports: + # - "9002:9000" + # environment: + # - MONGO_URI=mongodb://user-mongo:27017/userdb + + friend-service: build: - context: './backend-services/user-service' + context: './backend-services/friend-service' dockerfile: Dockerfile restart: unless-stopped ports: - - "9002:9000" + - "9003:9000" environment: - - MONGO_URI=mongodb://user-mongo:27017/userdb + - MONGO_HOST=friend-mongo + - MONGO_PORT=27017 + - MONGO_DBNAME=friends # feed-mongo: @@ -27,14 +39,19 @@ services: # ports: # - "27017:27017" - user-mongo: - image: mongo - container_name: user-mongo - volumes: - - "./mongo/user:/data/user" - ports: - - "27018:27017" + # user-mongo: + # image: mongo + # container_name: user-mongo + # volumes: + # - "./mongo/user:/data/user" + # ports: + # - "27018:27017" + friend-mongo: + image: mongo + container_name: friend-mongo + ports: + - "27019:27017" \ No newline at end of file