lfapi

annotate lfapi/main.js @ 1:9fe872cc376d

2 small bug fixes
author bsw
date Mon Sep 12 21:09:48 2011 +0200 (2011-09-12)
parents ce6f95d23e1c
children e69609a3c98a
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@1 1190 var tmp = {}
bsw@0 1191 if (typeof(params[field]) != 'undefined') {
bsw@1 1192 tmp[field] = params[field];
bsw@0 1193 } else {
bsw@1 1194 tmp[field] = null;
bsw@0 1195 }
bsw@1 1196 query.addValues(tmp);
bsw@0 1197 });
bsw@0 1198 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1199 });
bsw@0 1200 },
bsw@0 1201
bsw@0 1202 '/membership': function (conn, req, res, params) {
bsw@0 1203 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1204
bsw@0 1205 // check if area_id is set
bsw@0 1206 var area_id = parseInt(params.area_id);
bsw@0 1207 if (!area_id) {
bsw@0 1208 respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an area_id.');
bsw@0 1209 return;
bsw@0 1210 }
bsw@0 1211
bsw@0 1212 // delete membership
bsw@0 1213 if (params.delete) {
bsw@0 1214 var query;
bsw@0 1215 query = new selector.SQLDelete('membership');
bsw@0 1216 query.addWhere(['area_id = ?', area_id]);
bsw@0 1217 query.addWhere(['member_id = ?', req.current_member_id]);
bsw@0 1218 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1219
bsw@0 1220 // add membership
bsw@0 1221 } else {
bsw@0 1222
bsw@0 1223 // lock member for upsert
bsw@0 1224 lockMemberById(conn, req, res, req.current_member_id, function() {
bsw@0 1225
bsw@0 1226 // check and lock privilege
bsw@0 1227 requireAreaPrivilege(conn, req, res, area_id, function() {
bsw@0 1228
bsw@0 1229 // upsert membership
bsw@0 1230 var query = new selector.Upserter('membership', ['area_id', 'member_id']);
bsw@0 1231 query.addValues({ area_id: area_id, member_id: req.current_member_id });
bsw@0 1232 db.query(conn, req, res, query, function(result) {
bsw@0 1233 respond('json', conn, req, res, 'ok');
bsw@0 1234 });
bsw@0 1235 });
bsw@0 1236 });
bsw@0 1237 }
bsw@0 1238 });
bsw@0 1239 },
bsw@0 1240
bsw@0 1241 '/interest': function (conn, req, res, params) {
bsw@0 1242 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1243 var query;
bsw@0 1244
bsw@0 1245 // check if issue_id is set
bsw@0 1246 var issue_id = parseInt(params.issue_id);
bsw@0 1247 if (!issue_id) {
bsw@0 1248 respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an issue_id.');
bsw@0 1249 return;
bsw@0 1250 }
bsw@0 1251
bsw@0 1252 // lock member for upsert
bsw@0 1253 lockMemberById(conn, req, res, req.current_member_id, function() {
bsw@0 1254
bsw@0 1255 // delete interest
bsw@0 1256 if (params.delete) {
bsw@0 1257
bsw@0 1258 // check issue state
bsw@0 1259 requireIssueState(conn, req, res, issue_id, ['admission', 'discussion', 'verification'], function() {
bsw@0 1260
bsw@0 1261 // delete interest
bsw@0 1262 query = new selector.SQLDelete('interest');
bsw@0 1263 query.addWhere(['issue_id = ?', issue_id]);
bsw@0 1264 query.addWhere(['member_id = ?', req.current_member_id]);
bsw@0 1265 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1266 });
bsw@0 1267
bsw@0 1268 // add interest
bsw@0 1269 } else {
bsw@0 1270
bsw@0 1271 // check and lock privilege
bsw@0 1272 requireIssuePrivilege(conn, req, res, issue_id, function() {
bsw@0 1273
bsw@0 1274 // check issue state
bsw@0 1275 requireIssueState(conn, req, res, issue_id, ['admission', 'discussion', 'verification'], function() {
bsw@0 1276
bsw@0 1277 // upsert interest
bsw@0 1278 var query = new selector.Upserter('interest', ['issue_id', 'member_id']);
bsw@0 1279 query.addValues({ issue_id: issue_id, member_id: req.current_member_id });
bsw@0 1280 db.query(conn, req, res, query, function(result) {
bsw@0 1281 respond('json', conn, req, res, 'ok');
bsw@0 1282 });
bsw@0 1283 });
bsw@0 1284 });
bsw@0 1285 };
bsw@0 1286 });
bsw@0 1287 });
bsw@0 1288 },
bsw@0 1289
bsw@0 1290 '/issue_comment': function (conn, req, res, params) {
bsw@0 1291 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1292
bsw@0 1293 var issue_id = parseInt(params.issue_id);
bsw@0 1294 var formatting_engine = params.formatting_engine
bsw@0 1295 var content = params.content;
bsw@0 1296
bsw@0 1297 if (!issue_id) {
bsw@0 1298 respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an issue_id.');
bsw@0 1299 return;
bsw@0 1300 }
bsw@0 1301
bsw@0 1302 // delete issue comment
bsw@0 1303 if (params.delete) {
bsw@0 1304 var query;
bsw@0 1305 query = new selector.SQLDelete('issue_comment');
bsw@0 1306 query.addWhere(['issue_id = ?', params.issue_id]);
bsw@0 1307 query.addWhere(['member_id = ?', req.current_member_id]);
bsw@0 1308 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1309
bsw@0 1310 // upsert issue comment
bsw@0 1311 } else {
bsw@0 1312
bsw@0 1313 // check if formatting engine is supplied and valid
bsw@0 1314 if (!formatting_engine) {
bsw@0 1315 respond('json', conn, req, res, 'unprocessable', null, 'No formatting engine supplied.');
bsw@0 1316 return;
bsw@0 1317 } else if (formatting_engine != 'rocketwiki' && formatting_engine != 'compat') {
bsw@0 1318 respond('json', conn, req, res, 'unprocessable', null, 'Invalid formatting engine supplied.');
bsw@0 1319 return;
bsw@0 1320 };
bsw@0 1321
bsw@0 1322 // check if content is supplied
bsw@0 1323 if (!content) {
bsw@0 1324 respond('json', conn, req, res, 'unprocessable', null, 'No content supplied.');
bsw@0 1325 return;
bsw@0 1326 }
bsw@0 1327
bsw@0 1328 // lock member for upsert
bsw@0 1329 lockMemberById(conn, req, res, req.current_member_id, function() {
bsw@0 1330
bsw@0 1331 // check and lock privilege
bsw@0 1332 requireIssuePrivilege(conn, req, res, issue_id, function() {
bsw@0 1333
bsw@0 1334 // upsert issue comment
bsw@0 1335 var query = new selector.Upserter('issue_comment', ['issue_id', 'member_id']);
bsw@0 1336 query.addValues({
bsw@0 1337 issue_id: issue_id,
bsw@0 1338 member_id: req.current_member_id,
bsw@0 1339 changed: 'now',
bsw@0 1340 formatting_engine: formatting_engine,
bsw@0 1341 content: content
bsw@0 1342 });
bsw@0 1343
bsw@0 1344 db.query(conn, req, res, query, function(result) {
bsw@0 1345 respond('json', conn, req, res, 'ok');
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 },
bsw@0 1355
bsw@0 1356 '/voting_comment': function (conn, req, res, params) {
bsw@0 1357 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1358
bsw@0 1359 var issue_id = parseInt(params.issue_id);
bsw@0 1360 var formatting_engine = params.formatting_engine
bsw@0 1361 var content = params.content;
bsw@0 1362
bsw@0 1363 if (!issue_id) {
bsw@0 1364 respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an issue_id.');
bsw@0 1365 return;
bsw@0 1366 }
bsw@0 1367
bsw@0 1368
bsw@0 1369 // delete voting comment
bsw@0 1370 if (params.delete) {
bsw@0 1371 var query;
bsw@0 1372 query = new selector.SQLDelete('voting_comment');
bsw@0 1373 query.addWhere(['issue_id = ?', params.issue_id]);
bsw@0 1374 query.addWhere(['member_id = ?', req.current_member_id]);
bsw@0 1375 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1376
bsw@0 1377 // upsert voting comment
bsw@0 1378 } else {
bsw@0 1379
bsw@0 1380 // check if formatting engine is supplied and valid
bsw@0 1381 if (!formatting_engine) {
bsw@0 1382 respond('json', conn, req, res, 'unprocessable', null, 'No formatting engine supplied.');
bsw@0 1383 return;
bsw@0 1384 } else if (formatting_engine != 'rocketwiki' && formatting_engine != 'compat') {
bsw@0 1385 respond('json', conn, req, res, 'unprocessable', null, 'Invalid formatting engine supplied.');
bsw@0 1386 return;
bsw@0 1387 };
bsw@0 1388
bsw@0 1389 // check if content is supplied
bsw@0 1390 if (!content) {
bsw@0 1391 respond('json', conn, req, res, 'unprocessable', null, 'No content supplied.');
bsw@0 1392 return;
bsw@0 1393 }
bsw@0 1394
bsw@0 1395 // lock member for upsert
bsw@0 1396 lockMemberById(conn, req, res, req.current_member_id, function() {
bsw@0 1397
bsw@0 1398 // check and lock privilege
bsw@0 1399 requireIssuePrivilege(conn, req, res, issue_id, function() {
bsw@0 1400
bsw@0 1401 // check issue state
bsw@0 1402 requireIssueState(conn, req, res, issue_id, ['voting', 'finished_with_winner', 'finished_without_winner'], function() {
bsw@0 1403
bsw@0 1404 // upsert voting comment
bsw@0 1405 var query = new selector.Upserter('voting_comment', ['issue_id', 'member_id']);
bsw@0 1406 query.addValues({
bsw@0 1407 issue_id: issue_id,
bsw@0 1408 member_id: req.current_member_id,
bsw@0 1409 changed: 'now',
bsw@0 1410 formatting_engine: formatting_engine,
bsw@0 1411 content: content
bsw@0 1412 });
bsw@0 1413
bsw@0 1414 db.query(conn, req, res, query, function(result) {
bsw@0 1415 respond('json', conn, req, res, 'ok');
bsw@0 1416 });
bsw@0 1417
bsw@0 1418 });
bsw@0 1419 });
bsw@0 1420 })
bsw@0 1421 };
bsw@0 1422 });
bsw@0 1423 },
bsw@0 1424
bsw@0 1425 '/supporter': function (conn, req, res, params) {
bsw@0 1426 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1427 var initiative_id = parseInt(params.initiative_id);
bsw@0 1428 var draft_id = parseInt(params.draft_id);
bsw@0 1429
bsw@0 1430 // check if needed arguments are supplied
bsw@0 1431 if (!initiative_id) {
bsw@0 1432 respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an initiative_id.');
bsw@0 1433 return;
bsw@0 1434 }
bsw@0 1435
bsw@0 1436 if (!draft_id) {
bsw@0 1437 respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an draft_id.');
bsw@0 1438 return;
bsw@0 1439 }
bsw@0 1440
bsw@0 1441 // lock member for upsert
bsw@0 1442 lockMemberById(conn, req, res, req.current_member_id, function() {
bsw@0 1443
bsw@0 1444 // delete supporter
bsw@0 1445 if (params.delete) {
bsw@0 1446
bsw@0 1447 // check issue state
bsw@0 1448 requireIssueStateForInitiative(conn, req, res, initiative_id, ['admission', 'discussion', 'verification'], function() {
bsw@0 1449
bsw@0 1450 // delete supporter
bsw@0 1451 var query = new selector.SQLDelete('supporter');
bsw@0 1452 query.addWhere(['initiative_id = ?', initiative_id]);
bsw@0 1453 query.addWhere(['member_id = ?', req.current_member_id]);
bsw@0 1454 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1455
bsw@0 1456 });
bsw@0 1457
bsw@0 1458 // upsert supporter
bsw@0 1459 } else {
bsw@0 1460
bsw@0 1461 // check and lock privilege
bsw@0 1462 requireInitiativePrivilege(conn, req, res, initiative_id, function() {
bsw@0 1463
bsw@0 1464 // check issue state
bsw@0 1465 requireIssueStateForInitiative(conn, req, res, initiative_id, ['admission', 'discussion', 'verification'], function() {
bsw@0 1466
bsw@0 1467 // check if given draft is the current one
bsw@0 1468 var query = new selector.Selector('current_draft');
bsw@0 1469 query.addField('NULL');
bsw@0 1470 query.addWhere(['current_draft.initiative_id = ?', initiative_id]);
bsw@0 1471 query.addWhere(['current_draft.id = ?', draft_id]);
bsw@0 1472
bsw@0 1473 db.query(conn, req, res, query, function(result) {
bsw@0 1474 if (result.rows.length != 1) {
bsw@0 1475 respond('json', conn, req, res, 'conflict', null, 'The draft with the supplied draft_id is not the current one anymore!');
bsw@0 1476 return;
bsw@0 1477 }
bsw@0 1478
bsw@0 1479 // upsert supporter
bsw@0 1480 var query = new selector.Upserter('supporter', ['initiative_id', 'member_id']);
bsw@0 1481 query.addValues({
bsw@0 1482 initiative_id: initiative_id,
bsw@0 1483 member_id: req.current_member_id,
bsw@0 1484 draft_id: draft_id
bsw@0 1485 });
bsw@0 1486
bsw@0 1487 db.query(conn, req, res, query, function(result) {
bsw@0 1488 respond('json', conn, req, res, 'ok');
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 },
bsw@0 1498
bsw@0 1499 '/draft': function (conn, req, res, params) {
bsw@0 1500 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1501 var area_id = parseInt(params.area_id);
bsw@0 1502 var policy_id = parseInt(params.policy_id);
bsw@0 1503 var issue_id = parseInt(params.issue_id);
bsw@0 1504 var initiative_id = parseInt(params.initiative_id);
bsw@0 1505 var initiative_name = params.initiative_name;
bsw@0 1506 var initiative_discussion_url = params.initiative_discussion_url;
bsw@0 1507 var formatting_engine = params.formatting_engine;
bsw@0 1508 var content = params.content;
bsw@0 1509
bsw@0 1510 if (!initiative_discussion_url) initiative_discussion_url = null;
bsw@0 1511
bsw@0 1512 // check parameters
bsw@0 1513 if (!formatting_engine) {
bsw@0 1514 respond('json', conn, req, res, 'unprocessable', null, 'No formatting_engine supplied.');
bsw@0 1515 return;
bsw@0 1516 } else if (formatting_engine != 'rocketwiki' && formatting_engine != 'compat') {
bsw@0 1517 respond('json', conn, req, res, 'unprocessable', null, 'Invalid formatting engine supplied.');
bsw@0 1518 return;
bsw@0 1519 };
bsw@0 1520
bsw@0 1521 if (!content) {
bsw@0 1522 respond('json', conn, req, res, 'unprocessable', null, 'No draft content supplied.');
bsw@0 1523 return;
bsw@0 1524 };
bsw@0 1525
bsw@0 1526 lockMemberById(conn, req, res, req.current_member_id, function() {
bsw@0 1527
bsw@0 1528 // new draft in new initiative in new issue
bsw@0 1529 if (area_id && !issue_id && !initiative_id) {
bsw@0 1530
bsw@0 1531 // check parameters for new issue
bsw@0 1532 if (!policy_id) {
bsw@0 1533 respond('json', conn, req, res, 'unprocessable', null, 'No policy supplied.');
bsw@0 1534 return;
bsw@0 1535 }
bsw@0 1536
bsw@0 1537 if (!initiative_name) {
bsw@0 1538 respond('json', conn, req, res, 'unprocessable', null, 'No initiative name supplied.');
bsw@0 1539 return;
bsw@0 1540 }
bsw@0 1541
bsw@0 1542 requireAreaPrivilege(conn, req, res, area_id, function() {
bsw@0 1543
bsw@0 1544 // check if policy is allowed in this area and if area and policy are active
bsw@0 1545 var query = new selector.Selector();
bsw@0 1546 query.from('allowed_policy');
bsw@0 1547 query.join('area', null, 'area.id = allowed_policy.area_id AND area.active');
bsw@0 1548 query.join('policy', null, 'policy.id = allowed_policy.policy_id AND policy.active');
bsw@0 1549 query.addField('NULL');
bsw@0 1550 query.addWhere(['area.id = ? AND policy.id = ?', area_id, policy_id]);
bsw@0 1551 db.query(conn, req, res, query, function (result, conn) {
bsw@0 1552 if (result.rows.length != 1) {
bsw@0 1553 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 1554 return;
bsw@0 1555 };
bsw@0 1556
bsw@0 1557 // check contingent
bsw@0 1558 requireContingentLeft(conn, req, res, true, function() {
bsw@0 1559
bsw@0 1560 // insert new issue
bsw@0 1561 var query = new selector.SQLInsert('issue');
bsw@0 1562 query.addValues({
bsw@0 1563 area_id: area_id,
bsw@0 1564 policy_id: policy_id
bsw@0 1565 });
bsw@0 1566 query.addReturning('id');
bsw@0 1567 db.query(conn, req, res, query, function(result) {
bsw@0 1568 var issue_id = result.rows[0].id;
bsw@0 1569
bsw@0 1570 // insert new initiative
bsw@0 1571 var query = new selector.SQLInsert('initiative');
bsw@0 1572 query.addValues({
bsw@0 1573 issue_id: issue_id,
bsw@0 1574 name: initiative_name,
bsw@0 1575 discussion_url: initiative_discussion_url
bsw@0 1576 });
bsw@0 1577 query.addReturning('id');
bsw@0 1578 db.query(conn, req, res, query, function(result) {
bsw@0 1579 var initiative_id = result.rows[0].id;
bsw@0 1580
bsw@0 1581 // insert initiator
bsw@0 1582 var query = new selector.SQLInsert('initiator');
bsw@0 1583 query.addValues({ initiative_id: initiative_id, member_id: req.current_member_id, accepted: true });
bsw@0 1584 db.query(conn, req, res, query, function(result) {
bsw@0 1585
bsw@0 1586 // insert new draft
bsw@0 1587 var query = new selector.SQLInsert('draft');
bsw@0 1588 query.addValues({
bsw@0 1589 initiative_id: initiative_id,
bsw@0 1590 author_id: req.current_member_id,
bsw@0 1591 formatting_engine: formatting_engine,
bsw@0 1592 content: content
bsw@0 1593 });
bsw@0 1594 query.addReturning('id');
bsw@0 1595 db.query(conn, req, res, query, function (result, conn) {
bsw@0 1596 var draft_id = result.rows[0].id;
bsw@0 1597
bsw@0 1598 respond('json', conn, req, res, 'ok', { issue_id: issue_id, initiative_id: initiative_id, draft_id: draft_id } );
bsw@0 1599 });
bsw@0 1600 });
bsw@0 1601 });
bsw@0 1602 });
bsw@0 1603 });
bsw@0 1604 });
bsw@0 1605 });
bsw@0 1606
bsw@0 1607 // new draft in new initiative in existant issue
bsw@0 1608 } else if (issue_id && !area_id && !initiative_id) {
bsw@0 1609
bsw@0 1610 // check privilege
bsw@0 1611 requireIssuePrivilege(conn, req, res, issue_id, function() {
bsw@0 1612
bsw@0 1613 // check issue state
bsw@0 1614 requireIssueState(conn, req, res, issue_id, ['admission', 'discussion', 'verification'], function() {
bsw@0 1615
bsw@0 1616 // check contingent
bsw@0 1617 requireContingentLeft(conn, req, res, true, function() {
bsw@0 1618
bsw@0 1619 // insert initiative
bsw@0 1620 var query = new selector.SQLInsert('initiative');
bsw@0 1621 query.addValues({
bsw@0 1622 issue_id: issue_id,
bsw@0 1623 name: initiative_name,
bsw@0 1624 discussion_url: initiative_discussion_url
bsw@0 1625 });
bsw@0 1626 query.addReturning('id');
bsw@0 1627 db.query(conn, req, res, query, function(result) {
bsw@0 1628 var initiative_id = result.rows[0].id;
bsw@0 1629
bsw@0 1630 // insert initiator
bsw@0 1631 var query = new selector.SQLInsert('initiator');
bsw@0 1632 query.addValues({
bsw@0 1633 initiative_id: initiative_id,
bsw@0 1634 member_id: req.current_member_id,
bsw@0 1635 accepted: true
bsw@0 1636 });
bsw@0 1637 db.query(conn, req, res, query, function(result) {
bsw@0 1638
bsw@0 1639 // insert draft
bsw@0 1640 var query = new selector.SQLInsert('draft');
bsw@0 1641 query.addValues({
bsw@0 1642 initiative_id: initiative_id,
bsw@0 1643 author_id: req.current_member_id,
bsw@0 1644 formatting_engine: formatting_engine,
bsw@0 1645 content: content
bsw@0 1646 });
bsw@0 1647 query.addReturning('id');
bsw@0 1648 db.query(conn, req, res, query, function (result, conn) {
bsw@0 1649
bsw@0 1650 var draft_id = result.rows[0].id;
bsw@0 1651 respond('json', conn, req, res, 'ok', { initiative_id: initiative_id, draft_id: draft_id } );
bsw@0 1652
bsw@0 1653 });
bsw@0 1654 });
bsw@0 1655 });
bsw@0 1656 });
bsw@0 1657 });
bsw@0 1658 });
bsw@0 1659
bsw@0 1660 // new draft in existant initiative
bsw@0 1661 } else if (initiative_id && !area_id && !issue_id ) {
bsw@0 1662
bsw@0 1663 // check privilege
bsw@0 1664 requireInitiativePrivilege(conn, req, res, initiative_id, function() {
bsw@0 1665
bsw@0 1666 // check issue state
bsw@0 1667 requireIssueStateForInitiative(conn, req, res, initiative_id, ['admission', 'discussion'], function() {
bsw@0 1668
bsw@0 1669
bsw@0 1670 // get initiator
bsw@0 1671 var query = new selector.Selector();
bsw@0 1672 query.from('initiator');
bsw@0 1673 query.addField('accepted');
bsw@0 1674 query.addWhere(['initiative_id = ? AND member_id = ?', initiative_id, req.current_member_id]);
bsw@0 1675 db.query(conn, req, res, query, function (result, conn) {
bsw@0 1676
bsw@0 1677 // if member is not initiator, deny creating new draft
bsw@0 1678 if (result.rows.length != 1) {
bsw@0 1679 respond('json', conn, req, res, 'forbidden', null, 'You are not initiator of this initiative and not allowed to update its draft.');
bsw@0 1680 return;
bsw@0 1681 }
bsw@0 1682 var initiator = result.rows[0];
bsw@0 1683 if (!initiator.accepted) {
bsw@0 1684 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 1685 return;
bsw@0 1686 };
bsw@0 1687
bsw@0 1688 // check contingent
bsw@0 1689 requireContingentLeft(conn, req, res, false, function() {
bsw@0 1690
bsw@0 1691 // insert new draft
bsw@0 1692 var query = new selector.SQLInsert('draft');
bsw@0 1693 query.addValues({
bsw@0 1694 initiative_id: initiative_id,
bsw@0 1695 author_id: req.current_member_id,
bsw@0 1696 formatting_engine: formatting_engine,
bsw@0 1697 content: content
bsw@0 1698 });
bsw@0 1699 query.addReturning('id');
bsw@0 1700 db.query(conn, req, res, query, function (result, conn) {
bsw@0 1701
bsw@0 1702 var draft_id = result.rows[0].id;
bsw@0 1703 respond('json', conn, req, res, 'ok', { draft_id: draft_id } );
bsw@0 1704 });
bsw@0 1705 });
bsw@0 1706 });
bsw@0 1707 });
bsw@0 1708 });
bsw@0 1709
bsw@0 1710 // none of them (invalid request)
bsw@0 1711 } else {
bsw@0 1712 respond('json', conn, req, res, 'unprocessable', null, 'Excactly one of area_id, issue_id or initiative_id must be supplied!');
bsw@0 1713 };
bsw@0 1714
bsw@0 1715 });
bsw@0 1716 });
bsw@0 1717 },
bsw@0 1718
bsw@0 1719 '/suggestion': function (conn, req, res, params) {
bsw@0 1720 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1721 // TODO
bsw@0 1722 });
bsw@0 1723 },
bsw@0 1724
bsw@0 1725 '/opinion': function (conn, req, res, params) {
bsw@0 1726 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1727 // TODO
bsw@0 1728 });
bsw@0 1729 },
bsw@0 1730
bsw@0 1731 '/delegation': function (conn, req, res, params) {
bsw@0 1732 requireAccessLevel(conn, req, res, 'member', function() {
bsw@0 1733 var unit_id = parseInt(params.unit_id);
bsw@0 1734 var area_id = parseInt(params.area_id);
bsw@0 1735 var issue_id = parseInt(params.issue_id);
bsw@0 1736 var trustee_id;
bsw@0 1737
bsw@0 1738 if (params.trustee_id == '') {
bsw@0 1739 trustee_id = null;
bsw@0 1740 } else {
bsw@0 1741 trustee_id = parseInt(params.trustee_id);
bsw@0 1742 }
bsw@0 1743
bsw@0 1744 lockMemberById(conn, req, res, req.current_member_id, function() {
bsw@0 1745
bsw@0 1746 if (params.delete) {
bsw@0 1747 var query = new selector.SQLDelete('delegation')
bsw@0 1748 if (unit_id && !area_id && !issue_id) {
bsw@0 1749 query.addWhere(['unit_id = ?', unit_id]);
bsw@0 1750 } else if (!unit_id && area_id && !issue_id) {
bsw@0 1751 query.addWhere(['area_id = ?', area_id]);
bsw@0 1752 } else if (!unit_id && !area_id && issue_id) {
bsw@0 1753 query.addWhere(['issue_id = ?', issue_id]);
bsw@0 1754 } else {
bsw@0 1755 respond('json', conn, req, res, 'unprocessable', null, 'Excactly one of unit, area_id, issue_id must be supplied!');
bsw@0 1756 return;
bsw@0 1757 }
bsw@0 1758 query.addWhere(['truster_id = ?', req.current_member_id]);
bsw@0 1759 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1760 } else {
bsw@0 1761 var query = new selector.Upserter('delegation', ['truster_id']);
bsw@0 1762 query.addValues({
bsw@0 1763 truster_id: req.current_member_id,
bsw@0 1764 trustee_id: trustee_id
bsw@0 1765 });
bsw@0 1766 if (unit_id && !area_id && !issue_id) {
bsw@0 1767
bsw@0 1768 // check privilege
bsw@0 1769 requireUnitPrivilege(conn, req, res, unit_id, function() {
bsw@0 1770
bsw@0 1771 query.addKeys(['unit_id'])
bsw@0 1772 query.addValues({ unit_id: unit_id, scope: 'unit' });
bsw@0 1773 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1774 });
bsw@0 1775
bsw@0 1776 } else if (!unit_id && area_id && !issue_id) {
bsw@0 1777
bsw@0 1778 // check privilege
bsw@0 1779 requireAreaPrivilege(conn, req, res, area_id, function() {
bsw@0 1780
bsw@0 1781 query.addKeys(['area_id'])
bsw@0 1782 query.addValues({ area_id: area_id, scope: 'area' });
bsw@0 1783 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1784 });
bsw@0 1785
bsw@0 1786 } else if (!unit_id && !area_id && issue_id) {
bsw@0 1787
bsw@0 1788 // check privilege
bsw@0 1789 requireIssuePrivilege(conn, req, res, issue_id, function() {
bsw@0 1790
bsw@0 1791 // check issue state
bsw@0 1792 requireIssueState(conn, req, res, issue_id, ['admission', 'discussion', 'verification', 'voting'], function() {
bsw@0 1793
bsw@0 1794 query.addKeys(['issue_id'])
bsw@0 1795 query.addValues({ issue_id: issue_id, scope: 'issue' });
bsw@0 1796 db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); });
bsw@0 1797 });
bsw@0 1798 });
bsw@0 1799 } else {
bsw@0 1800 respond('json', conn, req, res, 'unprocessable', null, 'Excactly one of unit_id, area_id, issue_id must be supplied!');
bsw@0 1801 return;
bsw@0 1802 }
bsw@0 1803 }
bsw@0 1804
bsw@0 1805 });
bsw@0 1806
bsw@0 1807 });
bsw@0 1808 },
bsw@0 1809
bsw@0 1810 };

Impressum / About Us