Check-in [aa4dd79835]
Not logged in

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

Overview
Comment:Tickets are now held for moderator approval.
Timelines: family | ancestors | descendants | both | moderation
Files: files | file ages | folders
SHA1: aa4dd798351eeced19d8e13aa2bd28be6c8264fd
User & Date: drh 2012-11-01 15:08:29.735
Context
2012-11-01
17:56
Add moderator approval for attachments. check-in: 9ac467310f user: drh tags: moderation
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
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/info.c.
1662
1663
1664
1665
1666
1667
1668


1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684


1685
1686
1687










1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702

1703



1704
1705








1706
1707
1708
1709
1710


1711
1712







1713





1714
1715
1716
1717
1718
1719
1720
*/
void tinfo_page(void){
  int rid;
  char *zDate;
  const char *zUuid;
  char zTktName[UUID_SIZE+1];
  Manifest *pTktChng;



  login_check_credentials();
  if( !g.perm.RdTkt ){ login_needed(); return; }
  rid = name_to_rid_www("name");
  if( rid==0 ){ fossil_redirect_home(); }
  zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
  if( g.perm.Admin ){
    if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
      style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
            g.zTop, zUuid);
    }else{
      style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
            g.zTop, zUuid);
    }
  }
  pTktChng = manifest_get(rid, CFTYPE_TICKET);


  if( pTktChng==0 ){
    fossil_redirect_home();
  }










  style_header("Ticket Change Details");
  zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
  memcpy(zTktName, pTktChng->zTicketUuid, UUID_SIZE);
  zTktName[UUID_SIZE] = 0;
  if( g.perm.Hyperlink ){
    @ <h2>Changes to ticket
    @ %z(href("%R/tktview/%s",zTktName))%s(zTktName)</a></h2>
    @
    @ <p>By %h(pTktChng->zUser) on %s(zDate).
    style_submenu_element("Raw", "Raw", "%R/artifact/%T", zUuid);
    style_submenu_element("History", "History", 
             "%R/tkthistory/%s", pTktChng->zTicketUuid);
  }else{
    @ <h2>Changes to ticket %s(zTktName)</h2>
    @

    @ <p>By %h(pTktChng->zUser) on %s(zDate).



    @ </p>
  }








  free(zDate);
  ticket_output_change_artifact(pTktChng);
  manifest_destroy(pTktChng);
  if( g.perm.Setup ){
    @


    @ <p>These changes are implemented by artifact
    @ %z(href("%R/artifact/%s",zUuid))%s(zUuid)</a> (%d(rid)).</p>







  }





  style_footer();
}


/*
** WEBPAGE: info
** URL: info/ARTIFACTID







>
>
















>
>



>
>
>
>
>
>
>
>
>
>

<
<
<
<
<
<
<
<
|
|
|
<
|
|
>
|
>
>
>
|

>
>
>
>
>
>
>
>

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

>
>
>
>
>







1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702








1703
1704
1705

1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
*/
void tinfo_page(void){
  int rid;
  char *zDate;
  const char *zUuid;
  char zTktName[UUID_SIZE+1];
  Manifest *pTktChng;
  int modPending;
  const char *zModAction;

  login_check_credentials();
  if( !g.perm.RdTkt ){ login_needed(); return; }
  rid = name_to_rid_www("name");
  if( rid==0 ){ fossil_redirect_home(); }
  zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
  if( g.perm.Admin ){
    if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
      style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
            g.zTop, zUuid);
    }else{
      style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
            g.zTop, zUuid);
    }
  }
  pTktChng = manifest_get(rid, CFTYPE_TICKET);
  zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
  memcpy(zTktName, pTktChng->zTicketUuid, UUID_SIZE+1);
  if( pTktChng==0 ){
    fossil_redirect_home();
  }
  if( g.perm.ModTkt && (zModAction = P("modaction"))!=0 ){
    if( strcmp(zModAction,"delete")==0 ){
      moderation_disapprove(rid);
      cgi_redirectf("%R/tktview/%s", zTktName);
      /*NOTREACHED*/
    }
    if( strcmp(zModAction,"approve")==0 ){
      moderation_approve(rid);
    }
  }
  style_header("Ticket Change Details");








  style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
  style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
  style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);

  style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);

  @ <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>
  }
  @ <tr><th>Ticket:</th>
  @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a></td></tr>
  @ <tr><th>Date:</th><td>
  hyperlink_to_date(zDate, "</td></tr>");
  free(zDate);
  @ <tr><th>User:</th><td>
  hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>");
  @ </table>
  
  if( g.perm.ModTkt && modPending ){
    @ <div class="section">Moderation</div>
    @ <blockquote>
    @ <form method="POST" action="%R/tinfo/%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">Changes</div>
  @ <p>
  ticket_output_change_artifact(pTktChng);
  manifest_destroy(pTktChng);
  style_footer();
}


