Skip to content

Commit d728ce2

Browse files
authored
feat(public): update parser for source materials
1 parent bdb816e commit d728ce2

17 files changed

+299
-176
lines changed

CONTRIBUTING.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,14 @@ Environment variables are required in order to locally run this API. Please find
5959

6060
### Starting the Development Server
6161

62-
You are now ready to start the development server, and interact with the API.
62+
- Run `npm run dev` to start the development server, and interact with the API.
6363

64-
- Run `npm run dev` to start the server.
65-
- Pleae note that when you are working with the front end applications, the congregation request is automatically approved.
64+
### Creating Your Congregation Account
65+
66+
As each development server will start with a new and clean Firebase Emulator instance, you have to create your user and congregation account.
67+
68+
- When creating user account, the use of authenticator app is optional. When required, the OTP code is printed on the dev console. If you still want to use authenticator app, you have to delete and create a new account each time you run the dev server.
69+
- The congregation request is automatically approved.
6670

6771
## Sending a Pull Request (PR)
6872

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Get active source materials using EPUB file downloaded on the fly from JW.ORG.
1313

1414
#### `lang`
1515

16-
Language code of the materials you want to fetch. Currently, only English (`e`) and Malagasy (`mg`) are supported.
16+
Language code of the materials you want to fetch.
1717

1818
#### Response
1919

package-lock.json

Lines changed: 26 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"geoip-lite": "^1.4.6",
4141
"helmet": "^6.0.1",
4242
"is-online": "^10.0.0",
43-
"jw-epub-parser": "^1.29.0",
43+
"jw-epub-parser": "^1.30.0-alpha.7",
4444
"node-2fa": "^2.0.3",
4545
"node-fetch": "^3.3.0",
4646
"nodemailer": "^6.8.0",

src/app.js

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -24,46 +24,46 @@ import { errorHandler, getAppVersion, getRoot, invalidEndpointHandler } from './
2424

2525
// allowed apps url
2626
const whitelist = [
27-
'https://alpha-sws-pocket.web.app',
28-
'https://alpha-sws-pocket.firebaseapp.com',
29-
'https://sws-pocket.web.app',
30-
'https://sws-pocket.firebaseapp.com',
31-
'https://lmm-oa-sws.web.app',
32-
'https://lmm-oa-sws.firebaseapp.com',
33-
'https://sws-apps-dev.web.app',
34-
'https://sws-apps-dev.firebaseapp.com',
35-
'https://sws2apps-tools.web.app',
36-
'https://sws2apps-tools.firebaseapp.com',
27+
'https://alpha-sws-pocket.web.app',
28+
'https://alpha-sws-pocket.firebaseapp.com',
29+
'https://sws-pocket.web.app',
30+
'https://sws-pocket.firebaseapp.com',
31+
'https://lmm-oa-sws.web.app',
32+
'https://lmm-oa-sws.firebaseapp.com',
33+
'https://sws-apps-dev.web.app',
34+
'https://sws-apps-dev.firebaseapp.com',
35+
'https://sws2apps-tools.web.app',
36+
'https://sws2apps-tools.firebaseapp.com',
3737
];
3838

3939
const allowedUri = ['/app-version', '/api/public/source-material'];
4040

