@@ -7,8 +7,9 @@ const path = require('path');
7
7
const app = express ( ) ;
8
8
const port = process . env . PORT || 3000 ;
9
9
const wikisFilePath = path . join ( __dirname , 'wikis.json' ) ;
10
+ const bannedUsersFilePath = path . join ( __dirname , 'bannedUsers.json' ) ;
10
11
11
- // Load the wikis from the file
12
+ // Load the wikis and banned users from the files
12
13
const loadWikis = ( ) => {
13
14
if ( fs . existsSync ( wikisFilePath ) ) {
14
15
const data = fs . readFileSync ( wikisFilePath , 'utf-8' ) ;
@@ -18,18 +19,37 @@ const loadWikis = () => {
18
19
}
19
20
} ;
20
21
21
- // Save the wikis to the file
22
+ const loadBannedUsers = ( ) => {
23
+ if ( fs . existsSync ( bannedUsersFilePath ) ) {
24
+ const data = fs . readFileSync ( bannedUsersFilePath , 'utf-8' ) ;
25
+ return JSON . parse ( data ) ;
26
+ } else {
27
+ return [ ] ;
28
+ }
29
+ } ;
30
+
31
+ // Save the wikis and banned users to their respective files
22
32
const saveWikis = ( wikis ) => {
23
33
fs . writeFileSync ( wikisFilePath , JSON . stringify ( wikis , null , 2 ) , 'utf-8' ) ;
24
34
} ;
25
35
36
+ const saveBannedUsers = ( bannedUsers ) => {
37
+ fs . writeFileSync ( bannedUsersFilePath , JSON . stringify ( bannedUsers , null , 2 ) , 'utf-8' ) ;
38
+ } ;
39
+
26
40
// In-memory storage for wikis (loaded from file)
27
41
let wikis = loadWikis ( ) ;
42
+ let bannedUsers = loadBannedUsers ( ) ;
28
43
29
44
app . use ( bodyParser . json ( ) ) ;
30
45
app . use ( cors ( ) ) ;
31
46
app . use ( express . static ( 'public' ) ) ;
32
47
48
+ // Middleware to check if user is banned
49
+ const isUserBanned = ( userId ) => {
50
+ return bannedUsers . includes ( userId ) ;
51
+ } ;
52
+
33
53
// Serve HTML page for a specific wiki title
34
54
app . get ( '/wiki/:title' , ( req , res ) => {
35
55
const { title } = req . params ;
@@ -75,22 +95,6 @@ app.get('/wiki/:title', (req, res) => {
75
95
<p>${ wiki . content } </p>
76
96
<small id="wiki-owner">${ wiki . owner } </small>
77
97
</div>
78
-
79
- <div class="comment-section">
80
- <h3>Comments</h3>
81
- ${ wiki . comments . slice ( - 7 ) . map ( comment => `
82
- <div class="comment" id="comment-${ comment . id } ">
83
- <div class="comment-author">${ comment . author } <small>(${ new Date ( comment . createdAt ) . toLocaleString ( ) } )</small></div>
84
- <div class="comment-content">${ comment . content } </div>
85
- ${ comment . replies . length > 0 ? comment . replies . map ( reply => `
86
- <div class="comment-reply">
87
- <strong>${ reply . author } </strong>: ${ reply . content } <small>(${ new Date ( reply . createdAt ) . toLocaleString ( ) } )</small>
88
- </div>
89
- ` ) . join ( '' ) : '' }
90
- </div>
91
- ` ) . join ( '' ) }
92
- </div>
93
-
94
98
<div class="comment-form">
95
99
<h3>Add a Comment</h3>
96
100
<textarea class="comment-input" id="comment-content" placeholder="Write your comment..." rows="4"></textarea>
@@ -104,7 +108,6 @@ app.get('/wiki/:title', (req, res) => {
104
108
.then(response => response.json())
105
109
.then(data => {
106
110
const ip = data.ip;
107
- // Use the IP as needed
108
111
console.log(ip);
109
112
});
110
113
const urlParams = new URLSearchParams(window.location.search);
@@ -122,14 +125,13 @@ app.get('/wiki/:title', (req, res) => {
122
125
})
123
126
.then(response => response.json())
124
127
.then(comment => {
125
- // Append new comment to the comment section
126
128
const commentSection = document.querySelector('.comment-section');
127
- commentSection.innerHTML += \ `
129
+ commentSection.innerHTML += `
128
130
< div class = "comment" id = "comment-${comment.id}" >
129
131
< div class = "comment-author" > ${ comment . author } </ div >
130
132
< div class = "comment-content" > $ { comment . content } </div >
131
133
< / div >
132
- \ `;
134
+ `;
133
135
} )
134
136
. catch ( error => console . error ( 'Error adding comment:' , error ) ) ;
135
137
}
@@ -139,7 +141,17 @@ app.get('/wiki/:title', (req, res) => {
139
141
`);
140
142
} ) ;
141
143
142
- // API: Get wiki details (including comments)
144
+ // API: Get all wikis (without comments)
145
+ app . get ( '/api/wikis' , ( req , res ) => {
146
+ res . json ( wikis . map ( wiki => ( {
147
+ id : wiki . id ,
148
+ title : wiki . title ,
149
+ content : wiki . content ,
150
+ owner : wiki . owner
151
+ } ) ) ) ;
152
+ } ) ;
153
+
154
+ // API: Get wiki details (without comments)
143
155
app . get ( '/api/wikis/:id' , ( req , res ) => {
144
156
const { id } = req . params ;
145
157
const wiki = wikis . find ( w => w . id === parseInt ( id ) ) ;
@@ -148,15 +160,23 @@ app.get('/api/wikis/:id', (req, res) => {
148
160
return res . status ( 404 ) . json ( { error : 'Wiki not found' } ) ;
149
161
}
150
162
151
- // Return the wiki details including comments
152
- res . json ( wiki ) ;
163
+ res . json ( {
164
+ id : wiki . id ,
165
+ title : wiki . title ,
166
+ content : wiki . content ,
167
+ owner : wiki . owner
168
+ } ) ;
153
169
} ) ;
154
170
155
171
// API: Add a comment to a specific wiki
156
172
app . post ( '/api/wikis/:id/comments' , ( req , res ) => {
157
173
const { id } = req . params ;
158
174
const { user, content, replyTo } = req . body ;
159
175
176
+ if ( isUserBanned ( user ) ) {
177
+ return res . status ( 403 ) . json ( { error : 'User is banned' } ) ;
178
+ }
179
+
160
180
const wiki = wikis . find ( w => w . id === parseInt ( id ) ) ;
161
181
if ( ! wiki ) {
162
182
return res . status ( 404 ) . json ( { error : 'Wiki not found' } ) ;
@@ -178,7 +198,6 @@ app.post('/api/wikis/:id/comments', (req, res) => {
178
198
replies : [ ] ,
179
199
} ;
180
200
181
- // If it's a reply, add to the appropriate parent comment's replies
182
201
if ( replyTo ) {
183
202
const parentComment = wiki . comments . find ( comment => comment . id === replyTo ) ;
184
203
if ( parentComment ) {
@@ -194,6 +213,90 @@ app.post('/api/wikis/:id/comments', (req, res) => {
194
213
res . status ( 201 ) . json ( newComment ) ;
195
214
} ) ;
196
215
216
+ // API: Edit a user's comment
217
+ app . put ( '/api/wikis/:id/comments/:commentId' , ( req , res ) => {
218
+ const { id, commentId } = req . params ;
219
+ const { user, content } = req . body ;
220
+
221
+ const wiki = wikis . find ( w => w . id === parseInt ( id ) ) ;
222
+ if ( ! wiki ) {
223
+ return res . status ( 404 ) . json ( { error : 'Wiki not found' } ) ;
224
+ }
225
+
226
+ const comment = wiki . comments . find ( c => c . id === parseInt ( commentId ) ) ;
227
+
228
+ if ( ! comment ) {
229
+ return res . status ( 404 ) . json ( { error : 'Comment not found' } ) ;
230
+ }
231
+
232
+ const username = atob ( user ) ; // Decode the username
233
+
234
+ if ( comment . author !== username ) {
235
+ return res . status ( 403 ) . json ( { error : 'You can only edit your own comments' } ) ;
236
+ }
237
+
238
+ if ( ! content ) {
239
+ return res . status ( 400 ) . json ( { error : 'Content is required' } ) ;
240
+ }
241
+
242
+ comment . content = content ;
243
+ comment . editedAt = new Date ( ) . toISOString ( ) ;
244
+
245
+ saveWikis ( wikis ) ;
246
+ res . json ( comment ) ;
247
+ } ) ;
248
+
249
+ // API: Delete a comment (Admin only)
250
+ app . delete ( '/api/wikis/:id/comments/:commentId' , ( req , res ) => {
251
+ const { id, commentId } = req . params ;
252
+
253
+ const wiki = wikis . find ( w => w . id === parseInt ( id ) ) ;
254
+ if ( ! wiki ) {
255
+ return res . status ( 404 ) . json ( { error : 'Wiki not found' } ) ;
256
+ }
257
+
258
+ const commentIndex = wiki . comments . findIndex ( c => c . id === parseInt ( commentId ) ) ;
259
+
260
+ if ( commentIndex === - 1 ) {
261
+ return res . status ( 404 ) . json ( { error : 'Comment not found' } ) ;
262
+ }
263
+
264
+ wiki . comments . splice ( commentIndex , 1 ) ;
265
+
266
+ saveWikis ( wikis ) ;
267
+ res . status ( 204 ) . end ( ) ;
268
+ } ) ;
269
+
270
+ // Admin: Ban a user
271
+ app . post ( '/api/admin/ban' , ( req , res ) => {
272
+ const { userId } = req . body ;
273
+
274
+ if ( ! userId ) {
275
+ return res . status ( 400 ) . json ( { error : 'User ID is required' } ) ;
276
+ }
277
+
278
+ if ( ! bannedUsers . includes ( userId ) ) {
279
+ bannedUsers . push ( userId ) ;
280
+ saveBannedUsers ( bannedUsers ) ;
281
+ res . status ( 201 ) . json ( { message : 'User banned successfully' } ) ;
282
+ } else {
283
+ res . status ( 400 ) . json ( { error : 'User is already banned' } ) ;
284
+ }
285
+ } ) ;
286
+
287
+ // Admin: Unban a user
288
+ app . post ( '/api/admin/unban' , ( req , res ) => {
289
+ const { userId } = req . body ;
290
+
291
+ if ( ! userId ) {
292
+ return res . status ( 400 ) . json ( { error : 'User ID is required' } ) ;
293
+ }
294
+
295
+ bannedUsers = bannedUsers . filter ( id => id !== userId ) ;
296
+ saveBannedUsers ( bannedUsers ) ;
297
+ res . status ( 201 ) . json ( { message : 'User unbanned successfully' } ) ;
298
+ } ) ;
299
+
197
300
// Start the server
198
301
app . listen ( port , ( ) => {
199
302
console . log ( `Server is running on port ${ port } ` ) ;
0 commit comments