|
1
|
#ifdef FOSSIL_ENABLE_JSON |
|
2
|
/* |
|
3
|
** Copyright (c) 2011 D. Richard Hipp |
|
4
|
** |
|
5
|
** This program is free software; you can redistribute it and/or |
|
6
|
** modify it under the terms of the Simplified BSD License (also |
|
7
|
** known as the "2-Clause License" or "FreeBSD License".) |
|
8
|
** |
|
9
|
** This program is distributed in the hope that it will be useful, |
|
10
|
** but without any warranty; without even the implied warranty of |
|
11
|
** merchantability or fitness for a particular purpose. |
|
12
|
** |
|
13
|
** Author contact information: |
|
14
|
** [email protected] |
|
15
|
** http://www.hwaci.com/drh/ |
|
16
|
** |
|
17
|
*/ |
|
18
|
|
|
19
|
#include "config.h" |
|
20
|
#include "json_report.h" |
|
21
|
|
|
22
|
#if INTERFACE |
|
23
|
#include "json_detail.h" |
|
24
|
#endif |
|
25
|
|
|
26
|
|
|
27
|
static cson_value * json_report_create(void); |
|
28
|
static cson_value * json_report_get(void); |
|
29
|
static cson_value * json_report_list(void); |
|
30
|
static cson_value * json_report_run(void); |
|
31
|
static cson_value * json_report_save(void); |
|
32
|
|
|
33
|
/* |
|
34
|
** Mapping of /json/report/XXX commands/paths to callbacks. |
|
35
|
*/ |
|
36
|
static const JsonPageDef JsonPageDefs_Report[] = { |
|
37
|
{"create", json_report_create, 0}, |
|
38
|
{"get", json_report_get, 0}, |
|
39
|
{"list", json_report_list, 0}, |
|
40
|
{"run", json_report_run, 0}, |
|
41
|
{"save", json_report_save, 0}, |
|
42
|
/* Last entry MUST have a NULL name. */ |
|
43
|
{NULL,NULL,0} |
|
44
|
}; |
|
45
|
/* |
|
46
|
** Implementation of the /json/report page. |
|
47
|
** |
|
48
|
** |
|
49
|
*/ |
|
50
|
cson_value * json_page_report(void){ |
|
51
|
if(!g.perm.RdTkt && !g.perm.NewTkt ){ |
|
52
|
json_set_err(FSL_JSON_E_DENIED, |
|
53
|
"Requires 'r' or 'n' permissions."); |
|
54
|
return NULL; |
|
55
|
} |
|
56
|
return json_page_dispatch_helper(JsonPageDefs_Report); |
|
57
|
} |
|
58
|
|
|
59
|
/* |
|
60
|
** Searches the environment for a "report" parameter |
|
61
|
** (CLI: -report/-r #). |
|
62
|
** |
|
63
|
** If one is not found and argPos is >0 then json_command_arg() |
|
64
|
** is checked. |
|
65
|
** |
|
66
|
** Returns >0 (the report number) on success . |
|
67
|
*/ |
|
68
|
static int json_report_get_number(int argPos){ |
|
69
|
int nReport = json_find_option_int("report",NULL,"r",-1); |
|
70
|
if( (nReport<=0) && cson_value_is_integer(g.json.reqPayload.v)){ |
|
71
|
nReport = cson_value_get_integer(g.json.reqPayload.v); |
|
72
|
} |
|
73
|
if( (nReport <= 0) && (argPos>0) ){ |
|
74
|
char const * arg = json_command_arg(argPos); |
|
75
|
if(arg && fossil_isdigit(*arg)) { |
|
76
|
nReport = atoi(arg); |
|
77
|
} |
|
78
|
} |
|
79
|
return nReport; |
|
80
|
} |
|
81
|
|
|
82
|
static cson_value * json_report_create(void){ |
|
83
|
json_set_err(FSL_JSON_E_NYI, NULL); |
|
84
|
return NULL; |
|
85
|
} |
|
86
|
|
|
87
|
static cson_value * json_report_get(void){ |
|
88
|
int nReport; |
|
89
|
Stmt q = empty_Stmt; |
|
90
|
cson_value * pay = NULL; |
|
91
|
|
|
92
|
if(!g.perm.TktFmt){ |
|
93
|
json_set_err(FSL_JSON_E_DENIED, |
|
94
|
"Requires 't' privileges."); |
|
95
|
return NULL; |
|
96
|
} |
|
97
|
nReport = json_report_get_number(3); |
|
98
|
if(nReport <=0){ |
|
99
|
json_set_err(FSL_JSON_E_MISSING_ARGS, |
|
100
|
"Missing or invalid 'report' (-r) parameter."); |
|
101
|
return NULL; |
|
102
|
} |
|
103
|
|
|
104
|
db_prepare(&q,"SELECT rn AS report," |
|
105
|
" owner AS owner," |
|
106
|
" title AS title," |
|
107
|
" cast(strftime('%%s',mtime) as int) as timestamp," |
|
108
|
" cols as columns," |
|
109
|
" sqlcode as sqlCode" |
|
110
|
" FROM reportfmt" |
|
111
|
" WHERE rn=%d", |
|
112
|
nReport); |
|
113
|
if( SQLITE_ROW != db_step(&q) ){ |
|
114
|
db_finalize(&q); |
|
115
|
json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND, |
|
116
|
"Report #%d not found.", nReport); |
|
117
|
return NULL; |
|
118
|
} |
|
119
|
pay = cson_sqlite3_row_to_object(q.pStmt); |
|
120
|
db_finalize(&q); |
|
121
|
return pay; |
|
122
|
} |
|
123
|
|
|
124
|
/* |
|
125
|
** Impl of /json/report/list. |
|
126
|
*/ |
|
127
|
static cson_value * json_report_list(void){ |
|
128
|
Blob sql = empty_blob; |
|
129
|
cson_value * pay = NULL; |
|
130
|
if(!g.perm.RdTkt){ |
|
131
|
json_set_err(FSL_JSON_E_DENIED, |
|
132
|
"Requires 'r' privileges."); |
|
133
|
return NULL; |
|
134
|
} |
|
135
|
blob_append(&sql, "SELECT" |
|
136
|
" rn AS report," |
|
137
|
" title as title," |
|
138
|
" owner as owner" |
|
139
|
" FROM reportfmt" |
|
140
|
" WHERE 1" |
|
141
|
" ORDER BY title", |
|
142
|
-1); |
|
143
|
pay = json_sql_to_array_of_obj(&sql, NULL, 1); |
|
144
|
if(!pay){ |
|
145
|
json_set_err(FSL_JSON_E_UNKNOWN, |
|
146
|
"Quite unexpected: no ticket reports found."); |
|
147
|
} |
|
148
|
return pay; |
|
149
|
} |
|
150
|
|
|
151
|
/* |
|
152
|
** Impl for /json/report/run |
|
153
|
** |
|
154
|
** Options/arguments: |
|
155
|
** |
|
156
|
** report=int (CLI: -report # or -r #) is the report number to run. |
|
157
|
** |
|
158
|
** limit=int (CLI: -limit # or -n #) -n is for compat. with other commands. |
|
159
|
** |
|
160
|
** format=a|o Specifies result format: a=each row is an array, o=each |
|
161
|
** row is an object. Default=o. |
|
162
|
*/ |
|
163
|
static cson_value * json_report_run(void){ |
|
164
|
int nReport; |
|
165
|
Stmt q = empty_Stmt; |
|
166
|
cson_object * pay = NULL; |
|
167
|
cson_array * tktList = NULL; |
|
168
|
char const * zFmt; |
|
169
|
char * zTitle = NULL; |
|
170
|
Blob sql = empty_blob; |
|
171
|
int limit = 0; |
|
172
|
cson_value * colNames = NULL; |
|
173
|
int i; |
|
174
|
|
|
175
|
if(!g.perm.RdTkt){ |
|
176
|
json_set_err(FSL_JSON_E_DENIED, |
|
177
|
"Requires 'r' privileges."); |
|
178
|
return NULL; |
|
179
|
} |
|
180
|
nReport = json_report_get_number(3); |
|
181
|
if(nReport <=0){ |
|
182
|
json_set_err(FSL_JSON_E_MISSING_ARGS, |
|
183
|
"Missing or invalid 'number' (-n) parameter."); |
|
184
|
goto error; |
|
185
|
} |
|
186
|
zFmt = json_find_option_cstr2("format",NULL,"f",3); |
|
187
|
if(!zFmt) zFmt = "o"; |
|
188
|
db_prepare(&q, |
|
189
|
"SELECT sqlcode, " |
|
190
|
" title" |
|
191
|
" FROM reportfmt" |
|
192
|
" WHERE rn=%d", |
|
193
|
nReport); |
|
194
|
if(SQLITE_ROW != db_step(&q)){ |
|
195
|
json_set_err(FSL_JSON_E_INVALID_ARGS, |
|
196
|
"Report number %d not found.", |
|
197
|
nReport); |
|
198
|
db_finalize(&q); |
|
199
|
goto error; |
|
200
|
} |
|
201
|
|
|
202
|
limit = json_find_option_int("limit",NULL,"n",-1); |
|
203
|
|
|
204
|
|
|
205
|
/* Copy over report's SQL...*/ |
|
206
|
blob_append(&sql, db_column_text(&q,0), -1); |
|
207
|
zTitle = fossil_strdup(db_column_text(&q,1)); |
|
208
|
db_finalize(&q); |
|
209
|
db_prepare(&q, "%s", blob_sql_text(&sql)); |
|
210
|
|
|
211
|
/** Build the response... */ |
|
212
|
pay = cson_new_object(); |
|
213
|
|
|
214
|
cson_object_set(pay, "report", json_new_int(nReport)); |
|
215
|
cson_object_set(pay, "title", json_new_string(zTitle)); |
|
216
|
if(limit>0){ |
|
217
|
cson_object_set(pay, "limit", json_new_int((limit<0) ? 0 : limit)); |
|
218
|
} |
|
219
|
free(zTitle); |
|
220
|
zTitle = NULL; |
|
221
|
|
|
222
|
if(g.perm.TktFmt){ |
|
223
|
cson_object_set(pay, "sqlcode", |
|
224
|
cson_value_new_string(blob_str(&sql), |
|
225
|
(unsigned int)blob_size(&sql))); |
|
226
|
} |
|
227
|
blob_reset(&sql); |
|
228
|
|
|
229
|
colNames = cson_sqlite3_column_names(q.pStmt); |
|
230
|
cson_object_set( pay, "columnNames", colNames); |
|
231
|
for( i = 0 ; ((limit>0) ?(i < limit) : 1) |
|
232
|
&& (SQLITE_ROW == db_step(&q)); |
|
233
|
++i){ |
|
234
|
cson_value * row = ('a'==*zFmt) |
|
235
|
? cson_sqlite3_row_to_array(q.pStmt) |
|
236
|
: cson_sqlite3_row_to_object2(q.pStmt, |
|
237
|
cson_value_get_array(colNames)); |
|
238
|
; |
|
239
|
if(row && !tktList){ |
|
240
|
tktList = cson_new_array(); |
|
241
|
} |
|
242
|
cson_array_append(tktList, row); |
|
243
|
} |
|
244
|
db_finalize(&q); |
|
245
|
cson_object_set(pay, "tickets", |
|
246
|
tktList ? cson_array_value(tktList) : cson_value_null()); |
|
247
|
|
|
248
|
goto end; |
|
249
|
|
|
250
|
error: |
|
251
|
assert(0 != g.json.resultCode); |
|
252
|
cson_value_free( cson_object_value(pay) ); |
|
253
|
pay = NULL; |
|
254
|
end: |
|
255
|
|
|
256
|
return pay ? cson_object_value(pay) : NULL; |
|
257
|
|
|
258
|
} |
|
259
|
|
|
260
|
static cson_value * json_report_save(void){ |
|
261
|
return NULL; |
|
262
|
} |
|
263
|
#endif /* FOSSIL_ENABLE_JSON */ |
|
264
|
|