Fossil SCM

Permissions fixes in json/report. Added json/timeline/branch, analog to /brtimeline.

stephan 2011-10-08 12:13 UTC json-multitag-test
Commit 6841b11647954d83ebe5835e9252fc1d9ea7444e
+10 -1
--- ajax/index.html
+++ ajax/index.html
@@ -219,22 +219,28 @@
219219
If the POST textarea is not empty then it will be posted with the request.
220220
<hr/>
221221
<strong>Quick-posts:</strong><br/>
222222
<input type='button' value='HAI' onclick='TheApp.cgi.HAI()' />
223223
<input type='button' value='HAI JSONP' onclick='TheApp.cgi.sendCommand("/json/HAI",undefined,{jsonp:"myJsonPCallback"});' />
224
-
225224
<input type='button' value='version' onclick='TheApp.cgi.sendCommand("/json/version")' />
226225
<input type='button' value='stat' onclick='TheApp.cgi.sendCommand("/json/stat?full=0")' />
227226
<input type='button' value='whoami' onclick='TheApp.cgi.whoami()' />
228227
<input type='button' value='cap' onclick='TheApp.cgi.sendCommand("/json/cap")' />
228
+
229
+<br/>
230
+
229231
<input type='button' value='branch/list' onclick='TheApp.cgi.sendCommand("/json/branch/list")' />
230232
<input type='button' value='timeline/ci' onclick='TheApp.cgi.sendCommand("/json/timeline/ci?files=true")' />
231233
<input type='button' value='timeline/wiki' onclick='TheApp.cgi.sendCommand("/json/timeline/wiki")' />
232234
<input type='button' value='timeline/ticket' onclick='TheApp.cgi.sendCommand("/json/timeline/ticket")' />
235
+<input type='button' value='timeline/branch' onclick='TheApp.cgi.sendCommand("/json/timeline/branch")' />
233236
<input type='button' value='wiki/list' onclick='TheApp.cgi.sendCommand("/json/wiki/list")' />
234237
<input type='button' value='wiki/get Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get",{name:"Fossil"})' />
235238
<input type='button' value='wiki/get/Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get/Fossil")' />
239
+
240
+<br/>
241
+
236242
<input type='button' value='user/list' onclick='TheApp.cgi.sendCommand("/json/user/list")' />
237243
<input type='button' value='user/get' onclick='TheApp.cgi.sendCommand("/json/user/get?name=anonymous")' />
238244
<input type='button' value='resultCodes' onclick='TheApp.cgi.sendCommand("/json/resultCodes")' />
239245
<input type='button' value='tag/list' onclick='TheApp.cgi.sendCommand("/json/tag/list?includeTickets=false&raw=false")' />
240246
<input type='button' value='tag/list/json' onclick='TheApp.cgi.sendCommand("/json/tag/list/json?raw=false")' />
@@ -242,10 +248,13 @@
242248
onclick='TheApp.cgi.sendCommand("/json/tag/add",{name:"json-add-tag-test",checkin:"json",value:"tag test",propagate:false,raw:false})' />
243249
<input type='button' value='tag/cancel'
244250
onclick='TheApp.cgi.sendCommand("/json/tag/cancel",{name:"json-add-tag-test",checkin:"json",raw:false})' />
245251
<input type='button' value='tag/find'
246252
onclick='TheApp.cgi.sendCommand("/json/tag/find",{name:"json",type:"*",raw:false,limit:5})' />
253
+
254
+<br/>
255
+
247256
<input type='button' value='diff'
248257
onclick='TheApp.cgi.sendCommand("/json/diff",{v1:"b0e9b45baed6f885",v2:"5f225e261d836287",context:2})' />
249258
<input type='button' value='diff/A/B'
250259
onclick='TheApp.cgi.sendCommand("/json/diff/b0e9b45baed6f885/5f225e261d836287?context=2")' />
251260
252261
--- ajax/index.html
+++ ajax/index.html
@@ -219,22 +219,28 @@
219 If the POST textarea is not empty then it will be posted with the request.
220 <hr/>
221 <strong>Quick-posts:</strong><br/>
222 <input type='button' value='HAI' onclick='TheApp.cgi.HAI()' />
223 <input type='button' value='HAI JSONP' onclick='TheApp.cgi.sendCommand("/json/HAI",undefined,{jsonp:"myJsonPCallback"});' />
224
225 <input type='button' value='version' onclick='TheApp.cgi.sendCommand("/json/version")' />
226 <input type='button' value='stat' onclick='TheApp.cgi.sendCommand("/json/stat?full=0")' />
227 <input type='button' value='whoami' onclick='TheApp.cgi.whoami()' />
228 <input type='button' value='cap' onclick='TheApp.cgi.sendCommand("/json/cap")' />
 
 
 
