Fossil SCM

An attempt to begin scanning wiki for backlinks. It does not currently work. I suspect a problem in the markdown link scanner.

drh 2020-04-16 20:06 backlink-updates
Commit f0b0293ba77c2d8be943c3c684929cc19f84a444959140c04ae9c5472d875c45
+61 -10
--- src/backlink.c
+++ src/backlink.c
@@ -36,14 +36,18 @@
3636
Blob sql;
3737
Stmt q;
3838
char *zGlob;
3939
zGlob = mprintf("%.5s*", zUuid);
4040
db_multi_exec(
41
- "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
42
- "DELETE FROM ok;"
43
- "INSERT OR IGNORE INTO ok"
44
- " SELECT srcid FROM backlink"
41
+ "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);\n"
42
+ "DELETE FROM ok;\n"
43
+ "INSERT OR IGNORE INTO ok(rid)\n"
44
+ " SELECT CASE srctype\n"
45
+ " WHEN 2 THEN (SELECT rid FROM tagxref WHERE tagid=backlink.srcid\n"
46
+ " ORDER BY mtime DESC LIMIT 1)\n"
47
+ " ELSE srcid END\n"
48
+ " FROM backlink\n"
4549
" WHERE target GLOB %Q"
4650
" AND %Q GLOB (target || '*');",
4751
zGlob, zUuid
4852
);
4953
if( !db_exists("SELECT 1 FROM ok") ) return;
@@ -106,11 +110,15 @@
106110
}
107111
style_header("Backlink Table (Internal Testing Use)");
108112
n = db_int(0, "SELECT count(*) FROM backlink");
109113
@ <p>%d(n) backlink table entries:</p>
110114
db_prepare(&q,
111
- "SELECT target, srctype, srcid, datetime(mtime) FROM backlink"
115
+ "SELECT target, srctype, srcid, datetime(mtime),"
116
+ " CASE srctype"
117
+ " WHEN 2 THEN (SELECT substr(tagname,6) FROM tag"
118
+ " WHERE tagid=srcid AND tagname GLOB 'wiki-*')"
119
+ " ELSE null END FROM backlink"
112120
);
113121
style_table_sorter();
114122
@ <table border="1" cellpadding="2" cellspacing="0" \
115123
@ class='sortable' data-column-types='ttt' data-init-sort='0'>
116124
@ <thead><tr><th> Source <th> Target <th> mtime </tr></thead>
@@ -118,11 +126,10 @@
118126
while( db_step(&q)==SQLITE_ROW ){
119127
const char *zTarget = db_column_text(&q, 0);
120128
int srctype = db_column_int(&q, 1);
121129
int srcid = db_column_int(&q, 2);
122130
const char *zMtime = db_column_text(&q, 3);
123
- static const char *azSrcType[] = { "comment", "ticket", "wiki", "unknown" };
124131
@ <tr><td><a href="%R/info/%h(zTarget)">%h(zTarget)</a>
125132
switch( srctype ){
126133
case BKLNK_COMMENT: {
127134
@ <td><a href="%R/info?name=rid:%d(srcid)">comment-%d(srcid)</a>
128135
break;
@@ -130,11 +137,12 @@
130137
case BKLNK_TICKET: {
131138
@ <td><a href="%R/info?name=rid:%d(srcid)">ticket-%d(srcid)</a>
132139
break;
133140
}
134141
case BKLNK_WIKI: {
135
- @ <td><a href="%R/info?name=rid:%d(srcid)">wiki-%d(srcid)</a>
142
+ const char *zName = db_column_text(&q, 4);
143
+ @ <td><a href="%R/wiki?name=%h(zName)&p">wiki-%d(srcid)</a>
136144
break;
137145
}
138146
default: {
139147
@ <td>unknown(%d(srctype)) - %d(srcid)
140148
break;
@@ -146,11 +154,28 @@
146154
@ </table>
147155
db_finalize(&q);
148156
style_footer();
149157
}
150158
151
-
159
+/*
160
+** Remove all prior backlinks for the wiki page given. Then
161
+** add new backlinks for the latest version of the wiki page.
162
+*/
163
+void backlink_wiki_refresh(const char *zWikiTitle){
164
+ int tagid = wiki_tagid(zWikiTitle);
165
+ int rid;
166
+ Manifest *pWiki;
167
+ if( tagid==0 ) return;
168
+ rid = db_int(0, "SELECT rid FROM tagxref WHERE tagid=%d"
169
+ " ORDER BY mtime DESC LIMIT 1", tagid);
170
+ if( rid==0 ) return;
171
+ pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
172
+ if( pWiki ){
173
+ backlink_extract(pWiki->zWiki, pWiki->zMimetype, tagid, 2, pWiki->rDate,1);
174
+ manifest_destroy(pWiki);
175
+ }
176
+}
152177
153178
/*
154179
** Structure used to pass down state information through the
155180
** markup formatters into the BACKLINK generator.
156181
*/
@@ -266,11 +291,11 @@
266291
if( replaceFlag ){
267292
db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid=%d",
268293
srctype, srcid);
269294
}
270295
bklnk.srcid = srcid;
271
- assert( srctype>=BKLNK_COMMENT && srctype<=BKLNK_WIKI );
296
+ assert( ValidBklnk(srctype) );
272297
bklnk.srctype = srctype;
273298
bklnk.mtime = mtime;
274299
if( zMimetype==0 || strstr(zMimetype,"wiki")!=0 ){
275300
wiki_extract_links(zSrc, &bklnk, srctype==BKLNK_COMMENT ? WIKI_INLINE : 0);
276301
}else if( strstr(zMimetype,"markdown")!=0 ){
@@ -279,11 +304,11 @@
279304
}
280305
281306
/*
282307
** COMMAND: test-backlinks
283308
**
284
-** Usage: %fossil test-backlinks SRCID SRCTYPE ?OPTIONS? INPUT-FILE
309
+** Usage: %fossil test-backlinks SRCTYPE SRCID ?OPTIONS? INPUT-FILE
285310
**
286311
** Read the content of INPUT-FILE and pass it into the backlink_extract()
287312
** routine. But instead of adding backlinks to the backlink table,
288313
** just print them on stdout. SRCID and SRCTYPE are integers.
289314
**
@@ -327,5 +352,31 @@
327352
"END;"
328353
);
329354
backlink_extract(blob_str(&in),zMimetype,srcid,srctype,mtime,0);
330355
blob_reset(&in);
331356
}
357
+
358
+
359
+/*
360
+** COMMAND: test-wiki-relink
361
+**
362
+** Usage: %fossil test-wiki-relink WIKI-PAGE-NAME
363
+**
364
+** Run the backlink_wiki_refresh() procedure on the wiki page
365
+** named. WIKI-PAGE-NAME can be a glob pattern or a prefix
366
+** of the wiki page.
367
+*/
368
+void test_wiki_relink_cmd(void){
369
+ Stmt q;
370
+ db_find_and_open_repository(0, 0);
371
+ if( g.argc!=3 ) usage("WIKI-PAGE-NAME");
372
+ db_prepare(&q,
373
+ "SELECT substr(tagname,6) FROM tag WHERE tagname GLOB 'wiki-%q*'",
374
+ g.argv[2]
375
+ );
376
+ while( db_step(&q)==SQLITE_ROW ){
377
+ const char *zPage = db_column_text(&q,0);
378
+ fossil_print("Relinking page: %s\n", zPage);
379
+ backlink_wiki_refresh(zPage);
380
+ }
381
+ db_finalize(&q);
382
+}
332383
--- src/backlink.c
+++ src/backlink.c
@@ -36,14 +36,18 @@
36 Blob sql;
37 Stmt q;
38 char *zGlob;
39 zGlob = mprintf("%.5s*", zUuid);
40 db_multi_exec(
41 "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
42 "DELETE FROM ok;"
43 "INSERT OR IGNORE INTO ok"
44 " SELECT srcid FROM backlink"
 
 
 
 
45 " WHERE target GLOB %Q"
46 " AND %Q GLOB (target || '*');",
47 zGlob, zUuid
48 );
49 if( !db_exists("SELECT 1 FROM ok") ) return;
@@ -106,11 +110,15 @@
106 }
107 style_header("Backlink Table (Internal Testing Use)");
108 n = db_int(0, "SELECT count(*) FROM backlink");
109 @ <p>%d(n) backlink table entries:</p>
110 db_prepare(&q,
111 "SELECT target, srctype, srcid, datetime(mtime) FROM backlink"
 
 
 
 
112 );
113 style_table_sorter();
114 @ <table border="1" cellpadding="2" cellspacing="0" \
115 @ class='sortable' data-column-types='ttt' data-init-sort='0'>
116 @ <thead><tr><th> Source <th> Target <th> mtime </tr></thead>
@@ -118,11 +126,10 @@
118 while( db_step(&q)==SQLITE_ROW ){
119 const char *zTarget = db_column_text(&q, 0);
120 int srctype = db_column_int(&q, 1);
121 int srcid = db_column_int(&q, 2);
122 const char *zMtime = db_column_text(&q, 3);
123 static const char *azSrcType[] = { "comment", "ticket", "wiki", "unknown" };
124 @ <tr><td><a href="%R/info/%h(zTarget)">%h(zTarget)</a>
125 switch( srctype ){
126 case BKLNK_COMMENT: {
127 @ <td><a href="%R/info?name=rid:%d(srcid)">comment-%d(srcid)</a>
128 break;
@@ -130,11 +137,12 @@
130 case BKLNK_TICKET: {
131 @ <td><a href="%R/info?name=rid:%d(srcid)">ticket-%d(srcid)</a>
132 break;
133 }
134 case BKLNK_WIKI: {
135 @ <td><a href="%R/info?name=rid:%d(srcid)">wiki-%d(srcid)</a>
 
136 break;
137 }
138 default: {
139 @ <td>unknown(%d(srctype)) - %d(srcid)
140 break;
@@ -146,11 +154,28 @@
146 @ </table>
147 db_finalize(&q);
148 style_footer();
149 }
150
151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
153 /*
154 ** Structure used to pass down state information through the
155 ** markup formatters into the BACKLINK generator.
156 */
@@ -266,11 +291,11 @@
266 if( replaceFlag ){
267 db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid=%d",
268 srctype, srcid);
269 }
270 bklnk.srcid = srcid;
271 assert( srctype>=BKLNK_COMMENT && srctype<=BKLNK_WIKI );
272 bklnk.srctype = srctype;
273 bklnk.mtime = mtime;
274 if( zMimetype==0 || strstr(zMimetype,"wiki")!=0 ){
275 wiki_extract_links(zSrc, &bklnk, srctype==BKLNK_COMMENT ? WIKI_INLINE : 0);
276 }else if( strstr(zMimetype,"markdown")!=0 ){
@@ -279,11 +304,11 @@
279 }
280
281 /*
282 ** COMMAND: test-backlinks
283 **
284 ** Usage: %fossil test-backlinks SRCID SRCTYPE ?OPTIONS? INPUT-FILE
285 **
286 ** Read the content of INPUT-FILE and pass it into the backlink_extract()
287 ** routine. But instead of adding backlinks to the backlink table,
288 ** just print them on stdout. SRCID and SRCTYPE are integers.
289 **
@@ -327,5 +352,31 @@
327 "END;"
328 );
329 backlink_extract(blob_str(&in),zMimetype,srcid,srctype,mtime,0);
330 blob_reset(&in);
331 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
332
--- src/backlink.c
+++ src/backlink.c
@@ -36,14 +36,18 @@
36 Blob sql;
37 Stmt q;
38 char *zGlob;
39 zGlob = mprintf("%.5s*", zUuid);
40 db_multi_exec(
41 "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);\n"
42 "DELETE FROM ok;\n"
43 "INSERT OR IGNORE INTO ok(rid)\n"
44 " SELECT CASE srctype\n"
45 " WHEN 2 THEN (SELECT rid FROM tagxref WHERE tagid=backlink.srcid\n"
46 " ORDER BY mtime DESC LIMIT 1)\n"
47 " ELSE srcid END\n"
48 " FROM backlink\n"
49 " WHERE target GLOB %Q"
50 " AND %Q GLOB (target || '*');",
51 zGlob, zUuid
52 );
53 if( !db_exists("SELECT 1 FROM ok") ) return;
@@ -106,11 +110,15 @@
110 }
111 style_header("Backlink Table (Internal Testing Use)");
112 n = db_int(0, "SELECT count(*) FROM backlink");
113 @ <p>%d(n) backlink table entries:</p>
114 db_prepare(&q,
115 "SELECT target, srctype, srcid, datetime(mtime),"
116 " CASE srctype"
117 " WHEN 2 THEN (SELECT substr(tagname,6) FROM tag"
118 " WHERE tagid=srcid AND tagname GLOB 'wiki-*')"
119 " ELSE null END FROM backlink"
120 );
121 style_table_sorter();
122 @ <table border="1" cellpadding="2" cellspacing="0" \
123 @ class='sortable' data-column-types='ttt' data-init-sort='0'>
124 @ <thead><tr><th> Source <th> Target <th> mtime </tr></thead>
@@ -118,11 +126,10 @@
126 while( db_step(&q)==SQLITE_ROW ){
127 const char *zTarget = db_column_text(&q, 0);
128 int srctype = db_column_int(&q, 1);
129 int srcid = db_column_int(&q, 2);
130 const char *zMtime = db_column_text(&q, 3);
 
131 @ <tr><td><a href="%R/info/%h(zTarget)">%h(zTarget)</a>
132 switch( srctype ){
133 case BKLNK_COMMENT: {
134 @ <td><a href="%R/info?name=rid:%d(srcid)">comment-%d(srcid)</a>
135 break;
@@ -130,11 +137,12 @@
137 case BKLNK_TICKET: {
138 @ <td><a href="%R/info?name=rid:%d(srcid)">ticket-%d(srcid)</a>
139 break;
140 }
141 case BKLNK_WIKI: {
142 const char *zName = db_column_text(&q, 4);
143 @ <td><a href="%R/wiki?name=%h(zName)&p">wiki-%d(srcid)</a>
144 break;
145 }
146 default: {
147 @ <td>unknown(%d(srctype)) - %d(srcid)
148 break;
@@ -146,11 +154,28 @@
154 @ </table>
155 db_finalize(&q);
156 style_footer();
157 }
158
159 /*
160 ** Remove all prior backlinks for the wiki page given. Then
161 ** add new backlinks for the latest version of the wiki page.
162 */
163 void backlink_wiki_refresh(const char *zWikiTitle){
164 int tagid = wiki_tagid(zWikiTitle);
165 int rid;
166 Manifest *pWiki;
167 if( tagid==0 ) return;
168 rid = db_int(0, "SELECT rid FROM tagxref WHERE tagid=%d"
169 " ORDER BY mtime DESC LIMIT 1", tagid);
170 if( rid==0 ) return;
171 pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
172 if( pWiki ){
173 backlink_extract(pWiki->zWiki, pWiki->zMimetype, tagid, 2, pWiki->rDate,1);
174 manifest_destroy(pWiki);
175 }
176 }
177
178 /*
179 ** Structure used to pass down state information through the
180 ** markup formatters into the BACKLINK generator.
181 */
@@ -266,11 +291,11 @@
291 if( replaceFlag ){
292 db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid=%d",
293 srctype, srcid);
294 }
295 bklnk.srcid = srcid;
296 assert( ValidBklnk(srctype) );
297 bklnk.srctype = srctype;
298 bklnk.mtime = mtime;
299 if( zMimetype==0 || strstr(zMimetype,"wiki")!=0 ){
300 wiki_extract_links(zSrc, &bklnk, srctype==BKLNK_COMMENT ? WIKI_INLINE : 0);
301 }else if( strstr(zMimetype,"markdown")!=0 ){
@@ -279,11 +304,11 @@
304 }
305
306 /*
307 ** COMMAND: test-backlinks
308 **
309 ** Usage: %fossil test-backlinks SRCTYPE SRCID ?OPTIONS? INPUT-FILE
310 **
311 ** Read the content of INPUT-FILE and pass it into the backlink_extract()
312 ** routine. But instead of adding backlinks to the backlink table,
313 ** just print them on stdout. SRCID and SRCTYPE are integers.
314 **
@@ -327,5 +352,31 @@
352 "END;"
353 );
354 backlink_extract(blob_str(&in),zMimetype,srcid,srctype,mtime,0);
355 blob_reset(&in);
356 }
357
358
359 /*
360 ** COMMAND: test-wiki-relink
361 **
362 ** Usage: %fossil test-wiki-relink WIKI-PAGE-NAME
363 **
364 ** Run the backlink_wiki_refresh() procedure on the wiki page
365 ** named. WIKI-PAGE-NAME can be a glob pattern or a prefix
366 ** of the wiki page.
367 */
368 void test_wiki_relink_cmd(void){
369 Stmt q;
370 db_find_and_open_repository(0, 0);
371 if( g.argc!=3 ) usage("WIKI-PAGE-NAME");
372 db_prepare(&q,
373 "SELECT substr(tagname,6) FROM tag WHERE tagname GLOB 'wiki-%q*'",
374 g.argv[2]
375 );
376 while( db_step(&q)==SQLITE_ROW ){
377 const char *zPage = db_column_text(&q,0);
378 fossil_print("Relinking page: %s\n", zPage);
379 backlink_wiki_refresh(zPage);
380 }
381 db_finalize(&q);
382 }
383
+28 -9
--- src/manifest.c
+++ src/manifest.c
@@ -1828,19 +1828,30 @@
18281828
void manifest_crosslink_begin(void){
18291829
assert( manifest_crosslink_busy==0 );
18301830
manifest_crosslink_busy = 1;
18311831
db_begin_transaction();
18321832
db_multi_exec(
1833
- "CREATE TEMP TABLE pending_tkt(uuid TEXT UNIQUE);"
1833
+ "CREATE TEMP TABLE pending_xlink(id TEXT PRIMARY KEY)WITHOUT ROWID;"
18341834
"CREATE TEMP TABLE time_fudge("
18351835
" mid INTEGER PRIMARY KEY," /* The rid of a manifest */
18361836
" m1 REAL," /* The timestamp on mid */
18371837
" cid INTEGER," /* A child or mid */
18381838
" m2 REAL" /* Timestamp on the child */
18391839
");"
18401840
);
18411841
}
1842
+
1843
+/*
1844
+** Add a new entry to the pending_xlink table.
1845
+*/
1846
+static void add_pending_crosslink(char cType, const char *zId){
1847
+ assert( manifest_crosslink_busy==1 );
1848
+ db_multi_exec(
1849
+ "INSERT OR IGNORE INTO pending_xlink VALUES('%c%q')",
1850
+ cType, zId
1851
+ );
1852
+}
18421853
18431854
#if INTERFACE
18441855
/* Timestamps might be adjusted slightly to ensure that check-ins appear
18451856
** on the timeline in chronological order. This is the maximum amount
18461857
** of the adjustment window, in days.
@@ -1879,20 +1890,28 @@
18791890
int rid = db_column_int(&q,0);
18801891
const char *zValue = db_column_text(&q,1);
18811892
manifest_reparent_checkin(rid, zValue);
18821893
}
18831894
db_finalize(&q);
1884
- db_prepare(&q, "SELECT uuid FROM pending_tkt");
1895
+ db_prepare(&q, "SELECT id FROM pending_xlink");
18851896
while( db_step(&q)==SQLITE_ROW ){
1886
- const char *zUuid = db_column_text(&q, 0);
1887
- ticket_rebuild_entry(zUuid);
1888
- if( permitHooks && rc==TH_OK ){
1889
- rc = xfer_run_script(zScript, zUuid, 0);
1897
+ const char *zId = db_column_text(&q, 0);
1898
+ char cType;
1899
+ if( zId==0 || zId[0]==0 ) continue;
1900
+ cType = zId[0];
1901
+ zId++;
1902
+ if( cType=='t' ){
1903
+ ticket_rebuild_entry(zId);
1904
+ if( permitHooks && rc==TH_OK ){
1905
+ rc = xfer_run_script(zScript, zId, 0);
1906
+ }
1907
+ }else if( cType=='w' ){
1908
+ backlink_wiki_refresh(zId);
18901909
}
18911910
}
18921911
db_finalize(&q);
1893
- db_multi_exec("DROP TABLE pending_tkt");
1912
+ db_multi_exec("DROP TABLE pending_xlink");
18941913
18951914
/* If multiple check-ins happen close together in time, adjust their
18961915
** times by a few milliseconds to make sure they appear in chronological
18971916
** order.
18981917
*/
@@ -2249,10 +2268,11 @@
22492268
zComment = mprintf("Changes to wiki page [%h]", p->zWikiTitle);
22502269
}else{
22512270
zComment = mprintf("Deleted wiki page [%h]", p->zWikiTitle);
22522271
}
22532272
search_doc_touch('w',rid,p->zWikiTitle);
2273
+ add_pending_crosslink('w',p->zWikiTitle);
22542274
db_multi_exec(
22552275
"REPLACE INTO event(type,mtime,objid,user,comment,"
22562276
" bgcolor,euser,ecomment)"
22572277
"VALUES('w',%.17g,%d,%Q,%Q,"
22582278
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>1),"
@@ -2349,12 +2369,11 @@
23492369
Stmt qatt;
23502370
assert( manifest_crosslink_busy==1 );
23512371
zTag = mprintf("tkt-%s", p->zTicketUuid);
23522372
tag_insert(zTag, 1, 0, rid, p->rDate, rid);
23532373
fossil_free(zTag);
2354
- db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)",
2355
- p->zTicketUuid);
2374
+ add_pending_crosslink('t',p->zTicketUuid);
23562375
/* Locate and update comment for any attachments */
23572376
db_prepare(&qatt,
23582377
"SELECT attachid, src, target, filename FROM attachment"
23592378
" WHERE target=%Q",
23602379
p->zTicketUuid
23612380
--- src/manifest.c
+++ src/manifest.c
@@ -1828,19 +1828,30 @@
1828 void manifest_crosslink_begin(void){
1829 assert( manifest_crosslink_busy==0 );
1830 manifest_crosslink_busy = 1;
1831 db_begin_transaction();
1832 db_multi_exec(
1833 "CREATE TEMP TABLE pending_tkt(uuid TEXT UNIQUE);"
1834 "CREATE TEMP TABLE time_fudge("
1835 " mid INTEGER PRIMARY KEY," /* The rid of a manifest */
1836 " m1 REAL," /* The timestamp on mid */
1837 " cid INTEGER," /* A child or mid */
1838 " m2 REAL" /* Timestamp on the child */
1839 ");"
1840 );
1841 }
 
 
 
 
 
 
 
 
 
 
 
1842
1843 #if INTERFACE
1844 /* Timestamps might be adjusted slightly to ensure that check-ins appear
1845 ** on the timeline in chronological order. This is the maximum amount
1846 ** of the adjustment window, in days.
@@ -1879,20 +1890,28 @@
1879 int rid = db_column_int(&q,0);
1880 const char *zValue = db_column_text(&q,1);
1881 manifest_reparent_checkin(rid, zValue);
1882 }
1883 db_finalize(&q);
1884 db_prepare(&q, "SELECT uuid FROM pending_tkt");
1885 while( db_step(&q)==SQLITE_ROW ){
1886 const char *zUuid = db_column_text(&q, 0);
1887 ticket_rebuild_entry(zUuid);
1888 if( permitHooks && rc==TH_OK ){
1889 rc = xfer_run_script(zScript, zUuid, 0);
 
 
 
 
 
 
 
 
1890 }
1891 }
1892 db_finalize(&q);
1893 db_multi_exec("DROP TABLE pending_tkt");
1894
1895 /* If multiple check-ins happen close together in time, adjust their
1896 ** times by a few milliseconds to make sure they appear in chronological
1897 ** order.
1898 */
@@ -2249,10 +2268,11 @@
2249 zComment = mprintf("Changes to wiki page [%h]", p->zWikiTitle);
2250 }else{
2251 zComment = mprintf("Deleted wiki page [%h]", p->zWikiTitle);
2252 }
2253 search_doc_touch('w',rid,p->zWikiTitle);
 
