Skip to content

Conversation

@AkshaTGA
Copy link
Contributor

Issue: #119

⚠️ This PR must be linked to a valid OpenCode issue number.
PRs without an issue number may not be reviewed.


Thank you for contributing to SubSentry 🚀
Please complete this template carefully to help mentors and bots review your PR efficiently.


📌 Description

Added API routes for Creation and fetching of subscriptions from the DB with Proper validation.

🧩 Issue Reference

Related Issue: #119

Note: Do NOT use words like Closes, Fixes, or Resolves.
Issues are Open for All and should not be auto-closed.


🛠️ What Did You Implement?

Please list the major things you worked on in this PR:

  • Feature implementation
  • UI changes
  • API / backend logic
  • Refactor / cleanup
  • Documentation update
  • Demo / setup task

(Select all that apply)


📁 Workspace Confirmation (MANDATORY)

Since all issues are Open for All, confirm the following:

  • All changes are inside
    contributors/<your-github-username>/
  • Base client/ and/or server/ files were copied from the main directory
  • No files outside my personal workspace were modified

🧪 Testing Performed

Please check what applies:

  • Frontend runs locally without errors
  • Backend server runs locally without errors
  • APIs tested with valid inputs
  • APIs tested with invalid / edge-case inputs
  • No console errors or warnings

📷 Screenshots / Demo (REQUIRED for most PRs)

Please attach screenshots or recordings showing:

  • Folder structure
  • Major code changes
  • UI changes (if applicable)
  • Server / client running (for setup or demo issues)

PRs without screenshots for significant changes may be requested for updates.


✅ Final PR Checklist

Before submitting, ensure:

  • This PR addresses only one issue
  • Issue number is mentioned at the top
  • Code is readable and well-structured
  • No unnecessary files are included
  • No sensitive data or .env files committed
  • Commit messages follow project conventions
  • PR title is clear and descriptive

📎 Additional Notes for Reviewers

Add any extra context, assumptions, or known limitations here.


Thank you for contributing to SubSentry 💙
Your effort helps make this project better for everyone 🚀

Copilot AI review requested due to automatic review settings December 30, 2025 09:14
@OpenGitBot
Copy link

Hey @AkshaTGA

Thanks for opening this PR 🚀. Mentor will review your pull request soon and till then, keep contributing and stay calm.

Thanks for contributing in OpenCode'25 ✨✨!

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds API routes for creating and fetching subscriptions with date-based validation logic. The implementation includes POST and GET endpoints at /api/subscriptions, with controllers that compute billing intervals and renewal dates based on user-provided start and end dates.

  • Added subscription routes with GET and POST endpoints
  • Implemented date utilities and billing interval calculation logic
  • Modified the schema to use CommonJS module exports

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
contributors/AkshaTGA/server/src/index.js Integrated subscription routes under /api prefix and cleaned up error formatting
contributors/AkshaTGA/server/src/controllers/Api.js Added controller functions for getting and creating subscriptions with date validation and billing interval calculations
contributors/AkshaTGA/server/src/Routes/routes.js Created route definitions for GET and POST /api/subscriptions endpoints
contributors/AkshaTGA/server/src/Models/SubscriptionSchema.js Changed from ES6 to CommonJS module syntax and commented out userId required constraint
contributors/AkshaTGA/server/package.json Added dev script for nodemon

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
// required: true,
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The userId field's required constraint has been commented out. This allows subscriptions to be created without a userId, which could lead to orphaned subscriptions that cannot be queried or managed. This appears to be a workaround for missing authentication rather than a proper solution.

Suggested change
// required: true,
required: true,

Copilot uses AI. Check for mistakes.
res.status(500).json({ error: "Failed to fetch subscriptions" });
});
};
//in this function, I have made is so that the next renewal date and billing interval count are calculated based on the start and end date entered byt the user.
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error in the comment: "byt" should be "by". The comment contains a typo where "byt the user" should read "by the user".

Suggested change
//in this function, I have made is so that the next renewal date and billing interval count are calculated based on the start and end date entered byt the user.
//in this function, I have made is so that the next renewal date and billing interval count are calculated based on the start and end date entered by the user.

