Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 88 additions & 14 deletions src/controllers/membershipController.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Request, Response } from "express";
import * as membershipService from "../services/membership.service";
import { IUser } from "../types"
import { IUser } from "../types";
import logger from "../config/loggingConfig";
import { addNotification } from "../services/notification.service";
import { computeRatings } from "../services/reviewFeedback.service";

export const getMembershipList = async (req: Request, res: Response) => {
try {
Expand All @@ -14,14 +16,19 @@ export const getMembershipList = async (req: Request, res: Response) => {
return res.status(200).json(membershipList);
} catch (error) {
logger.error(`Error getting membership list: `, error);
return res.status(500).json({ message: 'An error occurred while getting membership list; please try again later' });
return res.status(500).json({
message:
"An error occurred while getting membership list; please try again later",
});
}
};
};

export const getSingleMembership = async (req: Request, res: Response) => {
const { membership_id } = req.params;
try {
const membership = await membershipService.getSingleMembershipById(membership_id);
const membership = await membershipService.getSingleMembershipById(
membership_id
);
if (!membership) {
logger.warn(`Membership with ID ${membership_id} not found.`);
return res.status(404).json({ message: "Membership not found" });
Expand All @@ -30,39 +37,106 @@ export const getSingleMembership = async (req: Request, res: Response) => {
return res.status(200).json(membership);
} catch (error) {
logger.error(`Error getting membership ID ${membership_id}:`, error);
return res.status(500).json({ message: 'An error occurred while getting single membership; please try again later' });
return res.status(500).json({
message:
"An error occurred while getting single membership; please try again later",
});
}
};

export const fetchUserMembership = async (req: Request, res: Response) => {
const authUser = req.currentUser as IUser;
try {
const currentMembership = await membershipService.getUserMembership(authUser);
const currentMembership = await membershipService.getUserMembership(
authUser
);
if (!currentMembership) {
logger.warn(`User Membership with ID ${authUser.pi_uid} not found.`);
return res.status(404).json({ message: "User Membership not found" });
}
logger.info(`Fetched user membership with ID ${authUser.pi_uid}`);
return res.status(200).json(currentMembership);
} catch (error) {
logger.error(`Failed to fetch user membership with ID ${authUser.pi_uid}:`, error);
return res.status(500).json({ message: 'An error occurred while fetching user membership; please try again later' });
logger.error(
`Failed to fetch user membership with ID ${authUser.pi_uid}:`,
error
);
return res.status(500).json({
message:
"An error occurred while fetching user membership; please try again later",
});
}
};

export const updateMembership = async (req: Request, res: Response) => {
export const updateMembership = async (req: Request, res: Response) => {
try {
const { membership_class } = req.body;
const authUser = req.currentUser;
if (!authUser) {
logger.warn('No authenticated user found when updating/ renewing membership.');
return res.status(401).json({ error: 'Unauthorized' });
logger.warn(
"No authenticated user found when updating/ renewing membership."
);
return res.status(401).json({ error: "Unauthorized" });
}
logger.info(`Updated or renewed membership for user ${authUser.pi_uid}`);
const updatedMembership = await membershipService.applyMembershipChange(authUser.pi_uid, membership_class);
const updatedMembership = await membershipService.applyMembershipChange(
authUser.pi_uid,
membership_class
);
return res.status(200).json(updatedMembership);
} catch (error: any) {
logger.error("Failed to update or renew membership:", error);
return res.status(500).json({ message: 'An error occurred while updating membership; please try again later' });
return res.status(500).json({
message:
"An error occurred while updating membership; please try again later",
});
}
};

// Deduct Mappi, update trust rating, and send notification
export const deductMappi = async (req: Request, res: Response) => {
try {
const authUser = req.currentUser as IUser;
if (!authUser) {
logger.warn("No authenticated user found for Mappi deduction.");
return res.status(401).json({ message: "Unauthorized" });
}

const { amount } = req.body;
if (!amount || amount <= 0) {
return res.status(400).json({ message: "Invalid Mappi amount" });
}

// Deduct Mappi using your service
const deductionResult = await membershipService.deductMappi(
authUser.pi_uid,
amount
);

// Compute updated trust rating
const trustRating = await computeRatings(authUser.pi_uid);

// Send notification to user
await addNotification(
authUser.pi_uid,
`You have successfully used ${amount} Mappi. Current balance: ${deductionResult.balance}`
);

logger.info(`Deducted ${amount} Mappi for user ${authUser.pi_uid}`);

return res.status(200).json({
message: deductionResult.message,
balance: deductionResult.balance,
mappi_used_to_date: deductionResult.mappi_used_to_date,
trust_meter_rating: trustRating,
});
} catch (error: any) {
logger.error(
`Failed to deduct Mappi for user ${req.currentUser?.pi_uid}:`,
error
);
return res
.status(500)
.json({ message: "Failed to deduct Mappi; please try again later" });
}
};
};
38 changes: 37 additions & 1 deletion src/controllers/reviewFeedbackController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import * as reviewFeedbackService from "../services/reviewFeedback.service";
import { uploadImage } from "../services/misc/image.service";

import logger from "../config/loggingConfig";
import * as notificationService from "../services/notification.service";


export const getReviews = async (req: Request, res: Response) => {
const { review_receiver_id } = req.params;
Expand Down Expand Up @@ -94,4 +96,38 @@ export const updateReview = async (req: Request, res: Response) => {
logger.error(`Failed to update review for userID ${req.currentUser?.pi_uid}:`, error);
return res.status(500).json({ message: 'An error occurred while updating review; please try again later' });
}
};
};
export const applyTrustProtect = async (req: Request, res: Response) => {
try {
const authUser = req.currentUser;
const { review_id } = req.params;

if (!authUser) {
return res.status(401).json({ message: "Unauthorized" });
}

const updatedReview = await reviewFeedbackService.applyTrustProtect(review_id, authUser);

// ✅ Send notification if Trust Protect changed rating to SAD
if (updatedReview && updatedReview.rating === 2) {
await notificationService.addNotification(
updatedReview.review_giver_id,
`Your review has been adjusted by Trust Protect you can reverse back the rating in the review screen.`
);
logger.info(
`Notification sent to review giver ${updatedReview.review_giver_id} for Trust Protect adjustment.`
);
}

return res.status(200).json({
message: "Trust Protect applied successfully",
updatedReview,
});
} catch (error: any) {
logger.error(
`Failed to apply Trust Protect for review ${req.params.review_id}:`,
error
);
return res.status(500).json({ message: "Failed to apply Trust Protect" });
}
};
77 changes: 70 additions & 7 deletions src/routes/membership.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ import * as membershipController from "../controllers/membershipController";
* $numberDecimal:
* type: string
* required:
* - $numberDecimal
* - $numberDecimal
* membership_expiry_date:
* type: string
* description: Membership expiration date
* format: date-time
*
*
* MembershipTiers:
* type: object
* properties:
Expand Down Expand Up @@ -68,7 +68,10 @@ const membershipRoutes = Router();
* 500:
* description: Internal server error
*/
membershipRoutes.get("/membership-list", membershipController.getMembershipList);
membershipRoutes.get(
"/membership-list",
membershipController.getMembershipList
);

/**
* @swagger
Expand Down Expand Up @@ -96,7 +99,10 @@ membershipRoutes.get("/membership-list", membershipController.getMembershipList)
* 500:
* description: Internal server error
*/
membershipRoutes.get("/:membership_id", membershipController.getSingleMembership);
membershipRoutes.get(
"/:membership_id",
membershipController.getSingleMembership
);

/**
* @swagger
Expand All @@ -121,7 +127,11 @@ membershipRoutes.get("/:membership_id", membershipController.getSingleMembership
* 500:
* description: Internal server error
*/
membershipRoutes.get("/", verifyToken, membershipController.fetchUserMembership);
membershipRoutes.get(
"/",
verifyToken,
membershipController.fetchUserMembership
);

/**
* @swagger
Expand Down Expand Up @@ -155,6 +165,59 @@ membershipRoutes.get("/", verifyToken, membershipController.fetchUserMembership)
* 500:
* description: Internal server error
*/
membershipRoutes.put("/manage", verifyToken, membershipController.updateMembership);
membershipRoutes.put(
"/manage",
verifyToken,
membershipController.updateMembership
);

export default membershipRoutes;
/**
* @swagger
* /api/v1/memberships/deduct-mappi:
* post:
* tags:
* - Membership
* summary: Deduct Mappi credits from a user for TrustProtect usage
* security:
* - bearerAuth: [] # Ensures only authenticated users can perform this action
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - amount
* properties:
* amount:
* type: number
* example: 100
* description: Amount of Mappi to deduct (e.g., 100)
* responses:
* 200:
* description: Mappi deducted successfully
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
* balance:
* type: number
* mappi_used_to_date:
* type: number
* 400:
* description: Invalid request body
* 401:
* description: Unauthorized access
* 500:
* description: Internal server error
*/
membershipRoutes.post(
"/deduct-mappi",
verifyToken,
membershipController.deductMappi
);

export default membershipRoutes;
29 changes: 29 additions & 0 deletions src/routes/reviewFeedback.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,5 +191,34 @@ reviewFeedbackRoutes.put(
upload.single("image"),
reviewFeedbackController.updateReview
);
/**
* @swagger
* /api/v1/review-feedback/trust-protect/{review_id}:
* put:
* tags:
* - Review Feedback
* summary: Apply Trust Protect on a review (admin/moderation action)
* parameters:
* - name: review_id
* in: path
* required: true
* schema:
* type: string
* description: The ID of the review to apply Trust Protect on
* responses:
* 200:
* description: Trust Protect applied successfully
* 401:
* description: Unauthorized
* 404:
* description: Review not found
* 500:
* description: Internal server error
*/
reviewFeedbackRoutes.put(
"/trust-protect/:review_id",
verifyToken,
reviewFeedbackController.applyTrustProtect
);

export default reviewFeedbackRoutes;
Loading