2254 db_multi_exec(
2255 "REPLACE INTO event(type,mtime,objid,user,comment,"
2256 " bgcolor,euser,ecomment)"
2257 "VALUES('w',%.17g,%d,%Q,%Q,"
2258 " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>1),"
@@ -2349,12 +2369,11 @@
2349 Stmt qatt;
2350 assert( manifest_crosslink_busy==1 );
2351 zTag = mprintf("tkt-%s", p->zTicketUuid);
2352 tag_insert(zTag, 1, 0, rid, p->rDate, rid);
2353 fossil_free(zTag);
2354 db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)",
2355 p->zTicketUuid);
2356 /* Locate and update comment for any attachments */
2357 db_prepare(&qatt,
2358 "SELECT attachid, src, target, filename FROM attachment"
2359 " WHERE target=%Q",
2360 p->zTicketUuid
2361
--- src/manifest.c
+++ src/manifest.c
@@ -1828,19 +1828,30 @@
1828 void manifest_crosslink_begin(void){
1829 assert( manifest_crosslink_busy==0 );
1830 manifest_crosslink_busy = 1;
1831 db_begin_transaction();
1832 db_multi_exec(
1833 "CREATE TEMP TABLE pending_xlink(id TEXT PRIMARY KEY)WITHOUT ROWID;"
1834 "CREATE TEMP TABLE time_fudge("
1835 " mid INTEGER PRIMARY KEY," /* The rid of a manifest */
1836 " m1 REAL," /* The timestamp on mid */
1837 " cid INTEGER," /* A child or mid */
1838 " m2 REAL" /* Timestamp on the child */
1839 ");"
1840 );
1841 }
1842
1843 /*
1844 ** Add a new entry to the pending_xlink table.
1845 */
1846 static void add_pending_crosslink(char cType, const char *zId){
1847 assert( manifest_crosslink_busy==1 );
1848 db_multi_exec(
1849 "INSERT OR IGNORE INTO pending_xlink VALUES('%c%q')",
1850 cType, zId
1851 );
1852 }
1853
1854 #if INTERFACE
1855 /* Timestamps might be adjusted slightly to ensure that check-ins appear
1856 ** on the timeline in chronological order. This is the maximum amount
1857 ** of the adjustment window, in days.
@@ -1879,20 +1890,28 @@
1890 int rid = db_column_int(&q,0);
1891 const char *zValue = db_column_text(&q,1);
1892 manifest_reparent_checkin(rid, zValue);
1893 }
1894 db_finalize(&q);
1895 db_prepare(&q, "SELECT id FROM pending_xlink");
1896 while( db_step(&q)==SQLITE_ROW ){
1897 const char *zId = db_column_text(&q, 0);
1898 char cType;
1899 if( zId==0 || zId[0]==0 ) continue;
1900 cType = zId[0];
1901 zId++;
1902 if( cType=='t' ){
1903 ticket_rebuild_entry(zId);
1904 if( permitHooks && rc==TH_OK ){
1905 rc = xfer_run_script(zScript, zId, 0);
1906 }
1907 }else if( cType=='w' ){
1908 backlink_wiki_refresh(zId);
1909 }
1910 }
1911 db_finalize(&q);
1912 db_multi_exec("DROP TABLE pending_xlink");
1913
1914 /* If multiple check-ins happen close together in time, adjust their
1915 ** times by a few milliseconds to make sure they appear in chronological
1916 ** order.
1917 */
@@ -2249,10 +2268,11 @@
2268 zComment = mprintf("Changes to wiki page [%h]", p->zWikiTitle);
2269 }else{
2270 zComment = mprintf("Deleted wiki page [%h]", p->zWikiTitle);
2271 }
2272 search_doc_touch('w',rid,p->zWikiTitle);
2273 add_pending_crosslink('w',p->zWikiTitle);
2274 db_multi_exec(
2275 "REPLACE INTO event(type,mtime,objid,user,comment,"
2276 " bgcolor,euser,ecomment)"
2277 "VALUES('w',%.17g,%d,%Q,%Q,"
2278 " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>1),"
@@ -2349,12 +2369,11 @@
2369 Stmt qatt;
2370 assert( manifest_crosslink_busy==1 );
2371 zTag = mprintf("tkt-%s", p->zTicketUuid);
2372 tag_insert(zTag, 1, 0, rid, p->rDate, rid);
2373 fossil_free(zTag);
2374 add_pending_crosslink('t',p->zTicketUuid);
 
2375 /* Locate and update comment for any attachments */
2376 db_prepare(&qatt,
2377 "SELECT attachid, src, target, filename FROM attachment"
2378 " WHERE target=%Q",
2379 p->zTicketUuid
2380
+5 -2
--- src/schema.c
+++ src/schema.c
@@ -477,16 +477,19 @@
477477
@ ) WITHOUT ROWID;
478478
@ CREATE INDEX cherrypick_cid ON cherrypick(childid);
479479
;
480480
481481
/*
482
-** Backlink source types
482
+** Allowed values for backlink.srctype
483483
*/
484484
#if INTERFACE
485485
# define BKLNK_COMMENT 0 /* Check-in comment */
486486
# define BKLNK_TICKET 1 /* Ticket body or title */
487
-# define BKLNK_WIKI 2 /* Wiki, Technote, or Forum body */
487
+# define BKLNK_WIKI 2 /* Wiki */
488
+# define BKLNK_EVENT 3 /* Technote */
489
+# define BKLNK_FORUM 4 /* Forum post */
490
+# define ValidBklnk(X) (X>=0 && X<=4) /* True if backlink.srctype is valid */
488491
#endif
489492
490493
/*
491494
** Predefined tagid values
492495
*/
493496
--- src/schema.c
+++ src/schema.c
@@ -477,16 +477,19 @@
477 @ ) WITHOUT ROWID;
478 @ CREATE INDEX cherrypick_cid ON cherrypick(childid);
479 ;
480
481 /*
482 ** Backlink source types
483 */
484 #if INTERFACE
485 # define BKLNK_COMMENT 0 /* Check-in comment */
486 # define BKLNK_TICKET 1 /* Ticket body or title */
487 # define BKLNK_WIKI 2 /* Wiki, Technote, or Forum body */
 
 
 
