Skip to content

Commit 9f7a4ae

Browse files
committed
resolve: remove package-lock.json
2 parents 8766eba + 22dd660 commit 9f7a4ae

7 files changed

Lines changed: 96 additions & 106 deletions

File tree

package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@
2828
"dev": "nodemon --exec \"babel-node --ignore 'node_modules/(?!@typespec)' src/server.js\"",
2929
"serve": "babel-node src/server.js",
3030
"prepare-macos-linux": "husky install && chmod ug+x .husky/* && chmod ug+x .git/hooks/*",
31-
"prepare": "husky install",
32-
"postinstall": "npx puppeteer browsers install chrome"
31+
"prepare": "husky install"
3332
},
3433
"author": "AK",
3534
"license": "ISC",
@@ -121,7 +120,7 @@
121120
"nodemailer": "^7.0.11",
122121
"parse-link-header": "^2.0.0",
123122
"pdfkit": "^0.17.2",
124-
"puppeteer": "^24.37.5",
123+
"playwright": "^1.58.2",
125124
"redis": "^4.2.0",
126125
"regression": "^2.0.1",
127126
"sanitize-html": "^2.16.0",

src/controllers/reportsController.js

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1+
/* eslint-disable no-console */
12
/* eslint-disable consistent-return */
23
const fs = require('node:fs');
34
const mongoose = require('mongoose');
45
// eslint-disable-next-line import/no-unresolved
5-
const puppeteer = require('puppeteer');
66
const reporthelperClosure = require('../helpers/reporthelper');
77
const overviewReportHelperClosure = require('../helpers/overviewReportHelper');
88
const { hasPermission } = require('../utilities/permissions');
99
const UserProfile = require('../models/userProfile');
1010
const emailSender = require('../utilities/emailSender');
1111
const cacheModule = require('../utilities/nodeCache');
12+
const playwrightLogic = require('../utilities/playwrightUtil');
1213

1314
const cacheUtil = cacheModule();
1415

@@ -783,37 +784,6 @@ const reportsController = function () {
783784
res.status(500).send({ msg: 'Error occured while fetching data. Please try again!' });
784785
}
785786
};
786-
const puppeteerLogic = async () => {
787-
const { PUPPETEER_EMAIL, PUPPETEER_PASSWORD, REACT_FRONTEND_URL } = process.env;
788-
if (!PUPPETEER_EMAIL || !PUPPETEER_PASSWORD) {
789-
console.log('Puppeteer email or password not found in environment variables');
790-
}
791-
const browser = await puppeteer.launch({
792-
headless: true,
793-
args: ['--no-sandbox', '--disable-setuid-sandbox'],
794-
});
795-
const page = await browser.newPage();
796-
await page.goto(`${REACT_FRONTEND_URL}/login`, { waitUntil: 'networkidle2' });
797-
await page.setViewport({
798-
width: 1920,
799-
height: 1080,
800-
deviceScaleFactor: 1.5,
801-
});
802-
await page.type('input[id="email"]', PUPPETEER_EMAIL, { delay: 100 });
803-
await page.type('input[id="password"]', PUPPETEER_PASSWORD, { delay: 100 });
804-
await page.click('.btn.btn-primary', { delay: 100 });
805-
await page.waitForNavigation({ waitUntil: 'networkidle2' });
806-
await page.goto(`${REACT_FRONTEND_URL}/totalorgsummary`, { waitUntil: 'networkidle2' });
807-
808-
// eslint-disable-next-line no-restricted-syntax
809-
await new Promise((resolve) => {
810-
setTimeout(resolve, 50000);
811-
});
812-
// take a screenshot of the page
813-
await page.screenshot({ path: 'weeklyCompanySummary.png', fullPage: true });
814-
// close the browser
815-
await browser.close();
816-
};
817787

