Skip to content

Commit

Permalink
Merge pull request #969 from IkkiOcean/backend-schema-10
Browse files Browse the repository at this point in the history
Implement Referral System with Schema, Controllers, Routes, and Logging
  • Loading branch information
manikumarreddyu authored Nov 10, 2024
2 parents ad03026 + ae318c1 commit d6302e7
Show file tree
Hide file tree
Showing 6 changed files with 423 additions and 0 deletions.
202 changes: 202 additions & 0 deletions backend/controllers/shop/sub-controllers/referralController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@

const Referral = require("../../../model/shop/sub-model/Referral");
const User = require("../../../model/user");
const {
generateUniqueCode,
validateReferralCodeFormat,
} = require("../../../services/sub-service/referralUtils");
const { logInfo, logError } = require("../../../services/sub-service/logger");

// Create a referral code and handle errors
exports.createReferral = async (req, res) => {
try {
const { referrerId } = req.body;

const referrer = await User.findById(referrerId);
if (!referrer) {
logError("Referrer not found");
return res.status(404).json({ message: "Referrer user not found" });
}

const existingReferral = await Referral.findOne({
referrerId,
status: "pending",
});
if (existingReferral) {
logInfo("Active referral code already exists for this user");
return res
.status(400)
.json({ message: "Active referral code already exists" });
}

const referralCode = generateUniqueCode();
const newReferral = new Referral({ referrerId, referralCode });

await newReferral.save();
logInfo(
`Referral created for referrerId: ${referrerId}, code: ${referralCode}`
);
res
.status(201)
.json({ message: "Referral created successfully", referralCode });
} catch (error) {
logError("Error creating referral", error);
res.status(500).json({ message: "Error creating referral", error });
}
};

// Get referral status
exports.checkReferralStatus = async (req, res) => {
try {
const { code } = req.params;

if (!validateReferralCodeFormat(code)) {
logError("Invalid referral code format");
return res.status(400).json({ message: "Invalid referral code format" });
}

const referral = await Referral.findOne({ referralCode: code });
if (!referral) {
logInfo("Referral code not found");
return res.status(404).json({ message: "Referral code not found" });
}

res.status(200).json({ status: referral.status });
} catch (error) {
logError("Error checking referral status", error);
res.status(500).json({ message: "Error checking referral status", error });
}
};

// Complete a referral process
exports.completeReferral = async (req, res) => {
try {
const { code, refereeId } = req.body;

if (!validateReferralCodeFormat(code)) {
logError("Invalid referral code format");
return res.status(400).json({ message: "Invalid referral code format" });
}

const referral = await Referral.findOne({ referralCode: code });
if (!referral) {
logInfo("Referral code not found");
return res.status(404).json({ message: "Referral code not found" });
}

if (referral.status === "completed") {
logInfo("Referral code already used");
return res.status(400).json({ message: "Referral code already used" });
}

const referee = await User.findById(refereeId);
if (!referee) {
logInfo("Referee user not found");
return res.status(404).json({ message: "Referee user not found" });
}

if (referral.referrerId.toString() === refereeId) {
logInfo("Cannot use your own referral code");
return res
.status(400)
.json({ message: "Cannot use your own referral code" });
}

referral.status = "completed";
referral.refereeId = refereeId;
await referral.save();
logInfo(`Referral code ${code} completed successfully by ${refereeId}`);

res.status(200).json({ message: "Referral completed successfully" });
} catch (error) {
logError("Error completing referral", error);
res.status(500).json({ message: "Error completing referral", error });
}
};

