From a92647bd379054aaac46a8113976d9dd2b56c7f7 Mon Sep 17 00:00:00 2001 From: JamesNg Date: Wed, 30 Apr 2025 16:48:35 -0400 Subject: [PATCH 1/6] wrote unit tests for Auth router --- backend/globalConfig.json | 2 +- backend/package.json | 1 + backend/routers/auth.router.test.js | 80 +++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 backend/routers/auth.router.test.js diff --git a/backend/globalConfig.json b/backend/globalConfig.json index ae758586..1cc98fd3 100644 --- a/backend/globalConfig.json +++ b/backend/globalConfig.json @@ -1 +1 @@ -{"mongoUri":"mongodb://127.0.0.1:56074/jest?","mongoDBName":"jest"} \ No newline at end of file +{"mongoUri":"mongodb://127.0.0.1:42383/jest?","mongoDBName":"jest"} \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index 628339b8..38839c70 100644 --- a/backend/package.json +++ b/backend/package.json @@ -8,6 +8,7 @@ "format": "prettier --check .", "test": "jest", "test:watch": "jest --watch", + "test:auth": "jest --watch auth.router.test.js", "start": "node server.js", "dev": "nodemon server.js", "client": "npm run start --prefix client", diff --git a/backend/routers/auth.router.test.js b/backend/routers/auth.router.test.js new file mode 100644 index 00000000..8e0cbad1 --- /dev/null +++ b/backend/routers/auth.router.test.js @@ -0,0 +1,80 @@ +// Set up mocks for UserController +const { User } = require('../models/user.model'); +const { UserController } = require('../controllers'); +const { verifyUser, verifyToken } = require('../middleware'); +const { authApiValidator } = require('../validators'); + +jest.mock('../controllers/user.controller'); +jest.mock('../models/user.model'); +jest.mock('../middleware/user.middleware'); + +// Import auth router +const express = require('express'); +const supertest = require('supertest'); +const authRouter = require('../routers/auth.router'); + +// Create a new Express application for testing +const testapp = express(); +// Use body parser to extract params in API calls +testapp.use(express.json()); +testapp.use('/api/auth', authRouter); +const request = supertest(testapp); + +describe('Unit tests for auth router', () => { + // Mocker user for test + const mockUser = { + id: 1, + name: { + firstName: 'mock', + lastName: 'user', + }, + email: 'mockUser@test.com', + accessLevel: 'user', + }; + + // Clear all mocks after each test + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('CREATE', () => { + // it('should sign up new user with POST /api/auth/signup', async (done) => { + // // Mock successful save + // User.mockImplementation(() => ({ + // save: jest.fn().mockImplementationOnce((callback) => { + // callback(null, mockUser); + // }), + // })); + + // const response = await request.post('/api/auth/signup').send({ + // name: { + // firstName: mockUser.firstName, + // lastName: mockUser.lastName, + // }, + // email: mockUser.email.toLowerCase(), + // }); + + // // Tests + // // expect(UserController.createUser).toHaveBeenCalled(); + // expect(response.sendStatus).toBe(201); + // // expect(response.status).toBe(201); + + // // Marks completion of tests + // done(); + // }); + + it('should sign in existing user with POST /api/auth/signin', async (done) => { + const response = await request + .post('/api/auth/signin') + .set('Authorization', 'Bearer valid-token') + .send({ + firstName: 'Jane', + lastName: 'Smith', + email: 'mockuser@gmail.com', + }); + + expect(response.statusCode).toBe(201); + done(); + }) + }); +}); From d16f572bea6a17e0b17c3803903a701933b1058d Mon Sep 17 00:00:00 2001 From: JamesNg Date: Mon, 12 May 2025 22:37:23 -0400 Subject: [PATCH 2/6] wrote unit tests --- backend/globalConfig.json | 2 +- backend/routers/auth.router.test.js | 154 +++++++++++++++++++--------- 2 files changed, 108 insertions(+), 48 deletions(-) diff --git a/backend/globalConfig.json b/backend/globalConfig.json index 1cc98fd3..f3c67520 100644 --- a/backend/globalConfig.json +++ b/backend/globalConfig.json @@ -1 +1 @@ -{"mongoUri":"mongodb://127.0.0.1:42383/jest?","mongoDBName":"jest"} \ No newline at end of file +{"mongoUri":"mongodb://127.0.0.1:33055/jest?","mongoDBName":"jest"} \ No newline at end of file diff --git a/backend/routers/auth.router.test.js b/backend/routers/auth.router.test.js index 8e0cbad1..657adf5e 100644 --- a/backend/routers/auth.router.test.js +++ b/backend/routers/auth.router.test.js @@ -1,12 +1,29 @@ -// Set up mocks for UserController -const { User } = require('../models/user.model'); -const { UserController } = require('../controllers'); -const { verifyUser, verifyToken } = require('../middleware'); -const { authApiValidator } = require('../validators'); - +// Set up mocks for User model and controller jest.mock('../controllers/user.controller'); +jest.mock('../controllers/email.controller'); jest.mock('../models/user.model'); -jest.mock('../middleware/user.middleware'); +// Set up mocks for middleware +jest.mock('../middleware', () => ({ + AuthUtil: { + verifyCookie: jest.fn((req, res, next) => next()), + }, + verifyUser: { + checkDuplicateEmail: jest.fn((req, res, next) => next()), + isAdminByEmail: jest.fn((req, res, next) => next()), + }, + verifyToken: { + isTokenValid: jest.fn((req, res, next) => next()), + }, +})); +// Set up mocks for authApiValidator +jest.mock('../validators/user.api.validator', () => ({ + validateCreateUserAPICall: jest.fn((req, res, next) => next()), + validateSigninUserAPICall: jest.fn((req, res, next) => next()), +})); + +// Import User model and controller +const { User } = require('../models/user.model'); +const { UserController, EmailController } = require('../controllers'); // Import auth router const express = require('express'); @@ -21,6 +38,11 @@ testapp.use('/api/auth', authRouter); const request = supertest(testapp); describe('Unit tests for auth router', () => { + // Clear all mocks after each test + afterEach(() => { + jest.clearAllMocks(); + }); + // Mocker user for test const mockUser = { id: 1, @@ -32,49 +54,87 @@ describe('Unit tests for auth router', () => { accessLevel: 'user', }; - // Clear all mocks after each test - afterEach(() => { - jest.clearAllMocks(); - }); - describe('CREATE', () => { - // it('should sign up new user with POST /api/auth/signup', async (done) => { - // // Mock successful save - // User.mockImplementation(() => ({ - // save: jest.fn().mockImplementationOnce((callback) => { - // callback(null, mockUser); - // }), - // })); - - // const response = await request.post('/api/auth/signup').send({ - // name: { - // firstName: mockUser.firstName, - // lastName: mockUser.lastName, - // }, - // email: mockUser.email.toLowerCase(), - // }); - - // // Tests - // // expect(UserController.createUser).toHaveBeenCalled(); - // expect(response.sendStatus).toBe(201); - // // expect(response.status).toBe(201); - - // // Marks completion of tests - // done(); - // }); + it('should sign up new user with POST /api/auth/signup', async (done) => { + // Mock implementation of UserController.createUser + UserController.createUser.mockImplementationOnce((req, res) => { + res.status(201).send({ message: 'User created successfully' }); + }); + + // Mock POST API call + const response = await request.post('/api/auth/signup').send({ + name: { + firstName: mockUser.firstName, + lastName: mockUser.lastName, + }, + email: mockUser.email.toLowerCase(), + }); + + // Tests + expect(UserController.createUser).toHaveBeenCalled(); + expect(response.status).toBe(201); + expect(response.body).toEqual({ message: 'User created successfully' }); + + // Marks completion of tests + done(); + }); it('should sign in existing user with POST /api/auth/signin', async (done) => { - const response = await request - .post('/api/auth/signin') - .set('Authorization', 'Bearer valid-token') - .send({ - firstName: 'Jane', - lastName: 'Smith', - email: 'mockuser@gmail.com', - }); - - expect(response.statusCode).toBe(201); + // Mock implementation for UserController.signin + const jsonToken = 'mockedToken'; + const email = mockUser.email.toLowerCase(); + const auth_origin = 'web'; + const cookie = 'mockedCookie'; + const headers = { + origin: 'http://localhost:3000', + }; + + UserController.signin.mockImplementation((req, res) => { + // Set a cookie in the response + res.cookie('token', cookie, { httpOnly: true }); + + // Set custom headers in the response + res.set('origin', headers.origin); + + EmailController.sendLoginLink( + req.body.email, + req.body.auth_origin, + mockUser.name.firstName, + jsonToken, + cookie, + headers.origin, + ); + + res.status(200).send({ message: 'Signin successful' }); + }); + + // Mock implementation for EmailController.sendLoginLink + EmailController.sendLoginLink.mockImplementation(() => { + console.log('Mocked EmailController.sendLoginLink called'); + }); + + const response = await request.post('/api/auth/signin').send({ + email: email, + auth_origin: auth_origin, + }); + + // Tests + expect(UserController.signin).toHaveBeenCalled(); + expect(EmailController.sendLoginLink).toHaveBeenCalledWith( + email, + auth_origin, + mockUser.name.firstName, + jsonToken, + cookie, + headers.origin, + ); + expect(response.status).toBe(200); + // Verify that the cookie is set + expect(response.headers['set-cookie']).toBeDefined(); + expect(response.headers['set-cookie'][0]).toContain('token=mockedCookie'); + + // Marks completion of tests done(); - }) + }); }); }); From d637b52588aa6c563beaad66f9ee6d0eddf3615e Mon Sep 17 00:00:00 2001 From: JamesNg Date: Tue, 13 May 2025 14:22:05 -0400 Subject: [PATCH 3/6] wrote unit tests for Auth router --- backend/globalConfig.json | 2 +- backend/package.json | 1 - backend/routers/auth.router.test.js | 77 ++++++++++++++++++++++++++++- 3 files changed, 76 insertions(+), 4 deletions(-) diff --git a/backend/globalConfig.json b/backend/globalConfig.json index f3c67520..6e8e3d60 100644 --- a/backend/globalConfig.json +++ b/backend/globalConfig.json @@ -1 +1 @@ -{"mongoUri":"mongodb://127.0.0.1:33055/jest?","mongoDBName":"jest"} \ No newline at end of file +{"mongoUri":"mongodb://127.0.0.1:37269/jest?","mongoDBName":"jest"} \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index 38839c70..628339b8 100644 --- a/backend/package.json +++ b/backend/package.json @@ -8,7 +8,6 @@ "format": "prettier --check .", "test": "jest", "test:watch": "jest --watch", - "test:auth": "jest --watch auth.router.test.js", "start": "node server.js", "dev": "nodemon server.js", "client": "npm run start --prefix client", diff --git a/backend/routers/auth.router.test.js b/backend/routers/auth.router.test.js index 657adf5e..8be2688f 100644 --- a/backend/routers/auth.router.test.js +++ b/backend/routers/auth.router.test.js @@ -29,6 +29,8 @@ const { UserController, EmailController } = require('../controllers'); const express = require('express'); const supertest = require('supertest'); const authRouter = require('../routers/auth.router'); +const { verifyToken, verifyUser, AuthUtil } = require('../middleware'); +const { authApiValidator } = require('../validators'); // Create a new Express application for testing const testapp = express(); @@ -37,6 +39,7 @@ testapp.use(express.json()); testapp.use('/api/auth', authRouter); const request = supertest(testapp); + describe('Unit tests for auth router', () => { // Clear all mocks after each test afterEach(() => { @@ -71,6 +74,8 @@ describe('Unit tests for auth router', () => { }); // Tests + expect(authApiValidator.validateCreateUserAPICall).toHaveBeenCalled(); + expect(verifyUser.checkDuplicateEmail).toHaveBeenCalled(); expect(UserController.createUser).toHaveBeenCalled(); expect(response.status).toBe(201); expect(response.body).toEqual({ message: 'User created successfully' }); @@ -105,7 +110,7 @@ describe('Unit tests for auth router', () => { headers.origin, ); - res.status(200).send({ message: 'Signin successful' }); + res.status(200).send('Signin successful'); }); // Mock implementation for EmailController.sendLoginLink @@ -119,6 +124,8 @@ describe('Unit tests for auth router', () => { }); // Tests + expect(authApiValidator.validateSigninUserAPICall).toHaveBeenCalled(); + expect(verifyUser.isAdminByEmail).toHaveBeenCalled(); expect(UserController.signin).toHaveBeenCalled(); expect(EmailController.sendLoginLink).toHaveBeenCalledWith( email, @@ -131,10 +138,76 @@ describe('Unit tests for auth router', () => { expect(response.status).toBe(200); // Verify that the cookie is set expect(response.headers['set-cookie']).toBeDefined(); - expect(response.headers['set-cookie'][0]).toContain('token=mockedCookie'); + expect(response.headers['set-cookie'][0]).toContain(`token=${cookie}`); + expect(response.text).toBe('Signin successful'); + + // Marks completion of tests + done(); + }); + + it('should verify sign in with POST /api/auth/verify-signin', async (done) => { + // Mock implementation for UserController.verifySignIn + UserController.verifySignIn.mockImplementation((req, res) => { + res.status(200).send(mockUser); + }); + + // Mock POST API call + const response = await request.post('/api/auth/verify-signin').send({ + token: 'mockedToken', + }); + + // Tests + expect(verifyToken.isTokenValid).toHaveBeenCalled(); + expect(UserController.verifySignIn).toHaveBeenCalled(); + expect(response.status).toBe(200); + expect(response.body).toEqual(mockUser); + + // Marks completion of tests + done(); + }); + + it('should verify me with POST /api/auth/me', async (done) => { + // Mock implementation for UserController.verifyMe + UserController.verifyMe.mockImplementation((req, res) => { + res.status(200).send(mockUser); + }); + + // Mock POST API call + const response = await request.post('/api/auth/me').send({ + token: 'mockedToken', + }); + + // Tests + expect(AuthUtil.verifyCookie).toHaveBeenCalled(); + expect(UserController.verifyMe).toHaveBeenCalled(); + expect(response.status).toBe(200); + expect(response.body).toEqual(mockUser); // Marks completion of tests done(); }); + + it('should log out with POST /api/auth/logout', async (done) => { + const token = 'token'; + // Mock implementation for UserController.logout + UserController.logout.mockImplementation((req, res) => { + res.clearCookie(token); + res.status(200).send('Successfully logged out.'); + }); + + // Mock POST API call + const response = await request.post('/api/auth/logout').set('Cookie', token); + + // Tests + expect(AuthUtil.verifyCookie).toHaveBeenCalled(); + expect(UserController.logout).toHaveBeenCalled(); + expect(response.headers['set-cookie'][0]).toMatch(/token=;/); + expect(response.status).toBe(200); + expect(response.text).toBe('Successfully logged out.'); + + // Marks completion of tests + done(); + }); }); + }); From e7bbb53686932ad31207196e2744055d8078cc47 Mon Sep 17 00:00:00 2001 From: JamesNg Date: Tue, 17 Jun 2025 18:16:55 -0400 Subject: [PATCH 4/6] resolved mismatching of globalConfig --- backend/globalConfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/globalConfig.json b/backend/globalConfig.json index 6e8e3d60..9219d5f4 100644 --- a/backend/globalConfig.json +++ b/backend/globalConfig.json @@ -1 +1 @@ -{"mongoUri":"mongodb://127.0.0.1:37269/jest?","mongoDBName":"jest"} \ No newline at end of file +{"mongoUri":"mongodb://127.0.0.1:43943/jest?","mongoDBName":"jest"} \ No newline at end of file From 072fcb0f2c0df8a665228fb30e3f5013ed7f6a4a Mon Sep 17 00:00:00 2001 From: JamesNg Date: Tue, 17 Jun 2025 18:23:07 -0400 Subject: [PATCH 5/6] resolved mismatching of globalConfig --- backend/globalConfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/globalConfig.json b/backend/globalConfig.json index e69de29b..f09aa418 100644 --- a/backend/globalConfig.json +++ b/backend/globalConfig.json @@ -0,0 +1 @@ +{ "mongoUri": "mongodb://127.0.0.1:43943/jest?", "mongoDBName": "jest" } From efb1e8867f64b570c34ec160c8605ce27243bab9 Mon Sep 17 00:00:00 2001 From: JamesNg Date: Thu, 25 Sep 2025 17:39:47 -0400 Subject: [PATCH 6/6] work in progress --- .../python/env/Populate Projects.ipynb | 291 ++++++++++++++++-- backend/scripts/python/env/requirements.txt | 207 +++++++------ 2 files changed, 367 insertions(+), 131 deletions(-) diff --git a/backend/scripts/python/env/Populate Projects.ipynb b/backend/scripts/python/env/Populate Projects.ipynb index 36fd748c..6978986f 100644 --- a/backend/scripts/python/env/Populate Projects.ipynb +++ b/backend/scripts/python/env/Populate Projects.ipynb @@ -11,7 +11,7 @@ }, { "cell_type": "code", - "execution_count": 393, + "execution_count": 21, "id": "d04b046c-ad92-4f9b-a7d1-c900c1ff4581", "metadata": {}, "outputs": [], @@ -30,7 +30,9 @@ "\n", "load_dotenv()\n", "custom_request_header = os.getenv(\"CUSTOM_REQUEST_HEADER\")\n", - "DATABASE_URL = os.getenv(\"DATABASE_URL\")" + "DATABASE_URL = os.getenv(\"DATABASE_URL\")\n", + "\n", + "OPERATE_ON_LIVE_DATA = True" ] }, { @@ -43,7 +45,7 @@ }, { "cell_type": "code", - "execution_count": 395, + "execution_count": 8, "id": "33d48fca-a40d-4619-b97b-46b598258967", "metadata": {}, "outputs": [ @@ -73,13 +75,45 @@ }, { "cell_type": "code", - "execution_count": 396, + "execution_count": 22, + "id": "27434cbf-0ecd-477d-889b-9ecd3a53e6aa", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Operate on live data is: True\n" + ] + } + ], + "source": [ + "print(f\"Operate on live data is: {OPERATE_ON_LIVE_DATA}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 23, "id": "68a7e8a9-e3f3-4231-8424-8b8dd44f522f", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Database(MongoClient(host=['cluster0-shard-00-01.5buwz.mongodb.net:27017', 'cluster0-shard-00-02.5buwz.mongodb.net:27017', 'cluster0-shard-00-00.5buwz.mongodb.net:27017'], document_class=dict, tz_aware=False, connect=True, retrywrites=True, w='majority', authsource='admin', replicaset='atlas-rl9oiw-shard-0', tls=True), 'vrms-test')\n" + ] + } + ], "source": [ "db_source = client['vrms-test']\n", - "db_copy = client['vrms-populate-projects-test']" + "db_copy = None\n", + "\n", + "if OPERATE_ON_LIVE_DATA:\n", + " db_copy = client['vrms-test']\n", + "else:\n", + " db_copy = client['vrms-populate-projects-test']\n", + "print(db_copy)" ] }, { @@ -92,14 +126,28 @@ }, { "cell_type": "code", - "execution_count": 405, + "execution_count": 12, "id": "a4cb07f2-3e55-4a2e-8358-96bf67ebf354", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dropped collection: users\n", + "Dropped collection: projects\n", + "[]\n" + ] + } + ], "source": [ - "# for collection_name in db_copy.list_collection_names():\n", - "# db_copy.drop_collection(collection_name)\n", - "# print(f\"Dropped collection: {collection_name}\")" + "if OPERATE_ON_LIVE_DATA == False:\n", + " for collection_name in db_copy.list_collection_names():\n", + " db_copy.drop_collection(collection_name)\n", + " print(f\"Dropped collection: {collection_name}\")\n", + " print(db_copy.list_collection_names())\n", + "else:\n", + " print('Skipping this step')" ] }, { @@ -112,10 +160,18 @@ }, { "cell_type": "code", - "execution_count": 398, + "execution_count": 25, "id": "fd46eb06-d246-455e-8f48-a4e5df0efc9a", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Skipping this step\n" + ] + } + ], "source": [ "users_collection = db_source['users']\n", "users = list(users_collection.find())\n", @@ -126,11 +182,15 @@ "projects_copy = db_copy['projects']\n", "\n", "try:\n", - " users_copy.insert_many(users, ordered=False) # Copy source db users to test db users\n", - " projects_copy.insert_many(projects, ordered=False) # Copy source db projects to test db projects\n", + " if OPERATE_ON_LIVE_DATA == False:\n", + " users_copy.insert_many(users, ordered=False) # Copy source db users to test db users\n", + " projects_copy.insert_many(projects, ordered=False) # Copy source db projects to test db projects\n", + " print(db_copy.list_collection_names())\n", + " else:\n", + " print('Skipping database insertions')\n", "except BulkWriteError as bwe:\n", " print(\"BulkWriteError details:\")\n", - " print(bwe.details) # This contains info on which documents failed and why" + " print(bwe.details) # This contains info on which documents failed and why\n" ] }, { @@ -145,10 +205,76 @@ }, { "cell_type": "code", - "execution_count": 399, + "execution_count": 26, "id": "d4f52891-72c0-440c-8ef1-0f2102cebdb1", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[{'__v': 0,\n", + " '_id': ObjectId('6481155fab091f001e30925b'),\n", + " 'accessLevel': 'admin',\n", + " 'createdDate': datetime.datetime(2023, 6, 7, 23, 40, 15, 196000),\n", + " 'currentRole': 'Product Manager',\n", + " 'desiredRole': 'Product Manager',\n", + " 'email': 'jhaeger30@gmail.com',\n", + " 'firstAttended': 'JUN 2023',\n", + " 'managedProjects': ['68a3e64ee2653c001fe3ff3b'],\n", + " 'name': {'firstName': 'Jack', 'lastName': 'Haeger'},\n", + " 'newMember': False,\n", + " 'projects': [],\n", + " 'skillsToMatch': [],\n", + " 'textingOk': False},\n", + " {'__v': 0,\n", + " '_id': ObjectId('66024c13e6a0050028e07948'),\n", + " 'accessLevel': 'user',\n", + " 'createdDate': datetime.datetime(2024, 3, 26, 4, 16, 19, 45000),\n", + " 'currentRole': 'PM',\n", + " 'desiredRole': 'PM',\n", + " 'email': 'jack.haeger@gmail.com',\n", + " 'firstAttended': 'MAR 2024',\n", + " 'isActive': True,\n", + " 'managedProjects': ['68a3e64ee2653c001fe3ff3b'],\n", + " 'name': {'firstName': 'Jack', 'lastName': 'Haeger-PM'},\n", + " 'newMember': True,\n", + " 'projects': [],\n", + " 'skillsToMatch': [],\n", + " 'textingOk': False},\n", + " {'__v': 3,\n", + " '_id': ObjectId('670dd397cace6a002abb20ce'),\n", + " 'accessLevel': 'admin',\n", + " 'createdDate': datetime.datetime(2024, 10, 15, 2, 29, 43, 441000),\n", + " 'currentRole': 'Full Stack Developer',\n", + " 'desiredRole': 'Full Stack Developer',\n", + " 'email': 'njames15@gmail.com',\n", + " 'firstAttended': 'OCT 2024',\n", + " 'isActive': True,\n", + " 'managedProjects': ['68a3e64ee2653c001fe3ff3b', '68a3e75ea19d60385b3938f8'],\n", + " 'name': {'firstName': 'James', 'lastName': 'Ng'},\n", + " 'newMember': False,\n", + " 'projects': [],\n", + " 'skillsToMatch': [],\n", + " 'textingOk': False},\n", + " {'__v': 0,\n", + " '_id': ObjectId('68d1ffc4e2653c001fe400c9'),\n", + " 'accessLevel': 'admin',\n", + " 'createdDate': datetime.datetime(2025, 9, 23, 2, 2, 44, 786000),\n", + " 'currentRole': 'Software Engineer',\n", + " 'desiredRole': 'Software Engineer',\n", + " 'email': 'simmigon.flagg@gmail.com',\n", + " 'firstAttended': 'SEP 2025',\n", + " 'isActive': True,\n", + " 'managedProjects': ['5edeac78ce228b001778facd'],\n", + " 'name': {'firstName': 'Simmigon', 'lastName': 'Flagg'},\n", + " 'newMember': True,\n", + " 'projects': [],\n", + " 'skillsToMatch': [],\n", + " 'textingOk': False}]\n" + ] + } + ], "source": [ "query = {\n", " \"managedProjects\": { \n", @@ -157,7 +283,8 @@ " }\n", "}\n", "\n", - "target_users = list(users_copy.find(query))" + "target_users = list(users_copy.find(query))\n", + "pp.pprint(target_users)" ] }, { @@ -172,7 +299,7 @@ }, { "cell_type": "code", - "execution_count": 400, + "execution_count": 27, "id": "dd384405-c9bc-4b00-bb9b-8dcd4be0e9ba", "metadata": {}, "outputs": [ @@ -180,7 +307,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'68a3e64ee2653c001fe3ff3b': [ObjectId('6481155fab091f001e30925b'),\n", + "{'5edeac78ce228b001778facd': [ObjectId('68d1ffc4e2653c001fe400c9')],\n", + " '68a3e64ee2653c001fe3ff3b': [ObjectId('6481155fab091f001e30925b'),\n", " ObjectId('66024c13e6a0050028e07948'),\n", " ObjectId('670dd397cace6a002abb20ce')],\n", " '68a3e75ea19d60385b3938f8': [ObjectId('670dd397cace6a002abb20ce')]}\n" @@ -222,7 +350,7 @@ }, { "cell_type": "code", - "execution_count": 404, + "execution_count": 28, "id": "f280d029-47ed-46ef-a8d1-731071600a49", "metadata": {}, "outputs": [ @@ -239,9 +367,7 @@ " 'githubUrl': 'lkjlk',\n", " 'googleDriveUrl': 'https://drive.google.com/drive/folders/1hAq0wyZKOaZLujqOYiaFv5PYgooISger?usp=drive_link',\n", " 'hflaWebsiteUrl': 'lkjlkj',\n", - " 'managedByUsers': [ObjectId('6481155fab091f001e30925b'),\n", - " ObjectId('66024c13e6a0050028e07948'),\n", - " ObjectId('670dd397cace6a002abb20ce')],\n", + " 'managedByUsers': [],\n", " 'name': 'Jacks Test Project',\n", " 'partners': [],\n", " 'projectStatus': 'Active',\n", @@ -256,13 +382,34 @@ " 'githubUrl': 'afk',\n", " 'googleDriveUrl': 'https://drive.google.com/test',\n", " 'hflaWebsiteUrl': 'afk',\n", - " 'managedByUsers': [ObjectId('670dd397cace6a002abb20ce')],\n", + " 'managedByUsers': [],\n", " 'name': 'VRMS Test Project',\n", " 'partners': [],\n", " 'projectStatus': 'Active',\n", " 'recruitingCategories': [],\n", " 'slackUrl': 'afk'}\n", - "Result: BulkWriteResult({'writeErrors': [], 'writeConcernErrors': [], 'nInserted': 0, 'nUpserted': 0, 'nMatched': 2, 'nModified': 0, 'nRemoved': 0, 'upserted': []}, acknowledged=True)\n" + "Project before update:\n", + "{'__v': 0,\n", + " '_id': ObjectId('5edeac78ce228b001778facd'),\n", + " 'createdDate': datetime.datetime(2020, 6, 8, 21, 24, 8, 313000),\n", + " 'description': 'VRMS is a tool used for the engagement, support, and '\n", + " 'retention of a network of volunteers.',\n", + " 'githubIdentifier': '226157870',\n", + " 'githubUrl': 'https://github.com/hackforla/VRMS',\n", + " 'googleDriveId': '1uxCkpcPtDjrhftBO-axU2g8hjXsxiLiS',\n", + " 'googleDriveUrl': 'https://drive.google.com/drive/folders/1uxCkpcPtDjrhftBO-axU2g8hjXsxiLiS',\n", + " 'hflaWebsiteUrl': 'https://www.hackforla.org/projects/vrms',\n", + " 'location': 'DTLA',\n", + " 'lookingDescription': '- Front end devs (any level) \\n'\n", + " ' - Back end devs (any level)',\n", + " 'managedByUsers': [],\n", + " 'name': 'VRMS',\n", + " 'partners': ['TBD'],\n", + " 'projectStatus': 'Active',\n", + " 'recruitingCategories': [],\n", + " 'slackUrl': 'https://hackforla.slack.com/archives/CRGH5HM0Q',\n", + " 'videoConferenceLink': 'https://us02web.zoom.us/j/4451450308?pwd=U0JobzZqN0xGSXBUUkRsNlB5YzJiQT09'}\n", + "Result: BulkWriteResult({'writeErrors': [], 'writeConcernErrors': [], 'nInserted': 0, 'nUpserted': 0, 'nMatched': 3, 'nModified': 3, 'nRemoved': 0, 'upserted': []}, acknowledged=True)\n" ] } ], @@ -291,6 +438,96 @@ "\n", "print(f\"Result: \", result)" ] + }, + { + "cell_type": "markdown", + "id": "e50a4c4b-fe7a-45fa-bb4c-aab60ef2ffa5", + "metadata": {}, + "source": [ + "## Confirm Projects have been updated" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "6fa0e77b-96bc-4117-83b8-59431f68ff5c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Project after update:\n", + "{'__v': 0,\n", + " '_id': ObjectId('68a3e64ee2653c001fe3ff3b'),\n", + " 'createdDate': datetime.datetime(2025, 8, 19, 2, 49, 50, 843000),\n", + " 'description': 'Testing...',\n", + " 'githubIdentifier': 'lkjlkj',\n", + " 'githubUrl': 'lkjlk',\n", + " 'googleDriveUrl': 'https://drive.google.com/drive/folders/1hAq0wyZKOaZLujqOYiaFv5PYgooISger?usp=drive_link',\n", + " 'hflaWebsiteUrl': 'lkjlkj',\n", + " 'managedByUsers': [ObjectId('6481155fab091f001e30925b'),\n", + " ObjectId('66024c13e6a0050028e07948'),\n", + " ObjectId('670dd397cace6a002abb20ce')],\n", + " 'name': 'Jacks Test Project',\n", + " 'partners': [],\n", + " 'projectStatus': 'Active',\n", + " 'recruitingCategories': [],\n", + " 'slackUrl': 'lkjlkj'}\n", + "Project after update:\n", + "{'__v': 0,\n", + " '_id': ObjectId('68a3e75ea19d60385b3938f8'),\n", + " 'createdDate': datetime.datetime(2025, 8, 19, 2, 54, 22, 871000),\n", + " 'description': 'afk',\n", + " 'githubIdentifier': 'afk',\n", + " 'githubUrl': 'afk',\n", + " 'googleDriveUrl': 'https://drive.google.com/test',\n", + " 'hflaWebsiteUrl': 'afk',\n", + " 'managedByUsers': [ObjectId('670dd397cace6a002abb20ce')],\n", + " 'name': 'VRMS Test Project',\n", + " 'partners': [],\n", + " 'projectStatus': 'Active',\n", + " 'recruitingCategories': [],\n", + " 'slackUrl': 'afk'}\n", + "Project after update:\n", + "{'__v': 0,\n", + " '_id': ObjectId('5edeac78ce228b001778facd'),\n", + " 'createdDate': datetime.datetime(2020, 6, 8, 21, 24, 8, 313000),\n", + " 'description': 'VRMS is a tool used for the engagement, support, and '\n", + " 'retention of a network of volunteers.',\n", + " 'githubIdentifier': '226157870',\n", + " 'githubUrl': 'https://github.com/hackforla/VRMS',\n", + " 'googleDriveId': '1uxCkpcPtDjrhftBO-axU2g8hjXsxiLiS',\n", + " 'googleDriveUrl': 'https://drive.google.com/drive/folders/1uxCkpcPtDjrhftBO-axU2g8hjXsxiLiS',\n", + " 'hflaWebsiteUrl': 'https://www.hackforla.org/projects/vrms',\n", + " 'location': 'DTLA',\n", + " 'lookingDescription': '- Front end devs (any level) \\n'\n", + " ' - Back end devs (any level)',\n", + " 'managedByUsers': [ObjectId('68d1ffc4e2653c001fe400c9')],\n", + " 'name': 'VRMS',\n", + " 'partners': ['TBD'],\n", + " 'projectStatus': 'Active',\n", + " 'recruitingCategories': [],\n", + " 'slackUrl': 'https://hackforla.slack.com/archives/CRGH5HM0Q',\n", + " 'videoConferenceLink': 'https://us02web.zoom.us/j/4451450308?pwd=U0JobzZqN0xGSXBUUkRsNlB5YzJiQT09'}\n" + ] + } + ], + "source": [ + "for proj_id, user_ids in projects_users.items():\n", + " proj = projects_copy.find_one({\"_id\": ObjectId(proj_id)})\n", + " if proj:\n", + " print('Project after update:')\n", + " pp.pprint(proj)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7c1423a-b538-4d06-8268-93547755c199", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/backend/scripts/python/env/requirements.txt b/backend/scripts/python/env/requirements.txt index f3c9e906..8a082757 100644 --- a/backend/scripts/python/env/requirements.txt +++ b/backend/scripts/python/env/requirements.txt @@ -1,104 +1,103 @@ -anyio==4.9.0 -argon2-cffi==25.1.0 -argon2-cffi-bindings==25.1.0 -arrow==1.3.0 -asttokens==3.0.0 -async-lru==2.0.5 -attrs==25.3.0 -babel==2.17.0 -beautifulsoup4==4.13.4 -bleach==6.2.0 -certifi==2025.7.14 -cffi==1.17.1 -charset-normalizer==3.4.2 -colorama==0.4.6 -comm==0.2.3 -debugpy==1.8.15 -decorator==5.2.1 -defusedxml==0.7.1 -dnspython==2.7.0 -dotenv==0.9.9 -executing==2.2.0 -fastjsonschema==2.21.1 -fqdn==1.5.1 -h11==0.16.0 -httpcore==1.0.9 -httpx==0.28.1 -idna==3.10 -ipykernel==6.30.0 -ipython==9.4.0 -ipython_pygments_lexers==1.1.1 -ipywidgets==8.1.7 -isoduration==20.11.0 -jedi==0.19.2 -Jinja2==3.1.6 -json5==0.12.0 -jsonpointer==3.0.0 -jsonschema==4.25.0 -jsonschema-specifications==2025.4.1 -jupyter==1.1.1 -jupyter-console==6.6.3 -jupyter-events==0.12.0 -jupyter-lsp==2.2.6 -jupyter_client==8.6.3 -jupyter_core==5.8.1 -jupyter_server==2.16.0 -jupyter_server_terminals==0.5.3 -jupyterlab==4.4.5 -jupyterlab_pygments==0.3.0 -jupyterlab_server==2.27.3 -jupyterlab_widgets==3.0.15 -lark==1.2.2 -MarkupSafe==3.0.2 -matplotlib-inline==0.1.7 -mistune==3.1.3 -nbclient==0.10.2 -nbconvert==7.16.6 -nbformat==5.10.4 -nest-asyncio==1.6.0 -notebook==7.4.4 -notebook_shim==0.2.4 -overrides==7.7.0 -packaging==25.0 -pandocfilters==1.5.1 -parso==0.8.4 -platformdirs==4.3.8 -prometheus_client==0.22.1 -prompt_toolkit==3.0.51 -psutil==7.0.0 -pure_eval==0.2.3 -pycparser==2.22 -Pygments==2.19.2 -pymongo==4.13.2 -python-dateutil==2.9.0.post0 -python-dotenv==1.1.1 -python-json-logger==3.3.0 -pywin32==311 -pywinpty==2.0.15 -PyYAML==6.0.2 -pyzmq==27.0.0 -referencing==0.36.2 -requests==2.32.4 -rfc3339-validator==0.1.4 -rfc3986-validator==0.1.1 -rfc3987-syntax==1.1.0 -rpds-py==0.26.0 -Send2Trash==1.8.3 -setuptools==80.9.0 -six==1.17.0 -sniffio==1.3.1 -soupsieve==2.7 -stack-data==0.6.3 -terminado==0.18.1 -tinycss2==1.4.0 -tornado==6.5.1 -traitlets==5.14.3 -types-python-dateutil==2.9.0.20250708 -typing_extensions==4.14.1 -uri-template==1.3.0 -urllib3==2.5.0 -wcwidth==0.2.13 -webcolors==24.11.1 -webencodings==0.5.1 -websocket-client==1.8.0 -widgetsnbextension==4.0.14 +anyio<=4 +# argon2-cffi<=25.1.0 +argon2-cffi-bindings<=25.1.0 +arrow<=1.3.0 +asttokens<=3.0.0 +async-lru<=2.0.5 +# attrs<=25.3.0 +babel<=2.17.0 +# beautifulsoup4<=4.13.4 +bleach<=6.2.0 +# certifi<=2025.7.14 +cffi<=1.17.1 +charset-normalizer<=3.4.2 +# colorama<=0.4.6 +comm<=0.2.3 +debugpy<=1.8.15 +decorator<=5.2.1 +defusedxml<=0.7.1 +dnspython<=2.7.0 +dotenv<=0.9.9 +executing<=2.2.0 +fastjsonschema<=2.21.1 +fqdn<=1.5.1 +h11<=0.16.0 +httpcore<=1.0.9 +httpx<=0.28.1 +idna<=3.10 +ipykernel<=6.30.0 +ipython<=9.4.0 +ipython_pygments_lexers<=1.1.1 +ipywidgets<=8.1.7 +isoduration<=20.11.0 +jedi<=0.19.2 +Jinja2<=3.1.6 +json5<=0.12.0 +jsonpointer<=3.0.0 +jsonschema<=4.25.0 +jsonschema-specifications<=2025.4.1 +jupyter<=1.1.1 +jupyter-console<=6.6.3 +jupyter-events<=0.12.0 +jupyter-lsp<=2.2.6 +jupyter_client<=8.6.3 +jupyter_core<=5.8.1 +jupyter_server<=2.16.0 +jupyter_server_terminals<=0.5.3 +jupyterlab<=4.4.5 +jupyterlab_pygments<=0.3.0 +jupyterlab_server<=2.27.3 +jupyterlab_widgets<=3.0.15 +lark<=1.2.2 +MarkupSafe<=3.0.2 +matplotlib-inline<=0.1.7 +mistune<=3.1.3 +nbclient<=0.10.2 +nbconvert<=7.16.6 +nbformat<=5.10.4 +nest-asyncio<=1.6.0 +notebook<=7.4.4 +notebook_shim<=0.2.4 +overrides<=7.7.0 +packaging<=25.0 +pandocfilters<=1.5.1 +parso<=0.8.4 +platformdirs<=4.3.8 +prometheus_client<=0.22.1 +prompt_toolkit<=3.0.51 +psutil<=7.0.0 +pure_eval<=0.2.3 +pycparser<=2.22 +Pygments<=2.19.2 +pymongo<=4.13.2 +python-dateutil<=2.9.0.post0 +python-dotenv<=1.1.1 +python-json-logger<=3.3.0 +# pywinpty<=2.0.15 +PyYAML<=6.0.2 +pyzmq<=27.0.0 +referencing<=0.36.2 +requests<=2.32.4 +rfc3339-validator<=0.1.4 +# rfc3986-validator<=0.1.1 +# rfc3987-syntax<=1.1.0 +rpds-py<=0.26.0 +Send2Trash<=1.8.3 +setuptools<=80.9.0 +six<=1.17.0 +sniffio<=1.3.1 +soupsieve<=2.7 +stack-data<=0.6.3 +terminado<=0.18.1 +tinycss2<=1.4.0 +tornado<=6.5.1 +traitlets<=5.14.3 +types-python-dateutil<=2.9.0.20250708 +typing_extensions<=4.14.1 +uri-template<=1.3.0 +urllib3<=2.5.0 +wcwidth<=0.2.13 +webcolors<=24.11.1 +webencodings<=0.5.1 +websocket-client<=1.8.0 +widgetsnbextension<=4.0.14