Fossil SCM

Add moderator approval for attachments.

drh 2012-11-01 17:56 UTC moderation
Commit 9ac467310fd2155256ea4b3278412553fb7cfa4a
+35 -6
--- src/attach.c
+++ src/attach.c
@@ -41,11 +41,13 @@
4141
4242
if( zPage && zTkt ) zTkt = 0;
4343
login_check_credentials();
4444
blob_zero(&sql);
4545
blob_append(&sql,
46
- "SELECT datetime(mtime,'localtime'), src, target, filename, comment, user"
46
+ "SELECT datetime(mtime,'localtime'), src, target, filename,"
47
+ " comment, user,"
48
+ " (SELECT uuid FROM blob WHERE rid=attachid), attachid"
4749
" FROM attachment",
4850
-1
4951
);
5052
if( zPage ){
5153
if( g.perm.RdWiki==0 ) login_needed();
@@ -59,17 +61,20 @@
5961
if( g.perm.RdTkt==0 && g.perm.RdWiki==0 ) login_needed();
6062
style_header("All Attachments");
6163
}
6264
blob_appendf(&sql, " ORDER BY mtime DESC");
6365
db_prepare(&q, "%s", blob_str(&sql));
66
+ @ <ol>
6467
while( db_step(&q)==SQLITE_ROW ){
6568
const char *zDate = db_column_text(&q, 0);
6669
const char *zSrc = db_column_text(&q, 1);
6770
const char *zTarget = db_column_text(&q, 2);
6871
const char *zFilename = db_column_text(&q, 3);
6972
const char *zComment = db_column_text(&q, 4);
7073
const char *zUser = db_column_text(&q, 5);
74
+ const char *zUuid = db_column_text(&q, 6);
75
+ int attachid = db_column_int(&q, 7);
7176
int i;
7277
char *zUrlTail;
7378
for(i=0; zFilename[i]; i++){
7479
if( zFilename[i]=='/' && zFilename[i+1]!=0 ){
7580
zFilename = &zFilename[i+1];
@@ -79,12 +84,16 @@
7984
if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
8085
zUrlTail = mprintf("tkt=%s&file=%t", zTarget, zFilename);
8186
}else{
8287
zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename);
8388
}
84
- @
85
- @ <p><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a>
89
+ @ <li><p>
90
+ @ Attachment %z(href("%R/ainfo/%s",zUuid))%S(zUuid)</a>
91
+ if( moderation_pending(attachid) ){
92
+ @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
93
+ }
94
+ @ <br><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a>
8695
@ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br />
8796
if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++;
8897
if( zComment && zComment[0] ){
8998
@ %w(zComment)<br />
9099
}
@@ -111,10 +120,11 @@
111120
@ by %h(zUser) on
112121
hyperlink_to_date(zDate, ".");
113122
free(zUrlTail);
114123
}
115124
db_finalize(&q);
125
+ @ </ol>
116126
style_footer();
117127
return;
118128
}
119129
120130
/*
@@ -182,10 +192,28 @@
182192
cgi_replace_parameter("m", mimetype_from_name(zFile));
183193
rawartifact_page();
184194
}
185195
}
186196
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
+
187215
188216
/*
189217
** WEBPAGE: attachadd
190218
**
191219
** tkt=TICKETUUID
@@ -240,10 +268,11 @@
240268
char *zDate;
241269
int rid;
242270
int i, n;
243271
int addCompress = 0;
244272
Manifest *pManifest;
273
+ int isModerator;
245274
246275
db_begin_transaction();
247276
blob_init(&content, aContent, szContent);
248277
pManifest = manifest_parse(&content, 0, 0);
249278
manifest_destroy(pManifest);
@@ -250,11 +279,12 @@
250279
blob_init(&content, aContent, szContent);
251280
if( pManifest ){
252281
blob_compress(&content, &content);
253282
addCompress = 1;
254283
}
255
- rid = content_put(&content);
284
+ isModerator = (zTkt!=0 && g.perm.ModTkt) || (zPage!=0 && g.perm.ModWiki);
285
+ rid = content_put_ex(&content, 0, 0, 0, !isModerator);
256286
zUUID = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
257287
blob_zero(&manifest);
258288
for(i=n=0; zName[i]; i++){
259289
if( zName[i]=='/' || zName[i]=='\\' ) n = i;
260290
}
@@ -272,12 +302,11 @@
272302
zDate = date_in_standard_format("now");
273303
blob_appendf(&manifest, "D %s\n", zDate);
274304
blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody");
275305
md5sum_blob(&manifest, &cksum);
276306
blob_appendf(&manifest, "Z %b\n", &cksum);
277
- rid = content_put(&manifest);
278
- manifest_crosslink(rid, &manifest);
307
+ attach_put(&manifest, rid, !isModerator);
279308
assert( blob_is_reset(&manifest) );
280309
db_end_transaction(0);
281310
cgi_redirect(zFrom);
282311
}
283312
style_header("Add Attachment");
284313
--- src/attach.c
+++ src/attach.c
@@ -41,11 +41,13 @@
41
42 if( zPage && zTkt ) zTkt = 0;
43 login_check_credentials();
44 blob_zero(&sql);
45 blob_append(&sql,
46 "SELECT datetime(mtime,'localtime'), src, target, filename, comment, user"
 
 
47 " FROM attachment",
48 -1
49 );
50 if( zPage ){
51 if( g.perm.RdWiki==0 ) login_needed();
@@ -59,17 +61,20 @@
59 if( g.perm.RdTkt==0 && g.perm.RdWiki==0 ) login_needed();
60 style_header("All Attachments");
61 }
62 blob_appendf(&sql, " ORDER BY mtime DESC");
63 db_prepare(&q, "%s", blob_str(&sql));
 
64 while( db_step(&q)==SQLITE_ROW ){
65 const char *zDate = db_column_text(&q, 0);
66 const char *zSrc = db_column_text(&q, 1);
67 const char *zTarget = db_column_text(&q, 2);
68 const char *zFilename = db_column_text(&q, 3);
69 const char *zComment = db_column_text(&q, 4);
70 const char *zUser = db_column_text(&q, 5);
 
 
71 int i;
72 char *zUrlTail;
73 for(i=0; zFilename[i]; i++){
74 if( zFilename[i]=='/' && zFilename[i+1]!=0 ){
75 zFilename = &zFilename[i+1];
@@ -79,12 +84,16 @@
79 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
80 zUrlTail = mprintf("tkt=%s&file=%t", zTarget, zFilename);
81 }else{
82 zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename);
83 }
84 @
85 @ <p><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a>
 
 
 
 
86 @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br />
87 if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++;
88 if( zComment && zComment[0] ){
89 @ %w(zComment)<br />
90 }
@@ -111,10 +120,11 @@
111 @ by %h(zUser) on
112 hyperlink_to_date(zDate, ".");
113 free(zUrlTail);
114 }
115 db_finalize(&q);
 
116 style_footer();
117 return;
118 }
119
120 /*
@@ -182,10 +192,28 @@
182 cgi_replace_parameter("m", mimetype_from_name(zFile));
183 rawartifact_page();
184 }
185 }
186
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
188 /*
189 ** WEBPAGE: attachadd
190 **
191 ** tkt=TICKETUUID
@@ -240,10 +268,11 @@
240 char *zDate;
241 int rid;
242 int i, n;
243 int addCompress = 0;
244 Manifest *pManifest;
 
245
246 db_begin_transaction();
247 blob_init(&content, aContent, szContent);
248 pManifest = manifest_parse(&content, 0, 0);
249 manifest_destroy(pManifest);
@@ -250,11 +279,12 @@
250 blob_init(&content, aContent, szContent);
251 if( pManifest ){
252 blob_compress(&content, &content);
253 addCompress = 1;
254 }
255 rid = content_put(&content);
 
256 zUUID = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
257 blob_zero(&manifest);
258 for(i=n=0; zName[i]; i++){
259 if( zName[i]=='/' || zName[i]=='\\' ) n = i;
260 }
@@ -272,12 +302,11 @@
272 zDate = date_in_standard_format("now");
273 blob_appendf(&manifest, "D %s\n", zDate);
274 blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody");
275 md5sum_blob(&manifest, &cksum);
276 blob_appendf(&manifest, "Z %b\n", &cksum);
277 rid = content_put(&manifest);
278 manifest_crosslink(rid, &manifest);
279 assert( blob_is_reset(&manifest) );
280 db_end_transaction(0);
281 cgi_redirect(zFrom);
282 }
283 style_header("Add Attachment");
284
--- src/attach.c
+++ src/attach.c
@@ -41,11 +41,13 @@
41
42 if( zPage && zTkt ) zTkt = 0;
43 login_check_credentials();
44 blob_zero(&sql);
45 blob_append(&sql,
46 "SELECT datetime(mtime,'localtime'), src, target, filename,"
47 " comment, user,"
48 " (SELECT uuid FROM blob WHERE rid=attachid), attachid"
49 " FROM attachment",
50 -1
51 );
52 if( zPage ){
53 if( g.perm.RdWiki==0 ) login_needed();
@@ -59,17 +61,20 @@
61 if( g.perm.RdTkt==0 && g.perm.RdWiki==0 ) login_needed();
62 style_header("All Attachments");
63 }
64 blob_appendf(&sql, " ORDER BY mtime DESC");
65 db_prepare(&q, "%s", blob_str(&sql));
66 @ <ol>
67 while( db_step(&q)==SQLITE_ROW ){
68 const char *zDate = db_column_text(&q, 0);
69 const char *zSrc = db_column_text(&q, 1);
70 const char *zTarget = db_column_text(&q, 2);
71 const char *zFilename = db_column_text(&q, 3);
72 const char *zComment = db_column_text(&q, 4);
73 const char *zUser = db_column_text(&q, 5);
74 const char *zUuid = db_column_text(&q, 6);
75 int attachid = db_column_int(&q, 7);
76 int i;
77 char *zUrlTail;
78 for(i=0; zFilename[i]; i++){
79 if( zFilename[i]=='/' && zFilename[i+1]!=0 ){
80 zFilename = &zFilename[i+1];
@@ -79,12 +84,16 @@
84 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
85 zUrlTail = mprintf("tkt=%s&file=%t", zTarget, zFilename);
86 }else{
87 zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename);
88 }
89 @ <li><p>
90 @ Attachment %z(href("%R/ainfo/%s",zUuid))%S(zUuid)</a>
91 if( moderation_pending(attachid) ){
92 @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
93 }
94 @ <br><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a>
95 @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br />
96 if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++;
97 if( zComment && zComment[0] ){
98 @ %w(zComment)<br />
99 }
@@ -111,10 +120,11 @@
120 @ by %h(zUser) on
121 hyperlink_to_date(zDate, ".");
122 free(zUrlTail);
123 }
124 db_finalize(&q);
125 @ </ol>
126 style_footer();
127 return;
128 }
129
130 /*
@@ -182,10 +192,28 @@
192 cgi_replace_parameter("m", mimetype_from_name(zFile));
193 rawartifact_page();
194 }
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
216 /*
217 ** WEBPAGE: attachadd
218 **
219 ** tkt=TICKETUUID
@@ -240,10 +268,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);
@@ -250,11 +279,12 @@
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 }
@@ -272,12 +302,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");
313
+169 -7
--- src/info.c
+++ src/info.c
@@ -763,11 +763,11 @@
763763
if( g.perm.Setup ){
764764
@ (%d(rid))
765765
}
766766
modPending = moderation_pending(rid);
767767
if( modPending ){
768
- @ <span class="modpending">*** Moderation Pending ***</span>
768
+ @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
769769
}
770770
@ </td></tr>
771771
@ <tr><th>Page&nbsp;Name:</th><td>%h(pWiki->zWikiTitle)</td></tr>
772772
@ <tr><th>Date:</th><td>
773773
hyperlink_to_date(zDate, "</td></tr>");
@@ -1439,11 +1439,15 @@
14391439
g.zTop, zUuid);
14401440
}
14411441
}
14421442
style_header("Hex Artifact Content");
14431443
zUuid = db_text("?","SELECT uuid FROM blob WHERE rid=%d", rid);
1444
- @ <h2>Artifact %s(zUuid):</h2>
1444
+ if( g.perm.Setup ){
1445
+ @ <h2>Artifact %s(zUuid) (%d(rid)):</h2>
1446
+ }else{
1447
+ @ <h2>Artifact %s(zUuid):</h2>
1448
+ }
14451449
blob_zero(&downloadName);
14461450
object_description(rid, 0, &downloadName);
14471451
style_submenu_element("Download", "Download",
14481452
"%s/raw/%T?name=%s", g.zTop, blob_str(&downloadName), zUuid);
14491453
@ <hr />
@@ -1586,11 +1590,15 @@
15861590
g.zTop, zUuid);
15871591
}
15881592
}
15891593
style_header("Artifact Content");
15901594
zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
1591
- @ <h2>Artifact %s(zUuid)</h2>
1595
+ if( g.perm.Setup ){
1596
+ @ <h2>Artifact %s(zUuid) (%d(rid)):</h2>
1597
+ }else{
1598
+ @ <h2>Artifact %s(zUuid):</h2>
1599
+ }
15921600
blob_zero(&downloadName);
15931601
objType = object_description(rid, 0, &downloadName);
15941602
style_submenu_element("Download", "Download",
15951603
"%s/raw/%T?name=%s", g.zTop, blob_str(&downloadName), zUuid);
15961604
asText = P("txt")!=0;
@@ -1682,15 +1690,13 @@
16821690
style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
16831691
g.zTop, zUuid);
16841692
}
16851693
}
16861694
pTktChng = manifest_get(rid, CFTYPE_TICKET);
1695
+ if( pTktChng==0 ) fossil_redirect_home();
16871696
zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
16881697
memcpy(zTktName, pTktChng->zTicketUuid, UUID_SIZE+1);
1689
- if( pTktChng==0 ){
1690
- fossil_redirect_home();
1691
- }
16921698
if( g.perm.ModTkt && (zModAction = P("modaction"))!=0 ){
16931699
if( strcmp(zModAction,"delete")==0 ){
16941700
moderation_disapprove(rid);
16951701
cgi_redirectf("%R/tktview/%s", zTktName);
16961702
/*NOTREACHED*/
@@ -1712,11 +1718,11 @@
17121718
if( g.perm.Setup ){
17131719
@ (%d(rid))
17141720
}
17151721
modPending = moderation_pending(rid);
17161722
if( modPending ){
1717
- @ <span class="modpending">*** Moderation Pending ***</span>
1723
+ @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
17181724
}
17191725
@ <tr><th>Ticket:</th>
17201726
@ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a></td></tr>
17211727
@ <tr><th>Date:</th><td>
17221728
hyperlink_to_date(zDate, "</td></tr>");
@@ -1742,10 +1748,163 @@
17421748
@ <p>
17431749
ticket_output_change_artifact(pTktChng);
17441750
manifest_destroy(pTktChng);
17451751
style_footer();
17461752
}
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
+}
17471906
17481907
17491908
/*
17501909
** WEBPAGE: info
17511910
** URL: info/ARTIFACTID
@@ -1807,10 +1966,13 @@
18071966
if( db_exists("SELECT 1 FROM plink WHERE cid=%d", rid) ){
18081967
ci_page();
18091968
}else
18101969
if( db_exists("SELECT 1 FROM plink WHERE pid=%d", rid) ){
18111970
ci_page();
1971
+ }else
1972
+ if( db_exists("SELECT 1 FROM attachment WHERE attachid=%d", rid) ){
1973
+ ainfo_page();
18121974
}else
18131975
{
18141976
artifact_page();
18151977
}
18161978
}
18171979
--- src/info.c
+++ src/info.c
@@ -763,11 +763,11 @@
763 if( g.perm.Setup ){
764 @ (%d(rid))
765 }
766 modPending = moderation_pending(rid);
767 if( modPending ){
768 @ <span class="modpending">*** Moderation Pending ***</span>
769 }
770 @ </td></tr>
771 @ <tr><th>Page&nbsp;Name:</th><td>%h(pWiki->zWikiTitle)</td></tr>
772 @ <tr><th>Date:</th><td>
773 hyperlink_to_date(zDate, "</td></tr>");
@@ -1439,11 +1439,15 @@
1439 g.zTop, zUuid);
1440 }
1441 }
1442 style_header("Hex Artifact Content");
1443 zUuid = db_text("?","SELECT uuid FROM blob WHERE rid=%d", rid);
1444 @ <h2>Artifact %s(zUuid):</h2>
 
 
 
 
1445 blob_zero(&downloadName);
1446 object_description(rid, 0, &downloadName);
1447 style_submenu_element("Download", "Download",
1448 "%s/raw/%T?name=%s", g.zTop, blob_str(&downloadName), zUuid);
1449 @ <hr />
@@ -1586,11 +1590,15 @@
1586 g.zTop, zUuid);
1587 }
1588 }
1589 style_header("Artifact Content");
1590 zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
1591 @ <h2>Artifact %s(zUuid)</h2>
 
 
 
 
1592 blob_zero(&downloadName);
1593 objType = object_description(rid, 0, &downloadName);
1594 style_submenu_element("Download", "Download",
1595 "%s/raw/%T?name=%s", g.zTop, blob_str(&downloadName), zUuid);
1596 asText = P("txt")!=0;
@@ -1682,15 +1690,13 @@
1682 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
1683 g.zTop, zUuid);
1684 }
1685 }
1686 pTktChng = manifest_get(rid, CFTYPE_TICKET);
 
1687 zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
1688 memcpy(zTktName, pTktChng->zTicketUuid, UUID_SIZE+1);
1689 if( pTktChng==0 ){
1690 fossil_redirect_home();
1691 }
1692 if( g.perm.ModTkt && (zModAction = P("modaction"))!=0 ){
1693 if( strcmp(zModAction,"delete")==0 ){
1694 moderation_disapprove(rid);
1695 cgi_redirectf("%R/tktview/%s", zTktName);
1696 /*NOTREACHED*/
@@ -1712,11 +1718,11 @@
1712 if( g.perm.Setup ){
1713 @ (%d(rid))
1714 }
1715 modPending = moderation_pending(rid);
1716 if( modPending ){
1717 @ <span class="modpending">*** Moderation Pending ***</span>
1718 }
1719 @ <tr><th>Ticket:</th>
1720 @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a></td></tr>
1721 @ <tr><th>Date:</th><td>
1722 hyperlink_to_date(zDate, "</td></tr>");
@@ -1742,10 +1748,163 @@
1742 @ <p>
1743 ticket_output_change_artifact(pTktChng);
1744 manifest_destroy(pTktChng);
1745 style_footer();
1746 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1747
1748
1749 /*
1750 ** WEBPAGE: info
1751 ** URL: info/ARTIFACTID
@@ -1807,10 +1966,13 @@
1807 if( db_exists("SELECT 1 FROM plink WHERE cid=%d", rid) ){
1808 ci_page();
1809 }else
1810 if( db_exists("SELECT 1 FROM plink WHERE pid=%d", rid) ){
1811 ci_page();
 
 
 
1812 }else
1813 {
1814 artifact_page();
1815 }
1816 }
1817
--- src/info.c
+++ src/info.c
@@ -763,11 +763,11 @@
763 if( g.perm.Setup ){
764 @ (%d(rid))
765 }
766 modPending = moderation_pending(rid);
767 if( modPending ){
768 @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
769 }
770 @ </td></tr>
771 @ <tr><th>Page&nbsp;Name:</th><td>%h(pWiki->zWikiTitle)</td></tr>
772 @ <tr><th>Date:</th><td>
773 hyperlink_to_date(zDate, "</td></tr>");
@@ -1439,11 +1439,15 @@
1439 g.zTop, zUuid);
1440 }
1441 }
1442 style_header("Hex Artifact Content");
1443 zUuid = db_text("?","SELECT uuid FROM blob WHERE rid=%d", rid);
1444 if( g.perm.Setup ){
1445 @ <h2>Artifact %s(zUuid) (%d(rid)):</h2>
1446 }else{
1447 @ <h2>Artifact %s(zUuid):</h2>
1448 }
1449 blob_zero(&downloadName);
1450 object_description(rid, 0, &downloadName);
1451 style_submenu_element("Download", "Download",
1452 "%s/raw/%T?name=%s", g.zTop, blob_str(&downloadName), zUuid);
1453 @ <hr />
@@ -1586,11 +1590,15 @@
1590 g.zTop, zUuid);
1591 }
1592 }
1593 style_header("Artifact Content");
1594 zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
1595 if( g.perm.Setup ){
1596 @ <h2>Artifact %s(zUuid) (%d(rid)):</h2>
1597 }else{
1598 @ <h2>Artifact %s(zUuid):</h2>
1599 }
1600 blob_zero(&downloadName);
1601 objType = object_description(rid, 0, &downloadName);
1602 style_submenu_element("Download", "Download",
1603 "%s/raw/%T?name=%s", g.zTop, blob_str(&downloadName), zUuid);
1604 asText = P("txt")!=0;
@@ -1682,15 +1690,13 @@
1690 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
1691 g.zTop, zUuid);
1692 }
1693 }
1694 pTktChng = manifest_get(rid, CFTYPE_TICKET);
1695 if( pTktChng==0 ) fossil_redirect_home();
1696 zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
1697 memcpy(zTktName, pTktChng->zTicketUuid, UUID_SIZE+1);
 
 
 
1698 if( g.perm.ModTkt && (zModAction = P("modaction"))!=0 ){
1699 if( strcmp(zModAction,"delete")==0 ){
1700 moderation_disapprove(rid);
1701 cgi_redirectf("%R/tktview/%s", zTktName);
1702 /*NOTREACHED*/
@@ -1712,11 +1718,11 @@
1718 if( g.perm.Setup ){
1719 @ (%d(rid))
1720 }
1721 modPending = moderation_pending(rid);
1722 if( modPending ){
1723 @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
1724 }
1725 @ <tr><th>Ticket:</th>
1726 @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a></td></tr>
1727 @ <tr><th>Date:</th><td>
1728 hyperlink_to_date(zDate, "</td></tr>");
@@ -1742,10 +1748,163 @@
1748 @ <p>
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
@@ -1807,10 +1966,13 @@
1966 if( db_exists("SELECT 1 FROM plink WHERE cid=%d", rid) ){
1967 ci_page();
1968 }else
1969 if( db_exists("SELECT 1 FROM plink WHERE pid=%d", rid) ){
1970 ci_page();
1971 }else
1972 if( db_exists("SELECT 1 FROM attachment WHERE attachid=%d", rid) ){
1973 ainfo_page();
1974 }else
1975 {
1976 artifact_page();
1977 }
1978 }
1979
+39 -30
--- src/moderate.c
+++ src/moderate.c
@@ -28,11 +28,11 @@
2828
*/
2929
void moderation_table_create(void){
3030
db_multi_exec(
3131
"CREATE TABLE IF NOT EXISTS modreq(\n"
3232
" objid INTEGER PRIMARY KEY,\n" /* Record pending approval */
33
- " parent INTEGER REFERENCES modreq,\n" /* Parent record */
33
+ " attachRid INT,\n" /* Object attached */
3434
" tktid TEXT\n" /* Associated ticket id */
3535
");\n"
3636
);
3737
}
3838
@@ -61,18 +61,40 @@
6161
db_reset(&q);
6262
return rc;
6363
}
6464
6565
/*
66
-** Delete a moderation item given by rid
66
+** Check to see if the object identified by RID is used for anything.
67
+*/
68
+static int object_used(int rid){
69
+ static const char *aTabField[] = {
70
+ "modreq", "attachRid",
71
+ "mlink", "mid",
72
+ "mlink", "fid",
73
+ "tagxref", "srcid",
74
+ "tagxref", "rid",
75
+ };
76
+ int i;
77
+ for(i=0; i<sizeof(aTabField)/sizeof(aTabField[0]); i+=2){
78
+ if( db_exists("SELECT 1 FROM %s WHERE %s=%d",
79
+ aTabField[i], aTabField[i+1], rid) ) return 1;
80
+ }
81
+ return 0;
82
+}
83
+
84
+/*
85
+** Delete a moderation item given by objid
6786
*/
68
-void moderation_disapprove(int rid){
87
+void moderation_disapprove(int objid){
6988
Stmt q;
7089
char *zTktid;
71
- if( !moderation_pending(rid) ) return;
90
+ int attachRid = 0;
91
+ int rid;
92
+ if( !moderation_pending(objid) ) return;
7293
db_begin_transaction();
73
- if( content_is_private(rid) ){
94
+ rid = objid;
95
+ while( rid && content_is_private(rid) ){
7496
db_prepare(&q, "SELECT rid FROM delta WHERE srcid=%d", rid);
7597
while( db_step(&q)==SQLITE_ROW ){
7698
int ridUser = db_column_int(&q, 0);
7799
content_undelta(ridUser);
78100
}
@@ -80,54 +102,41 @@
80102
db_multi_exec(
81103
"DELETE FROM blob WHERE rid=%d;"
82104
"DELETE FROM delta WHERE rid=%d;"
83105
"DELETE FROM event WHERE objid=%d;"
84106
"DELETE FROM tagxref WHERE rid=%d;"
85
- "DELETE FROM private WHERE rid=%d;",
86
- rid, rid, rid, rid, rid
107
+ "DELETE FROM private WHERE rid=%d;"
108
+ "DELETE FROM attachment WHERE attachid=%d;",
109
+ rid, rid, rid, rid, rid, rid
87110
);
88
- zTktid = db_text(0, "SELECT tktid FROm modreq WHERE objid=%d", rid);
89
- if( zTktid ){
111
+ zTktid = db_text(0, "SELECT tktid FROM modreq WHERE objid=%d", rid);
112
+ if( zTktid && zTktid[0] ){
90113
ticket_rebuild_entry(zTktid);
91114
fossil_free(zTktid);
92115
}
93
- }
94
- db_prepare(&q, "SELECT objid FROM modreq WHERE parent=%d "
95
- "UNION SELECT parent FROM modreq WHERE objid=%d",
96
- rid, rid);
97
- while( db_step(&q)==SQLITE_ROW ){
98
- int other = db_column_int(&q, 0);
99
- if( other==rid ) continue;
100
- moderation_approve(other);
101
- }
102
- db_finalize(&q);
103
- db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
116
+ attachRid = db_int(0, "SELECT attachRid FROM modreq WHERE objid=%d", rid);
117
+ if( rid==objid ){
118
+ db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
119
+ }
120
+ if( attachRid && object_used(attachRid) ) attachRid = 0;
121
+ rid = attachRid;
122
+ }
104123
db_end_transaction(0);
105124
}
106125
107126
/*
108127
** Approve an object held for moderation.
109128
*/
110129
void moderation_approve(int rid){
111
- Stmt q;
112130
if( !moderation_pending(rid) ) return;
113131
db_begin_transaction();
114132
db_multi_exec(
115133
"DELETE FROM private WHERE rid=%d;"
116134
"INSERT OR IGNORE INTO unclustered VALUES(%d);"
117135
"INSERT OR IGNORE INTO unsent VALUES(%d);",
118136
rid, rid, rid
119137
);
120
- db_prepare(&q, "SELECT objid FROM modreq WHERE parent=%d "
121
- "UNION SELECT parent FROM modreq WHERE objid=%d",
122
- rid, rid);
123
- while( db_step(&q)==SQLITE_ROW ){
124
- int other = db_column_int(&q, 0);
125
- if( other==rid ) continue;
126
- moderation_approve(other);
127
- }
128
- db_finalize(&q);
129138
db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
130139
db_end_transaction(0);
131140
}
132141
133142
/*
134143
--- src/moderate.c
+++ src/moderate.c
@@ -28,11 +28,11 @@
28 */
29 void moderation_table_create(void){
30 db_multi_exec(
31 "CREATE TABLE IF NOT EXISTS modreq(\n"
32 " objid INTEGER PRIMARY KEY,\n" /* Record pending approval */
33 " parent INTEGER REFERENCES modreq,\n" /* Parent record */
34 " tktid TEXT\n" /* Associated ticket id */
35 ");\n"
36 );
37 }
38
@@ -61,18 +61,40 @@
61 db_reset(&q);
62 return rc;
63 }
64
65 /*
66 ** Delete a moderation item given by rid
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67 */
68 void moderation_disapprove(int rid){
69 Stmt q;
70 char *zTktid;
71 if( !moderation_pending(rid) ) return;
 
 
72 db_begin_transaction();
73 if( content_is_private(rid) ){
 
74 db_prepare(&q, "SELECT rid FROM delta WHERE srcid=%d", rid);
75 while( db_step(&q)==SQLITE_ROW ){
76 int ridUser = db_column_int(&q, 0);
77 content_undelta(ridUser);
78 }
@@ -80,54 +102,41 @@
80 db_multi_exec(
81 "DELETE FROM blob WHERE rid=%d;"
82 "DELETE FROM delta WHERE rid=%d;"
83 "DELETE FROM event WHERE objid=%d;"
84 "DELETE FROM tagxref WHERE rid=%d;"
85 "DELETE FROM private WHERE rid=%d;",
86 rid, rid, rid, rid, rid
 
87 );
88 zTktid = db_text(0, "SELECT tktid FROm modreq WHERE objid=%d", rid);
89 if( zTktid ){
90 ticket_rebuild_entry(zTktid);
91 fossil_free(zTktid);
92 }
93 }
94 db_prepare(&q, "SELECT objid FROM modreq WHERE parent=%d "
95 "UNION SELECT parent FROM modreq WHERE objid=%d",
96 rid, rid);
97 while( db_step(&q)==SQLITE_ROW ){
98 int other = db_column_int(&q, 0);
99 if( other==rid ) continue;
100 moderation_approve(other);
101 }
102 db_finalize(&q);
103 db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
104 db_end_transaction(0);
105 }
106
107 /*
108 ** Approve an object held for moderation.
109 */
110 void moderation_approve(int rid){
111 Stmt q;
112 if( !moderation_pending(rid) ) return;
113 db_begin_transaction();
114 db_multi_exec(
115 "DELETE FROM private WHERE rid=%d;"
116 "INSERT OR IGNORE INTO unclustered VALUES(%d);"
117 "INSERT OR IGNORE INTO unsent VALUES(%d);",
118 rid, rid, rid
119 );
120 db_prepare(&q, "SELECT objid FROM modreq WHERE parent=%d "
121 "UNION SELECT parent FROM modreq WHERE objid=%d",
122 rid, rid);
123 while( db_step(&q)==SQLITE_ROW ){
124 int other = db_column_int(&q, 0);
125 if( other==rid ) continue;
126 moderation_approve(other);
127 }
128 db_finalize(&q);
129 db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
130 db_end_transaction(0);
131 }
132
133 /*
134
--- src/moderate.c
+++ src/moderate.c
@@ -28,11 +28,11 @@
28 */
29 void moderation_table_create(void){
30 db_multi_exec(
31 "CREATE TABLE IF NOT EXISTS modreq(\n"
32 " objid INTEGER PRIMARY KEY,\n" /* Record pending approval */
33 " attachRid INT,\n" /* Object attached */
34 " tktid TEXT\n" /* Associated ticket id */
35 ");\n"
36 );
37 }
38
@@ -61,18 +61,40 @@
61 db_reset(&q);
62 return rc;
63 }
64
65 /*
66 ** Check to see if the object identified by RID is used for anything.
67 */
68 static int object_used(int rid){
69 static const char *aTabField[] = {
70 "modreq", "attachRid",
71 "mlink", "mid",
72 "mlink", "fid",
73 "tagxref", "srcid",
74 "tagxref", "rid",
75 };
76 int i;
77 for(i=0; i<sizeof(aTabField)/sizeof(aTabField[0]); i+=2){
78 if( db_exists("SELECT 1 FROM %s WHERE %s=%d",
79 aTabField[i], aTabField[i+1], rid) ) return 1;
80 }
81 return 0;
82 }
83
84 /*
85 ** Delete a moderation item given by objid
86 */
87 void moderation_disapprove(int objid){
88 Stmt q;
89 char *zTktid;
90 int attachRid = 0;
91 int rid;
92 if( !moderation_pending(objid) ) return;
93 db_begin_transaction();
94 rid = objid;
95 while( rid && content_is_private(rid) ){
96 db_prepare(&q, "SELECT rid FROM delta WHERE srcid=%d", rid);
97 while( db_step(&q)==SQLITE_ROW ){
98 int ridUser = db_column_int(&q, 0);
99 content_undelta(ridUser);
100 }
@@ -80,54 +102,41 @@
102 db_multi_exec(
103 "DELETE FROM blob WHERE rid=%d;"
104 "DELETE FROM delta WHERE rid=%d;"
105 "DELETE FROM event WHERE objid=%d;"
106 "DELETE FROM tagxref WHERE rid=%d;"
107 "DELETE FROM private WHERE rid=%d;"
108 "DELETE FROM attachment WHERE attachid=%d;",
109 rid, rid, rid, rid, rid, rid
110 );
111 zTktid = db_text(0, "SELECT tktid FROM modreq WHERE objid=%d", rid);
112 if( zTktid && zTktid[0] ){
113 ticket_rebuild_entry(zTktid);
114 fossil_free(zTktid);
115 }
116 attachRid = db_int(0, "SELECT attachRid FROM modreq WHERE objid=%d", rid);
117 if( rid==objid ){
118 db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
119 }
120 if( attachRid && object_used(attachRid) ) attachRid = 0;
121 rid = attachRid;
122 }
 
 
 
 
123 db_end_transaction(0);
124 }
125
126 /*
127 ** Approve an object held for moderation.
128 */
129 void moderation_approve(int rid){
 
130 if( !moderation_pending(rid) ) return;
131 db_begin_transaction();
132 db_multi_exec(
133 "DELETE FROM private WHERE rid=%d;"
134 "INSERT OR IGNORE INTO unclustered VALUES(%d);"
135 "INSERT OR IGNORE INTO unsent VALUES(%d);",
136 rid, rid, rid
137 );
 
 
 
 
 
 
 
 
 
138 db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
139 db_end_transaction(0);
140 }
141
142 /*
143
+1 -1
--- src/timeline.c
+++ src/timeline.c
@@ -325,11 +325,11 @@
325325
}
326326
if( pGraph && zType[0]!='c' ){
327327
@ &bull;
328328
}
329329
if( modPending ){
330
- @ <span class="modpending">(Pending Moderation)</span>
330
+ @ <span class="modpending">(Awaiting Moderator Approval)</span>
331331
}
332332
if( zType[0]=='c' ){
333333
hyperlink_to_uuid(zUuid);
334334
if( isLeaf ){
335335
if( db_exists("SELECT 1 FROM tagxref"
336336
--- src/timeline.c
+++ src/timeline.c
@@ -325,11 +325,11 @@
325 }
326 if( pGraph && zType[0]!='c' ){
327 @ &bull;
328 }
329 if( modPending ){
330 @ <span class="modpending">(Pending Moderation)</span>
331 }
332 if( zType[0]=='c' ){
333 hyperlink_to_uuid(zUuid);
334 if( isLeaf ){
335 if( db_exists("SELECT 1 FROM tagxref"
336
--- src/timeline.c
+++ src/timeline.c
@@ -325,11 +325,11 @@
325 }
326 if( pGraph && zType[0]!='c' ){
327 @ &bull;
328 }
329 if( modPending ){
330 @ <span class="modpending">(Awaiting Moderator Approval)</span>
331 }
332 if( zType[0]=='c' ){
333 hyperlink_to_uuid(zUuid);
334 if( isLeaf ){
335 if( db_exists("SELECT 1 FROM tagxref"
336

Keyboard Shortcuts

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