Skip to content

Commit 8d149ec

Browse files
authored
Merge pull request #251 from map-of-pi/feature-toggle-impl
Approved (1).
2 parents 322947f + 3793938 commit 8d149ec

File tree

11 files changed

+947
-1
lines changed

11 files changed

+947
-1
lines changed

src/config/docs/TogglesSchema.yml

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
components:
2+
schemas:
3+
AddToggleRq:
4+
type: object
5+
properties:
6+
name:
7+
type: string
8+
example: testToggle
9+
enabled:
10+
type: boolean
11+
example: false
12+
description:
13+
type: string
14+
example: This is a toggle description.
15+
required:
16+
- name
17+
- enabled
18+
- description
19+
20+
UpdateToggleRq:
21+
type: object
22+
properties:
23+
name:
24+
type: string
25+
example: testToggle
26+
enabled:
27+
type: boolean
28+
example: false
29+
description:
30+
type: string
31+
example: This is a toggle description.
32+
33+
GetAllTogglesRs:
34+
type: array
35+
items:
36+
type: object
37+
properties:
38+
name:
39+
type: string
40+
example: testToggle
41+
enabled:
42+
type: boolean
43+
example: false
44+
description:
45+
type: string
46+
example: This is a toggle description.
47+
48+
GetSingleToggleRs:
49+
type: object
50+
properties:
51+
name:
52+
type: string
53+
example: testToggle
54+
enabled:
55+
type: boolean
56+
example: false
57+
description:
58+
type: string
59+
example: This is a toggle description.
60+
61+
AddToggleRs:
62+
type: object
63+
properties:
64+
addedToggle:
65+
name:
66+
type: string
67+
example: testToggle
68+
enabled:
69+
type: boolean
70+
example: false
71+
description:
72+
type: string
73+
example: This is a toggle description.
74+
75+
UpdateToggleRs:
76+
type: object
77+
properties:
78+
updatedToggle:
79+
name:
80+
type: string
81+
example: testToggle
82+
enabled:
83+
type: boolean
84+
example: false
85+
description:
86+
type: string
87+
example: This is a toggle description.
88+
89+
DeleteToggleRs:
90+
type: object
91+
properties:
92+
deletedToggle:
93+
name:
94+
type: string
95+
example: testToggle
96+
enabled:
97+
type: boolean
98+
example: false
99+
description:
100+
type: string
101+
example: This is a toggle description.
102+
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { Request, Response } from "express";
2+
import * as toggleService from "../../services/admin/toggle.service";
3+
import { IToggle } from "../../types";
4+
5+
import logger from "../../config/loggingConfig";
6+
7+
export const getToggles = async (req: Request, res: Response) => {
8+
try {
9+
const existingToggles = await toggleService.getToggles();
10+
logger.info(`Successfully fetched ${ existingToggles.length } toggles`);
11+
return res.status(200).json(existingToggles);
12+
} catch (error) {
13+
logger.error('Failed to get toggles', error);
14+
return res.status(500).json({ message: 'An error occurred while fetching toggles; please try again later' });
15+
}
16+
};
17+
18+
export const getToggle = async (req: Request, res: Response) => {
19+
const { toggle_name } = req.params;
20+
try {
21+
const currentToggle = await toggleService.getToggleByName(toggle_name);
22+
if (!currentToggle) {
23+
logger.warn(`Toggle with identifier ${toggle_name} not found.`);
24+
return res.status(404).json({ message: "Toggle not found" });
25+
}
26+
logger.info(`Fetched toggle with identifier ${toggle_name}`);
27+
return res.status(200).json(currentToggle);
28+
} catch (error) {
29+
logger.error(`Failed to get toggle for identifier ${ toggle_name }:`, error);
30+
return res.status(500).json({ message: 'An error occurred while fetching toggle; please try again later' });
31+
}
32+
};
33+
34+
export const addToggle = async (req: Request, res: Response) => {
35+
const { name, enabled, description } = req.body;
36+
try {
37+
const newToggle = await toggleService.addToggle({ name, enabled, description } as IToggle);
38+
logger.info(`Successfully added toggle with identifier ${name}`);
39+
return res.status(201).json({ message: "Toggle successfully added", newToggle });
40+
} catch (error) {
41+
logger.error(`Failed to add toggle for identifier ${ name }:`, error);
42+
return res.status(500).json({ message: 'An error occurred while adding toggle; please try again later' });
43+
}
44+
};
45+
46+
export const updateToggle = async (req: Request, res: Response) => {
47+
const { name, enabled, description } = req.body;
48+
try {
49+
const updatedToggle = await toggleService.updateToggle(name, enabled, description);
50+
logger.info(`Successfully updated toggle with identifier ${name}`);
51+
return res.status(200).json({ message: "Toggle successfully updated", updatedToggle });
52+
} catch (error) {
53+
logger.error(`Failed to update toggle for identifier ${ name }:`, error);
54+
return res.status(500).json({ message: 'An error occurred while updating toggle; please try again later' });
55+
}
56+
};
57+
58+
export const deleteToggle = async (req: Request, res: Response) => {
59+
const { toggle_name } = req.params;
60+
try {
61+
const deletedToggle = await toggleService.deleteToggleByName(toggle_name);
62+
if (!deletedToggle) {
63+
logger.warn(`Toggle with identifier ${toggle_name} not found.`);
64+
return res.status(404).json({ message: "Toggle not found" });
65+
}
66+
logger.info(`Successfully deleted toggle with identifier ${toggle_name}`);
67+
return res.status(200).json({ message: "Toggle successfully deleted", deletedToggle });
68+
} catch (error) {
69+
logger.error(`Failed to delete toggle for identifier ${ toggle_name }:`, error);
70+
return res.status(500).json({ message: 'An error occurred while deleting toggle; please try again later' });
71+
}
72+
};

