Fossil

Check-in [b7ccf110f3]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Wiki moderation now appears to be working.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | moderation
Files: files | file ages | folders
SHA1: b7ccf110f37cf390e5b8a2c9439a426f73273027
User & Date: drh 2012-11-01 14:34:34.536
Context
2012-11-01
15:08
Tickets are now held for moderator approval. check-in: aa4dd79835 user: drh tags: moderation
14:34
Wiki moderation now appears to be working. check-in: b7ccf110f3 user: drh tags: moderation
13:11
More infrastructure for wiki and ticket moderation. check-in: f7938ebd00 user: drh tags: moderation
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/info.c.
721
722
723
724
725
726
727


728
729
730
731
732
733
734
735
736
737



738







739
740
741
742
743
744
745
746
747
748
749

750
751
752




753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769














770

771
772
773
774
775
776
777
*/
void winfo_page(void){
  int rid;
  Manifest *pWiki;
  char *zUuid;
  char *zDate;
  Blob wiki;



  login_check_credentials();
  if( !g.perm.RdWiki ){ login_needed(); return; }
  rid = name_to_rid_www("name");
  if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI))==0 ){
    style_header("Wiki Page Information Error");
    @ No such object: %h(P("name"))
    style_footer();
    return;
  }



  style_header("Edit To %h", pWiki->zWikiTitle);







  zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
  zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate);
  style_submenu_element("Raw", "Raw", "artifact/%S", zUuid);
  style_submenu_element("History", "History", "whistory?name=%t",
                        pWiki->zWikiTitle);
  style_submenu_element("Page", "Page", "wiki?name=%t",
                        pWiki->zWikiTitle);
  login_anonymous_available();
  @ <div class="section">Overview</div>
  @ <p><table class="label-value">
  @ <tr><th>Artifact&nbsp;ID:</th><td>%s(zUuid)

  if( g.perm.Setup ){
    @ (%d(rid))
  }




  @ </td></tr>
  @ <tr><th>Page&nbsp;Name:</th><td>%h(pWiki->zWikiTitle)</td></tr>
  @ <tr><th>Date:</th><td>
  hyperlink_to_date(zDate, "</td></tr>");
  @ <tr><th>Original&nbsp;User:</th><td>
  hyperlink_to_user(pWiki->zUser, zDate, "</td></tr>");
  if( pWiki->nParent>0 ){
    int i;
    @ <tr><th>Parent%s(pWiki->nParent==1?"":"s"):</th><td>
    for(i=0; i<pWiki->nParent; i++){
      char *zParent = pWiki->azParent[i];
      @ %z(href("info/%S",zParent))%s(zParent)</a>
    }
    @ </td></tr>
  }
  @ </table>
  blob_init(&wiki, pWiki->zWiki, -1);














  @ <div class="section">Content</div>

  wiki_convert(&wiki, 0, 0);
  blob_reset(&wiki);
  manifest_destroy(pWiki);
  style_footer();
}