229 <input type='button' value='branch/list' onclick='TheApp.cgi.sendCommand("/json/branch/list")' />
230 <input type='button' value='timeline/ci' onclick='TheApp.cgi.sendCommand("/json/timeline/ci?files=true")' />
231 <input type='button' value='timeline/wiki' onclick='TheApp.cgi.sendCommand("/json/timeline/wiki")' />
232 <input type='button' value='timeline/ticket' onclick='TheApp.cgi.sendCommand("/json/timeline/ticket")' />
 
233 <input type='button' value='wiki/list' onclick='TheApp.cgi.sendCommand("/json/wiki/list")' />
234 <input type='button' value='wiki/get Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get",{name:"Fossil"})' />
235 <input type='button' value='wiki/get/Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get/Fossil")' />
 
 
 
236 <input type='button' value='user/list' onclick='TheApp.cgi.sendCommand("/json/user/list")' />
237 <input type='button' value='user/get' onclick='TheApp.cgi.sendCommand("/json/user/get?name=anonymous")' />
238 <input type='button' value='resultCodes' onclick='TheApp.cgi.sendCommand("/json/resultCodes")' />
239 <input type='button' value='tag/list' onclick='TheApp.cgi.sendCommand("/json/tag/list?includeTickets=false&raw=false")' />
240 <input type='button' value='tag/list/json' onclick='TheApp.cgi.sendCommand("/json/tag/list/json?raw=false")' />
@@ -242,10 +248,13 @@
242 onclick='TheApp.cgi.sendCommand("/json/tag/add",{name:"json-add-tag-test",checkin:"json",value:"tag test",propagate:false,raw:false})' />
243 <input type='button' value='tag/cancel'
244 onclick='TheApp.cgi.sendCommand("/json/tag/cancel",{name:"json-add-tag-test",checkin:"json",raw:false})' />
245 <input type='button' value='tag/find'
246 onclick='TheApp.cgi.sendCommand("/json/tag/find",{name:"json",type:"*",raw:false,limit:5})' />
 
 
 
247 <input type='button' value='diff'
248 onclick='TheApp.cgi.sendCommand("/json/diff",{v1:"b0e9b45baed6f885",v2:"5f225e261d836287",context:2})' />
249 <input type='button' value='diff/A/B'
250 onclick='TheApp.cgi.sendCommand("/json/diff/b0e9b45baed6f885/5f225e261d836287?context=2")' />
251
252
--- ajax/index.html
+++ ajax/index.html
@@ -219,22 +219,28 @@
219 If the POST textarea is not empty then it will be posted with the request.
220 <hr/>
221 <strong>Quick-posts:</strong><br/>
222 <input type='button' value='HAI' onclick='TheApp.cgi.HAI()' />
223 <input type='button' value='HAI JSONP' onclick='TheApp.cgi.sendCommand("/json/HAI",undefined,{jsonp:"myJsonPCallback"});' />
 
