lfapi

annotate lfapi/main.js @ 0:ce6f95d23e1c

Initial checkin
author bsw
date Sat Sep 10 23:31:20 2011 +0200 (2011-09-10)
parents
children 9fe872cc376d
rev   line source
bsw@0 1 var api_version = '0.2.0';
bsw@0 2
bsw@0 3 // creates a random string with the given length
bsw@0 4 function randomString(number_of_chars) {
bsw@0 5 var charset, rand, i, ret;
bsw@0 6 charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
bsw@0 7 random_string = '';
bsw@0 8
bsw@0 9 for (var i = 0; i < number_of_chars; i++) {
bsw@0 10 random_string += charset[parseInt(Math.random() * charset.length)]
bsw@0 11 }
bsw@0 12 return random_string;
bsw@0 13 }
bsw@0 14
bsw@0 15 var fields = require('./fields.js');
bsw@0 16
bsw@0 17 var general_params = require('./general_params.js');
bsw@0 18
bsw@0 19 var config = general_params.config;
bsw@0 20 exports.config = config;
bsw@0 21
bsw@0 22 var db = require('./db.js');
bsw@0 23 exports.db = db;
bsw@0 24
bsw@0 25 var selector = db.selector;
bsw@0 26
bsw@0 27 var email = require('mailer');
bsw@0 28
bsw@0 29
bsw@0 30 // check if current session has at least given access level, returns error to client if not.
bsw@0 31 // used by request handlers below
bsw@0 32 function requireAccessLevel(conn, req, res, access_level, callback) {
bsw@0 33 switch (access_level) {
bsw@0 34 case 'anonymous':
bsw@0 35 if (req.current_access_level == 'anonymous') { callback(); return; };
bsw@0 36 case 'pseudonym':
bsw@0 37 if (req.current_access_level == 'pseudonym') { callback(); return; };
bsw@0 38 case 'full':
bsw@0 39 if (req.current_access_level == 'full') { callback(); return; };
bsw@0 40 case 'member':
bsw@0 41 if (req.current_member_id) { callback(); return; };
bsw@0 42 default:
bsw@0 43 respond('json', conn, req, res, 'forbidden', { error: 'Access denied' });
bsw@0 44 }
bsw@0 45 };
bsw@0 46
bsw@0 47 // callback function, encoding result and sending it to the client
bsw@0 48 function respond(mode, conn, req, res, status, object, err) {
bsw@0 49 var http_status = 500;
bsw@0 50 var command;
bsw@0 51
bsw@0 52 if (status == 'ok') {
bsw@0 53 command = 'COMMIT';
bsw@0 54 } else {
bsw@0 55 command = 'ROLLBACK';
bsw@0 56 };
bsw@0 57
bsw@0 58 switch (status) {
bsw@0 59 case 'ok':
bsw@0 60 http_status = 200;
bsw@0 61 break;
bsw@0 62 case 'forbidden':
bsw@0 63 //http_status = 403;
bsw@0 64 break;
bsw@0 65 case 'notfound':
bsw@0 66 http_status = 404;
bsw@0 67 break;
bsw@0 68 case 'unprocessable':
bsw@0 69 //http_status = 422;
bsw@0 70 break;
bsw@0 71 case 'conflict':
bsw@0 72 //http_status = 409;
bsw@0 73 break;
bsw@0 74 };
bsw@0 75
bsw@0 76 var query;
bsw@0 77 if (mode == 'json' && ! err) query = 'SELECT null';
bsw@0 78 db.query(conn, req, res, query, function(result, conn) {
bsw@0 79 db.query(conn, req, res, command, function (result, conn) {
bsw@0 80
bsw@0 81 if (conn && typeof(conn) != 'string') conn.drain();
bsw@0 82
bsw@0 83 if (mode == 'json') {
bsw@0 84 if (! object) object = {};
bsw@0 85 } else if (mode == 'html') {
bsw@0 86 if (! object) object = 'no content';
bsw@0 87 if (err) object = "Error: " + err;
bsw@0 88 }
bsw@0 89
bsw@0 90 object.status = status;
bsw@0 91 object.error = err;
bsw@0 92
bsw@0 93 if (mode == 'json') {
bsw@0 94 var body = JSON.stringify(object);
bsw@0 95 var content_type = 'application/json';
bsw@0 96 if (req.params && req.params.callback) {
bsw@0 97 body = req.params.callback + '(' + body + ')';
bsw@0 98 content_type = 'text/javascript';
bsw@0 99 }
bsw@0 100 res.writeHead(
bsw@0 101 http_status,
bsw@0 102 {
bsw@0 103 'Content-Type': content_type,
bsw@0 104 //'Content-Length': body.length
bsw@0 105 }
bsw@0 106 );
bsw@0 107 res.end(body);
bsw@0 108 } else if (mode == 'html') {
bsw@0 109 var body = ['<html><head><title>lfapi</title><style>body { font-family: sans-serif; }</style></head><body>']
bsw@0 110 body.push(object)
bsw@0 111 body.push('</body></html>')
bsw@0 112 body = body.join('');
bsw@0 113 res.writeHead(
bsw@0 114 http_status,
bsw@0 115 {
bsw@0 116 'Content-Type': 'text/html',
bsw@0 117 'Content-Length': body.length
bsw@0 118 }
bsw@0 119 );
bsw@0 120 res.end(body);
bsw@0 121 }
bsw@0 122 })
bsw@0 123 });
bsw@0 124 };
bsw@0 125
bsw@0 126 exports.respond = respond;
bsw@0 127 db.error_handler = respond;
bsw@0 128
bsw@0 129 // add requested related data for requests with include_* parameters
bsw@0 130 function addRelatedData(conn, req, res, result, includes) {
bsw@0 131 if (includes.length > 0) {
bsw@0 132 var include = includes.shift();
bsw@0 133 var class = include.class;
bsw@0 134 var objects = result[include.objects];
bsw@0 135
bsw@0 136 var query;
bsw@0 137
bsw@0 138 if (objects) {
bsw@0 139 var objects_exists = false;
bsw@0 140 query = new selector.Selector();
bsw@0 141 var ids_hash = {};
bsw@0 142 if (typeof(objects) == 'array') {
bsw@0 143 if (objects.length > 0) {
bsw@0 144 objects_exists = true;
bsw@0 145 objects.forEach( function(object) {
bsw@0 146 if (object[class + "_id"]) {
bsw@0 147 ids_hash[object[class + "_id"]] = true;
bsw@0 148 };
bsw@0 149 });
bsw@0 150 }
bsw@0 151 } else {
bsw@0 152 for (var key in objects) {
bsw@0 153 objects_exists = true;
bsw@0 154 var object = objects[key];
bsw@0 155 if (object[class + "_id"]) {
bsw@0 156 ids_hash[object[class + "_id"]] = true;
bsw@0 157 };
bsw@0 158 };
bsw@0 159 };
bsw@0 160
bsw@0 161 if (objects_exists) {
bsw@0 162 var ids = [];
bsw@0 163 for (key in ids_hash) {
bsw@0 164 ids.push(key)
bsw@0 165 }
bsw@0 166
bsw@0 167 query.from(class);
bsw@0 168 query.addWhere([class + '.id IN (??)', ids]);
bsw@0 169 fields.addObjectFields(query, class);
bsw@0 170 };
bsw@0 171 };
bsw@0 172
bsw@0 173 db.query(conn, req, res, query, function (result2, conn) {
bsw@0 174 // add result to main result, regarding correct pluralization
bsw@0 175 var tmp = {};
bsw@0 176 if (result2) {
bsw@0 177 result2.rows.forEach( function(row) {
bsw@0 178 tmp[row.id] = row;
bsw@0 179 });
bsw@0 180 };
bsw@0 181
bsw@0 182 if (class == 'policy') {
bsw@0 183 result['policies'] = tmp;
bsw@0 184 } else {
bsw@0 185 result[class + 's'] = tmp;
bsw@0 186 }
bsw@0 187 addRelatedData(conn, req, res, result, includes);
bsw@0 188 });
bsw@0 189 } else {
bsw@0 190 respond('json', conn, req, res, 'ok', result);
bsw@0 191 };
bsw@0 192
bsw@0 193 };
bsw@0 194
bsw@0 195 function lockMemberById(conn, req, res, member_id, callback) {
bsw@0 196 var query = new selector.Selector('member');
bsw@0 197 query.addField('NULL');
bsw@0 198 query.addWhere(['member.id = ?', member_id]);
bsw@0 199 query.forUpdate();
bsw@0 200 db.query(conn, req, res, query, callback);
bsw@0 201 };
bsw@0 202
bsw@0 203 function requireUnitPrivilege(conn, req, res, unit_id, callback) {
bsw@0 204 var query = new selector.Selector('privilege');
bsw@0 205 query.addField('NULL');
bsw@0 206 query.addWhere(['privilege.member_id = ?', req.current_member_id]);
bsw@0 207 query.addWhere(['privilege.unit_id = ?', unit_id ]);
bsw@0 208 query.addWhere('privilege.voting_right');
bsw@0 209 query.forShareOf('privilege');
bsw@0 210 db.query(conn, req, res, query, function(result, conn) {
bsw@0 211 if (result.rows.length != 1) {
bsw@0 212 respond('json', conn, req, res, 'forbidden', null, 'You have no voting right for this unit.');
bsw@0 213 return;
bsw@0 214 }
bsw@0 215 callback();
bsw@0 216 });
bsw@0 217 };
bsw@0 218
bsw@0 219 function requireAreaPrivilege(conn, req, res, area_id, callback) {
bsw@0 220 var query = new selector.Selector('privilege');
bsw@0 221 query.join('area', null, 'area.unit_id = privilege.unit_id');
bsw@0 222 query.addField('NULL');
bsw@0 223 query.addWhere(['privilege.member_id = ?', req.current_member_id]);
bsw@0 224 query.addWhere(['area.id = ?', area_id ]);
bsw@0 225 query.addWhere('privilege.voting_right');
bsw@0 226 query.forShareOf('privilege');
bsw@0 227 db.query(conn, req, res, query, function(result, conn) {
bsw@0 228 if (result.rows.length != 1) {
bsw@0 229 respond('json', conn, req, res, 'forbidden', null, 'You have no voting right for areas in this unit.');
bsw@0 230 return;
bsw@0 231 }
bsw@0 232 callback();
bsw@0 233 });
bsw@0 234 };
bsw@0 235
bsw@0 236 function requireIssuePrivilege(conn, req, res, issue_id, callback) {
bsw@0 237 var query = new selector.Selector('privilege');
bsw@0 238 query.join('area', null, 'area.unit_id = privilege.unit_id');
bsw@0 239 query.join('issue', null, 'issue.area_id = area.id');
bsw@0 240 query.addField('NULL');
bsw@0 241 query.addWhere(['privilege.member_id = ?', req.current_member_id]);
bsw@0 242 query.addWhere(['issue.id = ?', issue_id ]);
bsw@0 243 query.addWhere('privilege.voting_right');
bsw@0 244 query.forShareOf('privilege');
bsw@0 245 db.query(conn, req, res, query, function(result, conn) {
bsw@0 246 if (result.rows.length != 1) {
bsw@0 247 respond('json', conn, req, res, 'forbidden', null, 'You have no voting right for issues in this unit.');
bsw@0 248 return;
bsw@0 249 }
bsw@0 250 callback();
bsw@0 251 });
bsw@0 252 };
bsw@0 253
bsw@0 254 function requireInitiativePrivilege(conn, req, res, initiative_id, callback) {
bsw@0 255 var query = new selector.Selector('privilege');
bsw@0 256 query.join('area', null, 'area.unit_id = privilege.unit_id');
bsw@0 257 query.join('issue', null, 'issue.area_id = area.id');
bsw@0 258 query.join('initiative', null, 'initiative.issue_id = issue.id');
bsw@0 259 query.addField('NULL');
bsw@0 260 query.addWhere(['privilege.member_id = ?', req.current_member_id]);
bsw@0 261 query.addWhere(['initiative.id = ?', initiative_id ]);
bsw@0 262 query.addWhere('privilege.voting_right');
bsw@0 263 query.forShareOf('privilege');
bsw@0 264 db.query(conn, req, res, query, function(result, conn) {
bsw@0 265 if (result.rows.length != 1) {
bsw@0 266 respond('json', conn, req, res, 'forbidden', null, 'You have no voting right for initiatives in this unit.');
bsw@0 267 return;
bsw@0 268 }
bsw@0 269 callback();
bsw@0 270 });
bsw@0 271 };
bsw@0 272
bsw@0 273 function requireIssueState(conn, req, res, issue_id, required_states, callback) {
bsw@0 274 var query = new selector.Selector('issue');
bsw@0 275 query.addField('NULL');
bsw@0 276 query.addWhere(['issue.id = ?', issue_id]);
bsw@0 277 query.addWhere(['issue.state IN (??)', required_states]);
bsw@0 278 query.forUpdateOf('issue');
bsw@0 279 db.query(conn, req, res, query, function(result, conn) {
bsw@0 280 if (result.rows.length != 1) {
bsw@0 281 respond('json', conn, req, res, 'forbidden', null, 'Issue is in wrong state.');
bsw@0 282 return;
bsw@0 283 }
bsw@0 284 callback();
bsw@0 285 });
bsw@0 286 };
bsw@0 287
bsw@0 288 function requireIssueStateForInitiative(conn, req, res, initiative_id, required_states, callback) {
bsw@0 289 var query = new selector.Selector('issue');
bsw@0 290 query.join('initiative', null, 'initiative.issue_id = issue.id');
bsw@0 291 query.addField('NULL');
bsw@0 292 query.addWhere(['initiative.id = ?', initiative_id]);
bsw@0 293 query.addWhere(['issue.state IN (??)', required_states]);
bsw@0 294 query.forUpdateOf('issue');
bsw@0 295 db.query(conn, req, res, query, function(result, conn) {
bsw@0 296 if (result.rows.length != 1) {
bsw@0 297 respond('json', conn, req, res, 'forbidden', null, 'Issue is in wrong state.');
bsw@0 298 return;
bsw@0 299 }
bsw@0 300 callback();
bsw@0 301 });
bsw@0 302 }
bsw@0 303
bsw@0 304 function requireContingentLeft(conn, req, res, is_initiative, callback) {
bsw@0 305 var query = new selector.Selector('member_contingent_left');
bsw@0 306 query.addField('NULL');
bsw@0 307 query.addWhere(['member_contingent_left.member_id = ?', req.current_member_id]);
bsw@0 308 query.addWhere('member_contingent_left.text_entries_left >= 1');
bsw@0 309 if (is_initiative) {
bsw@0 310 query.addWhere('member_contingent_left.initiatives_left >= 1');
bsw@0 311 }
bsw@0 312 db.query(conn, req, res, query, function(result, conn) {
bsw@0 313 if (result.rows.length != 1) {
bsw@0 314 respond('json', conn, req, res, 'forbidden', null, 'Contingent empty.');
bsw@0 315 return;
bsw@0 316 }
bsw@0 317 callback();
bsw@0 318 });
bsw@0 319 }
bsw@0 320
bsw@0 321 // ==========================================================================
bsw@0 322 // GETT methods
bsw@0 323 // ==========================================================================
bsw@0 324
bsw@0 325
bsw@0 326 exports.get = {
bsw@0 327
bsw@0 328 // startpage (html) for users
bsw@0 329 // currently used for implementing public alpha test
bsw@0 330 '/': function (conn, req, res, params) {
bsw@0 331
bsw@0 332 var html = [];
bsw@0 333 html.push('<h2>welcome to lfapi public developer alpha test</h2>');
bsw@0 334 html.push('<p>This service is provided for testing purposes and is <i><b>dedicated to developers interested in creating applications</b></i> based on LiquidFeedback.</p>');
bsw@0 335 html.push('<h2>how to use</h2>');
bsw@0 336 html.push('<p>The programming interface is described in the <a href="http://dev.liquidfeedback.org/trac/lf/wiki/API">LiquidFeedback API specification</a>.</p>')
bsw@0 337 html.push('<p>The current implementation status of lfapi is published at the <a href="http://dev.liquidfeedback.org/trac/lf/wiki/lfapi">LiquidFeedback API server</a> page in our Wiki.</p>');
bsw@0 338 html.push('<p><b><i>Neither the API specification nor the implementation of lfapi is finished yet.</i></b> This public test should enable developers to join the specification process of the programming interface and makes it possible to start creating applications.</p>');
bsw@0 339 html.push('<h2>questions and suggestions</h2>');
bsw@0 340 html.push('<p>Please use our <a href="http://dev.liquidfeedback.org/cgi-bin/mailman/listinfo/main">public mailing list</a> if you have any questions or suggestions.</p>');
bsw@0 341 html.push('<h2>developer registration</h2>');
bsw@0 342 html.push('<p>To register as developer and receive an account, please submit the following form. You\'ll receive an email with instructions to complete the registration process by verifying your email address.<br />');
bsw@0 343 html.push('<form action="register_test" method="POST">');
bsw@0 344 html.push('<label for="name">Your name:</label> <input type="text" id="name" name="name" /> &nbsp; &nbsp; ');
bsw@0 345 html.push('<label for="email">Email address:</label> <input type="text" id="email" name="email" /> &nbsp; &nbsp; ');
bsw@0 346 html.push('<label for="location">Location:</label> <select name="location" id="location"><option value="earth">Earth</option><option value="moon">Moon</option><option value="mars">Mars</option></select>');
bsw@0 347 html.push('<br />');
bsw@0 348 html.push('<br />');
bsw@0 349 html.push('<div style="border: 2px solid #c00000; background-color: #ffa0a0; padding: 1ex;">');
bsw@0 350 html.push('<b>WARNING:</b> All data you entered above and all data you enter later while using the system and all data you are submitting via the programming interface will be stored in the LiquidFeedback database and published. Every access to the system is subject of tracing and logging for development purposes.<br />Please notice, this is a <b>public alpha test dedicated to developers</b>: serious errors can happen, private data unintentionally published or even <a href="http://en.wikipedia.org/wiki/Grey_goo"> grey goo</a> can appear without further warning. Everything is <b>ON YOUR OWN RISK</b>!');
bsw@0 351 html.push('<br />');
bsw@0 352 html.push('<br />');
bsw@0 353 html.push('<input type="checkbox" name="understood" value="understood" /> I understand the previous warning and I understand that everything is on my own risk.<br />');
bsw@0 354 html.push('</div>');
bsw@0 355 html.push('<br />');
bsw@0 356 html.push('<input type="submit" value="Register account" />');
bsw@0 357 respond('html', null, req, res, 'ok', html.join(''));
bsw@0 358 },
bsw@0 359
bsw@0 360 // temporary method to implement public alpha test
bsw@0 361 '/register_test_confirm': function (conn, req, res, params) {
bsw@0 362 var secret = params.secret;
bsw@0 363
bsw@0 364 var query = new selector.Selector('member');
bsw@0 365 query.addField('member.id, member.notify_email_unconfirmed');
bsw@0 366 query.addWhere(['member.notify_email_secret = ?', secret]);
bsw@0 367 db.query(conn, req, res, query, function (result, conn) {
bsw@0 368 var member = result.rows[0];
bsw@0 369 if (member) {
bsw@0 370 var query = new selector.SQLUpdate('member');
bsw@0 371 query.addValues({
bsw@0 372 notify_email: member.notify_email_unconfirmed,
bsw@0 373 notify_email_secret: null,
bsw@0 374 notify_email_unconfirmed: null,
bsw@0 375 active: true,
bsw@0 376 activated: 'now',
bsw@0 377 active: true,
bsw@0 378 last_activity: 'now',
bsw@0 379 locked: false
bsw@0 380 });
bsw@0 381 query.addWhere(['id = ?', member.id]);
bsw@0 382 db.query(conn, req, res, query, function (err, result) {
bsw@0 383 respond('html', conn, req, res, 'ok', 'Account activated: ');
bsw@0 384 });
bsw@0 385 } else {
bsw@0 386 respond('html', conn, req, res, 'forbidden', 'Secret not valid or already used.');
bsw@0 387 }
bsw@0 388 })
bsw@0 389 },
bsw@0 390
bsw@0 391 '/info': function (conn, req, res, params) {
bsw@0 392 requireAccessLevel(conn, req, res, 'anonymous', function() {
bsw@0 393 var query = new selector.Selector();
bsw@0 394 query.from('"liquid_feedback_version"');
bsw@0 395 query.addField('"liquid_feedback_version".*');
bsw@0 396 db.query(conn, req, res, query, function (result, conn) {
bsw@0 397 var liquid_feedback_version = result.rows[0];
bsw@0 398 respond('json', conn, req, res, 'ok', {
bsw@0 399 core_version: liquid_feedback_version.string,
bsw@0 400 api_version: api_version,
bsw@0 401 current_access_level: req.current_member_id ? 'member' : req.current_access_level,
bsw@0 402 current_member_id: req.current_member_id,
bsw@0 403 settings: config.settings
bsw@0 404 });
bsw@0 405 });
bsw@0 406 });
bsw@0 407 },
bsw@0 408
bsw@0 409 '/member_count': function (conn, req, res, params) {
bsw@0 410 requireAccessLevel(conn, req, res, 'anonymous', function() {
bsw@0 411 var query = new selector.Selector();
bsw@0 412 query.from('"member_count"');
bsw@0 413 query.addField('"member_count".*');
bsw@0 414 db.query(conn, req, res, query, function (result, conn) {
bsw@0 415 var member_count = result.rows[0];
bsw@0 416 respond('json', conn, req, res, 'ok', {
bsw@0 417 member_count: member_count.total_count,
bsw@0 418 member_count_calculated: member_count.calculated
bsw@0 419 });
bsw@0 420 });
bsw@0 421 });
bsw@0 422 },
bsw@0 423
bsw@0 424 '/contingent': function (conn, req, res, params) {
bsw@0 425 requireAccessLevel(conn, req, res, 'anonymous', function() {
bsw@0 426 var query = new selector.Selector();
bsw@0 427 query.from('"contingent"');
bsw@0 428 query.addField('"contingent".*');
bsw@0 429 db.query(conn, req, res, query, function (result, conn) {
bsw@0 430 respond('json', conn, req, res, 'ok', { result: result.rows });
bsw@0 431 });
bsw@0 432 });
bsw@0 433 },
bsw@0 434
bsw@0 435 '/contingent_left': function (conn, req, res, params) {
bsw@0 436 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 437 var query = new selector.Selector();
bsw@0 438 query.from('"member_contingent_left"');
bsw@0 439 query.addField('"member_contingent_left".text_entries_left');
bsw@0 440 query.addField('"member_contingent_left".initiatives_left');
bsw@0 441 query.addWhere(['member_id = ?', req.current_member_id]);
bsw@0 442 db.query(conn, req, res, query, function (result, conn) {
bsw@0 443 respond('json', conn, req, res, 'ok', { result: result.rows[0] });
bsw@0 444 });
bsw@0 445 });
bsw@0 446 },
bsw@0 447
bsw@0 448 '/member': function (conn, req, res, params) {
bsw@0 449 requireAccessLevel(conn, req, res, 'pseudonym', function() {
bsw@0 450 var query = new selector.Selector();
bsw@0 451 query.from('"member"');
bsw@0 452 if (req.current_access_level == 'pseudonym' && !req.current_member_id ) {
bsw@0 453 fields.addObjectFields(query, 'member', 'member_pseudonym');
bsw@0 454 } else {
bsw@0 455 fields.addObjectFields(query, 'member');
bsw@0 456 }
bsw@0 457 general_params.addMemberOptions(req, query, params);
bsw@0 458 query.addOrderBy('"member"."id"');
bsw@0 459 general_params.addLimitAndOffset(query, params);
bsw@0 460 db.query(conn, req, res, query, function (result, conn) {
bsw@0 461 respond('json', conn, req, res, 'ok', { result: result.rows });
bsw@0 462 });
bsw@0 463 });
bsw@0 464 },
bsw@0 465
bsw@0 466 '/member_history': function (conn, req, res, params) {
bsw@0 467 requireAccessLevel(conn, req, res, 'full', function() {
bsw@0 468 var query = new selector.Selector();
bsw@0 469 query.from('"member_history" JOIN "member" ON "member"."id" = "member_history"."member_id"');
bsw@0 470 query.addField('"member_history".*');
bsw@0 471 general_params.addMemberOptions(req, query, params);
bsw@0 472 query.addOrderBy('member_history.id');
bsw@0 473 general_params.addLimitAndOffset(query, params);
bsw@0 474 db.query(conn, req, res, query, function (member_history_result, conn) {
bsw@0 475 var result = { result: member_history_result.rows }
bsw@0 476 includes = [];
bsw@0 477 if (params.include_members) includes.push({ class: 'member', objects: 'result'});
bsw@0 478 addRelatedData(conn, req, res, result, includes);
bsw@0 479 });
bsw@0 480 });
bsw@0 481 },
bsw@0 482
bsw@0 483 '/member_image': function (conn, req, res, params) {
bsw@0 484 requireAccessLevel(conn, req, res, 'full', function() {
bsw@0 485 var query = new selector.Selector();
bsw@0 486 query.from('"member_image" JOIN "member" ON "member"."id" = "member_image"."member_id"');
bsw@0 487 query.addField('"member_image".*');
bsw@0 488 query.addWhere('member_image.scaled');
bsw@0 489 general_params.addMemberOptions(req, query, params);
bsw@0 490 query.addOrderBy = ['member_image.member_id, member_image.image_type'];
bsw@0 491 db.query(conn, req, res, query, function (result, conn) {
bsw@0 492 respond('json', conn, req, res, 'ok', { result: result.rows });
bsw@0 493 });
bsw@0 494 });
bsw@0 495 },
bsw@0 496
bsw@0 497 '/contact': function (conn, req, res, params) {
bsw@0 498 requireAccessLevel(conn, req, res, 'pseudonym', function() {
bsw@0 499 var query = new selector.Selector();
bsw@0 500 query.from('contact JOIN member ON member.id = contact.member_id');
bsw@0 501 query.addField('"contact".*');
bsw@0 502 if (req.current_member_id) {
bsw@0 503 // public or own for members
bsw@0 504 query.addWhere(['"contact"."public" OR "contact"."member_id" = ?', req.current_member_id]);
bsw@0 505 } else {
bsw@0 506 // public for everybody
bsw@0 507 query.addWhere('"contact"."public"');
bsw@0 508 }
bsw@0 509 general_params.addMemberOptions(req, query, params);
bsw@0 510 query.addOrderBy('"contact"."id"');
bsw@0 511 general_params.addLimitAndOffset(query, params);
bsw@0 512 db.query(conn, req, res, query, function (result, conn) {
bsw@0 513 respond('json', conn, req, res, 'ok', { result: result.rows });
bsw@0 514 });
bsw@0 515 });
bsw@0 516 },
bsw@0 517
bsw@0 518 '/privilege': function (conn, req, res, params) {
bsw@0 519 requireAccessLevel(conn, req, res, 'pseudonym', function() {
bsw@0 520 var query = new selector.Selector();
bsw@0 521 query.from('privilege JOIN member ON member.id = privilege.member_id JOIN unit ON unit.id = privilege.unit_id');
bsw@0 522 query.addField('privilege.*');
bsw@0 523 general_params.addUnitOptions(req, query, params);
bsw@0 524 general_params.addMemberOptions(req, query, params);
bsw@0 525 query.addOrderBy('privilege.unit_id, privilege.member_id');
bsw@0 526 general_params.addLimitAndOffset(query, params);
bsw@0 527 db.query(conn, req, res, query, function (privilege_result, conn) {
bsw@0 528 var result = { result: privilege_result.rows }
bsw@0 529 includes = [];
bsw@0 530 if (params.include_units) includes.push({ class: 'unit', objects: 'result'});
bsw@0 531 if (params.include_members) includes.push({ class: 'member', objects: 'result'});
bsw@0 532 addRelatedData(conn, req, res, result, includes);
bsw@0 533 });
bsw@0 534 });
bsw@0 535 },
bsw@0 536
bsw@0 537 '/policy': function (conn, req, res, params) {
bsw@0 538 requireAccessLevel(conn, req, res, 'anonymous', function() {
bsw@0 539 var query = new selector.Selector();
bsw@0 540 query.from('"policy"');
bsw@0 541 query.addField('"policy".*');
bsw@0 542 general_params.addPolicyOptions(req, query, params);
bsw@0 543 query.addOrderBy('"policy"."index"');
bsw@0 544 general_params.addLimitAndOffset(query, params);
bsw@0 545 db.query(conn, req, res, query, function (result, conn) {
bsw@0 546 respond('json', conn, req, res, 'ok', { result: result.rows });
bsw@0 547 });
bsw@0 548 });
bsw@0 549 },
bsw@0 550
bsw@0 551 '/unit': function (conn, req, res, params) {
bsw@0 552 requireAccessLevel(conn, req, res, 'anonymous', function() {
bsw@0 553 var query = new selector.Selector();
bsw@0 554 query.from('"unit"');
bsw@0 555 fields.addObjectFields(query, 'unit');
bsw@0 556 general_params.addUnitOptions(req, query, params);
bsw@0 557 query.addOrderBy('unit.id');
bsw@0 558 general_params.addLimitAndOffset(query, params);
bsw@0 559 db.query(conn, req, res, query, function (result, conn) {
bsw@0 560 respond('json', conn, req, res, 'ok', { result: result.rows });
bsw@0 561 });
bsw@0 562 });
bsw@0 563 },
bsw@0 564
bsw@0 565 '/area': function (conn, req, res, params) {
bsw@0 566 requireAccessLevel(conn, req, res, 'anonymous', function() {
bsw@0 567 var query = new selector.Selector();
bsw@0 568 query.from('area JOIN unit ON area.unit_id = unit.id');
bsw@0 569 fields.addObjectFields(query, 'area');
bsw@0 570 general_params.addAreaOptions(req, query, params);
bsw@0 571 query.addOrderBy('area.id');
bsw@0 572 general_params.addLimitAndOffset(query, params);
bsw@0 573 db.query(conn, req, res, query, function (area_result, conn) {
bsw@0 574 var result = { result: area_result.rows }
bsw@0 575 includes = [];
bsw@0 576 if (params.include_units) includes.push({ class: 'unit', objects: 'result'});
bsw@0 577 addRelatedData(conn, req, res, result, includes);
bsw@0 578 });
bsw@0 579 });
bsw@0 580 },
bsw@0 581
bsw@0 582 '/allowed_policy': function (conn, req, res, params) {
bsw@0 583 requireAccessLevel(conn, req, res, 'anonymous', function() {
bsw@0 584 var query = new selector.Selector();
bsw@0 585 query.from('allowed_policy');
bsw@0 586 query.join('area', null, 'area.id = allowed_policy.area_id');
bsw@0 587 query.join('unit', null, 'unit.id = area.unit_id');
bsw@0 588 query.addField('allowed_policy.*');
bsw@0 589 general_params.addAreaOptions(req, query, params);
bsw@0 590 query.addOrderBy('allowed_policy.area_id, allowed_policy.policy_id');
bsw@0 591 general_params.addLimitAndOffset(query, params);
bsw@0 592 db.query(conn, req, res, query, function (allowed_policy_result, conn) {
bsw@0 593 var result = { result: allowed_policy_result.rows }
bsw@0 594 includes = [];
bsw@0 595 if (params.include_policies) includes.push({ class: 'policy', objects: 'result'});
bsw@0 596 if (params.include_areas) includes.push({ class: 'area', objects: 'result'});
bsw@0 597 if (params.include_units) includes.push({ class: 'unit', objects: 'areas'});
bsw@0 598 addRelatedData(conn, req, res, result, includes);
bsw@0 599 });
bsw@0 600 }); },
bsw@0 601
bsw@0 602 '/membership': function (conn, req, res, params) {
bsw@0 603 requireAccessLevel(conn, req, res, 'pseudonym', function() {
bsw@0 604 var query = new selector.Selector();
bsw@0 605 query.from('membership JOIN member ON membership.member_id = member.id JOIN area ON area.id = membership.area_id JOIN unit ON unit.id = area.unit_id');
bsw@0 606 query.addField('membership.*');
bsw@0 607 general_params.addAreaOptions(req, query, params);
bsw@0 608 general_params.addMemberOptions(req, query, params);
bsw@0 609 query.addOrderBy('membership.area_id, membership.member_id');
bsw@0 610 general_params.addLimitAndOffset(query, params);
bsw@0 611 db.query(conn, req, res, query, function (membership_result, conn) {
bsw@0 612 var result = { result: membership_result.rows }
bsw@0 613 includes = [];
bsw@0 614 if (params.include_members) includes.push({ class: 'member', objects: 'result'});
bsw@0 615 if (params.include_areas) includes.push({ class: 'area', objects: 'result'});
bsw@0 616 if (params.include_units) includes.push({ class: 'unit', objects: 'areas'});
bsw@0 617 addRelatedData(conn, req, res, result, includes);
bsw@0 618 });
bsw@0 619 });
bsw@0 620 },
bsw@0 621
bsw@0 622 '/issue': function (conn, req, res, params) {
bsw@0 623 requireAccessLevel(conn, req, res, 'anonymous', function() {
bsw@0 624 var query = new selector.Selector()
bsw@0 625 query.from('issue JOIN policy ON policy.id = issue.policy_id JOIN area ON area.id = issue.area_id JOIN unit ON area.unit_id = unit.id');
bsw@0 626 fields.addObjectFields(query, 'issue');
bsw@0 627 general_params.addIssueOptions(req, query, params);
bsw@0 628 query.addOrderBy('issue.id');
bsw@0 629 general_params.addLimitAndOffset(query, params);
bsw@0 630 db.query(conn, req, res, query, function (issue_result, conn) {
bsw@0 631 var result = { result: issue_result.rows }
bsw@0 632 includes = [];
bsw@0 633 if (params.include_areas) includes.push({ class: 'area', objects: 'result'});
bsw@0 634 if (params.include_units) includes.push({ class: 'unit', objects: 'areas'});
bsw@0 635 if (params.include_policies) includes.push({ class: 'policy', objects: 'result' });
bsw@0 636 addRelatedData(conn, req, res, result, includes);
bsw@0 637 });
bsw@0 638 });
bsw@0 639 },
bsw@0 640
bsw@0 641 '/interest': function (conn, req, res, params) {
bsw@0 642 requireAccessLevel(conn, req, res, 'pseudonym', function() {
bsw@0 643 var query = new selector.Selector();
bsw@0 644 query.from('interest JOIN member ON member.id = interest.member_id JOIN issue on interest.issue_id = issue.id JOIN policy ON policy.id = issue.policy_id JOIN area ON area.id = issue.area_id JOIN unit ON area.unit_id = unit.id');
bsw@0 645 query.addField('interest.*');
bsw@0 646 general_params.addMemberOptions(req, query, params);
bsw@0 647 general_params.addIssueOptions(req, query, params);
bsw@0 648 query.addOrderBy('interest.issue_id, interest.member_id');
bsw@0 649 general_params.addLimitAndOffset(query, params);
bsw@0 650 db.query(conn, req, res, query, function (interest_result, conn) {
bsw@0 651 var result = { result: interest_result.rows }
bsw@0 652 includes = [];
bsw@0 653 if (params.include_members) includes.push({ class: 'member', objects: 'result'});
bsw@0 654 if (params.include_issues) includes.push({ class: 'issue', objects: 'result'});
bsw@0 655 if (params.include_areas) includes.push({ class: 'area', objects: 'issues'});
bsw@0 656 if (params.include_units) includes.push({ class: 'unit', objects: 'areas'});
bsw@0 657 if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' });
bsw@0 658 addRelatedData(conn, req, res, result, includes);
bsw@0 659 });
bsw@0 660 });
bsw@0 661 },
bsw@0 662
bsw@0 663 '/issue_comment': function (conn, req, res, params) {
bsw@0 664 requireAccessLevel(conn, req, res, 'pseudonym', function() {
bsw@0 665 var query = new selector.Selector();
bsw@0 666 query.from('issue_comment JOIN member ON member.id = issue_comment.member_id JOIN issue on issue_comment.issue_id = issue.id JOIN policy ON policy.id = issue.policy_id JOIN area ON area.id = issue.area_id JOIN unit ON area.unit_id = unit.id');
bsw@0 667 query.addField('issue_comment.*');
bsw@0 668 general_params.addMemberOptions(req, query, params);
bsw@0 669 general_params.addIssueOptions(req, query, params);
bsw@0 670 query.addOrderBy('issue_comment.issue_id, issue_comment.member_id');
bsw@0 671 general_params.addLimitAndOffset(query, params);
bsw@0 672 db.query(conn, req, res, query, function (issue_comment_result, conn) {
bsw@0 673 var result = { result: issue_comment_result.rows }
bsw@0 674 includes = [];
bsw@0 675 if (params.include_members) includes.push({ class: 'member', objects: 'result'});
bsw@0 676 if (params.include_issues) includes.push({ class: 'issue', objects: 'result'});
bsw@0 677 if (params.include_areas) includes.push({ class: 'area', objects: 'issues'});
bsw@0 678 if (params.include_units) includes.push({ class: 'unit', objects: 'areas'});
bsw@0 679 if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' });
bsw@0 680 addRelatedData(conn, req, res, result, includes);
bsw@0 681 });
bsw@0 682 });
bsw@0 683 },
bsw@0 684
bsw@0 685 '/initiative': function (conn, req, res, params) {
bsw@0 686 requireAccessLevel(conn, req, res, 'anonymous', function() {
bsw@0 687 var query = new selector.Selector();
bsw@0 688 query.from('initiative JOIN issue ON issue.id = initiative.issue_id JOIN policy ON policy.id = issue.policy_id JOIN area ON area.id = issue.area_id JOIN unit ON area.unit_id = unit.id');
bsw@0 689 fields.addObjectFields(query, 'initiative');
bsw@0 690 general_params.addInitiativeOptions(req, query, params);
bsw@0 691 query.addOrderBy('initiative.issue_id, initiative.id');
bsw@0 692 general_params.addLimitAndOffset(query, params);
bsw@0 693 db.query(conn, req, res, query, function (initiative_result, conn) {
bsw@0 694 var result = { result: initiative_result.rows }
bsw@0 695 includes = [];
bsw@0 696 if (params.include_issues) includes.push({ class: 'issue', objects: 'result'});
bsw@0 697 if (params.include_areas) includes.push({ class: 'area', objects: 'issues'});
bsw@0 698 if (params.include_units) includes.push({ class: 'unit', objects: 'areas'});
bsw@0 699 if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' });
bsw@0 700 addRelatedData(conn, req, res, result, includes);
bsw@0 701 });
bsw@0 702 });
bsw@0 703 },
bsw@0 704
bsw@0 705 '/initiator': function (conn, req, res, params) {
bsw@0 706 requireAccessLevel(conn, req, res, 'pseudonym', function() {
bsw@0 707 var fields = ['initiator.initiative_id', 'initiator.member_id'];
bsw@0 708 var query = new selector.Selector();
bsw@0 709 query.from('initiator JOIN member ON member.id = initiator.member_id JOIN initiative ON initiative.id = initiator.initiative_id JOIN issue ON issue.id = initiative.issue_id JOIN policy ON policy.id = issue.policy_id JOIN area ON area.id = issue.area_id JOIN unit ON area.unit_id = unit.id');
bsw@0 710 query.addWhere('initiator.accepted');
bsw@0 711 fields.forEach( function(field) {
bsw@0 712 query.addField(field, null, ['grouped']);
bsw@0 713 });
bsw@0 714 general_params.addMemberOptions(req, query, params);
bsw@0 715 general_params.addInitiativeOptions(req, query, params);
bsw@0 716 query.addOrderBy('initiator.initiative_id, initiator.member_id');
bsw@0 717 general_params.addLimitAndOffset(query, params);
bsw@0 718 db.query(conn, req, res, query, function (initiator, conn) {
bsw@0 719 var result = { result: initiator.rows }
bsw@0 720 includes = [];
bsw@0 721 if (params.include_initiatives) includes.push({ class: 'initiative', objects: 'result'});
bsw@0 722 if (params.include_issues) includes.push({ class: 'issue', objects: 'initiatives'});
bsw@0 723 if (params.include_areas) includes.push({ class: 'area', objects: 'issues'});
bsw@0 724 if (params.include_units) includes.push({ class: 'unit', objects: 'areas'});
bsw@0 725 if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' });
bsw@0 726 addRelatedData(conn, req, res, result, includes);
bsw@0 727 });
bsw@0 728 });
bsw@0 729 },
bsw@0 730
bsw@0 731
bsw@0 732 '/supporter': function (conn, req, res, params) {
bsw@0 733 requireAccessLevel(conn, req, res, 'pseudonym', function() {
bsw@0 734 var fields = ['supporter.issue_id', 'supporter.initiative_id', 'supporter.member_id', 'supporter.draft_id'];
bsw@0 735 var query = new selector.Selector();
bsw@0 736 query.from('supporter')
bsw@0 737 query.join('member', null, 'member.id = supporter.member_id JOIN initiative ON initiative.id = supporter.initiative_id JOIN issue ON issue.id = initiative.issue_id JOIN policy ON policy.id = issue.policy_id JOIN area ON area.id = issue.area_id JOIN unit ON area.unit_id = unit.id');
bsw@0 738 fields.forEach( function(field) {
bsw@0 739 query.addField(field, null, ['grouped']);
bsw@0 740 });
bsw@0 741 general_params.addMemberOptions(req, query, params);
bsw@0 742 general_params.addInitiativeOptions(req, query, params);
bsw@0 743 query.addOrderBy('supporter.issue_id, supporter.initiative_id, supporter.member_id');
bsw@0 744 general_params.addLimitAndOffset(query, params);
bsw@0 745 db.query(conn, req, res, query, function (supporter, conn) {
bsw@0 746 var result = { result: supporter.rows }
bsw@0 747 includes = [];
bsw@0 748 if (params.include_initiatives) includes.push({ class: 'initiative', objects: 'result'});
bsw@0 749 if (params.include_issues) includes.push({ class: 'issue', objects: 'initiatives'});
bsw@0 750 if (params.include_areas) includes.push({ class: 'area', objects: 'issues'});
bsw@0 751 if (params.include_units) includes.push({ class: 'unit', objects: 'areas'});
bsw@0 752 if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' });
bsw@0 753 addRelatedData(conn, req, res, result, includes);
bsw@0 754 });
bsw@0 755 });
bsw@0 756 },
bsw@0 757
bsw@0 758 '/battle': function (conn, req, res, params) {
bsw@0 759 requireAccessLevel(conn, req, res, 'anonymous', function() {
bsw@0 760 var query = new selector.Selector();
bsw@0 761 query.from('battle JOIN initiative ON initiative.id = battle.winning_initiative_id OR initiative.id = battle.losing_initiative_id JOIN issue ON issue.id = battle.issue_id JOIN policy ON policy.id = issue.policy_id JOIN area ON area.id = issue.area_id JOIN unit ON area.unit_id = unit.id');
bsw@0 762 query.addField('battle.*');
bsw@0 763 general_params.addInitiativeOptions(req, query, params);
bsw@0 764 query.addOrderBy('battle.issue_id, battle.winning_initiative_id, battle.losing_initiative_id');
bsw@0 765 general_params.addLimitAndOffset(query, params);
bsw@0 766 db.query(conn, req, res, query, function (result, conn) {
bsw@0 767 var result = { result: result.rows }
bsw@0 768 includes = [];
bsw@0 769 if (params.include_initiatives) includes.push({ class: 'initiative', objects: 'result'});
bsw@0 770 if (params.include_issues) includes.push({ class: 'issue', objects: 'initiatives'});
bsw@0 771 if (params.include_areas) includes.push({ class: 'area', objects: 'issues'});
bsw@0 772 if (params.include_units) includes.push({ class: 'unit', objects: 'areas'});
bsw@0 773 if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' });
bsw@0 774 addRelatedData(conn, req, res, result, includes);
bsw@0 775 });
bsw@0 776 });
bsw@0 777 },
bsw@0 778
bsw@0 779 '/draft': function (conn, req, res, params) {
bsw@0 780 requireAccessLevel(conn, req, res, 'anonymous', function() {
bsw@0 781 var fields = ['draft.initiative_id', 'draft.id', 'draft.formatting_engine', 'draft.content', 'draft.author_id'];
bsw@0 782 var query = new selector.Selector();
bsw@0 783 query.from('draft JOIN initiative ON initiative.id = draft.initiative_id JOIN issue ON issue.id = initiative.issue_id JOIN policy ON policy.id = issue.policy_id JOIN area ON area.id = issue.area_id JOIN unit ON area.unit_id = unit.id');
bsw@0 784 fields.forEach( function(field) {
bsw@0 785 query.addField(field, null, ['grouped']);
bsw@0 786 });
bsw@0 787 if (req.current_access_level != 'anonymous' || req.current_member_id) {
bsw@0 788 query.addField('draft.author_id');
bsw@0 789 }
bsw@0 790 if (params.draft_id) {
bsw@0 791 query.addWhere('draft.id = ?', params.draft_id);
bsw@0 792 }
bsw@0 793 if (params.current_draft) {
bsw@0 794 query.join('current_draft', null, 'current_draft.initiative_id = initiative.id AND current_draft.id = draft.id')
bsw@0 795 }
bsw@0 796 general_params.addInitiativeOptions(req, query, params);
bsw@0 797 query.addOrderBy('draft.initiative_id, draft.id');
bsw@0 798 general_params.addLimitAndOffset(query, params);
bsw@0 799 db.query(conn, req, res, query, function (result, conn) {
bsw@0 800 var result = { result: result.rows }
bsw@0 801 includes = [];
bsw@0 802 if (params.include_initiatives) includes.push({ class: 'initiative', objects: 'result'});
bsw@0 803 if (params.include_issues) includes.push({ class: 'issue', objects: 'initiatives'});
bsw@0 804 if (params.include_areas) includes.push({ class: 'area', objects: 'issues'});
bsw@0 805 if (params.include_units) includes.push({ class: 'unit', objects: 'areas'});
bsw@0 806 if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' });
bsw@0 807 addRelatedData(conn, req, res, result, includes);
bsw@0 808 });
bsw@0 809 });
bsw@0 810 },
bsw@0 811
bsw@0 812 '/suggestion': function (conn, req, res, params) {
bsw@0 813 requireAccessLevel(conn, req, res, 'anonymous', function() {
bsw@0 814 var query = new selector.Selector();
bsw@0 815 query.from('suggestion JOIN initiative ON initiative.id = suggestion.initiative_id JOIN issue ON issue.id = initiative.issue_id JOIN policy ON policy.id = issue.policy_id JOIN area ON area.id = issue.area_id JOIN unit ON area.unit_id = unit.id');
bsw@0 816 if (req.current_access_level == 'anonymous' && !req.current_member_id ) {
bsw@0 817 fields.addObjectFields(query, 'suggestion', 'suggestion_pseudonym');
bsw@0 818 } else {
bsw@0 819 fields.addObjectFields(query, 'suggestion');
bsw@0 820 }
bsw@0 821 general_params.addSuggestionOptions(req, query, params);
bsw@0 822 query.addOrderBy('suggestion.initiative_id, suggestion.id');
bsw@0 823 general_params.addLimitAndOffset(query, params);
bsw@0 824 db.query(conn, req, res, query, function (result, conn) {
bsw@0 825 var result = { result: result.rows }
bsw@0 826 includes = [];
bsw@0 827 if (params.include_initiatives) includes.push({ class: 'initiative', objects: 'result'});
bsw@0 828 if (params.include_issues) includes.push({ class: 'issue', objects: 'initiatives'});
bsw@0 829 if (params.include_areas) includes.push({ class: 'area', objects: 'issues'});
bsw@0 830 if (params.include_units) includes.push({ class: 'unit', objects: 'areas'});
bsw@0 831 if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' });
bsw@0 832 addRelatedData(conn, req, res, result, includes);
bsw@0 833 });
bsw@0 834 });
bsw@0 835 },
bsw@0 836
bsw@0 837 '/opinion': function (conn, req, res, params) {
bsw@0 838 requireAccessLevel(conn, req, res, 'pseudonym', function() {
bsw@0 839 var fields = ['opinion.initiative_id', 'opinion.suggestion_id', 'opinion.member_id', 'opinion.degree', 'opinion.fulfilled']
bsw@0 840 var query = new selector.Selector();
bsw@0 841 query.from('opinion JOIN member ON member.id = opinion.member_id JOIN suggestion ON suggestion.id = opinion.suggestion_id JOIN initiative ON initiative.id = suggestion.initiative_id JOIN issue ON issue.id = initiative.issue_id JOIN policy ON policy.id = issue.policy_id JOIN area ON area.id = issue.area_id JOIN unit ON area.unit_id = unit.id');
bsw@0 842 fields.forEach( function(field) {
bsw@0 843 query.addField(field, null, ['grouped']);
bsw@0 844 });
bsw@0 845 general_params.addMemberOptions(req, query, params);
bsw@0 846 general_params.addSuggestionOptions(req, query, params);
bsw@0 847 query.addOrderBy = ['opinion.initiative_id, opinion.suggestion_id, opinion.member_id'];
bsw@0 848 general_params.addLimitAndOffset(query, params);
bsw@0 849 db.query(conn, req, res, query, function (result, conn) {
bsw@0 850 var result = { result: result.rows }
bsw@0 851 includes = [];
bsw@0 852 if (params.include_suggestions) includes.push({ class: 'suggestion', objects: 'result'});
bsw@0 853 if (params.include_initiatives) includes.push({ class: 'initiative', objects: 'suggestions'});
bsw@0 854 if (params.include_issues) includes.push({ class: 'issue', objects: 'initiatives'});
bsw@0 855 if (params.include_areas) includes.push({ class: 'area', objects: 'issues'});
bsw@0 856 if (params.include_units) includes.push({ class: 'unit', objects: 'areas'});
bsw@0 857 if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' });
bsw@0 858 addRelatedData(conn, req, res, result, includes);
bsw@0 859 });
bsw@0 860 });
bsw@0 861 },
bsw@0 862
bsw@0 863 '/delegation': function (conn, req, res, params) {
bsw@0 864 requireAccessLevel(conn, req, res, 'pseudonym', function() {
bsw@0 865 var fields = ['delegation.id', 'delegation.truster_id', 'delegation.trustee_id', 'delegation.scope', 'delegation.area_id', 'delegation.issue_id', 'delegation.unit_id'];
bsw@0 866 var query = new selector.Selector();
bsw@0 867 query.from('delegation LEFT JOIN issue on delegation.issue_id = issue.id LEFT JOIN policy ON policy.id = issue.policy_id LEFT JOIN area ON area.id = issue.area_id OR area.id = delegation.area_id LEFT JOIN unit ON area.unit_id = unit.id OR unit.id = delegation.unit_id');
bsw@0 868 fields.forEach( function(field) {
bsw@0 869 query.addField(field, null, ['grouped']);
bsw@0 870 });
bsw@0 871 if (params.direction) {
bsw@0 872 switch (params.direction) {
bsw@0 873 case 'in':
bsw@0 874 query.join('member', null, 'member.id = delegation.trustee_id');
bsw@0 875 break;
bsw@0 876 case 'out':
bsw@0 877 query.join('member', null, 'member.id = delegation.truster_id');
bsw@0 878 break;
bsw@0 879 default:
bsw@0 880 respond('json', conn, req, res, 'unprocessable', 'Direction must be "in" or "out" if set.');
bsw@0 881 }
bsw@0 882 } else {
bsw@0 883 query.join('member', null, 'member.id = delegation.truster_id OR member.id = delegation.trustee_id');
bsw@0 884 }
bsw@0 885 general_params.addMemberOptions(req, query, params);
bsw@0 886 general_params.addIssueOptions(req, query, params);
bsw@0 887 if (params.scope) {
bsw@0 888 query.addWhere(['delegation.scope IN (??)', params.scope.split(',')]);
bsw@0 889 };
bsw@0 890 query.addOrderBy = ['delegation.id'];
bsw@0 891 general_params.addLimitAndOffset(query, params);
bsw@0 892 db.query(conn, req, res, query, function (result, conn) {
bsw@0 893 respond('json', conn, req, res, 'ok', { result: result.rows });
bsw@0 894 });
bsw@0 895 });
bsw@0 896 },
bsw@0 897
bsw@0 898 '/vote': function (conn, req, res, params) {
bsw@0 899 requireAccessLevel(conn, req, res, 'pseudonym', function() {
bsw@0 900 var query = new selector.Selector();
bsw@0 901 query.from('vote JOIN member ON member.id = vote.member_id JOIN initiative ON initiative.id = vote.initiative_id JOIN issue ON issue.id = initiative.issue_id JOIN policy ON policy.id = issue.policy_id JOIN area ON area.id = issue.area_id JOIN unit ON area.unit_id = unit.id');
bsw@0 902 query.addField('vote.*');
bsw@0 903 query.addWhere('issue.closed_at NOTNULL');
bsw@0 904 general_params.addMemberOptions(req, query, params);
bsw@0 905 general_params.addInitiativeOptions(req, query, params);
bsw@0 906 general_params.addLimitAndOffset(query, params);
bsw@0 907 db.query(conn, req, res, query, function (result, conn) {
bsw@0 908 respond('json', conn, req, res, 'ok', { result: result.rows });
bsw@0 909 });
bsw@0 910 });
bsw@0 911 },
bsw@0 912
bsw@0 913 '/event': function (conn, req, res, params) { requireAccessLevel(conn, req, res, 'anonymous', function() {
bsw@0 914 var fields = ['event.id', 'event.occurrence', 'event.event', 'event.member_id', 'event.issue_id', 'event.state', 'event.initiative_id', 'event.draft_id', 'event.suggestion_id'];
bsw@0 915 var query = new selector.Selector();
bsw@0 916 query.from('event LEFT JOIN member ON member.id = event.member_id LEFT JOIN initiative ON initiative.id = event.initiative_id LEFT JOIN issue ON issue.id = event.issue_id LEFT JOIN policy ON policy.id = issue.policy_id LEFT JOIN area ON area.id = issue.area_id LEFT JOIN unit ON area.unit_id = unit.id');
bsw@0 917 fields.forEach( function(field) {
bsw@0 918 query.addField(field, null, ['grouped']);
bsw@0 919 });
bsw@0 920 general_params.addMemberOptions(req, query, params);
bsw@0 921 general_params.addInitiativeOptions(req, query, params);
bsw@0 922 query.addOrderBy('event.id');
bsw@0 923 general_params.addLimitAndOffset(query, params);
bsw@0 924 db.query(conn, req, res, query, function (events, conn) {
bsw@0 925 var result = { result: events.rows }
bsw@0 926 includes = [];
bsw@0 927 if (params.include_initiatives) includes.push({ class: 'initiative', objects: 'result'});
bsw@0 928 if (params.include_issues) includes.push({ class: 'issue', objects: 'result'});
bsw@0 929 if (params.include_areas) includes.push({ class: 'area', objects: 'issues'});
bsw@0 930 if (params.include_units) includes.push({ class: 'unit', objects: 'areas'});
bsw@0 931 if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' });
bsw@0 932 addRelatedData(conn, req, res, result, includes);
bsw@0 933 });
bsw@0 934 }); },
bsw@0 935
bsw@0 936 // TODO add interfaces for data structure:
bsw@0 937 // event requireAccessLevel(conn, req, res, 'member');
bsw@0 938 // ignored_member requireAccessLevel(conn, req, res, 'member');
bsw@0 939 // ignored_initiative requireAccessLevel(conn, req, res, 'member');
bsw@0 940 // setting requireAccessLevel(conn, req, res, 'member');
bsw@0 941
bsw@0 942 };
bsw@0 943
bsw@0 944 // ==========================================================================
bsw@0 945 // POST methods
bsw@0 946 // ==========================================================================
bsw@0 947
bsw@0 948
bsw@0 949
bsw@0 950 exports.post = {
bsw@0 951
bsw@0 952 '/echo_test': function (conn, req, res, params) { requireAccessLevel(conn, req, res, 'anonymous', function() {
bsw@0 953 respond('json', conn, req, res, 'ok', { result: params });
bsw@0 954 }); },
bsw@0 955
bsw@0 956 '/register_test': function (conn, req, res, params) {
bsw@0 957 var understood = params.understood;
bsw@0 958 var member_login = randomString(16);
bsw@0 959 var member_name = params.name;
bsw@0 960 var member_password = randomString(16);
bsw@0 961 var member_notify_email = params.email;
bsw@0 962 var member_notify_email_secret = randomString(24);
bsw@0 963 var api_key_member = randomString(24);
bsw@0 964 var api_key_full = randomString(24);
bsw@0 965 var api_key_pseudonym = randomString(24);
bsw@0 966 var api_key_anonymous = randomString(24);
bsw@0 967
bsw@0 968 if (understood != 'understood') {
bsw@0 969 respond('html', conn, req, res, 'unprocessable', null, 'You didn\'t checked the checkbox! Please hit back in your browser and try again.');
bsw@0 970 return;
bsw@0 971 }
bsw@0 972
bsw@0 973 // add member
bsw@0 974 var query = new selector.SQLInsert('member');
bsw@0 975 query.addValues({
bsw@0 976 login: member_login,
bsw@0 977 password: member_password, // TODO hashing of password
bsw@0 978 notify_email_unconfirmed: member_notify_email,
bsw@0 979 notify_email_secret: member_notify_email_secret,
bsw@0 980 name: member_name
bsw@0 981 });
bsw@0 982 query.addReturning('id');
bsw@0 983 db.query(conn, req, res, query, function (result, conn) {
bsw@0 984 var member_id = result.rows[0].id;
bsw@0 985
bsw@0 986 // add privilege for root unit
bsw@0 987 var query = new selector.SQLInsert('privilege');
bsw@0 988 query.addValues({ unit_id: 1, member_id: member_id, voting_right: true });
bsw@0 989 db.query(conn, req, res, query, function (result, conn) {
bsw@0 990
bsw@0 991 var location = params.location;
bsw@0 992 var unit_id;
bsw@0 993 switch(location) {
bsw@0 994 case 'earth':
bsw@0 995 unit_id = 3;
bsw@0 996 break;
bsw@0 997 case 'moon':
bsw@0 998 unit_id = 4;
bsw@0 999 break;
bsw@0 1000 case 'mars':
bsw@0 1001 unit_id = 5;
bsw@0 1002 break;
bsw@0 1003 }
bsw@0 1004
bsw@0 1005 // add privilege for selected planet
bsw@0 1006 var query = new selector.SQLInsert('privilege');
bsw@0 1007 query.addValues({ unit_id: unit_id, member_id: member_id, voting_right: true });
bsw@0 1008 db.query(conn, req, res, query, function (result, conn) {
bsw@0 1009
bsw@0 1010 // add application key
bsw@0 1011 var query = new selector.SQLInsert('member_application');
bsw@0 1012 query.addValues({
bsw@0 1013 member_id: member_id,
bsw@0 1014 name: 'member',
bsw@0 1015 comment: 'access_level member',
bsw@0 1016 access_level: 'member',
bsw@0 1017 key: api_key_member
bsw@0 1018 });
bsw@0 1019 query.addReturning('id');
bsw@0 1020
bsw@0 1021 db.query(conn, req, res, query, function (result, conn) {
bsw@0 1022
bsw@0 1023 // send email to user
bsw@0 1024 email.send({
bsw@0 1025 host : config.mail.smtp_host,
bsw@0 1026 port: config.mail.smtp_port,
bsw@0 1027 ssl: config.mail.smtp_ssl,
bsw@0 1028 domain: config.mail.smtp_domain,
bsw@0 1029 authentication: config.mail.smtp_authentication,
bsw@0 1030 username: config.mail.smtp_username,
bsw@0 1031 password: config.mail.smtp_password,
bsw@0 1032 from: config.mail.from,
bsw@0 1033 subject: config.mail.subject_prefix + "Your LiquidFeedback API alpha test account needs confirmation",
bsw@0 1034 to: member_notify_email,
bsw@0 1035 body: "\
bsw@0 1036 Hello " + member_name + ",\n\
bsw@0 1037 \n\
bsw@0 1038 thank you for registering at the public alpha test of the LiquidFeedback\n\
bsw@0 1039 application programming interface. To complete the registration process,\n\
bsw@0 1040 you need to confirm your email address by opening the following URL:\n\
bsw@0 1041 \n\
bsw@0 1042 " + config.public_url_path + "register_test_confirm?secret=" + member_notify_email_secret + "\n\
bsw@0 1043 \n\
bsw@0 1044 \n\
bsw@0 1045 After you've confirmed your email address, your account will be automatically\n\
bsw@0 1046 activated.\n\
bsw@0 1047 \n\
bsw@0 1048 Your account name is: " + member_name + "\n\
bsw@0 1049 \n\
bsw@0 1050 \n\
bsw@0 1051 You will need the following login and password to register and unregister\n\
bsw@0 1052 applications for your account later. This function is currently not\n\
bsw@0 1053 implemented, but please keep the credentials for future use.\n\
bsw@0 1054 \n\
bsw@0 1055 Account ID: " + member_id + "\n\
bsw@0 1056 Login: " + member_login + "\n\
bsw@0 1057 Password: " + member_password + "\n\
bsw@0 1058 \n\
bsw@0 1059 \n\
bsw@0 1060 To make you able to actually access the API interface, we added the following\n\
bsw@0 1061 application key with full member access privileges to your account:\n\
bsw@0 1062 \n\
bsw@0 1063 API Key: " + api_key_member + "\n\
bsw@0 1064 \n\
bsw@0 1065 \n\
bsw@0 1066 The base address of the public test is: " + config.public_url_path + "\n\
bsw@0 1067 \n\
bsw@0 1068 The programming interface is described in the LiquidFeedback API\n\
bsw@0 1069 specification: http://dev.liquidfeedback.org/trac/lf/wiki/API\n\
bsw@0 1070 \n\
bsw@0 1071 The current implementation status of lfapi is published at the LiquidFeedback\n\
bsw@0 1072 API server page: http://dev.liquidfeedback.org/trac/lf/wiki/lfapi\n\
bsw@0 1073 \n\
bsw@0 1074 If you have any questions or suggestions, please use our public mailing list\n\
bsw@0 1075 at http://dev.liquidfeedback.org/cgi-bin/mailman/listinfo/main\n\
bsw@0 1076 \n\
bsw@0 1077 For issues regarding your test account, contact us via email at\n\
bsw@0 1078 lqfb-maintainers@public-software-group.org\n\
bsw@0 1079 \n\
bsw@0 1080 \n\
bsw@0 1081 Sincerely,\n\
bsw@0 1082 \n\
bsw@0 1083 Your LiquidFeedback maintainers",
bsw@0 1084 },
bsw@0 1085 function(err, result){
bsw@0 1086 if(err){ console.log(err); }
bsw@0 1087 });
bsw@0 1088
bsw@0 1089 respond('html', conn, req, res, 'ok', 'Account created. Please check your mailbox!<br /><br /><br /><a href="/">Back to start page</a>');
bsw@0 1090 });
bsw@0 1091 });
bsw@0 1092 });
bsw@0 1093 });
bsw@0 1094 },
bsw@0 1095
bsw@0 1096 /*
bsw@0 1097 '/register': function (conn, req, res, params) {
bsw@0 1098 var invite_key = params.invite_key;
bsw@0 1099 var login = params.login;
bsw@0 1100 var password = params.password;
bsw@0 1101 var name = params.name;
bsw@0 1102 var notify_email = params.notify_email;
bsw@0 1103 if (!invite_key) {
bsw@0 1104 respond('json', conn, req, res, 'unprocessable', null, 'No invite_key supplied.');
bsw@0 1105 return;
bsw@0 1106 };
bsw@0 1107 if (!login) {
bsw@0 1108 respond('json', conn, req, res, 'unprocessable', null, 'No login supplied.');
bsw@0 1109 return;
bsw@0 1110 };
bsw@0 1111 if (!password) {
bsw@0 1112 respond('json', conn, req, res, 'unprocessable', null, 'No password supplied.');
bsw@0 1113 return;
bsw@0 1114 };
bsw@0 1115 if (!name) {
bsw@0 1116 respond('json', conn, req, res, 'unprocessable', null, 'No name supplied.');
bsw@0 1117 return;
bsw@0 1118 };
bsw@0 1119 if (!notify_email) {
bsw@0 1120 respond('json', conn, req, res, 'unprocessable', null, 'No notify_email supplied.');
bsw@0 1121 return;
bsw@0 1122 };
bsw@0 1123 // check if akey is valid and get member_id for akey
bsw@0 1124 db.query(conn, req, res, { select: ['member.id'], from: ['member'], where: ['NOT member.activation AND member.invite_key = ' + db.pgEncode(invite_key)] }, function (result, conn) {
bsw@0 1125 if (result.rows.length != 1) {
bsw@0 1126 respond('json', conn, req, res, 'forbidden', null, 'Supplied invite_key is not valid.');
bsw@0 1127 return;
bsw@0 1128 };
bsw@0 1129 var member_id = result.rows[0].id;
bsw@0 1130 // check if name is available
bsw@0 1131 db.query(conn, req, res, { select: ['NULL'], from: ['member'], where: ['member.name = ' + db.pgEncode(name)] }, function (result, conn) {
bsw@0 1132 if (result.rows.length > 0) {
bsw@0 1133 respond('json', conn, req, res, 'forbidden', null, 'Login name is not available, choose another one.');
bsw@0 1134 return;
bsw@0 1135 };
bsw@0 1136 // check if login is available
bsw@0 1137 db.query(conn, req, res, { select: ['NULL'], from: ['member'], where: ['member.login = ' + db.pgEncode(login)] }, function (result, conn) {
bsw@0 1138 if (result.rows.length > 0) {
bsw@0 1139 respond('json', conn, req, res, 'forbidden', null, 'Name is not available, choose another one.');
bsw@0 1140 return;
bsw@0 1141 };
bsw@0 1142 var query = { update: 'member', set: { activation: 'now', active: true, } };
bsw@0 1143
bsw@0 1144 });
bsw@0 1145 });
bsw@0 1146 });
bsw@0 1147 },
bsw@0 1148 */
bsw@0 1149
bsw@0 1150 '/session': function (conn, req, res, params) {
bsw@0 1151 var key = params.key;
bsw@0 1152 if (!key) {
bsw@0 1153 respond('json', conn, req, res, 'unprocessable', null, 'No application key supplied.');
bsw@0 1154 return;
bsw@0 1155 };
bsw@0 1156 var query = new selector.Selector();
bsw@0 1157 query.from('member');
bsw@0 1158 query.join('member_application', null, 'member_application.member_id = member.id');
bsw@0 1159 query.addField('member.id');
bsw@0 1160 query.addWhere(['member.active AND member_application.key = ?', key]);
bsw@0 1161 if (params.interactive) {
bsw@0 1162 query.forUpdateOf('member');
bsw@0 1163 }
bsw@0 1164 db.query(conn, req, res, query, function (result, conn) {
bsw@0 1165 if (result.rows.length != 1) {
bsw@0 1166 respond('json', conn, req, res, 'forbidden', null, 'Supplied application key is not valid.');
bsw@0 1167 return;
bsw@0 1168 };
bsw@0 1169 var member_id = result.rows[0].id;
bsw@0 1170 var session_key = randomString(16);
bsw@0 1171 req.sessions[session_key] = member_id;
bsw@0 1172 var query;
bsw@0 1173 if (params.interactive) {
bsw@0 1174 query = new selector.SQLUpdate('member');
bsw@0 1175 query.addWhere(['member.id = ?', member_id]);
bsw@0 1176 query.addValues({ last_activity: 'now' });
bsw@0 1177 }
bsw@0 1178 db.query(conn, req, res, query, function (result, conn) {
bsw@0 1179 respond('json', conn, req, res, 'ok', { session_key: session_key });
bsw@0 1180 });
bsw@0 1181 });
bsw@0 1182 },
bsw@0 1183
bsw@0 1184 '/member': function (conn, req, res, params) {
bsw@0 1185 var fields = ['organizational_unit', 'internal_posts', 'realname', 'birthday', 'address', 'email', 'xmpp_address', 'website', 'phone', 'mobile_phone', 'profession', 'external_memberships', 'external_posts', 'statement']
bsw@0 1186 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1187 var query = new selector.SQLUpdate('member');
bsw@0 1188 query.addWhere(['member.id = ?', req.current_member_id]);
bsw@0 1189 fields.forEach( function(field) {
bsw@0 1190 if (typeof(params[field]) != 'undefined') {
bsw@0 1191 query.addValues({ field: params[field] });
bsw@0 1192 } else {
bsw@0 1193 query.addValues({ field: null });
bsw@0 1194 }
bsw@0 1195 });
bsw@0 1196 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1197 });
bsw@0 1198 },
bsw@0 1199
bsw@0 1200 '/membership': function (conn, req, res, params) {
bsw@0 1201 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1202
bsw@0 1203 // check if area_id is set
bsw@0 1204 var area_id = parseInt(params.area_id);
bsw@0 1205 if (!area_id) {
bsw@0 1206 respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an area_id.');
bsw@0 1207 return;
bsw@0 1208 }
bsw@0 1209
bsw@0 1210 // delete membership
bsw@0 1211 if (params.delete) {
bsw@0 1212 var query;
bsw@0 1213 query = new selector.SQLDelete('membership');
bsw@0 1214 query.addWhere(['area_id = ?', area_id]);
bsw@0 1215 query.addWhere(['member_id = ?', req.current_member_id]);
bsw@0 1216 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1217
bsw@0 1218 // add membership
bsw@0 1219 } else {
bsw@0 1220
bsw@0 1221 // lock member for upsert
bsw@0 1222 lockMemberById(conn, req, res, req.current_member_id, function() {
bsw@0 1223
bsw@0 1224 // check and lock privilege
bsw@0 1225 requireAreaPrivilege(conn, req, res, area_id, function() {
bsw@0 1226
bsw@0 1227 // upsert membership
bsw@0 1228 var query = new selector.Upserter('membership', ['area_id', 'member_id']);
bsw@0 1229 query.addValues({ area_id: area_id, member_id: req.current_member_id });
bsw@0 1230 db.query(conn, req, res, query, function(result) {
bsw@0 1231 respond('json', conn, req, res, 'ok');
bsw@0 1232 });
bsw@0 1233 });
bsw@0 1234 });
bsw@0 1235 }
bsw@0 1236 });
bsw@0 1237 },
bsw@0 1238
bsw@0 1239 '/interest': function (conn, req, res, params) {
bsw@0 1240 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1241 var query;
bsw@0 1242
bsw@0 1243 // check if issue_id is set
bsw@0 1244 var issue_id = parseInt(params.issue_id);
bsw@0 1245 if (!issue_id) {
bsw@0 1246 respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an issue_id.');
bsw@0 1247 return;
bsw@0 1248 }
bsw@0 1249
bsw@0 1250 // lock member for upsert
bsw@0 1251 lockMemberById(conn, req, res, req.current_member_id, function() {
bsw@0 1252
bsw@0 1253 // delete interest
bsw@0 1254 if (params.delete) {
bsw@0 1255
bsw@0 1256 // check issue state
bsw@0 1257 requireIssueState(conn, req, res, issue_id, ['admission', 'discussion', 'verification'], function() {
bsw@0 1258
bsw@0 1259 // delete interest
bsw@0 1260 query = new selector.SQLDelete('interest');
bsw@0 1261 query.addWhere(['issue_id = ?', issue_id]);
bsw@0 1262 query.addWhere(['member_id = ?', req.current_member_id]);
bsw@0 1263 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1264 });
bsw@0 1265
bsw@0 1266 // add interest
bsw@0 1267 } else {
bsw@0 1268
bsw@0 1269 // check and lock privilege
bsw@0 1270 requireIssuePrivilege(conn, req, res, issue_id, function() {
bsw@0 1271
bsw@0 1272 // check issue state
bsw@0 1273 requireIssueState(conn, req, res, issue_id, ['admission', 'discussion', 'verification'], function() {
bsw@0 1274
bsw@0 1275 // upsert interest
bsw@0 1276 var query = new selector.Upserter('interest', ['issue_id', 'member_id']);
bsw@0 1277 query.addValues({ issue_id: issue_id, member_id: req.current_member_id });
bsw@0 1278 db.query(conn, req, res, query, function(result) {
bsw@0 1279 respond('json', conn, req, res, 'ok');
bsw@0 1280 });
bsw@0 1281 });
bsw@0 1282 });
bsw@0 1283 };
bsw@0 1284 });
bsw@0 1285 });
bsw@0 1286 },
bsw@0 1287
bsw@0 1288 '/issue_comment': function (conn, req, res, params) {
bsw@0 1289 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1290
bsw@0 1291 var issue_id = parseInt(params.issue_id);
bsw@0 1292 var formatting_engine = params.formatting_engine
bsw@0 1293 var content = params.content;
bsw@0 1294
bsw@0 1295 if (!issue_id) {
bsw@0 1296 respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an issue_id.');
bsw@0 1297 return;
bsw@0 1298 }
bsw@0 1299
bsw@0 1300 // delete issue comment
bsw@0 1301 if (params.delete) {
bsw@0 1302 var query;
bsw@0 1303 query = new selector.SQLDelete('issue_comment');
bsw@0 1304 query.addWhere(['issue_id = ?', params.issue_id]);
bsw@0 1305 query.addWhere(['member_id = ?', req.current_member_id]);
bsw@0 1306 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1307
bsw@0 1308 // upsert issue comment
bsw@0 1309 } else {
bsw@0 1310
bsw@0 1311 // check if formatting engine is supplied and valid
bsw@0 1312 if (!formatting_engine) {
bsw@0 1313 respond('json', conn, req, res, 'unprocessable', null, 'No formatting engine supplied.');
bsw@0 1314 return;
bsw@0 1315 } else if (formatting_engine != 'rocketwiki' && formatting_engine != 'compat') {
bsw@0 1316 respond('json', conn, req, res, 'unprocessable', null, 'Invalid formatting engine supplied.');
bsw@0 1317 return;
bsw@0 1318 };
bsw@0 1319
bsw@0 1320 // check if content is supplied
bsw@0 1321 if (!content) {
bsw@0 1322 respond('json', conn, req, res, 'unprocessable', null, 'No content supplied.');
bsw@0 1323 return;
bsw@0 1324 }
bsw@0 1325
bsw@0 1326 // lock member for upsert
bsw@0 1327 lockMemberById(conn, req, res, req.current_member_id, function() {
bsw@0 1328
bsw@0 1329 // check and lock privilege
bsw@0 1330 requireIssuePrivilege(conn, req, res, issue_id, function() {
bsw@0 1331
bsw@0 1332 // upsert issue comment
bsw@0 1333 var query = new selector.Upserter('issue_comment', ['issue_id', 'member_id']);
bsw@0 1334 query.addValues({
bsw@0 1335 issue_id: issue_id,
bsw@0 1336 member_id: req.current_member_id,
bsw@0 1337 changed: 'now',
bsw@0 1338 formatting_engine: formatting_engine,
bsw@0 1339 content: content
bsw@0 1340 });
bsw@0 1341
bsw@0 1342 db.query(conn, req, res, query, function(result) {
bsw@0 1343 respond('json', conn, req, res, 'ok');
bsw@0 1344 });
bsw@0 1345
bsw@0 1346 });
bsw@0 1347 });
bsw@0 1348
bsw@0 1349 }
bsw@0 1350
bsw@0 1351 });
bsw@0 1352 },
bsw@0 1353
bsw@0 1354 '/voting_comment': function (conn, req, res, params) {
bsw@0 1355 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1356
bsw@0 1357 var issue_id = parseInt(params.issue_id);
bsw@0 1358 var formatting_engine = params.formatting_engine
bsw@0 1359 var content = params.content;
bsw@0 1360
bsw@0 1361 if (!issue_id) {
bsw@0 1362 respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an issue_id.');
bsw@0 1363 return;
bsw@0 1364 }
bsw@0 1365
bsw@0 1366
bsw@0 1367 // delete voting comment
bsw@0 1368 if (params.delete) {
bsw@0 1369 var query;
bsw@0 1370 query = new selector.SQLDelete('voting_comment');
bsw@0 1371 query.addWhere(['issue_id = ?', params.issue_id]);
bsw@0 1372 query.addWhere(['member_id = ?', req.current_member_id]);
bsw@0 1373 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1374
bsw@0 1375 // upsert voting comment
bsw@0 1376 } else {
bsw@0 1377
bsw@0 1378 // check if formatting engine is supplied and valid
bsw@0 1379 if (!formatting_engine) {
bsw@0 1380 respond('json', conn, req, res, 'unprocessable', null, 'No formatting engine supplied.');
bsw@0 1381 return;
bsw@0 1382 } else if (formatting_engine != 'rocketwiki' && formatting_engine != 'compat') {
bsw@0 1383 respond('json', conn, req, res, 'unprocessable', null, 'Invalid formatting engine supplied.');
bsw@0 1384 return;
bsw@0 1385 };
bsw@0 1386
bsw@0 1387 // check if content is supplied
bsw@0 1388 if (!content) {
bsw@0 1389 respond('json', conn, req, res, 'unprocessable', null, 'No content supplied.');
bsw@0 1390 return;
bsw@0 1391 }
bsw@0 1392
bsw@0 1393 // lock member for upsert
bsw@0 1394 lockMemberById(conn, req, res, req.current_member_id, function() {
bsw@0 1395
bsw@0 1396 // check and lock privilege
bsw@0 1397 requireIssuePrivilege(conn, req, res, issue_id, function() {
bsw@0 1398
bsw@0 1399 // check issue state
bsw@0 1400 requireIssueState(conn, req, res, issue_id, ['voting', 'finished_with_winner', 'finished_without_winner'], function() {
bsw@0 1401
bsw@0 1402 // upsert voting comment
bsw@0 1403 var query = new selector.Upserter('voting_comment', ['issue_id', 'member_id']);
bsw@0 1404 query.addValues({
bsw@0 1405 issue_id: issue_id,
bsw@0 1406 member_id: req.current_member_id,
bsw@0 1407 changed: 'now',
bsw@0 1408 formatting_engine: formatting_engine,
bsw@0 1409 content: content
bsw@0 1410 });
bsw@0 1411
bsw@0 1412 db.query(conn, req, res, query, function(result) {
bsw@0 1413 respond('json', conn, req, res, 'ok');
bsw@0 1414 });
bsw@0 1415
bsw@0 1416 });
bsw@0 1417 });
bsw@0 1418 })
bsw@0 1419 };
bsw@0 1420 });
bsw@0 1421 },
bsw@0 1422
bsw@0 1423 '/supporter': function (conn, req, res, params) {
bsw@0 1424 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1425 var initiative_id = parseInt(params.initiative_id);
bsw@0 1426 var draft_id = parseInt(params.draft_id);
bsw@0 1427
bsw@0 1428 // check if needed arguments are supplied
bsw@0 1429 if (!initiative_id) {
bsw@0 1430 respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an initiative_id.');
bsw@0 1431 return;
bsw@0 1432 }
bsw@0 1433
bsw@0 1434 if (!draft_id) {
bsw@0 1435 respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an draft_id.');
bsw@0 1436 return;
bsw@0 1437 }
bsw@0 1438
bsw@0 1439 // lock member for upsert
bsw@0 1440 lockMemberById(conn, req, res, req.current_member_id, function() {
bsw@0 1441
bsw@0 1442 // delete supporter
bsw@0 1443 if (params.delete) {
bsw@0 1444
bsw@0 1445 // check issue state
bsw@0 1446 requireIssueStateForInitiative(conn, req, res, initiative_id, ['admission', 'discussion', 'verification'], function() {
bsw@0 1447
bsw@0 1448 // delete supporter
bsw@0 1449 var query = new selector.SQLDelete('supporter');
bsw@0 1450 query.addWhere(['initiative_id = ?', initiative_id]);
bsw@0 1451 query.addWhere(['member_id = ?', req.current_member_id]);
bsw@0 1452 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1453
bsw@0 1454 });
bsw@0 1455
bsw@0 1456 // upsert supporter
bsw@0 1457 } else {
bsw@0 1458
bsw@0 1459 // check and lock privilege
bsw@0 1460 requireInitiativePrivilege(conn, req, res, initiative_id, function() {
bsw@0 1461
bsw@0 1462 // check issue state
bsw@0 1463 requireIssueStateForInitiative(conn, req, res, initiative_id, ['admission', 'discussion', 'verification'], function() {
bsw@0 1464
bsw@0 1465 // check if given draft is the current one
bsw@0 1466 var query = new selector.Selector('current_draft');
bsw@0 1467 query.addField('NULL');
bsw@0 1468 query.addWhere(['current_draft.initiative_id = ?', initiative_id]);
bsw@0 1469 query.addWhere(['current_draft.id = ?', draft_id]);
bsw@0 1470
bsw@0 1471 db.query(conn, req, res, query, function(result) {
bsw@0 1472 if (result.rows.length != 1) {
bsw@0 1473 respond('json', conn, req, res, 'conflict', null, 'The draft with the supplied draft_id is not the current one anymore!');
bsw@0 1474 return;
bsw@0 1475 }
bsw@0 1476
bsw@0 1477 // upsert supporter
bsw@0 1478 var query = new selector.Upserter('supporter', ['initiative_id', 'member_id']);
bsw@0 1479 query.addValues({
bsw@0 1480 initiative_id: initiative_id,
bsw@0 1481 member_id: req.current_member_id,
bsw@0 1482 draft_id: draft_id
bsw@0 1483 });
bsw@0 1484
bsw@0 1485 db.query(conn, req, res, query, function(result) {
bsw@0 1486 respond('json', conn, req, res, 'ok');
bsw@0 1487 });
bsw@0 1488
bsw@0 1489 });
bsw@0 1490 });
bsw@0 1491 });
bsw@0 1492 };
bsw@0 1493 });
bsw@0 1494 });
bsw@0 1495 },
bsw@0 1496
bsw@0 1497 '/draft': function (conn, req, res, params) {
bsw@0 1498 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1499 var area_id = parseInt(params.area_id);
bsw@0 1500 var policy_id = parseInt(params.policy_id);
bsw@0 1501 var issue_id = parseInt(params.issue_id);
bsw@0 1502 var initiative_id = parseInt(params.initiative_id);
bsw@0 1503 var initiative_name = params.initiative_name;
bsw@0 1504 var initiative_discussion_url = params.initiative_discussion_url;
bsw@0 1505 var formatting_engine = params.formatting_engine;
bsw@0 1506 var content = params.content;
bsw@0 1507
bsw@0 1508 if (!initiative_discussion_url) initiative_discussion_url = null;
bsw@0 1509
bsw@0 1510 // check parameters
bsw@0 1511 if (!formatting_engine) {
bsw@0 1512 respond('json', conn, req, res, 'unprocessable', null, 'No formatting_engine supplied.');
bsw@0 1513 return;
bsw@0 1514 } else if (formatting_engine != 'rocketwiki' && formatting_engine != 'compat') {
bsw@0 1515 respond('json', conn, req, res, 'unprocessable', null, 'Invalid formatting engine supplied.');
bsw@0 1516 return;
bsw@0 1517 };
bsw@0 1518
bsw@0 1519 if (!content) {
bsw@0 1520 respond('json', conn, req, res, 'unprocessable', null, 'No draft content supplied.');
bsw@0 1521 return;
bsw@0 1522 };
bsw@0 1523
bsw@0 1524 lockMemberById(conn, req, res, req.current_member_id, function() {
bsw@0 1525
bsw@0 1526 // new draft in new initiative in new issue
bsw@0 1527 if (area_id && !issue_id && !initiative_id) {
bsw@0 1528
bsw@0 1529 // check parameters for new issue
bsw@0 1530 if (!policy_id) {
bsw@0 1531 respond('json', conn, req, res, 'unprocessable', null, 'No policy supplied.');
bsw@0 1532 return;
bsw@0 1533 }
bsw@0 1534
bsw@0 1535 if (!initiative_name) {
bsw@0 1536 respond('json', conn, req, res, 'unprocessable', null, 'No initiative name supplied.');
bsw@0 1537 return;
bsw@0 1538 }
bsw@0 1539
bsw@0 1540 requireAreaPrivilege(conn, req, res, area_id, function() {
bsw@0 1541
bsw@0 1542 // check if policy is allowed in this area and if area and policy are active
bsw@0 1543 var query = new selector.Selector();
bsw@0 1544 query.from('allowed_policy');
bsw@0 1545 query.join('area', null, 'area.id = allowed_policy.area_id AND area.active');
bsw@0 1546 query.join('policy', null, 'policy.id = allowed_policy.policy_id AND policy.active');
bsw@0 1547 query.addField('NULL');
bsw@0 1548 query.addWhere(['area.id = ? AND policy.id = ?', area_id, policy_id]);
bsw@0 1549 db.query(conn, req, res, query, function (result, conn) {
bsw@0 1550 if (result.rows.length != 1) {
bsw@0 1551 respond('json', conn, req, res, 'unprocessable', null, 'Area and/or policy doesn\'t exist, area and/or policy is not active or policy is not allowed in this area.');
bsw@0 1552 return;
bsw@0 1553 };
bsw@0 1554
bsw@0 1555 // check contingent
bsw@0 1556 requireContingentLeft(conn, req, res, true, function() {
bsw@0 1557
bsw@0 1558 // insert new issue
bsw@0 1559 var query = new selector.SQLInsert('issue');
bsw@0 1560 query.addValues({
bsw@0 1561 area_id: area_id,
bsw@0 1562 policy_id: policy_id
bsw@0 1563 });
bsw@0 1564 query.addReturning('id');
bsw@0 1565 db.query(conn, req, res, query, function(result) {
bsw@0 1566 var issue_id = result.rows[0].id;
bsw@0 1567
bsw@0 1568 // insert new initiative
bsw@0 1569 var query = new selector.SQLInsert('initiative');
bsw@0 1570 query.addValues({
bsw@0 1571 issue_id: issue_id,
bsw@0 1572 name: initiative_name,
bsw@0 1573 discussion_url: initiative_discussion_url
bsw@0 1574 });
bsw@0 1575 query.addReturning('id');
bsw@0 1576 db.query(conn, req, res, query, function(result) {
bsw@0 1577 var initiative_id = result.rows[0].id;
bsw@0 1578
bsw@0 1579 // insert initiator
bsw@0 1580 var query = new selector.SQLInsert('initiator');
bsw@0 1581 query.addValues({ initiative_id: initiative_id, member_id: req.current_member_id, accepted: true });
bsw@0 1582 db.query(conn, req, res, query, function(result) {
bsw@0 1583
bsw@0 1584 // insert new draft
bsw@0 1585 var query = new selector.SQLInsert('draft');
bsw@0 1586 query.addValues({
bsw@0 1587 initiative_id: initiative_id,
bsw@0 1588 author_id: req.current_member_id,
bsw@0 1589 formatting_engine: formatting_engine,
bsw@0 1590 content: content
bsw@0 1591 });
bsw@0 1592 query.addReturning('id');
bsw@0 1593 db.query(conn, req, res, query, function (result, conn) {
bsw@0 1594 var draft_id = result.rows[0].id;
bsw@0 1595
bsw@0 1596 respond('json', conn, req, res, 'ok', { issue_id: issue_id, initiative_id: initiative_id, draft_id: draft_id } );
bsw@0 1597 });
bsw@0 1598 });
bsw@0 1599 });
bsw@0 1600 });
bsw@0 1601 });
bsw@0 1602 });
bsw@0 1603 });
bsw@0 1604
bsw@0 1605 // new draft in new initiative in existant issue
bsw@0 1606 } else if (issue_id && !area_id && !initiative_id) {
bsw@0 1607
bsw@0 1608 // check privilege
bsw@0 1609 requireIssuePrivilege(conn, req, res, issue_id, function() {
bsw@0 1610
bsw@0 1611 // check issue state
bsw@0 1612 requireIssueState(conn, req, res, issue_id, ['admission', 'discussion', 'verification'], function() {
bsw@0 1613
bsw@0 1614 // check contingent
bsw@0 1615 requireContingentLeft(conn, req, res, true, function() {
bsw@0 1616
bsw@0 1617 // insert initiative
bsw@0 1618 var query = new selector.SQLInsert('initiative');
bsw@0 1619 query.addValues({
bsw@0 1620 issue_id: issue_id,
bsw@0 1621 name: initiative_name,
bsw@0 1622 discussion_url: initiative_discussion_url
bsw@0 1623 });
bsw@0 1624 query.addReturning('id');
bsw@0 1625 db.query(conn, req, res, query, function(result) {
bsw@0 1626 var initiative_id = result.rows[0].id;
bsw@0 1627
bsw@0 1628 // insert initiator
bsw@0 1629 var query = new selector.SQLInsert('initiator');
bsw@0 1630 query.addValues({
bsw@0 1631 initiative_id: initiative_id,
bsw@0 1632 member_id: req.current_member_id,
bsw@0 1633 accepted: true
bsw@0 1634 });
bsw@0 1635 db.query(conn, req, res, query, function(result) {
bsw@0 1636
bsw@0 1637 // insert draft
bsw@0 1638 var query = new selector.SQLInsert('draft');
bsw@0 1639 query.addValues({
bsw@0 1640 initiative_id: initiative_id,
bsw@0 1641 author_id: req.current_member_id,
bsw@0 1642 formatting_engine: formatting_engine,
bsw@0 1643 content: content
bsw@0 1644 });
bsw@0 1645 query.addReturning('id');
bsw@0 1646 db.query(conn, req, res, query, function (result, conn) {
bsw@0 1647
bsw@0 1648 var draft_id = result.rows[0].id;
bsw@0 1649 respond('json', conn, req, res, 'ok', { initiative_id: initiative_id, draft_id: draft_id } );
bsw@0 1650
bsw@0 1651 });
bsw@0 1652 });
bsw@0 1653 });
bsw@0 1654 });
bsw@0 1655 });
bsw@0 1656 });
bsw@0 1657
bsw@0 1658 // new draft in existant initiative
bsw@0 1659 } else if (initiative_id && !area_id && !issue_id ) {
bsw@0 1660
bsw@0 1661 // check privilege
bsw@0 1662 requireInitiativePrivilege(conn, req, res, initiative_id, function() {
bsw@0 1663
bsw@0 1664 // check issue state
bsw@0 1665 requireIssueStateForInitiative(conn, req, res, initiative_id, ['admission', 'discussion'], function() {
bsw@0 1666
bsw@0 1667
bsw@0 1668 // get initiator
bsw@0 1669 var query = new selector.Selector();
bsw@0 1670 query.from('initiator');
bsw@0 1671 query.addField('accepted');
bsw@0 1672 query.addWhere(['initiative_id = ? AND member_id = ?', initiative_id, req.current_member_id]);
bsw@0 1673 db.query(conn, req, res, query, function (result, conn) {
bsw@0 1674
bsw@0 1675 // if member is not initiator, deny creating new draft
bsw@0 1676 if (result.rows.length != 1) {
bsw@0 1677 respond('json', conn, req, res, 'forbidden', null, 'You are not initiator of this initiative and not allowed to update its draft.');
bsw@0 1678 return;
bsw@0 1679 }
bsw@0 1680 var initiator = result.rows[0];
bsw@0 1681 if (!initiator.accepted) {
bsw@0 1682 respond('json', conn, req, res, 'forbidden', null, 'You have been invited as initiator, but haven\'t accepted invitation and you are not allowed to update this initiative.');
bsw@0 1683 return;
bsw@0 1684 };
bsw@0 1685
bsw@0 1686 // check contingent
bsw@0 1687 requireContingentLeft(conn, req, res, false, function() {
bsw@0 1688
bsw@0 1689 // insert new draft
bsw@0 1690 var query = new selector.SQLInsert('draft');
bsw@0 1691 query.addValues({
bsw@0 1692 initiative_id: initiative_id,
bsw@0 1693 author_id: req.current_member_id,
bsw@0 1694 formatting_engine: formatting_engine,
bsw@0 1695 content: content
bsw@0 1696 });
bsw@0 1697 query.addReturning('id');
bsw@0 1698 db.query(conn, req, res, query, function (result, conn) {
bsw@0 1699
bsw@0 1700 var draft_id = result.rows[0].id;
bsw@0 1701 respond('json', conn, req, res, 'ok', { draft_id: draft_id } );
bsw@0 1702 });
bsw@0 1703 });
bsw@0 1704 });
bsw@0 1705 });
bsw@0 1706 });
bsw@0 1707
bsw@0 1708 // none of them (invalid request)
bsw@0 1709 } else {
bsw@0 1710 respond('json', conn, req, res, 'unprocessable', null, 'Excactly one of area_id, issue_id or initiative_id must be supplied!');
bsw@0 1711 };
bsw@0 1712
bsw@0 1713 });
bsw@0 1714 });
bsw@0 1715 },
bsw@0 1716
bsw@0 1717 '/suggestion': function (conn, req, res, params) {
bsw@0 1718 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1719 // TODO
bsw@0 1720 });
bsw@0 1721 },
bsw@0 1722
bsw@0 1723 '/opinion': function (conn, req, res, params) {
bsw@0 1724 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1725 // TODO
bsw@0 1726 });
bsw@0 1727 },
bsw@0 1728
bsw@0 1729 '/delegation': function (conn, req, res, params) {
bsw@0 1730 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1731 var unit_id = parseInt(params.unit_id);
bsw@0 1732 var area_id = parseInt(params.area_id);
bsw@0 1733 var issue_id = parseInt(params.issue_id);
bsw@0 1734 var trustee_id;
bsw@0 1735
bsw@0 1736 if (params.trustee_id == '') {
bsw@0 1737 trustee_id = null;
bsw@0 1738 } else {
bsw@0 1739 trustee_id = parseInt(params.trustee_id);
bsw@0 1740 }
bsw@0 1741
bsw@0 1742 lockMemberById(conn, req, res, req.current_member_id, function() {
bsw@0 1743
bsw@0 1744 if (params.delete) {
bsw@0 1745 var query = new selector.SQLDelete('delegation')
bsw@0 1746 if (unit_id && !area_id && !issue_id) {
bsw@0 1747 query.addWhere(['unit_id = ?', unit_id]);
bsw@0 1748 } else if (!unit_id && area_id && !issue_id) {
bsw@0 1749 query.addWhere(['area_id = ?', area_id]);
bsw@0 1750 } else if (!unit_id && !area_id && issue_id) {
bsw@0 1751 query.addWhere(['issue_id = ?', issue_id]);
bsw@0 1752 } else {
bsw@0 1753 respond('json', conn, req, res, 'unprocessable', null, 'Excactly one of unit, area_id, issue_id must be supplied!');
bsw@0 1754 return;
bsw@0 1755 }
bsw@0 1756 query.addWhere(['truster_id = ?', req.current_member_id]);
bsw@0 1757 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1758 } else {
bsw@0 1759 var query = new selector.Upserter('delegation', ['truster_id']);
bsw@0 1760 query.addValues({
bsw@0 1761 truster_id: req.current_member_id,
bsw@0 1762 trustee_id: trustee_id
bsw@0 1763 });
bsw@0 1764 if (unit_id && !area_id && !issue_id) {
bsw@0 1765
bsw@0 1766 // check privilege
bsw@0 1767 requireUnitPrivilege(conn, req, res, unit_id, function() {
bsw@0 1768
bsw@0 1769 query.addKeys(['unit_id'])
bsw@0 1770 query.addValues({ unit_id: unit_id, scope: 'unit' });
bsw@0 1771 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1772 });
bsw@0 1773
bsw@0 1774 } else if (!unit_id && area_id && !issue_id) {
bsw@0 1775
bsw@0 1776 // check privilege
bsw@0 1777 requireAreaPrivilege(conn, req, res, area_id, function() {
bsw@0 1778
bsw@0 1779 query.addKeys(['area_id'])
bsw@0 1780 query.addValues({ area_id: area_id, scope: 'area' });
bsw@0 1781 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1782 });
bsw@0 1783
bsw@0 1784 } else if (!unit_id && !area_id && issue_id) {
bsw@0 1785
bsw@0 1786 // check privilege
bsw@0 1787 requireIssuePrivilege(conn, req, res, issue_id, function() {
bsw@0 1788
bsw@0 1789 // check issue state
bsw@0 1790 requireIssueState(conn, req, res, issue_id, ['admission', 'discussion', 'verification', 'voting'], function() {
bsw@0 1791
bsw@0 1792 query.addKeys(['issue_id'])
bsw@0 1793 query.addValues({ issue_id: issue_id, scope: 'issue' });
bsw@0 1794 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1795 });
bsw@0 1796 });
bsw@0 1797 } else {
bsw@0 1798 respond('json', conn, req, res, 'unprocessable', null, 'Excactly one of unit_id, area_id, issue_id must be supplied!');
bsw@0 1799 return;
bsw@0 1800 }
bsw@0 1801 }
bsw@0 1802
bsw@0 1803 });
bsw@0 1804
bsw@0 1805 });
bsw@0 1806 },
bsw@0 1807
bsw@0 1808 };

Impressum / About Us