/*







>
>










>
>
>
|
>
>
>
>
>
>
>










|
>



>
>
>
>
















|
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>







721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
*/
void winfo_page(void){
  int rid;
  Manifest *pWiki;
  char *zUuid;
  char *zDate;
  Blob wiki;
  int modPending;
  const char *zModAction;

  login_check_credentials();
  if( !g.perm.RdWiki ){ login_needed(); return; }
  rid = name_to_rid_www("name");
  if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI))==0 ){
    style_header("Wiki Page Information Error");
    @ No such object: %h(P("name"))
    style_footer();
    return;
  }
  if( g.perm.ModWiki && (zModAction = P("modaction"))!=0 ){
    if( strcmp(zModAction,"delete")==0 ){
      moderation_disapprove(rid);
      cgi_redirectf("%R/wiki?name=%T", pWiki->zWikiTitle);
      /*NOTREACHED*/
    }
    if( strcmp(zModAction,"approve")==0 ){
      moderation_approve(rid);
    }
  }
  style_header("Update of \"%h\"", pWiki->zWikiTitle);
  zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
  zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate);
  style_submenu_element("Raw", "Raw", "artifact/%S", zUuid);
  style_submenu_element("History", "History", "whistory?name=%t",
                        pWiki->zWikiTitle);
  style_submenu_element("Page", "Page", "wiki?name=%t",
                        pWiki->zWikiTitle);
  login_anonymous_available();
  @ <div class="section">Overview</div>
  @ <p><table class="label-value">
  @ <tr><th>Artifact&nbsp;ID:</th>
  @ <td>%z(href("%R/artifact/%s",zUuid))%s(zUuid)</a>
  if( g.perm.Setup ){
    @ (%d(rid))
  }
  modPending = moderation_pending(rid);
  if( modPending ){
    @ <span class="modpending">*** Moderation Pending ***</span>
  }
  @ </td></tr>
  @ <tr><th>Page&nbsp;Name:</th><td>%h(pWiki->zWikiTitle)</td></tr>
  @ <tr><th>Date:</th><td>
  hyperlink_to_date(zDate, "</td></tr>");
  @ <tr><th>Original&nbsp;User:</th><td>
  hyperlink_to_user(pWiki->zUser, zDate, "</td></tr>");
  if( pWiki->nParent>0 ){
    int i;
    @ <tr><th>Parent%s(pWiki->nParent==1?"":"s"):</th><td>
    for(i=0; i<pWiki->nParent; i++){
      char *zParent = pWiki->azParent[i];
      @ %z(href("info/%S",zParent))%s(zParent)</a>
    }
    @ </td></tr>
  }
  @ </table>

  if( g.perm.ModWiki && modPending ){
    @ <div class="section">Moderation</div>
    @ <blockquote>
    @ <form method="POST" action="%R/winfo/%s(zUuid)">
    @ <label><input type="radio" name="modaction" value="delete">
    @ Delete this change</label><br />
    @ <label><input type="radio" name="modaction" value="approve">
    @ Approve this change</label><br />
    @ <input type="submit" value="Submit">
    @ </form>
    @ </blockquote>
  }


  @ <div class="section">Content</div>
  blob_init(&wiki, pWiki->zWiki, -1);
  wiki_convert(&wiki, 0, 0);
  blob_reset(&wiki);
  manifest_destroy(pWiki);
  style_footer();
}

/*
Changes to src/login.c.
975
976
977
978
979
980
981
982

983
984
985
986
987
988
989
  for(i=0; zCap[i]; i++){
    switch( zCap[i] ){
      case 's':   g.perm.Setup = 1;  /* Fall thru into Admin */
      case 'a':   g.perm.Admin = g.perm.RdTkt = g.perm.WrTkt = g.perm.Zip =
                           g.perm.RdWiki = g.perm.WrWiki = g.perm.NewWiki =
                           g.perm.ApndWiki = g.perm.Hyperlink = g.perm.Clone = 
                           g.perm.NewTkt = g.perm.Password = g.perm.RdAddr =
                           g.perm.TktFmt = g.perm.Attach = g.perm.ApndTkt = 1;

                           /* Fall thru into Read/Write */
      case 'i':   g.perm.Read = g.perm.Write = 1;                     break;
      case 'o':   g.perm.Read = 1;                                 break;
      case 'z':   g.perm.Zip = 1;                                  break;

      case 'd':   g.perm.Delete = 1;                               break;
      case 'h':   g.perm.Hyperlink = 1;                            break;







|
>







