Fossil SCM

All aspects of Wiki and Ticket moderation and attachments are working better. But there are still room for improvement before merging this enhancement sprint into trunk.

drh 2012-11-01 22:54 UTC moderation
Commit 628c402414e3d47c2f83d757d66709d22f00360e
5 files changed +224 -55 +1 -154 +47 +10 -42 +3 -39
+224 -55
--- src/attach.c
+++ src/attach.c
@@ -195,21 +195,27 @@
195195
}
196196
197197
/*
198198
** Save an attachment control artifact into the repository
199199
*/
200
-static void attach_put(Blob *pAttach, int attachRid, int needMod){
200
+static void attach_put(
201
+ Blob *pAttach, /* Text of the Attachment record */
202
+ int attachRid, /* RID for the file that is being attached */
203
+ int needMod /* True if the attachment is subject to moderation */
204
+){
201205
int rid;
202206
if( needMod ){
203207
rid = content_put_ex(pAttach, 0, 0, 0, 1);
204208
moderation_table_create();
205209
db_multi_exec(
206210
"INSERT INTO modreq(objid,attachRid) VALUES(%d,%d);",
207211
rid, attachRid
208212
);
209213
}else{
210
- content_put(pAttach);
214
+ rid = content_put(pAttach);
215
+ db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
216
+ db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
211217
}
212218
manifest_crosslink(rid, pAttach);
213219
}
214220
215221
@@ -268,11 +274,11 @@
268274
char *zDate;
269275
int rid;
270276
int i, n;
271277
int addCompress = 0;
272278
Manifest *pManifest;
273
- int isModerator;
279
+ int needModerator;
274280
275281
db_begin_transaction();
276282
blob_init(&content, aContent, szContent);
277283
pManifest = manifest_parse(&content, 0, 0);
278284
manifest_destroy(pManifest);
@@ -279,12 +285,14 @@
279285
blob_init(&content, aContent, szContent);
280286
if( pManifest ){
281287
blob_compress(&content, &content);
282288
addCompress = 1;
283289
}
284
- isModerator = (zTkt!=0 && g.perm.ModTkt) || (zPage!=0 && g.perm.ModWiki);
285
- rid = content_put_ex(&content, 0, 0, 0, !isModerator);
290
+ needModerator =
291
+ (zTkt!=0 && g.perm.ModTkt==0 && db_get_boolean("modreq-tkt",0)==1) ||
292
+ (zPage!=0 && g.perm.ModWiki==0 && db_get_boolean("modreq-wiki",0)==1);
293
+ rid = content_put_ex(&content, 0, 0, 0, needModerator);
286294
zUUID = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
287295
blob_zero(&manifest);
288296
for(i=n=0; zName[i]; i++){
289297
if( zName[i]=='/' || zName[i]=='\\' ) n = i;
290298
}
@@ -302,11 +310,11 @@
302310
zDate = date_in_standard_format("now");
303311
blob_appendf(&manifest, "D %s\n", zDate);
304312
blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody");
305313
md5sum_blob(&manifest, &cksum);
306314
blob_appendf(&manifest, "Z %b\n", &cksum);
307
- attach_put(&manifest, rid, !isModerator);
315
+ attach_put(&manifest, rid, needModerator);
308316
assert( blob_is_reset(&manifest) );
309317
db_end_transaction(0);
310318
cgi_redirect(zFrom);
311319
}
312320
style_header("Add Attachment");
@@ -327,50 +335,77 @@
327335
@ <input type="submit" name="cancel" value="Cancel" />
328336
@ </div></form>
329337
style_footer();
330338
}
331339
332
-
333
-/*
334
-** WEBPAGE: attachdelete
335
-**
336
-** tkt=TICKETUUID
337
-** page=WIKIPAGE
338
-** file=FILENAME
339
-**
340
-** "Delete" an attachment. Because objects in Fossil are immutable
341
-** the attachment isn't really deleted. Instead, we change the content
342
-** of the attachment to NULL, which the system understands as being
343
-** deleted. Historical values of the attachment are preserved.
344
-*/
345
-void attachdel_page(void){
346
- const char *zPage = P("page");
347
- const char *zTkt = P("tkt");
348
- const char *zFile = P("file");
349
- const char *zFrom = P("from");
350
- const char *zTarget;
351
-
352
- if( zPage && zTkt ) fossil_redirect_home();
353
- if( zPage==0 && zTkt==0 ) fossil_redirect_home();
354
- if( zFile==0 ) fossil_redirect_home();
340
+/*
341
+** WEBPAGE: ainfo
342
+** URL: /ainfo?name=ARTIFACTID
343
+**
344
+** Show the details of an attachment artifact.
345
+*/
346
+void ainfo_page(void){
347
+ int rid; /* RID for the control artifact */
348
+ int ridSrc; /* RID for the attached file */
349
+ char *zDate; /* Date attached */
350
+ const char *zUuid; /* UUID of the control artifact */
351
+ Manifest *pAttach; /* Parse of the control artifact */
352
+ const char *zTarget; /* Wiki or ticket attached to */
353
+ const char *zSrc; /* UUID of the attached file */
354
+ const char *zName; /* Name of the attached file */
355
+ const char *zDesc; /* Description of the attached file */
356
+ const char *zWikiName = 0; /* Wiki page name when attached to Wiki */
357
+ const char *zTktUuid = 0; /* Ticket ID when attached to a ticket */
358
+ int modPending; /* True if awaiting moderation */
359
+ const char *zModAction; /* Moderation action or NULL */
360
+ int isModerator; /* TRUE if user is the moderator */
361
+ const char *zMime; /* MIME Type */
362
+ Blob attach; /* Content of the attachment */
363
+ int wantToDelete = P("del")!=0;/* Want to delete */
364
+
355365
login_check_credentials();
356
- if( zPage ){
357
- if( g.perm.WrWiki==0 || g.perm.Attach==0 ) login_needed();
358
- zTarget = zPage;
359
- }else{
360
- if( g.perm.WrTkt==0 || g.perm.Attach==0 ) login_needed();
361
- zTarget = zTkt;
362
- }
363
- if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop);
364
- if( P("cancel") ){
365
- cgi_redirect(zFrom);
366
- }
367
- if( P("confirm") ){
366
+ if( !g.perm.Attach ){ login_needed(); return; }
367
+ rid = name_to_rid_www("name");
368
+ if( rid==0 ){ fossil_redirect_home(); }
369
+ zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
370
+#if 0
371
+ /* Shunning here needs to get both the attachment control artifact and
372
+ ** the object that is attached. */
373
+ if( g.perm.Admin ){
374
+ if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
375
+ style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
376
+ g.zTop, zUuid);
377
+ }else{
378
+ style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
379
+ g.zTop, zUuid);
380
+ }
381
+ }
382
+#endif
383
+ pAttach = manifest_get(rid, CFTYPE_ATTACHMENT);
384
+ if( pAttach==0 ) fossil_redirect_home();
385
+ zTarget = pAttach->zAttachTarget;
386
+ zSrc = pAttach->zAttachSrc;
387
+ ridSrc = db_int(0,"SELECT rid FROM blob WHERE uuid='%s'", zSrc);
388
+ zName = pAttach->zAttachName;
389
+ zDesc = pAttach->zComment;
390
+ if( validate16(zTarget, strlen(zTarget))
391
+ && db_exists("SELECT 1 FROM ticket WHERE tkt_uuid='%s'", zTarget)
392
+ ){
393
+ zTktUuid = zTarget;
394
+ }else if( db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'",zTarget) ){
395
+ zWikiName = zTarget;
396
+ }
397
+ zDate = db_text(0, "SELECT datetime(%.12f)", pAttach->rDate);
398
+
399
+ if( P("confirm")
400
+ && ((zTktUuid && g.perm.WrTkt) || (zWikiName && g.perm.WrWiki))
401
+ ){
368402
int i, n, rid;
369403
char *zDate;
370404
Blob manifest;
371405
Blob cksum;
406
+ const char *zFile = zName;
372407
373408
db_begin_transaction();
374409
blob_zero(&manifest);
375410
for(i=n=0; zFile[i]; i++){
376411
if( zFile[i]=='/' || zFile[i]=='\\' ) n = i;
@@ -384,24 +419,158 @@
384419
md5sum_blob(&manifest, &cksum);
385420
blob_appendf(&manifest, "Z %b\n", &cksum);
386421
rid = content_put(&manifest);
387422
manifest_crosslink(rid, &manifest);
388423
db_end_transaction(0);
389
- cgi_redirect(zFrom);
390
- }
391
- style_header("Delete Attachment");
392
- @ <form action="%s(g.zTop)/attachdelete" method="post"><div>
393
- @ <p>Confirm that you want to delete the attachment named
394
- @ "%h(zFile)" on %s(zTkt?"ticket":"wiki page") %h(zTarget):<br /></p>
395
- if( zTkt ){
396
- @ <input type="hidden" name="tkt" value="%h(zTkt)" />
424
+ @ <p>The attachment below has been deleted.</p>
425
+ }
426
+
427
+ if( P("del")
428
+ && ((zTktUuid && g.perm.WrTkt) || (zWikiName && g.perm.WrWiki))
429
+ ){
430
+ @ <form method="post" action="%R/ainfo/%s(zUuid)">
431
+ @ <p>Confirm you want to delete the attachment shown below.
432
+ @ <input type="submit" name="confirm" value="Confirm">
433
+ @ </form>
434
+ }
435
+
436
+ isModerator = (zTktUuid && g.perm.ModTkt) || (zWikiName && g.perm.ModWiki);
437
+ if( isModerator && (zModAction = P("modaction"))!=0 ){
438
+ if( strcmp(zModAction,"delete")==0 ){
439
+ moderation_disapprove(rid);
440
+ if( zTktUuid ){
441
+ cgi_redirectf("%R/tktview/%s", zTktUuid);
442
+ }else{
443
+ cgi_redirectf("%R/wiki?name=%t", zWikiName);
444
+ }
445
+ return;
446
+ }
447
+ if( strcmp(zModAction,"approve")==0 ){
448
+ moderation_approve(rid);
449
+ }
450
+ }
451
+ style_header("Attachment Details");
452
+ style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
453
+
454
+ @ <div class="section">Overview</div>
455
+ @ <p><table class="label-value">
456
+ @ <tr><th>Artifact&nbsp;ID:</th>
457
+ @ <td>%z(href("%R/artifact/%s",zUuid))%s(zUuid)</a>
458
+ if( g.perm.Setup ){
459
+ @ (%d(rid))
460
+ }
461
+ modPending = moderation_pending(rid);
462
+ if( modPending ){
463
+ @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
464
+ }
465
+ if( zTktUuid ){
466
+ @ <tr><th>Ticket:</th>
467
+ @ <td>%z(href("%R/tktview/%s",zTktUuid))%s(zTktUuid)</a></td></tr>
468
+ if( g.perm.WrTkt ){
469
+ style_submenu_element("Delete","Delete","%R/ainfo/%s?del", zUuid);
470
+ }
471
+ }
472
+ if( zWikiName ){
473
+ @ <tr><th>Wiki&nbsp;Page:</th>
474
+ @ <td>%z(href("%R/wiki?name=%t",zWikiName))%h(zWikiName)</a></td></tr>
475
+ if( g.perm.WrWiki ){
476
+ style_submenu_element("Delete","Delete","%R/ainfo/%s?del", zUuid);
477
+ }
478
+ }
479
+ @ <tr><th>Date:</th><td>
480
+ hyperlink_to_date(zDate, "</td></tr>");
481
+ free(zDate);
482
+ @ <tr><th>User:</th><td>
483
+ hyperlink_to_user(pAttach->zUser, zDate, "</td></tr>");
484
+ @ <tr><th>Artifact&nbsp;Attached:</th>
485
+ @ <td>%z(href("%R/artifact/%s",zSrc))%s(zSrc)</a>
486
+ if( g.perm.Setup ){
487
+ @ (%d(ridSrc))
488
+ }
489
+ @ <tr><th>Filename:</th><td>%h(zName)</td></tr>
490
+ zMime = mimetype_from_name(zName);
491
+ if( g.perm.Setup ){
492
+ @ <tr><th>MIME-Type:</th><td>%h(zMime)</td></tr>
493
+ }
494
+ @ <tr><th valign="top">Description:</th><td valign="top">%h(zDesc)</td></tr>
495
+ @ </table>
496
+
497
+ if( isModerator && modPending ){
498
+ @ <div class="section">Moderation</div>
499
+ @ <blockquote>
500
+ @ <form method="POST" action="%R/ainfo/%s(zUuid)">
501
+ @ <label><input type="radio" name="modaction" value="delete">
502
+ @ Delete this change</label><br />
503
+ @ <label><input type="radio" name="modaction" value="approve">
504
+ @ Approve this change</label><br />
505
+ @ <input type="submit" value="Submit">
506
+ @ </form>
507
+ @ </blockquote>
508
+ }
509
+
510
+ @ <div class="section">Content Appended</div>
511
+ @ <blockquote>
512
+ blob_zero(&attach);
513
+ if( zMime==0 || strncmp(zMime,"text/", 5)==0 ){
514
+ const char *z;
515
+ const char *zLn = P("ln");
516
+ content_get(ridSrc, &attach);
517
+ blob_strip_bom(&attach, 0);
518
+ z = blob_str(&attach);
519
+ if( zLn ){
520
+ output_text_with_line_numbers(z, zLn);
521
+ }else{
522
+ @ <pre>
523
+ @ %h(z)
524
+ @ </pre>
525
+ }
526
+ }else if( strncmp(zMime, "image/", 6)==0 ){
527
+ @ <img src="%R/raw?name=%s(zSrc)&m=%s(zMime)"></img>
397528
}else{
398
- @ <input type="hidden" name="page" value="%h(zPage)" />
529
+ int sz = db_int(0, "SELECT sz FROM blob WHERE rid=%d", ridSrc);
530
+ @ <i>(file is %d(sz) bytes of binary data)</i>
399531
}
400
- @ <input type="hidden" name="file" value="%h(zFile)" />
401
- @ <input type="hidden" name="from" value="%h(zFrom)" />
402
- @ <input type="submit" name="confirm" value="Delete" />
403
- @ <input type="submit" name="cancel" value="Cancel" />
404
- @ </div></form>
532
+ @ </blockquote>
533
+ manifest_destroy(pAttach);
534
+ blob_reset(&attach);
405535
style_footer();
536
+}
406537
538
+/*
539
+** Output HTML to show a list of attachments.
540
+*/
541
+void attachment_list(
542
+ const char *zTarget, /* Object that things are attached to */
543
+ const char *zHeader /* Header to display with attachments */
544
+){
545
+ int cnt = 0;
546
+ Stmt q;
547
+ db_prepare(&q,
548
+ "SELECT datetime(mtime,'localtime'), filename, user,"
549
+ " (SELECT uuid FROM blob WHERE rid=attachid)"
550
+ " FROM attachment"
551
+ " WHERE isLatest AND src!='' AND target=%Q"
552
+ " ORDER BY mtime DESC",
553
+ zTarget
554
+ );
555
+ while( db_step(&q)==SQLITE_ROW ){
556
+ const char *zDate = db_column_text(&q, 0);
557
+ const char *zFile = db_column_text(&q, 1);
558
+ const char *zUser = db_column_text(&q, 2);
559
+ const char *zUuid = db_column_text(&q, 3);
560
+ if( cnt==0 ){
561
+ @ %s(zHeader)
562
+ }
563
+ cnt++;
564
+ @ <li>
565
+ @ %z(href("%R/artifact/%s",zUuid))%h(zFile)</a>
566
+ @ added by %h(zUser) on
567
+ hyperlink_to_date(zDate, ".");
568
+ @ [%z(href("%R/ainfo/%s",zUuid))details</a>]
569
+ @ </li>
570
+ }
571
+ if( cnt ){
572
+ @ </ul>
573
+ }
574
+ db_finalize(&q);
575
+
407576
}
408577
--- src/attach.c
+++ src/attach.c
@@ -195,21 +195,27 @@
195 }
196
197 /*
198 ** Save an attachment control artifact into the repository
199 */
200 static void attach_put(Blob *pAttach, int attachRid, int needMod){
 
 
 
 
201 int rid;
202 if( needMod ){
203 rid = content_put_ex(pAttach, 0, 0, 0, 1);
204 moderation_table_create();
205 db_multi_exec(
206 "INSERT INTO modreq(objid,attachRid) VALUES(%d,%d);",
207 rid, attachRid
208 );
209 }else{
210 content_put(pAttach);
 
 
211 }
212 manifest_crosslink(rid, pAttach);
213 }
214
215
@@ -268,11 +274,11 @@
268 char *zDate;
269 int rid;
270 int i, n;
271 int addCompress = 0;
272 Manifest *pManifest;
273 int isModerator;
274
275 db_begin_transaction();
276 blob_init(&content, aContent, szContent);
277 pManifest = manifest_parse(&content, 0, 0);
278 manifest_destroy(pManifest);
@@ -279,12 +285,14 @@
279 blob_init(&content, aContent, szContent);
280 if( pManifest ){
281 blob_compress(&content, &content);
282 addCompress = 1;
283 }
284 isModerator = (zTkt!=0 && g.perm.ModTkt) || (zPage!=0 && g.perm.ModWiki);
285 rid = content_put_ex(&content, 0, 0, 0, !isModerator);
 
 
286 zUUID = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
287 blob_zero(&manifest);
288 for(i=n=0; zName[i]; i++){
289 if( zName[i]=='/' || zName[i]=='\\' ) n = i;
290 }
@@ -302,11 +310,11 @@
302 zDate = date_in_standard_format("now");
303 blob_appendf(&manifest, "D %s\n", zDate);
304 blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody");
305 md5sum_blob(&manifest, &cksum);
306 blob_appendf(&manifest, "Z %b\n", &cksum);
307 attach_put(&manifest, rid, !isModerator);
308 assert( blob_is_reset(&manifest) );
309 db_end_transaction(0);
310 cgi_redirect(zFrom);
311 }
312 style_header("Add Attachment");
@@ -327,50 +335,77 @@
327 @ <input type="submit" name="cancel" value="Cancel" />
328 @ </div></form>
329 style_footer();
330 }
331
332
333 /*
334 ** WEBPAGE: attachdelete
335 **
336 ** tkt=TICKETUUID
337 ** page=WIKIPAGE
338 ** file=FILENAME
339 **
340 ** "Delete" an attachment. Because objects in Fossil are immutable
341 ** the attachment isn't really deleted. Instead, we change the content
342 ** of the attachment to NULL, which the system understands as being
343 ** deleted. Historical values of the attachment are preserved.
344 */
345 void attachdel_page(void){
346 const char *zPage = P("page");
347 const char *zTkt = P("tkt");
348 const char *zFile = P("file");
349 const char *zFrom = P("from");
350 const char *zTarget;
351
352 if( zPage && zTkt ) fossil_redirect_home();
353 if( zPage==0 && zTkt==0 ) fossil_redirect_home();
354 if( zFile==0 ) fossil_redirect_home();
 
 
355 login_check_credentials();
356 if( zPage ){
357 if( g.perm.WrWiki==0 || g.perm.Attach==0 ) login_needed();
358 zTarget = zPage;
359 }else{
360 if( g.perm.WrTkt==0 || g.perm.Attach==0 ) login_needed();
361 zTarget = zTkt;
362 }
363 if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop);
364 if( P("cancel") ){
365 cgi_redirect(zFrom);
366 }
367 if( P("confirm") ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368 int i, n, rid;
369 char *zDate;
370 Blob manifest;
371 Blob cksum;
 
372
373 db_begin_transaction();
374 blob_zero(&manifest);
375 for(i=n=0; zFile[i]; i++){
376 if( zFile[i]=='/' || zFile[i]=='\\' ) n = i;
@@ -384,24 +419,158 @@
384 md5sum_blob(&manifest, &cksum);
385 blob_appendf(&manifest, "Z %b\n", &cksum);
386 rid = content_put(&manifest);
387 manifest_crosslink(rid, &manifest);
388 db_end_transaction(0);
389 cgi_redirect(zFrom);
390 }
391 style_header("Delete Attachment");
392 @ <form action="%s(g.zTop)/attachdelete" method="post"><div>
393 @ <p>Confirm that you want to delete the attachment named
394 @ "%h(zFile)" on %s(zTkt?"ticket":"wiki page") %h(zTarget):<br /></p>
395 if( zTkt ){
396 @ <input type="hidden" name="tkt" value="%h(zTkt)" />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397 }else{
398 @ <input type="hidden" name="page" value="%h(zPage)" />
 
399 }
400 @ <input type="hidden" name="file" value="%h(zFile)" />
401 @ <input type="hidden" name="from" value="%h(zFrom)" />
402 @ <input type="submit" name="confirm" value="Delete" />
403 @ <input type="submit" name="cancel" value="Cancel" />
404 @ </div></form>
405 style_footer();
 
406
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
407 }
408
--- src/attach.c
+++ src/attach.c
@@ -195,21 +195,27 @@
195 }
196
197 /*
198 ** Save an attachment control artifact into the repository
199 */
200 static void attach_put(
201 Blob *pAttach, /* Text of the Attachment record */
202 int attachRid, /* RID for the file that is being attached */
203 int needMod /* True if the attachment is subject to moderation */
204 ){
205 int rid;
206 if( needMod ){
207 rid = content_put_ex(pAttach, 0, 0, 0, 1);
208 moderation_table_create();
209 db_multi_exec(
210 "INSERT INTO modreq(objid,attachRid) VALUES(%d,%d);",
211 rid, attachRid
212 );
213 }else{
214 rid = content_put(pAttach);
215 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
216 db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
217 }
218 manifest_crosslink(rid, pAttach);
219 }
220
221
@@ -268,11 +274,11 @@
274 char *zDate;
275 int rid;
276 int i, n;
277 int addCompress = 0;
278 Manifest *pManifest;
279 int needModerator;
280
281 db_begin_transaction();
282 blob_init(&content, aContent, szContent);
283 pManifest = manifest_parse(&content, 0, 0);
284 manifest_destroy(pManifest);
@@ -279,12 +285,14 @@
285 blob_init(&content, aContent, szContent);
286 if( pManifest ){
287 blob_compress(&content, &content);
288 addCompress = 1;
289 }
290 needModerator =
291 (zTkt!=0 && g.perm.ModTkt==0 && db_get_boolean("modreq-tkt",0)==1) ||
292 (zPage!=0 && g.perm.ModWiki==0 && db_get_boolean("modreq-wiki",0)==1);
293 rid = content_put_ex(&content, 0, 0, 0, needModerator);
294 zUUID = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
295 blob_zero(&manifest);
296 for(i=n=0; zName[i]; i++){
297 if( zName[i]=='/' || zName[i]=='\\' ) n = i;
298 }
@@ -302,11 +310,11 @@
310 zDate = date_in_standard_format("now");
311 blob_appendf(&manifest, "D %s\n", zDate);
312 blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody");
313 md5sum_blob(&manifest, &cksum);
314 blob_appendf(&manifest, "Z %b\n", &cksum);
315 attach_put(&manifest, rid, needModerator);
316 assert( blob_is_reset(&manifest) );
317 db_end_transaction(0);
318 cgi_redirect(zFrom);
319 }
320 style_header("Add Attachment");
@@ -327,50 +335,77 @@
335 @ <input type="submit" name="cancel" value="Cancel" />
336 @ </div></form>
337 style_footer();
338 }
339
340 /*
341 ** WEBPAGE: ainfo
342 ** URL: /ainfo?name=ARTIFACTID
343 **
344 ** Show the details of an attachment artifact.
345 */
346 void ainfo_page(void){
347 int rid; /* RID for the control artifact */
348 int ridSrc; /* RID for the attached file */
349 char *zDate; /* Date attached */
350 const char *zUuid; /* UUID of the control artifact */
351 Manifest *pAttach; /* Parse of the control artifact */
352 const char *zTarget; /* Wiki or ticket attached to */
353 const char *zSrc; /* UUID of the attached file */
354 const char *zName; /* Name of the attached file */
355 const char *zDesc; /* Description of the attached file */
356 const char *zWikiName = 0; /* Wiki page name when attached to Wiki */
357 const char *zTktUuid = 0; /* Ticket ID when attached to a ticket */
358 int modPending; /* True if awaiting moderation */
359 const char *zModAction; /* Moderation action or NULL */
360 int isModerator; /* TRUE if user is the moderator */
361 const char *zMime; /* MIME Type */
362 Blob attach; /* Content of the attachment */
363 int wantToDelete = P("del")!=0;/* Want to delete */
364
365 login_check_credentials();
366 if( !g.perm.Attach ){ login_needed(); return; }
367 rid = name_to_rid_www("name");
368 if( rid==0 ){ fossil_redirect_home(); }
369 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
370 #if 0
371 /* Shunning here needs to get both the attachment control artifact and
372 ** the object that is attached. */
373 if( g.perm.Admin ){
374 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
375 style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
376 g.zTop, zUuid);
377 }else{
378 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
379 g.zTop, zUuid);
380 }
381 }
382 #endif
383 pAttach = manifest_get(rid, CFTYPE_ATTACHMENT);
384 if( pAttach==0 ) fossil_redirect_home();
385 zTarget = pAttach->zAttachTarget;
386 zSrc = pAttach->zAttachSrc;
387 ridSrc = db_int(0,"SELECT rid FROM blob WHERE uuid='%s'", zSrc);
388 zName = pAttach->zAttachName;
389 zDesc = pAttach->zComment;
390 if( validate16(zTarget, strlen(zTarget))
391 && db_exists("SELECT 1 FROM ticket WHERE tkt_uuid='%s'", zTarget)
392 ){
393 zTktUuid = zTarget;
394 }else if( db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'",zTarget) ){
395 zWikiName = zTarget;
396 }
397 zDate = db_text(0, "SELECT datetime(%.12f)", pAttach->rDate);
398
399 if( P("confirm")
400 && ((zTktUuid && g.perm.WrTkt) || (zWikiName && g.perm.WrWiki))
401 ){
402 int i, n, rid;
403 char *zDate;
404 Blob manifest;
405 Blob cksum;
406 const char *zFile = zName;
407
408 db_begin_transaction();
409 blob_zero(&manifest);
410 for(i=n=0; zFile[i]; i++){
411 if( zFile[i]=='/' || zFile[i]=='\\' ) n = i;
@@ -384,24 +419,158 @@
419 md5sum_blob(&manifest, &cksum);
420 blob_appendf(&manifest, "Z %b\n", &cksum);
421 rid = content_put(&manifest);
422 manifest_crosslink(rid, &manifest);
423 db_end_transaction(0);
424 @ <p>The attachment below has been deleted.</p>
425 }
426
427 if( P("del")
428 && ((zTktUuid && g.perm.WrTkt) || (zWikiName && g.perm.WrWiki))
429 ){
430 @ <form method="post" action="%R/ainfo/%s(zUuid)">
431 @ <p>Confirm you want to delete the attachment shown below.
432 @ <input type="submit" name="confirm" value="Confirm">
433 @ </form>
434 }
435
436 isModerator = (zTktUuid && g.perm.ModTkt) || (zWikiName && g.perm.ModWiki);
437 if( isModerator && (zModAction = P("modaction"))!=0 ){
438 if( strcmp(zModAction,"delete")==0 ){
439 moderation_disapprove(rid);
440 if( zTktUuid ){
441 cgi_redirectf("%R/tktview/%s", zTktUuid);
442 }else{
443 cgi_redirectf("%R/wiki?name=%t", zWikiName);
444 }
445 return;
446 }
447 if( strcmp(zModAction,"approve")==0 ){
448 moderation_approve(rid);
449 }
450 }
451 style_header("Attachment Details");
452 style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
453
454 @ <div class="section">Overview</div>
455 @ <p><table class="label-value">
456 @ <tr><th>Artifact&nbsp;ID:</th>
457 @ <td>%z(href("%R/artifact/%s",zUuid))%s(zUuid)</a>
458 if( g.perm.Setup ){
459 @ (%d(rid))
460 }
461 modPending = moderation_pending(rid);
462 if( modPending ){
463 @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
464 }
465 if( zTktUuid ){
466 @ <tr><th>Ticket:</th>
467 @ <td>%z(href("%R/tktview/%s",zTktUuid))%s(zTktUuid)</a></td></tr>
468 if( g.perm.WrTkt ){
469 style_submenu_element("Delete","Delete","%R/ainfo/%s?del", zUuid);
470 }
471 }
472 if( zWikiName ){
473 @ <tr><th>Wiki&nbsp;Page:</th>
474 @ <td>%z(href("%R/wiki?name=%t",zWikiName))%h(zWikiName)</a></td></tr>
475 if( g.perm.WrWiki ){
476 style_submenu_element("Delete","Delete","%R/ainfo/%s?del", zUuid);
477 }
478 }
479 @ <tr><th>Date:</th><td>
480 hyperlink_to_date(zDate, "</td></tr>");
481 free(zDate);
482 @ <tr><th>User:</th><td>
483 hyperlink_to_user(pAttach->zUser, zDate, "</td></tr>");
484 @ <tr><th>Artifact&nbsp;Attached:</th>
485 @ <td>%z(href("%R/artifact/%s",zSrc))%s(zSrc)</a>
486 if( g.perm.Setup ){
487 @ (%d(ridSrc))
488 }
489 @ <tr><th>Filename:</th><td>%h(zName)</td></tr>
490 zMime = mimetype_from_name(zName);
491 if( g.perm.Setup ){
492 @ <tr><th>MIME-Type:</th><td>%h(zMime)</td></tr>
493 }
494 @ <tr><th valign="top">Description:</th><td valign="top">%h(zDesc)</td></tr>
495 @ </table>
496
497 if( isModerator && modPending ){
498 @ <div class="section">Moderation</div>
499 @ <blockquote>
500 @ <form method="POST" action="%R/ainfo/%s(zUuid)">
501 @ <label><input type="radio" name="modaction" value="delete">
502 @ Delete this change</label><br />
503 @ <label><input type="radio" name="modaction" value="approve">
504 @ Approve this change</label><br />
505 @ <input type="submit" value="Submit">
506 @ </form>
507 @ </blockquote>
508 }
509
510 @ <div class="section">Content Appended</div>
511 @ <blockquote>
512 blob_zero(&attach);
513 if( zMime==0 || strncmp(zMime,"text/", 5)==0 ){
514 const char *z;
515 const char *zLn = P("ln");
516 content_get(ridSrc, &attach);
517 blob_strip_bom(&attach, 0);
518 z = blob_str(&attach);
519 if( zLn ){
520 output_text_with_line_numbers(z, zLn);
521 }else{
522 @ <pre>
523 @ %h(z)
524 @ </pre>
525 }
526 }else if( strncmp(zMime, "image/", 6)==0 ){
527 @ <img src="%R/raw?name=%s(zSrc)&m=%s(zMime)"></img>
528 }else{
529 int sz = db_int(0, "SELECT sz FROM blob WHERE rid=%d", ridSrc);
530 @ <i>(file is %d(sz) bytes of binary data)</i>
531 }
532 @ </blockquote>
533 manifest_destroy(pAttach);
534 blob_reset(&attach);
 
 
535 style_footer();
536 }
537
538 /*
539 ** Output HTML to show a list of attachments.
540 */
541 void attachment_list(
542 const char *zTarget, /* Object that things are attached to */
543 const char *zHeader /* Header to display with attachments */
544 ){
545 int cnt = 0;
546 Stmt q;
547 db_prepare(&q,
548 "SELECT datetime(mtime,'localtime'), filename, user,"
549 " (SELECT uuid FROM blob WHERE rid=attachid)"
550 " FROM attachment"
551 " WHERE isLatest AND src!='' AND target=%Q"
552 " ORDER BY mtime DESC",
553 zTarget
554 );
555 while( db_step(&q)==SQLITE_ROW ){
556 const char *zDate = db_column_text(&q, 0);
557 const char *zFile = db_column_text(&q, 1);
558 const char *zUser = db_column_text(&q, 2);
559 const char *zUuid = db_column_text(&q, 3);
560 if( cnt==0 ){
561 @ %s(zHeader)
562 }
563 cnt++;
564 @ <li>
565 @ %z(href("%R/artifact/%s",zUuid))%h(zFile)</a>
566 @ added by %h(zUser) on
567 hyperlink_to_date(zDate, ".");
568 @ [%z(href("%R/ainfo/%s",zUuid))details</a>]
569 @ </li>
570 }
571 if( cnt ){
572 @ </ul>
573 }
574 db_finalize(&q);
575
576 }
577
+1 -154
--- src/info.c
+++ src/info.c
@@ -1493,11 +1493,11 @@
14931493
**
14941494
** zLn is the ?ln= parameter for the HTTP query. If there is an argument,
14951495
** then highlight that line number and scroll to it once the page loads.
14961496
** If there are two line numbers, highlight the range of lines.
14971497
*/
1498
-static void output_text_with_line_numbers(
1498
+void output_text_with_line_numbers(
14991499
const char *z,
15001500
const char *zLn
15011501
){
15021502
int iStart, iEnd; /* Start and end of region to highlight */
15031503
int n = 0; /* Current line number */
@@ -1749,163 +1749,10 @@
17491749
ticket_output_change_artifact(pTktChng);
17501750
manifest_destroy(pTktChng);
17511751
style_footer();
17521752
}
17531753
1754
-/*
1755
-** WEBPAGE: ainfo
1756
-** URL: /ainfo?name=ARTIFACTID
1757
-**
1758
-** Show the details of an attachment artifact.
1759
-*/
1760
-void ainfo_page(void){
1761
- int rid; /* RID for the control artifact */
1762
- int ridSrc; /* RID for the attached file */
1763
- char *zDate; /* Date attached */
1764
- const char *zUuid; /* UUID of the control artifact */
1765
- Manifest *pAttach; /* Parse of the control artifact */
1766
- const char *zTarget; /* Wiki or ticket attached to */
1767
- const char *zSrc; /* UUID of the attached file */
1768
- const char *zName; /* Name of the attached file */
1769
- const char *zDesc; /* Description of the attached file */
1770
- const char *zWikiName = 0; /* Wiki page name when attached to Wiki */
1771
- const char *zTktUuid = 0; /* Ticket ID when attached to a ticket */
1772
- int modPending; /* True if awaiting moderation */
1773
- const char *zModAction; /* Moderation action or NULL */
1774
- int isModerator; /* TRUE if user is the moderator */
1775
- const char *zMime; /* MIME Type */
1776
- Blob attach; /* Content of the attachment */
1777
-
1778
- login_check_credentials();
1779
- if( !g.perm.Attach ){ login_needed(); return; }
1780
- rid = name_to_rid_www("name");
1781
- if( rid==0 ){ fossil_redirect_home(); }
1782
- zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
1783
-#if 0
1784
- /* Shunning here needs to get both the attachment control artifact and
1785
- ** the object that is attached. */
1786
- if( g.perm.Admin ){
1787
- if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
1788
- style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
1789
- g.zTop, zUuid);
1790
- }else{
1791
- style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
1792
- g.zTop, zUuid);
1793
- }
1794
- }
1795
-#endif
1796
- pAttach = manifest_get(rid, CFTYPE_ATTACHMENT);
1797
- if( pAttach==0 ) fossil_redirect_home();
1798
- zTarget = pAttach->zAttachTarget;
1799
- zSrc = pAttach->zAttachSrc;
1800
- ridSrc = db_int(0,"SELECT rid FROM blob WHERE uuid='%s'", zSrc);
1801
- zName = pAttach->zAttachName;
1802
- zDesc = pAttach->zComment;
1803
- if( validate16(zTarget, strlen(zTarget))
1804
- && db_exists("SELECT 1 FROM ticket WHERE tkt_uuid='%s'", zTarget)
1805
- ){
1806
- zTktUuid = zTarget;
1807
- }else if( db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'",zTarget) ){
1808
- zWikiName = zTarget;
1809
- }
1810
- zDate = db_text(0, "SELECT datetime(%.12f)", pAttach->rDate);
1811
- isModerator = (zTktUuid && g.perm.ModTkt) || (zWikiName && g.perm.ModWiki);
1812
- if( isModerator && (zModAction = P("modaction"))!=0 ){
1813
- if( strcmp(zModAction,"delete")==0 ){
1814
- moderation_disapprove(rid);
1815
- if( zTktUuid ){
1816
- cgi_redirectf("%R/tktview/%s", zTktUuid);
1817
- }else{
1818
- cgi_redirectf("%R/wiki?name=%t", zWikiName);
1819
- }
1820
- return;
1821
- }
1822
- if( strcmp(zModAction,"approve")==0 ){
1823
- moderation_approve(rid);
1824
- }
1825
- }
1826
- style_header("Attachment Details");
1827
- style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
1828
-
1829
- @ <div class="section">Overview</div>
1830
- @ <p><table class="label-value">
1831
- @ <tr><th>Artifact&nbsp;ID:</th>
1832
- @ <td>%z(href("%R/artifact/%s",zUuid))%s(zUuid)</a>
1833
- if( g.perm.Setup ){
1834
- @ (%d(rid))
1835
- }
1836
- modPending = moderation_pending(rid);
1837
- if( modPending ){
1838
- @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
1839
- }
1840
- if( zTktUuid ){
1841
- @ <tr><th>Ticket:</th>
1842
- @ <td>%z(href("%R/tktview/%s",zTktUuid))%s(zTktUuid)</a></td></tr>
1843
- }
1844
- if( zWikiName ){
1845
- @ <tr><th>Wiki&nbsp;Page:</th>
1846
- @ <td>%z(href("%R/wiki?name=%t",zWikiName))%h(zWikiName)</a></td></tr>
1847
- }
1848
- @ <tr><th>Date:</th><td>
1849
- hyperlink_to_date(zDate, "</td></tr>");
1850
- free(zDate);
1851
- @ <tr><th>User:</th><td>
1852
- hyperlink_to_user(pAttach->zUser, zDate, "</td></tr>");
1853
- @ <tr><th>Artifact&nbsp;Attached:</th>
1854
- @ <td>%z(href("%R/artifact/%s",zSrc))%s(zSrc)</a>
1855
- if( g.perm.Setup ){
1856
- @ (%d(ridSrc))
1857
- }
1858
- @ <tr><th>Filename:</th><td>%h(zName)</td></tr>
1859
- zMime = mimetype_from_name(zName);
1860
- if( g.perm.Setup ){
1861
- @ <tr><th>MIME-Type:</th><td>%h(zMime)</td></tr>
1862
- }
1863
- @ <tr><th valign="top">Description:</th><td valign="top">%h(zDesc)</td></tr>
1864
- @ </table>
1865
-
1866
- if( isModerator && modPending ){
1867
- @ <div class="section">Moderation</div>
1868
- @ <blockquote>
1869
- @ <form method="POST" action="%R/ainfo/%s(zUuid)">
1870
- @ <label><input type="radio" name="modaction" value="delete">
1871
- @ Delete this change</label><br />
1872
- @ <label><input type="radio" name="modaction" value="approve">
1873
- @ Approve this change</label><br />
1874
- @ <input type="submit" value="Submit">
1875
- @ </form>
1876
- @ </blockquote>
1877
- }
1878
-
1879
- @ <div class="section">Content Appended</div>
1880
- @ <blockquote>
1881
- blob_zero(&attach);
1882
- if( zMime==0 || strncmp(zMime,"text/", 5)==0 ){
1883
- const char *z;
1884
- const char *zLn = P("ln");
1885
- content_get(ridSrc, &attach);
1886
- blob_strip_bom(&attach, 0);
1887
- z = blob_str(&attach);
1888
- if( zLn ){
1889
- output_text_with_line_numbers(z, zLn);
1890
- }else{
1891
- @ <pre>
1892
- @ %h(z)
1893
- @ </pre>
1894
- }
1895
- }else if( strncmp(zMime, "image/", 6)==0 ){
1896
- @ <img src="%R/raw?name=%s(zSrc)&m=%s(zMime)"></img>
1897
- }else{
1898
- int sz = db_int(0, "SELECT sz FROM blob WHERE rid=%d", ridSrc);
1899
- @ <i>(file is %d(sz) bytes of binary data)</i>
1900
- }
1901
- @ </blockquote>
1902
- manifest_destroy(pAttach);
1903
- blob_reset(&attach);
1904
- style_footer();
1905
-}
1906
-
19071754
19081755
/*
19091756
** WEBPAGE: info
19101757
** URL: info/ARTIFACTID
19111758
**
19121759
--- src/info.c
+++ src/info.c
@@ -1493,11 +1493,11 @@
1493 **
1494 ** zLn is the ?ln= parameter for the HTTP query. If there is an argument,
1495 ** then highlight that line number and scroll to it once the page loads.
1496 ** If there are two line numbers, highlight the range of lines.
1497 */
1498 static void output_text_with_line_numbers(
1499 const char *z,
1500 const char *zLn
1501 ){
1502 int iStart, iEnd; /* Start and end of region to highlight */
1503 int n = 0; /* Current line number */
@@ -1749,163 +1749,10 @@
1749 ticket_output_change_artifact(pTktChng);
1750 manifest_destroy(pTktChng);
1751 style_footer();
1752 }
1753
1754 /*
1755 ** WEBPAGE: ainfo
1756 ** URL: /ainfo?name=ARTIFACTID
1757 **
1758 ** Show the details of an attachment artifact.
1759 */
1760 void ainfo_page(void){
1761 int rid; /* RID for the control artifact */
1762 int ridSrc; /* RID for the attached file */
1763 char *zDate; /* Date attached */
1764 const char *zUuid; /* UUID of the control artifact */
1765 Manifest *pAttach; /* Parse of the control artifact */
1766 const char *zTarget; /* Wiki or ticket attached to */
1767 const char *zSrc; /* UUID of the attached file */
1768 const char *zName; /* Name of the attached file */
1769 const char *zDesc; /* Description of the attached file */
1770 const char *zWikiName = 0; /* Wiki page name when attached to Wiki */
1771 const char *zTktUuid = 0; /* Ticket ID when attached to a ticket */
1772 int modPending; /* True if awaiting moderation */
1773 const char *zModAction; /* Moderation action or NULL */
1774 int isModerator; /* TRUE if user is the moderator */
1775 const char *zMime; /* MIME Type */
1776 Blob attach; /* Content of the attachment */
1777
1778 login_check_credentials();
1779 if( !g.perm.Attach ){ login_needed(); return; }
1780 rid = name_to_rid_www("name");
1781 if( rid==0 ){ fossil_redirect_home(); }
1782 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
1783 #if 0
1784 /* Shunning here needs to get both the attachment control artifact and
1785 ** the object that is attached. */
1786 if( g.perm.Admin ){
1787 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
1788 style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
1789 g.zTop, zUuid);
1790 }else{
1791 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
1792 g.zTop, zUuid);
1793 }
1794 }
1795 #endif
1796 pAttach = manifest_get(rid, CFTYPE_ATTACHMENT);
1797 if( pAttach==0 ) fossil_redirect_home();
1798 zTarget = pAttach->zAttachTarget;
1799 zSrc = pAttach->zAttachSrc;
1800 ridSrc = db_int(0,"SELECT rid FROM blob WHERE uuid='%s'", zSrc);
1801 zName = pAttach->zAttachName;
1802 zDesc = pAttach->zComment;
1803 if( validate16(zTarget, strlen(zTarget))
1804 && db_exists("SELECT 1 FROM ticket WHERE tkt_uuid='%s'", zTarget)
1805 ){
1806 zTktUuid = zTarget;
1807 }else if( db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'",zTarget) ){
1808 zWikiName = zTarget;
1809 }
1810 zDate = db_text(0, "SELECT datetime(%.12f)", pAttach->rDate);
1811 isModerator = (zTktUuid && g.perm.ModTkt) || (zWikiName && g.perm.ModWiki);
1812 if( isModerator && (zModAction = P("modaction"))!=0 ){
1813 if( strcmp(zModAction,"delete")==0 ){
1814 moderation_disapprove(rid);
1815 if( zTktUuid ){
1816 cgi_redirectf("%R/tktview/%s", zTktUuid);
1817 }else{
1818 cgi_redirectf("%R/wiki?name=%t", zWikiName);
1819 }
1820 return;
1821 }
1822 if( strcmp(zModAction,"approve")==0 ){
1823 moderation_approve(rid);
1824 }
1825 }
1826 style_header("Attachment Details");
1827 style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
1828
1829 @ <div class="section">Overview</div>
1830 @ <p><table class="label-value">
1831 @ <tr><th>Artifact&nbsp;ID:</th>
1832 @ <td>%z(href("%R/artifact/%s",zUuid))%s(zUuid)</a>
1833 if( g.perm.Setup ){
1834 @ (%d(rid))
1835 }
1836 modPending = moderation_pending(rid);
1837 if( modPending ){
1838 @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
1839 }
1840 if( zTktUuid ){
1841 @ <tr><th>Ticket:</th>
1842 @ <td>%z(href("%R/tktview/%s",zTktUuid))%s(zTktUuid)</a></td></tr>
1843 }
1844 if( zWikiName ){
1845 @ <tr><th>Wiki&nbsp;Page:</th>
1846 @ <td>%z(href("%R/wiki?name=%t",zWikiName))%h(zWikiName)</a></td></tr>
1847 }
1848 @ <tr><th>Date:</th><td>
1849 hyperlink_to_date(zDate, "</td></tr>");
1850 free(zDate);
1851 @ <tr><th>User:</th><td>
1852 hyperlink_to_user(pAttach->zUser, zDate, "</td></tr>");
1853 @ <tr><th>Artifact&nbsp;Attached:</th>
1854 @ <td>%z(href("%R/artifact/%s",zSrc))%s(zSrc)</a>
1855 if( g.perm.Setup ){
1856 @ (%d(ridSrc))
1857 }
1858 @ <tr><th>Filename:</th><td>%h(zName)</td></tr>
1859 zMime = mimetype_from_name(zName);
1860 if( g.perm.Setup ){
1861 @ <tr><th>MIME-Type:</th><td>%h(zMime)</td></tr>
1862 }
1863 @ <tr><th valign="top">Description:</th><td valign="top">%h(zDesc)</td></tr>
1864 @ </table>
1865
1866 if( isModerator && modPending ){
1867 @ <div class="section">Moderation</div>
1868 @ <blockquote>
1869 @ <form method="POST" action="%R/ainfo/%s(zUuid)">
1870 @ <label><input type="radio" name="modaction" value="delete">
1871 @ Delete this change</label><br />
1872 @ <label><input type="radio" name="modaction" value="approve">
1873 @ Approve this change</label><br />
1874 @ <input type="submit" value="Submit">
1875 @ </form>
1876 @ </blockquote>
1877 }
1878
1879 @ <div class="section">Content Appended</div>
1880 @ <blockquote>
1881 blob_zero(&attach);
1882 if( zMime==0 || strncmp(zMime,"text/", 5)==0 ){
1883 const char *z;
1884 const char *zLn = P("ln");
1885 content_get(ridSrc, &attach);
1886 blob_strip_bom(&attach, 0);
1887 z = blob_str(&attach);
1888 if( zLn ){
1889 output_text_with_line_numbers(z, zLn);
1890 }else{
1891 @ <pre>
1892 @ %h(z)
1893 @ </pre>
1894 }
1895 }else if( strncmp(zMime, "image/", 6)==0 ){
1896 @ <img src="%R/raw?name=%s(zSrc)&m=%s(zMime)"></img>
1897 }else{
1898 int sz = db_int(0, "SELECT sz FROM blob WHERE rid=%d", ridSrc);
1899 @ <i>(file is %d(sz) bytes of binary data)</i>
1900 }
1901 @ </blockquote>
1902 manifest_destroy(pAttach);
1903 blob_reset(&attach);
1904 style_footer();
1905 }
1906
1907
1908 /*
1909 ** WEBPAGE: info
1910 ** URL: info/ARTIFACTID
1911 **
1912
--- src/info.c
+++ src/info.c
@@ -1493,11 +1493,11 @@
1493 **
1494 ** zLn is the ?ln= parameter for the HTTP query. If there is an argument,
1495 ** then highlight that line number and scroll to it once the page loads.
1496 ** If there are two line numbers, highlight the range of lines.
1497 */
1498 void output_text_with_line_numbers(
1499 const char *z,
1500 const char *zLn
1501 ){
1502 int iStart, iEnd; /* Start and end of region to highlight */
1503 int n = 0; /* Current line number */
@@ -1749,163 +1749,10 @@
1749 ticket_output_change_artifact(pTktChng);
1750 manifest_destroy(pTktChng);
1751 style_footer();
1752 }
1753
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1754
1755 /*
1756 ** WEBPAGE: info
1757 ** URL: info/ARTIFACTID
1758 **
1759
+47
--- src/setup.c
+++ src/setup.c
@@ -92,10 +92,13 @@
9292
"Edit the Cascading Style Sheet used by all pages of this repository");
9393
setup_menu_entry("Header", "setup_header",
9494
"Edit HTML text inserted at the top of every page");
9595
setup_menu_entry("Footer", "setup_footer",
9696
"Edit HTML text inserted at the bottom of every page");
97
+ setup_menu_entry("Moderation", "setup_modreq",
98
+ "Enable/Disable requiring moderator approval of Wiki and/or Ticket"
99
+ "edits and attachments.");
97100
setup_menu_entry("Ad-Unit", "setup_adunit",
98101
"Edit HTML text for an ad unit inserted after the menu bar");
99102
setup_menu_entry("Logo", "setup_logo",
100103
"Change the logo and background images for the server");
101104
setup_menu_entry("Shunned", "shun",
@@ -1403,10 +1406,54 @@
14031406
@ <blockquote><pre>
14041407
@ %h(zDefaultFooter)
14051408
@ </pre></blockquote>
14061409
style_footer();
14071410
db_end_transaction(0);
1411
+}
1412
+
1413
+/*
1414
+** WEBPAGE: setup_modreq
1415
+*/
1416
+void setup_modreq(void){
1417
+ login_check_credentials();
1418
+ if( !g.perm.Setup ){
1419
+ login_needed();
1420
+ }
1421
+
1422
+ style_header("Moderator For Wiki And Tickets");
1423
+ db_begin_transaction();
1424
+ @ <form action="%R/setup_modreq" method="post"><div>
1425
+ login_insert_csrf_secret();
1426
+ @ <hr />
1427
+ onoff_attribute("Moderate ticket changes",
1428
+ "modreq-tkt", "modreq-tkt", 0);
1429
+ @ <p>When enabled, any change to tickets is subject to the approval
1430
+ @ a ticket moderator - a user with the "q" or Mod-Tkt privilege.
1431
+ @ Ticket changes enter the system and are shown locally, but are not
1432
+ @ synced until they are approved. The moderator has the option to
1433
+ @ delete the change rather than approve it. Ticket changes made by
1434
+ @ a user who hwas the Mod-Tkt privilege are never subject to
1435
+ @ moderation.
1436
+ @
1437
+ @ <hr />
1438
+ onoff_attribute("Moderate wiki changes",
1439
+ "modreq-wiki", "modreq-wiki", 0);
1440
+ @ <p>When enabled, any change to wiki is subject to the approval
1441
+ @ a ticket moderator - a user with the "l" or Mod-Wiki privilege.
1442
+ @ Wiki changes enter the system and are shown locally, but are not
1443
+ @ synced until they are approved. The moderator has the option to
1444
+ @ delete the change rather than approve it. Wiki changes made by
1445
+ @ a user who has the Mod-Wiki privilege are never subject to
1446
+ @ moderation.
1447
+ @ </p>
1448
+
1449
+ @ <hr />
1450
+ @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
1451
+ @ </div></form>
1452
+ db_end_transaction(0);
1453
+ style_footer();
1454
+
14081455
}
14091456
14101457
/*
14111458
** WEBPAGE: setup_adunit
14121459
*/
14131460
--- src/setup.c
+++ src/setup.c
@@ -92,10 +92,13 @@
92 "Edit the Cascading Style Sheet used by all pages of this repository");
93 setup_menu_entry("Header", "setup_header",
94 "Edit HTML text inserted at the top of every page");
95 setup_menu_entry("Footer", "setup_footer",
96 "Edit HTML text inserted at the bottom of every page");
 
 
 