224 <input type='button' value='version' onclick='TheApp.cgi.sendCommand("/json/version")' />
225 <input type='button' value='stat' onclick='TheApp.cgi.sendCommand("/json/stat?full=0")' />
226 <input type='button' value='whoami' onclick='TheApp.cgi.whoami()' />
227 <input type='button' value='cap' onclick='TheApp.cgi.sendCommand("/json/cap")' />
228
229 <br/>
230
231 <input type='button' value='branch/list' onclick='TheApp.cgi.sendCommand("/json/branch/list")' />
232 <input type='button' value='timeline/ci' onclick='TheApp.cgi.sendCommand("/json/timeline/ci?files=true")' />
233 <input type='button' value='timeline/wiki' onclick='TheApp.cgi.sendCommand("/json/timeline/wiki")' />
234 <input type='button' value='timeline/ticket' onclick='TheApp.cgi.sendCommand("/json/timeline/ticket")' />
235 <input type='button' value='timeline/branch' onclick='TheApp.cgi.sendCommand("/json/timeline/branch")' />
236 <input type='button' value='wiki/list' onclick='TheApp.cgi.sendCommand("/json/wiki/list")' />
237 <input type='button' value='wiki/get Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get",{name:"Fossil"})' />
238 <input type='button' value='wiki/get/Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get/Fossil")' />
239
240 <br/>
241
242 <input type='button' value='user/list' onclick='TheApp.cgi.sendCommand("/json/user/list")' />
243 <input type='button' value='user/get' onclick='TheApp.cgi.sendCommand("/json/user/get?name=anonymous")' />
244 <input type='button' value='resultCodes' onclick='TheApp.cgi.sendCommand("/json/resultCodes")' />
245 <input type='button' value='tag/list' onclick='TheApp.cgi.sendCommand("/json/tag/list?includeTickets=false&raw=false")' />
246 <input type='button' value='tag/list/json' onclick='TheApp.cgi.sendCommand("/json/tag/list/json?raw=false")' />
@@ -242,10 +248,13 @@
248 onclick='TheApp.cgi.sendCommand("/json/tag/add",{name:"json-add-tag-test",checkin:"json",value:"tag test",propagate:false,raw:false})' />
249 <input type='button' value='tag/cancel'
250 onclick='TheApp.cgi.sendCommand("/json/tag/cancel",{name:"json-add-tag-test",checkin:"json",raw:false})' />
251 <input type='button' value='tag/find'
252 onclick='TheApp.cgi.sendCommand("/json/tag/find",{name:"json",type:"*",raw:false,limit:5})' />
253
254 <br/>
255
256 <input type='button' value='diff'
257 onclick='TheApp.cgi.sendCommand("/json/diff",{v1:"b0e9b45baed6f885",v2:"5f225e261d836287",context:2})' />
258 <input type='button' value='diff/A/B'
259 onclick='TheApp.cgi.sendCommand("/json/diff/b0e9b45baed6f885/5f225e261d836287?context=2")' />
260
261
+36 -18
--- src/json_report.c
+++ src/json_report.c
@@ -53,38 +53,57 @@
5353
return NULL;
5454
}
5555
return json_page_dispatch_helper(&JsonPageDefs_Report[0]);
5656
}
5757
58
+/*
59
+** Searches the environment for a "report" parameter
60
+** (CLI: -report/-r #).
61
+**
62
+** If one is not found and argPos is >0 then json_command_arg()
63
+** is checked.
64
+**
65
+** Returns >0 (the report number) on success .
66
+*/
67
+static int json_report_get_number(int argPos){
68
+ int nReport = json_find_option_int("report",NULL,"r",-1);
69
+ if( (nReport <= 0) && (argPos>0) ){
70
+ char const * arg = json_command_arg(argPos);
71
+ if(arg && fossil_isdigit(*arg)) {
72
+ nReport = atoi(arg);
73
+ }
74
+ }
75
+ return nReport;
76
+}
5877
5978
static cson_value * json_report_create(){
6079
return NULL;
6180
}
6281
6382
static cson_value * json_report_get(){
6483
return NULL;
6584
}
6685
86
+/*
87
+** Impl of /json/report/list.
88
+*/
6789
static cson_value * json_report_list(){
6890
Blob sql = empty_blob;
6991
cson_value * pay = NULL;
92
+ if(!g.perm.RdTkt){
93
+ json_set_err(FSL_JSON_E_DENIED,
94
+ "Requires 'r' privileges.");
95
+ return NULL;
96
+ }
7097
blob_append(&sql, "SELECT"
7198
" rn AS report,"
7299
" title as title,"
73100
" owner as owner"
74101
" FROM reportfmt"
75
- " WHERE 1", -1);
76
- /* This logic was adapted from the HTML mode report list
77
- page. However, for reasons i cannot explain, enbling this block
78
- causes a crash in CGI mode when request is made via a user
79
- without TktFmt.
80
- */
81
- if(!g.perm.TktFmt){
82
- blob_append(&sql,
83
- " AND title NOT LIKE '_%'", -1);
84
- }
85
- blob_append(&sql," ORDER BY title",-1);
102
+ " WHERE 1"
103
+ " ORDER BY title",
104
+ -1);
86105
pay = json_sql_to_array_of_obj(&sql, NULL, 1);
87106
if(!pay){
88107
json_set_err(FSL_JSON_E_UNKNOWN,
89108
"Quite unexpected: no ticket reports found.");
90109
}
@@ -113,17 +132,16 @@
113132
Blob sql = empty_blob;
114133
int limit = 0;
115134
cson_value * colNames = NULL;
116135
int i;
117136
118
- nReport = json_find_option_int("report",NULL,"r",-1);
119
- if( nReport <= 0 ){
120
- char const * arg = json_command_arg(3);
121
- if(arg && fossil_isdigit(*arg)) {
122
- nReport = atoi(arg);
123
- }
137
+ if(!g.perm.RdTkt){
138
+ json_set_err(FSL_JSON_E_DENIED,
139
+ "Requires 'r' privileges.");
140
+ return NULL;
124141
}
142
+ nReport = json_report_get_number(3);
125143
if(nReport <=0){
126144
json_set_err(FSL_JSON_E_MISSING_ARGS,
127145
"Missing or invalid 'number' (-n) parameter.");
128146
goto error;
129147
}
@@ -161,11 +179,11 @@
161179
cson_object_set(pay, "limit", json_new_int((limit<0) ? 0 : limit));
162180
}
163181
free(zTitle);
164182
zTitle = NULL;
165183
166
- if(g.perm.WrTkt){
184
+ if(g.perm.TktFmt){
167185
cson_object_set(pay, "sqlcode",
168186
cson_value_new_string(blob_str(&sql),
169187
(unsigned int)blob_size(&sql)));
170188
}
171189
blob_reset(&sql);
172190
--- src/json_report.c
+++ src/json_report.c
@@ -53,38 +53,57 @@
53 return NULL;
54 }
55 return json_page_dispatch_helper(&JsonPageDefs_Report[0]);
56 }
57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
59 static cson_value * json_report_create(){
60 return NULL;
61 }
62
63 static cson_value * json_report_get(){
64 return NULL;
65 }
66
 
 
 