975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
  for(i=0; zCap[i]; i++){
    switch( zCap[i] ){
      case 's':   g.perm.Setup = 1;  /* Fall thru into Admin */
      case 'a':   g.perm.Admin = g.perm.RdTkt = g.perm.WrTkt = g.perm.Zip =
                           g.perm.RdWiki = g.perm.WrWiki = g.perm.NewWiki =
                           g.perm.ApndWiki = g.perm.Hyperlink = g.perm.Clone = 
                           g.perm.NewTkt = g.perm.Password = g.perm.RdAddr =
                           g.perm.TktFmt = g.perm.Attach = g.perm.ApndTkt =
                           g.perm.ModWiki = g.perm.ModTkt = 1;
                           /* Fall thru into Read/Write */
      case 'i':   g.perm.Read = g.perm.Write = 1;                     break;
      case 'o':   g.perm.Read = 1;                                 break;
      case 'z':   g.perm.Zip = 1;                                  break;

      case 'd':   g.perm.Delete = 1;                               break;
      case 'h':   g.perm.Hyperlink = 1;                            break;
Changes to src/moderate.c.
65
66
67
68
69
70
71

72
73
74
75
76
77
78
/*
** Delete a moderation item given by rid
*/
void moderation_disapprove(int rid){
  Stmt q;
  char *zTktid;
  if( !moderation_pending(rid) ) return;

  if( content_is_private(rid) ){
    db_prepare(&q, "SELECT rid FROM delta WHERE srcid=%d", rid);
    while( db_step(&q)==SQLITE_ROW ){
      int ridUser = db_column_int(&q, 0);
      content_undelta(ridUser);
    }
    db_finalize(&q);







>







65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/*
** Delete a moderation item given by rid
*/
void moderation_disapprove(int rid){
  Stmt q;
  char *zTktid;
  if( !moderation_pending(rid) ) return;
  db_begin_transaction();
  if( content_is_private(rid) ){
    db_prepare(&q, "SELECT rid FROM delta WHERE srcid=%d", rid);
    while( db_step(&q)==SQLITE_ROW ){
      int ridUser = db_column_int(&q, 0);
      content_undelta(ridUser);
    }
    db_finalize(&q);
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

103
104
105
106
107
108
109
110


111




112
113
114
115
116
117
118
119
120
121

122
123
124
125
126
127
128
    );
    zTktid = db_text(0, "SELECT tktid FROm modreq WHERE objid=%d", rid);
    if( zTktid ){
      ticket_rebuild_entry(zTktid);
      fossil_free(zTktid);
    }
  }
  db_prepare(&q, "SELECT objid FROM modreq WHERE parent=%d AND "
                 "UNION SELECT parent FROM modreq WHERE objid=%d",
                 rid, rid);
  while( db_step(&q)==SQLITE_ROW ){
    int other = db_column_int(&q, 0);
    if( other==rid ) continue;
    moderation_approve(other);
  }
  db_finalize(&q);
  db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);

}

/*
** Approve an object held for moderation.
*/
void moderation_approve(int rid){
  Stmt q;
  if( !moderation_pending(rid) ) return;


  db_multi_exec("DELETE FROM private WHERE rid=%d;", rid);




  db_prepare(&q, "SELECT objid FROM modreq WHERE parent=%d AND "
                 "UNION SELECT parent FROM modreq WHERE objid=%d",
                 rid, rid);
  while( db_step(&q)==SQLITE_ROW ){
    int other = db_column_int(&q, 0);
    if( other==rid ) continue;
    moderation_approve(other);
  }
  db_finalize(&q);
  db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);

}

/*
** WEBPAGE: modreq
**
** Show all pending moderation request
*/







|









>








>
>
|
>
>
>
>
|









>







87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
    );
    zTktid = db_text(0, "SELECT tktid FROm modreq WHERE objid=%d", rid);
    if( zTktid ){
      ticket_rebuild_entry(zTktid);
      fossil_free(zTktid);
    }
  }
  db_prepare(&q, "SELECT objid FROM modreq WHERE parent=%d "
                 "UNION SELECT parent FROM modreq WHERE objid=%d",
                 rid, rid);
  while( db_step(&q)==SQLITE_ROW ){
    int other = db_column_int(&q, 0);
    if( other==rid ) continue;
    moderation_approve(other);
  }
  db_finalize(&q);
  db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
  db_end_transaction(0);
}

/*
** Approve an object held for moderation.
*/
void moderation_approve(int rid){
  Stmt q;
  if( !moderation_pending(rid) ) return;
  db_begin_transaction();
  db_multi_exec(
    "DELETE FROM private WHERE rid=%d;"
    "INSERT OR IGNORE INTO unclustered VALUES(%d);"
    "INSERT OR IGNORE INTO unsent VALUES(%d);",
    rid, rid, rid
  );
  db_prepare(&q, "SELECT objid FROM modreq WHERE parent=%d "
                 "UNION SELECT parent FROM modreq WHERE objid=%d",
                 rid, rid);
  while( db_step(&q)==SQLITE_ROW ){
    int other = db_column_int(&q, 0);
    if( other==rid ) continue;
    moderation_approve(other);
  }
  db_finalize(&q);
  db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
  db_end_transaction(0);
}

/*
** WEBPAGE: modreq
**
** Show all pending moderation request
*/
Changes to src/wiki.c.
253
254
255
256
257
258
259

















260
261
262
263
264
265
266
    @ </ul>
  }
  db_finalize(&q);
 
  manifest_destroy(pWiki);
  style_footer();
}


















/*
** WEBPAGE: wikiedit
** URL: /wikiedit?name=PAGENAME
*/
void wikiedit_page(void){
  char *zTag;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
    @ </ul>
  }
  db_finalize(&q);
 
  manifest_destroy(pWiki);
  style_footer();
}

/*
** Write a wiki artifact into the repository
*/
static void wiki_put(Blob *pWiki, int parent){
  int nrid;
  if( g.perm.ModWiki ){
    nrid = content_put_ex(pWiki, 0, 0, 0, 0);
    if( parent) content_deltify(parent, nrid, 0);
  }else{
    nrid = content_put_ex(pWiki, 0, 0, 0, 1);
    moderation_table_create();
    db_multi_exec("INSERT INTO modreq(objid) VALUES(%d)", nrid);
  }
  db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
  manifest_crosslink(nrid, pWiki);
}

