Fossil SCM

More infrastructure for wiki and ticket moderation.

drh 2012-11-01 13:11 UTC moderation
Commit f7938ebd00ee6d47fa7684c44de4be68dc778a58
+9 -6
--- src/info.c
+++ src/info.c
@@ -1630,11 +1630,11 @@
16301630
*/
16311631
void tinfo_page(void){
16321632
int rid;
16331633
char *zDate;
16341634
const char *zUuid;
1635
- char zTktName[20];
1635
+ char zTktName[UUID_SIZE+1];
16361636
Manifest *pTktChng;
16371637
16381638
login_check_credentials();
16391639
if( !g.perm.RdTkt ){ login_needed(); return; }
16401640
rid = name_to_rid_www("name");
@@ -1653,15 +1653,15 @@
16531653
if( pTktChng==0 ){
16541654
fossil_redirect_home();
16551655
}
16561656
style_header("Ticket Change Details");
16571657
zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
1658
- memcpy(zTktName, pTktChng->zTicketUuid, 10);
1659
- zTktName[10] = 0;
1658
+ memcpy(zTktName, pTktChng->zTicketUuid, UUID_SIZE);
1659
+ zTktName[UUID_SIZE] = 0;
16601660
if( g.perm.Hyperlink ){
16611661
@ <h2>Changes to ticket
1662
- @ %z(href("%R/tktview/%s",pTktChng->zTicketUuid))%s(zTktName)</a></h2>
1662
+ @ %z(href("%R/tktview/%s",zTktName))%s(zTktName)</a></h2>
16631663
@
16641664
@ <p>By %h(pTktChng->zUser) on %s(zDate).
16651665
style_submenu_element("Raw", "Raw", "%R/artifact/%T", zUuid);
16661666
style_submenu_element("History", "History",
16671667
"%R/tkthistory/%s", pTktChng->zTicketUuid);
@@ -1669,15 +1669,18 @@
16691669
@ <h2>Changes to ticket %s(zTktName)</h2>
16701670
@
16711671
@ <p>By %h(pTktChng->zUser) on %s(zDate).
16721672
@ </p>
16731673
}
1674
- @
1675
- @ <ol>
16761674
free(zDate);
16771675
ticket_output_change_artifact(pTktChng);
16781676
manifest_destroy(pTktChng);
1677
+ if( g.perm.Setup ){
1678
+ @
1679
+ @ <p>These changes are implemented by artifact
1680
+ @ %z(href("%R/artifact/%s",zUuid))%s(zUuid)</a> (%d(rid)).</p>
1681
+ }
16791682
style_footer();
16801683
}
16811684
16821685
16831686
/*
16841687
--- src/info.c
+++ src/info.c
@@ -1630,11 +1630,11 @@
1630 */
1631 void tinfo_page(void){
1632 int rid;
1633 char *zDate;
1634 const char *zUuid;
1635 char zTktName[20];
1636 Manifest *pTktChng;
1637
1638 login_check_credentials();
1639 if( !g.perm.RdTkt ){ login_needed(); return; }
1640 rid = name_to_rid_www("name");
@@ -1653,15 +1653,15 @@
1653 if( pTktChng==0 ){
1654 fossil_redirect_home();
1655 }
1656 style_header("Ticket Change Details");
1657 zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
1658 memcpy(zTktName, pTktChng->zTicketUuid, 10);
1659 zTktName[10] = 0;
1660 if( g.perm.Hyperlink ){
1661 @ <h2>Changes to ticket
1662 @ %z(href("%R/tktview/%s",pTktChng->zTicketUuid))%s(zTktName)</a></h2>
1663 @
1664 @ <p>By %h(pTktChng->zUser) on %s(zDate).
1665 style_submenu_element("Raw", "Raw", "%R/artifact/%T", zUuid);
1666 style_submenu_element("History", "History",
1667 "%R/tkthistory/%s", pTktChng->zTicketUuid);
@@ -1669,15 +1669,18 @@
1669 @ <h2>Changes to ticket %s(zTktName)</h2>
1670 @
1671 @ <p>By %h(pTktChng->zUser) on %s(zDate).
1672 @ </p>
1673 }
1674 @
1675 @ <ol>
1676 free(zDate);
1677 ticket_output_change_artifact(pTktChng);
1678 manifest_destroy(pTktChng);
 
 
 
 
 
1679 style_footer();
1680 }
1681
1682
1683 /*
1684
--- src/info.c
+++ src/info.c
@@ -1630,11 +1630,11 @@
1630 */
1631 void tinfo_page(void){
1632 int rid;
1633 char *zDate;
1634 const char *zUuid;
1635 char zTktName[UUID_SIZE+1];
1636 Manifest *pTktChng;
1637
1638 login_check_credentials();
1639 if( !g.perm.RdTkt ){ login_needed(); return; }
1640 rid = name_to_rid_www("name");
@@ -1653,15 +1653,15 @@
1653 if( pTktChng==0 ){
1654 fossil_redirect_home();
1655 }
1656 style_header("Ticket Change Details");
1657 zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
1658 memcpy(zTktName, pTktChng->zTicketUuid, UUID_SIZE);
1659 zTktName[UUID_SIZE] = 0;
1660 if( g.perm.Hyperlink ){
1661 @ <h2>Changes to ticket
1662 @ %z(href("%R/tktview/%s",zTktName))%s(zTktName)</a></h2>
1663 @
1664 @ <p>By %h(pTktChng->zUser) on %s(zDate).
1665 style_submenu_element("Raw", "Raw", "%R/artifact/%T", zUuid);
1666 style_submenu_element("History", "History",
1667 "%R/tkthistory/%s", pTktChng->zTicketUuid);
@@ -1669,15 +1669,18 @@
1669 @ <h2>Changes to ticket %s(zTktName)</h2>
1670 @
1671 @ <p>By %h(pTktChng->zUser) on %s(zDate).
1672 @ </p>
1673 }
 
 
1674 free(zDate);
1675 ticket_output_change_artifact(pTktChng);
1676 manifest_destroy(pTktChng);
1677 if( g.perm.Setup ){
1678 @
1679 @ <p>These changes are implemented by artifact
1680 @ %z(href("%R/artifact/%s",zUuid))%s(zUuid)</a> (%d(rid)).</p>
1681 }
1682 style_footer();
1683 }
1684
1685
1686 /*
1687
+113 -11
--- src/moderate.c
+++ src/moderate.c
@@ -20,24 +20,126 @@
2020
*/
2121
#include "config.h"
2222
#include "moderate.h"
2323
#include <assert.h>
2424
25
-
2625
/*
2726
** Create a table to represent pending moderation requests, if the
2827
** table does not already exist.
2928
*/
3029
void moderation_table_create(void){
3130
db_multi_exec(
32
- "CREATE TABLE IF NOT EXISTS modreq("
33
- " mreqid INTEGER PRIMARY KEY," /* Unique ID for the request */
34
- " objid INT UNIQUE," /* Record pending approval */
35
- " ctime DATETIME," /* Julian day number */
36
- " user TEXT," /* Name of user submitter */
37
- " ipaddr TEXT," /* IP address of submitter */
38
- " mtype TEXT," /* 't', 'w', 'at', or 'aw' */
39
- " afile INT," /* File being attached, or NULL */
40
- " aid ANY" /* TicketId or Wiki Name */
41
- ");"
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
+
39
+/*
40
+** Return TRUE if the modreq table exists
41
+*/
42
+int moderation_table_exists(void){
43
+ static int modreqExists = -1;
44
+ if( modreqExists<0 ){
45
+ modreqExists = db_exists("SELECT 1 FROM %s.sqlite_master"
46
+ " WHERE name='modreq'", db_name("repository"));
47
+ }
48
+ return modreqExists;
49
+}
50
+
51
+/*
52
+** Return TRUE if the object specified is being held for moderation.
53
+*/
54
+int moderation_pending(int rid){
55
+ static Stmt q;
56
+ int rc;
57
+ if( rid==0 || !moderation_table_exists() ) return 0;
58
+ db_static_prepare(&q, "SELECT 1 FROM modreq WHERE objid=:objid");
59
+ db_bind_int(&q, ":objid", rid);
60
+ rc = db_step(&q)==SQLITE_ROW;
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
+ if( content_is_private(rid) ){
73
+ db_prepare(&q, "SELECT rid FROM delta WHERE srcid=%d", rid);
74
+ while( db_step(&q)==SQLITE_ROW ){
75
+ int ridUser = db_column_int(&q, 0);
76
+ content_undelta(ridUser);
77
+ }
78
+ db_finalize(&q);
79
+ db_multi_exec(
80
+ "DELETE FROM blob WHERE rid=%d;"
81
+ "DELETE FROM delta WHERE rid=%d;"
82
+ "DELETE FROM event WHERE objid=%d;"
83
+ "DELETE FROM tagxref WHERE rid=%d;"
84
+ "DELETE FROM private WHERE rid=%d;",
85
+ rid, rid, rid, rid, rid
86
+ );
87
+ zTktid = db_text(0, "SELECT tktid FROm modreq WHERE objid=%d", rid);
88
+ if( zTktid ){
89
+ ticket_rebuild_entry(zTktid);
90
+ fossil_free(zTktid);
91
+ }
92
+ }
93
+ db_prepare(&q, "SELECT objid FROM modreq WHERE parent=%d AND "
94
+ "UNION SELECT parent FROM modreq WHERE objid=%d",
95
+ rid, rid);
96
+ while( db_step(&q)==SQLITE_ROW ){
97
+ int other = db_column_int(&q, 0);
98
+ if( other==rid ) continue;
99
+ moderation_approve(other);
100
+ }
101
+ db_finalize(&q);
102
+ db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
103
+}
104
+
105
+/*
106
+** Approve an object held for moderation.
107
+*/
108
+void moderation_approve(int rid){
109
+ Stmt q;
110
+ if( !moderation_pending(rid) ) return;
111
+ db_multi_exec("DELETE FROM private WHERE rid=%d;", rid);
112
+ db_prepare(&q, "SELECT objid FROM modreq WHERE parent=%d AND "
113
+ "UNION SELECT parent FROM modreq WHERE objid=%d",
114
+ rid, rid);
115
+ while( db_step(&q)==SQLITE_ROW ){
116
+ int other = db_column_int(&q, 0);
117
+ if( other==rid ) continue;
118
+ moderation_approve(other);
119
+ }
120
+ db_finalize(&q);
121
+ db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
122
+}
123
+
124
+/*
125
+** WEBPAGE: modreq
126
+**
127
+** Show all pending moderation request
128
+*/
129
+void modreq_page(void){
130
+ Blob sql;
131
+ Stmt q;
132
+
133
+ login_check_credentials();
134
+ if( !g.perm.RdWiki && !g.perm.RdTkt ){ login_needed(); return; }
135
+ style_header("Pending Moderation Requests");
136
+ blob_init(&sql, timeline_query_for_www(), -1);
137
+ blob_appendf(&sql,
138
+ " AND event.objid IN (SELECT objid FROM modreq)"
139
+ " ORDER BY event.mtime DESC"
42140
);
141
+ db_prepare(&q, blob_str(&sql));
142
+ www_print_timeline(&q, 0, 0, 0, 0);
143
+ db_finalize(&q);
144
+ style_footer();
43145
}
44146
--- src/moderate.c
+++ src/moderate.c
@@ -20,24 +20,126 @@
20 */
21 #include "config.h"
22 #include "moderate.h"
23 #include <assert.h>
24
25
26 /*
27 ** Create a table to represent pending moderation requests, if the
28 ** table does not already exist.
29 */
30 void moderation_table_create(void){
31 db_multi_exec(
32 "CREATE TABLE IF NOT EXISTS modreq("
33 " mreqid INTEGER PRIMARY KEY," /* Unique ID for the request */
34 " objid INT UNIQUE," /* Record pending approval */
35 " ctime DATETIME," /* Julian day number */
36 " user TEXT," /* Name of user submitter */
37 " ipaddr TEXT," /* IP address of submitter */
38 " mtype TEXT," /* 't', 'w', 'at', or 'aw' */
39 " afile INT," /* File being attached, or NULL */
40 " aid ANY" /* TicketId or Wiki Name */
41 ");"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42 );
 
 
 
 
43 }
44
--- src/moderate.c
+++ src/moderate.c
@@ -20,24 +20,126 @@
20 */
21 #include "config.h"
22 #include "moderate.h"
23 #include <assert.h>
24
 
25 /*
26 ** Create a table to represent pending moderation requests, if the
27 ** table does not already exist.
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
39 /*
40 ** Return TRUE if the modreq table exists
41 */
42 int moderation_table_exists(void){
43 static int modreqExists = -1;
44 if( modreqExists<0 ){
45 modreqExists = db_exists("SELECT 1 FROM %s.sqlite_master"
46 " WHERE name='modreq'", db_name("repository"));
47 }
48 return modreqExists;
49 }
50
51 /*
52 ** Return TRUE if the object specified is being held for moderation.
53 */
54 int moderation_pending(int rid){
55 static Stmt q;
56 int rc;
57 if( rid==0 || !moderation_table_exists() ) return 0;
58 db_static_prepare(&q, "SELECT 1 FROM modreq WHERE objid=:objid");
59 db_bind_int(&q, ":objid", rid);
60 rc = db_step(&q)==SQLITE_ROW;
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 if( content_is_private(rid) ){
73 db_prepare(&q, "SELECT rid FROM delta WHERE srcid=%d", rid);
74 while( db_step(&q)==SQLITE_ROW ){
75 int ridUser = db_column_int(&q, 0);
76 content_undelta(ridUser);
77 }
78 db_finalize(&q);
79 db_multi_exec(
80 "DELETE FROM blob WHERE rid=%d;"
81 "DELETE FROM delta WHERE rid=%d;"
82 "DELETE FROM event WHERE objid=%d;"
83 "DELETE FROM tagxref WHERE rid=%d;"
84 "DELETE FROM private WHERE rid=%d;",
85 rid, rid, rid, rid, rid
86 );
87 zTktid = db_text(0, "SELECT tktid FROm modreq WHERE objid=%d", rid);
88 if( zTktid ){
89 ticket_rebuild_entry(zTktid);
90 fossil_free(zTktid);
91 }
92 }
93 db_prepare(&q, "SELECT objid FROM modreq WHERE parent=%d AND "
94 "UNION SELECT parent FROM modreq WHERE objid=%d",
95 rid, rid);
96 while( db_step(&q)==SQLITE_ROW ){
97 int other = db_column_int(&q, 0);
98 if( other==rid ) continue;
99 moderation_approve(other);
100 }
101 db_finalize(&q);
102 db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
103 }
104
105 /*
106 ** Approve an object held for moderation.
107 */
108 void moderation_approve(int rid){
109 Stmt q;
110 if( !moderation_pending(rid) ) return;
111 db_multi_exec("DELETE FROM private WHERE rid=%d;", rid);
112 db_prepare(&q, "SELECT objid FROM modreq WHERE parent=%d AND "
113 "UNION SELECT parent FROM modreq WHERE objid=%d",
114 rid, rid);
115 while( db_step(&q)==SQLITE_ROW ){
116 int other = db_column_int(&q, 0);
117 if( other==rid ) continue;
118 moderation_approve(other);
119 }
120 db_finalize(&q);
121 db_multi_exec("DELETE FROM modreq WHERE objid=%d", rid);
122 }
123
124 /*
125 ** WEBPAGE: modreq
126 **
127 ** Show all pending moderation request
128 */
129 void modreq_page(void){
130 Blob sql;
131 Stmt q;
132
133 login_check_credentials();
134 if( !g.perm.RdWiki && !g.perm.RdTkt ){ login_needed(); return; }
135 style_header("Pending Moderation Requests");
136 blob_init(&sql, timeline_query_for_www(), -1);
137 blob_appendf(&sql,
138 " AND event.objid IN (SELECT objid FROM modreq)"
139 " ORDER BY event.mtime DESC"
140 );
141 db_prepare(&q, blob_str(&sql));
142 www_print_timeline(&q, 0, 0, 0, 0);
143 db_finalize(&q);
144 style_footer();
145 }
146
+6 -1
--- src/style.c
+++ src/style.c
@@ -930,13 +930,18 @@
930930
{ "span.diffhr",
931931
"suppressed lines in a diff",
932932
@ color: #0000ff;
933933
},
934934
{ "span.diffln",
935
- "line nubmers in a diff",
935
+ "line numbers in a diff",
936936
@ color: #a0a0a0;
937937
},
938
+ { "span.modpending",
939
+ "Moderation Pending message on timelin",
940
+ @ color: #b03800;
941
+ @ font-style: italic;
942
+ },
938943
{ 0,
939944
0,
940945
0
941946
}
942947
};
943948
--- src/style.c
+++ src/style.c
@@ -930,13 +930,18 @@
930 { "span.diffhr",
931 "suppressed lines in a diff",
932 @ color: #0000ff;
933 },
934 { "span.diffln",
935 "line nubmers in a diff",
936 @ color: #a0a0a0;
937 },
 
 
 
 
 
938 { 0,
939 0,
940 0
941 }
942 };
943
--- src/style.c
+++ src/style.c
@@ -930,13 +930,18 @@
930 { "span.diffhr",
931 "suppressed lines in a diff",
932 @ color: #0000ff;
933 },
934 { "span.diffln",
935 "line numbers in a diff",
936 @ color: #a0a0a0;
937 },
938 { "span.modpending",
939 "Moderation Pending message on timelin",
940 @ color: #b03800;
941 @ font-style: italic;
942 },
943 { 0,
944 0,
945 0
946 }
947 };
948
+9 -2
--- src/timeline.c
+++ src/timeline.c
@@ -236,12 +236,16 @@
236236
const char *zUser = db_column_text(pQuery, 4);
237237
const char *zTagList = db_column_text(pQuery, 8);
238238
int tagid = db_column_int(pQuery, 9);
239239
const char *zBr = 0; /* Branch */
240240
int commentColumn = 3; /* Column containing comment text */
241
+ int modPending; /* Pending moderation */
241242
char zTime[8];
243
+
244
+ modPending = moderation_pending(rid);
242245
if( tagid ){
246
+ if( modPending ) tagid = -tagid;
243247
if( tagid==prevTagid ){
244248
if( tmFlags & TIMELINE_BRIEF ){
245249
suppressCnt++;
246250
continue;
247251
}else{
@@ -320,10 +324,13 @@
320324
@ <td class="timelineTableCell">
321325
}
322326
if( pGraph && zType[0]!='c' ){
323327
@ &bull;
324328
}
329
+ if( modPending ){
330
+ @ <span class="modpending">(Pending Moderation)</span>
331
+ }
325332
if( zType[0]=='c' ){
326333
hyperlink_to_uuid(zUuid);
327334
if( isLeaf ){
328335
if( db_exists("SELECT 1 FROM tagxref"
329336
" WHERE rid=%d AND tagid=%d AND tagtype>0",
@@ -332,11 +339,11 @@
332339
}else{
333340
@ <span class="timelineLeaf">Leaf:</span>
334341
}
335342
}
336343
}else if( zType[0]=='e' && tagid ){
337
- hyperlink_to_event_tagid(tagid);
344
+ hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
338345
}else if( (tmFlags & TIMELINE_ARTID)!=0 ){
339346
hyperlink_to_uuid(zUuid);
340347
}
341348
db_column_blob(pQuery, commentColumn, &comment);
342349
if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){
@@ -361,11 +368,11 @@
361368
}else{
362369
@ (user: %h(zUser)%s(zTagList?",":"\051")
363370
}
364371
365372
/* Generate a "detail" link for tags. */
366
- if( zType[0]=='g' && g.perm.Hyperlink ){
373
+ if( (zType[0]=='g' || zType[0]=='w' || zType[0]=='t') && g.perm.Hyperlink ){
367374
@ [%z(href("%R/info/%S",zUuid))details</a>]
368375
}
369376
370377
/* Generate the "tags: TAGLIST" at the end of the comment, together
371378
** with hyperlinks to the tag list.
372379
--- src/timeline.c
+++ src/timeline.c
@@ -236,12 +236,16 @@
236 const char *zUser = db_column_text(pQuery, 4);
237 const char *zTagList = db_column_text(pQuery, 8);
238 int tagid = db_column_int(pQuery, 9);
239 const char *zBr = 0; /* Branch */
240 int commentColumn = 3; /* Column containing comment text */
 
241 char zTime[8];
 
 
242 if( tagid ){
 
243 if( tagid==prevTagid ){
244 if( tmFlags & TIMELINE_BRIEF ){
245 suppressCnt++;
246 continue;
247 }else{
@@ -320,10 +324,13 @@
320 @ <td class="timelineTableCell">
321 }
322 if( pGraph && zType[0]!='c' ){
323 @ &bull;
324 }
 
 
 
325 if( zType[0]=='c' ){
326 hyperlink_to_uuid(zUuid);
327 if( isLeaf ){
328 if( db_exists("SELECT 1 FROM tagxref"
329 " WHERE rid=%d AND tagid=%d AND tagtype>0",
@@ -332,11 +339,11 @@
332 }else{
333 @ <span class="timelineLeaf">Leaf:</span>
334 }
335 }
336 }else if( zType[0]=='e' && tagid ){
337 hyperlink_to_event_tagid(tagid);
338 }else if( (tmFlags & TIMELINE_ARTID)!=0 ){
339 hyperlink_to_uuid(zUuid);
340 }
341 db_column_blob(pQuery, commentColumn, &comment);
342 if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){
@@ -361,11 +368,11 @@
361 }else{
362 @ (user: %h(zUser)%s(zTagList?",":"\051")
363 }
364
365 /* Generate a "detail" link for tags. */
366 if( zType[0]=='g' && g.perm.Hyperlink ){
367 @ [%z(href("%R/info/%S",zUuid))details</a>]
368 }
369
370 /* Generate the "tags: TAGLIST" at the end of the comment, together
371 ** with hyperlinks to the tag list.
372
--- src/timeline.c
+++ src/timeline.c
@@ -236,12 +236,16 @@
236 const char *zUser = db_column_text(pQuery, 4);
237 const char *zTagList = db_column_text(pQuery, 8);
238 int tagid = db_column_int(pQuery, 9);
239 const char *zBr = 0; /* Branch */
240 int commentColumn = 3; /* Column containing comment text */
241 int modPending; /* Pending moderation */
242 char zTime[8];
243
244 modPending = moderation_pending(rid);
245 if( tagid ){
246 if( modPending ) tagid = -tagid;
247 if( tagid==prevTagid ){
248 if( tmFlags & TIMELINE_BRIEF ){
249 suppressCnt++;
250 continue;
251 }else{
@@ -320,10 +324,13 @@
324 @ <td class="timelineTableCell">
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 " WHERE rid=%d AND tagid=%d AND tagtype>0",
@@ -332,11 +339,11 @@
339 }else{
340 @ <span class="timelineLeaf">Leaf:</span>
341 }
342 }
343 }else if( zType[0]=='e' && tagid ){
344 hyperlink_to_event_tagid(tagid<0?-tagid:tagid);
345 }else if( (tmFlags & TIMELINE_ARTID)!=0 ){
346 hyperlink_to_uuid(zUuid);
347 }
348 db_column_blob(pQuery, commentColumn, &comment);
349 if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){
@@ -361,11 +368,11 @@
368 }else{
369 @ (user: %h(zUser)%s(zTagList?",":"\051")
370 }
371
372 /* Generate a "detail" link for tags. */
373 if( (zType[0]=='g' || zType[0]=='w' || zType[0]=='t') && g.perm.Hyperlink ){
374 @ [%z(href("%R/info/%S",zUuid))details</a>]
375 }
376
377 /* Generate the "tags: TAGLIST" at the end of the comment, together
378 ** with hyperlinks to the tag list.
379

Keyboard Shortcuts

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