-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add bug CRUD routes, controller and model #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| node_modules | ||
| .env |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| const mongoose = require('mongoose'); | ||
|
|
||
| const bugSchema = new mongoose.Schema( | ||
| { | ||
| title: | ||
| { | ||
| type:String, | ||
| required:true, | ||
| trim:true | ||
| }, | ||
| description: | ||
| { | ||
| type: String, | ||
| required: true | ||
| }, | ||
| techStack: | ||
| [{ | ||
| type: String, | ||
| lowercase: true, | ||
| trim: true | ||
| }], | ||
| tags: | ||
| [{ | ||
| type: String, | ||
| lowercase: true, | ||
| trim: true | ||
| }], | ||
| difficulty: | ||
| { | ||
| type: String, | ||
| enum: ["EASY", "MEDIUM", "HARD"], | ||
| index: true | ||
| }, | ||
| reward: | ||
| { | ||
| type: Number, | ||
| required: true, | ||
| min: 1 | ||
| }, | ||
| status: | ||
| { | ||
| type: String, | ||
| enum: ["OPEN", "SOLVED", "CLOSED"], | ||
| default: "OPEN", | ||
| index: true | ||
| }, | ||
| ownerId: | ||
| { | ||
| type: mongoose.Schema.Types.ObjectId, | ||
| ref: "User", | ||
| index: true | ||
| }, | ||
| acceptedSolutionId: | ||
| { | ||
| type: mongoose.Schema.Types.ObjectId, | ||
| ref: "Solution" | ||
| }, | ||
| solutionCount: | ||
| { | ||
| type: Number, | ||
| default: 0 | ||
| }, | ||
|
Comment on lines
+58
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cd core-services && cat -n Models/bug.js | head -80Repository: call-0f-code/Bug-Graveyard Length of output: 1925 🏁 Script executed: cd core-services && rg "solutionCount" --type js -B 2 -A 2Repository: call-0f-code/Bug-Graveyard Length of output: 384 🏁 Script executed: cd core-services && rg "\$inc|solutionCount\s*[:=]|updateOne|updateMany|findByIdAndUpdate" --type js -B 2 -A 2 | head -100Repository: call-0f-code/Bug-Graveyard Length of output: 673 🏁 Script executed: cd core-services && find . -name "*[Ss]olution*" -type f | grep -E "\.(js|ts)$"Repository: call-0f-code/Bug-Graveyard Length of output: 94 🏁 Script executed: cd core-services && cat src/models/Solution.js && echo "---" && find . -name "*[Ss]olution*[Cc]ontroller*" -type fRepository: call-0f-code/Bug-Graveyard Length of output: 887 🏁 Script executed: cd core-services && find . -type f -name "*.js" -exec rg -l "new Solution|solution.*save|solutionCount.*\+|\$inc.*solutionCount" {} \; | head -10Repository: call-0f-code/Bug-Graveyard Length of output: 52 🏁 Script executed: cd core-services && rg "solution|Solution" --type js -i | grep -i "controller\|route" | head -20Repository: call-0f-code/Bug-Graveyard Length of output: 52 🏁 Script executed: cd core-services && ls -la controllers/ && ls -la src/controllers/ 2>/dev/null || echo "src/controllers not found"Repository: call-0f-code/Bug-Graveyard Length of output: 419 🏁 Script executed: cd core-services && cat -n controllers/bugController.jsRepository: call-0f-code/Bug-Graveyard Length of output: 2728 🏁 Script executed: cd core-services && find . -name "*route*" -type f && find . -name "*middleware*" -type fRepository: call-0f-code/Bug-Graveyard Length of output: 52 🏁 Script executed: cd core-services && rg -i "bug|solution" --type js | grep -i "increment\|decrement\|add\|remove" | head -20Repository: call-0f-code/Bug-Graveyard Length of output: 52 Add minimum value validation to prevent negative The Proposed validation solutionCount:
{
type: Number,
- default: 0
+ default: 0,
+ min: 0
},🤖 Prompt for AI Agents |
||
| github: | ||
| { | ||
| repoUrl: String, | ||
| filePath: String, | ||
| issueUrl: String | ||
| }, | ||
| deadline: Date, | ||
| isRewardLocked: | ||
| { | ||
| type: Boolean, | ||
| default: true | ||
| }, | ||
| isAbusive: | ||
| { | ||
| type: Boolean, | ||
| default: false | ||
| }, | ||
| refundProcessed: | ||
| { | ||
| type: Boolean, | ||
| default: false | ||
|
Comment on lines
+40
to
+83
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Description: Inspect Bug write paths for raw request-body persistence.
# Expected: Bug.create/findByIdAndUpdate should use an explicit allowlist DTO, not req.body directly.
rg -n -C4 'Bug\.(create|findByIdAndUpdate|findOneAndUpdate|updateOne)\s*\(|req\.body' --iglob '*.js'Repository: call-0f-code/Bug-Graveyard Length of output: 1981 🏁 Script executed: #!/bin/bash
# In bugController.js updateBug function, replace req.body with explicit field allowlist
# Example: const {title, description, reward} = req.body; then pass {title, description, reward} to findByIdAndUpdateRepository: call-0f-code/Bug-Graveyard Length of output: 52 Fix the update handler to whitelist mutable fields. While Fields like 🤖 Prompt for AI Agents |
||
| } | ||
| }, | ||
| { | ||
| timestamps: true | ||
| } | ||
| ); | ||
| module.exports = mongoose.model('Bug',bugSchema); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| const mongoose = require('mongoose'); | ||
|
|
||
| const connectDb = async() => | ||
| { | ||
| try | ||
| { | ||
| const connect = await mongoose.connect(process.env.CONNECTION_STRING); | ||
| console.log( | ||
| 'Database connected:', | ||
| connect.connection.host, | ||
| connect.connection.name | ||
| ); | ||
| } | ||
| catch (err) | ||
| { | ||
| console.log(err); | ||
| process.exit(1); | ||
| } | ||
|
Comment on lines
+14
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Log errors to stderr and add disconnect handling. Two minor concerns:
Proposed fix catch (err)
{
- console.log(err);
+ console.error('Database connection failed:', err);
process.exit(1);
}
};
+
+mongoose.connection.on('error', (err) => console.error('Mongoose error:', err));
+mongoose.connection.on('disconnected', () => console.warn('Mongoose disconnected'));🤖 Prompt for AI Agents |
||
| }; | ||
|
|
||
| module.exports = connectDb; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| exports.constants = | ||
| { | ||
| VALIDATION_ERROR:400, | ||
| NOT_FOUND:404, | ||
| UNAUTHORIZED:401, | ||
| FORBIDDEN:403, | ||
| SERVER_ERROR:500 | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| const asyncHandler = require('express-async-handler'); | ||
| const Bug = require('../Models/bug'); | ||
|
|
||
| //@desc Get all Bugs.. | ||
| //@route Get /api/bugs | ||
| //@access public | ||
|
|
||
| const getBugs = asyncHandler(async (req,res) => | ||
| { | ||
| const bugs = await Bug.find(); | ||
| res.status(200).json(bugs); | ||
| }); | ||
|
|
||
| //@desc Create new Bug.. | ||
| //@route POST /api/bugs | ||
| //@access public | ||
|
|
||
| const createBug = asyncHandler(async (req, res) => | ||
| { | ||
| console.log('The request body is: ',req.body); | ||
| const {title,description,deadline,reward} = req.body; | ||
| if(!title || !description || !deadline || !reward) | ||
| { | ||
| res.status(400); | ||
| throw new Error('All fields are mandatory') | ||
| } | ||
| const bug = await Bug.create({ | ||
| title, | ||
| description, | ||
| deadline, | ||
| reward | ||
| }); | ||
| res.status(201).json(bug); | ||
| }); | ||
|
|
||
| //@desc Get Bug by id.. | ||
| //@route Get /api/bugs/:id | ||
| //@access public | ||
|
|
||
| const getBug = asyncHandler(async (req, res) => | ||
| { | ||
| const bug = await Bug.findById(req.params.id); | ||
| if(!bug) | ||
| { | ||
| res.status(404); | ||
| throw new Error('Bug not found'); | ||
| } | ||
| res.status(200).json(bug); | ||
| }); | ||
|
Comment on lines
+40
to
+49
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validate
Proposed fix (apply in getBug, updateBug, deleteBugs) const mongoose = require('mongoose');
...
const getBug = asyncHandler(async (req, res) =>
{
+ if (!mongoose.isValidObjectId(req.params.id))
+ {
+ res.status(404);
+ throw new Error('Bug not found');
+ }
const bug = await Bug.findById(req.params.id);
if(!bug)
{
res.status(404);
throw new Error('Bug not found');
}
res.status(200).json(bug);
});🤖 Prompt for AI Agents |
||
|
|
||
| //@desc Update Bug by id.. | ||
| //@route PUT /api/bugs/:id | ||
| //@access public | ||
|
|
||
| const updateBug = asyncHandler(async(req, res) => | ||
| { | ||
| const bug = await Bug.findById(req.params.id); | ||
| if(!bug) | ||
| { | ||
| res.status(404); | ||
| throw new Error('Bug not found'); | ||
| } | ||
| const updatedBug = await Bug.findByIdAndUpdate( | ||
| req.params.id, | ||
| req.body, | ||
| {new: true} | ||
| ); | ||
|
|
||
| res.status(200).json(updatedBug); | ||
| }); | ||
|
Comment on lines
+55
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: In Mongoose 9, the default behavior of Model.findByIdAndUpdate regarding runValidators is false. Update validators, including those triggered by runValidators: true, are off by default for findByIdAndUpdate and similar update operations. You must explicitly set { runValidators: true } in the options to enable validation on updates. This has been consistent across Mongoose versions, including 9.x, with no changes noted in the 9.0 changelog or migration guides. Citations:
🏁 Script executed: # Find the Bug model/schema definition
fd -t f Bug -i | grep -E '\.(js|ts)$'Repository: call-0f-code/Bug-Graveyard Length of output: 207 🏁 Script executed: # Also search for Bug schema/model definition in common patterns
rg "const Bug|export.*Bug|mongoose.model.*Bug" -t js -t ts -A 5Repository: call-0f-code/Bug-Graveyard Length of output: 595 🏁 Script executed: # Check the Bug schema definition in the Models directory (since that's what the controller imports)
cat -n core-services/Models/bug.jsRepository: call-0f-code/Bug-Graveyard Length of output: 2130 🏁 Script executed: # Also check the src models version to see if there are differences
cat -n core-services/src/models/Bug.jsRepository: call-0f-code/Bug-Graveyard Length of output: 1892 🏁 Script executed: # Let's check the full updateBug function and surrounding context
sed -n '45,90p' core-services/controllers/bugController.jsRepository: call-0f-code/Bug-Graveyard Length of output: 979 🏁 Script executed: # Also check if there are any other update operations or patterns in the controller
rg "findByIdAndUpdate|findOneAndUpdate" core-services/controllers/bugController.js -A 10 -B 2Repository: call-0f-code/Bug-Graveyard Length of output: 332 Harden Three issues here:
Proposed fix-const updateBug = asyncHandler(async(req, res) =>
-{
- const bug = await Bug.findById(req.params.id);
- if(!bug)
- {
- res.status(404);
- throw new Error('Bug not found');
- }
- const updatedBug = await Bug.findByIdAndUpdate(
- req.params.id,
- req.body,
- {new: true}
- );
-
- res.status(200).json(updatedBug);
-});
+const updateBug = asyncHandler(async (req, res) =>
+{
+ const { title, description, deadline, reward } = req.body;
+ const updates = { title, description, deadline, reward };
+ Object.keys(updates).forEach(k => updates[k] === undefined && delete updates[k]);
+
+ const updatedBug = await Bug.findByIdAndUpdate(
+ req.params.id,
+ updates,
+ { new: true, runValidators: true }
+ );
+ if (!updatedBug)
+ {
+ res.status(404);
+ throw new Error('Bug not found');
+ }
+ res.status(200).json(updatedBug);
+});🤖 Prompt for AI Agents |
||
|
|
||
| //@desc Delete Bug.. | ||
| //@route DELETE /api/bugs/:id | ||
| //@access public | ||
|
|
||
| const deleteBugs = asyncHandler(async (req, res) => | ||
| { | ||
| const bug = await Bug.findById(req.params.id); | ||
| if(!bug) | ||
| { | ||
| res.status(404); | ||
| throw new Error('Bug not found'); | ||
| } | ||
|
|
||
| await bug.deleteOne(); | ||
| res.status(200).json(bug); | ||
| }); | ||
|
|
||
| module.exports = | ||
| { | ||
| getBugs, | ||
| createBug, | ||
| getBug, | ||
| updateBug, | ||
| deleteBugs | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| const{constants} = require('../constants'); | ||
| const errorHandler = (err,req,res,next) => | ||
| { | ||
| const statusCode = res.statusCode ? res.statusCode: 500; | ||
|
|
||
| switch (statusCode) | ||
| { | ||
| case constants.VALIDATION_ERROR: | ||
| res.json({title: "Validation Failed",message: err.message,stackTrace: err.stack}); | ||
| break; | ||
|
|
||
| case constants.NOT_FOUND: | ||
| res.json({title: "Not Found",message: err.message,stackTrace: err.stack}); | ||
| break; | ||
|
|
||
| case constants.UNAUTHORIZED: | ||
| res.json({title: "Not Authorized",message: err.message,stackTrace: err.stack}); | ||
| break; | ||
|
|
||
| case constants.FORBIDDEN: | ||
| res.json({title: "Forbidden",message: err.message,stackTrace: err.stack}); | ||
| break; | ||
|
|
||
| case constants.SERVER_ERROR: | ||
| res.json({title: "Server Error",message: err.message,stackTrace: err.stack}); | ||
| break; | ||
|
|
||
| default: | ||
| console.log('No Error'); | ||
| break; | ||
| } | ||
| }; | ||
|
Comment on lines
+1
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: unmapped errors leave the request hanging; stack traces leak to clients. Several problems on this hot path:
Proposed fix-const{constants} = require('../constants');
-const errorHandler = (err,req,res,next) =>
-{
- const statusCode = res.statusCode ? res.statusCode: 500;
-
- switch (statusCode)
- {
- case constants.VALIDATION_ERROR:
- res.json({title: "Validation Failed",message: err.message,stackTrace: err.stack});
- break;
-
- case constants.NOT_FOUND:
- res.json({title: "Not Found",message: err.message,stackTrace: err.stack});
- break;
-
- case constants.UNAUTHORIZED:
- res.json({title: "Not Authorized",message: err.message,stackTrace: err.stack});
- break;
-
- case constants.FORBIDDEN:
- res.json({title: "Forbidden",message: err.message,stackTrace: err.stack});
- break;
-
- case constants.SERVER_ERROR:
- res.json({title: "Server Error",message: err.message,stackTrace: err.stack});
- break;
-
- default:
- console.log('No Error');
- break;
- }
-};
+const { constants } = require('../constants');
+
+const TITLES = {
+ [constants.VALIDATION_ERROR]: 'Validation Failed',
+ [constants.NOT_FOUND]: 'Not Found',
+ [constants.UNAUTHORIZED]: 'Not Authorized',
+ [constants.FORBIDDEN]: 'Forbidden',
+ [constants.SERVER_ERROR]: 'Server Error',
+};
+
+const errorHandler = (err, req, res, next) => {
+ // If no explicit error status was set by the controller, treat as 500.
+ const statusCode =
+ res.statusCode && res.statusCode !== 200 ? res.statusCode : 500;
+
+ res.status(statusCode).json({
+ title: TITLES[statusCode] || 'Error',
+ message: err.message,
+ ...(process.env.NODE_ENV !== 'production' && { stackTrace: err.stack }),
+ });
+};
module.exports = errorHandler;🤖 Prompt for AI Agents |
||
|
|
||
| module.exports = errorHandler; | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: call-0f-code/Bug-Graveyard
Length of output: 144
🏁 Script executed:
Repository: call-0f-code/Bug-Graveyard
Length of output: 151
🏁 Script executed:
Repository: call-0f-code/Bug-Graveyard
Length of output: 2130
🏁 Script executed:
Repository: call-0f-code/Bug-Graveyard
Length of output: 2728
Require
ownerIdfor created bugs.The
ownerIdfield is currently optional, and the controller'screateBugfunction (line 21) does not set this value from the authenticated user—it only extracts{title, description, deadline, reward}from the request. This allows bugs to be persisted with a nullownerId, creating orphan records that cannot be reliably authorized, listed by owner, or refunded. The schema must enforcerequired: true, and the controller must sourceownerIdfrom the authenticated request context rather than the request body.🛡️ Proposed schema change
ownerId: { type: mongoose.Schema.Types.ObjectId, ref: "User", + required: true, index: true },📝 Committable suggestion
🤖 Prompt for AI Agents