/*
** WEBPAGE: wikiedit
** URL: /wikiedit?name=PAGENAME
*/
void wikiedit_page(void){
  char *zTag;
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
      if( g.zLogin ){
        blob_appendf(&wiki, "U %F\n", g.zLogin);
      }
      blob_appendf(&wiki, "W %d\n%s\n", strlen(zBody), zBody);
      md5sum_blob(&wiki, &cksum);
      blob_appendf(&wiki, "Z %b\n", &cksum);
      blob_reset(&cksum);
      nrid = content_put(&wiki);
      db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
      manifest_crosslink(nrid, &wiki);
      assert( blob_is_reset(&wiki) );
      content_deltify(rid, nrid, 0);
    }
    db_end_transaction(0);
    cgi_redirectf("wiki?name=%T", zPageName);
  }
  if( P("cancel")!=0 ){
    cgi_redirectf("wiki?name=%T", zPageName);
    return;







|
<
<
<
<







353
354
355
356
357
358
359
360




361
362
363
364
365
366
367
      if( g.zLogin ){
        blob_appendf(&wiki, "U %F\n", g.zLogin);
      }
      blob_appendf(&wiki, "W %d\n%s\n", strlen(zBody), zBody);
      md5sum_blob(&wiki, &cksum);
      blob_appendf(&wiki, "Z %b\n", &cksum);
      blob_reset(&cksum);
      wiki_put(&wiki, 0);




    }
    db_end_transaction(0);
    cgi_redirectf("wiki?name=%T", zPageName);
  }
  if( P("cancel")!=0 ){
    cgi_redirectf("wiki?name=%T", zPageName);
    return;
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
        blob_appendf(&wiki, "U %F\n", g.zLogin);
      }
      appendRemark(&body);
      blob_appendf(&wiki, "W %d\n%s\n", blob_size(&body), blob_str(&body));
      md5sum_blob(&wiki, &cksum);
      blob_appendf(&wiki, "Z %b\n", &cksum);
      blob_reset(&cksum);
      nrid = content_put(&wiki);
      db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
      manifest_crosslink(nrid, &wiki);
      assert( blob_is_reset(&wiki) );
      content_deltify(rid, nrid, 0);
      db_end_transaction(0);
    }
    cgi_redirectf("wiki?name=%T", zPageName);
  }
  if( P("cancel")!=0 ){
    cgi_redirectf("wiki?name=%T", zPageName);
    return;







|
<
<
<
<







549
550
551
552
553
554
555
556




557
558
559
560
561
562
563
        blob_appendf(&wiki, "U %F\n", g.zLogin);
      }
      appendRemark(&body);
      blob_appendf(&wiki, "W %d\n%s\n", blob_size(&body), blob_str(&body));
      md5sum_blob(&wiki, &cksum);
      blob_appendf(&wiki, "Z %b\n", &cksum);
      blob_reset(&cksum);
      wiki_put(&wiki, rid);




      db_end_transaction(0);
    }
    cgi_redirectf("wiki?name=%T", zPageName);
  }
  if( P("cancel")!=0 ){
    cgi_redirectf("wiki?name=%T", zPageName);
    return;
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
  }
  blob_appendf( &wiki, "W %d\n%s\n", blob_size(pContent),
                blob_str(pContent) );
  md5sum_blob(&wiki, &cksum);
  blob_appendf(&wiki, "Z %b\n", &cksum);
  blob_reset(&cksum);
  db_begin_transaction();
  nrid = content_put( &wiki);
  db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
  manifest_crosslink(nrid,&wiki);
  assert( blob_is_reset(&wiki) );
  content_deltify(rid,nrid,0);
  db_end_transaction(0);
  return 1;
}

/*
** COMMAND: wiki*
**







<
<
<
|
<







888
889
890
891
892
893
894



895

896
897
898
899
900
901
902
  }
  blob_appendf( &wiki, "W %d\n%s\n", blob_size(pContent),
                blob_str(pContent) );
  md5sum_blob(&wiki, &cksum);
  blob_appendf(&wiki, "Z %b\n", &cksum);
  blob_reset(&cksum);
  db_begin_transaction();



  wiki_put(&wiki, 0);

  db_end_transaction(0);
  return 1;
}

/*
** COMMAND: wiki*
**