Skip to content

Commit b1a55f3

Browse files
Merge pull request #1322 from OneCommunityGlobal/development
Backend Release to Main [2.27]
2 parents 1b5c768 + 3497be0 commit b1a55f3

14 files changed

Lines changed: 1337 additions & 419 deletions

package-lock.json

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

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@
3333
"eslint-config-prettier": "^9.1.0",
3434
"eslint-import-resolver-babel-module": "^5.3.1",
3535
"eslint-plugin-import": "^2.28.0",
36-
"husky": "^8.0.1",
37-
"jest": "^29.7.0",
3836
"eslint-plugin-jsx-a11y": "^6.7.1",
3937
"eslint-plugin-react": "^7.33.1",
4038
"eslint-plugin-react-hooks": "^4.6.0",
39+
"husky": "^8.0.1",
40+
"jest": "^29.7.0",
4141
"lint-staged": "^13.0.3",
4242
"mongodb-memory-server": "^7.2.1",
4343
"nodemon": "^3.0.1",
@@ -59,7 +59,7 @@
5959
"babel-plugin-module-resolver": "^5.0.0",
6060
"bcryptjs": "^2.4.3",
6161
"body-parser": "^1.18.3",
62-
"cheerio": "^1.0.0-rc.12",
62+
"cheerio": "^0.22.0",
6363
"cors": "^2.8.4",
6464
"cron": "^1.8.2",
6565
"dotenv": "^5.0.1",

src/controllers/badgeController.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const UserProfile = require('../models/userProfile');
33
const helper = require('../utilities/permissions');
44
const escapeRegex = require('../utilities/escapeRegex');
55
const cacheClosure = require('../utilities/nodeCache');
6-
// const userHelper = require('../helpers/userHelper')();
6+
//const userHelper = require('../helpers/userHelper')();
77