4141
const corsOptionsDelegate = function (req, callback) {
42-
var corsOptions;
43-
44-
if (process.env.NODE_ENV === 'production') {
45-
const reqOrigin = req.header('Origin');
46-
if (reqOrigin) {
47-
if (whitelist.indexOf(reqOrigin) !== -1) {
48-
corsOptions = { origin: true }; // reflect (enable) the requested origin in the CORS response
49-
} else {
50-
const originalUri = req.headers['x-original-uri'];
51-
52-
if (originalUri === '/') {
53-
corsOptions = { origin: true }; // allow CORS for index route
54-
} else {
55-
const allowed = allowedUri.find((uri) => uri.startsWith(originalUri)) ? true : false;
56-
corsOptions = { origin: allowed };
57-
}
58-
}
59-
} else {
60-
corsOptions = { origin: false };
61-
}
62-
} else {
63-
corsOptions = { origin: true }; // allow cors during dev
64-
}
65-
66-
callback(null, corsOptions); // callback expects two parameters: error and options
42+
var corsOptions;
43+
44+
if (process.env.NODE_ENV === 'production') {
45+
const reqOrigin = req.header('Origin');
46+
if (reqOrigin) {
47+
if (whitelist.indexOf(reqOrigin) !== -1) {
48+
corsOptions = { origin: true }; // reflect (enable) the requested origin in the CORS response
49+
} else {
50+
const originalUri = req.headers['x-original-uri'];
51+
52+
if (originalUri === '/') {
53+
corsOptions = { origin: true }; // allow CORS for index route
54+
} else {
55+
const allowed = allowedUri.find((uri) => uri.startsWith(originalUri)) ? true : false;
56+
corsOptions = { origin: allowed };
57+
}
58+
}
59+
} else {
60+
corsOptions = { origin: false };
61+
}
62+
} else {
63+
corsOptions = { origin: true }; // allow cors during dev
64+
}
65+
66+
callback(null, corsOptions); // callback expects two parameters: error and options
6767
};
6868

6969
const app = express();
@@ -84,13 +84,13 @@ app.use(requestChecker());
8484
app.use(updateTracker());
8585

8686
app.use(
87-
rateLimit({
88-
windowMs: 1000,
89-
max: 20,
90-
message: JSON.stringify({
91-
message: 'TOO_MANY_REQUESTS',
92-
}),
93-
})
87+
rateLimit({
88+
windowMs: 1000,
89+
max: 20,
90+
message: JSON.stringify({
91+
message: 'TOO_MANY_REQUESTS',
92+
}),
93+
})
9494
);
9595

9696
app.use('/', authRoute);