/*
** WEBPAGE: info
** URL: info/ARTIFACTID
Changes to src/moderate.c.
138
139
140
141
142
143
144

145
146
147
148
149
150
151
void modreq_page(void){
  Blob sql;
  Stmt q;

  login_check_credentials();
  if( !g.perm.RdWiki && !g.perm.RdTkt ){ login_needed(); return; }
  style_header("Pending Moderation Requests");

  blob_init(&sql, timeline_query_for_www(), -1);
  blob_appendf(&sql,
      " AND event.objid IN (SELECT objid FROM modreq)"
      " ORDER BY event.mtime DESC"
  );
  db_prepare(&q, blob_str(&sql));
  www_print_timeline(&q, 0, 0, 0, 0);







>







138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
void modreq_page(void){
  Blob sql;
  Stmt q;

  login_check_credentials();
  if( !g.perm.RdWiki && !g.perm.RdTkt ){ login_needed(); return; }
  style_header("Pending Moderation Requests");
  @ <h2>All Pending Moderation Requests</h2>
  blob_init(&sql, timeline_query_for_www(), -1);
  blob_appendf(&sql,
      " AND event.objid IN (SELECT objid FROM modreq)"
      " ORDER BY event.mtime DESC"
  );
  db_prepare(&q, blob_str(&sql));
  www_print_timeline(&q, 0, 0, 0, 0);
Changes to src/tkt.c.
413
414
415
416
417
418
419
























420
421
422
423
424
425
426
  if( idx>=nField ){
    Th_ErrorMessage(g.interp, "no such TICKET column: ", argv[1], argl[1]);
    return TH_ERROR;
  }
  azAppend[idx] = mprintf("%.*s", argl[2], argv[2]);
  return TH_OK;
}

























/*
** Subscript command:   submit_ticket
**
** Construct and submit a new ticket artifact.  The fields of the artifact
** are the names of the columns in the TICKET table.  The content is
** taken from TH variables.  If the content is unchanged, the field is







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







413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
  if( idx>=nField ){
    Th_ErrorMessage(g.interp, "no such TICKET column: ", argv[1], argl[1]);
    return TH_ERROR;
  }
  azAppend[idx] = mprintf("%.*s", argl[2], argv[2]);
  return TH_OK;
}

/*
** Write a ticket into the repository.
*/
static void ticket_put(Blob *pTicket, const char *zTktId, int needMod){
  int rid = content_put_ex(pTicket, 0, 0, 0, needMod);
  if( rid==0 ){
    fossil_panic("trouble committing ticket: %s", g.zErrMsg);
  }
  if( needMod ){
    moderation_table_create();
    db_multi_exec(
      "INSERT INTO modreq(objid, tktid) VALUES(%d,'%s')",
      rid, zTktId
    );
  }else{
    db_multi_exec("INSERT INTO unsent VALUES(%d);", rid);
    db_multi_exec("INSERT INTO unclustered VALUES(%d);", rid);
  }
  manifest_crosslink_begin();
  manifest_crosslink(rid, pTicket);
  assert( blob_is_reset(pTicket) );
  manifest_crosslink_end();
}

/*
** Subscript command:   submit_ticket
**
** Construct and submit a new ticket artifact.  The fields of the artifact
** are the names of the columns in the TICKET table.  The content is
** taken from TH variables.  If the content is unchanged, the field is
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
    @ <hr /></font>
    return TH_OK;
  }else if( g.thTrace ){
    Th_Trace("submit_ticket {\n<blockquote><pre>\n%h\n</pre></blockquote>\n"
             "}<br />\n",
       blob_str(&tktchng));
  }else{
    rid = content_put(&tktchng);
    if( rid==0 ){
      fossil_panic("trouble committing ticket: %s", g.zErrMsg);
    }
    manifest_crosslink_begin();
    manifest_crosslink(rid, &tktchng);
    assert( blob_is_reset(&tktchng) );
    manifest_crosslink_end();
  }
  return ticket_change();
}


/*
** WEBPAGE: tktnew







|
<
<
<
<
<
<
<







520
521
522
523
524
525
526
527







528
529
530
531
532
533
534
    @ <hr /></font>
    return TH_OK;
  }else if( g.thTrace ){
    Th_Trace("submit_ticket {\n<blockquote><pre>\n%h\n</pre></blockquote>\n"
             "}<br />\n",
       blob_str(&tktchng));
  }else{
    ticket_put(&tktchng, zUuid, g.perm.ModTkt==0);







  }
  return ticket_change();
}


/*
** WEBPAGE: tktnew
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
                       azField[i], strlen(zValue), zValue);
        }
      }
      blob_appendf(&tktchng, "K %s\n", zTktUuid);
      blob_appendf(&tktchng, "U %F\n", zUser);
      md5sum_blob(&tktchng, &cksum);
      blob_appendf(&tktchng, "Z %b\n", &cksum);
      rid = content_put(&tktchng);
      if( rid==0 ){
        fossil_panic("trouble committing ticket: %s", g.zErrMsg);
      }
      manifest_crosslink_begin();
      manifest_crosslink(rid, &tktchng);
      manifest_crosslink_end();
      assert( blob_is_reset(&tktchng) );
      printf("ticket %s succeeded for %s\n",
             (eCmd==set?"set":"add"),zTktUuid);
    }
  }
}







|
<
<
<
<
<
<
<





1202
1203
1204
1205
1206
1207
1208
1209







1210
1211
1212
1213
1214
                       azField[i], strlen(zValue), zValue);
        }
      }
      blob_appendf(&tktchng, "K %s\n", zTktUuid);
      blob_appendf(&tktchng, "U %F\n", zUser);
      md5sum_blob(&tktchng, &cksum);
      blob_appendf(&tktchng, "Z %b\n", &cksum);
      ticket_put(&tktchng, zTktUuid, 0);







      printf("ticket %s succeeded for %s\n",
             (eCmd==set?"set":"add"),zTktUuid);
    }
  }
}