Skip to content

Commit 99e5614

Browse files
authored
Merge pull request #377 from bluewave-labs/get-incomplete-guides
Get incomplete guides
2 parents 823ec6c + 03b5f8d commit 99e5614

10 files changed

+170
-18
lines changed

backend/Dockerfile

-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ FROM node:22-alpine3.21
22

33
RUN apk update && apk add bash && rm -rf /var/cache/apk/*
44

5-
RUN apk update && apk add bash && rm -rf /var/cache/apk/*
6-
75
WORKDIR /app
86

97
COPY package*.json ./

backend/config/settings.js

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ module.exports = {
2525
banners: [userRole.ADMIN],
2626
links: [userRole.ADMIN],
2727
tours: [userRole.ADMIN],
28+
helpers: [userRole.ADMIN],
2829
}
2930
}
3031
};
+41-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const bannerService = require("../service/banner.service");
2-
const linkService = require("../service/link.service");
2+
const guidelogService = require("../service/guidelog.service");
3+
const helperLinkService = require("../service/helperLink.service");
34
const popupService = require("../service/popup.service");
45

56
class GuideController {
@@ -10,19 +11,55 @@ class GuideController {
1011
if (!url || typeof url !== 'string') {
1112
return res.status(400).json({ errors: [{ msg: "URL is missing or invalid" }] });
1213
}
13-
const [banner, popup, link] = await Promise.all([
14+
const [banner, popup, helperLink] = await Promise.all([
1415
bannerService.getBannerByUrl(url),
1516
popupService.getPopupByUrl(url),
16-
linkService.getLinkByUrl(url),
17+
helperLinkService.getAllHelpersWithLinks(),
1718
]);
18-
res.status(200).json({ banner, popup, link });
19+
res.status(200).json({ banner, popup, helperLink });
1920
} catch (error) {
2021
internalServerError(
2122
"GET_GUIDES_BY_URL_ERROR",
2223
error.message,
2324
);
2425
}
2526
}
27+
28+
async getIncompleteGuidesByUrl(req, res) {
29+
try {
30+
const { url, userId } = req.body;
31+
32+
if (!url || typeof url !== 'string') {
33+
return res.status(400).json({ errors: [{ msg: "URL is missing or invalid" }] });
34+
}
35+
if (!userId || typeof userId !== 'string') {
36+
return res.status(400).json({ errors: [{ msg: "userId is missing or invalid" }] });
37+
}
38+
39+
const [completePopupLogs, completeBannerLogs, completeHelperLogs] = await Promise.all([
40+
guidelogService.getCompletePopupLogs(userId),
41+
guidelogService.getCompleteBannerLogs(userId),
42+
guidelogService.getCompleteHelperLogs(userId),
43+
]);
44+
45+
const popupIds = completePopupLogs.map(log => log.guideId);
46+
const bannerIds = completeBannerLogs.map(log => log.guideId);
47+
const helperLinkIds = completeHelperLogs.map(log => log.guideId);
48+
49+
const [banner, popup, helperLink] = await Promise.all([
50+
bannerService.getIncompleteBannersByUrl(url, bannerIds),
51+
popupService.getIncompletePopupsByUrl(url, popupIds),
52+
helperLinkService.getIncompleteHelpers(helperLinkIds),
53+
]);
54+
res.status(200).json({ banner, popup, helperLink });
55+
56+
} catch (error) {
57+
internalServerError(
58+
"GET_INCOMPLETE_GUIDES_BY_URL_ERROR",
59+
error.message,
60+
);
61+
}
62+
}
2663
}
2764

2865
module.exports = new GuideController();

backend/src/controllers/helperLink.controller.js

+13
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,19 @@ class LinkController {
185185
}
186186
}
187187

188+
async getAllHelpersWithLinks(_, res) {
189+
try {
190+
const links = await helperService.getAllHelpersWithLinks();
191+
res.status(200).json(links);
192+
} catch (err) {
193+
const { statusCode, payload } = internalServerError(
194+
"GET_ALL_HELPERS_WITH_LINKSERROR",
195+
err.message
196+
);
197+
res.status(statusCode).json(payload);
198+
}
199+
}
200+
188201
async getHelpersByUserId(req, res) {
189202
try {
190203
const userId = req.user.id;

backend/src/routes/guide.routes.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ const guideController = require("../controllers/guide.controller.js");
44
const router = express.Router();
55

66
router.post("/get_guides_by_url", guideController.getGuidesByUrl);
7-
// router.get("/get_incomplete_guides_by_url", guideController.getIncompleteGuidesByUrl);
7+
router.get("/get_incomplete_guides_by_url", guideController.getIncompleteGuidesByUrl);
88

99
module.exports = router;
+12-8
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
const express = require("express");
22
const helper = require("../controllers/helperLink.controller");
33
const authenticateJWT = require("../middleware/auth.middleware");
4-
4+
const settings = require('../../config/settings');
5+
const accessGuard = require('../middleware/accessGuard.middleware');
56
const helperController = helper.controller;
67

8+
79
const router = express.Router();
10+
const teamPermissions = settings.team.permissions;
11+
812

9-
router.use(authenticateJWT);
13+
router.post("/add_helper", authenticateJWT, accessGuard(teamPermissions.helpers), helperController.addHelper);
14+
router.get("/get_helpers", authenticateJWT, helperController.getHelpersByUserId);
15+
router.get("/get_helpers_with_links", authenticateJWT, helperController.getAllHelpersWithLinks);
16+
router.get("/all_helpers", authenticateJWT, helperController.getAllHelpers);
17+
router.get("/get_helper/:id", authenticateJWT, helperController.getHelperById);
18+
router.put("/edit_helper/:id", authenticateJWT, accessGuard(teamPermissions.helpers), helperController.editHelper);
19+
router.delete("/delete_helper/:id", authenticateJWT, accessGuard(teamPermissions.helpers), helperController.deleteHelper);
1020

11-
router.route("/add_helper").post(helperController.addHelper);
12-
router.route("/get_helpers").get(helperController.getHelpersByUserId);
13-
router.route("/all_helpers").get(helperController.getAllHelpers);
14-
router.route("/get_helper/:id").get(helperController.getHelperById);
15-
router.route("/edit_helper/:id").put(helperController.editHelper);
16-
router.route("/delete_helper/:id").delete(helperController.deleteHelper);
1721

1822
module.exports = router;

backend/src/service/banner.service.js

+14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const db = require("../models");
2+
const { Op } = require('sequelize');
23
const Banner = db.Banner;
34

45
class BannerService {
@@ -61,6 +62,19 @@ class BannerService {
6162
throw new Error("Error retrieving banner by URL");
6263
}
6364
};
65+
66+
async getIncompleteBannersByUrl(url, ids) {
67+
try {
68+
return await Banner.findAll({
69+
where: {
70+
url,
71+
id: { [Op.notIn]: ids }
72+
}
73+
});
74+
} catch (error) {
75+
throw new Error("Error retrieving banner by URL");
76+
}
77+
};
6478
}
6579

6680
module.exports = new BannerService();

backend/src/service/guidelog.service.js

+45
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const db = require("../models");
22
const GuideLog = db.GuideLog;
3+
const { GuideType } = require('../utils/guidelog.helper');
34

45
class GuideLogService {
56
async addGuideLog({ guideType, userId, guideId, completed }) {
@@ -22,6 +23,50 @@ class GuideLogService {
2223
async getAllGuideLogs() {
2324
return await GuideLog.findAll();
2425
}
26+
27+
async getCompleteBannerLogs(userId) {
28+
try {
29+
return await GuideLog.findAll({
30+
where: {
31+
userId: userId,
32+
completed: true,
33+
guideType: GuideType.BANNER
34+
},
35+
});
36+
} catch (err) {
37+
throw new Error(`Failed to retrieve banner log for user ${userId}: ${err.message}`);
38+
}
39+
}
40+
41+
async getCompletePopupLogs(userId) {
42+
try {
43+
return await GuideLog.findAll({
44+
where: {
45+
userId: userId,
46+
completed: true,
47+
guideType: GuideType.POPUP
48+
},
49+
});
50+
} catch (err) {
51+
throw new Error(`Failed to retrieve popup log for user ${userId}: ${err.message}`);
52+
}
53+
}
54+
55+
async getCompleteHelperLogs(userId) {
56+
try {
57+
return await GuideLog.findAll({
58+
where: {
59+
userId: userId,
60+
completed: true,
61+
guideType: GuideType.LINK
62+
},
63+
});
64+
} catch (err) {
65+
throw new Error(`Failed to retrieve helper link log for user ${userId}: ${err.message}`);
66+
}
67+
}
68+
69+
2570
async getCompleteGuideLogs(userId) {
2671
try {
2772
return await GuideLog.findAll({

backend/src/service/helperLink.service.js

+26
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
const { Op } = require("sequelize");
12
const db = require("../models");
23
const HelperLink = db.HelperLink;
34
const Link = db.Link;
@@ -17,6 +18,31 @@ class HelperLinkService {
1718
});
1819
}
1920

21+
async getAllHelpersWithLinks() {
22+
return await HelperLink.findAll({
23+
include: [
24+
{
25+
model: Link,
26+
as: "links",
27+
},
28+
]
29+
});
30+
}
31+
32+
async getIncompleteHelpers(ids) {
33+
return await HelperLink.findAll({
34+
include: [
35+
{
36+
model: Link,
37+
as: "links",
38+
},
39+
],
40+
where: {
41+
id: { [Op.notIn]: ids }
42+
}
43+
});
44+
}
45+
2046
async getHelpersByUserId(userId) {
2147
return await HelperLink.findAll({
2248
where: {

backend/src/service/popup.service.js

+17-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
const { Op } = require("sequelize");
12
const db = require("../models");
23
const Popup = db.Popup;
34

@@ -55,6 +56,14 @@ class PopupService {
5556
}
5657
}
5758

59+
async getPopupByUrl(url) {
60+
try {
61+
return await Popup.findAll({ where: { url } });
62+
} catch (error) {
63+
throw new Error("Error retrieving Popup by URL");
64+
}
65+
};
66+
5867
async getPopupByApiAndClientId(apiId, clientId) {
5968
try {
6069
return await Popup.findAll({
@@ -73,11 +82,16 @@ class PopupService {
7382
}
7483
}
7584

76-
async getPopupByUrl(url) {
85+
async getIncompletePopupsByUrl(url, ids) {
7786
try {
78-
return await Popup.findAll({ where: { url } });
87+
return await Popup.findAll({
88+
where: {
89+
url,
90+
id: { [Op.notIn]: ids }
91+
}
92+
});
7993
} catch (error) {
80-
throw new Error("Error retrieving Popup by URL");
94+
throw new Error("Error retrieving popup by URL");
8195
}
8296
};
8397
}

0 commit comments

Comments
 (0)