88
const badgeController = function (Badge) {
99
/**
@@ -343,7 +343,7 @@ const badgeController = function (Badge) {
343343

344344

345345
return {
346-
// awardBadgesTest,
346+
//awardBadgesTest,
347347
getAllBadges,
348348
assignBadges,
349349
postBadge,

src/controllers/formController.js

Lines changed: 338 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
const userprofile=require('../models/userProfile');
2+
3+
const formController = function (Form,formResponse) {
4+
// creating a new form
5+
const createForm =async function (req,res) {
6+
try {
7+
const { formName, questions, createdBy } = req.body;
8+
9+
// Check if required fields are present
10+
if (!formName || !questions || questions.length === 0) {
11+
return res.status(400).json({ message: 'Form name and questions are required.' });
12+
}
13+
14+
// check if form already exists or not
15+
let form_temp=await Form.find({formName:formName})
16+
if(form_temp.length>0){return res.status(400).json({message:"Form already exists with that name"})}
17+
// Create a new form with the provided structure
18+
const newForm = new Form({
19+
formName,
20+
questions,
21+
createdBy,
22+
});
23+
24+
// Save the form in the database
25+
const savedForm = await newForm.save();
26+
27+
// Generate a unique link to the form
28+
const formLink = `/forms/${savedForm.formID}`;
29+
30+
return res.status(201).json({
31+
message: 'Form created successfully',
32+
formID: savedForm.formID,
33+
id:savedForm._id,
34+
formLink: "hostname"+formLink,
35+
});
36+
} catch (error) {
37+
console.error('Error creating form:', error);
38+
return res.status(500).json({ message: 'Server error, could not create form.' });
39+
}
40+
}
41+
42+
const editFormFormat = async function (req, res) {
43+
try {
44+
const { id, userId, formName, formQuestions } = req.body;
45+
46+
// Fetch the existing form
47+
const existingForm = await Form.findById(id);
48+
if (!existingForm) {
49+
return res.status(400).json({ message: "Invalid Form ID" });
50+
}
51+
52+
// Check if user exists and is active
53+
const user_temp = await userprofile.findById(userId);
54+
if (!user_temp || user_temp.isActive === false) {
55+
return res.status(400).json({ message: "Invalid or inactive user ID" });
56+
}
57+
58+
let updateData = {};
59+
60+
// Check if the form name is actually changing
61+
if (formName && formName !== existingForm.formName) {
62+
updateData.formName = formName;
63+
}
64+
65+
// Validate and compare formQuestions before updating
66+
if (formQuestions) {
67+
if (!Array.isArray(formQuestions) || formQuestions.length === 0) {
68+
return res.status(400).json({ message: "Questions must be a non-empty array" });
69+
}
70+
71+
let isDifferent = false;
72+
let newQuestions = [];
73+
74+
for (let question of formQuestions) {
75+
if (!question.label || typeof question.label !== "string") {
76+
return res.status(400).json({ message: "Each question must have a valid 'label' of type string" });
77+
}
78+
79+
if (!question.type || typeof question.type !== "string") {
80+
return res.status(400).json({ message: "Each question must have a valid 'type' of type string" });
81+
}
82+
83+
if (["radio", "checkbox"].includes(question.type)) {
84+
if (!Array.isArray(question.options) || question.options.length === 0) {
85+
return res.status(400).json({ message: `Question of type '${question.type}' must have a non-empty options array` });
86+
}
87+
88+
for (let option of question.options) {
89+
if (typeof option !== "string" || option.trim() === "") {
90+
return res.status(400).json({ message: "Each option must be a valid non-empty string" });
91+
}
92+
}
93+
}
94+
95+
// Check if this question already exists in the database
96+
let existingQuestion = existingForm.questions.find(q => q.label === question.label);
97+
98+
if (!existingQuestion || JSON.stringify(existingQuestion.options) !== JSON.stringify(question.options)) {
99+
isDifferent = true; // Mark as different if any question changes
100+
}
101+
102+
newQuestions.push(question);
103+
}
104+
105+
// Only update if something actually changed
106+
if (isDifferent) {
107+
updateData.questions = newQuestions;
108+
}
109+
}
110+
111+
// If there's nothing to update, return early
112+
if (Object.keys(updateData).length === 0) {
113+
return res.status(200).json({ message: "No changes detected" });
114+
}
115+
116+
// Update the form
117+
await Form.updateOne({ _id: id }, { $set: updateData });
118+
119+
return res.status(200).json({ message: "Form Updated Successfully" });
120+
121+
} catch (err) {
122+
console.error("Error updating form:", err);
123+
return res.status(500).json({ message: "Internal Server Error", error: err.message });
124+
}
125+
};
126+
127+
const deleteFormFormat = async function(req,res){
128+
try {
129+
// here id is the record Id of the form.
130+
const {id}=req.body;
131+
let result=await Form.deleteOne({ _id : id});
132+
// Check if the form was actually deleted
133+
if (result.deletedCount === 0) {
134+
return res.status(400).json({ message: 'Error removing Form.' });
135+
}
136+
return res.status(200).json({message:"Form Deleted Successfully"})
137+
}catch(error){
138+
return res.status(400).json({message:"Error removing Form."})
139+
}
140+
}
141+
142+
// check if a user has already responded to a form or not.
143+
const checkForResponse = async function(req,res) {
144+
try{
145+
const {formID,userID}=req.query;
146+
let result=await formResponse.find({formID:formID,submittedBy:userID})
147+
if(result.length==0){
148+
return res.status(400).json({message:"No records Found"});
149+
}
150+
return res.status(200).json({message:result})
151+
}catch(error){
152+
return res.status(404).json({message:"Error Searching for Recods"})
153+
}
154+
}
155+
156+
const getFormData =async function (req,res) {
157+
try {
158+
const formID = req.query.formID;
159+
// Check if formID is provided
160+
if (!formID) {
161+
return res.status(400).json({ message: 'Form ID is required.' });
162+
}
163+
164+
// Check if the form exists
165+
const form = await Form.findOne({ formID });
166+
if (!form || form.length===0) {
167+
return res.status(404).json({ message: 'Form not found.' });
168+
}
169+
170+
// Fetch all responses associated with the formID
171+
const responses = await formResponse.find({ formID });
172+
173+
// If no responses found, return a message
174+
if (responses.length === 0) {
175+
return res.status(404).json({ message: 'No responses found for this form.' });
176+
}
177+
178+
return res.status(200).json({
179+
message: 'Responses retrieved successfully',
180+
formID: formID,
181+
formName: form.formName,
182+
responses: responses,
183+
});
184+
185+
} catch (error) {
186+
console.error('Error fetching form responses:', error);
187+
return res.status(500).json({ message: 'Server error, could not fetch form responses.' });
188+
}
189+
}
190+
191+
const addDataToForm = async function (req, res) {
192+
try {
193+
const { formID, responses, submittedBy } = req.body;
194+
195+
// Ensure all required fields are present
196+
if (!formID || !responses || responses.length === 0) {
197+
return res.status(400).json({ message: 'Form ID and responses are required.' });
198+
}
199+
if (!submittedBy) {
200+
return res.status(400).json({ message: 'User ID is required to submit this form.' });
201+
}
202+
203+
// Check if the form exists
204+
const form = await Form.findOne({ formID });
205+
if (!form) {
206+
return res.status(404).json({ message: 'Form not found.' });
207+
}
208+
209+
// Check if user exists and is active
210+
const user = await userprofile.findById(submittedBy);
211+
if (!user || user.isActive === false) {
212+
return res.status(400).json({ message: 'Invalid or inactive user.' });
213+
}
214+
215+
// Validate responses against the form questions
216+
if (!Array.isArray(responses)) {
217+
return res.status(400).json({ message: 'Responses must be an array.' });
218+
}
219+
220+
const formQuestions = form.questions;
221+
if (responses.length !== formQuestions.length) {
222+
return res.status(400).json({ message: 'Number of responses does not match the number of form questions.' });
223+
}
224+
225+
const validatedResponses = [];
226+
227+
for (let i = 0; i < responses.length; i++) {
228+
const question = formQuestions[i];
229+
const response = responses[i];
230+
231+
// Ensure response has the required label and value
232+
if (!response.questionLabel || response.answer === undefined) {
233+
return res.status(400).json({ message: `Response for question "${question.label}" is incomplete.` });
234+
}
235+
236+
// Ensure response label matches the expected question label
237+
if (response.questionLabel !== question.label) {
238+
return res.status(400).json({ message: `Invalid question label: Expected "${question.label}", got "${response.questionLabel}".` });
239+
}
240+
241+
// Validate response based on question type
242+
if (question.type === 'radio') {
243+
if (typeof response.answer !== 'string') {
244+
return res.status(400).json({ message: `Response for "${question.label}" must be a single string value.` });
245+
}
246+
if (!question.options.includes(response.answer)) {
247+
return res.status(400).json({ message: `Invalid response for "${question.label}". Expected one of: ${question.options.join(', ')}` });
248+
}
249+
} else if (question.type === 'checkbox') {
250+
if (!Array.isArray(response.answer)) {
251+
return res.status(400).json({ message: `Response for "${question.label}" must be an array of selected options.` });
252+
}
253+
if (response.answer.length === 0) {
254+
return res.status(400).json({ message: `At least one option must be selected for "${question.label}".` });
255+
}
256+
const invalidOptions = response.answer.filter(option => !question.options.includes(option));
257+
if (invalidOptions.length > 0) {
258+
return res.status(400).json({ message: `Invalid options selected for "${question.label}": ${invalidOptions.join(', ')}` });
259+
}
260+
} else if (question.type === 'text') {
261+
if (typeof response.answer !== 'string' || response.answer.trim() === '') {
262+
return res.status(400).json({ message: `Response for "${question.label}" must be a non-empty text string.` });
263+
}
264+
} else {
265+
return res.status(400).json({ message: `Invalid question type: "${question.type}"` });
266+
}
267+
268+
// Push the validated response into the validatedResponses array
269+
validatedResponses.push({
270+
questionLabel: response.questionLabel,
271+
answer: response.answer,
272+
});
273+
}
274+
275+
// Create and save the valid response
276+
const formResp = new formResponse({
277+
formID,
278+
responses: validatedResponses,
279+
submittedBy,
280+
});
281+
282+
const savedResponse = await formResp.save();
283+
284+
return res.status(201).json({
285+
message: 'Form response submitted successfully',
286+
responseID: savedResponse._id,
287+
});
288+
289+
} catch (error) {
290+
console.error('Error submitting form response:', error);
291+
return res.status(500).json({ message: 'Server error, could not submit form response.' });
292+
}
293+
};
294+
295+
296+
const getAllForms = async (req,res)=>{
297+
try{
298+
const result=await Form.find({})
299+
return res.status(200).json({data:result})
300+
}catch(err){
301+
return res.status(404).json({error:err})
302+
}
303+
}
304+
305+
const getFormFormat = async (req,res)=>{
306+
try{
307+
// const formID=req.params.id;
308+
const {formID, userId}=req.body;
309+
console.log(formID)
310+
console.log(userId);
311+
const result=await Form.find({formID})
312+
console.log(result)
313+
if (!result || result.length===0) {
314+
return res.status(404).json({ message: 'Form not found.' });
315+
}
316+
317+
let user=await userprofile.find({_id:userId})
318+
if(user[0].isActive === false || user===undefined || user === null || user.length===0){
319+
return res.status(400).json({message: 'Invalid User'});
320+
}
321+
return res.status(200).json({data:result})
322+
}catch(err){
323+
return res.status(404).json({data:err})
324+
}
325+
}
326+
return {
327+
createForm,
328+
getFormData,
329+
addDataToForm,
330+
getAllForms,
331+
getFormFormat,
332+
editFormFormat,
333+
deleteFormFormat,
334+
checkForResponse
335+
}
336+
};
337+
338+
module.exports = formController;

0 commit comments

Comments
 (0)