src/classes/Congregation.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,10 @@ Congregation.prototype.saveBackup = async function (
116116
this.cong_sourceMaterial_draft = cong_sourceMaterial;
117117
this.cong_swsPocket = cong_swsPocket;
118118
this.cong_settings = cong_settings;
119-
this.last_backup.by = userInfo.username;
120-
this.last_backup.date = data.last_backup.date;
119+
this.last_backup = {
120+
by: userInfo.username,
121+
date: data.last_backup.date,
122+
};
121123
} catch (error) {
122124
throw new Error(error.message);
123125
}
@@ -148,6 +150,7 @@ Congregation.prototype.removeUser = async function (userId) {
148150
user.cong_id = '';
149151
user.cong_name = '';
150152
user.cong_number = '';
153+
user.cong_role = [];
151154

152155
// update congregation members
153156
this.reloadMembers();

src/classes/User.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,28 @@ User.prototype.updatePocketMembers = async function (members) {
119119
try {
120120
await db.collection('users').doc(this.id).update({ 'congregation.pocket_members': members });
121121
this.pocket_members = members;
122+
123+
// update cong members
124+
const cong = congregations.findCongregationById(this.cong_id);
125+
cong.reloadMembers();
126+
} catch (error) {
127+
throw new Error(error.message);
128+
}
129+
};
130+
131+
User.prototype.updatePocketLocalId = async function (id) {
132+
try {
133+
if (id !== '') {
134+
await db.collection('users').doc(this.id).update({ 'congregation.local_id': id });
135+
} else {
136+
await db.collection('users').doc(this.id).update({ 'congregation.local_id': FieldValue.delete() });
137+
}
138+
139+
this.pocket_local_id = id;
140+
141+
// update cong members
142+
const cong = congregations.findCongregationById(this.cong_id);
143+
cong.reloadMembers();
122144
} catch (error) {
123145
throw new Error(error.message);
124146
}
@@ -212,7 +234,7 @@ User.prototype.adminLogout = async function () {
212234
User.prototype.generateSecret = async function () {
213235
try {
214236
const isProd = process.env.NODE_ENV === 'production';
215-
237+
216238
if (this.secret && this.secret !== '') {
217239
const decryptedData = JSON.parse(decryptData(this.secret));
218240
return decryptedData;
@@ -423,4 +445,10 @@ User.prototype.updateSessionsInfo = async function (visitorid) {
423445
await db.collection('users').doc(this.id).update({ 'about.sessions': newSessions });
424446

425447
this.sessions = newSessions;
448+
449+
// update cong members
450+
if (this.cong_id !== '') {
451+
const cong = congregations.findCongregationById(this.cong_id);
452+
cong.reloadMembers();
453+
}
426454
};

src/config/mock.data.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { getFirestore } from 'firebase-admin/firestore';
33

44
const db = getFirestore();
55

6+
const isTesting = process.env.NODE_ENV === 'testing';
7+
68
// create admin user
79
export const createAdmin = async () => {
810
try {
@@ -20,7 +22,7 @@ export const createAdmin = async () => {
2022
name: 'admin',
2123
role: 'admin',
2224
user_uid: '[email protected]',
23-
mfaEnabled: true,
25+
mfaEnabled: isTesting ? true : false,
2426
},
2527
};
2628

src/controllers/admin-controller.js

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ export const getAllAnnouncements = async (req, res, next) => {
107107
}
108108
};
109109

110-
export const saveAnnouncementDraft = async (req, res, next) => {
110+
export const handleAnnouncementAction = async (req, res, next) => {
111111
try {
112112
const errors = validationResult(req);
113113

@@ -127,12 +127,24 @@ export const saveAnnouncementDraft = async (req, res, next) => {
127127
return;
128128
}
129129

130-
const { announcement } = req.body;
131-
const list = await announcements.saveDraft({ ...announcement, isDraft: true });
130+
let { action, announcement } = req.body;
131+
if (action !== 'publish') action = 'save';
132132

133-
res.locals.type = 'info';
134-
res.locals.message = 'draft announcement saved successfully';
135-
res.status(200).json(list);
133+
if (action === 'save') {
134+
const list = await announcements.saveDraft(announcement);
135+
136+
res.locals.type = 'info';
137+
res.locals.message = 'draft announcement saved successfully';
138+
res.status(200).json(list);
139+
}
140+
141+
if (action === 'publish') {
142+
const list = await announcements.publish(announcement);
143+
144+
res.locals.type = 'info';
145+
res.locals.message = 'announcement published successfully';
146+
res.status(200).json(list);
147+
}
136148
} catch (err) {
137149
next(err);
138150
}
@@ -206,37 +218,6 @@ export const deleteAnnouncementAdmin = async (req, res, next) => {
206218
}
207219
};
208220

209-
export const publishAnnouncementAdmin = async (req, res, next) => {
210-
try {
211-
const errors = validationResult(req);
212-
213-
if (!errors.isEmpty()) {
214-
let msg = '';
215-
errors.array().forEach((error) => {
216-
msg += `${msg === '' ? '' : ', '}${error.param}: ${error.msg}`;
217-
});
218-
219-
res.locals.type = 'warn';
220-
res.locals.message = `invalid input: ${msg}`;
221-
222-
res.status(400).json({
223-
message: 'Bad request: provided inputs are invalid.',
224-
});
225-
226-
return;
227-
}
228-
229-
const { announcement } = req.body;
230-
const list = await announcements.publish(announcement);
231-
232-
res.locals.type = 'info';
233-
res.locals.message = 'announcement published successfully';
234-
res.status(200).json(list);
235-
} catch (err) {
236-
next(err);
237-
}
238-
};
239-
240221
export const getAdminDashboard = async (req, res, next) => {
241222
try {
242223
const finalResult = congregationRequests.list;

0 commit comments

Comments
 (0)