// Get referrals for specific referrer with extra filters and pagination
exports.getReferralsByReferrer = async (req, res) => {
try {
const { referrerId } = req.params;
const { status, page = 1, limit = 10 } = req.query;

const referrer = await User.findById(referrerId);
if (!referrer) {
logError("Referrer user not found");
return res.status(404).json({ message: "Referrer user not found" });
}

const filter = { referrerId };
if (status) filter.status = status;

const referrals = await Referral.find(filter)
.skip((page - 1) * limit)
.limit(parseInt(limit));
const totalCount = await Referral.countDocuments(filter);

res.status(200).json({
referrals,
totalPages: Math.ceil(totalCount / limit),
currentPage: page,
});
} catch (error) {
logError("Error retrieving referrals by referrer", error);
res.status(500).json({ message: "Error retrieving referrals", error });
}
};

// List all referrals for admin with advanced filtering and sorting
exports.listAllReferrals = async (req, res) => {
try {
const {
page = 1,
limit = 10,
sortBy = "createdAt",
order = "desc",
} = req.query;

const referrals = await Referral.find()
.sort({ [sortBy]: order === "asc" ? 1 : -1 })
.skip((page - 1) * limit)
.limit(parseInt(limit));
const totalCount = await Referral.countDocuments();

res.status(200).json({
referrals,
totalPages: Math.ceil(totalCount / limit),
currentPage: page,
});
} catch (error) {
logError("Error retrieving all referrals", error);
res.status(500).json({ message: "Error retrieving referrals", error });
}
};

// Cancel a pending referral
exports.cancelReferral = async (req, res) => {
try {
const { code } = req.body;

const referral = await Referral.findOne({ referralCode: code });
if (!referral) {
logInfo("Referral code not found");
return res.status(404).json({ message: "Referral code not found" });
}

if (referral.status !== "pending") {
logInfo("Only pending referrals can be canceled");
return res
.status(400)
.json({ message: "Only pending referrals can be canceled" });
}

referral.status = "canceled";
await referral.save();
logInfo(`Referral code ${code} canceled successfully`);

res.status(200).json({ message: "Referral canceled successfully" });
} catch (error) {
logError("Error canceling referral", error);
res.status(500).json({ message: "Error canceling referral", error });
}
};
32 changes: 32 additions & 0 deletions backend/model/shop/sub-model/Referral.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

const mongoose = require("mongoose");
const { Schema } = mongoose;

const referralSchema = new Schema({
referrerId: {
type: Schema.Types.ObjectId,
ref: "User",
required: true,
},
refereeId: {
type: Schema.Types.ObjectId,
ref: "User",
required: false,
},
referralCode: {
type: String,
required: true,
unique: true,
},
status: {
type: String,
enum: ["pending", "completed"],
default: "pending",
},
timestamp: {
type: Date,
default: Date.now,
},
});

module.exports = mongoose.model("Referral", referralSchema);
35 changes: 35 additions & 0 deletions backend/routes/sub-routes/referralRoutes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const express = require("express");
const router = express.Router();
const referralController = require("../controllers/referralController");

// Route to create a new referral
// Endpoint: POST /api/referrals
router.post("/",
referralController.createReferral);

// Route to check referral status by code
// Endpoint: GET /api/referrals/status/:code
router.get("/status/:code",
referralController.checkReferralStatus);

// Route to complete a referral when a referral code is used by a referee
// Endpoint: POST /api/referrals/complete
router.post("/complete",
referralController.completeReferral);

// Route to get all referrals by a specific referrer, with optional status filter and pagination
// Endpoint: GET /api/referrals/referrer/:referrerId
router.get("/referrer/:referrerId",
referralController.getReferralsByReferrer);

// Route for admin to list all referrals with pagination and sorting
// Endpoint: GET /api/referrals
router.get("/",
referralController.listAllReferrals);

// Route to cancel a pending referral by code
// Endpoint: POST /api/referrals/cancel
router.post("/cancel",
referralController.cancelReferral);

module.exports = router;
10 changes: 10 additions & 0 deletions backend/services/sub-service/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@


exports.logInfo = (message) => {
console.log(`[INFO] ${message}`);
};

exports.logError = (message, error) => {
console.error(`[ERROR] ${message}`, error);
};

Loading

0 comments on commit d6302e7

Please sign in to comment.