488 #endif
489
490 /*
491 ** Predefined tagid values
492 */
493
--- src/schema.c
+++ src/schema.c
@@ -477,16 +477,19 @@
477 @ ) WITHOUT ROWID;
478 @ CREATE INDEX cherrypick_cid ON cherrypick(childid);
479 ;
480
481 /*
482 ** Allowed values for backlink.srctype
483 */
484 #if INTERFACE
485 # define BKLNK_COMMENT 0 /* Check-in comment */
486 # define BKLNK_TICKET 1 /* Ticket body or title */
487 # define BKLNK_WIKI 2 /* Wiki */
488 # define BKLNK_EVENT 3 /* Technote */
489 # define BKLNK_FORUM 4 /* Forum post */
490 # define ValidBklnk(X) (X>=0 && X<=4) /* True if backlink.srctype is valid */
491 #endif
492
493 /*
494 ** Predefined tagid values
495 */
496
+17 -3
--- src/tkt.c
+++ src/tkt.c
@@ -856,10 +856,14 @@
856856
}
857857
858858
/*
859859
** Draw a timeline for a ticket with tag.tagid given by the tagid
860860
** parameter.
861
+**
862
+** If zType[0]=='c' then only show check-ins associated with the
863
+** ticket. For any other value of zType, show all events associated
864
+** with the ticket.
861865
*/
862866
void tkt_draw_timeline(int tagid, const char *zType){
863867
Stmt q;
864868
char *zFullUuid;
865869
char *zSQL;
@@ -866,20 +870,26 @@
866870
zFullUuid = db_text(0, "SELECT substr(tagname, 5) FROM tag WHERE tagid=%d",
867871
tagid);
868872
if( zType[0]=='c' ){
869873
zSQL = mprintf(
870874
"%s AND event.objid IN "
871
- " (SELECT srcid FROM backlink WHERE target GLOB '%.4s*' "
875
+ " (SELECT srcid FROM backlink WHERE target GLOB '%.4s*' "
876
+ "AND srctype=0 "
872877
"AND '%s' GLOB (target||'*')) "
873878
"ORDER BY mtime DESC",
874879
timeline_query_for_www(), zFullUuid, zFullUuid
875880
);
876881
}else{
877882
zSQL = mprintf(
878883
"%s AND event.objid IN "
879884
" (SELECT rid FROM tagxref WHERE tagid=%d"
880
- " UNION SELECT srcid FROM backlink"
885
+ " UNION"
886
+ " SELECT CASE srctype WHEN 2 THEN"
887
+ " (SELECT rid FROM tagxref WHERE tagid=backlink.srcid"
888
+ " ORDER BY mtime DESC LIMIT 1)"
889
+ " ELSE srcid END"
890
+ " FROM backlink"
881891
" WHERE target GLOB '%.4s*'"
882892
" AND '%s' GLOB (target||'*')"
883893
" UNION SELECT attachid FROM attachment"
884894
" WHERE target=%Q) "
885895
"ORDER BY mtime DESC",
@@ -894,13 +904,17 @@
894904
fossil_free(zFullUuid);
895905
}
896906
897907
/*
898908
** WEBPAGE: tkttimeline
899
-** URL: /tkttimeline?name=TICKETUUID&y=TYPE
909
+** URL: /tkttimeline/TICKETUUID
900910
**
901911
** Show the change history for a single ticket in timeline format.
912
+**
913
+** Query parameters:
914
+**
915
+** y=ci Show only check-ins associated with the ticket
902916
*/
903917
void tkttimeline_page(void){
904918
char *zTitle;
905919
const char *zUuid;
906920
int tagid;
907921
--- src/tkt.c
+++ src/tkt.c
@@ -856,10 +856,14 @@
856 }
857
858 /*
859 ** Draw a timeline for a ticket with tag.tagid given by the tagid
860 ** parameter.
 
 
 
 
861 */
862 void tkt_draw_timeline(int tagid, const char *zType){
863 Stmt q;
864 char *zFullUuid;
865 char *zSQL;
@@ -866,20 +870,26 @@
866 zFullUuid = db_text(0, "SELECT substr(tagname, 5) FROM tag WHERE tagid=%d",
867 tagid);
868 if( zType[0]=='c' ){
869 zSQL = mprintf(
870 "%s AND event.objid IN "
871 " (SELECT srcid FROM backlink WHERE target GLOB '%.4s*' "
 
872 "AND '%s' GLOB (target||'*')) "
873 "ORDER BY mtime DESC",
874 timeline_query_for_www(), zFullUuid, zFullUuid
875 );
876 }else{
877 zSQL = mprintf(
878 "%s AND event.objid IN "
879 " (SELECT rid FROM tagxref WHERE tagid=%d"
880 " UNION SELECT srcid FROM backlink"
 
 
 
 
 
881 " WHERE target GLOB '%.4s*'"
882 " AND '%s' GLOB (target||'*')"
883 " UNION SELECT attachid FROM attachment"
884 " WHERE target=%Q) "
885 "ORDER BY mtime DESC",
@@ -894,13 +904,17 @@
894 fossil_free(zFullUuid);
895 }
896
897 /*
898 ** WEBPAGE: tkttimeline
899 ** URL: /tkttimeline?name=TICKETUUID&y=TYPE
900 **
901 ** Show the change history for a single ticket in timeline format.
 
 
 
 
902 */
903 void tkttimeline_page(void){
904 char *zTitle;
905 const char *zUuid;
906 int tagid;
907
--- src/tkt.c
+++ src/tkt.c
@@ -856,10 +856,14 @@
856 }
857
858 /*
859 ** Draw a timeline for a ticket with tag.tagid given by the tagid
860 ** parameter.
861 **
862 ** If zType[0]=='c' then only show check-ins associated with the
863 ** ticket. For any other value of zType, show all events associated
864 ** with the ticket.
865 */
866 void tkt_draw_timeline(int tagid, const char *zType){
867 Stmt q;
868 char *zFullUuid;
869 char *zSQL;
@@ -866,20 +870,26 @@
870 zFullUuid = db_text(0, "SELECT substr(tagname, 5) FROM tag WHERE tagid=%d",
871 tagid);
872 if( zType[0]=='c' ){
873 zSQL = mprintf(
874 "%s AND event.objid IN "
875 " (SELECT srcid FROM backlink WHERE target GLOB '%.4s*' "
876 "AND srctype=0 "
877 "AND '%s' GLOB (target||'*')) "
878 "ORDER BY mtime DESC",
879 timeline_query_for_www(), zFullUuid, zFullUuid
880 );
881 }else{
882 zSQL = mprintf(
883 "%s AND event.objid IN "
884 " (SELECT rid FROM tagxref WHERE tagid=%d"
885 " UNION"
886 " SELECT CASE srctype WHEN 2 THEN"
887 " (SELECT rid FROM tagxref WHERE tagid=backlink.srcid"
888 " ORDER BY mtime DESC LIMIT 1)"
889 " ELSE srcid END"
890 " FROM backlink"
891 " WHERE target GLOB '%.4s*'"
892 " AND '%s' GLOB (target||'*')"
893 " UNION SELECT attachid FROM attachment"
894 " WHERE target=%Q) "
895 "ORDER BY mtime DESC",
@@ -894,13 +904,17 @@
904 fossil_free(zFullUuid);
905 }
906
907 /*
908 ** WEBPAGE: tkttimeline
909 ** URL: /tkttimeline/TICKETUUID
910 **
911 ** Show the change history for a single ticket in timeline format.
912 **
913 ** Query parameters:
914 **
915 ** y=ci Show only check-ins associated with the ticket
916 */
917 void tkttimeline_page(void){
918 char *zTitle;
919 const char *zUuid;
920 int tagid;
921

Keyboard Shortcuts

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