Fossil SCM

Add the website_assert() macro. Fixes to forum post editing.

drh 2018-07-25 16:10 forum-v2
Commit e67efdd784156e6af05dee43e873e0f208f7580aacfc13a3fd9981925a664bd4
2 files changed +102 -63 +42 -37
+102 -63
--- src/forum.c
+++ src/forum.c
@@ -22,16 +22,25 @@
2222
#include "forum.h"
2323
2424
/*
2525
** Render a forum post for display
2626
*/
27
-void forum_render(const char *zMimetype, const char *zContent){
27
+void forum_render(
28
+ const char *zTitle,
29
+ const char *zMimetype,
30
+ const char *zContent
31
+){
2832
Blob x;
33
+ @ <div style='border: 1px solid black;padding: 1ex;'>
34
+ if( zTitle ){
35
+ @ <h1>%h(zTitle)</h1>
36
+ }
2937
blob_init(&x, 0, 0);
3038
blob_append(&x, zContent, -1);
3139
wiki_render_by_mimetype(&x, zMimetype);
3240
blob_reset(&x);
41
+ @ </div>
3342
}
3443
3544
/*
3645
** Display all posts in a forum thread in chronological order
3746
*/
@@ -65,13 +74,13 @@
6574
if( firt ){
6675
@ reply to %d(firt)
6776
}
6877
if( g.perm.Debug ){
6978
@ <span class="debug">\
70
- @ <a href="%R/artifact/%h(zUuid)">raw artifact</a></span>
79
+ @ <a href="%R/artifact/%h(zUuid)">artifact</a></span>
7180
}
72
- forum_render(pPost->zMimetype, pPost->zWiki);
81
+ forum_render(0, pPost->zMimetype, pPost->zWiki);
7382
if( g.perm.WrForum ){
7483
int sameUser = login_is_individual()
7584
&& fossil_strcmp(pPost->zUser, g.zLogin)==0;
7685
int isPrivate = content_is_private(fpid);
7786
@ <p><form action="%R/forumedit" method="POST">
@@ -161,39 +170,51 @@
161170
int iEdit, /* Post being edited, or zero for a new post */
162171
const char *zUser, /* Username. NULL means use login name */
163172
const char *zMimetype, /* Mimetype of content. */
164173
const char *zContent /* Content */
165174
){
166
- Blob x, cksum;
167175
char *zDate;
176
+ char *zI;
177
+ char *zG;
178
+ int iBasis;
179
+ Blob x, cksum, formatCheck, errMsg;
180
+ Manifest *pPost;
181
+
168182
schema_forum();
183
+ if( iInReplyTo==0 && iEdit>0 ){
184
+ iBasis = iEdit;
185
+ iInReplyTo = db_int(0, "SELECT firt FROM forumpost WHERE fpid=%d", iEdit);
186
+ }else{
187
+ iBasis = iInReplyTo;
188
+ }
189
+ webpage_assert( (zTitle==0)+(iInReplyTo==0)==1 );
169190
blob_init(&x, 0, 0);
170191
zDate = date_in_standard_format("now");
171192
blob_appendf(&x, "D %s\n", zDate);
172193
fossil_free(zDate);
173
- if( zTitle ){
174
- blob_appendf(&x, "H %F\n", zTitle);
175
- }else{
176
- char *zG = db_text(0,
177
- "SELECT uuid FROM blob, forumpost"
178
- " WHERE blob.rid==forumpost.froot"
179
- " AND forumpost.fpid=%d", iInReplyTo);
180
- char *zI;
181
- if( zG==0 ) goto forum_post_error;
194
+ zG = db_text(0,
195
+ "SELECT uuid FROM blob, forumpost"
196
+ " WHERE blob.rid==forumpost.froot"
197
+ " AND forumpost.fpid=%d", iBasis);
198
+ if( zG ){
182199
blob_appendf(&x, "G %s\n", zG);
183200
fossil_free(zG);
184
- zI = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", iInReplyTo);
185
- if( zI==0 ) goto forum_post_error;
201
+ }
202
+ if( zTitle ){
203
+ blob_appendf(&x, "H %F\n", zTitle);
204
+ }
205
+ zI = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", iInReplyTo);
206
+ if( zI ){
186207
blob_appendf(&x, "I %s\n", zI);
187208
fossil_free(zI);
188209
}
189210
if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")!=0 ){
190211
blob_appendf(&x, "N %s\n", zMimetype);
191212
}
192213
if( iEdit>0 ){
193214
char *zP = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", iEdit);
194
- if( zP==0 ) goto forum_post_error;
215
+ if( zP==0 ) webpage_error("missing edit artifact %d", iEdit);
195216
blob_appendf(&x, "P %s\n", zP);
196217
fossil_free(zP);
197218
}
198219
if( zUser==0 ){
199220
if( login_is_nobody() ){
@@ -205,24 +226,36 @@
205226
blob_appendf(&x, "U %F\n", zUser);
206227
blob_appendf(&x, "W %d\n%s\n", strlen(zContent), zContent);
207228
md5sum_blob(&x, &cksum);
208229
blob_appendf(&x, "Z %b\n", &cksum);
209230
blob_reset(&cksum);
231
+
232
+ /* Verify that the artifact we are creating is well-formed */
233
+ blob_init(&formatCheck, 0, 0);
234
+ blob_init(&errMsg, 0, 0);
235
+ blob_copy(&formatCheck, &x);
236
+ pPost = manifest_parse(&formatCheck, 0, &errMsg);
237
+ if( pPost==0 ){
238
+ webpage_error("malformed forum post artifact - %s", blob_str(&errMsg));
239
+ }
240
+ if( pPost->type!=CFTYPE_FORUM ){
241
+ webpage_error("forum post artifact malformed");
242
+ }
243
+ manifest_destroy(pPost);
244
+
210245
if( P("dryrun") ){
211246
@ <div class='debug'>
212247
@ This is the artifact that would have been generated:
213248
@ <pre>%h(blob_str(&x))</pre>
214249
@ </div>
250
+ blob_reset(&x);
251
+ return 0;
215252
}else{
216253
int nrid = wiki_put(&x, 0, forum_need_moderation());
217254
cgi_redirectf("%R/forumthread/%S", rid_to_uuid(nrid));
218255
return 1;
219256
}
220
-
221
-forum_post_error:
222
- blob_reset(&x);
223
- return 0;
224257
}
225258
226259
/*
227260
** Paint the form elements for entering a Forum post
228261
*/
@@ -256,13 +289,12 @@
256289
}
257290
if( P("submit") ){
258291
if( forum_post(zTitle, 0, 0, 0, zMimetype, zContent) ) return;
259292
}
260293
if( P("preview") ){
261
- @ <h1>%h(zTitle)</h1>
262
- forum_render(zMimetype, zContent);
263
- @ <hr>
294
+ @ <h1>Preview:</h1>
295
+ forum_render(zTitle, zMimetype, zContent);
264296
}
265297
style_header("New Forum Thread");
266298
@ <form action="%R/%s(g.zPath)" method="POST">
267299
forum_entry_widget(zTitle, zMimetype, zContent);
268300
@ <input type="submit" name="preview" value="Preview">
@@ -284,24 +316,10 @@
284316
}
285317
@ </form>
286318
style_footer();
287319
}
288320
289
-/*
290
-** WEBPAGE: forumreply
291
-**
292
-** Reply to a forum message.
293
-** Query parameters:
294
-**
295
-** name=X Hash of the post to reply to. REQUIRED
296
-*/
297
-void forumreply_page(void){
298
- style_header("Pending");
299
- @ TBD...
300
- style_footer();
301
-}
302
-
303321
/*
304322
** WEBPAGE: forumedit
305323
**
306324
** Edit an existing forum message.
307325
** Query parameters:
@@ -309,20 +327,22 @@
309327
** name=X Hash of the post to be editted. REQUIRED
310328
*/
311329
void forumedit_page(void){
312330
int fpid;
313331
Manifest *pPost;
332
+ const char *zMimetype = 0;
333
+ const char *zContent = 0;
334
+ const char *zTitle = 0;
314335
315336
login_check_credentials();
316337
if( !g.perm.WrForum ){
317338
login_needed(g.anon.WrForum);
318339
return;
319340
}
320341
fpid = symbolic_name_to_rid(PD("fpid",""), "f");
321342
if( fpid<=0 || (pPost = manifest_get(fpid, CFTYPE_FORUM, 0))==0 ){
322343
webpage_error("Missing or invalid fpid query parameter");
323
- return;
324344
}
325345
if( g.perm.ModForum ){
326346
if( P("approve") ){
327347
webpage_not_yet_implemented();
328348
return;
@@ -337,49 +357,68 @@
337357
const char *zMimetype = PD("mimetype","text/x-fossil-wiki");
338358
const char *zContent = PDT("content","");
339359
if( P("reply") ){
340360
done = forum_post(0, fpid, 0, 0, zMimetype, zContent);
341361
}else if( P("edit") ){
342
- done = forum_post(0, 0, fpid, 0, zMimetype, zContent);
362
+ done = forum_post(P("title"), 0, fpid, 0, zMimetype, zContent);
343363
}else{
344
- webpage_error("Need one of 'edit' or 'reply' query parameters");
364
+ webpage_error("Missing 'reply' query parameter");
345365
}
346366
if( done ) return;
347367
}
348368
if( P("edit") ){
349369
/* Provide an edit to the fpid post */
350
- webpage_not_yet_implemented();
351
- return;
370
+ zMimetype = P("mimetype");
371
+ zContent = PT("content");
372
+ zTitle = P("title");
373
+ if( zContent==0 ) zContent = fossil_strdup(pPost->zWiki);
374
+ if( zMimetype==0 ) zMimetype = fossil_strdup(pPost->zMimetype);
375
+ if( zTitle==0 && pPost->zThreadTitle!=0 ){
376
+ zTitle = fossil_strdup(pPost->zThreadTitle);
377
+ }
378
+ style_header("Forum Edit");
379
+ @ <h1>Original Post:</h1>
380
+ forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki);
381
+ if( P("preview") ){
382
+ @ <h1>Preview Of Editted Post:</h1>
383
+ forum_render(zTitle, zMimetype, zContent);
384
+ }
385
+ @ <h1>
386
+ @ <h1>Enter A Reply:</h1>
387
+ @ <form action="%R/forumedit" method="POST">
388
+ @ <input type="hidden" name="fpid" value="%h(P("fpid"))">
389
+ @ <input type="hidden" name="edit" value="1">
390
+ forum_entry_widget(zTitle, zMimetype, zContent);
352391
}else{
353
- const char *zMimetype = PD("mimetype","text/x-fossil-wiki");
354
- const char *zContent = PDT("content","");
392
+ zMimetype = PD("mimetype","text/x-fossil-wiki");
393
+ zContent = PDT("content","");
355394
style_header("Forum Reply");
356395
@ <h1>Replying To:</h1>
357
- forum_render(pPost->zMimetype, pPost->zWiki);
396
+ forum_render(0, pPost->zMimetype, pPost->zWiki);
358397
if( P("preview") ){
359398
@ <h1>Preview:</h1>
360
- forum_render(zMimetype,zContent);
399
+ forum_render(0, zMimetype,zContent);
361400
}
362401
@ <h1>Enter A Reply:</h1>
363402
@ <form action="%R/forumedit" method="POST">
364403
@ <input type="hidden" name="fpid" value="%h(P("fpid"))">
365404
@ <input type="hidden" name="reply" value="1">
366405
forum_entry_widget(0, zMimetype, zContent);
367
- @ <input type="submit" name="preview" value="Preview">
368
- if( P("preview") ){
369
- @ <input type="submit" name="submit" value="Submit">
370
- }
371
- if( g.perm.Debug ){
372
- /* For the test-forumnew page add these extra debugging controls */
373
- @ <div class="debug">
374
- @ <label><input type="checkbox" name="dryrun" %s(PCK("dryrun"))> \
375
- @ Dry run</label>
376
- @ <br><label><input type="checkbox" name="domod" %s(PCK("domod"))> \
377
- @ Require moderator approval</label>
378
- @ <br><label><input type="checkbox" name="showqp" %s(PCK("showqp"))> \
379
- @ Show query parameters</label>
380
- @ </div>
381
- }
382
- @ </form>
383
- }
406
+ }
407
+ @ <input type="submit" name="preview" value="Preview">
408
+ if( P("preview") ){
409
+ @ <input type="submit" name="submit" value="Submit">
410
+ }
411
+ if( g.perm.Debug ){
412
+ /* For the test-forumnew page add these extra debugging controls */
413
+ @ <div class="debug">
414
+ @ <label><input type="checkbox" name="dryrun" %s(PCK("dryrun"))> \
415
+ @ Dry run</label>
416
+ @ <br><label><input type="checkbox" name="domod" %s(PCK("domod"))> \
417
+ @ Require moderator approval</label>
418
+ @ <br><label><input type="checkbox" name="showqp" %s(PCK("showqp"))> \
419
+ @ Show query parameters</label>
420
+ @ </div>
421
+ }
422
+ @ </form>
384423
style_footer();
385424
}
386425
--- src/forum.c
+++ src/forum.c
@@ -22,16 +22,25 @@
22 #include "forum.h"
23
24 /*
25 ** Render a forum post for display
26 */
27 void forum_render(const char *zMimetype, const char *zContent){
 
 
 
 
28 Blob x;
 
 
 
 
29 blob_init(&x, 0, 0);
30 blob_append(&x, zContent, -1);
31 wiki_render_by_mimetype(&x, zMimetype);
32 blob_reset(&x);
 
33 }
34
35 /*
36 ** Display all posts in a forum thread in chronological order
37 */
@@ -65,13 +74,13 @@
65 if( firt ){
66 @ reply to %d(firt)
67 }
68 if( g.perm.Debug ){
69 @ <span class="debug">\
70 @ <a href="%R/artifact/%h(zUuid)">raw artifact</a></span>
71 }
72 forum_render(pPost->zMimetype, pPost->zWiki);
73 if( g.perm.WrForum ){
74 int sameUser = login_is_individual()
75 && fossil_strcmp(pPost->zUser, g.zLogin)==0;
76 int isPrivate = content_is_private(fpid);
77 @ <p><form action="%R/forumedit" method="POST">
@@ -161,39 +170,51 @@
161 int iEdit, /* Post being edited, or zero for a new post */
162 const char *zUser, /* Username. NULL means use login name */
163 const char *zMimetype, /* Mimetype of content. */
164 const char *zContent /* Content */
165 ){
166 Blob x, cksum;
167 char *zDate;
 
 
 
 
 
 
168 schema_forum();
 
 
 
 
 
 
 
169 blob_init(&x, 0, 0);
170 zDate = date_in_standard_format("now");
171 blob_appendf(&x, "D %s\n", zDate);
172 fossil_free(zDate);
173 if( zTitle ){
174 blob_appendf(&x, "H %F\n", zTitle);
175 }else{
176 char *zG = db_text(0,
177 "SELECT uuid FROM blob, forumpost"
178 " WHERE blob.rid==forumpost.froot"
179 " AND forumpost.fpid=%d", iInReplyTo);
180 char *zI;
181 if( zG==0 ) goto forum_post_error;
182 blob_appendf(&x, "G %s\n", zG);
183 fossil_free(zG);
184 zI = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", iInReplyTo);
185 if( zI==0 ) goto forum_post_error;
 
 
 
 
186 blob_appendf(&x, "I %s\n", zI);
187 fossil_free(zI);
188 }
189 if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")!=0 ){
190 blob_appendf(&x, "N %s\n", zMimetype);
191 }
192 if( iEdit>0 ){
193 char *zP = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", iEdit);
194 if( zP==0 ) goto forum_post_error;
195 blob_appendf(&x, "P %s\n", zP);
196 fossil_free(zP);
197 }
198 if( zUser==0 ){
199 if( login_is_nobody() ){
@@ -205,24 +226,36 @@
205 blob_appendf(&x, "U %F\n", zUser);
206 blob_appendf(&x, "W %d\n%s\n", strlen(zContent), zContent);
207 md5sum_blob(&x, &cksum);
208 blob_appendf(&x, "Z %b\n", &cksum);
209 blob_reset(&cksum);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210 if( P("dryrun") ){
211 @ <div class='debug'>
212 @ This is the artifact that would have been generated:
213 @ <pre>%h(blob_str(&x))</pre>
214 @ </div>
 
 
215 }else{
216 int nrid = wiki_put(&x, 0, forum_need_moderation());
217 cgi_redirectf("%R/forumthread/%S", rid_to_uuid(nrid));
218 return 1;
219 }
220
221 forum_post_error:
222 blob_reset(&x);
223 return 0;
224 }
225
226 /*
227 ** Paint the form elements for entering a Forum post
228 */
@@ -256,13 +289,12 @@
256 }
257 if( P("submit") ){
258 if( forum_post(zTitle, 0, 0, 0, zMimetype, zContent) ) return;
259 }
260 if( P("preview") ){
261 @ <h1>%h(zTitle)</h1>
262 forum_render(zMimetype, zContent);
263 @ <hr>
264 }
265 style_header("New Forum Thread");
266 @ <form action="%R/%s(g.zPath)" method="POST">
267 forum_entry_widget(zTitle, zMimetype, zContent);
268 @ <input type="submit" name="preview" value="Preview">
@@ -284,24 +316,10 @@
284 }
285 @ </form>
286 style_footer();
287 }
288
289 /*
290 ** WEBPAGE: forumreply
291 **
292 ** Reply to a forum message.
293 ** Query parameters:
294 **
295 ** name=X Hash of the post to reply to. REQUIRED
296 */
297 void forumreply_page(void){
298 style_header("Pending");
299 @ TBD...
300 style_footer();
301 }
302
303 /*
304 ** WEBPAGE: forumedit
305 **
306 ** Edit an existing forum message.
307 ** Query parameters:
@@ -309,20 +327,22 @@
309 ** name=X Hash of the post to be editted. REQUIRED
310 */
311 void forumedit_page(void){
312 int fpid;
313 Manifest *pPost;
 
 
 
314
315 login_check_credentials();
316 if( !g.perm.WrForum ){
317 login_needed(g.anon.WrForum);
318 return;
319 }
320 fpid = symbolic_name_to_rid(PD("fpid",""), "f");
321 if( fpid<=0 || (pPost = manifest_get(fpid, CFTYPE_FORUM, 0))==0 ){
322 webpage_error("Missing or invalid fpid query parameter");
323 return;
324 }
325 if( g.perm.ModForum ){
326 if( P("approve") ){
327 webpage_not_yet_implemented();
328 return;
@@ -337,49 +357,68 @@
337 const char *zMimetype = PD("mimetype","text/x-fossil-wiki");
338 const char *zContent = PDT("content","");
339 if( P("reply") ){
340 done = forum_post(0, fpid, 0, 0, zMimetype, zContent);
341 }else if( P("edit") ){
342 done = forum_post(0, 0, fpid, 0, zMimetype, zContent);
343 }else{
344 webpage_error("Need one of 'edit' or 'reply' query parameters");
345 }
346 if( done ) return;
347 }
348 if( P("edit") ){
349 /* Provide an edit to the fpid post */
350 webpage_not_yet_implemented();
351 return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352 }else{
353 const char *zMimetype = PD("mimetype","text/x-fossil-wiki");
354 const char *zContent = PDT("content","");
355 style_header("Forum Reply");
356 @ <h1>Replying To:</h1>
357 forum_render(pPost->zMimetype, pPost->zWiki);
358 if( P("preview") ){
359 @ <h1>Preview:</h1>
360 forum_render(zMimetype,zContent);
361 }
362 @ <h1>Enter A Reply:</h1>
363 @ <form action="%R/forumedit" method="POST">
364 @ <input type="hidden" name="fpid" value="%h(P("fpid"))">
365 @ <input type="hidden" name="reply" value="1">
366 forum_entry_widget(0, zMimetype, zContent);
367 @ <input type="submit" name="preview" value="Preview">
368 if( P("preview") ){
369 @ <input type="submit" name="submit" value="Submit">
370 }
371 if( g.perm.Debug ){
372 /* For the test-forumnew page add these extra debugging controls */
373 @ <div class="debug">
374 @ <label><input type="checkbox" name="dryrun" %s(PCK("dryrun"))> \
375 @ Dry run</label>
376 @ <br><label><input type="checkbox" name="domod" %s(PCK("domod"))> \
377 @ Require moderator approval</label>
378 @ <br><label><input type="checkbox" name="showqp" %s(PCK("showqp"))> \
379 @ Show query parameters</label>
380 @ </div>
381 }
382 @ </form>
383 }
384 style_footer();
385 }
386
--- src/forum.c
+++ src/forum.c
@@ -22,16 +22,25 @@
22 #include "forum.h"
23
24 /*
25 ** Render a forum post for display
26 */
27 void forum_render(
28 const char *zTitle,
29 const char *zMimetype,
30 const char *zContent
31 ){
32 Blob x;
33 @ <div style='border: 1px solid black;padding: 1ex;'>
34 if( zTitle ){
35 @ <h1>%h(zTitle)</h1>
36 }
37 blob_init(&x, 0, 0);
38 blob_append(&x, zContent, -1);
39 wiki_render_by_mimetype(&x, zMimetype);
40 blob_reset(&x);
41 @ </div>
42 }
43
44 /*
45 ** Display all posts in a forum thread in chronological order
46 */
@@ -65,13 +74,13 @@
74 if( firt ){
75 @ reply to %d(firt)
76 }
77 if( g.perm.Debug ){
78 @ <span class="debug">\
79 @ <a href="%R/artifact/%h(zUuid)">artifact</a></span>
80 }
81 forum_render(0, pPost->zMimetype, pPost->zWiki);
82 if( g.perm.WrForum ){
83 int sameUser = login_is_individual()
84 && fossil_strcmp(pPost->zUser, g.zLogin)==0;
85 int isPrivate = content_is_private(fpid);
86 @ <p><form action="%R/forumedit" method="POST">
@@ -161,39 +170,51 @@
170 int iEdit, /* Post being edited, or zero for a new post */
171 const char *zUser, /* Username. NULL means use login name */
172 const char *zMimetype, /* Mimetype of content. */
173 const char *zContent /* Content */
174 ){
 
175 char *zDate;
176 char *zI;
177 char *zG;
178 int iBasis;
179 Blob x, cksum, formatCheck, errMsg;
180 Manifest *pPost;
181
182 schema_forum();
183 if( iInReplyTo==0 && iEdit>0 ){
184 iBasis = iEdit;
185 iInReplyTo = db_int(0, "SELECT firt FROM forumpost WHERE fpid=%d", iEdit);
186 }else{
187 iBasis = iInReplyTo;
188 }
189 webpage_assert( (zTitle==0)+(iInReplyTo==0)==1 );
190 blob_init(&x, 0, 0);
191 zDate = date_in_standard_format("now");
192 blob_appendf(&x, "D %s\n", zDate);
193 fossil_free(zDate);
194 zG = db_text(0,
195 "SELECT uuid FROM blob, forumpost"
196 " WHERE blob.rid==forumpost.froot"
197 " AND forumpost.fpid=%d", iBasis);
198 if( zG ){
 
 
 
 
199 blob_appendf(&x, "G %s\n", zG);
200 fossil_free(zG);
201 }
202 if( zTitle ){
203 blob_appendf(&x, "H %F\n", zTitle);
204 }
205 zI = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", iInReplyTo);
206 if( zI ){
207 blob_appendf(&x, "I %s\n", zI);
208 fossil_free(zI);
209 }
210 if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")!=0 ){
211 blob_appendf(&x, "N %s\n", zMimetype);
212 }
213 if( iEdit>0 ){
214 char *zP = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", iEdit);
215 if( zP==0 ) webpage_error("missing edit artifact %d", iEdit);
216 blob_appendf(&x, "P %s\n", zP);
217 fossil_free(zP);
218 }
219 if( zUser==0 ){
220 if( login_is_nobody() ){
@@ -205,24 +226,36 @@
226 blob_appendf(&x, "U %F\n", zUser);
227 blob_appendf(&x, "W %d\n%s\n", strlen(zContent), zContent);
228 md5sum_blob(&x, &cksum);
229 blob_appendf(&x, "Z %b\n", &cksum);
230 blob_reset(&cksum);
231
232 /* Verify that the artifact we are creating is well-formed */
233 blob_init(&formatCheck, 0, 0);
234 blob_init(&errMsg, 0, 0);
235 blob_copy(&formatCheck, &x);
236 pPost = manifest_parse(&formatCheck, 0, &errMsg);
237 if( pPost==0 ){
238 webpage_error("malformed forum post artifact - %s", blob_str(&errMsg));
239 }
240 if( pPost->type!=CFTYPE_FORUM ){
241 webpage_error("forum post artifact malformed");
242 }
243 manifest_destroy(pPost);
244
245 if( P("dryrun") ){
246 @ <div class='debug'>
247 @ This is the artifact that would have been generated:
248 @ <pre>%h(blob_str(&x))</pre>
249 @ </div>
250 blob_reset(&x);
251 return 0;
252 }else{
253 int nrid = wiki_put(&x, 0, forum_need_moderation());
254 cgi_redirectf("%R/forumthread/%S", rid_to_uuid(nrid));
255 return 1;
256 }
 
 
 
 
257 }
258
259 /*
260 ** Paint the form elements for entering a Forum post
261 */
@@ -256,13 +289,12 @@
289 }
290 if( P("submit") ){
291 if( forum_post(zTitle, 0, 0, 0, zMimetype, zContent) ) return;
292 }
293 if( P("preview") ){
294 @ <h1>Preview:</h1>
295 forum_render(zTitle, zMimetype, zContent);
 
296 }
297 style_header("New Forum Thread");
298 @ <form action="%R/%s(g.zPath)" method="POST">
299 forum_entry_widget(zTitle, zMimetype, zContent);
300 @ <input type="submit" name="preview" value="Preview">
@@ -284,24 +316,10 @@
316 }
317 @ </form>
318 style_footer();
319 }
320
 
 
 
 
 
 
 
 
 
 
 
 
 
 
321 /*
322 ** WEBPAGE: forumedit
323 **
324 ** Edit an existing forum message.
325 ** Query parameters:
@@ -309,20 +327,22 @@
327 ** name=X Hash of the post to be editted. REQUIRED
328 */
329 void forumedit_page(void){
330 int fpid;
331 Manifest *pPost;
332 const char *zMimetype = 0;
333 const char *zContent = 0;
334 const char *zTitle = 0;
335
336 login_check_credentials();
337 if( !g.perm.WrForum ){
338 login_needed(g.anon.WrForum);
339 return;
340 }
341 fpid = symbolic_name_to_rid(PD("fpid",""), "f");
342 if( fpid<=0 || (pPost = manifest_get(fpid, CFTYPE_FORUM, 0))==0 ){
343 webpage_error("Missing or invalid fpid query parameter");
 
344 }
345 if( g.perm.ModForum ){
346 if( P("approve") ){
347 webpage_not_yet_implemented();
348 return;
@@ -337,49 +357,68 @@
357 const char *zMimetype = PD("mimetype","text/x-fossil-wiki");
358 const char *zContent = PDT("content","");
359 if( P("reply") ){
360 done = forum_post(0, fpid, 0, 0, zMimetype, zContent);
361 }else if( P("edit") ){
362 done = forum_post(P("title"), 0, fpid, 0, zMimetype, zContent);
363 }else{
364 webpage_error("Missing 'reply' query parameter");
365 }
366 if( done ) return;
367 }
368 if( P("edit") ){
369 /* Provide an edit to the fpid post */
370 zMimetype = P("mimetype");
371 zContent = PT("content");
372 zTitle = P("title");
373 if( zContent==0 ) zContent = fossil_strdup(pPost->zWiki);
374 if( zMimetype==0 ) zMimetype = fossil_strdup(pPost->zMimetype);
375 if( zTitle==0 && pPost->zThreadTitle!=0 ){
376 zTitle = fossil_strdup(pPost->zThreadTitle);
377 }
378 style_header("Forum Edit");
379 @ <h1>Original Post:</h1>
380 forum_render(pPost->zThreadTitle, pPost->zMimetype, pPost->zWiki);
381 if( P("preview") ){
382 @ <h1>Preview Of Editted Post:</h1>
383 forum_render(zTitle, zMimetype, zContent);
384 }
385 @ <h1>
386 @ <h1>Enter A Reply:</h1>
387 @ <form action="%R/forumedit" method="POST">
388 @ <input type="hidden" name="fpid" value="%h(P("fpid"))">
389 @ <input type="hidden" name="edit" value="1">
390 forum_entry_widget(zTitle, zMimetype, zContent);
391 }else{
392 zMimetype = PD("mimetype","text/x-fossil-wiki");
393 zContent = PDT("content","");
394 style_header("Forum Reply");
395 @ <h1>Replying To:</h1>
396 forum_render(0, pPost->zMimetype, pPost->zWiki);
397 if( P("preview") ){
398 @ <h1>Preview:</h1>
399 forum_render(0, zMimetype,zContent);
400 }
401 @ <h1>Enter A Reply:</h1>
402 @ <form action="%R/forumedit" method="POST">
403 @ <input type="hidden" name="fpid" value="%h(P("fpid"))">
404 @ <input type="hidden" name="reply" value="1">
405 forum_entry_widget(0, zMimetype, zContent);
406 }
407 @ <input type="submit" name="preview" value="Preview">
408 if( P("preview") ){
409 @ <input type="submit" name="submit" value="Submit">
410 }
411 if( g.perm.Debug ){
412 /* For the test-forumnew page add these extra debugging controls */
413 @ <div class="debug">
414 @ <label><input type="checkbox" name="dryrun" %s(PCK("dryrun"))> \
415 @ Dry run</label>
416 @ <br><label><input type="checkbox" name="domod" %s(PCK("domod"))> \
417 @ Require moderator approval</label>
418 @ <br><label><input type="checkbox" name="showqp" %s(PCK("showqp"))> \
419 @ Show query parameters</label>
420 @ </div>
421 }
422 @ </form>
423 style_footer();
424 }
425
+42 -37
--- src/style.c
+++ src/style.c
@@ -936,11 +936,11 @@
936936
** If zFormat is an empty string, then this is the /test_env page.
937937
*/
938938
void webpage_error(const char *zFormat, ...){
939939
int i;
940940
int showAll;
941
- char *zErr;
941
+ char *zErr = 0;
942942
int isAuth = 0;
943943
char zCap[100];
944944
static const char *const azCgiVars[] = {
945945
"COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE",
946946
"HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING",
@@ -969,16 +969,11 @@
969969
va_start(ap, zFormat);
970970
zErr = vmprintf(zFormat, ap);
971971
va_end(ap);
972972
style_header("Bad Request");
973973
@ <h1>/%h(g.zPath): %h(zErr)</h1>
974
- fossil_free(zErr);
975974
showAll = 0;
976
- if( !isAuth ){
977
- style_footer();
978
- return;
979
- }
980975
}else if( !isAuth ){
981976
login_needed(0);
982977
return;
983978
}else{
984979
style_header("Environment Test");
@@ -985,46 +980,56 @@
985980
showAll = PB("showall");
986981
style_submenu_checkbox("showall", "Cookies", 0, 0);
987982
style_submenu_element("Stats", "%R/stat");
988983
}
989984
990
-#if !defined(_WIN32)
991
- @ uid=%d(getuid()), gid=%d(getgid())<br />
992
-#endif
993
- @ g.zBaseURL = %h(g.zBaseURL)<br />
994
- @ g.zHttpsURL = %h(g.zHttpsURL)<br />
995
- @ g.zTop = %h(g.zTop)<br />
996
- @ g.zPath = %h(g.zPath)<br />
997
- @ g.userUid = %d(g.userUid)<br />
998
- @ g.zLogin = %h(g.zLogin)<br />
999
- @ g.isHuman = %d(g.isHuman)<br />
1000
- if( g.nRequest ){
1001
- @ g.nRequest = %d(g.nRequest)<br />
1002
- }
1003
- if( g.nPendingRequest>1 ){
1004
- @ g.nPendingRequest = %d(g.nPendingRequest)<br />
1005
- }
1006
- @ capabilities = %s(find_capabilities(zCap))<br />
1007
- if( zCap[0] ){
1008
- @ anonymous-adds = %s(find_anon_capabilities(zCap))<br />
1009
- }
1010
- @ g.zRepositoryName = %h(g.zRepositoryName)<br />
1011
- @ load_average() = %f(load_average())<br />
1012
- @ cgi_csrf_safe(0) = %d(cgi_csrf_safe(0))<br />
1013
- @ <hr />
1014
- P("HTTP_USER_AGENT");
1015
- cgi_print_all(showAll, 0);
1016
- if( showAll && blob_size(&g.httpHeader)>0 ){
1017
- @ <hr />
1018
- @ <pre>
1019
- @ %h(blob_str(&g.httpHeader))
1020
- @ </pre>
985
+ if( isAuth ){
986
+ #if !defined(_WIN32)
987
+ @ uid=%d(getuid()), gid=%d(getgid())<br />
988
+ #endif
989
+ @ g.zBaseURL = %h(g.zBaseURL)<br />
990
+ @ g.zHttpsURL = %h(g.zHttpsURL)<br />
991
+ @ g.zTop = %h(g.zTop)<br />
992
+ @ g.zPath = %h(g.zPath)<br />
993
+ @ g.userUid = %d(g.userUid)<br />
994
+ @ g.zLogin = %h(g.zLogin)<br />
995
+ @ g.isHuman = %d(g.isHuman)<br />
996
+ if( g.nRequest ){
997
+ @ g.nRequest = %d(g.nRequest)<br />
998
+ }
999
+ if( g.nPendingRequest>1 ){
1000
+ @ g.nPendingRequest = %d(g.nPendingRequest)<br />
1001
+ }
1002
+ @ capabilities = %s(find_capabilities(zCap))<br />
1003
+ if( zCap[0] ){
1004
+ @ anonymous-adds = %s(find_anon_capabilities(zCap))<br />
1005
+ }
1006
+ @ g.zRepositoryName = %h(g.zRepositoryName)<br />
1007
+ @ load_average() = %f(load_average())<br />
1008
+ @ cgi_csrf_safe(0) = %d(cgi_csrf_safe(0))<br />
1009
+ @ <hr />
1010
+ P("HTTP_USER_AGENT");
1011
+ cgi_print_all(showAll, 0);
1012
+ if( showAll && blob_size(&g.httpHeader)>0 ){
1013
+ @ <hr />
1014
+ @ <pre>
1015
+ @ %h(blob_str(&g.httpHeader))
1016
+ @ </pre>
1017
+ }
10211018
}
10221019
style_footer();
1020
+ if( zErr ){
1021
+ fossil_panic("webpage_error: %s", zErr);
1022
+ }
10231023
}
10241024
10251025
/*
10261026
** Generate a Not Yet Implemented error page.
10271027
*/
10281028
void webpage_not_yet_implemented(void){
10291029
webpage_error("Not yet implemented");
10301030
}
1031
+
1032
+#if INTERFACE
1033
+# define webpage_assert(T) \
1034
+ if(!(T)){webpage_error("assertion failed %s:%d: %s",__FILE__,__LINE__,#T);}
1035
+#endif
10311036
--- src/style.c
+++ src/style.c
@@ -936,11 +936,11 @@
936 ** If zFormat is an empty string, then this is the /test_env page.
937 */
938 void webpage_error(const char *zFormat, ...){
939 int i;
940 int showAll;
941 char *zErr;
942 int isAuth = 0;
943 char zCap[100];
944 static const char *const azCgiVars[] = {
945 "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE",
946 "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING",
@@ -969,16 +969,11 @@
969 va_start(ap, zFormat);
970 zErr = vmprintf(zFormat, ap);
971 va_end(ap);
972 style_header("Bad Request");
973 @ <h1>/%h(g.zPath): %h(zErr)</h1>
974 fossil_free(zErr);
975 showAll = 0;
976 if( !isAuth ){
977 style_footer();
978 return;
979 }
980 }else if( !isAuth ){
981 login_needed(0);
982 return;
983 }else{
984 style_header("Environment Test");
@@ -985,46 +980,56 @@
985 showAll = PB("showall");
986 style_submenu_checkbox("showall", "Cookies", 0, 0);
987 style_submenu_element("Stats", "%R/stat");
988 }
989
990 #if !defined(_WIN32)
991 @ uid=%d(getuid()), gid=%d(getgid())<br />
992 #endif
993 @ g.zBaseURL = %h(g.zBaseURL)<br />
994 @ g.zHttpsURL = %h(g.zHttpsURL)<br />
995 @ g.zTop = %h(g.zTop)<br />
996 @ g.zPath = %h(g.zPath)<br />
997 @ g.userUid = %d(g.userUid)<br />
998 @ g.zLogin = %h(g.zLogin)<br />
999 @ g.isHuman = %d(g.isHuman)<br />
1000 if( g.nRequest ){
1001 @ g.nRequest = %d(g.nRequest)<br />
1002 }
1003 if( g.nPendingRequest>1 ){
1004 @ g.nPendingRequest = %d(g.nPendingRequest)<br />
1005 }
1006 @ capabilities = %s(find_capabilities(zCap))<br />
1007 if( zCap[0] ){
1008 @ anonymous-adds = %s(find_anon_capabilities(zCap))<br />
1009 }
1010 @ g.zRepositoryName = %h(g.zRepositoryName)<br />
1011 @ load_average() = %f(load_average())<br />
1012 @ cgi_csrf_safe(0) = %d(cgi_csrf_safe(0))<br />
1013 @ <hr />
1014 P("HTTP_USER_AGENT");
1015 cgi_print_all(showAll, 0);
1016 if( showAll && blob_size(&g.httpHeader)>0 ){
1017 @ <hr />
1018 @ <pre>
1019 @ %h(blob_str(&g.httpHeader))
1020 @ </pre>
 
 
1021 }
1022 style_footer();
 
 
 
1023 }
1024
1025 /*
1026 ** Generate a Not Yet Implemented error page.
1027 */
1028 void webpage_not_yet_implemented(void){
1029 webpage_error("Not yet implemented");
1030 }
 
 
 
 
 
1031
--- src/style.c
+++ src/style.c
@@ -936,11 +936,11 @@
936 ** If zFormat is an empty string, then this is the /test_env page.
937 */
938 void webpage_error(const char *zFormat, ...){
939 int i;
940 int showAll;
941 char *zErr = 0;
942 int isAuth = 0;
943 char zCap[100];
944 static const char *const azCgiVars[] = {
945 "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE",
946 "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING",
@@ -969,16 +969,11 @@
969 va_start(ap, zFormat);
970 zErr = vmprintf(zFormat, ap);
971 va_end(ap);
972 style_header("Bad Request");
973 @ <h1>/%h(g.zPath): %h(zErr)</h1>
 
974 showAll = 0;
 
 
 
 
975 }else if( !isAuth ){
976 login_needed(0);
977 return;
978 }else{
979 style_header("Environment Test");
@@ -985,46 +980,56 @@
980 showAll = PB("showall");
981 style_submenu_checkbox("showall", "Cookies", 0, 0);
982 style_submenu_element("Stats", "%R/stat");
983 }
984
985 if( isAuth ){
986 #if !defined(_WIN32)
987 @ uid=%d(getuid()), gid=%d(getgid())<br />
988 #endif
989 @ g.zBaseURL = %h(g.zBaseURL)<br />
990 @ g.zHttpsURL = %h(g.zHttpsURL)<br />
991 @ g.zTop = %h(g.zTop)<br />
992 @ g.zPath = %h(g.zPath)<br />
993 @ g.userUid = %d(g.userUid)<br />
994 @ g.zLogin = %h(g.zLogin)<br />
995 @ g.isHuman = %d(g.isHuman)<br />
996 if( g.nRequest ){
997 @ g.nRequest = %d(g.nRequest)<br />
998 }
999 if( g.nPendingRequest>1 ){
1000 @ g.nPendingRequest = %d(g.nPendingRequest)<br />
1001 }
1002 @ capabilities = %s(find_capabilities(zCap))<br />
1003 if( zCap[0] ){
1004 @ anonymous-adds = %s(find_anon_capabilities(zCap))<br />
1005 }
1006 @ g.zRepositoryName = %h(g.zRepositoryName)<br />
1007 @ load_average() = %f(load_average())<br />
1008 @ cgi_csrf_safe(0) = %d(cgi_csrf_safe(0))<br />
1009 @ <hr />
1010 P("HTTP_USER_AGENT");
1011 cgi_print_all(showAll, 0);
1012 if( showAll && blob_size(&g.httpHeader)>0 ){
1013 @ <hr />
1014 @ <pre>
1015 @ %h(blob_str(&g.httpHeader))
1016 @ </pre>
1017 }
1018 }
1019 style_footer();
1020 if( zErr ){
1021 fossil_panic("webpage_error: %s", zErr);
1022 }
1023 }
1024
1025 /*
1026 ** Generate a Not Yet Implemented error page.
1027 */
1028 void webpage_not_yet_implemented(void){
1029 webpage_error("Not yet implemented");
1030 }
1031
1032 #if INTERFACE
1033 # define webpage_assert(T) \
1034 if(!(T)){webpage_error("assertion failed %s:%d: %s",__FILE__,__LINE__,#T);}
1035 #endif
1036

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button