src/models/misc/Toggle.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import mongoose, { Schema } from "mongoose";
2+
3+
import { IToggle } from "../../types";
4+
5+
const toggleSchema = new Schema<IToggle>(
6+
{
7+
name: {
8+
type: String,
9+
required: true,
10+
unique: true,
11+
},
12+
enabled: {
13+
type: Boolean,
14+
required: true,
15+
default: false,
16+
},
17+
description: {
18+
type: String,
19+
required: false,
20+
},
21+
},
22+
{
23+
timestamps: true, // Automatically creates createdAt and updatedAt
24+
toJSON: {
25+
transform: function (doc, ret) {
26+
delete ret._id;
27+
delete ret.__v;
28+
return ret;
29+
}
30+
}
31+
}
32+
);
33+
34+
const Toggle = mongoose.model<IToggle>("Toggle", toggleSchema);
35+
36+
export default Toggle;

src/routes/toggle.routes.ts

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import { Router } from "express";
2+
3+
import * as toggleController from "../controllers/admin/toggleController";
4+
import { verifyAdminToken } from "../middlewares/verifyToken";
5+
6+
/**
7+
* @swagger
8+
* components:
9+
* schemas:
10+
* ToggleSchema:
11+
* type: object
12+
* properties:
13+
* name:
14+
* type: string
15+
* description: Name of the toggle
16+
* enabled:
17+
* type: boolean
18+
* description: State of the toggle
19+
* description:
20+
* type: string
21+
* description: Description of the toggle
22+
*/
23+
const toggleRoutes = Router();
24+
25+
/**
26+
* @swagger
27+
* /api/v1/toggles:
28+
* get:
29+
* tags:
30+
* - Toggle
31+
* summary: Get all existing toggles
32+
* responses:
33+
* 200:
34+
* description: Successful response
35+
* content:
36+
* application/json:
37+
* schema:
38+
* type: array
39+
* items:
40+
* $ref: '/api/docs/TogglesSchema.yml#/components/schemas/GetAllTogglesRs'
41+
* 500:
42+
* description: Internal server error
43+
*/
44+
toggleRoutes.get("/", toggleController.getToggles);
45+
46+
/**
47+
* @swagger
48+
* /api/v1/toggles/{toggle_name}:
49+
* get:
50+
* tags:
51+
* - Toggle
52+
* summary: Get the corresponding toggle by toggle name
53+
* parameters:
54+
* - name: toggle_name
55+
* in: path
56+
* required: true
57+
* schema:
58+
* type: string
59+
* description: The name of the toggle to retrieve
60+
* responses:
61+
* 200:
62+
* description: Successful response
63+
* content:
64+
* application/json:
65+
* schema:
66+
* type: array
67+
* items:
68+
* $ref: '/api/docs/TogglesSchema.yml#/components/schemas/GetSingleToggleRs'
69+
* 404:
70+
* description: Toggle not found
71+
* 500:
72+
* description: Internal server error
73+
*/
74+
toggleRoutes.get("/:toggle_name", toggleController.getToggle);
75+
76+
/**
77+
* @swagger
78+
* /api/v1/toggles/add:
79+
* post:
80+
* tags:
81+
* - Toggle
82+
* summary: Add a new toggle *
83+
* security:
84+
* - AdminPasswordAuth: []
85+
* requestBody:
86+
* required: true
87+
* content:
88+
* application/json:
89+
* schema:
90+
* $ref: '/api/docs/TogglesSchema.yml#/components/schemas/AddToggleRq'
91+
* responses:
92+
* 201:
93+
* description: Successful response
94+
* content:
95+
* application/json:
96+
* schema:
97+
* type: object
98+
* properties:
99+
* message:
100+
* type: string
101+
* example: "Toggle successfully added"
102+
* addedToggle:
103+
* $ref: '/api/docs/TogglesSchema.yml#/components/schemas/AddToggleRs'
104+
* 401:
105+
* description: Unauthorized
106+
* 500:
107+
* description: Internal server error
108+
*/
109+
toggleRoutes.post("/add", verifyAdminToken, toggleController.addToggle);
110+
111+
/**
112+
* @swagger
113+
* /api/v1/toggles/update:
114+
* put:
115+
* tags:
116+
* - Toggle
117+
* summary: Update an existing toggle *
118+
* security:
119+
* - AdminPasswordAuth: []
120+
* requestBody:
121+
* required: true
122+
* content:
123+
* application/json:
124+
* schema:
125+
* $ref: '/api/docs/TogglesSchema.yml#/components/schemas/UpdateToggleRq'
126+
* responses:
127+
* 200:
128+
* description: Successful response
129+
* content:
130+
* application/json:
131+
* schema:
132+
* type: object
133+
* properties:
134+
* message:
135+
* type: string
136+
* example: "Toggle successfully updated"
137+
* updatedToggle:
138+
* $ref: '/api/docs/TogglesSchema.yml#/components/schemas/UpdateToggleRs'
139+
* 401:
140+
* description: Unauthorized
141+
* 500:
142+
* description: Internal server error
143+
*/
144+
toggleRoutes.put("/update", verifyAdminToken, toggleController.updateToggle);
145+
146+
/**
147+
* @swagger
148+
* /api/v1/toggles/delete/{toggle_name}:
149+
* delete:
150+
* tags:
151+
* - Toggle
152+
* summary: Delete the corresponding toggle by toggle name *
153+
* security:
154+
* - AdminPasswordAuth: []
155+
* parameters:
156+
* - name: toggle_name
157+
* in: path
158+
* required: true
159+
* schema:
160+
* type: string
161+
* description: The name of the toggle to delete
162+
* responses:
163+
* 200:
164+
* description: Successful response
165+
* content:
166+
* application/json:
167+
* schema:
168+
* type: object
169+
* properties:
170+
* message:
171+
* type: string
172+
* example: "Toggle successfully deleted"
173+
* deletedToggle:
174+
* $ref: '/api/docs/TogglesSchema.yml#/components/schemas/DeleteToggleRs'
175+
* 404:
176+
* description: Toggle not found
177+
* 401:
178+
* description: Unauthorized
179+
* 500:
180+
* description: Internal server error
181+
*/
182+
toggleRoutes.delete("/delete/:toggle_name", verifyAdminToken, toggleController.deleteToggle);
183+
184+
export default toggleRoutes;

0 commit comments

Comments
 (0)