818788
const sendEmailReport = async (req, res) => {
819789
try {
@@ -822,7 +792,7 @@ const reportsController = function () {
822792
return res.status(400).send({ msg: 'Please provide at least one recipient' });
823793
}
824794

825-
await puppeteerLogic();
795+
await playwrightLogic();
826796

827797
const attachment = {
828798
filename: 'weeklyCompanySummary.png',

src/controllers/teamController.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,11 @@ const teamcontroller = function (Team) {
166166

167167
// Store the old team code before updating
168168
const oldTeamCode = record.teamCode;
169-
const newTeamCode = req.body.teamCode;
169+
const newTeamCode = req.body.teamCode || '';
170170

171171
record.teamName = req.body.teamName;
172172
record.isActive = req.body.isActive;
173-
record.teamCode = req.body.teamCode;
173+
record.teamCode = newTeamCode;
174174
record.createdDatetime = Date.now();
175175
record.modifiedDatetime = Date.now();
176176

src/helpers/overviewReportHelper.js

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -963,33 +963,27 @@ const overviewReportHelper = function () {
963963

964964
/** aggregates role distribution statistics
965965
* counts total number of volunteers that fall within each of the different roles
966+
* NOTE: This shows ALL active users regardless of createdDate to provide
967+
* a complete picture of current role distribution in the organization
966968
*/
967969
async function getRoleDistributionStats(
968970
startDate,
969971
endDate,
970972
comparisonStartDate,
971973
comparisonEndDate,
972974
) {
973-
// Helper to build match stage depending on whether start/end are provided
974-
const buildMatch = (s, e) => {
975-
const match = { isActive: true };
976-
if (s && e) {
977-
match.createdDate = { $gte: new Date(s), $lte: new Date(e) };
978-
}
979-
return match;
980-
};
975+
// Always match only active users, ignore date filters for role distribution
976+
// This ensures all current roles are displayed, not just recently created users
977+
const buildMatch = () => ({ isActive: true });
981978

982979
// If comparison dates provided, return both current and comparison facets
983980
if (comparisonStartDate && comparisonEndDate) {
984981
const roleStats = await UserProfile.aggregate([
985982
{
986983
$facet: {
987-
current: [
988-
{ $match: buildMatch(startDate, endDate) },
989-
{ $group: { _id: '$role', count: { $sum: 1 } } },
990-
],
984+
current: [{ $match: buildMatch() }, { $group: { _id: '$role', count: { $sum: 1 } } }],
991985
comparison: [
992-
{ $match: buildMatch(comparisonStartDate, comparisonEndDate) },
986+
{ $match: buildMatch() },
993987
{ $group: { _id: '$role', count: { $sum: 1 } } },
994988
],
995989
},
@@ -1003,7 +997,7 @@ const overviewReportHelper = function () {
1003997
}
1004998

1005999
// No comparison: return same shape as before (array of {_id: role, count})
1006-
const matchStage = buildMatch(startDate, endDate);
1000+
const matchStage = buildMatch();
10071001
const result = await UserProfile.aggregate([
10081002
{ $match: matchStage },
10091003
{ $group: { _id: '$role', count: { $sum: 1 } } },

src/helpers/userHelper.js

Lines changed: 2 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
const path = require('node:path');
1414
const fs = require('fs');
1515
// eslint-disable-next-line import/no-unresolved
16-
const puppeteer = require('puppeteer');
1716
const mongoose = require('mongoose');
1817
const moment = require('moment-timezone');
1918
const _ = require('lodash');
@@ -34,10 +33,10 @@ const { NEW_USER_BLUE_SQUARE_NOTIFICATION_MESSAGE } = require('../constants/mess
3433
const timeUtils = require('../utilities/timeUtils');
3534
const Team = require('../models/team');
3635
const BlueSquareEmailAssignmentModel = require('../models/BlueSquareEmailAssignment');
36+
const playwrightLogic = require('../utilities/playwrightUtil');
3737
const myTeam = require('./helperModels/myTeam');
3838
const dashboardHelper = require('./dashboardhelper')();
3939
const reportHelper = require('./reporthelper')();
40-
4140
// eslint-disable-next-line no-promise-executor-return
4241
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
4342

@@ -3250,56 +3249,6 @@ const userHelper = function () {
32503249
}
32513250
};
32523251

3253-
const puppeteerLogic = async () => {
3254-
// get login details from env
3255-
const { PUPPETEER_EMAIL, PUPPETEER_PASSWORD, REACT_FRONTEND_URL } = process.env;
3256-
if (!PUPPETEER_EMAIL || !PUPPETEER_PASSWORD) {
3257-
logger.logError('Puppeteer email or password not found in environment variables');
3258-
}
3259-
// launch puppeteer
3260-
const browser = await puppeteer.launch({
3261-
headless: true,
3262-
args: ['--no-sandbox', '--disable-setuid-sandbox'],
3263-
});
3264-
const page = await browser.newPage();
3265-
// navigate to the login page
3266-
await page.goto(`${REACT_FRONTEND_URL}/login`, { waitUntil: 'networkidle2' });
3267-
await page.setViewport({
3268-
width: 1920,
3269-
height: 1080,
3270-
deviceScaleFactor: 1.5,
3271-
});
3272-
// enter email and password
3273-
await page.type('input[id="email"]', PUPPETEER_EMAIL, { delay: 100 });
3274-
await page.type('input[id="password"]', PUPPETEER_PASSWORD, { delay: 100 });
3275-
// click the login button
3276-
// await page.click('button[type="submit"]', { delay: 100 });
3277-
await page.click('.btn.btn-primary', { delay: 100 });
3278-
// wait for navigation to complete
3279-
await page.waitForNavigation({ waitUntil: 'networkidle2' });
3280-
3281-
// go to /totalorgsummary
3282-
await page.goto(`${REACT_FRONTEND_URL}/totalorgsummary`, { waitUntil: 'networkidle2' });
3283-
3284-
// click on all toggle elements
3285-
const elements = await page.$$('.accordian-trigger');
3286-
3287-
console.log('elements', elements);
3288-
3289-
// Looping through and interacting with each element
3290-
for (const element of elements) {
3291-
await element.click();
3292-
await page.waitForTimeout(1000); // wait for the animation to complete
3293-
}
3294-
await page.waitForTimeout(50000);
3295-
// take a screenshot of the page
3296-
// await page.setViewport({ width: 1920, height: 1080 });
3297-
await page.screenshot({ path: 'weeklyCompanySummary.png', fullPage: true });
3298-
3299-
// close the browser
3300-
await browser.close();
3301-
};
3302-
33033252
// Weekly Company Summary Email
33043253
const weeklyCompanySummaryEmail = async () => {
33053254
console.log('Weekly Company Summary Email');
@@ -3313,7 +3262,7 @@ const userHelper = function () {
33133262
<p>One Community</p>`;
33143263

33153264
// generate screenshot
3316-
await puppeteerLogic();
3265+
await playwrightLogic();
33173266
console.log('Puppeteer logic completed');
33183267

33193268
// create an attachment object

src/routes/educationRouter.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
const express = require('express');
2-
32
const controller = require('../controllers/educationUserProfileController');
43

54
const studentProfileRouter = express.Router();

src/utilities/playwrightUtil.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/* eslint-disable no-console */
2+
const { execSync } = require('node:child_process');
3+
const { chromium } = require('playwright');
4+
5+
async function ensureBrowserInstalled() {
6+
try {
7+
// Try launching once
8+
const browser = await chromium.launch({
9+
headless: true,
10+
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
11+
});
12+
await browser.close();
13+
} catch (err) {
14+
console.warn('Browser launch failed, attempting install...', err);
15+
16+
try {
17+
// Force install without relying on .bin/playwright
18+
execSync('node node_modules/playwright/cli.js install chromium', {
19+
stdio: 'inherit',
20+
});
21+
} catch (installErr) {
22+
console.error('Playwright browser installation failed:', installErr);
23+
throw installErr;
24+
}
25+
}
26+
}
27+
28+
const playwrightLogic = async () => {
29+
try {
30+
const { PUPPETEER_EMAIL, PUPPETEER_PASSWORD, REACT_FRONTEND_URL } = process.env;
31+
32+
if (!PUPPETEER_EMAIL || !PUPPETEER_PASSWORD) {
33+
console.log('Playwright email or password not found in environment variables');
34+
}
35+
36+
await ensureBrowserInstalled();
37+
38+
const browser = await chromium.launch({
39+
headless: true,
40+
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
41+
});
42+
43+
const context = await browser.newContext({
44+
viewport: { width: 1920, height: 1080 },
45+
});
46+
47+
const page = await context.newPage();
48+
49+
// Login page
50+
await page.goto(`${REACT_FRONTEND_URL}/login`, { waitUntil: 'networkidle' });
51+
52+
await page.fill('input[id="email"]', PUPPETEER_EMAIL);
53+
await page.fill('input[id="password"]', PUPPETEER_PASSWORD);
54+
55+
await page.click('.btn.btn-primary');
56+
57+
// Wait for navigation after login
58+
await page.waitForNavigation({ waitUntil: 'networkidle' });
59+
60+
// Navigate to report page
61+
await page.goto(`${REACT_FRONTEND_URL}/totalorgsummary`, { waitUntil: 'networkidle' });
62+
63+
// Wait for full load (instead of setTimeout)
64+
await page.waitForLoadState('networkidle');
65+
66+
// Screenshot
67+
await page.screenshot({
68+
path: 'weeklyCompanySummary.png',
69+
fullPage: true,
70+
});
71+
72+
await browser.close();
73+
} catch (err) {
74+
console.error('Playwright error:', err);
75+
throw err;
76+
}
77+
};
78+
79+
module.exports = playwrightLogic;

0 commit comments

Comments
 (0)