67 static cson_value * json_report_list(){
68 Blob sql = empty_blob;
69 cson_value * pay = NULL;
 
 
 
 
 
70 blob_append(&sql, "SELECT"
71 " rn AS report,"
72 " title as title,"
73 " owner as owner"
74 " FROM reportfmt"
75 " WHERE 1", -1);
76 /* This logic was adapted from the HTML mode report list
77 page. However, for reasons i cannot explain, enbling this block
78 causes a crash in CGI mode when request is made via a user
79 without TktFmt.
80 */
81 if(!g.perm.TktFmt){
82 blob_append(&sql,
83 " AND title NOT LIKE '_%'", -1);
84 }
85 blob_append(&sql," ORDER BY title",-1);
86 pay = json_sql_to_array_of_obj(&sql, NULL, 1);
87 if(!pay){
88 json_set_err(FSL_JSON_E_UNKNOWN,
89 "Quite unexpected: no ticket reports found.");
90 }
@@ -113,17 +132,16 @@
113 Blob sql = empty_blob;
114 int limit = 0;
115 cson_value * colNames = NULL;
116 int i;
117
118 nReport = json_find_option_int("report",NULL,"r",-1);
119 if( nReport <= 0 ){
120 char const * arg = json_command_arg(3);
121 if(arg && fossil_isdigit(*arg)) {
122 nReport = atoi(arg);
123 }
124 }
 
125 if(nReport <=0){
126 json_set_err(FSL_JSON_E_MISSING_ARGS,
127 "Missing or invalid 'number' (-n) parameter.");
128 goto error;
129 }
@@ -161,11 +179,11 @@
161 cson_object_set(pay, "limit", json_new_int((limit<0) ? 0 : limit));
162 }
163 free(zTitle);
164 zTitle = NULL;
165
166 if(g.perm.WrTkt){
167 cson_object_set(pay, "sqlcode",
168 cson_value_new_string(blob_str(&sql),
169 (unsigned int)blob_size(&sql)));
170 }
171 blob_reset(&sql);
172
--- src/json_report.c
+++ src/json_report.c
@@ -53,38 +53,57 @@
53 return NULL;
54 }
55 return json_page_dispatch_helper(&JsonPageDefs_Report[0]);
56 }
57
58 /*
59 ** Searches the environment for a "report" parameter
60 ** (CLI: -report/-r #).
61 **
62 ** If one is not found and argPos is >0 then json_command_arg()
63 ** is checked.
64 **
65 ** Returns >0 (the report number) on success .
66 */
67 static int json_report_get_number(int argPos){
68 int nReport = json_find_option_int("report",NULL,"r",-1);
69 if( (nReport <= 0) && (argPos>0) ){
70 char const * arg = json_command_arg(argPos);
71 if(arg && fossil_isdigit(*arg)) {
72 nReport = atoi(arg);
73 }
74 }
75 return nReport;
76 }
77
78 static cson_value * json_report_create(){
79 return NULL;
80 }
81
82 static cson_value * json_report_get(){
83 return NULL;
84 }
85
86 /*
87 ** Impl of /json/report/list.
88 */
89 static cson_value * json_report_list(){
90 Blob sql = empty_blob;
91 cson_value * pay = NULL;
92 if(!g.perm.RdTkt){
93 json_set_err(FSL_JSON_E_DENIED,
94 "Requires 'r' privileges.");
95 return NULL;
96 }
97 blob_append(&sql, "SELECT"
98 " rn AS report,"
99 " title as title,"
100 " owner as owner"
101 " FROM reportfmt"
102 " WHERE 1"
103 " ORDER BY title",
104 -1);
 
 
 
 
 
 
 
 
105 pay = json_sql_to_array_of_obj(&sql, NULL, 1);
106 if(!pay){
107 json_set_err(FSL_JSON_E_UNKNOWN,
108 "Quite unexpected: no ticket reports found.");
109 }
@@ -113,17 +132,16 @@
132 Blob sql = empty_blob;
133 int limit = 0;
134 cson_value * colNames = NULL;
135 int i;
136
137 if(!g.perm.RdTkt){
138 json_set_err(FSL_JSON_E_DENIED,
139 "Requires 'r' privileges.");
140 return NULL;
 
 
141 }
142 nReport = json_report_get_number(3);
143 if(nReport <=0){
144 json_set_err(FSL_JSON_E_MISSING_ARGS,
145 "Missing or invalid 'number' (-n) parameter.");
146 goto error;
147 }
@@ -161,11 +179,11 @@
179 cson_object_set(pay, "limit", json_new_int((limit<0) ? 0 : limit));
180 }
181 free(zTitle);
182 zTitle = NULL;
183
184 if(g.perm.TktFmt){
185 cson_object_set(pay, "sqlcode",
186 cson_value_new_string(blob_str(&sql),
187 (unsigned int)blob_size(&sql)));
188 }
189 blob_reset(&sql);
190
--- src/json_timeline.c
+++ src/json_timeline.c
@@ -21,10 +21,11 @@
2121
2222
#if INTERFACE
2323
#include "json_detail.h"
2424
#endif
2525
26
+static cson_value * json_timeline_branch();
2627
static cson_value * json_timeline_ci();
2728
static cson_value * json_timeline_ticket();
2829
/*
2930
** Mapping of /json/timeline/XXX commands/paths to callbacks.
3031
*/
@@ -31,10 +32,11 @@
3132
static const JsonPageDef JsonPageDefs_Timeline[] = {
3233
/* the short forms are only enabled in CLI mode, to avoid
3334
that we end up with HTTP clients using 3 different names
3435
for the same requests.
3536
*/
37
+{"branch", json_timeline_branch, 0},
3638
{"c", json_timeline_ci, -1},
3739
{"checkin", json_timeline_ci, 0},
3840
{"ci", json_timeline_ci, -1},
3941
{"com", json_timeline_ci, -1},
4042
{"commit", json_timeline_ci, 0},
@@ -111,13 +113,13 @@
111113
@ blob.rid IN leaf,
112114
@ bgcolor,
113115
@ event.type,
114116
@ (SELECT group_concat(substr(tagname,5), ',') FROM tag, tagxref
115117
@ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
116
- @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0),
117
- @ tagid,
118
- @ brief
118
+ @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0) as tags,
119
+ @ tagid as tagId,
120
+ @ brief as brief
119121
@ FROM event JOIN blob
120122
@ WHERE blob.rid=event.objid
121123
;
122124
return zBaseSql;
123125
}
@@ -343,10 +345,75 @@
343345
cson_array_append( rows, rowV );
344346
}
345347
db_finalize(&q);
346348
return rowsV;
347349
}
350
+
351
+static cson_value * json_timeline_branch(){
352
+ cson_value * pay = NULL;
353
+ Blob sql = empty_blob;
354
+ Stmt q = empty_Stmt;
355
+ if(!g.perm.Read){
356
+ json_set_err(FSL_JSON_E_DENIED,
357
+ "Requires 'o' permissions.");
358
+ return NULL;
359
+ }
360
+ json_timeline_temp_table();
361
+ blob_append(&sql,
362
+ "SELECT"
363
+ " blob.rid AS rid,"
364
+ " uuid AS uuid,"
365
+ " datetime(event.mtime,'utc') as mtime,"
366
+ " coalesce(ecomment, comment) as comment,"
367
+ " coalesce(euser, user) as user,"
368
+ " blob.rid IN leaf as isLeaf,"
369
+ " bgcolor as bgColor"
370
+ " FROM event JOIN blob"
371
+ " WHERE blob.rid=event.objid",
372
+ -1);
373
+
374
+ blob_appendf(&sql,
375
+ " AND event.type='ci'"
376
+ " AND blob.rid IN (SELECT rid FROM tagxref"
377
+ " WHERE tagtype>0 AND tagid=%d AND srcid!=0)"
378
+ " ORDER BY event.mtime DESC",
379
+ TAG_BRANCH);
380
+ db_prepare(&q,"%s", blob_str(&sql));
381
+ blob_reset(&sql);
382
+ pay = json_stmt_to_array_of_obj(&q, NULL);
383
+ db_finalize(&q);
384
+ assert(NULL != pay);
385
+ if(pay){
386
+ /* get the array-form tags of each record. */
387
+ cson_string * tags = cson_new_string("tags",4);
388
+ cson_string * isLeaf = cson_new_string("isLeaf",6);
389
+ cson_value_add_reference( cson_string_value(tags) );
390
+ cson_value_add_reference( cson_string_value(isLeaf) );
391
+ cson_array * ar = cson_value_get_array(pay);
392
+ unsigned int i = 0;
393
+ unsigned int len = cson_array_length_get(ar);
394
+ for( ; i < len; ++i ){
395
+ cson_object * row = cson_value_get_object(cson_array_get(ar,i));
396
+ int rid = cson_value_get_integer(cson_object_get(row,"rid"));
397
+ if(row>0) {
398
+ cson_object_set_s(row, tags, json_tags_for_rid(rid,0));
399
+ cson_object_set_s(row, isLeaf, json_value_to_bool(cson_object_get(row,"isLeaf")));
400
+ }
401
+ }
402
+ cson_value_free( cson_string_value(tags) );
403
+ cson_value_free( cson_string_value(isLeaf) );
404
+ }
405
+
406
+ goto end;
407
+ error:
408
+ assert( 0 != g.json.resultCode );
409
+ cson_value_free(pay);
410
+
411
+ end:
412
+ return pay;
413
+}
414
+
348415
/*
349416
** Implementation of /json/timeline/ci.
350417
**
351418
** Still a few TODOs (like figuring out how to structure
352419
** inheritance info).
@@ -410,11 +477,11 @@
410477
/*tagId is always null?*/
411478
" tagId AS tagId"
412479
# endif
413480
#endif
414481
" FROM json_timeline"
415
- " ORDER BY sortId");
482
+ " ORDER BY rowid");
416483
listV = cson_value_new_array();
417484
list = cson_value_get_array(listV);
418485
tmp = listV;
419486
SET("timeline");
420487
while( (SQLITE_ROW == db_step(&q) )){
@@ -496,11 +563,11 @@
496563
" tags AS tags," /*FIXME: split this into
497564
a JSON array*/
498565
" tagId AS tagId,"
499566
#endif
500567
" FROM json_timeline"
501
- " ORDER BY sortId",
568
+ " ORDER BY rowid",
502569
-1);
503570
listV = cson_value_new_array();
504571
list = cson_value_get_array(listV);
505572
tmp = listV;
506573
SET("timeline");
@@ -572,11 +639,11 @@
572639
" user AS user,"
573640
" eventType AS eventType,"
574641
" comment AS comment,"
575642
" brief AS briefComment"
576643
" FROM json_timeline"
577
- " ORDER BY sortId",
644
+ " ORDER BY rowid",
578645
-1);
579646
listV = cson_value_new_array();
580647
list = cson_value_get_array(listV);
581648
tmp = listV;
582649
SET("timeline");
583650
--- src/json_timeline.c
+++ src/json_timeline.c
@@ -21,10 +21,11 @@
21
22 #if INTERFACE
23 #include "json_detail.h"
24 #endif
25
 
