From e466e99b361d4179f8683a141b58ae6241e8d4e0 Mon Sep 17 00:00:00 2001 From: talksik Date: Thu, 2 Jun 2022 12:03:28 -0500 Subject: [PATCH] delete api and will start over for it --- packages/api/.dockerignore | 1 - packages/api/.env.development | 3 - packages/api/.env.production | 3 - packages/api/.gitignore | 130 ------------- packages/api/Dockerfile | 17 -- packages/api/config.ts | 16 -- packages/api/index.ts | 49 ----- packages/api/middleware/auth.ts | 39 ---- packages/api/nodemon.json | 6 - packages/api/package.json | 30 --- packages/api/routes/line.ts | 216 ---------------------- packages/api/routes/search.ts | 46 ----- packages/api/routes/user.ts | 150 --------------- packages/api/services/database.service.ts | 34 ---- packages/api/services/line.service.ts | 148 --------------- packages/api/services/user.service.ts | 118 ------------ packages/api/sockets/index.ts | 215 --------------------- packages/api/tsconfig.json | 101 ---------- 18 files changed, 1322 deletions(-) delete mode 100644 packages/api/.dockerignore delete mode 100644 packages/api/.env.development delete mode 100644 packages/api/.env.production delete mode 100644 packages/api/.gitignore delete mode 100644 packages/api/Dockerfile delete mode 100644 packages/api/config.ts delete mode 100644 packages/api/index.ts delete mode 100644 packages/api/middleware/auth.ts delete mode 100644 packages/api/nodemon.json delete mode 100644 packages/api/package.json delete mode 100644 packages/api/routes/line.ts delete mode 100644 packages/api/routes/search.ts delete mode 100644 packages/api/routes/user.ts delete mode 100644 packages/api/services/database.service.ts delete mode 100644 packages/api/services/line.service.ts delete mode 100644 packages/api/services/user.service.ts delete mode 100644 packages/api/sockets/index.ts delete mode 100644 packages/api/tsconfig.json diff --git a/packages/api/.dockerignore b/packages/api/.dockerignore deleted file mode 100644 index b512c09..0000000 --- a/packages/api/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -node_modules \ No newline at end of file diff --git a/packages/api/.env.development b/packages/api/.env.development deleted file mode 100644 index 95d58c9..0000000 --- a/packages/api/.env.development +++ /dev/null @@ -1,3 +0,0 @@ -MONGO_CONNECTION_STRING=mongodb+srv://default:M9iZXokJlZpN4KLX@cluster0.mkuqa.mongodb.net/default?retryWrites=true&w=majority - -JWT_TOKEN_SECRET=afajdslfwk1@lkkasdfl21ASDF!2 \ No newline at end of file diff --git a/packages/api/.env.production b/packages/api/.env.production deleted file mode 100644 index 7be6773..0000000 --- a/packages/api/.env.production +++ /dev/null @@ -1,3 +0,0 @@ -MONGO_CONNECTION_STRING=mongodb+srv://default:M9iZXokJlZpN4KLX@cluster0.mkuqa.mongodb.net/default?retryWrites=true&w=majority - -JWT_TOKEN_SECRET=woasdfkajsdflj!@!@#0012399 \ No newline at end of file diff --git a/packages/api/.gitignore b/packages/api/.gitignore deleted file mode 100644 index 6a7d6d8..0000000 --- a/packages/api/.gitignore +++ /dev/null @@ -1,130 +0,0 @@ -# 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/packages/api/Dockerfile b/packages/api/Dockerfile deleted file mode 100644 index 32d25d0..0000000 --- a/packages/api/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM node:12 - -WORKDIR /app - -COPY packages/core packages/core -COPY package.json . - -RUN yarn install - -COPY . . - -ENV PORT=8080 -ENV NODE_ENV=production - -EXPOSE 8080 - -CMD ["yarn", "production"] \ No newline at end of file diff --git a/packages/api/config.ts b/packages/api/config.ts deleted file mode 100644 index 54d4c97..0000000 --- a/packages/api/config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import dotenv from "dotenv"; - -if (process.env && process.env.NODE_ENV === "development") { - dotenv.config({ path: ".env.development" }); -} else { - dotenv.config({ path: ".env" }); -} - -export const loadConfig = () => { - return { - MONGO_CONNECTION_STRING: process.env.MONGO_CONNECTION_STRING!, - JWT_TOKEN_SECRET: process.env.JWT_TOKEN_SECRET!, - GOOGLE_AUTH_CLIENT_ID: process.env.GOOGLE_AUTH_CLIENT_ID!, - GOOGLE_AUTH_CLIENT_SECRET: process.env.GOOGLE_AUTH_CLIENT_SECRET!, - }; -}; diff --git a/packages/api/index.ts b/packages/api/index.ts deleted file mode 100644 index 3dd2b6c..0000000 --- a/packages/api/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -import express, { Application, Request, Response } from 'express'; - -import GetAllSocketClients from '@nirvana/core/sockets/getAllActiveSocketClients'; -import InitializeWs from './sockets'; -import { NextFunction } from 'express'; -import NirvanaResponse from '@nirvana/core/responses/nirvanaResponse'; -import ReceiveSignal from '../core/sockets/receiveSignal'; -import SendSignal from '@nirvana/core/sockets/sendSignal'; -import SocketChannels from '@nirvana/core/sockets/channels'; -import { UserService } from './services/user.service'; -import { UserStatus } from '@nirvana/core/models'; -import cors from 'cors'; -import getLineRoutes from './routes/line'; -import getSearchRoutes from './routes/search'; -import getUserRoutes from './routes/user'; - -const app = express(); - -app.use(cors()); -app.use(express.json()); - -app.use((req: Request, res: Response, next: NextFunction) => { - console.log('Time: ', new Date()); - next(); -}); - -app.get('/', (req: Request, res: Response) => { - res.send('hello world.'); -}); - -app.use('/api/status', (req: Request, res: Response) => { - res.json(new NirvanaResponse('wohoo, server is healthy')); -}); - -app.use('/api/user', getUserRoutes()); -app.use('/api/search', getSearchRoutes()); -app.use('/api/lines', getLineRoutes()); - -const PORT = 8080; -const server = app.listen(PORT, () => console.log('express running')); - -const io = require('socket.io')(server, { - // todo: add authentication - cors: { - origin: '*', - }, -}); - -InitializeWs(io); diff --git a/packages/api/middleware/auth.ts b/packages/api/middleware/auth.ts deleted file mode 100644 index f0bccc4..0000000 --- a/packages/api/middleware/auth.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { NextFunction, Request, Response } from "express"; - -import { loadConfig } from "../config"; - -const jwt = require("jsonwebtoken"); - -const config = loadConfig(); - -// used by specific routes that need to authentication -export const authCheck = async ( - req: Request, - res: Response, - next: NextFunction -) => { - try { - const { authorization } = req.headers; - - if (!authorization) { - throw Error("No provided header"); - } - - // verify jwt token with our api secret - var decoded: JwtClaims = jwt.verify(authorization, config.JWT_TOKEN_SECRET); - - res.locals.userInfo = decoded; - - next(); - } catch (error) { - res.status(401).send("unauthorized"); - } -}; - -export interface JwtClaims { - userId: string; - googleUserId: string; - picture: string; - email: string; - name: string; -} diff --git a/packages/api/nodemon.json b/packages/api/nodemon.json deleted file mode 100644 index 4d05214..0000000 --- a/packages/api/nodemon.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "ignore": ["**/*.test.ts", "**/*.spec.ts", "node_modules"], - "watch": ["./"], - "exec": "npm start", - "ext": "ts" -} diff --git a/packages/api/package.json b/packages/api/package.json deleted file mode 100644 index 4355833..0000000 --- a/packages/api/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "@nirvana/api", - "version": "1.0.0", - "main": "index.ts", - "private": true, - "license": "MIT", - "dependencies": { - "@nirvana/core": "workspace:*", - "axios": "^0.26.1", - "cors": "^2.8.5", - "dotenv": "^16.0.0", - "express": "^4.17.3", - "google-auth-library": "^7.14.0", - "jsonwebtoken": "^8.5.1", - "mongodb": "^4.4.1", - "socket.io": "^4.4.1" - }, - "scripts": { - "dev": "NODE_ENV=development nodemon", - "start": "ts-node index.ts", - "production": "NODE_ENV=production nodemon" - }, - "devDependencies": { - "@types/express": "^4.17.13", - "@types/node": "^17.0.21", - "nodemon": "^2.0.15", - "ts-node": "^10.7.0", - "typescript": "^4.6.2" - } -} diff --git a/packages/api/routes/line.ts b/packages/api/routes/line.ts deleted file mode 100644 index 1236511..0000000 --- a/packages/api/routes/line.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { JwtClaims, authCheck } from '../middleware/auth'; -import { Line, LineMember, LineMemberState } from '@nirvana/core/models/line.model'; -import express, { Application, Request, Response } from 'express'; - -import Content from '@nirvana/core/models/content.model'; -import CreateLineRequest from '@nirvana/core/requests/createLine.request'; -import GetConversationDetailsResponse from '@nirvana/core/responses/getConversationDetails.response'; -import GetDmConversationByOtherUserIdResponse from '@nirvana/core/responses/getDmConversationByOtherUserId.response'; -import GetUserLinesResponse from '@nirvana/core/responses/getUserLines.response'; -import { LineService } from '../services/line.service'; -import MasterLineData from '@nirvana/core/models/masterLineData.model'; -import NirvanaResponse from '@nirvana/core/responses/nirvanaResponse'; -import { ObjectId } from 'mongodb'; -import Relationship from '@nirvana/core/models/relationship.model'; -import { User } from '@nirvana/core/models/user.model'; -import { UserService } from '../services/user.service'; -import { collections } from '../services/database.service'; -import UpdateLineMemberState from '@nirvana/core/requests/updateLineMemberState.request'; - -export default function getLineRoutes() { - const router = express.Router(); - - router.use(express.json()); - - // get data for a one on one conversation - // router.get("/:otherUserGoogleUserId", authCheck, getConversationDetails); - - // create a line - router.post('/', authCheck, createLine); - - // get all of user's lines - router.get('/', authCheck, getUserLines); - - // toggle tune into a line - router.post('/:lineId/state', authCheck, updateLineMemberState); - - // get conversation between user and other user - router.get('/dm/:otherUserId', authCheck, getDmByOtherUserId); - - return router; -} - -async function getDmByOtherUserId(req: Request, res: Response) { - try { - const { otherUserId } = req.params; - const userInfo = res.locals.userInfo as JwtClaims; - - console.log(otherUserId); - - // check db for lines between me and this other person - // if there is one, then return it with 200 status - // else return it with custom status that frontend will read - - res.status(200).json(); - return; - - res.status(205).json('no such conversation between you two'); - } catch (error) { - res.status(500).json(error); - } -} - -async function createLine(req: Request, res: Response) { - try { - const reqObj: CreateLineRequest = req.body as CreateLineRequest; - console.log(req.body); - - if (!reqObj?.otherMemberIds.length) { - res.status(400).json('must provide member Ids'); - return; - } - - const userInfo = res.locals.userInfo as JwtClaims; - - const newLine = new Line( - new ObjectId(userInfo.userId), - reqObj.lineName ?? undefined, - new Date(), - new Date(), - new ObjectId(), - ); - - // TODO: validate that users exists before creating line members - const lineMembers: LineMember[] = - reqObj.otherMemberIds.map((memId) => { - const newLineMember = new LineMember( - newLine._id!, - new ObjectId(memId), - LineMemberState.INBOX, - ); - - return newLineMember; - }) ?? []; - - lineMembers.push( - new LineMember(newLine._id!, new ObjectId(userInfo.userId), LineMemberState.INBOX), - ); - - const transactionResult = await LineService.createLine(newLine, lineMembers); - - transactionResult - ? res.status(200).json(new NirvanaResponse(newLine)) - : res.status(400).json(new NirvanaResponse(undefined, new Error('unable to create line'))); - } catch (error) { - console.log(error); - res.status(500).json(error); - } -} - -async function updateLineMemberState(req: Request, res: Response) { - try { - const userInfo = res.locals.userInfo as JwtClaims; - const { lineId } = req.params; - const request = req.body as UpdateLineMemberState; - - // TODO: validation to check if user is actually a member of the line - - const result = await LineService.updateLineMemberState( - lineId, - userInfo.userId, - request.newState, - ); - - return result?.ok - ? res.status(200).json(new NirvanaResponse("successfully updated line member's state")) - : res - .status(400) - .json(new NirvanaResponse(undefined, new Error('not updated...something went wrong'))); - } catch (error) { - res.status(500).json(new NirvanaResponse(undefined, error as Error)); - } -} - -async function getUserLines(req: Request, res: Response) { - try { - const userInfo = res.locals.userInfo as JwtClaims; - - // get all of user's lineMember entries - const userLineMembers = await LineService.getLineMembersByUserId(userInfo.userId); - - if (!userLineMembers?.length) { - const resObj = new GetUserLinesResponse([]); - - res.json(new NirvanaResponse(resObj, undefined, 'this user is not in any lines')); - - return; - } - - const lineIds = userLineMembers?.map((lineMember) => lineMember.lineId) ?? []; - - // this will include the current user lineMember association to the line - const allLineMembers = await LineService.getLineMembersInLines(lineIds); - - const allLinesUsersIds: ObjectId[] = []; - allLineMembers?.map((currentLineMember) => { - if (currentLineMember?.userId) allLinesUsersIds.push(currentLineMember.userId); - }) ?? []; - - // get all users relevant here - const allRelevantUsers = await UserService.getUsersByIds(allLinesUsersIds); - - // get all lines from the list of relevant lines - const lines = (await LineService.getLinesByIds(lineIds)) ?? []; - - const masterLines: MasterLineData[] = []; - - // TODO: get the latest audio blocks for this line...maybe like today and yesterday or by block count - - lines.map((currentLine) => { - let associatedLineMembersForLine: LineMember[] = []; - - // get all of the line members for this Line - // make sure that we don't add line member if it's the current user - allLineMembers?.map((lineMember) => { - if (currentLine._id) { - if (lineMember.lineId.equals(currentLine._id)) - associatedLineMembersForLine.push(lineMember); - } - }) ?? []; - - // get the user lineMember assoc out of the list of the lineMembers for this line - const userLineMember = associatedLineMembersForLine?.find( - (currentLineMemberForLine) => - currentLineMemberForLine.userId.toString() === userInfo.userId, - ); - - if (userLineMember) { - // take out the current user from the "other" line members list now - - associatedLineMembersForLine = associatedLineMembersForLine.filter( - (currentLineMember) => currentLineMember.userId.toString() !== userInfo.userId, - ); - - // get the user objects for all of the other members - const otherUsers: User[] = []; - associatedLineMembersForLine.forEach((currentLineMember) => { - const foundUserObject = allRelevantUsers?.find((currentUser) => - currentUser._id?.equals(currentLineMember.userId), - ); - - if (foundUserObject) otherUsers.push(foundUserObject); - }); - - masterLines.push( - new MasterLineData(currentLine, userLineMember, associatedLineMembersForLine, otherUsers), - ); - } - }); - - const resObj = new GetUserLinesResponse(masterLines); - - res.json(new NirvanaResponse(resObj)); - } catch (error) { - res.status(500).json(error); - } -} diff --git a/packages/api/routes/search.ts b/packages/api/routes/search.ts deleted file mode 100644 index 63d75fc..0000000 --- a/packages/api/routes/search.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { JwtClaims, authCheck } from "../middleware/auth"; -import express, { Application, Request, Response } from "express"; - -import { User } from "@nirvana/core/models"; -import UserSearchResponse from "../../core/responses/userSearch.response"; -import { UserService } from "../services/user.service"; - -export default function getSearchRoutes() { - const router = express.Router(); - - router.use(express.json()); - - // get user details based on id token - router.get("/users", authCheck, handleUserSearch); - - return router; -} - -async function handleUserSearch(req: Request, res: Response) { - try { - const userInfo = res.locals.userInfo as JwtClaims; - - const { query } = req.query; - - if (!query) { - res.status(400).send("No search query provided!"); - return; - } - - // text search on users - const users: User[] | null = await UserService.getUsersLikeEmailAndName( - query as string - ); - - const filteredUsers = users?.filter( - (currUser) => currUser._id?.toString() !== userInfo.userId - ); - - const resObj = new UserSearchResponse(filteredUsers ?? []); - - res.send(resObj); - } catch (error) { - console.log(error); - res.status(500).send(`something went wrong`); - } -} diff --git a/packages/api/routes/user.ts b/packages/api/routes/user.ts deleted file mode 100644 index c45f143..0000000 --- a/packages/api/routes/user.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { GoogleUserInfo, User } from "@nirvana/core/models"; -import { JwtClaims, authCheck } from "../middleware/auth"; -import express, { Application, Request, Response } from "express"; - -import LoginResponse from "../../core/responses/login.response"; -import { OAuth2Client } from "google-auth-library"; -import { ObjectID } from "bson"; -import { ObjectId } from "mongodb"; -import UserDetailsResponse from "../../core/responses/userDetails.response"; -import { UserService } from "../services/user.service"; -import { UserStatus } from "../../core/models/user.model"; -import { collections } from "../services/database.service"; -import { loadConfig } from "../config"; - -const jwt = require("jsonwebtoken"); - -const config = loadConfig(); - -const client = new OAuth2Client(config.GOOGLE_AUTH_CLIENT_ID); - -export default function getUserRoutes() { - const router = express.Router(); - - router.use(express.json()); - - // get user details based on id token - router.get("/", authCheck, getUserDetails); - - router.get("/login", login); - - router.get("/authcheck", authCheck, handleAuthCheck); - - return router; -} - -async function handleAuthCheck(req: Request, res: Response) { - try { - res.status(200).json("You are good to go!"); - } catch (error) { - res.status(401).json("Unauthorized"); - } -} - -async function getUserDetails(req: Request, res: Response) { - try { - const userInfo = res.locals.userInfo as JwtClaims; - - const user = await UserService.getUserById(userInfo.userId); - - user - ? res.status(200).json(new UserDetailsResponse(user)) - : res.status(404).json("No such user"); - } catch (error) { - console.log(error); - res.status(500).json(`Problem with signing user up or logging in`); - } -} - -/** Create user if doesn't exist - * Returns jwt token for client and user details - */ -async function login(req: Request, res: Response) { - // passed in accesstoken no matter what - const { access_token, id_token } = req.query; - - try { - const ticket = await client.verifyIdToken({ - idToken: (id_token as string) ?? "", - audience: config.GOOGLE_AUTH_CLIENT_ID, // Specify the CLIENT_ID of the app that accesses the backend - }); - const googleUserId = ticket.getPayload()?.sub as string; - const email = ticket.getPayload()?.email as string; - - if (!googleUserId || !email) { - res.status(401).json("no google account found"); - return; - } - - // return user details if it passed auth middleware - let user = await UserService.getUserByEmail(email); - - // if no user found, then go ahead and create user - if (!user) { - if (!access_token) { - res.status(400).json("No access token provided"); - return; - } - - // get google user info from access token - const userInfo: GoogleUserInfo = - await UserService.getGoogleUserInfoWithAccessToken( - access_token as string - ); - - // create initial user model object - - const newUser = new User( - googleUserId, - userInfo.email, - userInfo.name, - userInfo.given_name, - userInfo.family_name, - new Date(), - userInfo.picture, - userInfo.verifiedEmail, - userInfo.locale - ); - - // create user if not exists - const insertResult = await UserService.createUserIfNotExists(newUser); - - newUser._id = insertResult?.insertedId; - - // create jwt token with new user info - const jwtToken = jwt.sign( - { - userId: newUser._id, - googleUserId: newUser.googleId, - picture: newUser.picture, - email: newUser.email, - name: newUser.name, - }, - config.JWT_TOKEN_SECRET - ); - - insertResult - ? res.status(200).json(new LoginResponse(jwtToken, newUser)) - : res.status(500).json("Failed to create account, already exists"); - - return; - } - - // create jwt token with new user info - const jwtToken = jwt.sign( - { - userId: user._id, - googleUserId: user.googleId, - picture: user.picture, - email: user.email, - name: user.name, - }, - config.JWT_TOKEN_SECRET - ); - - res.status(200).json(new LoginResponse(jwtToken, user)); - } catch (error) { - console.log(error); - res.status(500).json(`Problem with signing user up or logging in`); - } -} diff --git a/packages/api/services/database.service.ts b/packages/api/services/database.service.ts deleted file mode 100644 index 497f340..0000000 --- a/packages/api/services/database.service.ts +++ /dev/null @@ -1,34 +0,0 @@ -// External Dependencies -import * as mongoDB from "mongodb"; - -import { loadConfig } from "../config"; - -// Global Variables -export const collections: { - users?: mongoDB.Collection; - lines?: mongoDB.Collection; - lineMembers?: mongoDB.Collection; -} = {}; - -// Initialize Connection -const config = loadConfig(); - -export const client: mongoDB.MongoClient = new mongoDB.MongoClient( - config.MONGO_CONNECTION_STRING -); - -client.connect(); - -const db: mongoDB.Db = client.db(process.env.DB_NAME); - -const usersCollection: mongoDB.Collection = db.collection("users"); -const lineCollection: mongoDB.Collection = db.collection("lines"); -const lineMembersCollection: mongoDB.Collection = db.collection("lineMembers"); - -collections.users = usersCollection; -collections.lines = lineCollection; -collections.lineMembers = lineMembersCollection; - -console.log( - `Successfully connected to database: ${db.databaseName} and collections` -); diff --git a/packages/api/services/line.service.ts b/packages/api/services/line.service.ts deleted file mode 100644 index bcfa195..0000000 --- a/packages/api/services/line.service.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { - Line, - LineMember, - LineMemberState, -} from "@nirvana/core/models/line.model"; -import { client, collections } from "./database.service"; - -import NirvanaResponse from "@nirvana/core/responses/nirvanaResponse"; -import { ObjectId } from "mongodb"; - -export class LineService { - static async getLineByOtherUserId(otherUserId: ObjectId) { - // get all of the conversations for this user that have exactly two conversation members - // get all of the conversationMembers for this user - // get all of the conversations for this user - // get all of the conversations - // const query = { googleId: userId }; - // const res = await collections.users?.findOne(query); - // // exists - // if (res?._id) { - // return res as User; - // } - // return null; - } - - static async getLinesByIds(convoIds: ObjectId[]) { - const query = { _id: { $in: convoIds } }; - - const convosRes = await collections.lines?.find(query).toArray(); - - // exists - if (convosRes?.length) { - return convosRes as Line[]; - } - - return null; - } - - static async getLineMembersByUserId(userId: string) { - const query = { userId: new ObjectId(userId) }; - - const convoMembersRes = await collections.lineMembers - ?.find(query) - .toArray(); - - // exists - if (convoMembersRes?.length) { - return convoMembersRes as LineMember[]; - } - - return null; - } - - /** Get all of the members associated to the given list of lines */ - static async getLineMembersInLines(lineIds: ObjectId[]) { - const query = { lineId: { $in: lineIds } }; - - const lineMembersRes = await collections.lineMembers?.find(query).toArray(); - - // exists - if (lineMembersRes?.length) { - return lineMembersRes as LineMember[]; - } - - return null; - } - - static async createLine(line: Line, lineMembers: LineMember[]) { - const session = client.startSession(); - try { - const transactionResults = await session.withTransaction(async () => { - // todo: check if convoMembers userId's actually exist - - const insertLineRes = await collections.lines?.insertOne(line); - if (!insertLineRes?.insertedId) { - await session.abortTransaction(); - console.error("failed to create line"); - - return; - } - - const insertConvoMembersRes = await collections.lineMembers?.insertMany( - lineMembers - ); - if (!insertConvoMembersRes?.insertedCount) { - await session.abortTransaction(); - console.error("failed to create line members"); - - return; - } - - console.log("success"); - return insertConvoMembersRes; - }); - - console.log(transactionResults); - - return "success"; - - // if (transactionResults) { - // console.log("The convo was successfully created."); - // return transactionResults; - // } else { - // console.log("The convo was intentionally aborted."); - // return null; - // } - } catch (e) { - console.log( - "The transaction was aborted due to an unexpected error: " + e - ); - } finally { - await session.endSession(); - } - - return null; - } - - static async updateLineMemberState( - lineId: string, - userId: string, - newState: LineMemberState - ) { - const query = { - lineId: new ObjectId(lineId), - userId: new ObjectId(userId), - }; - const updateSet = { $set: { state: newState, lastVisitDate: new Date() } }; - - const updateRes = await collections.lineMembers?.findOneAndUpdate( - query, - updateSet - ); - - return updateRes; - } - - static async updateLineMemberVisitDate(lineId: string, userId: string) { - const query = { lineId, userId: new ObjectId(userId) }; - const updateSet = { $set: { lastVisitDate: new Date() } }; - - const updateRes = await collections.lineMembers?.findOneAndUpdate( - query, - updateSet - ); - - return updateRes; - } -} diff --git a/packages/api/services/user.service.ts b/packages/api/services/user.service.ts deleted file mode 100644 index 443ba9a..0000000 --- a/packages/api/services/user.service.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { GoogleUserInfo, User } from "@nirvana/core/models"; - -import { ObjectId } from "mongodb"; -import { UserStatus } from "../../core/models/user.model"; -import axios from "axios"; -import { collections } from "./database.service"; - -export class UserService { - static async getUserById(userId: string) { - const query = { _id: new ObjectId(userId) }; - - const res = await collections.users?.findOne(query); - - // exists - if (res?._id) { - return res as User; - } - - return null; - } - - static async getUsersByIds(userIds: ObjectId[]) { - const query = { _id: { $in: userIds } }; - - const res = await collections.users?.find(query).toArray(); - - // exists - if (res?.length) { - return res as User[]; - } - - return undefined; - } - - static async getUserByGoogleId(googleUserId: string) { - const query = { googleId: googleUserId }; - - const res = await collections.users?.findOne(query); - - // exists - if (res?._id) { - return res as User; - } - - return null; - } - - static async getUserByEmail(email: string) { - const query = { email }; - - const res = await collections.users?.findOne(query); - - // exists - if (res?._id) { - return res as User; - } - - return null; - } - - static async getUsersLikeEmailAndName(searchQuery: string) { - // based on index defined in Mongo atlas - const query = { - $search: { - index: "basic user search", - text: { - query: searchQuery, - path: { - wildcard: "*", - }, - }, - }, - }; - - // const res = await collections.users?.find(query).toArray(); - - const res = await collections.users?.aggregate([query]).toArray(); - - // exists - if (res?.length) { - return res as User[]; - } - - return null; - } - - static async createUserIfNotExists(newUser: User) { - const getUser = await this.getUserByEmail(newUser.email); - - if (!getUser) { - return await collections.users?.insertOne(newUser); - } - - // user with email exists already, don't create - return null; - } - - static async getGoogleUserInfoWithAccessToken( - accessToken: string - ): Promise { - return ( - await axios.get( - `https://www.googleapis.com/oauth2/v1/userinfo?access_token=${accessToken}` - ) - ).data; - } - - static async updateUserStatus(userGoogleId: string, newStatus: UserStatus) { - const query = { googleId: userGoogleId }; - const updateDoc = { - $set: { status: newStatus, lastUpdatedDate: new Date() }, - }; - - const resultUpdate = await collections.users?.updateOne(query, updateDoc); - - return resultUpdate; - } -} diff --git a/packages/api/sockets/index.ts b/packages/api/sockets/index.ts deleted file mode 100644 index 9075add..0000000 --- a/packages/api/sockets/index.ts +++ /dev/null @@ -1,215 +0,0 @@ -import { - ConnectToLineRequest, - RtcAnswerSomeoneRequest, - RtcCallRequest, - RtcNewUserJoinedResponse, - RtcReceiveAnswerResponse, - ServerRequestChannels, - ServerResponseChannels, - SomeoneConnectedResponse, - SomeoneDisconnectedResponse, - SomeoneTunedResponse, - SomeoneUntunedFromLineResponse, - StartBroadcastingRequest, - StopBroadcastingRequest, - TuneToLineRequest, - UntuneFromLineRequest, - UserStartedBroadcastingResponse, - UserStoppedBroadcastingResponse, -} from '@nirvana/core/sockets/channels'; - -import GetAllSocketClients from '@nirvana/core/sockets/getAllActiveSocketClients'; -import { JwtClaims } from '../middleware/auth'; -import { LineMemberState } from '@nirvana/core/models/line.model'; -import { LineService } from '../services/line.service'; -import ReceiveSignal from '@nirvana/core/sockets/receiveSignal'; -import SendSignal from '@nirvana/core/sockets/sendSignal'; -import { UserService } from '../services/user.service'; -import { UserStatus } from '@nirvana/core/models/user.model'; -import { client } from '../services/database.service'; -import { loadConfig } from '../config'; - -const jwt = require('jsonwebtoken'); - -const config = loadConfig(); - -// NOTE: client socket connections should never have to deal with socketIds -const socketIdsToUserIds: { - [socketId: string]: string; -} = {}; -const userIdsToSocketIds: { - [userId: string]: string; -} = {}; - -export default function InitializeWs(io: any) { - console.log('initializing web sockets'); - - return io - .use(function (socket: any, next: any) { - console.log('authenticating user...'); - - try { - const { token } = socket.handshake.query; - console.log(token); - - // verify jwt token with our api secret - var decoded: JwtClaims = jwt.verify(token, config.JWT_TOKEN_SECRET); - - socket.userInfo = decoded; - - next(); - } catch (error) { - console.error(error); - next(new Error('WS Authentication Error')); - } - }) - .on('connection', function (socket: any) { - const userInfo: JwtClaims = socket.userInfo; - - socketIdsToUserIds[socket.id] = userInfo.userId.toString(); - userIdsToSocketIds[userInfo.userId.toString()] = socket.id; - - console.log(`a user connected | user Id: ${userInfo.userId} and name: ${userInfo.name}`); - - socket.on('test', () => { - console.log('asdf'); - }); - - // ?verification that user is in a particular line to be tuned into it or just generally in it? - - /** CONNECT | User wants to subscribe to live emissions of a line */ - socket.on(ServerRequestChannels.CONNECT_TO_LINE, (req: ConnectToLineRequest) => { - // add this user to the room - console.log(`${socket.id} user CONNECTED room for line ${Object.keys(socket.rooms)}`); - - const roomName = `connectedLine:${req.lineId}`; - socket.join(roomName); - - const clientUserIdsInRoom = [...(io.sockets.adapter.rooms.get(roomName) ?? [])].map( - (otherUserSocketId: string) => socketIdsToUserIds[otherUserSocketId], - ); - - io.in(roomName).emit( - ServerResponseChannels.SOMEONE_CONNECTED_TO_LINE, - new SomeoneConnectedResponse(req.lineId, userInfo.userId, clientUserIdsInRoom), - ); - }); - - /** TUNE | User tunes into the line either temporarily or toggled in */ - socket.on(ServerRequestChannels.TUNE_INTO_LINE, async (req: TuneToLineRequest) => { - console.log(`${socket.id} user TUNED into room for line ${req.lineId}`); - - const roomName = `tunedLine:${req.lineId}`; - socket.join(roomName); - - const clientUserIdsInRoom = [...(io.sockets.adapter.rooms.get(roomName) ?? [])].map( - (otherUserSocketId: string) => socketIdsToUserIds[otherUserSocketId], - ); - - // we want to notify everyone connected to the line even if they are not tuned in - const connectedLineRoomName = `connectedLine:${req.lineId}`; - - io.in(connectedLineRoomName).emit( - ServerResponseChannels.SOMEONE_TUNED_INTO_LINE, - new SomeoneTunedResponse(req.lineId, userInfo.userId, clientUserIdsInRoom), - ); - }); - - /** - * Notify all connected users when someone UNTUNES from a room - */ - socket.on(ServerRequestChannels.UNTUNE_FROM_LINE, async (req: UntuneFromLineRequest) => { - const roomName = `tunedLine:${req.lineId}`; - socket.leave(roomName); - - console.log(`${userInfo.userId} left room: ${roomName}`); - - // we want to notify everyone connected to the line even if they are not tuned in - const connectedLineRoomName = `connectedLine:${req.lineId}`; - - io.in(connectedLineRoomName).emit( - ServerResponseChannels.SOMEONE_UNTUNED_FROM_LINE, - new SomeoneUntunedFromLineResponse(req.lineId, userInfo.userId), - ); - }); - - // TODO: use same pattern as tuning and untuning and send updated fresh list of current broadcasters but using another namespace/room for broadcasters in a line - /** BROADCAST UPDATE | tell all connected, not just tuned into, that there is an update to someone broadcasting */ - socket.on(ServerRequestChannels.BROADCAST_TO_LINE, (req: StartBroadcastingRequest) => { - const roomName = `connectedLine:${req.lineId}`; - - io.in(roomName).emit( - ServerResponseChannels.SOMEONE_STARTED_BROADCASTING, - new UserStartedBroadcastingResponse(req.lineId, userInfo.userId), - ); - }); - - socket.on(ServerRequestChannels.STOP_BROADCAST_TO_LINE, (req: StopBroadcastingRequest) => { - const roomName = `connectedLine:${req.lineId}`; - - io.in(roomName).emit( - ServerResponseChannels.SOMEONE_STOPPED_BROADCASTING, - new UserStoppedBroadcastingResponse(req.lineId, userInfo.userId), - ); - }); - - socket.on(ServerRequestChannels.RTC_CALL_SOMEONE_FOR_LINE, (req: RtcCallRequest) => { - console.log('slave calling a master'); - - const userSocketId = userIdsToSocketIds[req.userToCall]; - - io.to(userSocketId).emit( - ServerResponseChannels.RTC_NEW_USER_JOINED, - new RtcNewUserJoinedResponse(userInfo.userId, req.lineId, req.simplePeerSignal), - ); - }); - - socket.on( - ServerRequestChannels.RTC_ANSWER_SOMEONE_FOR_LINE, - (req: RtcAnswerSomeoneRequest) => { - console.log('master answering slave'); - - const userSocketId = userIdsToSocketIds[req.newbieUserId]; - - io.to(userSocketId).emit( - ServerResponseChannels.RTC_RECEIVING_MASTER_ANSWER, - new RtcReceiveAnswerResponse(userInfo.userId, req.lineId, req.simplePeerSignal), - ); - }, - ); - - // tell everyone in the channel to - // socket.on(ServerRequestChannels.CREATED_CHANNEL, (req: CreatedLineRequest) => { - - // }) - - // tell all people in all my lines that I am disconnecting or untuning - // tell the tuned in folks the new list of - socket.on('disconnecting', (reason: any) => { - console.log(`someone disconnecting: ${reason}`); - - console.log(socket.rooms); - - for (const roomName of socket.rooms) { - if (roomName !== socket.id) { - const lineId = roomName.split(':')[1]; - - const roomToTell = roomName.includes('tunedLine') - ? `connectedLine:${lineId}` - : roomName; - - io.in(roomToTell).emit( - ServerResponseChannels.SOMEONE_DISCONNECTED_FROM_LINE, - new SomeoneDisconnectedResponse(lineId, userInfo.userId), - ); - } - } - }); - - // ==== DISCONNECT ==== - socket.on('disconnect', () => { - delete socketIdsToUserIds[socket.id]; - delete userIdsToSocketIds[userInfo.userId]; - }); - }); -} diff --git a/packages/api/tsconfig.json b/packages/api/tsconfig.json deleted file mode 100644 index 5679481..0000000 --- a/packages/api/tsconfig.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "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": "es2016", /* 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 ``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": "./", /* 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. */ - } -}