bsw@0: var api_version = '0.2.0'; bsw@0: bsw@0: // creates a random string with the given length bsw@0: function randomString(number_of_chars) { bsw@0: var charset, rand, i, ret; bsw@0: charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; bsw@0: random_string = ''; bsw@0: bsw@0: for (var i = 0; i < number_of_chars; i++) { bsw@0: random_string += charset[parseInt(Math.random() * charset.length)] bsw@0: } bsw@0: return random_string; bsw@0: } bsw@0: bsw@0: var fields = require('./fields.js'); bsw@0: bsw@0: var general_params = require('./general_params.js'); bsw@0: bsw@0: var config = general_params.config; bsw@0: exports.config = config; bsw@0: bsw@0: var db = require('./db.js'); bsw@0: exports.db = db; bsw@0: bsw@0: var selector = db.selector; bsw@0: bsw@0: var email = require('mailer'); bsw@0: bsw@0: bsw@0: // check if current session has at least given access level, returns error to client if not. bsw@0: // used by request handlers below bsw@0: function requireAccessLevel(conn, req, res, access_level, callback) { bsw@0: switch (access_level) { bsw@0: case 'anonymous': bsw@0: if (req.current_access_level == 'anonymous') { callback(); return; }; bsw@0: case 'pseudonym': bsw@0: if (req.current_access_level == 'pseudonym') { callback(); return; }; bsw@0: case 'full': bsw@0: if (req.current_access_level == 'full') { callback(); return; }; bsw@0: case 'member': bsw@0: if (req.current_member_id) { callback(); return; }; bsw@0: default: bsw@0: respond('json', conn, req, res, 'forbidden', { error: 'Access denied' }); bsw@0: } bsw@0: }; bsw@0: bsw@0: // callback function, encoding result and sending it to the client bsw@0: function respond(mode, conn, req, res, status, object, err) { bsw@0: var http_status = 500; bsw@0: var command; bsw@0: bsw@0: if (status == 'ok') { bsw@0: command = 'COMMIT'; bsw@0: } else { bsw@0: command = 'ROLLBACK'; bsw@0: }; bsw@0: bsw@0: switch (status) { bsw@0: case 'ok': bsw@0: http_status = 200; bsw@0: break; bsw@0: case 'forbidden': bsw@0: //http_status = 403; bsw@0: break; bsw@0: case 'notfound': bsw@0: http_status = 404; bsw@0: break; bsw@0: case 'unprocessable': bsw@0: //http_status = 422; bsw@0: break; bsw@0: case 'conflict': bsw@0: //http_status = 409; bsw@0: break; bsw@0: }; bsw@0: bsw@0: var query; bsw@0: if (mode == 'json' && ! err) query = 'SELECT null'; bsw@0: db.query(conn, req, res, query, function(result, conn) { bsw@0: db.query(conn, req, res, command, function (result, conn) { bsw@0: bsw@0: if (conn && typeof(conn) != 'string') conn.drain(); bsw@0: bsw@0: if (mode == 'json') { bsw@0: if (! object) object = {}; bsw@0: } else if (mode == 'html') { bsw@0: if (! object) object = 'no content'; bsw@0: if (err) object = "Error: " + err; bsw@0: } bsw@0: bsw@0: object.status = status; bsw@0: object.error = err; bsw@0: bsw@0: if (mode == 'json') { bsw@0: var body = JSON.stringify(object); bsw@0: var content_type = 'application/json'; bsw@0: if (req.params && req.params.callback) { bsw@0: body = req.params.callback + '(' + body + ')'; bsw@0: content_type = 'text/javascript'; bsw@0: } bsw@0: res.writeHead( bsw@0: http_status, bsw@0: { bsw@0: 'Content-Type': content_type, bsw@0: //'Content-Length': body.length bsw@0: } bsw@0: ); bsw@0: res.end(body); bsw@0: } else if (mode == 'html') { bsw@0: var body = ['lfapi'] bsw@0: body.push(object) bsw@0: body.push('') bsw@0: body = body.join(''); bsw@0: res.writeHead( bsw@0: http_status, bsw@0: { bsw@0: 'Content-Type': 'text/html', bsw@0: 'Content-Length': body.length bsw@0: } bsw@0: ); bsw@0: res.end(body); bsw@0: } bsw@0: }) bsw@0: }); bsw@0: }; bsw@0: bsw@0: exports.respond = respond; bsw@0: db.error_handler = respond; bsw@0: bsw@0: // add requested related data for requests with include_* parameters bsw@0: function addRelatedData(conn, req, res, result, includes) { bsw@0: if (includes.length > 0) { bsw@0: var include = includes.shift(); bsw@0: var class = include.class; bsw@0: var objects = result[include.objects]; bsw@0: bsw@0: var query; bsw@0: bsw@0: if (objects) { bsw@0: var objects_exists = false; bsw@0: query = new selector.Selector(); bsw@0: var ids_hash = {}; bsw@0: if (typeof(objects) == 'array') { bsw@0: if (objects.length > 0) { bsw@0: objects_exists = true; bsw@0: objects.forEach( function(object) { bsw@0: if (object[class + "_id"]) { bsw@0: ids_hash[object[class + "_id"]] = true; bsw@0: }; bsw@0: }); bsw@0: } bsw@0: } else { bsw@0: for (var key in objects) { bsw@0: objects_exists = true; bsw@0: var object = objects[key]; bsw@0: if (object[class + "_id"]) { bsw@0: ids_hash[object[class + "_id"]] = true; bsw@0: }; bsw@0: }; bsw@0: }; bsw@0: bsw@0: if (objects_exists) { bsw@0: var ids = []; bsw@0: for (key in ids_hash) { bsw@0: ids.push(key) bsw@0: } bsw@0: bsw@0: query.from(class); bsw@0: query.addWhere([class + '.id IN (??)', ids]); bsw@0: fields.addObjectFields(query, class); bsw@0: }; bsw@0: }; bsw@0: bsw@0: db.query(conn, req, res, query, function (result2, conn) { bsw@0: // add result to main result, regarding correct pluralization bsw@0: var tmp = {}; bsw@0: if (result2) { bsw@0: result2.rows.forEach( function(row) { bsw@0: tmp[row.id] = row; bsw@0: }); bsw@0: }; bsw@0: bsw@0: if (class == 'policy') { bsw@0: result['policies'] = tmp; bsw@0: } else { bsw@0: result[class + 's'] = tmp; bsw@0: } bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: } else { bsw@0: respond('json', conn, req, res, 'ok', result); bsw@0: }; bsw@0: bsw@0: }; bsw@0: bsw@0: function lockMemberById(conn, req, res, member_id, callback) { bsw@0: var query = new selector.Selector('member'); bsw@0: query.addField('NULL'); bsw@0: query.addWhere(['member.id = ?', member_id]); bsw@0: query.forUpdate(); bsw@0: db.query(conn, req, res, query, callback); bsw@0: }; bsw@0: bsw@0: function requireUnitPrivilege(conn, req, res, unit_id, callback) { bsw@0: var query = new selector.Selector('privilege'); bsw@0: query.addField('NULL'); bsw@0: query.addWhere(['privilege.member_id = ?', req.current_member_id]); bsw@0: query.addWhere(['privilege.unit_id = ?', unit_id ]); bsw@0: query.addWhere('privilege.voting_right'); bsw@0: query.forShareOf('privilege'); bsw@0: db.query(conn, req, res, query, function(result, conn) { bsw@0: if (result.rows.length != 1) { bsw@0: respond('json', conn, req, res, 'forbidden', null, 'You have no voting right for this unit.'); bsw@0: return; bsw@0: } bsw@0: callback(); bsw@0: }); bsw@0: }; bsw@0: bsw@0: function requireAreaPrivilege(conn, req, res, area_id, callback) { bsw@0: var query = new selector.Selector('privilege'); bsw@0: query.join('area', null, 'area.unit_id = privilege.unit_id'); bsw@0: query.addField('NULL'); bsw@0: query.addWhere(['privilege.member_id = ?', req.current_member_id]); bsw@0: query.addWhere(['area.id = ?', area_id ]); bsw@0: query.addWhere('privilege.voting_right'); bsw@0: query.forShareOf('privilege'); bsw@0: db.query(conn, req, res, query, function(result, conn) { bsw@0: if (result.rows.length != 1) { bsw@0: respond('json', conn, req, res, 'forbidden', null, 'You have no voting right for areas in this unit.'); bsw@0: return; bsw@0: } bsw@0: callback(); bsw@0: }); bsw@0: }; bsw@0: bsw@0: function requireIssuePrivilege(conn, req, res, issue_id, callback) { bsw@0: var query = new selector.Selector('privilege'); bsw@0: query.join('area', null, 'area.unit_id = privilege.unit_id'); bsw@0: query.join('issue', null, 'issue.area_id = area.id'); bsw@0: query.addField('NULL'); bsw@0: query.addWhere(['privilege.member_id = ?', req.current_member_id]); bsw@0: query.addWhere(['issue.id = ?', issue_id ]); bsw@0: query.addWhere('privilege.voting_right'); bsw@0: query.forShareOf('privilege'); bsw@0: db.query(conn, req, res, query, function(result, conn) { bsw@0: if (result.rows.length != 1) { bsw@0: respond('json', conn, req, res, 'forbidden', null, 'You have no voting right for issues in this unit.'); bsw@0: return; bsw@0: } bsw@0: callback(); bsw@0: }); bsw@0: }; bsw@0: bsw@0: function requireInitiativePrivilege(conn, req, res, initiative_id, callback) { bsw@0: var query = new selector.Selector('privilege'); bsw@0: query.join('area', null, 'area.unit_id = privilege.unit_id'); bsw@0: query.join('issue', null, 'issue.area_id = area.id'); bsw@0: query.join('initiative', null, 'initiative.issue_id = issue.id'); bsw@0: query.addField('NULL'); bsw@0: query.addWhere(['privilege.member_id = ?', req.current_member_id]); bsw@0: query.addWhere(['initiative.id = ?', initiative_id ]); bsw@0: query.addWhere('privilege.voting_right'); bsw@0: query.forShareOf('privilege'); bsw@0: db.query(conn, req, res, query, function(result, conn) { bsw@0: if (result.rows.length != 1) { bsw@0: respond('json', conn, req, res, 'forbidden', null, 'You have no voting right for initiatives in this unit.'); bsw@0: return; bsw@0: } bsw@0: callback(); bsw@0: }); bsw@0: }; bsw@0: bsw@0: function requireIssueState(conn, req, res, issue_id, required_states, callback) { bsw@0: var query = new selector.Selector('issue'); bsw@0: query.addField('NULL'); bsw@0: query.addWhere(['issue.id = ?', issue_id]); bsw@0: query.addWhere(['issue.state IN (??)', required_states]); bsw@0: query.forUpdateOf('issue'); bsw@0: db.query(conn, req, res, query, function(result, conn) { bsw@0: if (result.rows.length != 1) { bsw@0: respond('json', conn, req, res, 'forbidden', null, 'Issue is in wrong state.'); bsw@0: return; bsw@0: } bsw@0: callback(); bsw@0: }); bsw@0: }; bsw@0: bsw@0: function requireIssueStateForInitiative(conn, req, res, initiative_id, required_states, callback) { bsw@0: var query = new selector.Selector('issue'); bsw@0: query.join('initiative', null, 'initiative.issue_id = issue.id'); bsw@0: query.addField('NULL'); bsw@0: query.addWhere(['initiative.id = ?', initiative_id]); bsw@0: query.addWhere(['issue.state IN (??)', required_states]); bsw@0: query.forUpdateOf('issue'); bsw@0: db.query(conn, req, res, query, function(result, conn) { bsw@0: if (result.rows.length != 1) { bsw@0: respond('json', conn, req, res, 'forbidden', null, 'Issue is in wrong state.'); bsw@0: return; bsw@0: } bsw@0: callback(); bsw@0: }); bsw@0: } bsw@0: bsw@0: function requireContingentLeft(conn, req, res, is_initiative, callback) { bsw@0: var query = new selector.Selector('member_contingent_left'); bsw@0: query.addField('NULL'); bsw@0: query.addWhere(['member_contingent_left.member_id = ?', req.current_member_id]); bsw@0: query.addWhere('member_contingent_left.text_entries_left >= 1'); bsw@0: if (is_initiative) { bsw@0: query.addWhere('member_contingent_left.initiatives_left >= 1'); bsw@0: } bsw@0: db.query(conn, req, res, query, function(result, conn) { bsw@0: if (result.rows.length != 1) { bsw@0: respond('json', conn, req, res, 'forbidden', null, 'Contingent empty.'); bsw@0: return; bsw@0: } bsw@0: callback(); bsw@0: }); bsw@0: } bsw@0: bsw@0: // ========================================================================== bsw@0: // GETT methods bsw@0: // ========================================================================== bsw@0: bsw@0: bsw@0: exports.get = { bsw@0: bsw@0: // startpage (html) for users bsw@0: // currently used for implementing public alpha test bsw@0: '/': function (conn, req, res, params) { bsw@0: bsw@0: var html = []; bsw@0: html.push('