26 static cson_value * json_timeline_ci();
27 static cson_value * json_timeline_ticket();
28 /*
29 ** Mapping of /json/timeline/XXX commands/paths to callbacks.
30 */
@@ -31,10 +32,11 @@
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},
@@ -111,13 +113,13 @@
111 @ blob.rid IN leaf,
112 @ bgcolor,
113 @ event.type,
114 @ (SELECT group_concat(substr(tagname,5), ',') FROM tag, tagxref
115 @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
116 @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0),
117 @ tagid,
118 @ brief
119 @ FROM event JOIN blob
120 @ WHERE blob.rid=event.objid
121 ;
122 return zBaseSql;
123 }
@@ -343,10 +345,75 @@
343 cson_array_append( rows, rowV );
344 }
345 db_finalize(&q);
346 return rowsV;
347 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348 /*
349 ** Implementation of /json/timeline/ci.
350 **
351 ** Still a few TODOs (like figuring out how to structure
352 ** inheritance info).
@@ -410,11 +477,11 @@
410 /*tagId is always null?*/
411 " tagId AS tagId"
412 # endif
413 #endif
414 " FROM json_timeline"
415 " ORDER BY sortId");
416 listV = cson_value_new_array();
417 list = cson_value_get_array(listV);
418 tmp = listV;
419 SET("timeline");
420 while( (SQLITE_ROW == db_step(&q) )){
@@ -496,11 +563,11 @@
496 " tags AS tags," /*FIXME: split this into
497 a JSON array*/
498 " tagId AS tagId,"
499 #endif
500 " FROM json_timeline"
501 " ORDER BY sortId",
502 -1);
503 listV = cson_value_new_array();
504 list = cson_value_get_array(listV);
505 tmp = listV;
506 SET("timeline");
@@ -572,11 +639,11 @@
572 " user AS user,"
573 " eventType AS eventType,"
574 " comment AS comment,"
575 " brief AS briefComment"
576 " FROM json_timeline"
577 " ORDER BY sortId",
578 -1);
579 listV = cson_value_new_array();
580 list = cson_value_get_array(listV);
581 tmp = listV;
582 SET("timeline");
583
--- src/json_timeline.c
+++ src/json_timeline.c
@@ -21,10 +21,11 @@
21
22 #if INTERFACE
23 #include "json_detail.h"
24 #endif
25
26 static cson_value * json_timeline_branch();
27 static cson_value * json_timeline_ci();
28 static cson_value * json_timeline_ticket();
29 /*
30 ** Mapping of /json/timeline/XXX commands/paths to callbacks.
31 */
@@ -31,10 +32,11 @@
32 static const JsonPageDef JsonPageDefs_Timeline[] = {
33 /* the short forms are only enabled in CLI mode, to avoid
34 that we end up with HTTP clients using 3 different names
35 for the same requests.
36 */
37 {"branch", json_timeline_branch, 0},
38 {"c", json_timeline_ci, -1},
39 {"checkin", json_timeline_ci, 0},
40 {"ci", json_timeline_ci, -1},
41 {"com", json_timeline_ci, -1},
42 {"commit", json_timeline_ci, 0},
@@ -111,13 +113,13 @@
113 @ blob.rid IN leaf,
114 @ bgcolor,
115 @ event.type,
116 @ (SELECT group_concat(substr(tagname,5), ',') FROM tag, tagxref
117 @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
118 @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0) as tags,
119 @ tagid as tagId,
120 @ brief as brief
121 @ FROM event JOIN blob
122 @ WHERE blob.rid=event.objid
123 ;
124 return zBaseSql;
125 }
@@ -343,10 +345,75 @@
345 cson_array_append( rows, rowV );
346 }
347 db_finalize(&q);
348 return rowsV;
349 }
350
351 static cson_value * json_timeline_branch(){
352 cson_value * pay = NULL;
353 Blob sql = empty_blob;
354 Stmt q = empty_Stmt;
355 if(!g.perm.Read){
356 json_set_err(FSL_JSON_E_DENIED,
357 "Requires 'o' permissions.");
358 return NULL;
359 }
360 json_timeline_temp_table();
361 blob_append(&sql,
362 "SELECT"
363 " blob.rid AS rid,"
364 " uuid AS uuid,"
365 " datetime(event.mtime,'utc') as mtime,"
366 " coalesce(ecomment, comment) as comment,"
367 " coalesce(euser, user) as user,"
368 " blob.rid IN leaf as isLeaf,"
369 " bgcolor as bgColor"
370 " FROM event JOIN blob"
371 " WHERE blob.rid=event.objid",
372 -1);
373
374 blob_appendf(&sql,
375 " AND event.type='ci'"
376 " AND blob.rid IN (SELECT rid FROM tagxref"
377 " WHERE tagtype>0 AND tagid=%d AND srcid!=0)"
378 " ORDER BY event.mtime DESC",
379 TAG_BRANCH);
380 db_prepare(&q,"%s", blob_str(&sql));
381 blob_reset(&sql);
382 pay = json_stmt_to_array_of_obj(&q, NULL);
383 db_finalize(&q);
384 assert(NULL != pay);
385 if(pay){
386 /* get the array-form tags of each record. */
387 cson_string * tags = cson_new_string("tags",4);
388 cson_string * isLeaf = cson_new_string("isLeaf",6);
389 cson_value_add_reference( cson_string_value(tags) );
390 cson_value_add_reference( cson_string_value(isLeaf) );
391 cson_array * ar = cson_value_get_array(pay);
392 unsigned int i = 0;
393 unsigned int len = cson_array_length_get(ar);
394 for( ; i < len; ++i ){
395 cson_object * row = cson_value_get_object(cson_array_get(ar,i));
396 int rid = cson_value_get_integer(cson_object_get(row,"rid"));
397 if(row>0) {
398 cson_object_set_s(row, tags, json_tags_for_rid(rid,0));
399 cson_object_set_s(row, isLeaf, json_value_to_bool(cson_object_get(row,"isLeaf")));
400 }
401 }
402 cson_value_free( cson_string_value(tags) );
403 cson_value_free( cson_string_value(isLeaf) );
404 }
405
406 goto end;
407 error:
408 assert( 0 != g.json.resultCode );
409 cson_value_free(pay);
410
411 end:
412 return pay;
413 }
414
415 /*
416 ** Implementation of /json/timeline/ci.
417 **
418 ** Still a few TODOs (like figuring out how to structure
419 ** inheritance info).
@@ -410,11 +477,11 @@
477 /*tagId is always null?*/
478 " tagId AS tagId"
479 # endif
480 #endif
481 " FROM json_timeline"
482 " ORDER BY rowid");
483 listV = cson_value_new_array();
484 list = cson_value_get_array(listV);
485 tmp = listV;
486 SET("timeline");
487 while( (SQLITE_ROW == db_step(&q) )){
@@ -496,11 +563,11 @@
563 " tags AS tags," /*FIXME: split this into
564 a JSON array*/
565 " tagId AS tagId,"
566 #endif
567 " FROM json_timeline"
568 " ORDER BY rowid",
569 -1);
570 listV = cson_value_new_array();
571 list = cson_value_get_array(listV);
572 tmp = listV;
573 SET("timeline");
@@ -572,11 +639,11 @@
639 " user AS user,"
640 " eventType AS eventType,"
641 " comment AS comment,"
642 " brief AS briefComment"
643 " FROM json_timeline"
644 " ORDER BY rowid",
645 -1);
646 listV = cson_value_new_array();
647 list = cson_value_get_array(listV);
648 tmp = listV;
649 SET("timeline");
650

Keyboard Shortcuts

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