Copilot uses AI. Check for mistakes.
.then((subscriptions) => {
res.status(200).json({ subscriptions });
})
.catch((err) => {
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error handler does not log the error details. When an error occurs during subscription fetch, the error is caught but not logged, making it difficult to debug issues in production. Consider logging the error before returning the response.

Suggested change
.catch((err) => {
.catch((err) => {
console.error("Error fetching subscriptions for user:", user._id, err);

Copilot uses AI. Check for mistakes.
Comment on lines +109 to +118

if (!name || typeof name !== "string" || !name.trim()) {
return res.status(400).json({ error: "name is required" });
}
if (!status) {
return res.status(400).json({ error: "status is required" });
}
if (!billingInterval) {
return res.status(400).json({ error: "billingInterval is required" });
}
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validation for status and billingInterval only checks for truthiness, not whether the values are valid according to the schema enums. For example, status must be one of "trial", "active", "paused", "cancelled", or "expired", but any truthy value would pass this check. Consider validating against the allowed enum values before attempting to create the subscription.

Suggested change
if (!name || typeof name !== "string" || !name.trim()) {
return res.status(400).json({ error: "name is required" });
}
if (!status) {
return res.status(400).json({ error: "status is required" });
}
if (!billingInterval) {
return res.status(400).json({ error: "billingInterval is required" });
}
// derive allowed enum values from the Subscription schema, if defined
const statusPath = Subscription.schema && Subscription.schema.path
? Subscription.schema.path("status")
: null;
const billingIntervalPath = Subscription.schema && Subscription.schema.path
? Subscription.schema.path("billingInterval")
: null;
const allowedStatuses =
statusPath && Array.isArray(statusPath.enumValues)
? statusPath.enumValues
: null;
const allowedBillingIntervals =
billingIntervalPath && Array.isArray(billingIntervalPath.enumValues)
? billingIntervalPath.enumValues
: null;
if (!name || typeof name !== "string" || !name.trim()) {
return res.status(400).json({ error: "name is required" });
}
if (!status) {
return res.status(400).json({ error: "status is required" });
}
if (
allowedStatuses &&
(typeof status !== "string" || !allowedStatuses.includes(status))
) {
return res.status(400).json({ error: "status is invalid" });
}
if (!billingInterval) {
return res.status(400).json({ error: "billingInterval is required" });
}
if (
allowedBillingIntervals &&
(typeof billingInterval !== "string" ||
!allowedBillingIntervals.includes(billingInterval))
) {
return res.status(400).json({ error: "billingInterval is invalid" });
}

Copilot uses AI. Check for mistakes.
Comment on lines +117 to +128
return res.status(400).json({ error: "billingInterval is required" });
}
if (!startDate) {
return res.status(400).json({ error: "startDate is required" });
}
if (billingInterval !== "custom" && !endDate) {
return res.status(400).json({ error: "endDate is required" });
}

const parsedStartDate = toUtcDateOnly(startDate);
if (!parsedStartDate) {
return res.status(400).json({ error: "startDate must be a valid date" });
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message is inconsistent with how other field names are formatted in error messages. Throughout the code, field names in error messages are lowercase (e.g., "name is required", "status is required"), maintaining consistency would improve user experience.

Suggested change
return res.status(400).json({ error: "billingInterval is required" });
}
if (!startDate) {
return res.status(400).json({ error: "startDate is required" });
}
if (billingInterval !== "custom" && !endDate) {
return res.status(400).json({ error: "endDate is required" });
}
const parsedStartDate = toUtcDateOnly(startDate);
if (!parsedStartDate) {
return res.status(400).json({ error: "startDate must be a valid date" });
return res.status(400).json({ error: "billing interval is required" });
}
if (!startDate) {
return res.status(400).json({ error: "start date is required" });
}
if (billingInterval !== "custom" && !endDate) {
return res.status(400).json({ error: "end date is required" });
}
const parsedStartDate = toUtcDateOnly(startDate);
if (!parsedStartDate) {
return res.status(400).json({ error: "start date must be a valid date" });

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +7

router.get('/subscriptions', getSubscriptions )
router.post('/subscriptions',addSubscription )
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The routes are missing authentication middleware. Both controllers expect req.user to be populated (lines 80 and 94 in Api.js) but there's no middleware to authenticate users and attach user information to the request. Without authentication middleware, req.user will always be undefined, causing all requests to fail with a 401 Unauthorized error.

Suggested change
router.get('/subscriptions', getSubscriptions )
router.post('/subscriptions',addSubscription )
// Simple authentication middleware to ensure req.user is populated
function authenticate(req, res, next) {
if (!req.user) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
}
router.get('/subscriptions', authenticate, getSubscriptions )
router.post('/subscriptions', authenticate, addSubscription )

Copilot uses AI. Check for mistakes.
app.get("/", (req, res) => {
res.send("Server is running...");
});
app.use("/api",router);
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after comma in the router middleware call. Should be '/api', router with a space after the comma for consistent formatting.

Suggested change
app.use("/api",router);
app.use("/api", router);

Copilot uses AI. Check for mistakes.
"description": "",
"main": "index.js",
"scripts": {
"dev":"nodemon index.js",
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after comma in the dev script. Should be "dev": "nodemon index.js" with a space after the colon for consistent JSON formatting.

Suggested change
"dev":"nodemon index.js",
"dev": "nodemon index.js",

Copilot uses AI. Check for mistakes.
Comment on lines +44 to +73
const computeIntervalCount = (startUtc, endUtc, billingInterval) => {
const msPerDay = 24 * 60 * 60 * 1000;
const diffMs = endUtc.getTime() - startUtc.getTime();
if (diffMs <= 0) return null;

const diffDays = diffMs / msPerDay;
if (!Number.isInteger(diffDays)) return null;

switch (billingInterval) {
case "daily":
return diffDays + 1;
case "weekly":
return diffDays % 7 === 0 ? diffDays / 7 + 1 : null;
case "monthly": {
if (startUtc.getUTCDate() !== endUtc.getUTCDate()) return null;
const months =
(endUtc.getUTCFullYear() - startUtc.getUTCFullYear()) * 12 +
(endUtc.getUTCMonth() - startUtc.getUTCMonth());
return months > 0 ? months + 1 : null;
}
case "yearly": {
if (
startUtc.getUTCMonth() !== endUtc.getUTCMonth() ||
startUtc.getUTCDate() !== endUtc.getUTCDate()
) {
return null;
}
const years = endUtc.getUTCFullYear() - startUtc.getUTCFullYear();
return years > 0 ? years + 1 : null;
}
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validation logic has an off-by-one error in the billing interval count calculation. The functions computeIntervalCount returns count + 1 for daily/weekly/monthly/yearly intervals (lines 54, 56, 62, 72), which includes both the start and end dates. However, this means if a subscription starts on Jan 1 and ends on Jan 2 (daily), it would count as 2 days instead of 1. This could lead to incorrect billing calculations where users are charged for an extra period.

Copilot uses AI. Check for mistakes.
@Aryan-coder06
Copy link
Collaborator

I think copilot itself suggested changes in your commit , so please review and we will re - evaluate

@ShubhamKumarSahu-svg
Copy link
Collaborator

@AkshaTGA please provide screenshots as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants