Fossil SCM

Added tag/branch option to /json/timeline/ci, analog to HTML mode t/r options.

stephan 2011-10-02 19:57 UTC json-multitag-test
Commit 762128512afdb2326dc25d16d1431386e397552a
1 file changed +135 -27
+135 -27
--- src/json_timeline.c
+++ src/json_timeline.c
@@ -27,20 +27,24 @@
2727
static cson_value * json_timeline_ticket();
2828
/*
2929
** Mapping of /json/timeline/XXX commands/paths to callbacks.
3030
*/
3131
static const JsonPageDef JsonPageDefs_Timeline[] = {
32
-{"c", json_timeline_ci, 0},
32
+/* the short forms are only enabled in CLI mode, to avoid
33
+ that we end up with HTTP clients using 3 different names
34
+ for the same requests.
35
+*/
36
+{"c", json_timeline_ci, -1},
3337
{"checkin", json_timeline_ci, 0},
34
-{"ci", json_timeline_ci, 0},
35
-{"com", json_timeline_ci, 0},
38
+{"ci", json_timeline_ci, -1},
39
+{"com", json_timeline_ci, -1},
3640
{"commit", json_timeline_ci, 0},
37
-{"t", json_timeline_ticket, 0},
41
+{"t", json_timeline_ticket, -1},
42
+{"tkt", json_timeline_ticket, -1},
3843
{"ticket", json_timeline_ticket, 0},
39
-{"w", json_timeline_wiki, 0},
40
-{"wi", json_timeline_wiki, 0},
41
-{"wik", json_timeline_wiki, 0},
44
+{"w", json_timeline_wiki, -1},
45
+{"wi", json_timeline_wiki, -1},
4246
{"wiki", json_timeline_wiki, 0},
4347
/* Last entry MUST have a NULL name. */
4448
{NULL,NULL,0}
4549
};
4650
@@ -106,10 +110,88 @@
106110
@ WHERE blob.rid=event.objid
107111
;
108112
return zBaseSql;
109113
}
110114
115
+/*
116
+** Internal helper to append query information if the
117
+** "tag" or "branch" request properties (CLI: --tag/--branch)
118
+** are set. Limits the query to a particular branch/tag.
119
+**
120
+** tag works like HTML mode's "t" option and branch works like HTML
121
+** mode's "r" option. They are very similar, but subtly different -
122
+** tag mode shows only entries with a given tag but branch mode can
123
+** also reveal some with "related" tags (meaning they were merged into
124
+** the requested branch).
125
+**
126
+** pSql is the target blob to append the query [subset]
127
+** to.
128
+**
129
+** Returns a positive value if it modifies pSql, 0 if it
130
+** does not. It returns a negative value if the tag
131
+** provided to the request was not found (pSql is not modified
132
+** in that case.
133
+**
134
+** If payload is not NULL then on success its "tag" or "branch"
135
+** property is set to the tag/branch name found in the request.
136
+**
137
+** Only one of "tag" or "branch" modes will work at a time, and if
138
+** both are specified, which one takes precedence is unspecified.
139
+*/
140
+static char json_timeline_add_tag_branch_clause(Blob *pSql,
141
+ cson_object * pPayload){
142
+ char const * zTag = NULL;
143
+ char const * zBranch = NULL;
144
+ int tagid = 0;
145
+ if(! g.perm.Read ){
146
+ return 0;
147
+ }
148
+ else if(g.isHTTP){
149
+ zTag = json_getenv_cstr("tag");
150
+ }else{
151
+ zTag = find_option("tag",NULL,1);
152
+ }
153
+ if(!zTag || !*zTag){
154
+ if(g.isHTTP){
155
+ zBranch = json_getenv_cstr("branch");
156
+ }else{
157
+ zBranch = find_option("branch",NULL,1);
158
+ }
159
+ if(!zBranch || !*zBranch){
160
+ return 0;
161
+ }
162
+ zTag = zBranch;
163
+ }
164
+ tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",
165
+ zTag);
166
+ if(tagid<=0){
167
+ return -1;
168
+ }
169
+ if(pPayload){
170
+ cson_object_set( pPayload, zBranch ? "branch" : "tag", json_new_string(zTag) );
171
+ }
172
+ blob_appendf(pSql,
173
+ " AND ("
174
+ " EXISTS(SELECT 1 FROM tagxref"
175
+ " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)",
176
+ tagid);
177
+ if(zBranch){
178
+ /* from "r" flag code in page_timeline().*/
179
+ blob_appendf(pSql,
180
+ " OR EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=cid"
181
+ " WHERE tagid=%d AND tagtype>0 AND pid=blob.rid)",
182
+ tagid);
183
+#if 0 /* from the undocumented "mionly" flag in page_timeline() */
184
+ blob_appendf(pSql,
185
+ " OR EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=pid"
186
+ " WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)",
187
+ tagid);
188
+#endif
189
+ }
190
+ blob_append(pSql," ) ",3);
191
+ return 1;
192
+}
111193
/*
112194
** Helper for the timeline family of functions. Possibly appends 1
113195
** AND clause and an ORDER BY clause to pSql, depending on the state
114196
** of the "after" ("a") or "before" ("b") environment parameters.
115197
** This function gives "after" precedence over "before", and only
@@ -188,31 +270,39 @@
188270
** Internal helper for the json_timeline_EVENTTYPE() family of
189271
** functions. zEventType must be one of (ci, w, t). pSql must be a
190272
** cleanly-initialized, empty Blob to store the sql in. If pPayload is
191273
** not NULL it is assumed to be the pending response payload. If
192274
** json_timeline_limit() returns non-0, this function adds a LIMIT
193
-** clause to the generated SQL and (if pPayload is not NULL) adds the
194
-** limit value as the "limit" property of pPayload.
275
+** clause to the generated SQL.
276
+**
277
+** If pPayload is not NULL then this might add properties to pPayload,
278
+** reflecting options set in the request environment.
279
+**
280
+** Returns 0 on success. On error processing should not continue and
281
+** the returned value should be used as g.json.resultCode.
195282
*/
196
-static void json_timeline_setup_sql( char const * zEventType,
197
- Blob * pSql,
198
- cson_object * pPayload ){
283
+static int json_timeline_setup_sql( char const * zEventType,
284
+ Blob * pSql,
285
+ cson_object * pPayload ){
199286
int limit;
200287
assert( zEventType && *zEventType && pSql );
201288
json_timeline_temp_table();
202289
blob_append(pSql, "INSERT OR IGNORE INTO json_timeline ", -1);
203290
blob_append(pSql, json_timeline_query(), -1 );
204291
blob_appendf(pSql, " AND event.type IN(%Q) ", zEventType);
292
+ if( json_timeline_add_tag_branch_clause(pSql, pPayload) < 0 ){
293
+ return FSL_JSON_E_INVALID_ARGS;
294
+ }
205295
json_timeline_add_time_clause(pSql);
206296
limit = json_timeline_limit();
207
- if(limit){
297
+ if(limit>=0){
208298
blob_appendf(pSql,"LIMIT %d ",limit);
209299
}
210300
if(pPayload){
211
- cson_object_set(pPayload, "limit",json_new_int(limit));
301
+ cson_object_set(pPayload, "limit", json_new_int(limit));
212302
}
213
-
303
+ return 0;
214304
}
215305
216306
/*
217307
** If any files are associated with the given rid, a JSON array
218308
** containing information about them is returned (and is owned by the
@@ -219,11 +309,11 @@
219309
** caller). If no files are associated with it then NULL is returned.
220310
*/
221311
cson_value * json_get_changed_files(int rid){
222312
cson_value * rowsV = NULL;
223313
cson_array * rows = NULL;
224
- Stmt q;
314
+ Stmt q = empty_Stmt;
225315
db_prepare(&q,
226316
#if 0
227317
"SELECT (mlink.pid==0) AS isNew,"
228318
" (mlink.fid==0) AS isDel,"
229319
" filename.name AS name"
@@ -238,11 +328,11 @@
238328
" (SELECT name FROM filename WHERE fnid=mlink.fnid) AS name,"
239329
" (SELECT uuid FROM blob WHERE rid=fid) as uuid,"
240330
" (SELECT uuid FROM blob WHERE rid=pid) as prevUuid"
241331
" FROM mlink"
242332
" WHERE mid=%d AND pid!=fid"
243
- " ORDER BY 3 /*sort*/",
333
+ " ORDER BY name /*sort*/",
244334
#endif
245335
rid
246336
);
247337
while( (SQLITE_ROW == db_step(&q)) ){
248338
cson_value * rowV = cson_value_new_object();
@@ -281,11 +371,11 @@
281371
cson_value * tmp = NULL;
282372
cson_value * listV = NULL;
283373
cson_array * list = NULL;
284374
int check = 0;
285375
int showFiles = 0;
286
- Stmt q;
376
+ Stmt q = empty_Stmt;
287377
char warnRowToJsonFailed = 0;
288378
char warnStringToArrayFailed = 0;
289379
Blob sql = empty_blob;
290380
if( !g.perm.Read/* && !g.perm.RdTkt && !g.perm.RdWiki*/ ){
291381
g.json.resultCode = FSL_JSON_E_DENIED;
@@ -296,11 +386,15 @@
296386
}else{
297387
showFiles = 0!=find_option("show-files", "f",0);
298388
}
299389
payV = cson_value_new_object();
300390
pay = cson_value_get_object(payV);
301
- json_timeline_setup_sql( "ci", &sql, pay );
391
+ check = json_timeline_setup_sql( "ci", &sql, pay );
392
+ if(check){
393
+ g.json.resultCode = check;
394
+ goto error;
395
+ }
302396
#define SET(K) if(0!=(check=cson_object_set(pay,K,tmp))){ \
303397
g.json.resultCode = (cson_rc.AllocError==check) \
304398
? FSL_JSON_E_ALLOC : FSL_JSON_E_UNKNOWN; \
305399
goto error;\
306400
}
@@ -310,25 +404,27 @@
310404
SET("timelineSql");
311405
#endif
312406
db_multi_exec(blob_buffer(&sql));
313407
blob_reset(&sql);
314408
db_prepare(&q, "SELECT "
315
- " rid AS rid,"
409
+ " rid AS rid"
410
+#if 0
316411
" uuid AS uuid,"
317412
" mtime AS timestamp,"
318
-#if 0
413
+# if 0
319414
" timestampString AS timestampString,"
320
-#endif
415
+# endif
321416
" comment AS comment, "
322417
" user AS user,"
323418
" isLeaf AS isLeaf," /*FIXME: convert to JSON bool */
324419
" bgColor AS bgColor," /* why always null? */
325420
" eventType AS eventType"
326
-#if 0
421
+# if 0
327422
" tags AS tags"
328423
/*tagId is always null?*/
329424
" tagId AS tagId"
425
+# endif
330426
#endif
331427
" FROM json_timeline"
332428
" ORDER BY sortId");
333429
listV = cson_value_new_array();
334430
list = cson_value_get_array(listV);
@@ -370,19 +466,24 @@
370466
cson_object * pay = NULL;
371467
cson_value * tmp = NULL;
372468
cson_value * listV = NULL;
373469
cson_array * list = NULL;
374470
int check = 0;
375
- Stmt q;
471
+ Stmt q = empty_Stmt;
376472
Blob sql = empty_blob;
377473
if( !g.perm.Read || !g.perm.RdWiki ){
378474
g.json.resultCode = FSL_JSON_E_DENIED;
379475
return NULL;
380476
}
381477
payV = cson_value_new_object();
382478
pay = cson_value_get_object(payV);
383
- json_timeline_setup_sql( "w", &sql, pay );
479
+ check = json_timeline_setup_sql( "w", &sql, pay );
480
+ if(check){
481
+ g.json.resultCode = check;
482
+ goto error;
483
+ }
484
+
384485
#define SET(K) if(0!=(check=cson_object_set(pay,K,tmp))){ \
385486
g.json.resultCode = (cson_rc.AllocError==check) \
386487
? FSL_JSON_E_ALLOC : FSL_JSON_E_UNKNOWN; \
387488
goto error;\
388489
}
@@ -422,10 +523,11 @@
422523
assert( 0 != g.json.resultCode );
423524
cson_value_free(payV);
424525
payV = NULL;
425526
ok:
426527
db_finalize(&q);
528
+ blob_reset(&sql);
427529
return payV;
428530
}
429531
430532
/*
431533
** Implementation of /json/timeline/ticket.
@@ -437,19 +539,24 @@
437539
cson_object * pay = NULL;
438540
cson_value * tmp = NULL;
439541
cson_value * listV = NULL;
440542
cson_array * list = NULL;
441543
int check = 0;
442
- Stmt q;
544
+ Stmt q = empty_Stmt;
443545
Blob sql = empty_blob;
444546
if( !g.perm.Read || !g.perm.RdTkt ){
445547
g.json.resultCode = FSL_JSON_E_DENIED;
446548
return NULL;
447549
}
448550
payV = cson_value_new_object();
449551
pay = cson_value_get_object(payV);
450
- json_timeline_setup_sql( "t", &sql, pay );
552
+ check = json_timeline_setup_sql( "t", &sql, pay );
553
+ if(check){
554
+ g.json.resultCode = check;
555
+ goto error;
556
+ }
557
+
451558
db_multi_exec(blob_buffer(&sql));
452559
#define SET(K) if(0!=(check=cson_object_set(pay,K,tmp))){ \
453560
g.json.resultCode = (cson_rc.AllocError==check) \
454561
? FSL_JSON_E_ALLOC : FSL_JSON_E_UNKNOWN; \
455562
goto error;\
@@ -514,9 +621,10 @@
514621
error:
515622
assert( 0 != g.json.resultCode );
516623
cson_value_free(payV);
517624
payV = NULL;
518625
ok:
626
+ blob_reset(&sql);
519627
db_finalize(&q);
520628
return payV;
521629
}
522630
523631
--- src/json_timeline.c
+++ src/json_timeline.c
@@ -27,20 +27,24 @@
27 static cson_value * json_timeline_ticket();
28 /*
29 ** Mapping of /json/timeline/XXX commands/paths to callbacks.
30 */
31 static const JsonPageDef JsonPageDefs_Timeline[] = {
32 {"c", json_timeline_ci, 0},
 
 
 
 
33 {"checkin", json_timeline_ci, 0},
34 {"ci", json_timeline_ci, 0},
35 {"com", json_timeline_ci, 0},
36 {"commit", json_timeline_ci, 0},
37 {"t", json_timeline_ticket, 0},
 
38 {"ticket", json_timeline_ticket, 0},
39 {"w", json_timeline_wiki, 0},
40 {"wi", json_timeline_wiki, 0},
41 {"wik", json_timeline_wiki, 0},
42 {"wiki", json_timeline_wiki, 0},
43 /* Last entry MUST have a NULL name. */
44 {NULL,NULL,0}
45 };
46
@@ -106,10 +110,88 @@
106 @ WHERE blob.rid=event.objid
107 ;
108 return zBaseSql;
109 }
110
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111 /*
112 ** Helper for the timeline family of functions. Possibly appends 1
113 ** AND clause and an ORDER BY clause to pSql, depending on the state
114 ** of the "after" ("a") or "before" ("b") environment parameters.
115 ** This function gives "after" precedence over "before", and only
@@ -188,31 +270,39 @@
188 ** Internal helper for the json_timeline_EVENTTYPE() family of
189 ** functions. zEventType must be one of (ci, w, t). pSql must be a
190 ** cleanly-initialized, empty Blob to store the sql in. If pPayload is
191 ** not NULL it is assumed to be the pending response payload. If
192 ** json_timeline_limit() returns non-0, this function adds a LIMIT
193 ** clause to the generated SQL and (if pPayload is not NULL) adds the
194 ** limit value as the "limit" property of pPayload.
 
 
 
 
 
195 */
196 static void json_timeline_setup_sql( char const * zEventType,
197 Blob * pSql,
198 cson_object * pPayload ){
199 int limit;
200 assert( zEventType && *zEventType && pSql );
201 json_timeline_temp_table();
202 blob_append(pSql, "INSERT OR IGNORE INTO json_timeline ", -1);
203 blob_append(pSql, json_timeline_query(), -1 );
204 blob_appendf(pSql, " AND event.type IN(%Q) ", zEventType);
 
 
 
205 json_timeline_add_time_clause(pSql);
206 limit = json_timeline_limit();
207 if(limit){
208 blob_appendf(pSql,"LIMIT %d ",limit);
209 }
210 if(pPayload){
211 cson_object_set(pPayload, "limit",json_new_int(limit));
212 }
213
214 }
215
216 /*
217 ** If any files are associated with the given rid, a JSON array
218 ** containing information about them is returned (and is owned by the
@@ -219,11 +309,11 @@
219 ** caller). If no files are associated with it then NULL is returned.
220 */
221 cson_value * json_get_changed_files(int rid){
222 cson_value * rowsV = NULL;
223 cson_array * rows = NULL;
224 Stmt q;
225 db_prepare(&q,
226 #if 0
227 "SELECT (mlink.pid==0) AS isNew,"
228 " (mlink.fid==0) AS isDel,"
229 " filename.name AS name"
@@ -238,11 +328,11 @@
238 " (SELECT name FROM filename WHERE fnid=mlink.fnid) AS name,"
239 " (SELECT uuid FROM blob WHERE rid=fid) as uuid,"
240 " (SELECT uuid FROM blob WHERE rid=pid) as prevUuid"
241 " FROM mlink"
242 " WHERE mid=%d AND pid!=fid"
243 " ORDER BY 3 /*sort*/",
244 #endif
245 rid
246 );
247 while( (SQLITE_ROW == db_step(&q)) ){
248 cson_value * rowV = cson_value_new_object();
@@ -281,11 +371,11 @@
281 cson_value * tmp = NULL;
282 cson_value * listV = NULL;
283 cson_array * list = NULL;
284 int check = 0;
285 int showFiles = 0;
286 Stmt q;
287 char warnRowToJsonFailed = 0;
288 char warnStringToArrayFailed = 0;
289 Blob sql = empty_blob;
290 if( !g.perm.Read/* && !g.perm.RdTkt && !g.perm.RdWiki*/ ){
291 g.json.resultCode = FSL_JSON_E_DENIED;
@@ -296,11 +386,15 @@
296 }else{
297 showFiles = 0!=find_option("show-files", "f",0);
298 }
299 payV = cson_value_new_object();
300 pay = cson_value_get_object(payV);
301 json_timeline_setup_sql( "ci", &sql, pay );
 
 
 
 
302 #define SET(K) if(0!=(check=cson_object_set(pay,K,tmp))){ \
303 g.json.resultCode = (cson_rc.AllocError==check) \
304 ? FSL_JSON_E_ALLOC : FSL_JSON_E_UNKNOWN; \
305 goto error;\
306 }
@@ -310,25 +404,27 @@
310 SET("timelineSql");
311 #endif
312 db_multi_exec(blob_buffer(&sql));
313 blob_reset(&sql);
314 db_prepare(&q, "SELECT "
315 " rid AS rid,"
 
316 " uuid AS uuid,"
317 " mtime AS timestamp,"
318 #if 0
319 " timestampString AS timestampString,"
320 #endif
321 " comment AS comment, "
322 " user AS user,"
323 " isLeaf AS isLeaf," /*FIXME: convert to JSON bool */
324 " bgColor AS bgColor," /* why always null? */
325 " eventType AS eventType"
326 #if 0
327 " tags AS tags"
328 /*tagId is always null?*/
329 " tagId AS tagId"
 
330 #endif
331 " FROM json_timeline"
332 " ORDER BY sortId");
333 listV = cson_value_new_array();
334 list = cson_value_get_array(listV);
@@ -370,19 +466,24 @@
370 cson_object * pay = NULL;
371 cson_value * tmp = NULL;
372 cson_value * listV = NULL;
373 cson_array * list = NULL;
374 int check = 0;
375 Stmt q;
376 Blob sql = empty_blob;
377 if( !g.perm.Read || !g.perm.RdWiki ){
378 g.json.resultCode = FSL_JSON_E_DENIED;
379 return NULL;
380 }
381 payV = cson_value_new_object();
382 pay = cson_value_get_object(payV);
383 json_timeline_setup_sql( "w", &sql, pay );
 
 
 
 
 
384 #define SET(K) if(0!=(check=cson_object_set(pay,K,tmp))){ \
385 g.json.resultCode = (cson_rc.AllocError==check) \
386 ? FSL_JSON_E_ALLOC : FSL_JSON_E_UNKNOWN; \
387 goto error;\
388 }
@@ -422,10 +523,11 @@
422 assert( 0 != g.json.resultCode );
423 cson_value_free(payV);
424 payV = NULL;
425 ok:
426 db_finalize(&q);
 
427 return payV;
428 }
429
430 /*
431 ** Implementation of /json/timeline/ticket.
@@ -437,19 +539,24 @@
437 cson_object * pay = NULL;
438 cson_value * tmp = NULL;
439 cson_value * listV = NULL;
440 cson_array * list = NULL;
441 int check = 0;
442 Stmt q;
443 Blob sql = empty_blob;
444 if( !g.perm.Read || !g.perm.RdTkt ){
445 g.json.resultCode = FSL_JSON_E_DENIED;
446 return NULL;
447 }
448 payV = cson_value_new_object();
449 pay = cson_value_get_object(payV);
450 json_timeline_setup_sql( "t", &sql, pay );
 
 
 
 
 
451 db_multi_exec(blob_buffer(&sql));
452 #define SET(K) if(0!=(check=cson_object_set(pay,K,tmp))){ \
453 g.json.resultCode = (cson_rc.AllocError==check) \
454 ? FSL_JSON_E_ALLOC : FSL_JSON_E_UNKNOWN; \
455 goto error;\
@@ -514,9 +621,10 @@
514 error:
515 assert( 0 != g.json.resultCode );
516 cson_value_free(payV);
517 payV = NULL;
518 ok:
 
519 db_finalize(&q);
520 return payV;
521 }
522
523
--- src/json_timeline.c
+++ src/json_timeline.c
@@ -27,20 +27,24 @@
27 static cson_value * json_timeline_ticket();
28 /*
29 ** Mapping of /json/timeline/XXX commands/paths to callbacks.
30 */
31 static const JsonPageDef JsonPageDefs_Timeline[] = {
32 /* the short forms are only enabled in CLI mode, to avoid
33 that we end up with HTTP clients using 3 different names
34 for the same requests.
35 */
36 {"c", json_timeline_ci, -1},
37 {"checkin", json_timeline_ci, 0},
38 {"ci", json_timeline_ci, -1},
39 {"com", json_timeline_ci, -1},
40 {"commit", json_timeline_ci, 0},
41 {"t", json_timeline_ticket, -1},
42 {"tkt", json_timeline_ticket, -1},
43 {"ticket", json_timeline_ticket, 0},
44 {"w", json_timeline_wiki, -1},
45 {"wi", json_timeline_wiki, -1},
 
46 {"wiki", json_timeline_wiki, 0},
47 /* Last entry MUST have a NULL name. */
48 {NULL,NULL,0}
49 };
50
@@ -106,10 +110,88 @@
110 @ WHERE blob.rid=event.objid
111 ;
112 return zBaseSql;
113 }
114
115 /*
116 ** Internal helper to append query information if the
117 ** "tag" or "branch" request properties (CLI: --tag/--branch)
118 ** are set. Limits the query to a particular branch/tag.
119 **
120 ** tag works like HTML mode's "t" option and branch works like HTML
121 ** mode's "r" option. They are very similar, but subtly different -
122 ** tag mode shows only entries with a given tag but branch mode can
123 ** also reveal some with "related" tags (meaning they were merged into
124 ** the requested branch).
125 **
126 ** pSql is the target blob to append the query [subset]
127 ** to.
128 **
129 ** Returns a positive value if it modifies pSql, 0 if it
130 ** does not. It returns a negative value if the tag
131 ** provided to the request was not found (pSql is not modified
132 ** in that case.
133 **
134 ** If payload is not NULL then on success its "tag" or "branch"
135 ** property is set to the tag/branch name found in the request.
136 **
137 ** Only one of "tag" or "branch" modes will work at a time, and if
138 ** both are specified, which one takes precedence is unspecified.
139 */
140 static char json_timeline_add_tag_branch_clause(Blob *pSql,
141 cson_object * pPayload){
142 char const * zTag = NULL;
143 char const * zBranch = NULL;
144 int tagid = 0;
145 if(! g.perm.Read ){
146 return 0;
147 }
148 else if(g.isHTTP){
149 zTag = json_getenv_cstr("tag");
150 }else{
151 zTag = find_option("tag",NULL,1);
152 }
153 if(!zTag || !*zTag){
154 if(g.isHTTP){
155 zBranch = json_getenv_cstr("branch");
156 }else{
157 zBranch = find_option("branch",NULL,1);
158 }
159 if(!zBranch || !*zBranch){
160 return 0;
161 }
162 zTag = zBranch;
163 }
164 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",
165 zTag);
166 if(tagid<=0){
167 return -1;
168 }
169 if(pPayload){
170 cson_object_set( pPayload, zBranch ? "branch" : "tag", json_new_string(zTag) );
171 }
172 blob_appendf(pSql,
173 " AND ("
174 " EXISTS(SELECT 1 FROM tagxref"
175 " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)",
176 tagid);
177 if(zBranch){
178 /* from "r" flag code in page_timeline().*/
179 blob_appendf(pSql,
180 " OR EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=cid"
181 " WHERE tagid=%d AND tagtype>0 AND pid=blob.rid)",
182 tagid);
183 #if 0 /* from the undocumented "mionly" flag in page_timeline() */
184 blob_appendf(pSql,
185 " OR EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=pid"
186 " WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)",
187 tagid);
188 #endif
189 }
190 blob_append(pSql," ) ",3);
191 return 1;
192 }
193 /*
194 ** Helper for the timeline family of functions. Possibly appends 1
195 ** AND clause and an ORDER BY clause to pSql, depending on the state
196 ** of the "after" ("a") or "before" ("b") environment parameters.
197 ** This function gives "after" precedence over "before", and only
@@ -188,31 +270,39 @@
270 ** Internal helper for the json_timeline_EVENTTYPE() family of
271 ** functions. zEventType must be one of (ci, w, t). pSql must be a
272 ** cleanly-initialized, empty Blob to store the sql in. If pPayload is
273 ** not NULL it is assumed to be the pending response payload. If
274 ** json_timeline_limit() returns non-0, this function adds a LIMIT
275 ** clause to the generated SQL.
276 **
277 ** If pPayload is not NULL then this might add properties to pPayload,
278 ** reflecting options set in the request environment.
279 **
280 ** Returns 0 on success. On error processing should not continue and
281 ** the returned value should be used as g.json.resultCode.
282 */
283 static int json_timeline_setup_sql( char const * zEventType,
284 Blob * pSql,
285 cson_object * pPayload ){
286 int limit;
287 assert( zEventType && *zEventType && pSql );
288 json_timeline_temp_table();
289 blob_append(pSql, "INSERT OR IGNORE INTO json_timeline ", -1);
290 blob_append(pSql, json_timeline_query(), -1 );
291 blob_appendf(pSql, " AND event.type IN(%Q) ", zEventType);
292 if( json_timeline_add_tag_branch_clause(pSql, pPayload) < 0 ){
293 return FSL_JSON_E_INVALID_ARGS;
294 }
295 json_timeline_add_time_clause(pSql);
296 limit = json_timeline_limit();
297 if(limit>=0){
298 blob_appendf(pSql,"LIMIT %d ",limit);
299 }
300 if(pPayload){
301 cson_object_set(pPayload, "limit", json_new_int(limit));
302 }
303 return 0;
304 }
305
306 /*
307 ** If any files are associated with the given rid, a JSON array
308 ** containing information about them is returned (and is owned by the
@@ -219,11 +309,11 @@
309 ** caller). If no files are associated with it then NULL is returned.
310 */
311 cson_value * json_get_changed_files(int rid){
312 cson_value * rowsV = NULL;
313 cson_array * rows = NULL;
314 Stmt q = empty_Stmt;
315 db_prepare(&q,
316 #if 0
317 "SELECT (mlink.pid==0) AS isNew,"
318 " (mlink.fid==0) AS isDel,"
319 " filename.name AS name"
@@ -238,11 +328,11 @@
328 " (SELECT name FROM filename WHERE fnid=mlink.fnid) AS name,"
329 " (SELECT uuid FROM blob WHERE rid=fid) as uuid,"
330 " (SELECT uuid FROM blob WHERE rid=pid) as prevUuid"
331 " FROM mlink"
332 " WHERE mid=%d AND pid!=fid"
333 " ORDER BY name /*sort*/",
334 #endif
335 rid
336 );
337 while( (SQLITE_ROW == db_step(&q)) ){
338 cson_value * rowV = cson_value_new_object();
@@ -281,11 +371,11 @@
371 cson_value * tmp = NULL;
372 cson_value * listV = NULL;
373 cson_array * list = NULL;
374 int check = 0;
375 int showFiles = 0;
376 Stmt q = empty_Stmt;
377 char warnRowToJsonFailed = 0;
378 char warnStringToArrayFailed = 0;
379 Blob sql = empty_blob;
380 if( !g.perm.Read/* && !g.perm.RdTkt && !g.perm.RdWiki*/ ){
381 g.json.resultCode = FSL_JSON_E_DENIED;
@@ -296,11 +386,15 @@
386 }else{
387 showFiles = 0!=find_option("show-files", "f",0);
388 }
389 payV = cson_value_new_object();
390 pay = cson_value_get_object(payV);
391 check = json_timeline_setup_sql( "ci", &sql, pay );
392 if(check){
393 g.json.resultCode = check;
394 goto error;
395 }
396 #define SET(K) if(0!=(check=cson_object_set(pay,K,tmp))){ \
397 g.json.resultCode = (cson_rc.AllocError==check) \
398 ? FSL_JSON_E_ALLOC : FSL_JSON_E_UNKNOWN; \
399 goto error;\
400 }
@@ -310,25 +404,27 @@
404 SET("timelineSql");
405 #endif
406 db_multi_exec(blob_buffer(&sql));
407 blob_reset(&sql);
408 db_prepare(&q, "SELECT "
409 " rid AS rid"
410 #if 0
411 " uuid AS uuid,"
412 " mtime AS timestamp,"
413 # if 0
414 " timestampString AS timestampString,"
415 # endif
416 " comment AS comment, "
417 " user AS user,"
418 " isLeaf AS isLeaf," /*FIXME: convert to JSON bool */
419 " bgColor AS bgColor," /* why always null? */
420 " eventType AS eventType"
421 # if 0
422 " tags AS tags"
423 /*tagId is always null?*/
424 " tagId AS tagId"
425 # endif
426 #endif
427 " FROM json_timeline"
428 " ORDER BY sortId");
429 listV = cson_value_new_array();
430 list = cson_value_get_array(listV);
@@ -370,19 +466,24 @@
466 cson_object * pay = NULL;
467 cson_value * tmp = NULL;
468 cson_value * listV = NULL;
469 cson_array * list = NULL;
470 int check = 0;
471 Stmt q = empty_Stmt;
472 Blob sql = empty_blob;
473 if( !g.perm.Read || !g.perm.RdWiki ){
474 g.json.resultCode = FSL_JSON_E_DENIED;
475 return NULL;
476 }
477 payV = cson_value_new_object();
478 pay = cson_value_get_object(payV);
479 check = json_timeline_setup_sql( "w", &sql, pay );
480 if(check){
481 g.json.resultCode = check;
482 goto error;
483 }
484
485 #define SET(K) if(0!=(check=cson_object_set(pay,K,tmp))){ \
486 g.json.resultCode = (cson_rc.AllocError==check) \
487 ? FSL_JSON_E_ALLOC : FSL_JSON_E_UNKNOWN; \
488 goto error;\
489 }
@@ -422,10 +523,11 @@
523 assert( 0 != g.json.resultCode );
524 cson_value_free(payV);
525 payV = NULL;
526 ok:
527 db_finalize(&q);
528 blob_reset(&sql);
529 return payV;
530 }
531
532 /*
533 ** Implementation of /json/timeline/ticket.
@@ -437,19 +539,24 @@
539 cson_object * pay = NULL;
540 cson_value * tmp = NULL;
541 cson_value * listV = NULL;
542 cson_array * list = NULL;
543 int check = 0;
544 Stmt q = empty_Stmt;
545 Blob sql = empty_blob;
546 if( !g.perm.Read || !g.perm.RdTkt ){
547 g.json.resultCode = FSL_JSON_E_DENIED;
548 return NULL;
549 }
550 payV = cson_value_new_object();
551 pay = cson_value_get_object(payV);
552 check = json_timeline_setup_sql( "t", &sql, pay );
553 if(check){
554 g.json.resultCode = check;
555 goto error;
556 }
557
558 db_multi_exec(blob_buffer(&sql));
559 #define SET(K) if(0!=(check=cson_object_set(pay,K,tmp))){ \
560 g.json.resultCode = (cson_rc.AllocError==check) \
561 ? FSL_JSON_E_ALLOC : FSL_JSON_E_UNKNOWN; \
562 goto error;\
@@ -514,9 +621,10 @@
621 error:
622 assert( 0 != g.json.resultCode );
623 cson_value_free(payV);
624 payV = NULL;
625 ok:
626 blob_reset(&sql);
627 db_finalize(&q);
628 return payV;
629 }
630
631

Keyboard Shortcuts

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