97 setup_menu_entry("Ad-Unit", "setup_adunit",
98 "Edit HTML text for an ad unit inserted after the menu bar");
99 setup_menu_entry("Logo", "setup_logo",
100 "Change the logo and background images for the server");
101 setup_menu_entry("Shunned", "shun",
@@ -1403,10 +1406,54 @@
1403 @ <blockquote><pre>
1404 @ %h(zDefaultFooter)
1405 @ </pre></blockquote>
1406 style_footer();
1407 db_end_transaction(0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1408 }
1409
1410 /*
1411 ** WEBPAGE: setup_adunit
1412 */
1413
--- src/setup.c
+++ src/setup.c
@@ -92,10 +92,13 @@
92 "Edit the Cascading Style Sheet used by all pages of this repository");
93 setup_menu_entry("Header", "setup_header",
94 "Edit HTML text inserted at the top of every page");
95 setup_menu_entry("Footer", "setup_footer",
96 "Edit HTML text inserted at the bottom of every page");
97 setup_menu_entry("Moderation", "setup_modreq",
98 "Enable/Disable requiring moderator approval of Wiki and/or Ticket"
99 "edits and attachments.");
100 setup_menu_entry("Ad-Unit", "setup_adunit",
101 "Edit HTML text for an ad unit inserted after the menu bar");
102 setup_menu_entry("Logo", "setup_logo",
103 "Change the logo and background images for the server");
104 setup_menu_entry("Shunned", "shun",
@@ -1403,10 +1406,54 @@
1406 @ <blockquote><pre>
1407 @ %h(zDefaultFooter)
1408 @ </pre></blockquote>
1409 style_footer();
1410 db_end_transaction(0);
1411 }
1412
1413 /*
1414 ** WEBPAGE: setup_modreq
1415 */
1416 void setup_modreq(void){
1417 login_check_credentials();
1418 if( !g.perm.Setup ){
1419 login_needed();
1420 }
1421
1422 style_header("Moderator For Wiki And Tickets");
1423 db_begin_transaction();
1424 @ <form action="%R/setup_modreq" method="post"><div>
1425 login_insert_csrf_secret();
1426 @ <hr />
1427 onoff_attribute("Moderate ticket changes",
1428 "modreq-tkt", "modreq-tkt", 0);
1429 @ <p>When enabled, any change to tickets is subject to the approval
1430 @ a ticket moderator - a user with the "q" or Mod-Tkt privilege.
1431 @ Ticket changes enter the system and are shown locally, but are not
1432 @ synced until they are approved. The moderator has the option to
1433 @ delete the change rather than approve it. Ticket changes made by
1434 @ a user who hwas the Mod-Tkt privilege are never subject to
1435 @ moderation.
1436 @
1437 @ <hr />
1438 onoff_attribute("Moderate wiki changes",
1439 "modreq-wiki", "modreq-wiki", 0);
1440 @ <p>When enabled, any change to wiki is subject to the approval
1441 @ a ticket moderator - a user with the "l" or Mod-Wiki privilege.
1442 @ Wiki changes enter the system and are shown locally, but are not
1443 @ synced until they are approved. The moderator has the option to
1444 @ delete the change rather than approve it. Wiki changes made by
1445 @ a user who has the Mod-Wiki privilege are never subject to
1446 @ moderation.
1447 @ </p>
1448
1449 @ <hr />
1450 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
1451 @ </div></form>
1452 db_end_transaction(0);
1453 style_footer();
1454
1455 }
1456
1457 /*
1458 ** WEBPAGE: setup_adunit
1459 */
1460
+10 -42
--- src/tkt.c
+++ src/tkt.c
@@ -335,48 +335,11 @@
335335
336336
zFullName = db_text(0,
337337
"SELECT tkt_uuid FROM ticket"
338338
" WHERE tkt_uuid GLOB '%q*'", zUuid);
339339
if( zFullName ){
340
- int cnt = 0;
341
- Stmt q;
342
- db_prepare(&q,
343
- "SELECT datetime(mtime,'localtime'), filename, user"
344
- " FROM attachment"
345
- " WHERE isLatest AND src!='' AND target=%Q"
346
- " ORDER BY mtime DESC",
347
- zFullName);
348
- while( db_step(&q)==SQLITE_ROW ){
349
- const char *zDate = db_column_text(&q, 0);
350
- const char *zFile = db_column_text(&q, 1);
351
- const char *zUser = db_column_text(&q, 2);
352
- if( cnt==0 ){
353
- @ <hr /><h2>Attachments:</h2>
354
- @ <ul>
355
- }
356
- cnt++;
357
- @ <li>
358
- if( g.perm.Read && g.perm.Hyperlink ){
359
- @ %z(href("%R/attachview?tkt=%s&file=%t",zFullName,zFile))
360
- @ %h(zFile)</a>
361
- }else{
362
- @ %h(zFile)
363
- }
364
- @ added by %h(zUser) on
365
- hyperlink_to_date(zDate, ".");
366
- if( g.perm.WrTkt && g.perm.Attach ){
367
- char *zH;
368
- zH = href("%R/attachdelete?tkt=%s&file=%t&from=%R/tktview%%3fname=%s",
369
- zFullName, zFile, zFullName);
370
- @ [%z(zH)delete</a>]
371
- }
372
- @ </li>
373
- }
374
- if( cnt ){
375
- @ </ul>
376
- }
377
- db_finalize(&q);
340
+ attachment_list(zFullName, "<hr /><h2>Attachments:</h2><ul>");
378341
}
379342
380343
style_footer();
381344
}
382345
@@ -419,11 +382,15 @@
419382
}
420383
421384
/*
422385
** Write a ticket into the repository.
423386
*/
424
-static void ticket_put(Blob *pTicket, const char *zTktId, int needMod){
387
+static void ticket_put(
388
+ Blob *pTicket, /* The text of the ticket change record */
389
+ const char *zTktId, /* The ticket to which this change is applied */
390
+ int needMod /* True if moderation is needed */
391
+){
425392
int rid = content_put_ex(pTicket, 0, 0, 0, needMod);
426393
if( rid==0 ){
427394
fossil_panic("trouble committing ticket: %s", g.zErrMsg);
428395
}
429396
if( needMod ){
@@ -431,12 +398,12 @@
431398
db_multi_exec(
432399
"INSERT INTO modreq(objid, tktid) VALUES(%d,'%s')",
433400
rid, zTktId
434401
);
435402
}else{
436
- db_multi_exec("INSERT INTO unsent VALUES(%d);", rid);
437
- db_multi_exec("INSERT INTO unclustered VALUES(%d);", rid);
403
+ db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
404
+ db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
438405
}
439406
manifest_crosslink_begin();
440407
manifest_crosslink(rid, pTicket);
441408
assert( blob_is_reset(pTicket) );
442409
manifest_crosslink_end();
@@ -522,11 +489,12 @@
522489
}else if( g.thTrace ){
523490
Th_Trace("submit_ticket {\n<blockquote><pre>\n%h\n</pre></blockquote>\n"
524491
"}<br />\n",
525492
blob_str(&tktchng));
526493
}else{
527
- ticket_put(&tktchng, zUuid, g.perm.ModTkt==0);
494
+ ticket_put(&tktchng, zUuid,
495
+ (g.perm.ModTkt==0 && db_get_boolean("modreq-tkt",0)==1));
528496
}
529497
return ticket_change();
530498
}
531499
532500
533501
--- src/tkt.c
+++ src/tkt.c
@@ -335,48 +335,11 @@
335
336 zFullName = db_text(0,
337 "SELECT tkt_uuid FROM ticket"
338 " WHERE tkt_uuid GLOB '%q*'", zUuid);
339 if( zFullName ){
340 int cnt = 0;
341 Stmt q;
342 db_prepare(&q,
343 "SELECT datetime(mtime,'localtime'), filename, user"
344 " FROM attachment"
345 " WHERE isLatest AND src!='' AND target=%Q"
346 " ORDER BY mtime DESC",
347 zFullName);
348 while( db_step(&q)==SQLITE_ROW ){
349 const char *zDate = db_column_text(&q, 0);
350 const char *zFile = db_column_text(&q, 1);
351 const char *zUser = db_column_text(&q, 2);
352 if( cnt==0 ){
353 @ <hr /><h2>Attachments:</h2>
354 @ <ul>
355 }
356 cnt++;
357 @ <li>
358 if( g.perm.Read && g.perm.Hyperlink ){
359 @ %z(href("%R/attachview?tkt=%s&file=%t",zFullName,zFile))
360 @ %h(zFile)</a>
361 }else{
362 @ %h(zFile)
363 }
364 @ added by %h(zUser) on
365 hyperlink_to_date(zDate, ".");
366 if( g.perm.WrTkt && g.perm.Attach ){
367 char *zH;
368 zH = href("%R/attachdelete?tkt=%s&file=%t&from=%R/tktview%%3fname=%s",
369 zFullName, zFile, zFullName);
370 @ [%z(zH)delete</a>]
371 }
372 @ </li>
373 }
374 if( cnt ){
375 @ </ul>
376 }
377 db_finalize(&q);
378 }
379
380 style_footer();
381 }
382
@@ -419,11 +382,15 @@
419 }
420
421 /*
422 ** Write a ticket into the repository.
423 */
424 static void ticket_put(Blob *pTicket, const char *zTktId, int needMod){
 
 
 
 
425 int rid = content_put_ex(pTicket, 0, 0, 0, needMod);
426 if( rid==0 ){
427 fossil_panic("trouble committing ticket: %s", g.zErrMsg);
428 }
429 if( needMod ){
@@ -431,12 +398,12 @@
431 db_multi_exec(
432 "INSERT INTO modreq(objid, tktid) VALUES(%d,'%s')",
433 rid, zTktId
434 );
435 }else{
436 db_multi_exec("INSERT INTO unsent VALUES(%d);", rid);
437 db_multi_exec("INSERT INTO unclustered VALUES(%d);", rid);
438 }
439 manifest_crosslink_begin();
440 manifest_crosslink(rid, pTicket);
441 assert( blob_is_reset(pTicket) );
442 manifest_crosslink_end();
@@ -522,11 +489,12 @@
522 }else if( g.thTrace ){
523 Th_Trace("submit_ticket {\n<blockquote><pre>\n%h\n</pre></blockquote>\n"
524 "}<br />\n",
525 blob_str(&tktchng));
526 }else{
527 ticket_put(&tktchng, zUuid, g.perm.ModTkt==0);
 
528 }
529 return ticket_change();
530 }
531
532
533
--- src/tkt.c
+++ src/tkt.c
@@ -335,48 +335,11 @@
335
336 zFullName = db_text(0,
337 "SELECT tkt_uuid FROM ticket"
338 " WHERE tkt_uuid GLOB '%q*'", zUuid);
339 if( zFullName ){
340 attachment_list(zFullName, "<hr /><h2>Attachments:</h2><ul>");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341 }
342
343 style_footer();
344 }
345
@@ -419,11 +382,15 @@
382 }
383
384 /*
385 ** Write a ticket into the repository.
386 */
387 static void ticket_put(
388 Blob *pTicket, /* The text of the ticket change record */
389 const char *zTktId, /* The ticket to which this change is applied */
390 int needMod /* True if moderation is needed */
391 ){
392 int rid = content_put_ex(pTicket, 0, 0, 0, needMod);
393 if( rid==0 ){
394 fossil_panic("trouble committing ticket: %s", g.zErrMsg);
395 }
396 if( needMod ){
@@ -431,12 +398,12 @@
398 db_multi_exec(
399 "INSERT INTO modreq(objid, tktid) VALUES(%d,'%s')",
400 rid, zTktId
401 );
402 }else{
403 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
404 db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
405 }
406 manifest_crosslink_begin();
407 manifest_crosslink(rid, pTicket);
408 assert( blob_is_reset(pTicket) );
409 manifest_crosslink_end();
@@ -522,11 +489,12 @@
489 }else if( g.thTrace ){
490 Th_Trace("submit_ticket {\n<blockquote><pre>\n%h\n</pre></blockquote>\n"
491 "}<br />\n",
492 blob_str(&tktchng));
493 }else{
494 ticket_put(&tktchng, zUuid,
495 (g.perm.ModTkt==0 && db_get_boolean("modreq-tkt",0)==1));
496 }
497 return ticket_change();
498 }
499
500
501
+3 -39
--- src/wiki.c
+++ src/wiki.c
@@ -214,66 +214,30 @@
214214
style_set_current_page("%s?name=%T", g.zPath, zPageName);
215215
style_header(zPageName);
216216
blob_init(&wiki, zBody, -1);
217217
wiki_convert(&wiki, 0, 0);
218218
blob_reset(&wiki);
219
-
220
- db_prepare(&q,
221
- "SELECT datetime(mtime,'localtime'), filename, user"
222
- " FROM attachment"
223
- " WHERE isLatest AND src!='' AND target=%Q"
224
- " ORDER BY mtime DESC",
225
- zPageName);
226
- while( db_step(&q)==SQLITE_ROW ){
227
- const char *zDate = db_column_text(&q, 0);
228
- const char *zFile = db_column_text(&q, 1);
229
- const char *zUser = db_column_text(&q, 2);
230
- if( cnt==0 ){
231
- @ <hr /><h2>Attachments:</h2>
232
- @ <ul>
233
- }
234
- cnt++;
235
- @ <li>
236
- if( g.perm.Hyperlink && g.perm.Read ){
237
- @ %z(href("%R/attachview?page=%T&file=%t",zPageName,zFile))
238
- @ %h(zFile)</a>
239
- }else{
240
- @ %h(zFile)
241
- }
242
- @ added by %h(zUser) on
243
- hyperlink_to_date(zDate, ".");
244
- if( g.perm.WrWiki && g.perm.Attach ){
245
- char *zH;
246
- zH = href("%R/attachdelete?page=%t&file=%t&from=%R/wiki%%3fname=%f",
247
- zPageName, zFile, zPageName);
248
- @ [%z(zH)delete</a>]
249
- }
250
- @ </li>
251
- }
252
- if( cnt ){
253
- @ </ul>
254
- }
255
- db_finalize(&q);
256
-
219
+ attachment_list(zPageName, "<hr /><h2>Attachments:</h2><ul>");
257220
manifest_destroy(pWiki);
258221
style_footer();
259222
}
260223
261224
/*
262225
** Write a wiki artifact into the repository
263226
*/
264227
static void wiki_put(Blob *pWiki, int parent){
265228
int nrid;
266
- if( g.perm.ModWiki ){
229
+ if( g.perm.ModWiki || db_get_boolean("modreq-wiki",0)==0 ){
267230
nrid = content_put_ex(pWiki, 0, 0, 0, 0);
268231
if( parent) content_deltify(parent, nrid, 0);
269232
}else{
270233
nrid = content_put_ex(pWiki, 0, 0, 0, 1);
271234
moderation_table_create();
272235
db_multi_exec("INSERT INTO modreq(objid) VALUES(%d)", nrid);
273236
}
274237
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
238
+ db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid);
275239
manifest_crosslink(nrid, pWiki);
276240
}
277241
278242
/*
279243
** WEBPAGE: wikiedit
280244
--- src/wiki.c
+++ src/wiki.c
@@ -214,66 +214,30 @@
214 style_set_current_page("%s?name=%T", g.zPath, zPageName);
215 style_header(zPageName);
216 blob_init(&wiki, zBody, -1);
217 wiki_convert(&wiki, 0, 0);
218 blob_reset(&wiki);
219
220 db_prepare(&q,
221 "SELECT datetime(mtime,'localtime'), filename, user"
222 " FROM attachment"
223 " WHERE isLatest AND src!='' AND target=%Q"
224 " ORDER BY mtime DESC",
225 zPageName);
226 while( db_step(&q)==SQLITE_ROW ){
227 const char *zDate = db_column_text(&q, 0);
228 const char *zFile = db_column_text(&q, 1);
229 const char *zUser = db_column_text(&q, 2);
230 if( cnt==0 ){
231 @ <hr /><h2>Attachments:</h2>
232 @ <ul>
233 }
234 cnt++;
235 @ <li>
236 if( g.perm.Hyperlink && g.perm.Read ){
237 @ %z(href("%R/attachview?page=%T&file=%t",zPageName,zFile))
238 @ %h(zFile)</a>
239 }else{
240 @ %h(zFile)
241 }
242 @ added by %h(zUser) on
243 hyperlink_to_date(zDate, ".");
244 if( g.perm.WrWiki && g.perm.Attach ){
245 char *zH;
246 zH = href("%R/attachdelete?page=%t&file=%t&from=%R/wiki%%3fname=%f",
247 zPageName, zFile, zPageName);
248 @ [%z(zH)delete</a>]
249 }
250 @ </li>
251 }
252 if( cnt ){
253 @ </ul>
254 }
255 db_finalize(&q);
256
257 manifest_destroy(pWiki);
258 style_footer();
259 }
260
261 /*
262 ** Write a wiki artifact into the repository
263 */
264 static void wiki_put(Blob *pWiki, int parent){
265 int nrid;
266 if( g.perm.ModWiki ){
267 nrid = content_put_ex(pWiki, 0, 0, 0, 0);
268 if( parent) content_deltify(parent, nrid, 0);
269 }else{
270 nrid = content_put_ex(pWiki, 0, 0, 0, 1);
271 moderation_table_create();
272 db_multi_exec("INSERT INTO modreq(objid) VALUES(%d)", nrid);
273 }
274 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
 
275 manifest_crosslink(nrid, pWiki);
276 }
277
278 /*
279 ** WEBPAGE: wikiedit
280
--- src/wiki.c
+++ src/wiki.c
@@ -214,66 +214,30 @@
214 style_set_current_page("%s?name=%T", g.zPath, zPageName);
215 style_header(zPageName);
216 blob_init(&wiki, zBody, -1);
217 wiki_convert(&wiki, 0, 0);
218 blob_reset(&wiki);
219 attachment_list(zPageName, "<hr /><h2>Attachments:</h2><ul>");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220 manifest_destroy(pWiki);
221 style_footer();
222 }
223
224 /*
225 ** Write a wiki artifact into the repository
226 */
227 static void wiki_put(Blob *pWiki, int parent){
228 int nrid;
229 if( g.perm.ModWiki || db_get_boolean("modreq-wiki",0)==0 ){
230 nrid = content_put_ex(pWiki, 0, 0, 0, 0);
231 if( parent) content_deltify(parent, nrid, 0);
232 }else{
233 nrid = content_put_ex(pWiki, 0, 0, 0, 1);
234 moderation_table_create();
235 db_multi_exec("INSERT INTO modreq(objid) VALUES(%d)", nrid);
236 }
237 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
238 db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid);
239 manifest_crosslink(nrid, pWiki);
240 }
241
242 /*
243 ** WEBPAGE: wikiedit
244

Keyboard Shortcuts

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