welcome to lfapi public developer alpha test

'); bsw@0: html.push('

This service is provided for testing purposes and is dedicated to developers interested in creating applications based on LiquidFeedback.

'); bsw@0: html.push('

how to use

'); bsw@0: html.push('

The programming interface is described in the LiquidFeedback API specification.

') bsw@0: html.push('

The current implementation status of lfapi is published at the LiquidFeedback API server page in our Wiki.

'); bsw@0: html.push('

Neither the API specification nor the implementation of lfapi is finished yet. This public test should enable developers to join the specification process of the programming interface and makes it possible to start creating applications.

'); bsw@0: html.push('

questions and suggestions

'); bsw@0: html.push('

Please use our public mailing list if you have any questions or suggestions.

'); bsw@0: html.push('

developer registration

'); bsw@0: html.push('

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.
'); bsw@0: html.push('

'); bsw@0: html.push('     '); bsw@0: html.push('     '); bsw@0: html.push(' '); bsw@0: html.push('
'); bsw@0: html.push('
'); bsw@0: html.push('
'); bsw@0: html.push('WARNING: 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.
Please notice, this is a public alpha test dedicated to developers: serious errors can happen, private data unintentionally published or even grey goo can appear without further warning. Everything is ON YOUR OWN RISK!'); bsw@0: html.push('
'); bsw@0: html.push('
'); bsw@0: html.push(' I understand the previous warning and I understand that everything is on my own risk.
'); bsw@0: html.push('
'); bsw@0: html.push('
'); bsw@0: html.push(''); bsw@0: respond('html', null, req, res, 'ok', html.join('')); bsw@0: }, bsw@0: bsw@0: // temporary method to implement public alpha test bsw@0: '/register_test_confirm': function (conn, req, res, params) { bsw@0: var secret = params.secret; bsw@0: bsw@0: var query = new selector.Selector('member'); bsw@0: query.addField('member.id, member.notify_email_unconfirmed'); bsw@0: query.addWhere(['member.notify_email_secret = ?', secret]); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: var member = result.rows[0]; bsw@0: if (member) { bsw@0: var query = new selector.SQLUpdate('member'); bsw@0: query.addValues({ bsw@0: notify_email: member.notify_email_unconfirmed, bsw@0: notify_email_secret: null, bsw@0: notify_email_unconfirmed: null, bsw@0: active: true, bsw@0: activated: 'now', bsw@0: active: true, bsw@0: last_activity: 'now', bsw@0: locked: false bsw@0: }); bsw@0: query.addWhere(['id = ?', member.id]); bsw@0: db.query(conn, req, res, query, function (err, result) { bsw@0: respond('html', conn, req, res, 'ok', 'Account activated: '); bsw@0: }); bsw@0: } else { bsw@0: respond('html', conn, req, res, 'forbidden', 'Secret not valid or already used.'); bsw@0: } bsw@0: }) bsw@0: }, bsw@0: bsw@0: '/info': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'anonymous', function() { bsw@0: var query = new selector.Selector(); bsw@0: query.from('"liquid_feedback_version"'); bsw@0: query.addField('"liquid_feedback_version".*'); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: var liquid_feedback_version = result.rows[0]; bsw@0: respond('json', conn, req, res, 'ok', { bsw@0: core_version: liquid_feedback_version.string, bsw@0: api_version: api_version, bsw@0: current_access_level: req.current_member_id ? 'member' : req.current_access_level, bsw@0: current_member_id: req.current_member_id, bsw@0: settings: config.settings bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/member_count': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'anonymous', function() { bsw@0: var query = new selector.Selector(); bsw@0: query.from('"member_count"'); bsw@0: query.addField('"member_count".*'); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: var member_count = result.rows[0]; bsw@0: respond('json', conn, req, res, 'ok', { bsw@0: member_count: member_count.total_count, bsw@0: member_count_calculated: member_count.calculated bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/contingent': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'anonymous', function() { bsw@0: var query = new selector.Selector(); bsw@0: query.from('"contingent"'); bsw@0: query.addField('"contingent".*'); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: respond('json', conn, req, res, 'ok', { result: result.rows }); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/contingent_left': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'member', function() { bsw@0: var query = new selector.Selector(); bsw@0: query.from('"member_contingent_left"'); bsw@0: query.addField('"member_contingent_left".text_entries_left'); bsw@0: query.addField('"member_contingent_left".initiatives_left'); bsw@0: query.addWhere(['member_id = ?', req.current_member_id]); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: respond('json', conn, req, res, 'ok', { result: result.rows[0] }); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/member': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'pseudonym', function() { bsw@0: var query = new selector.Selector(); bsw@0: query.from('"member"'); bsw@0: if (req.current_access_level == 'pseudonym' && !req.current_member_id ) { bsw@0: fields.addObjectFields(query, 'member', 'member_pseudonym'); bsw@0: } else { bsw@0: fields.addObjectFields(query, 'member'); bsw@0: } bsw@0: general_params.addMemberOptions(req, query, params); bsw@0: query.addOrderBy('"member"."id"'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: respond('json', conn, req, res, 'ok', { result: result.rows }); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/member_history': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'full', function() { bsw@0: var query = new selector.Selector(); bsw@0: query.from('"member_history" JOIN "member" ON "member"."id" = "member_history"."member_id"'); bsw@0: query.addField('"member_history".*'); bsw@0: general_params.addMemberOptions(req, query, params); bsw@0: query.addOrderBy('member_history.id'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (member_history_result, conn) { bsw@0: var result = { result: member_history_result.rows } bsw@0: includes = []; bsw@0: if (params.include_members) includes.push({ class: 'member', objects: 'result'}); bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/member_image': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'full', function() { bsw@0: var query = new selector.Selector(); bsw@0: query.from('"member_image" JOIN "member" ON "member"."id" = "member_image"."member_id"'); bsw@0: query.addField('"member_image".*'); bsw@0: query.addWhere('member_image.scaled'); bsw@0: general_params.addMemberOptions(req, query, params); bsw@0: query.addOrderBy = ['member_image.member_id, member_image.image_type']; bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: respond('json', conn, req, res, 'ok', { result: result.rows }); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/contact': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'pseudonym', function() { bsw@0: var query = new selector.Selector(); bsw@0: query.from('contact JOIN member ON member.id = contact.member_id'); bsw@0: query.addField('"contact".*'); bsw@0: if (req.current_member_id) { bsw@0: // public or own for members bsw@0: query.addWhere(['"contact"."public" OR "contact"."member_id" = ?', req.current_member_id]); bsw@0: } else { bsw@0: // public for everybody bsw@0: query.addWhere('"contact"."public"'); bsw@0: } bsw@0: general_params.addMemberOptions(req, query, params); bsw@0: query.addOrderBy('"contact"."id"'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: respond('json', conn, req, res, 'ok', { result: result.rows }); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/privilege': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'pseudonym', function() { bsw@0: var query = new selector.Selector(); bsw@0: query.from('privilege JOIN member ON member.id = privilege.member_id JOIN unit ON unit.id = privilege.unit_id'); bsw@0: query.addField('privilege.*'); bsw@0: general_params.addUnitOptions(req, query, params); bsw@0: general_params.addMemberOptions(req, query, params); bsw@0: query.addOrderBy('privilege.unit_id, privilege.member_id'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (privilege_result, conn) { bsw@0: var result = { result: privilege_result.rows } bsw@0: includes = []; bsw@0: if (params.include_units) includes.push({ class: 'unit', objects: 'result'}); bsw@0: if (params.include_members) includes.push({ class: 'member', objects: 'result'}); bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/policy': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'anonymous', function() { bsw@0: var query = new selector.Selector(); bsw@0: query.from('"policy"'); bsw@0: query.addField('"policy".*'); bsw@0: general_params.addPolicyOptions(req, query, params); bsw@0: query.addOrderBy('"policy"."index"'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: respond('json', conn, req, res, 'ok', { result: result.rows }); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/unit': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'anonymous', function() { bsw@0: var query = new selector.Selector(); bsw@0: query.from('"unit"'); bsw@0: fields.addObjectFields(query, 'unit'); bsw@0: general_params.addUnitOptions(req, query, params); bsw@0: query.addOrderBy('unit.id'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: respond('json', conn, req, res, 'ok', { result: result.rows }); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/area': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'anonymous', function() { bsw@0: var query = new selector.Selector(); bsw@0: query.from('area JOIN unit ON area.unit_id = unit.id'); bsw@0: fields.addObjectFields(query, 'area'); bsw@0: general_params.addAreaOptions(req, query, params); bsw@0: query.addOrderBy('area.id'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (area_result, conn) { bsw@0: var result = { result: area_result.rows } bsw@0: includes = []; bsw@0: if (params.include_units) includes.push({ class: 'unit', objects: 'result'}); bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/allowed_policy': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'anonymous', function() { bsw@0: var query = new selector.Selector(); bsw@0: query.from('allowed_policy'); bsw@0: query.join('area', null, 'area.id = allowed_policy.area_id'); bsw@0: query.join('unit', null, 'unit.id = area.unit_id'); bsw@0: query.addField('allowed_policy.*'); bsw@0: general_params.addAreaOptions(req, query, params); bsw@0: query.addOrderBy('allowed_policy.area_id, allowed_policy.policy_id'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (allowed_policy_result, conn) { bsw@0: var result = { result: allowed_policy_result.rows } bsw@0: includes = []; bsw@0: if (params.include_policies) includes.push({ class: 'policy', objects: 'result'}); bsw@0: if (params.include_areas) includes.push({ class: 'area', objects: 'result'}); bsw@0: if (params.include_units) includes.push({ class: 'unit', objects: 'areas'}); bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: }); }, bsw@0: bsw@0: '/membership': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'pseudonym', function() { bsw@0: var query = new selector.Selector(); bsw@0: 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: query.addField('membership.*'); bsw@0: general_params.addAreaOptions(req, query, params); bsw@0: general_params.addMemberOptions(req, query, params); bsw@0: query.addOrderBy('membership.area_id, membership.member_id'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (membership_result, conn) { bsw@0: var result = { result: membership_result.rows } bsw@0: includes = []; bsw@0: if (params.include_members) includes.push({ class: 'member', objects: 'result'}); bsw@0: if (params.include_areas) includes.push({ class: 'area', objects: 'result'}); bsw@0: if (params.include_units) includes.push({ class: 'unit', objects: 'areas'}); bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/issue': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'anonymous', function() { bsw@0: var query = new selector.Selector() bsw@0: 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: fields.addObjectFields(query, 'issue'); bsw@0: general_params.addIssueOptions(req, query, params); bsw@0: query.addOrderBy('issue.id'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (issue_result, conn) { bsw@0: var result = { result: issue_result.rows } bsw@0: includes = []; bsw@0: if (params.include_areas) includes.push({ class: 'area', objects: 'result'}); bsw@0: if (params.include_units) includes.push({ class: 'unit', objects: 'areas'}); bsw@0: if (params.include_policies) includes.push({ class: 'policy', objects: 'result' }); bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/interest': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'pseudonym', function() { bsw@0: var query = new selector.Selector(); bsw@0: 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: query.addField('interest.*'); bsw@0: general_params.addMemberOptions(req, query, params); bsw@0: general_params.addIssueOptions(req, query, params); bsw@0: query.addOrderBy('interest.issue_id, interest.member_id'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (interest_result, conn) { bsw@0: var result = { result: interest_result.rows } bsw@0: includes = []; bsw@0: if (params.include_members) includes.push({ class: 'member', objects: 'result'}); bsw@0: if (params.include_issues) includes.push({ class: 'issue', objects: 'result'}); bsw@0: if (params.include_areas) includes.push({ class: 'area', objects: 'issues'}); bsw@0: if (params.include_units) includes.push({ class: 'unit', objects: 'areas'}); bsw@0: if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' }); bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/issue_comment': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'pseudonym', function() { bsw@0: var query = new selector.Selector(); bsw@0: 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: query.addField('issue_comment.*'); bsw@0: general_params.addMemberOptions(req, query, params); bsw@0: general_params.addIssueOptions(req, query, params); bsw@0: query.addOrderBy('issue_comment.issue_id, issue_comment.member_id'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (issue_comment_result, conn) { bsw@0: var result = { result: issue_comment_result.rows } bsw@0: includes = []; bsw@0: if (params.include_members) includes.push({ class: 'member', objects: 'result'}); bsw@0: if (params.include_issues) includes.push({ class: 'issue', objects: 'result'}); bsw@0: if (params.include_areas) includes.push({ class: 'area', objects: 'issues'}); bsw@0: if (params.include_units) includes.push({ class: 'unit', objects: 'areas'}); bsw@0: if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' }); bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/initiative': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'anonymous', function() { bsw@0: var query = new selector.Selector(); bsw@0: 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: fields.addObjectFields(query, 'initiative'); bsw@0: general_params.addInitiativeOptions(req, query, params); bsw@0: query.addOrderBy('initiative.issue_id, initiative.id'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (initiative_result, conn) { bsw@0: var result = { result: initiative_result.rows } bsw@0: includes = []; bsw@0: if (params.include_issues) includes.push({ class: 'issue', objects: 'result'}); bsw@0: if (params.include_areas) includes.push({ class: 'area', objects: 'issues'}); bsw@0: if (params.include_units) includes.push({ class: 'unit', objects: 'areas'}); bsw@0: if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' }); bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/initiator': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'pseudonym', function() { bsw@0: var fields = ['initiator.initiative_id', 'initiator.member_id']; bsw@0: var query = new selector.Selector(); bsw@0: 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: query.addWhere('initiator.accepted'); bsw@0: fields.forEach( function(field) { bsw@0: query.addField(field, null, ['grouped']); bsw@0: }); bsw@0: general_params.addMemberOptions(req, query, params); bsw@0: general_params.addInitiativeOptions(req, query, params); bsw@0: query.addOrderBy('initiator.initiative_id, initiator.member_id'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (initiator, conn) { bsw@0: var result = { result: initiator.rows } bsw@0: includes = []; bsw@0: if (params.include_initiatives) includes.push({ class: 'initiative', objects: 'result'}); bsw@0: if (params.include_issues) includes.push({ class: 'issue', objects: 'initiatives'}); bsw@0: if (params.include_areas) includes.push({ class: 'area', objects: 'issues'}); bsw@0: if (params.include_units) includes.push({ class: 'unit', objects: 'areas'}); bsw@0: if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' }); bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: bsw@0: '/supporter': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'pseudonym', function() { bsw@0: var fields = ['supporter.issue_id', 'supporter.initiative_id', 'supporter.member_id', 'supporter.draft_id']; bsw@0: var query = new selector.Selector(); bsw@0: query.from('supporter') bsw@0: 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: fields.forEach( function(field) { bsw@0: query.addField(field, null, ['grouped']); bsw@0: }); bsw@0: general_params.addMemberOptions(req, query, params); bsw@0: general_params.addInitiativeOptions(req, query, params); bsw@0: query.addOrderBy('supporter.issue_id, supporter.initiative_id, supporter.member_id'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (supporter, conn) { bsw@0: var result = { result: supporter.rows } bsw@0: includes = []; bsw@0: if (params.include_initiatives) includes.push({ class: 'initiative', objects: 'result'}); bsw@0: if (params.include_issues) includes.push({ class: 'issue', objects: 'initiatives'}); bsw@0: if (params.include_areas) includes.push({ class: 'area', objects: 'issues'}); bsw@0: if (params.include_units) includes.push({ class: 'unit', objects: 'areas'}); bsw@0: if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' }); bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/battle': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'anonymous', function() { bsw@0: var query = new selector.Selector(); bsw@0: 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: query.addField('battle.*'); bsw@0: general_params.addInitiativeOptions(req, query, params); bsw@0: query.addOrderBy('battle.issue_id, battle.winning_initiative_id, battle.losing_initiative_id'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: var result = { result: result.rows } bsw@0: includes = []; bsw@0: if (params.include_initiatives) includes.push({ class: 'initiative', objects: 'result'}); bsw@0: if (params.include_issues) includes.push({ class: 'issue', objects: 'initiatives'}); bsw@0: if (params.include_areas) includes.push({ class: 'area', objects: 'issues'}); bsw@0: if (params.include_units) includes.push({ class: 'unit', objects: 'areas'}); bsw@0: if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' }); bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/draft': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'anonymous', function() { bsw@0: var fields = ['draft.initiative_id', 'draft.id', 'draft.formatting_engine', 'draft.content', 'draft.author_id']; bsw@0: var query = new selector.Selector(); bsw@0: 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: fields.forEach( function(field) { bsw@0: query.addField(field, null, ['grouped']); bsw@0: }); bsw@0: if (req.current_access_level != 'anonymous' || req.current_member_id) { bsw@0: query.addField('draft.author_id'); bsw@0: } bsw@0: if (params.draft_id) { bsw@0: query.addWhere('draft.id = ?', params.draft_id); bsw@0: } bsw@0: if (params.current_draft) { bsw@0: query.join('current_draft', null, 'current_draft.initiative_id = initiative.id AND current_draft.id = draft.id') bsw@0: } bsw@0: general_params.addInitiativeOptions(req, query, params); bsw@0: query.addOrderBy('draft.initiative_id, draft.id'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: var result = { result: result.rows } bsw@0: includes = []; bsw@0: if (params.include_initiatives) includes.push({ class: 'initiative', objects: 'result'}); bsw@0: if (params.include_issues) includes.push({ class: 'issue', objects: 'initiatives'}); bsw@0: if (params.include_areas) includes.push({ class: 'area', objects: 'issues'}); bsw@0: if (params.include_units) includes.push({ class: 'unit', objects: 'areas'}); bsw@0: if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' }); bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/suggestion': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'anonymous', function() { bsw@0: var query = new selector.Selector(); bsw@0: 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: if (req.current_access_level == 'anonymous' && !req.current_member_id ) { bsw@0: fields.addObjectFields(query, 'suggestion', 'suggestion_pseudonym'); bsw@0: } else { bsw@0: fields.addObjectFields(query, 'suggestion'); bsw@0: } bsw@0: general_params.addSuggestionOptions(req, query, params); bsw@0: query.addOrderBy('suggestion.initiative_id, suggestion.id'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: var result = { result: result.rows } bsw@0: includes = []; bsw@0: if (params.include_initiatives) includes.push({ class: 'initiative', objects: 'result'}); bsw@0: if (params.include_issues) includes.push({ class: 'issue', objects: 'initiatives'}); bsw@0: if (params.include_areas) includes.push({ class: 'area', objects: 'issues'}); bsw@0: if (params.include_units) includes.push({ class: 'unit', objects: 'areas'}); bsw@0: if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' }); bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/opinion': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'pseudonym', function() { bsw@0: var fields = ['opinion.initiative_id', 'opinion.suggestion_id', 'opinion.member_id', 'opinion.degree', 'opinion.fulfilled'] bsw@0: var query = new selector.Selector(); bsw@0: 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: fields.forEach( function(field) { bsw@0: query.addField(field, null, ['grouped']); bsw@0: }); bsw@0: general_params.addMemberOptions(req, query, params); bsw@0: general_params.addSuggestionOptions(req, query, params); bsw@0: query.addOrderBy = ['opinion.initiative_id, opinion.suggestion_id, opinion.member_id']; bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: var result = { result: result.rows } bsw@0: includes = []; bsw@0: if (params.include_suggestions) includes.push({ class: 'suggestion', objects: 'result'}); bsw@0: if (params.include_initiatives) includes.push({ class: 'initiative', objects: 'suggestions'}); bsw@0: if (params.include_issues) includes.push({ class: 'issue', objects: 'initiatives'}); bsw@0: if (params.include_areas) includes.push({ class: 'area', objects: 'issues'}); bsw@0: if (params.include_units) includes.push({ class: 'unit', objects: 'areas'}); bsw@0: if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' }); bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/delegation': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'pseudonym', function() { bsw@0: var fields = ['delegation.id', 'delegation.truster_id', 'delegation.trustee_id', 'delegation.scope', 'delegation.area_id', 'delegation.issue_id', 'delegation.unit_id']; bsw@0: var query = new selector.Selector(); bsw@0: 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: fields.forEach( function(field) { bsw@0: query.addField(field, null, ['grouped']); bsw@0: }); bsw@0: if (params.direction) { bsw@0: switch (params.direction) { bsw@0: case 'in': bsw@0: query.join('member', null, 'member.id = delegation.trustee_id'); bsw@0: break; bsw@0: case 'out': bsw@0: query.join('member', null, 'member.id = delegation.truster_id'); bsw@0: break; bsw@0: default: bsw@0: respond('json', conn, req, res, 'unprocessable', 'Direction must be "in" or "out" if set.'); bsw@0: } bsw@0: } else { bsw@0: query.join('member', null, 'member.id = delegation.truster_id OR member.id = delegation.trustee_id'); bsw@0: } bsw@0: general_params.addMemberOptions(req, query, params); bsw@0: general_params.addIssueOptions(req, query, params); bsw@0: if (params.scope) { bsw@0: query.addWhere(['delegation.scope IN (??)', params.scope.split(',')]); bsw@0: }; bsw@0: query.addOrderBy = ['delegation.id']; bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: respond('json', conn, req, res, 'ok', { result: result.rows }); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/vote': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'pseudonym', function() { bsw@0: var query = new selector.Selector(); bsw@0: 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: query.addField('vote.*'); bsw@0: query.addWhere('issue.closed_at NOTNULL'); bsw@0: general_params.addMemberOptions(req, query, params); bsw@0: general_params.addInitiativeOptions(req, query, params); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: respond('json', conn, req, res, 'ok', { result: result.rows }); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/event': function (conn, req, res, params) { requireAccessLevel(conn, req, res, 'anonymous', function() { bsw@0: 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: var query = new selector.Selector(); bsw@0: 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: fields.forEach( function(field) { bsw@0: query.addField(field, null, ['grouped']); bsw@0: }); bsw@0: general_params.addMemberOptions(req, query, params); bsw@0: general_params.addInitiativeOptions(req, query, params); bsw@0: query.addOrderBy('event.id'); bsw@0: general_params.addLimitAndOffset(query, params); bsw@0: db.query(conn, req, res, query, function (events, conn) { bsw@0: var result = { result: events.rows } bsw@0: includes = []; bsw@0: if (params.include_initiatives) includes.push({ class: 'initiative', objects: 'result'}); bsw@0: if (params.include_issues) includes.push({ class: 'issue', objects: 'result'}); bsw@0: if (params.include_areas) includes.push({ class: 'area', objects: 'issues'}); bsw@0: if (params.include_units) includes.push({ class: 'unit', objects: 'areas'}); bsw@0: if (params.include_policies) includes.push({ class: 'policy', objects: 'issues' }); bsw@0: addRelatedData(conn, req, res, result, includes); bsw@0: }); bsw@0: }); }, bsw@0: bsw@0: // TODO add interfaces for data structure: bsw@0: // event requireAccessLevel(conn, req, res, 'member'); bsw@0: // ignored_member requireAccessLevel(conn, req, res, 'member'); bsw@0: // ignored_initiative requireAccessLevel(conn, req, res, 'member'); bsw@0: // setting requireAccessLevel(conn, req, res, 'member'); bsw@0: bsw@0: }; bsw@0: bsw@0: // ========================================================================== bsw@0: // POST methods bsw@0: // ========================================================================== bsw@0: bsw@0: bsw@0: bsw@0: exports.post = { bsw@0: bsw@0: '/echo_test': function (conn, req, res, params) { requireAccessLevel(conn, req, res, 'anonymous', function() { bsw@0: respond('json', conn, req, res, 'ok', { result: params }); bsw@0: }); }, bsw@0: bsw@0: '/register_test': function (conn, req, res, params) { bsw@0: var understood = params.understood; bsw@0: var member_login = randomString(16); bsw@0: var member_name = params.name; bsw@0: var member_password = randomString(16); bsw@0: var member_notify_email = params.email; bsw@0: var member_notify_email_secret = randomString(24); bsw@0: var api_key_member = randomString(24); bsw@0: var api_key_full = randomString(24); bsw@0: var api_key_pseudonym = randomString(24); bsw@0: var api_key_anonymous = randomString(24); bsw@0: bsw@0: if (understood != 'understood') { bsw@0: respond('html', conn, req, res, 'unprocessable', null, 'You didn\'t checked the checkbox! Please hit back in your browser and try again.'); bsw@0: return; bsw@0: } bsw@0: bsw@0: // add member bsw@0: var query = new selector.SQLInsert('member'); bsw@0: query.addValues({ bsw@0: login: member_login, bsw@0: password: member_password, // TODO hashing of password bsw@0: notify_email_unconfirmed: member_notify_email, bsw@0: notify_email_secret: member_notify_email_secret, bsw@0: name: member_name bsw@0: }); bsw@0: query.addReturning('id'); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: var member_id = result.rows[0].id; bsw@0: bsw@0: // add privilege for root unit bsw@0: var query = new selector.SQLInsert('privilege'); bsw@0: query.addValues({ unit_id: 1, member_id: member_id, voting_right: true }); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: bsw@0: var location = params.location; bsw@0: var unit_id; bsw@0: switch(location) { bsw@0: case 'earth': bsw@0: unit_id = 3; bsw@0: break; bsw@0: case 'moon': bsw@0: unit_id = 4; bsw@0: break; bsw@0: case 'mars': bsw@0: unit_id = 5; bsw@0: break; bsw@0: } bsw@0: bsw@0: // add privilege for selected planet bsw@0: var query = new selector.SQLInsert('privilege'); bsw@0: query.addValues({ unit_id: unit_id, member_id: member_id, voting_right: true }); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: bsw@0: // add application key bsw@0: var query = new selector.SQLInsert('member_application'); bsw@0: query.addValues({ bsw@0: member_id: member_id, bsw@0: name: 'member', bsw@0: comment: 'access_level member', bsw@0: access_level: 'member', bsw@0: key: api_key_member bsw@0: }); bsw@0: query.addReturning('id'); bsw@0: bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: bsw@0: // send email to user bsw@0: email.send({ bsw@0: host : config.mail.smtp_host, bsw@0: port: config.mail.smtp_port, bsw@0: ssl: config.mail.smtp_ssl, bsw@0: domain: config.mail.smtp_domain, bsw@0: authentication: config.mail.smtp_authentication, bsw@0: username: config.mail.smtp_username, bsw@0: password: config.mail.smtp_password, bsw@0: from: config.mail.from, bsw@0: subject: config.mail.subject_prefix + "Your LiquidFeedback API alpha test account needs confirmation", bsw@0: to: member_notify_email, bsw@0: body: "\ bsw@0: Hello " + member_name + ",\n\ bsw@0: \n\ bsw@0: thank you for registering at the public alpha test of the LiquidFeedback\n\ bsw@0: application programming interface. To complete the registration process,\n\ bsw@0: you need to confirm your email address by opening the following URL:\n\ bsw@0: \n\ bsw@0: " + config.public_url_path + "register_test_confirm?secret=" + member_notify_email_secret + "\n\ bsw@0: \n\ bsw@0: \n\ bsw@0: After you've confirmed your email address, your account will be automatically\n\ bsw@0: activated.\n\ bsw@0: \n\ bsw@0: Your account name is: " + member_name + "\n\ bsw@0: \n\ bsw@0: \n\ bsw@0: You will need the following login and password to register and unregister\n\ bsw@0: applications for your account later. This function is currently not\n\ bsw@0: implemented, but please keep the credentials for future use.\n\ bsw@0: \n\ bsw@0: Account ID: " + member_id + "\n\ bsw@0: Login: " + member_login + "\n\ bsw@0: Password: " + member_password + "\n\ bsw@0: \n\ bsw@0: \n\ bsw@0: To make you able to actually access the API interface, we added the following\n\ bsw@0: application key with full member access privileges to your account:\n\ bsw@0: \n\ bsw@0: API Key: " + api_key_member + "\n\ bsw@0: \n\ bsw@0: \n\ bsw@0: The base address of the public test is: " + config.public_url_path + "\n\ bsw@0: \n\ bsw@0: The programming interface is described in the LiquidFeedback API\n\ bsw@0: specification: http://dev.liquidfeedback.org/trac/lf/wiki/API\n\ bsw@0: \n\ bsw@0: The current implementation status of lfapi is published at the LiquidFeedback\n\ bsw@0: API server page: http://dev.liquidfeedback.org/trac/lf/wiki/lfapi\n\ bsw@0: \n\ bsw@0: If you have any questions or suggestions, please use our public mailing list\n\ bsw@0: at http://dev.liquidfeedback.org/cgi-bin/mailman/listinfo/main\n\ bsw@0: \n\ bsw@0: For issues regarding your test account, contact us via email at\n\ bsw@0: lqfb-maintainers@public-software-group.org\n\ bsw@0: \n\ bsw@0: \n\ bsw@0: Sincerely,\n\ bsw@0: \n\ bsw@0: Your LiquidFeedback maintainers", bsw@0: }, bsw@0: function(err, result){ bsw@0: if(err){ console.log(err); } bsw@0: }); bsw@0: bsw@0: respond('html', conn, req, res, 'ok', 'Account created. Please check your mailbox!


Back to start page'); bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: /* bsw@0: '/register': function (conn, req, res, params) { bsw@0: var invite_key = params.invite_key; bsw@0: var login = params.login; bsw@0: var password = params.password; bsw@0: var name = params.name; bsw@0: var notify_email = params.notify_email; bsw@0: if (!invite_key) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'No invite_key supplied.'); bsw@0: return; bsw@0: }; bsw@0: if (!login) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'No login supplied.'); bsw@0: return; bsw@0: }; bsw@0: if (!password) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'No password supplied.'); bsw@0: return; bsw@0: }; bsw@0: if (!name) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'No name supplied.'); bsw@0: return; bsw@0: }; bsw@0: if (!notify_email) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'No notify_email supplied.'); bsw@0: return; bsw@0: }; bsw@0: // check if akey is valid and get member_id for akey bsw@0: 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: if (result.rows.length != 1) { bsw@0: respond('json', conn, req, res, 'forbidden', null, 'Supplied invite_key is not valid.'); bsw@0: return; bsw@0: }; bsw@0: var member_id = result.rows[0].id; bsw@0: // check if name is available bsw@0: db.query(conn, req, res, { select: ['NULL'], from: ['member'], where: ['member.name = ' + db.pgEncode(name)] }, function (result, conn) { bsw@0: if (result.rows.length > 0) { bsw@0: respond('json', conn, req, res, 'forbidden', null, 'Login name is not available, choose another one.'); bsw@0: return; bsw@0: }; bsw@0: // check if login is available bsw@0: db.query(conn, req, res, { select: ['NULL'], from: ['member'], where: ['member.login = ' + db.pgEncode(login)] }, function (result, conn) { bsw@0: if (result.rows.length > 0) { bsw@0: respond('json', conn, req, res, 'forbidden', null, 'Name is not available, choose another one.'); bsw@0: return; bsw@0: }; bsw@0: var query = { update: 'member', set: { activation: 'now', active: true, } }; bsw@0: bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: */ bsw@0: bsw@0: '/session': function (conn, req, res, params) { bsw@0: var key = params.key; bsw@0: if (!key) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'No application key supplied.'); bsw@0: return; bsw@0: }; bsw@0: var query = new selector.Selector(); bsw@0: query.from('member'); bsw@0: query.join('member_application', null, 'member_application.member_id = member.id'); bsw@0: query.addField('member.id'); bsw@0: query.addWhere(['member.active AND member_application.key = ?', key]); bsw@0: if (params.interactive) { bsw@0: query.forUpdateOf('member'); bsw@0: } bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: if (result.rows.length != 1) { bsw@0: respond('json', conn, req, res, 'forbidden', null, 'Supplied application key is not valid.'); bsw@0: return; bsw@0: }; bsw@0: var member_id = result.rows[0].id; bsw@0: var session_key = randomString(16); bsw@0: req.sessions[session_key] = member_id; bsw@0: var query; bsw@0: if (params.interactive) { bsw@0: query = new selector.SQLUpdate('member'); bsw@0: query.addWhere(['member.id = ?', member_id]); bsw@0: query.addValues({ last_activity: 'now' }); bsw@0: } bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: respond('json', conn, req, res, 'ok', { session_key: session_key }); bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/member': function (conn, req, res, params) { bsw@0: var fields = ['organizational_unit', 'internal_posts', 'realname', 'birthday', 'address', 'email', 'xmpp_address', 'website', 'phone', 'mobile_phone', 'profession', 'external_memberships', 'external_posts', 'statement'] bsw@0: requireAccessLevel(conn, req, res, 'member', function() { bsw@0: var query = new selector.SQLUpdate('member'); bsw@0: query.addWhere(['member.id = ?', req.current_member_id]); bsw@0: fields.forEach( function(field) { bsw@1: var tmp = {} bsw@0: if (typeof(params[field]) != 'undefined') { bsw@1: tmp[field] = params[field]; bsw@0: } else { bsw@1: tmp[field] = null; bsw@0: } bsw@1: query.addValues(tmp); bsw@0: }); bsw@0: db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/membership': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'member', function() { bsw@0: bsw@0: // check if area_id is set bsw@0: var area_id = parseInt(params.area_id); bsw@0: if (!area_id) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an area_id.'); bsw@0: return; bsw@0: } bsw@0: bsw@0: // delete membership bsw@0: if (params.delete) { bsw@0: var query; bsw@0: query = new selector.SQLDelete('membership'); bsw@0: query.addWhere(['area_id = ?', area_id]); bsw@0: query.addWhere(['member_id = ?', req.current_member_id]); bsw@0: db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); }); bsw@0: bsw@0: // add membership bsw@0: } else { bsw@0: bsw@0: // lock member for upsert bsw@0: lockMemberById(conn, req, res, req.current_member_id, function() { bsw@0: bsw@0: // check and lock privilege bsw@0: requireAreaPrivilege(conn, req, res, area_id, function() { bsw@0: bsw@0: // upsert membership bsw@0: var query = new selector.Upserter('membership', ['area_id', 'member_id']); bsw@0: query.addValues({ area_id: area_id, member_id: req.current_member_id }); bsw@0: db.query(conn, req, res, query, function(result) { bsw@0: respond('json', conn, req, res, 'ok'); bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: } bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/interest': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'member', function() { bsw@0: var query; bsw@0: bsw@0: // check if issue_id is set bsw@0: var issue_id = parseInt(params.issue_id); bsw@0: if (!issue_id) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an issue_id.'); bsw@0: return; bsw@0: } bsw@0: bsw@0: // lock member for upsert bsw@0: lockMemberById(conn, req, res, req.current_member_id, function() { bsw@0: bsw@0: // delete interest bsw@0: if (params.delete) { bsw@0: bsw@0: // check issue state bsw@0: requireIssueState(conn, req, res, issue_id, ['admission', 'discussion', 'verification'], function() { bsw@0: bsw@0: // delete interest bsw@0: query = new selector.SQLDelete('interest'); bsw@0: query.addWhere(['issue_id = ?', issue_id]); bsw@0: query.addWhere(['member_id = ?', req.current_member_id]); bsw@0: db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); }); bsw@0: }); bsw@0: bsw@0: // add interest bsw@0: } else { bsw@0: bsw@0: // check and lock privilege bsw@0: requireIssuePrivilege(conn, req, res, issue_id, function() { bsw@0: bsw@0: // check issue state bsw@0: requireIssueState(conn, req, res, issue_id, ['admission', 'discussion', 'verification'], function() { bsw@0: bsw@0: // upsert interest bsw@0: var query = new selector.Upserter('interest', ['issue_id', 'member_id']); bsw@0: query.addValues({ issue_id: issue_id, member_id: req.current_member_id }); bsw@0: db.query(conn, req, res, query, function(result) { bsw@0: respond('json', conn, req, res, 'ok'); bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: }; bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/issue_comment': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'member', function() { bsw@0: bsw@0: var issue_id = parseInt(params.issue_id); bsw@0: var formatting_engine = params.formatting_engine bsw@0: var content = params.content; bsw@0: bsw@0: if (!issue_id) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an issue_id.'); bsw@0: return; bsw@0: } bsw@0: bsw@0: // delete issue comment bsw@0: if (params.delete) { bsw@0: var query; bsw@0: query = new selector.SQLDelete('issue_comment'); bsw@0: query.addWhere(['issue_id = ?', params.issue_id]); bsw@0: query.addWhere(['member_id = ?', req.current_member_id]); bsw@0: db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); }); bsw@0: bsw@0: // upsert issue comment bsw@0: } else { bsw@0: bsw@0: // check if formatting engine is supplied and valid bsw@0: if (!formatting_engine) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'No formatting engine supplied.'); bsw@0: return; bsw@0: } else if (formatting_engine != 'rocketwiki' && formatting_engine != 'compat') { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'Invalid formatting engine supplied.'); bsw@0: return; bsw@0: }; bsw@0: bsw@0: // check if content is supplied bsw@0: if (!content) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'No content supplied.'); bsw@0: return; bsw@0: } bsw@0: bsw@0: // lock member for upsert bsw@0: lockMemberById(conn, req, res, req.current_member_id, function() { bsw@0: bsw@0: // check and lock privilege bsw@0: requireIssuePrivilege(conn, req, res, issue_id, function() { bsw@0: bsw@0: // upsert issue comment bsw@0: var query = new selector.Upserter('issue_comment', ['issue_id', 'member_id']); bsw@0: query.addValues({ bsw@0: issue_id: issue_id, bsw@0: member_id: req.current_member_id, bsw@0: changed: 'now', bsw@0: formatting_engine: formatting_engine, bsw@0: content: content bsw@0: }); bsw@0: bsw@0: db.query(conn, req, res, query, function(result) { bsw@0: respond('json', conn, req, res, 'ok'); bsw@0: }); bsw@0: bsw@0: }); bsw@0: }); bsw@0: bsw@0: } bsw@0: bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/voting_comment': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'member', function() { bsw@0: bsw@0: var issue_id = parseInt(params.issue_id); bsw@0: var formatting_engine = params.formatting_engine bsw@0: var content = params.content; bsw@0: bsw@0: if (!issue_id) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an issue_id.'); bsw@0: return; bsw@0: } bsw@0: bsw@0: bsw@0: // delete voting comment bsw@0: if (params.delete) { bsw@0: var query; bsw@0: query = new selector.SQLDelete('voting_comment'); bsw@0: query.addWhere(['issue_id = ?', params.issue_id]); bsw@0: query.addWhere(['member_id = ?', req.current_member_id]); bsw@0: db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); }); bsw@0: bsw@0: // upsert voting comment bsw@0: } else { bsw@0: bsw@0: // check if formatting engine is supplied and valid bsw@0: if (!formatting_engine) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'No formatting engine supplied.'); bsw@0: return; bsw@0: } else if (formatting_engine != 'rocketwiki' && formatting_engine != 'compat') { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'Invalid formatting engine supplied.'); bsw@0: return; bsw@0: }; bsw@0: bsw@0: // check if content is supplied bsw@0: if (!content) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'No content supplied.'); bsw@0: return; bsw@0: } bsw@0: bsw@0: // lock member for upsert bsw@0: lockMemberById(conn, req, res, req.current_member_id, function() { bsw@0: bsw@0: // check and lock privilege bsw@0: requireIssuePrivilege(conn, req, res, issue_id, function() { bsw@0: bsw@0: // check issue state bsw@0: requireIssueState(conn, req, res, issue_id, ['voting', 'finished_with_winner', 'finished_without_winner'], function() { bsw@0: bsw@0: // upsert voting comment bsw@0: var query = new selector.Upserter('voting_comment', ['issue_id', 'member_id']); bsw@0: query.addValues({ bsw@0: issue_id: issue_id, bsw@0: member_id: req.current_member_id, bsw@0: changed: 'now', bsw@0: formatting_engine: formatting_engine, bsw@0: content: content bsw@0: }); bsw@0: bsw@0: db.query(conn, req, res, query, function(result) { bsw@0: respond('json', conn, req, res, 'ok'); bsw@0: }); bsw@0: bsw@0: }); bsw@0: }); bsw@0: }) bsw@0: }; bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/supporter': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'member', function() { bsw@0: var initiative_id = parseInt(params.initiative_id); bsw@0: var draft_id = parseInt(params.draft_id); bsw@0: bsw@0: // check if needed arguments are supplied bsw@0: if (!initiative_id) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an initiative_id.'); bsw@0: return; bsw@0: } bsw@0: bsw@0: if (!draft_id) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'You need to supply an draft_id.'); bsw@0: return; bsw@0: } bsw@0: bsw@0: // lock member for upsert bsw@0: lockMemberById(conn, req, res, req.current_member_id, function() { bsw@0: bsw@0: // delete supporter bsw@0: if (params.delete) { bsw@0: bsw@0: // check issue state bsw@0: requireIssueStateForInitiative(conn, req, res, initiative_id, ['admission', 'discussion', 'verification'], function() { bsw@0: bsw@0: // delete supporter bsw@0: var query = new selector.SQLDelete('supporter'); bsw@0: query.addWhere(['initiative_id = ?', initiative_id]); bsw@0: query.addWhere(['member_id = ?', req.current_member_id]); bsw@0: db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); }); bsw@0: bsw@0: }); bsw@0: bsw@0: // upsert supporter bsw@0: } else { bsw@0: bsw@0: // check and lock privilege bsw@0: requireInitiativePrivilege(conn, req, res, initiative_id, function() { bsw@0: bsw@0: // check issue state bsw@0: requireIssueStateForInitiative(conn, req, res, initiative_id, ['admission', 'discussion', 'verification'], function() { bsw@0: bsw@0: // check if given draft is the current one bsw@0: var query = new selector.Selector('current_draft'); bsw@0: query.addField('NULL'); bsw@0: query.addWhere(['current_draft.initiative_id = ?', initiative_id]); bsw@0: query.addWhere(['current_draft.id = ?', draft_id]); bsw@0: bsw@0: db.query(conn, req, res, query, function(result) { bsw@0: if (result.rows.length != 1) { bsw@0: respond('json', conn, req, res, 'conflict', null, 'The draft with the supplied draft_id is not the current one anymore!'); bsw@0: return; bsw@0: } bsw@0: bsw@0: // upsert supporter bsw@0: var query = new selector.Upserter('supporter', ['initiative_id', 'member_id']); bsw@0: query.addValues({ bsw@0: initiative_id: initiative_id, bsw@0: member_id: req.current_member_id, bsw@0: draft_id: draft_id bsw@0: }); bsw@0: bsw@0: db.query(conn, req, res, query, function(result) { bsw@0: respond('json', conn, req, res, 'ok'); bsw@0: }); bsw@0: bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: }; bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/draft': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'member', function() { bsw@0: var area_id = parseInt(params.area_id); bsw@0: var policy_id = parseInt(params.policy_id); bsw@0: var issue_id = parseInt(params.issue_id); bsw@0: var initiative_id = parseInt(params.initiative_id); bsw@0: var initiative_name = params.initiative_name; bsw@0: var initiative_discussion_url = params.initiative_discussion_url; bsw@0: var formatting_engine = params.formatting_engine; bsw@0: var content = params.content; bsw@0: bsw@0: if (!initiative_discussion_url) initiative_discussion_url = null; bsw@0: bsw@0: // check parameters bsw@0: if (!formatting_engine) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'No formatting_engine supplied.'); bsw@0: return; bsw@0: } else if (formatting_engine != 'rocketwiki' && formatting_engine != 'compat') { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'Invalid formatting engine supplied.'); bsw@0: return; bsw@0: }; bsw@0: bsw@0: if (!content) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'No draft content supplied.'); bsw@0: return; bsw@0: }; bsw@0: bsw@0: lockMemberById(conn, req, res, req.current_member_id, function() { bsw@0: bsw@0: // new draft in new initiative in new issue bsw@0: if (area_id && !issue_id && !initiative_id) { bsw@0: bsw@0: // check parameters for new issue bsw@0: if (!policy_id) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'No policy supplied.'); bsw@0: return; bsw@0: } bsw@0: bsw@0: if (!initiative_name) { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'No initiative name supplied.'); bsw@0: return; bsw@0: } bsw@0: bsw@0: requireAreaPrivilege(conn, req, res, area_id, function() { bsw@0: bsw@0: // check if policy is allowed in this area and if area and policy are active bsw@0: var query = new selector.Selector(); bsw@0: query.from('allowed_policy'); bsw@0: query.join('area', null, 'area.id = allowed_policy.area_id AND area.active'); bsw@0: query.join('policy', null, 'policy.id = allowed_policy.policy_id AND policy.active'); bsw@0: query.addField('NULL'); bsw@0: query.addWhere(['area.id = ? AND policy.id = ?', area_id, policy_id]); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: if (result.rows.length != 1) { bsw@0: 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: return; bsw@0: }; bsw@0: bsw@0: // check contingent bsw@0: requireContingentLeft(conn, req, res, true, function() { bsw@0: bsw@0: // insert new issue bsw@0: var query = new selector.SQLInsert('issue'); bsw@0: query.addValues({ bsw@0: area_id: area_id, bsw@0: policy_id: policy_id bsw@0: }); bsw@0: query.addReturning('id'); bsw@0: db.query(conn, req, res, query, function(result) { bsw@0: var issue_id = result.rows[0].id; bsw@0: bsw@0: // insert new initiative bsw@0: var query = new selector.SQLInsert('initiative'); bsw@0: query.addValues({ bsw@0: issue_id: issue_id, bsw@0: name: initiative_name, bsw@0: discussion_url: initiative_discussion_url bsw@0: }); bsw@0: query.addReturning('id'); bsw@0: db.query(conn, req, res, query, function(result) { bsw@0: var initiative_id = result.rows[0].id; bsw@0: bsw@0: // insert initiator bsw@0: var query = new selector.SQLInsert('initiator'); bsw@0: query.addValues({ initiative_id: initiative_id, member_id: req.current_member_id, accepted: true }); bsw@0: db.query(conn, req, res, query, function(result) { bsw@0: bsw@0: // insert new draft bsw@0: var query = new selector.SQLInsert('draft'); bsw@0: query.addValues({ bsw@0: initiative_id: initiative_id, bsw@0: author_id: req.current_member_id, bsw@0: formatting_engine: formatting_engine, bsw@0: content: content bsw@0: }); bsw@0: query.addReturning('id'); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: var draft_id = result.rows[0].id; bsw@0: bsw@0: respond('json', conn, req, res, 'ok', { issue_id: issue_id, initiative_id: initiative_id, draft_id: draft_id } ); bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: bsw@0: // new draft in new initiative in existant issue bsw@0: } else if (issue_id && !area_id && !initiative_id) { bsw@0: bsw@0: // check privilege bsw@0: requireIssuePrivilege(conn, req, res, issue_id, function() { bsw@0: bsw@0: // check issue state bsw@0: requireIssueState(conn, req, res, issue_id, ['admission', 'discussion', 'verification'], function() { bsw@0: bsw@0: // check contingent bsw@0: requireContingentLeft(conn, req, res, true, function() { bsw@0: bsw@0: // insert initiative bsw@0: var query = new selector.SQLInsert('initiative'); bsw@0: query.addValues({ bsw@0: issue_id: issue_id, bsw@0: name: initiative_name, bsw@0: discussion_url: initiative_discussion_url bsw@0: }); bsw@0: query.addReturning('id'); bsw@0: db.query(conn, req, res, query, function(result) { bsw@0: var initiative_id = result.rows[0].id; bsw@0: bsw@0: // insert initiator bsw@0: var query = new selector.SQLInsert('initiator'); bsw@0: query.addValues({ bsw@0: initiative_id: initiative_id, bsw@0: member_id: req.current_member_id, bsw@0: accepted: true bsw@0: }); bsw@0: db.query(conn, req, res, query, function(result) { bsw@0: bsw@0: // insert draft bsw@0: var query = new selector.SQLInsert('draft'); bsw@0: query.addValues({ bsw@0: initiative_id: initiative_id, bsw@0: author_id: req.current_member_id, bsw@0: formatting_engine: formatting_engine, bsw@0: content: content bsw@0: }); bsw@0: query.addReturning('id'); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: bsw@0: var draft_id = result.rows[0].id; bsw@0: respond('json', conn, req, res, 'ok', { initiative_id: initiative_id, draft_id: draft_id } ); bsw@0: bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: bsw@0: // new draft in existant initiative bsw@0: } else if (initiative_id && !area_id && !issue_id ) { bsw@0: bsw@0: // check privilege bsw@0: requireInitiativePrivilege(conn, req, res, initiative_id, function() { bsw@0: bsw@0: // check issue state bsw@0: requireIssueStateForInitiative(conn, req, res, initiative_id, ['admission', 'discussion'], function() { bsw@0: bsw@0: bsw@0: // get initiator bsw@0: var query = new selector.Selector(); bsw@0: query.from('initiator'); bsw@0: query.addField('accepted'); bsw@0: query.addWhere(['initiative_id = ? AND member_id = ?', initiative_id, req.current_member_id]); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: bsw@0: // if member is not initiator, deny creating new draft bsw@0: if (result.rows.length != 1) { bsw@0: respond('json', conn, req, res, 'forbidden', null, 'You are not initiator of this initiative and not allowed to update its draft.'); bsw@0: return; bsw@0: } bsw@0: var initiator = result.rows[0]; bsw@0: if (!initiator.accepted) { bsw@0: 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: return; bsw@0: }; bsw@0: bsw@0: // check contingent bsw@0: requireContingentLeft(conn, req, res, false, function() { bsw@0: bsw@0: // insert new draft bsw@0: var query = new selector.SQLInsert('draft'); bsw@0: query.addValues({ bsw@0: initiative_id: initiative_id, bsw@0: author_id: req.current_member_id, bsw@0: formatting_engine: formatting_engine, bsw@0: content: content bsw@0: }); bsw@0: query.addReturning('id'); bsw@0: db.query(conn, req, res, query, function (result, conn) { bsw@0: bsw@0: var draft_id = result.rows[0].id; bsw@0: respond('json', conn, req, res, 'ok', { draft_id: draft_id } ); bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: }); bsw@0: bsw@0: // none of them (invalid request) bsw@0: } else { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'Excactly one of area_id, issue_id or initiative_id must be supplied!'); bsw@0: }; bsw@0: bsw@0: }); bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/suggestion': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'member', function() { bsw@0: // TODO bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/opinion': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'member', function() { bsw@0: // TODO bsw@0: }); bsw@0: }, bsw@0: bsw@0: '/delegation': function (conn, req, res, params) { bsw@0: requireAccessLevel(conn, req, res, 'member', function() { bsw@0: var unit_id = parseInt(params.unit_id); bsw@0: var area_id = parseInt(params.area_id); bsw@0: var issue_id = parseInt(params.issue_id); bsw@0: var trustee_id; bsw@0: bsw@0: if (params.trustee_id == '') { bsw@0: trustee_id = null; bsw@0: } else { bsw@0: trustee_id = parseInt(params.trustee_id); bsw@0: } bsw@0: bsw@0: lockMemberById(conn, req, res, req.current_member_id, function() { bsw@0: bsw@0: if (params.delete) { bsw@0: var query = new selector.SQLDelete('delegation') bsw@0: if (unit_id && !area_id && !issue_id) { bsw@0: query.addWhere(['unit_id = ?', unit_id]); bsw@0: } else if (!unit_id && area_id && !issue_id) { bsw@0: query.addWhere(['area_id = ?', area_id]); bsw@0: } else if (!unit_id && !area_id && issue_id) { bsw@0: query.addWhere(['issue_id = ?', issue_id]); bsw@0: } else { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'Excactly one of unit, area_id, issue_id must be supplied!'); bsw@0: return; bsw@0: } bsw@0: query.addWhere(['truster_id = ?', req.current_member_id]); bsw@0: db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); }); bsw@0: } else { bsw@0: var query = new selector.Upserter('delegation', ['truster_id']); bsw@0: query.addValues({ bsw@0: truster_id: req.current_member_id, bsw@0: trustee_id: trustee_id bsw@0: }); bsw@0: if (unit_id && !area_id && !issue_id) { bsw@0: bsw@0: // check privilege bsw@0: requireUnitPrivilege(conn, req, res, unit_id, function() { bsw@0: bsw@0: query.addKeys(['unit_id']) bsw@0: query.addValues({ unit_id: unit_id, scope: 'unit' }); bsw@0: db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); }); bsw@0: }); bsw@0: bsw@0: } else if (!unit_id && area_id && !issue_id) { bsw@0: bsw@0: // check privilege bsw@0: requireAreaPrivilege(conn, req, res, area_id, function() { bsw@0: bsw@0: query.addKeys(['area_id']) bsw@0: query.addValues({ area_id: area_id, scope: 'area' }); bsw@0: db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); }); bsw@0: }); bsw@0: bsw@0: } else if (!unit_id && !area_id && issue_id) { bsw@0: bsw@0: // check privilege bsw@0: requireIssuePrivilege(conn, req, res, issue_id, function() { bsw@0: bsw@0: // check issue state bsw@0: requireIssueState(conn, req, res, issue_id, ['admission', 'discussion', 'verification', 'voting'], function() { bsw@0: bsw@0: query.addKeys(['issue_id']) bsw@0: query.addValues({ issue_id: issue_id, scope: 'issue' }); bsw@0: db.query(conn, req, res, query, function(result) { respond('json', conn, req, res, 'ok'); }); bsw@0: }); bsw@0: }); bsw@0: } else { bsw@0: respond('json', conn, req, res, 'unprocessable', null, 'Excactly one of unit_id, area_id, issue_id must be supplied!'); bsw@0: return; bsw@0: } bsw@0: } bsw@0: bsw@0: }); bsw@0: bsw@0: }); bsw@0: }, bsw@0: bsw@0: };