<commit_before>var ejs = require('./ejs.js');
var lf = require('./lfcli.js');

/**
 * Takes care of retrieving data for and rendering the
 * suggestion page.
 *
 * @param state The state object of the current HTTP-Request
 */
exports.show = function(state) {

	// we need a valid user session...
	if(!state.session_key()) {
		state.sendToLogin();
		return;
	}

	var suggestion_id = state.url.query.suggestion_id;
	if(suggestion_id === undefined) {
		state.fail_invalidResource('No suggestion ID given.', 400);
	}

	// the variables to that will be set by the data retrievers
	// and if set the page will be rendered
	var suggestion_info, opinions_info, my_opinion_info, paging_info, initiative_text;

	var finish = function() {
		var ctx = state.context;

		if(suggestion_info !== undefined && opinions_info !== undefined && my_opinion_info !== undefined && paging_info !== undefined && initiative_text !== undefined) {
			ctx.suggestion = suggestion_info;
			suggestion_info.opinions = opinions_info;
			suggestion_info.isayimplemented = my_opinion_info.i_say_implemented;
			suggestion_info.smiley = my_opinion_info.smiley;
			suggestion_info.my_opinion = my_opinion_info.opinion;
			suggestion_info.opinionpage = paging_info.opinionpage;
			suggestion_info.opinionpages = paging_info.opinionpages;
			suggestion_info.initiative.text = initiative_text;

			console.log('Final context for rendering: ' + JSON.stringify(ctx.suggestion));

			ctx.meta.currentpage = "suggestion";
			ejs.render(state, '/suggestion.tpl');
		}
	}

	// get the initiative
	lf.query('/suggestion', { 'suggestion_id': suggestion_id, 'include_initiatives': true, 'render_content': 'html' }, state, function(res) {
		console.log(JSON.stringify(res));
		if(res.result.length === 0) {
			state.fail_invalidResource('No suggestion with id ' + suggestion_id + ' found.', 404);
			return;
		}
		var suggestion_res = res.result[0];
		console.log('SUGGESTION: ' + JSON.stringify(suggestion_res));
		var initiative = res.initiatives[suggestion_res.initiative_id];
		if(initiative === undefined) {
			state.fail('Initiative ' + suggestion_res.initiative_id + ' for suggestion ' + suggestion_id + ' not included in reply.');
			return;
		}
		console.log('INITIATIVE: ' + JSON.stringify(initiative));

		lf.query('/draft', { 'initiative_id': initiative.id, 'current_draft': true, 'render_content': 'html' }, state, function(res) {
			if(res.result.length === 0) {
				state.fail('No draft found for initiative ' + initiative.id + ' found.');
				return;
			}
			var lf_draft = res.result[0];
			initiative_text = lf_draft.content;
			finish();
		});

		var total_supporters = initiative.supporter_count;

		var tmp_suggestion = {
			id: suggestion_id,
			initiative: {
				name: initiative.name
			},
			name: suggestion_res.name,
			text: suggestion_res.content,

			mustsupporter: suggestion_res.plus2_unfulfilled_count + suggestion_res.plus2_fulfilled_count,
			shouldsupporter: suggestion_res.plus1_unfulfilled_count + suggestion_res.plus1_fulfilled_count,
			neutralsupporter: total_supporters
			                  - (suggestion_res.plus2_unfulfilled_count + suggestion_res.plus2_fulfilled_count)
			                  - (suggestion_res.plus1_unfulfilled_count + suggestion_res.plus1_fulfilled_count)
			                  - (suggestion_res.minus2_unfulfilled_count + suggestion_res.minus2_fulfilled_count)
			                  - (suggestion_res.minus1_unfulfilled_count + suggestion_res.minus1_fulfilled_count),
			shouldnotsupporter: suggestion_res.minus1_unfulfilled_count + suggestion_res.minus1_fulfilled_count,
			mustnotsupporter: suggestion_res.minus2_unfulfilled_count + suggestion_res.minus2_fulfilled_count,

			notimplementedmustsupporter: suggestion_res.plus2_unfulfilled_count,
			notimplementedshouldsupporter: suggestion_res.plus1_unfulfilled_count,
			notimplementedshouldnotsupporter: suggestion_res.minus1_unfulfilled_count,
			notimplementedmustnotsupporter: suggestion_res.minus2_unfulfilled_count,

			implementedmustsupporter: suggestion_res.plus2_fulfilled_count,
			implementedshouldsupporter: suggestion_res.plus1_fulfilled_count,
			implementedshouldnotsupporter: suggestion_res.minus1_fulfilled_count,
			implementedmustnotsupporter: suggestion_res.minus2_fulfilled_count,
		};
		tmp_suggestion.notimplementedneutralsupporter = tmp_suggestion.neutralsupporter;
		tmp_suggestion.implementedneutralsupporter = tmp_suggestion.neutralsupporter;

		tmp_suggestion.mustsupportwidth = tmp_suggestion.mustsupporter * 100 / total_supporters + "%";
		tmp_suggestion.shouldsupportwidth = tmp_suggestion.shouldsupporter * 100 / total_supporters + "%";
		tmp_suggestion.neutralsupportwidth = tmp_suggestion.neutralsupporter * 100 / total_supporters + "%";
		tmp_suggestion.shouldnotsupportwidth = tmp_suggestion.shouldnotsupporter * 100 / total_supporters + "%";
		tmp_suggestion.mustnotsupportwidth = tmp_suggestion.mustnotsupporter * 100 / total_supporters + "%";

		var total_notimplemented = tmp_suggestion.notimplementedmustsupporter
		                         + tmp_suggestion.notimplementedshouldsupporter
		                         + tmp_suggestion.notimplementedneutralsupporter
		                         + tmp_suggestion.notimplementedshouldnotsupporter
		                         + tmp_suggestion.notimplementedmustnotsupporter;
		if(total_notimplemented == 0) {
			total_notimplemented = 1; // avoid devision by 0
			tmp_suggestion.notimplementedneutralsupporterwidth = '100%';
		} else {
			tmp_suggestion.notimplementedneutralsupporterwidth = tmp_suggestion.notimplementedneutralsupporter * 100 / total_notimplemented + "%";
		}
		tmp_suggestion.notimplementedmustsupporterwidth = tmp_suggestion.notimplementedmustsupporter * 100 / total_notimplemented + "%";
		tmp_suggestion.notimplementedshouldsupporterwidth = tmp_suggestion.notimplementedshouldsupporter * 100 / total_notimplemented + "%";
		tmp_suggestion.notimplementedneutralsupporterwidth = tmp_suggestion.notimplementedneutralsupporter * 100 / total_notimplemented + "%";
		tmp_suggestion.notimplementedshouldnotsupporterwidth = tmp_suggestion.notimplementedshouldnotsupporter * 100 / total_notimplemented + "%";
		tmp_suggestion.notimplementedmustnotsupporterwidth = tmp_suggestion.notimplementedmustnotsupporter * 100 / total_notimplemented + "%";

		var total_implemented = tmp_suggestion.implementedmustsupporter
		                         + tmp_suggestion.implementedshouldsupporter
		                         + tmp_suggestion.implementedneutralsupporter
		                         + tmp_suggestion.implementedshouldnotsupporter
		                         + tmp_suggestion.implementedmustnotsupporter;
		if(total_implemented == 0) {
			total_implemented = 1; // avoid devision by 0
			tmp_suggestion.implementedneutralsupporterwidth = '100%';
		} else {
			tmp_suggestion.implementedneutralsupporterwidth = tmp_suggestion.implementedneutralsupporter * 100 / total_implemented + "%";
		}
		tmp_suggestion.implementedmustsupporterwidth = tmp_suggestion.implementedmustsupporter * 100 / total_implemented + "%";
		tmp_suggestion.implementedshouldsupporterwidth = tmp_suggestion.implementedshouldsupporter * 100 / total_implemented + "%";
		tmp_suggestion.implementedshouldnotsupporterwidth = tmp_suggestion.implementedshouldnotsupporter * 100 / total_implemented + "%";
		tmp_suggestion.implementedmustnotsupporterwidth = tmp_suggestion.implementedmustnotsupporter * 100 / total_implemented + "%";

		// add author info
		lf.query('/member', { 'member_id': suggestion_res.author_id }, state, function(res) {
			if(res.result.length === 0) {
				state.fail('No member found with id ' + suggestion_res.author_id + ' when looking for author of suggestion ' + suggestion_id);
				return;
			}
			var author = res.result[0];
			console.log("AUTHOR: " + JSON.stringify(author));

			tmp_suggestion.author = {
				nick: author.name,
				name: author.realname || author.name,
				picsmall: "avatar/" + author.id,
				picmini: "picbig/" + author.id
			}

			suggestion_info = tmp_suggestion;
			finish();
		});
	});

	opinions(state, function(tmp_opinions, tmp_paging, tmp_my_opinion) {
		opinions_info = tmp_opinions;
		paging_info = tmp_paging;
		my_opinion_info = tmp_my_opinion;
		console.log('OPINIONS FINISHED!');
		finish();
	});
}

exports.updateOpinions = function(state) {
	if(!state.session_key()) {
		state.sendToLogin();
		return;
	}

	var finish = function(opinions, paging) {
		var ctx = state.context;
		ctx.meta.currentpage = "suggestion";

		ctx.suggestion = {
			id: state.url.query.suggestion_id,
			opinions: opinions,
			opinionpage: paging.opinionpage,
			opinionpages: paging.opinionpages
		}

		console.log('Sending out opinions!');
		ejs.render(state, '/update_opinions.tpl', true);
	}

	opinions(state, finish);
}

function opinions(state, finish) {
	// configuration stuff
	var OPINIONS_PER_PAGE = 4;

	var suggestion_id = state.url.query.suggestion_id;
	if(suggestion_id === undefined) {
		state.fail_invalidResource('No suggestion ID given.', 400);
	}

	lf.query('/opinion', { 'suggestion_id': suggestion_id }, state, function(res) {
		var lf_opinions = res.result;

		/**
		 * Calculate the hapiness smiley for the given opinion.
		 * Result is 1 for very happy, 4 for very unhappy
		 */
		var calculate_smiley = function(lf_opinion) {
			var smiley = 1; // if degree == 0 we don't care, so we are happy
			if(lf_opinion.degree !== 0) {
				// renormalize (map to 0...4 and then to 1...4)
				smiley = lf_opinion.degree + 2;
				if(smiley < 2) {
					smiley += 2;
				}
				// if fullfilled highest value is happy
				if(lf_opinion.fulfilled) {
					smiley = 5 - smiley;
				}
			}
			return smiley;
		}

		console.log('OPINIONS:' + JSON.stringify(res));
		var my_opinion_info = {
			i_say_implemented: false,
			smiley: 1,
			opinion: 0
		};
		var members_to_resolve = '';

		var paging_info = function() {
			var tmp = {
				opinionpages: Math.floor(lf_opinions.length / OPINIONS_PER_PAGE) + 1,
				opinionpage: state.url.query.opinionpage || 1
			}
			if(tmp.opinionpage < 1 || tmp.opinionpage > tmp.opinionpages) {
				console.log('WARNING: Opinion page ' + tmp.opinionpage + ' requested, but only pages 1 to ' + tmp.opinionpages + ' valid for suggestion ' + suggestion_id);
				tmp.opinionpage = 1;
			}
			return tmp;
		}();
		console.log('PAGING INFO ' + JSON.stringify(paging_info));

		for(var i = OPINIONS_PER_PAGE * (paging_info.opinionpage - 1); i < lf_opinions.length && i < OPINIONS_PER_PAGE * (paging_info.opinionpage); i++) {
			var lf_opinion = lf_opinions[i];
			if(lf_opinion.member_id == state.user_id()) {
				my_opinion_info.i_say_implemented = lf_opinion.fulfilled;
				my_opinion_info.smiley = calculate_smiley(lf_opinion);
				my_opinion_info.opinion = lf_opinion.degree;
			}

			if(members_to_resolve != '') {
				members_to_resolve += ',';
			}
			members_to_resolve += lf_opinion.member_id;
		}

		lf.query('/member', { 'member_id': members_to_resolve }, state, function(res) {
			var i;
			var lf_member;
			var lf_members = res.result;
			var lf_members_by_id = {};
			for(i = 0; i < lf_members.length; i++) {
				lf_member = lf_members[i];
				lf_members_by_id[lf_member.id] = lf_member;
			}

			var tmp_opinion;
			var tmp_opinions = [];

			var calculate_action = function(lf_opinion) {
				switch(lf_opinion.degree) {
					case -2:
					case -1:
						return 'against';
					case 1:
					case 2:
						return 'for';
					default:
						return '';
				}
			};

		for(var i = OPINIONS_PER_PAGE * (paging_info.opinionpage - 1); i < lf_opinions.length && i < OPINIONS_PER_PAGE * (paging_info.opinionpage); i++) {
				lf_opinion = lf_opinions[i];
				// filter own opinion
				if(lf_opinion.member_id != state.user_id()) {
					console.log('LF OPINION: ' + JSON.stringify(lf_opinion));
					lf_member = lf_members_by_id[lf_opinion.member_id];
					if(lf_member === undefined) {
						console.log('ERROR: Failed to lookup user with ' + lf_opinion.member_id + ', owner of opinion for suggeston ' + suggestion_id);
						continue; // skip
					}
					console.log('LF member: ' + JSON.stringify(lf_member));
					tmp_opinion = {
						user: {
							nick: lf_member.name,
							name: lf_member.realname,
							picsmall: 'avatar/' + lf_member.id,
							picmini: 'avatar/' + lf_member.id
						},
						action: calculate_action(lf_opinion),
						implemented: lf_opinion.fulfilled,
						smiley: calculate_smiley(lf_opinion)
					}
					tmp_opinions.push(tmp_opinion);
				}
			}

			finish(tmp_opinions, paging_info, my_opinion_info);
		});
	});
}
<commit_msg>Removed debug output from suggestion screen.<commit_after>var ejs = require('./ejs.js');
var lf = require('./lfcli.js');

/**
 * Takes care of retrieving data for and rendering the
 * suggestion page.
 *
 * @param state The state object of the current HTTP-Request
 */
exports.show = function(state) {

	// we need a valid user session...
	if(!state.session_key()) {
		state.sendToLogin();
		return;
	}

	var suggestion_id = state.url.query.suggestion_id;
	if(suggestion_id === undefined) {
		state.fail_invalidResource('No suggestion ID given.', 400);
	}

	// the variables to that will be set by the data retrievers
	// and if set the page will be rendered
	var suggestion_info, opinions_info, my_opinion_info, paging_info, initiative_text;

	var finish = function() {
		var ctx = state.context;

		if(suggestion_info !== undefined && opinions_info !== undefined && my_opinion_info !== undefined && paging_info !== undefined && initiative_text !== undefined) {
			ctx.suggestion = suggestion_info;
			suggestion_info.opinions = opinions_info;
			suggestion_info.isayimplemented = my_opinion_info.i_say_implemented;
			suggestion_info.smiley = my_opinion_info.smiley;
			suggestion_info.my_opinion = my_opinion_info.opinion;
			suggestion_info.opinionpage = paging_info.opinionpage;
			suggestion_info.opinionpages = paging_info.opinionpages;
			suggestion_info.initiative.text = initiative_text;

			ctx.meta.currentpage = "suggestion";
			ejs.render(state, '/suggestion.tpl');
		}
	}

	// get the initiative
	lf.query('/suggestion', { 'suggestion_id': suggestion_id, 'include_initiatives': true, 'render_content': 'html' }, state, function(res) {
		if(res.result.length === 0) {
			state.fail_invalidResource('No suggestion with id ' + suggestion_id + ' found.', 404);
			return;
		}
		var suggestion_res = res.result[0];
		var initiative = res.initiatives[suggestion_res.initiative_id];
		if(initiative === undefined) {
			state.fail('Initiative ' + suggestion_res.initiative_id + ' for suggestion ' + suggestion_id + ' not included in reply.');
			return;
		}

		lf.query('/draft', { 'initiative_id': initiative.id, 'current_draft': true, 'render_content': 'html' }, state, function(res) {
			if(res.result.length === 0) {
				state.fail('No draft found for initiative ' + initiative.id + ' found.');
				return;
			}
			var lf_draft = res.result[0];
			initiative_text = lf_draft.content;
			finish();
		});

		var total_supporters = initiative.supporter_count;

		var tmp_suggestion = {
			id: suggestion_id,
			initiative: {
				name: initiative.name
			},
			name: suggestion_res.name,
			text: suggestion_res.content,

			mustsupporter: suggestion_res.plus2_unfulfilled_count + suggestion_res.plus2_fulfilled_count,
			shouldsupporter: suggestion_res.plus1_unfulfilled_count + suggestion_res.plus1_fulfilled_count,
			neutralsupporter: total_supporters
			                  - (suggestion_res.plus2_unfulfilled_count + suggestion_res.plus2_fulfilled_count)
			                  - (suggestion_res.plus1_unfulfilled_count + suggestion_res.plus1_fulfilled_count)
			                  - (suggestion_res.minus2_unfulfilled_count + suggestion_res.minus2_fulfilled_count)
			                  - (suggestion_res.minus1_unfulfilled_count + suggestion_res.minus1_fulfilled_count),
			shouldnotsupporter: suggestion_res.minus1_unfulfilled_count + suggestion_res.minus1_fulfilled_count,
			mustnotsupporter: suggestion_res.minus2_unfulfilled_count + suggestion_res.minus2_fulfilled_count,

			notimplementedmustsupporter: suggestion_res.plus2_unfulfilled_count,
			notimplementedshouldsupporter: suggestion_res.plus1_unfulfilled_count,
			notimplementedshouldnotsupporter: suggestion_res.minus1_unfulfilled_count,
			notimplementedmustnotsupporter: suggestion_res.minus2_unfulfilled_count,

			implementedmustsupporter: suggestion_res.plus2_fulfilled_count,
			implementedshouldsupporter: suggestion_res.plus1_fulfilled_count,
			implementedshouldnotsupporter: suggestion_res.minus1_fulfilled_count,
			implementedmustnotsupporter: suggestion_res.minus2_fulfilled_count,
		};
		tmp_suggestion.notimplementedneutralsupporter = tmp_suggestion.neutralsupporter;
		tmp_suggestion.implementedneutralsupporter = tmp_suggestion.neutralsupporter;

		tmp_suggestion.mustsupportwidth = tmp_suggestion.mustsupporter * 100 / total_supporters + "%";
		tmp_suggestion.shouldsupportwidth = tmp_suggestion.shouldsupporter * 100 / total_supporters + "%";
		tmp_suggestion.neutralsupportwidth = tmp_suggestion.neutralsupporter * 100 / total_supporters + "%";
		tmp_suggestion.shouldnotsupportwidth = tmp_suggestion.shouldnotsupporter * 100 / total_supporters + "%";
		tmp_suggestion.mustnotsupportwidth = tmp_suggestion.mustnotsupporter * 100 / total_supporters + "%";

		var total_notimplemented = tmp_suggestion.notimplementedmustsupporter
		                         + tmp_suggestion.notimplementedshouldsupporter
		                         + tmp_suggestion.notimplementedneutralsupporter
		                         + tmp_suggestion.notimplementedshouldnotsupporter
		                         + tmp_suggestion.notimplementedmustnotsupporter;
		if(total_notimplemented == 0) {
			total_notimplemented = 1; // avoid devision by 0
			tmp_suggestion.notimplementedneutralsupporterwidth = '100%';
		} else {
			tmp_suggestion.notimplementedneutralsupporterwidth = tmp_suggestion.notimplementedneutralsupporter * 100 / total_notimplemented + "%";
		}
		tmp_suggestion.notimplementedmustsupporterwidth = tmp_suggestion.notimplementedmustsupporter * 100 / total_notimplemented + "%";
		tmp_suggestion.notimplementedshouldsupporterwidth = tmp_suggestion.notimplementedshouldsupporter * 100 / total_notimplemented + "%";
		tmp_suggestion.notimplementedneutralsupporterwidth = tmp_suggestion.notimplementedneutralsupporter * 100 / total_notimplemented + "%";
		tmp_suggestion.notimplementedshouldnotsupporterwidth = tmp_suggestion.notimplementedshouldnotsupporter * 100 / total_notimplemented + "%";
		tmp_suggestion.notimplementedmustnotsupporterwidth = tmp_suggestion.notimplementedmustnotsupporter * 100 / total_notimplemented + "%";

		var total_implemented = tmp_suggestion.implementedmustsupporter
		                         + tmp_suggestion.implementedshouldsupporter
		                         + tmp_suggestion.implementedneutralsupporter
		                         + tmp_suggestion.implementedshouldnotsupporter
		                         + tmp_suggestion.implementedmustnotsupporter;
		if(total_implemented == 0) {
			total_implemented = 1; // avoid devision by 0
			tmp_suggestion.implementedneutralsupporterwidth = '100%';
		} else {
			tmp_suggestion.implementedneutralsupporterwidth = tmp_suggestion.implementedneutralsupporter * 100 / total_implemented + "%";
		}
		tmp_suggestion.implementedmustsupporterwidth = tmp_suggestion.implementedmustsupporter * 100 / total_implemented + "%";
		tmp_suggestion.implementedshouldsupporterwidth = tmp_suggestion.implementedshouldsupporter * 100 / total_implemented + "%";
		tmp_suggestion.implementedshouldnotsupporterwidth = tmp_suggestion.implementedshouldnotsupporter * 100 / total_implemented + "%";
		tmp_suggestion.implementedmustnotsupporterwidth = tmp_suggestion.implementedmustnotsupporter * 100 / total_implemented + "%";

		// add author info
		lf.query('/member', { 'member_id': suggestion_res.author_id }, state, function(res) {
			if(res.result.length === 0) {
				state.fail('No member found with id ' + suggestion_res.author_id + ' when looking for author of suggestion ' + suggestion_id);
				return;
			}
			var author = res.result[0];

			tmp_suggestion.author = {
				nick: author.name,
				name: author.realname || author.name,
				picsmall: "avatar/" + author.id,
				picmini: "picbig/" + author.id
			}

			suggestion_info = tmp_suggestion;
			finish();
		});
	});

	opinions(state, function(tmp_opinions, tmp_paging, tmp_my_opinion) {
		opinions_info = tmp_opinions;
		paging_info = tmp_paging;
		my_opinion_info = tmp_my_opinion;
		finish();
	});
}

exports.updateOpinions = function(state) {
	if(!state.session_key()) {
		state.sendToLogin();
		return;
	}

	var finish = function(opinions, paging) {
		var ctx = state.context;
		ctx.meta.currentpage = "suggestion";

		ctx.suggestion = {
			id: state.url.query.suggestion_id,
			opinions: opinions,
			opinionpage: paging.opinionpage,
			opinionpages: paging.opinionpages
		}

		ejs.render(state, '/update_opinions.tpl', true);
	}

	opinions(state, finish);
}

function opinions(state, finish) {
	// configuration stuff
	var OPINIONS_PER_PAGE = 4;

	var suggestion_id = state.url.query.suggestion_id;
	if(suggestion_id === undefined) {
		state.fail_invalidResource('No suggestion ID given.', 400);
	}

	lf.query('/opinion', { 'suggestion_id': suggestion_id }, state, function(res) {
		var lf_opinions = res.result;

		/**
		 * Calculate the hapiness smiley for the given opinion.
		 * Result is 1 for very happy, 4 for very unhappy
		 */
		var calculate_smiley = function(lf_opinion) {
			var smiley = 1; // if degree == 0 we don't care, so we are happy
			if(lf_opinion.degree !== 0) {
				// renormalize (map to 0...4 and then to 1...4)
				smiley = lf_opinion.degree + 2;
				if(smiley < 2) {
					smiley += 2;
				}
				// if fullfilled highest value is happy
				if(lf_opinion.fulfilled) {
					smiley = 5 - smiley;
				}
			}
			return smiley;
		}

		var my_opinion_info = {
			i_say_implemented: false,
			smiley: 1,
			opinion: 0
		};
		var members_to_resolve = '';

		var paging_info = function() {
			var tmp = {
				opinionpages: Math.floor(lf_opinions.length / OPINIONS_PER_PAGE) + 1,
				opinionpage: state.url.query.opinionpage || 1
			}
			if(tmp.opinionpage < 1 || tmp.opinionpage > tmp.opinionpages) {
				console.log('WARNING: Opinion page ' + tmp.opinionpage + ' requested, but only pages 1 to ' + tmp.opinionpages + ' valid for suggestion ' + suggestion_id);
				tmp.opinionpage = 1;
			}
			return tmp;
		}();

		for(var i = OPINIONS_PER_PAGE * (paging_info.opinionpage - 1); i < lf_opinions.length && i < OPINIONS_PER_PAGE * (paging_info.opinionpage); i++) {
			var lf_opinion = lf_opinions[i];
			if(lf_opinion.member_id == state.user_id()) {
				my_opinion_info.i_say_implemented = lf_opinion.fulfilled;
				my_opinion_info.smiley = calculate_smiley(lf_opinion);
				my_opinion_info.opinion = lf_opinion.degree;
			}

			if(members_to_resolve != '') {
				members_to_resolve += ',';
			}
			members_to_resolve += lf_opinion.member_id;
		}

		lf.query('/member', { 'member_id': members_to_resolve }, state, function(res) {
			var i;
			var lf_member;
			var lf_members = res.result;
			var lf_members_by_id = {};
			for(i = 0; i < lf_members.length; i++) {
				lf_member = lf_members[i];
				lf_members_by_id[lf_member.id] = lf_member;
			}

			var tmp_opinion;
			var tmp_opinions = [];

			var calculate_action = function(lf_opinion) {
				switch(lf_opinion.degree) {
					case -2:
					case -1:
						return 'against';
					case 1:
					case 2:
						return 'for';
					default:
						return '';
				}
			};

		for(var i = OPINIONS_PER_PAGE * (paging_info.opinionpage - 1); i < lf_opinions.length && i < OPINIONS_PER_PAGE * (paging_info.opinionpage); i++) {
				lf_opinion = lf_opinions[i];
				// filter own opinion
				if(lf_opinion.member_id != state.user_id()) {
					lf_member = lf_members_by_id[lf_opinion.member_id];
					if(lf_member === undefined) {
						console.error('ERROR: Failed to lookup user with ' + lf_opinion.member_id + ', owner of opinion for suggeston ' + suggestion_id);
						continue; // skip
					}
					tmp_opinion = {
						user: {
							nick: lf_member.name,
							name: lf_member.realname,
							picsmall: 'avatar/' + lf_member.id,
							picmini: 'avatar/' + lf_member.id
						},
						action: calculate_action(lf_opinion),
						implemented: lf_opinion.fulfilled,
						smiley: calculate_smiley(lf_opinion)
					}
					tmp_opinions.push(tmp_opinion);
				}
			}

			finish(tmp_opinions, paging_info, my_opinion_info);
		});
	});
}
<|endoftext|>


<commit_before>(function () {
    angular.module("components").factory("ModalService", ModalService);

    ModalService.$inject = ['$uibModal'];

    function ModalService($uibModal) {
        var service = {
            modal: null
        };

        service.dismiss = function (reason) {
            service.modal.dismiss(reason);
            service.modal = null;
        };

        service.close = function (reason) {
            service.modal.close(reason);
            service.modal = null;
        };

        service.openScientillaDocumentForm = function (document, researchEntity) {
            var scopeVars = {
                document: document,
                researchEntity: researchEntity
            };

            service.modal = openModal(
                    '<scientilla-document-form\
                        document="vm.document"\
                        research-entity="vm.researchEntity"\
                        on-close="vm.onClose"\
                        on-submit="vm.onSubmit" >\
                    </scientilla-document-form>',
                    scopeVars
                    );

            return service.modal.result;
        };

        service.openScientillaUserForm = function (user) {

            var modalScope = getScope({
                user: user
            });

            service.modal = openModal(
                    '<scientilla-user-form\
                        user="vm.user"\
                        on-close="vm.onClose"\
                        on-submit="vm.onSubmit" >\
                    </scientilla-user-form>',
                    modalScope
                    );

            return service.modal.result;
        };

        service.openScientillaGroupForm = function (group) {

            var modalScope = getScope({
                group: group
            });

            service.modal = openModal(
                    '<scientilla-group-form\
                        group="vm.group"\
                        on-close="vm.onClose"\
                        on-submit="vm.onSubmit" >\
                    </scientilla-group-form>',
                    modalScope
                    );

            return service.modal.result;
        };

        function openModal(template, scope) {
            var callbacks = getDefaultCallbacks();

            _.defaults(scope,callbacks);

            var controller = function() {
                _.assign(this, scope);
            };

            return $uibModal.open({
                animation: true,
                template: template,
                controller: controller,
                controllerAs: 'vm'
            });
        }

        function getDefaultCallbacks() {
            var callbacks = {
                onClose: service.close,
                onSubmit: service.close
            };

            return callbacks;
        }

        return service;
    }

}());
<commit_msg>Fixed modal related merge problem<commit_after>(function () {
    angular.module("components").factory("ModalService", ModalService);

    ModalService.$inject = ['$uibModal'];

    function ModalService($uibModal) {
        var service = {
            modal: null
        };

        service.dismiss = function (reason) {
            service.modal.dismiss(reason);
            service.modal = null;
        };

        service.close = function (reason) {
            service.modal.close(reason);
            service.modal = null;
        };

        service.openScientillaDocumentForm = function (document, researchEntity) {
            var scopeVars = {
                document: document,
                researchEntity: researchEntity
            };

            service.modal = openModal(
                    '<scientilla-document-form\
                        document="vm.document"\
                        research-entity="vm.researchEntity"\
                        on-close="vm.onClose"\
                        on-submit="vm.onSubmit" >\
                    </scientilla-document-form>',
                    scopeVars
                    );

            return service.modal.result;
        };

        service.openScientillaUserForm = function (user) {

            var scopeVars = {
                user: user
            };

            service.modal = openModal(
                    '<scientilla-user-form\
                        user="vm.user"\
                        on-close="vm.onClose"\
                        on-submit="vm.onSubmit" >\
                    </scientilla-user-form>',
                    scopeVars
                    );

            return service.modal.result;
        };

        service.openScientillaGroupForm = function (group) {

            var scopeVars = {
                group: group
            };

            service.modal = openModal(
                    '<scientilla-group-form\
                        group="vm.group"\
                        on-close="vm.onClose"\
                        on-submit="vm.onSubmit" >\
                    </scientilla-group-form>',
                    scopeVars
                    );

            return service.modal.result;
        };

        function openModal(template, scope) {
            var callbacks = getDefaultCallbacks();

            _.defaults(scope,callbacks);

            var controller = function() {
                _.assign(this, scope);
            };

            return $uibModal.open({
                animation: true,
                template: template,
                controller: controller,
                controllerAs: 'vm'
            });
        }

        function getDefaultCallbacks() {
            var callbacks = {
                onClose: service.close,
                onSubmit: service.close
            };

            return callbacks;
        }

        return service;
    }

}());
<|endoftext|>


<commit_before>angular.module("DepotVente").controller('TabBordController',['$scope', 'Products', 'Depot', 'Vente', 'Paiement', 'Config',
	function($scope, Products, Depot, Vente, Paiement, Config){
		// Nombre de produits
        $scope.products = Products.query(
							function(data) {
                                $scope.nbrProducts = data.length;
                                $scope.nbrEnStock = 0;
                                $scope.nbrCoursVente = 0;
                                $scope.nbrVendu = 0;
                                $scope.nbrRendu = 0;
                                $scope.nbrPerdu = 0;
                                for (i in data){
                                    if(data[i].etat === "En stock"){
                                        $scope.nbrEnStock+=1;
                                    }
                                    if(data[i].etat === "En cours de vente"){
                                        $scope.nbrCoursVente+=1;
                                    }
                                    if(data[i].etat === "Vendu"){
                                        $scope.nbrVendu+=1;
                                    }
                                    if(data[i].etat === "Rendu"){
                                        $scope.nbrRendu+=1;
                                    }
                                    if(data[i].etat === "Perdu"){
                                        $scope.nbrPerdu+=1;
                                    }
                                    //Graphique pie : nombre produits en fonction de son etat
                                    $scope.labelspie=["En stock","En cours de vente","Vendu","Rendu","Perdu"];
                                    $scope.datapie=[$scope.nbrEnStock,$scope.nbrCoursVente,
                                                    $scope.nbrVendu,$scope.nbrRendu,$scope.nbrPerdu];
                                }
                            },
                            function(err) {
                                $scope.nbrProducts=0;
                                console.log(err);
                            });

        // Nombre de depot
        $scope.depots = Depot.query(
							function(data) {
                                $scope.nbrDepots=data.length;
                            },
                            function(err) {
                                $scope.nbrDepots=0;
                                console.log(err);
                            });

        // Nombre de vente
        $scope.ventes = Vente.query(
                            function(data) {
                                $scope.nbrVenteFini = 0;
                                $scope.nbrVenteEnCours = 0;
                                for (i in data){
                                    if(data[i].etat === 'Finie'){
                                        $scope.nbrVenteFini+=1;
                                    }
                                    if(data[i].etat === 'En cours'){
                                        $scope.nbrVenteEnCours+=1;
                                    }
                                }
                            },
                            function(err) {
                                $scope.nbrVenteFini=0;
                                $scope.nbrVenteEnCours = 0;
                                console.log(err);
                            });

        //Total des vente avec commission
        //Total des vente sans commission
        //valeur commission en %
        $scope.ventes = Vente.query(
                    function(data) {
                        $scope.totalAC=0;
                        $scope.totalSC=0;
                        $scope.commission=0;
                        for (i in data){
                            if(data[i].etat === 'Finie'){
                                Paiement.get({id_sale : data[i].id},function(data){
                                    $scope.totalAC+=data.prix;
                                    Config.get({id:1}, function(data){
                                        $scope.commission = data.valeur;
                                        $scope.totalSC = $scope.totalAC - (data.valeur * $scope.totalAC / 100);
                                    });
                                });
                            }
                        }
                    },
                    function(err) {
                        $scope.totalAC=0;
                        $scope.totalSC=0;
                        $scope.commission=0;
                        console.log(err);
                    });

        //Graphique line
        $scope.labelsline = ["January", "February", "March", "April", "May", "June", "July"];
        $scope.seriesline = ['Series A', 'Series B'];
        $scope.dataline = [
            [65, 59, 80, 81, 56, 55, 40],
            [28, 48, 40, 19, 86, 27, 90]
        ];
}]);<commit_msg>Mourad et les calcul sisi<commit_after>angular.module("DepotVente").controller('TabBordController',['$scope', 'Products', 'Depot', 'Vente', 'Paiement', 'Config',
	function($scope, Products, Depot, Vente, Paiement, Config){
		// Nombre de produits
        $scope.products = Products.query(
							function(data) {
                                $scope.nbrProducts = data.length;
                                $scope.nbrEnStock = 0;
                                $scope.nbrCoursVente = 0;
                                $scope.nbrVendu = 0;
                                $scope.nbrRendu = 0;
                                $scope.nbrPerdu = 0;
                                for (i in data){
                                    if(data[i].etat === "En stock"){
                                        $scope.nbrEnStock+=1;
                                    }
                                    if(data[i].etat === "En cours de vente"){
                                        $scope.nbrCoursVente+=1;
                                    }
                                    if(data[i].etat === "Vendu"){
                                        $scope.nbrVendu+=1;
                                    }
                                    if(data[i].etat === "Rendu"){
                                        $scope.nbrRendu+=1;
                                    }
                                    if(data[i].etat === "Perdu"){
                                        $scope.nbrPerdu+=1;
                                    }
                                    //Graphique pie : nombre produits en fonction de son etat
                                    $scope.labelspie=["En stock","En cours de vente","Vendu","Rendu","Perdu"];
                                    $scope.datapie=[$scope.nbrEnStock,$scope.nbrCoursVente,
                                                    $scope.nbrVendu,$scope.nbrRendu,$scope.nbrPerdu];
                                }
                            },
                            function(err) {
                                $scope.nbrProducts=0;
                                console.log(err);
                            });

        // Nombre de depot
        $scope.depots = Depot.query(
							function(data) {
                                $scope.nbrDepots=data.length;
                            },
                            function(err) {
                                $scope.nbrDepots=0;
                                console.log(err);
                            });

        // Nombre de vente
        $scope.ventes = Vente.query(
                            function(data) {
                                $scope.nbrVenteFini = 0;
                                $scope.nbrVenteEnCours = 0;
                                for (i in data){
                                    if(data[i].etat === 'Finie'){
                                        $scope.nbrVenteFini+=1;
                                    }
                                    if(data[i].etat === 'En cours'){
                                        $scope.nbrVenteEnCours+=1;
                                    }
                                }
                            },
                            function(err) {
                                $scope.nbrVenteFini=0;
                                $scope.nbrVenteEnCours = 0;
                                console.log(err);
                            });

        //Total des vente avec commission
        //Total des vente sans commission
        //valeur commission en %
        $scope.ventes = Vente.query(
                    function(data) {
                        $scope.totalAC=0;
                        $scope.totalSC=0;
                        $scope.commission=0;
                        for (i in data){
                            if(data[i].etat === 'Finie'){
                                Paiement.get({id_sale : data[i].id},function(data){
                                    $scope.totalAC+=data.prix;
                                    Config.get({id:1}, function(data){
                                        $scope.commission = data.valeur;
                                        $scope.totalSC = (100 * $scope.totalAC) / (100 + $scope.commission);
                                    });
                                });
                            }
                        }
                    },
                    function(err) {
                        $scope.totalAC=0;
                        $scope.totalSC=0;
                        $scope.commission=0;
                        console.log(err);
                    });

        //Graphique line
        $scope.labelsline = ["January", "February", "March", "April", "May", "June", "July"];
        $scope.seriesline = ['Series A', 'Series B'];
        $scope.dataline = [
            [65, 59, 80, 81, 56, 55, 40],
            [28, 48, 40, 19, 86, 27, 90]
        ];
}]);<|endoftext|>


<commit_before>// Copyright (c) 2018 Google Inc. All rights reserved.
// This code may only be used under the BSD style license found at
// http://polymer.github.io/LICENSE.txt
// Code distributed by Google as part of this project is also
// subject to an additional IP rights grant found at
// http://polymer.github.io/PATENTS.txt

defineParticle(({DomParticle}) => {
  const rootTemplate = `
    <style>
      hex-game {
        --hex-p1: #F44336;
        --hex-p2: #2196F3;
      }
      hex-game[player=p1] {
        --current-player-color: var(--hex-p1);
      }
      hex-game[player=p2] {
        --current-player-color: var(--hex-p2);
      }

      /* TODO: Remove this once we switch slots to use shadow dom */
      hexa-gon > div {
        width: 100%;
        height: 100%;
      }
      hex-cell {
        width: 100%;
        height: 100%;
        display: block;
      }
      hex-cell:hover {
        background: var(--current-player-color);
        opacity: 0.5;
      }
      hex-cell[player=p1] {
        background: var(--hex-p1);
        opacity: 1;
      }
      hex-cell[player=p2] {
        background: var(--hex-p2);
        opacity: 1;
      }
    </style>
    hex-game <hex-game player$="{{player}}" slotid="board"></hex-game>`;
  const cellTemplate = `<hex-cell player$="{{player}}" on-click="onCellClick"></hex-cell>`;

  class Board {
    constructor(size) {
      this._size = size;
      this._board = [];
      this._board.length = size * size;
    }

    get size() {
      return this._size;
    }

    trySetCell(x, y, value) {
      if (!this._board[x + this.size * y]) {
        this._board[x + this.size * y] = value;
        return true;
      }
      return false;
    }

    cell(x, y) {
      return this._board[x + this.size * y];
    }

    toModel() {
      let result = [];
      for (let x = 0; x < this.size; x++) {
        for (let y = 0; y < this.size; y++) {
          let value = this.cell(x, y);
          if (value) {
            result.push({subId: `${x}-${y}`, player: value});
          }
        }
      }
      return result;
    }
  }

  return class extends DomParticle {
    constructor() {
      super();
      this._board = new Board(8);
      this._player = 'p1';
    }
    getTemplate(slotName) {
      if (slotName == 'root')
        return rootTemplate;
      else if (slotName == 'cell')
        return cellTemplate;
    }
    render(props, state) {
      if (this.currentSlotName == 'root') {
        return {
          player: state.player,
        };
      }
      if (this.currentSlotName == 'cell') {
        return {
          items: state.cells || [],
        };
      }
    }
    onCellClick(e) {
      let subId = e.data.subId;
      let [x, y] = subId.split('-');
      x = Number(x);
      y = Number(y);
      if (this._board.trySetCell(x, y, this._player)) {
        this._player = this._player == 'p1' ? 'p2' : 'p1';
      }
      this.setState({
        player: this._player,
        cells: this._board.toModel(),
      });
    }
  };
});<commit_msg>Add the swap rule<commit_after>// Copyright (c) 2018 Google Inc. All rights reserved.
// This code may only be used under the BSD style license found at
// http://polymer.github.io/LICENSE.txt
// Code distributed by Google as part of this project is also
// subject to an additional IP rights grant found at
// http://polymer.github.io/PATENTS.txt

defineParticle(({DomParticle}) => {
  const rootTemplate = `
    <style>
      hex-game {
        --hex-p1: #F44336;
        --hex-p2: #2196F3;
      }
      hex-game[player=p1] {
        --current-player-color: var(--hex-p1);
      }
      hex-game[player=p2] {
        --current-player-color: var(--hex-p2);
      }
      hex-game[can-swap] {
        --swap-color: var(--current-player-color);
      }

      /* TODO: Remove this once we switch slots to use shadow dom */
      hexa-gon > div {
        width: 100%;
        height: 100%;
      }
      hex-cell {
        width: 100%;
        height: 100%;
        display: block;
      }
      hex-game[can-swap] hex-cell:hover,
      hex-cell:not([player]):hover {
        background: var(--current-player-color);
        opacity: 0.5;
      }
      hex-cell[player=p1] {
        background: var(--hex-p1);
      }
      hex-cell[player=p2] {
        background: var(--hex-p2);
      }
    </style>
    hex-game <hex-game player$="{{player}}" can-swap$="{{canSwap}}" slotid="board"></hex-game>`;
  const cellTemplate = `<hex-cell player$="{{player}}" on-click="onCellClick"></hex-cell>`;

  class Board {
    constructor(size) {
      this._size = size;
      this._board = [];
      this._board.length = size * size;
      this._player = 0;
      this._moves = 0;
    }

    get size() {
      return this._size;
    }

    get canSwap() {
      return this._moves == 1;
    }

    get player() {
      return this._player ? 'p1' : 'p2';
    }

    trySetCell(x, y) {
      if (!this._board[x + this.size * y] || this.canSwap) {
        this._board[x + this.size * y] = this.player;
        this._player ^= 1;
        this._moves++;
        return true;
      }
      return false;
    }

    cell(x, y) {
      return this._board[x + this.size * y];
    }

    toModel() {
      let result = [];
      for (let x = 0; x < this.size; x++) {
        for (let y = 0; y < this.size; y++) {
          let value = this.cell(x, y);
          if (value) {
            result.push({subId: `${x}-${y}`, player: value});
          }
        }
      }
      return result;
    }
  }

  return class extends DomParticle {
    constructor() {
      super();
      this._board = new Board(8);
      this._player = 'p1';
    }
    getTemplate(slotName) {
      if (slotName == 'root')
        return rootTemplate;
      else if (slotName == 'cell')
        return cellTemplate;
    }
    render(props, state) {
      if (this.currentSlotName == 'root') {
        return {
          player: state.player,
          canSwap: state.canSwap,
        };
      }
      if (this.currentSlotName == 'cell') {
        return {
          items: state.cells || [],
        };
      }
    }
    onCellClick(e) {
      let subId = e.data.subId;
      let [x, y] = subId.split('-');
      x = Number(x);
      y = Number(y);
      let board = this._board;
      board.trySetCell(x, y);
      this.setState({
        player: board.player,
        canSwap: board.canSwap,
        cells: board.toModel(),
      });
    }
  };
});<|endoftext|>


<commit_before>var path = require('path'),
    fs = require('fs');

// Prep for recursive dive of the directories
function getFilesFromDirectory(basePath, dirName, tree) {
  var dirPath = path.join(basePath, dirName),
      treeType = typeof tree,
      files = [],
      keys,
      key,
      i,
      len;

  // TODO: Use async lib and don't do sync
  // If the tree is not a tree/object
  if (treeType !== 'object') {
    // and is a boolean
    if (treeType === 'boolean') {
      // TODO: Handle black listing? (via false)
      if (tree === true) {
        keys = fs.readdirSync(dirPath);

        for (i = 0, len = keys.length; i < len; i++) {
          key = keys[i];
          files.push( path.join(dirPath, key) );
        }
      }
    }
  } else {
  // Otherwise, keep on diving in the tree
    keys = Object.getOwnPropertyNames(tree);
    for (i = 0, len = keys.length; i < len; i++) {
      key = keys[i];
      files = files.concat(getFilesFromDirectory(dirPath, key, tree[key]));
    }
  }

  return files;
}

function FileFinder(conf) {
  this.baseDir = conf.baseDir || process.cwd();
  this.directories = conf.directories || {};
  this.humanMap = {};

  // Scan for files
  this.scan();
}
FileFinder.prototype = {
  'query': function (query) {
    // Grab the keys for quick looping
    var humanMap = this.humanMap,
        humanNames = Object.getOwnPropertyNames(humanMap),

    // Collect all items that match
        regexpArr = query.split(/\s+/),
        j,
        matches = [];
    for (i = 0, len = humanNames.length; i < len; i++) {
      humanName = humanNames[i];
      matchesAll = true;
      for (j = regexpArr.length; j--;) {
        if (humanName.indexOf(regexpArr[j]) === -1) {
          matchesAll = false;
          break;
        }
      }

      if (matchesAll === true) {
        matches.push(humanName);
      }
    }

    // Return the matches
    return matches;
  },
  'scan': function () {
    var fullFilenames = this.scanFullFilenames();
    this.mapFilenamesToHuman(fullFilenames);
  },
  'scanFullFilenames': function () {
    var retArr = this.fullFilenames = getFilesFromDirectory(this.baseDir, '.', this.directories);
    return retArr;
  },
  'mapFilenamesToHuman': function (fullFilenames) {
    // Recusively dive and collect all files
    var i,
        len,
        humanToFullFilenameMap = this.humanMap,
        baseDir = this.baseDir,
        filename,
        humanName;

    // Loop through the files
    for (i = 0, len = fullFilenames.length; i < len; i++) {
      // Get each filename sans base_dir
      filename = fullFilenames[i];
      humanName = filename.replace(baseDir, '');

      // Add the file name to the map
      humanToFullFilenameMap[humanName] = filename;
    }

    return this;
  }
};

// Grab our config and create our fileFinder
var conf = require('./finder.conf.js'),
    fileFinder = new FileFinder(conf),
// Generate the interface
    rl = require('readline'),
    iface = rl.createInterface(process.stdin, process.stdout, null);

// Set up startSearch for calling later
function startSearch() {
  iface.question('Enter search: ', function (query) {
    // Get the results of our query
    var matches = fileFinder.query(query),
        len = matches.length;

    // If no results were found
    if (len === 0) {
      console.log('No results found for: ' + query);
      startSearch();
    } else {
    // Otherwise, list options
      for (i = 0; i < len; i++) {
        console.log(i + ': ' + matches[i]);
      }

      // Ask for a number
      iface.question('Which item would you like to open? ', function (numStr) {
        var num = +numStr,
            item;

        // If the number is not NaN
        if (num === num) {
          // and if it is in our result set
          if (numStr !== '' && num >= 0 && num < len) {
            // Open it
            item = matches[num];
            console.log('Opening: ' + item);
            var exec = require('child_process').exec;
            exec('start ' + humanToFullFilenameMap[item], function () {});
          }
        } else {
        // Otherwise, if there was a word in there so we are assuming it was 'rescan'
          // Rescan
          console.log('Rescanning...');
          fileFinder.scan();
        }

        // Begin the search again
        startSearch();
      });
    }
  });
}

startSearch();

// TODO: Eventually...
// // TEST: tty inputting
// var sentence = {
  // 'charArr': [],
  // 'push': function (letter) {
    // val += letter;
    // // TODO: Move the cursor
  // },
  // 'delete': function (letter) {

    // // TODO: Rewrite sentence
  // }
// };
// process.stdin.resume();
// process.stdin.setEncoding('utf8');

// require('tty').setRawMode(true);

// function ontype(letter) {
  // switch (letter) {
  // // If the command is to terminate, terminate
    // case '\u0003':
      // return process.exit();
      // break;
  // // If a carriage return (enter) was hit
    // case '\r':
    // case '\n':
      // // TODO: Open the highlighted item
      // console.log('Opening: ', sentence);

      // // and retype the selected item
      // console.log('Select a file: ', sentence);
      // break;
    // default:
      // // Otherwise, append the item to the sentence
      // sentence

      // // Get unicode
      // // console.log(arguments);
  // }
// }
// process.stdin.on('data', ontype);<commit_msg>Removed listing of directories. Will need to begin recursing directories.<commit_after>var path = require('path'),
    fs = require('fs');

// Prep for recursive dive of the directories
function getFilesFromDirectory(basePath, dirName, tree) {
  var dirPath = path.join(basePath, dirName),
      treeType = typeof tree,
      files = [],
      keys,
      key,
      i,
      len,
      currentPath,
      pathStats;

  // TODO: Use async lib and don't do sync
  // If the tree is not a tree/object
  if (treeType !== 'object') {
    // and is a boolean
    if (treeType === 'boolean') {
      // TODO: Handle black listing? (via false)
      if (tree === true) {
        keys = fs.readdirSync(dirPath);

        for (i = 0, len = keys.length; i < len; i++) {
          key = keys[i];
          currentPath = path.join(dirPath, key);
          pathStats = fs.statSync(currentPath);

          // If the item is a directory
          if (pathStats.isDirectory()) {
            // TODO: Recurse its files
            // getFilesFromDirectory(currentPath,
          } else {
            // Otherwise push on the new item
            files.push( currentPath );
          }
        }
      }
    }
  } else {
  // Otherwise, keep on diving in the tree
    keys = Object.getOwnPropertyNames(tree);
    for (i = 0, len = keys.length; i < len; i++) {
      key = keys[i];
      files = files.concat(getFilesFromDirectory(dirPath, key, tree[key]));
    }
  }

  return files;
}

function FileFinder(conf) {
  this.baseDir = conf.baseDir || process.cwd();
  this.directories = conf.directories || {};
  this.humanMap = {};

  // Scan for files
  this.scan();
}
FileFinder.prototype = {
  'open': function (name) {
    var exec = require('child_process').exec;
    exec('start ' + this.humanMap[name], function () {});
  },
  'query': function (query) {
    // Grab the keys for quick looping
    var humanMap = this.humanMap,
        humanNames = Object.getOwnPropertyNames(humanMap),

    // Collect all items that match
        regexpArr = query.split(/\s+/),
        j,
        matches = [],
        matchesAll;
    for (i = 0, len = humanNames.length; i < len; i++) {
      humanName = humanNames[i];
      matchesAll = true;
      for (j = regexpArr.length; j--;) {
        if (humanName.indexOf(regexpArr[j]) === -1) {
          matchesAll = false;
          break;
        }
      }

      if (matchesAll === true) {
        matches.push(humanName);
      }
    }

    // Return the matches
    return matches;
  },
  'scan': function () {
    var fullFilenames = this.scanFullFilenames();
    this.mapFilenamesToHuman(fullFilenames);
  },
  'scanFullFilenames': function () {
    var retArr = this.fullFilenames = getFilesFromDirectory(this.baseDir, '.', this.directories);
    return retArr;
  },
  'mapFilenamesToHuman': function (fullFilenames) {
    // Recusively dive and collect all files
    var i,
        len,
        humanToFullFilenameMap = this.humanMap,
        baseDir = this.baseDir,
        filename,
        humanName;

    // Loop through the files
    for (i = 0, len = fullFilenames.length; i < len; i++) {
      // Get each filename sans base_dir
      filename = fullFilenames[i];
      humanName = filename.replace(baseDir, '');

      // Add the file name to the map
      humanToFullFilenameMap[humanName] = filename;
    }

    return this;
  }
};

// Grab our config and create our fileFinder
var conf = require('./finder.conf.js'),
    fileFinder = new FileFinder(conf),
// Generate the interface
    rl = require('readline'),
    iface = rl.createInterface(process.stdin, process.stdout, null);

// Set up startSearch for calling later
function startSearch() {
  iface.question('Enter search: ', function (query) {
    // Get the results of our query
    var matches = fileFinder.query(query),
        len = matches.length;

    // If no results were found
    if (len === 0) {
      console.log('No results found for: ' + query);
      startSearch();
    } else {
    // Otherwise, list options
      for (i = 0; i < len; i++) {
        console.log(i + ': ' + matches[i]);
      }

      // Ask for a number
      iface.question('Which item would you like to open? ', function (numStr) {
        var num = +numStr,
            item;

        // If the number is not NaN
        if (num === num) {
          // and if it is in our result set
          if (numStr !== '' && num >= 0 && num < len) {
            // Open it
            item = matches[num];
            console.log('Opening: ' + item);
            fileFinder.open(item);
          }
        } else {
        // Otherwise, if there was a word in there so we are assuming it was 'rescan'
          // Rescan
          console.log('Rescanning...');
          fileFinder.scan();
        }

        // Begin the search again
        startSearch();
      });
    }
  });
}

startSearch();

// TODO: Eventually...
// // TEST: tty inputting
// var sentence = {
  // 'charArr': [],
  // 'push': function (letter) {
    // val += letter;
    // // TODO: Move the cursor
  // },
  // 'delete': function (letter) {

    // // TODO: Rewrite sentence
  // }
// };
// process.stdin.resume();
// process.stdin.setEncoding('utf8');

// require('tty').setRawMode(true);

// function ontype(letter) {
  // switch (letter) {
  // // If the command is to terminate, terminate
    // case '\u0003':
      // return process.exit();
      // break;
  // // If a carriage return (enter) was hit
    // case '\r':
    // case '\n':
      // // TODO: Open the highlighted item
      // console.log('Opening: ', sentence);

      // // and retype the selected item
      // console.log('Select a file: ', sentence);
      // break;
    // default:
      // // Otherwise, append the item to the sentence
      // sentence

      // // Get unicode
      // // console.log(arguments);
  // }
// }
// process.stdin.on('data', ontype);<|endoftext|>


<commit_before>function init(){var e=document.createElement("style");e.appendChild(document.createTextNode("")),document.head.appendChild(e),e.sheet.insertRule("body { visibility: hidden; }",0)}function scoper(e,t){var n=new RegExp("([^\r\n,{}]+)(,(?=[^}]*{)|s*{)","g");return e=e.replace(n,function(e,n,d){return n.match(/^\s*(@media|@keyframes|to|from|@font-face)/)?n+d:(n.match(/:scope/)&&(n=n.replace(/([^\s]*):scope/,function(e,t){return""===t?"> *":"> "+t})),(n=n.replace(/^(\s*)/,"$1"+t+" "))+d)})}function process(){var e=document.body.querySelectorAll("style[scoped]");if(0===e.length)return void(document.getElementsByTagName("body")[0].style.visibility="visible");for(var t=document.head||document.getElementsByTagName("head")[0],n=document.createElement("style"),d="",o=0;o<e.length;o++){var r=e[o],c=r.innerHTML;if(c&&"BODY"!==r.parentElement.nodeName){var a="scoper-"+o,i="#"+a,s=document.createElement("span");s.id=a;var l=r.parentNode;l.parentNode.replaceChild(s,l),s.appendChild(l),r.parentNode.removeChild(r),d+=scoper(c,i)}}n.styleSheet?n.styleSheet.cssText=d:n.appendChild(document.createTextNode(d)),t.appendChild(n),document.getElementsByTagName("body")[0].style.visibility="visible"}!function(){"use strict";"undefined"==typeof document||"scoped"in document.createElement("style")||(init(),"complete"===document.readyState||"loaded"===document.readyState?process():document.addEventListener("DOMContentLoaded",process))}(),"undefined"!=typeof exports&&(exports.scoper=scoper);<commit_msg>minify script<commit_after>function init(){var e=document.createElement("style");e.appendChild(document.createTextNode("")),document.head.appendChild(e),e.sheet.insertRule("body { visibility: hidden; }",0)}function scoper(e,t){var n=new RegExp("([^\r\n,{}]+)(,(?=[^}]*{)|s*{)","g");return e=e.replace(n,function(e,n,d){return n.match(/^\s*(@media|@.*keyframes|to|from|@font-face|1?[0-9]?[0-9])/)?n+d:(n.match(/:scope/)&&(n=n.replace(/([^\s]*):scope/,function(e,t){return""===t?"> *":"> "+t})),(n=n.replace(/^(\s*)/,"$1"+t+" "))+d)})}function process(){var e=document.body.querySelectorAll("style[scoped]");if(0===e.length)return void(document.getElementsByTagName("body")[0].style.visibility="visible");for(var t=document.head||document.getElementsByTagName("head")[0],n=document.createElement("style"),d="",o=0;o<e.length;o++){var r=e[o],c=r.innerHTML;if(c&&"BODY"!==r.parentElement.nodeName){var a="scoper-"+o,i="#"+a,s=document.createElement("span");s.id=a;var l=r.parentNode;l.parentNode.replaceChild(s,l),s.appendChild(l),r.parentNode.removeChild(r),d+=scoper(c,i)}}n.styleSheet?n.styleSheet.cssText=d:n.appendChild(document.createTextNode(d)),t.appendChild(n),document.getElementsByTagName("body")[0].style.visibility="visible"}!function(){"use strict";"undefined"==typeof document||"scoped"in document.createElement("style")||(init(),"complete"===document.readyState||"loaded"===document.readyState?process():document.addEventListener("DOMContentLoaded",process))}(),"undefined"!=typeof exports&&(exports.scoper=scoper);<|endoftext|>


<commit_before>/**
 * var connection = new Connection({ tag:             'droonga',
 *                                   defaultDataset:  'example',
 *                                   hostName:        '127.0.0.1',
 *                                   port:            24224,
 *                                   receiveHostName: '127.0.0.1',
 *                                   receivePort:     10030 });
 */

var EventEmitter = require('events').EventEmitter;
var fluent = require('fluent-logger');
var FluentReceiver = require('./receiver').FluentReceiver;
var util = require('util');

var DEFAULT_FLUENT_TAG =
      Connection.DEFAULT_FLUENT_TAG =
        'droonga';
var DEFAULT_FLUENT_HOST_NAME =
      Connection.DEFAULT_FLUENT_HOST_NAME =
        '127.0.0.1';
var DEFAULT_FLUENT_PORT =
      Connection.DEFAULT_FLUENT_PORT =
        24224;
var DEFAULT_RECEIVE_HOST_NAME =
      Connection.DEFAULT_RECEIVE_HOST_NAME =
        '127.0.0.1';

var ERROR_GATEWAY_TIMEOUT =
      Connection.ERROR_GATEWAY_TIMEOUT =
        504;

var DEFAULT_RESPONSE_TIMEOUT =
      Connection.DEFAULT_RESPONSE_TIMEOUT =
        60 * 1000;

function Connection(params) {
  EventEmitter.call(this);
  this._params = params || {};
  this._logger = this._params.logger || console;
  this._init();
}

util.inherits(Connection, EventEmitter);

Connection.prototype._init = function() {
  this.closed = false;
  this._callbacks = {};
  this._id = Date.now();
  this.tag = process.env.DROONGA_ENGINE_TAG ||
               this._params.tag ||
                 DEFAULT_FLUENT_TAG;
  this.defaultDataset = process.env.DROONGA_ENGINE_DEFAULT_DATASET ||
                          this._params.defaultDataset ||
                            '';
  this._initSender();
  this._initReceiver();
};

Connection.prototype._initSender = function(wait) {
  this._sendingMessages = {};
  var options = { host: process.env.DROONGA_ENGINE_HOST ||
                          this._params.hostName ||
                            DEFAULT_FLUENT_HOST_NAME,
                  port: process.env.DROONGA_ENGINE_PORT ||
                          this._params.port ||
                            DEFAULT_FLUENT_PORT };
  var sender = fluent.createFluentSender(this.tag, options);
  this._sender = sender;
  this._sender.on('error', (function(error) {
    var errorMessage =
      'An error is occurred in protocol adapter: ' +
      '[' + error.name + '] ' + error.message;
    var ids = Object.keys(this._sendingMessages);
    if (ids.length == 0) {
      this._logger.error(errorMessage, error);
    } else {
      ids.forEach(function(id) {
        var sendingMessage = this._sendingMessages[id];
        var message = {
          inReplyTo: id,
          statusCode: 500,
          type: sendingMessage.type + '.result',
          body: {
            name: 'ProtocolAdapterError',
            message: errorMessage,
            detail: error
          }
        }
        this.emit('reply:' + id, message.statusCode, message);
      }.bind(this));
      this._sendingMessages = {};
    }
  }).bind(this));
};

Connection.prototype._initReceiver = function() {
  this._receiveCount = 0;
  this._sendCount = 0;
  if (!this._receiver) {
    this.receiveHostName = process.env.DROONGA_ENGINE_RECEIVE_HOST ||
                             this._params.receiveHostName ||
                               DEFAULT_RECEIVE_HOST_NAME;
    this.receivePort = process.env.DROONGA_ENGINE_RECEIVE_PORT ||
                         this._params.receivePort;
  } else {
    this._receiver.close();
  }

  var receiver = new FluentReceiver(this.receivePort,
                                    { logger: this._logger });
  receiver.listen((function() {
    this.receivePort = receiver.port;
  }).bind(this));

  var tag = this.tag + '.message';
  this._logger.debug('Connection._initReceiver %d: %d %d:',
                     this._id, receiver._id, this.receivePort, tag);
  this._receiver = receiver;
  this._receiver.on(tag,
                    this._handleMessage.bind(this));
};

function isSuccess(code) {
  return Math.floor(code / 100) == 2;
}

Connection.prototype._handleMessage = function(envelope) {
  var inReplyTo = envelope.inReplyTo;
  if (inReplyTo) {
    delete this._sendingMessages[inReplyTo];
    this._logger.debug('Connection._handleMessage.reply %d:', this._id, inReplyTo);
    var errorCode = envelope.statusCode;
    if (!errorCode || isSuccess(errorCode))
      errorCode = null;
    this.emit('reply:' + inReplyTo, errorCode, envelope);
  } else {
    this._logger.debug('Connection._handleMessage.message %d:', this._id, envelope.type);
    this.emit(envelope.type, envelope);
  }
};

Connection.prototype.getRouteToSelf = function(options) {
  options = options || {};

  var from = this.receiveHostName + ':' + this.receivePort + '/' +
               this.tag + '?connection_id=' + this._id;
  if (options.sessionId)
    from += '&client_session_id=' + options.sessionId;

  return from;
}

var count = 0;
function createId() {
  return Date.now() + ':' + (count++);
}

function getCurrentTime() {
  // The method toISOString() returns a GMT (ex. 2013-01-10T08:34:41.252Z)
  // on node. However, a local time (ex. 2013-01-10T17:34:41.252+09:00) is
  // more helpful for debugging. We should use it in the feature...
  return new Date().toISOString();
}

function toPositiveInteger(number) {
  if (!number)
    return 0;

  var integer = parseInt(number);
  if (isNaN(integer))
    return 0;

  return Math.max(integer, 0);
}

Connection.prototype.emitMessage = function(type, body, callback, options) {
  if (!this._sender)
    throw new Error('emitMessage is unexpectedly called after the connection is closed!');

  options = options || {};

  // support emitMessage(type, body, options)
  if (callback && typeof callback != 'function') {
    options = callback;
    callback = null;
  }

  var id = createId();
  this._logger.debug('Connection.emitMessage %d:', this._id, id, type);
  var from = this.getRouteToSelf(options);
  var envelope = {
    id:         id,
    from:       from,
    date:       getCurrentTime(),
    dataset:    options.dataset || this.defaultDataset,
    type:       type,
    body:       body
  };
  if (callback) {
    envelope.replyTo = from;

    var event = 'reply:' + id;
    var timeoutId;
    this.once(event, function(errorCode, response) {
      this._logger.debug('Connection.emitMessage.reply %d:', this._id, errorCode);
      clearTimeout(timeoutId);
      callback(errorCode, response);
    });
    options.timeout = toPositiveInteger(options.timeout) ||
                        DEFAULT_RESPONSE_TIMEOUT;
    timeoutId = setTimeout((function() {
      this.removeAllListeners(event);
      callback(ERROR_GATEWAY_TIMEOUT, null);
    }).bind(this), options.timeout);
  }
  this._sendingMessages[id] = {
    type: type
  };
  this._sender.emit('message', envelope, options.emittedCallback);
  return envelope;
};

Connection.prototype.close = function() {
  this.removeAllListeners();

  if (this._sender && typeof this._sender.end == 'function') {
    this._sender.end();
    this._sender.removeAllListeners();
    delete this._sender;
  }

  if (this._receiver && typeof this._receiver.close == 'function') {
    this._receiver.close();
    this._receiver.removeAllListeners();
    delete this._receiver;
  }
  this.closed = true;
};

exports.Connection = Connection;
<commit_msg>Output all whole envelope for debugging<commit_after>/**
 * var connection = new Connection({ tag:             'droonga',
 *                                   defaultDataset:  'example',
 *                                   hostName:        '127.0.0.1',
 *                                   port:            24224,
 *                                   receiveHostName: '127.0.0.1',
 *                                   receivePort:     10030 });
 */

var EventEmitter = require('events').EventEmitter;
var fluent = require('fluent-logger');
var FluentReceiver = require('./receiver').FluentReceiver;
var util = require('util');

var DEFAULT_FLUENT_TAG =
      Connection.DEFAULT_FLUENT_TAG =
        'droonga';
var DEFAULT_FLUENT_HOST_NAME =
      Connection.DEFAULT_FLUENT_HOST_NAME =
        '127.0.0.1';
var DEFAULT_FLUENT_PORT =
      Connection.DEFAULT_FLUENT_PORT =
        24224;
var DEFAULT_RECEIVE_HOST_NAME =
      Connection.DEFAULT_RECEIVE_HOST_NAME =
        '127.0.0.1';

var ERROR_GATEWAY_TIMEOUT =
      Connection.ERROR_GATEWAY_TIMEOUT =
        504;

var DEFAULT_RESPONSE_TIMEOUT =
      Connection.DEFAULT_RESPONSE_TIMEOUT =
        60 * 1000;

function Connection(params) {
  EventEmitter.call(this);
  this._params = params || {};
  this._logger = this._params.logger || console;
  this._init();
}

util.inherits(Connection, EventEmitter);

Connection.prototype._init = function() {
  this.closed = false;
  this._callbacks = {};
  this._id = Date.now();
  this.tag = process.env.DROONGA_ENGINE_TAG ||
               this._params.tag ||
                 DEFAULT_FLUENT_TAG;
  this.defaultDataset = process.env.DROONGA_ENGINE_DEFAULT_DATASET ||
                          this._params.defaultDataset ||
                            '';
  this._initSender();
  this._initReceiver();
};

Connection.prototype._initSender = function(wait) {
  this._sendingMessages = {};
  var options = { host: process.env.DROONGA_ENGINE_HOST ||
                          this._params.hostName ||
                            DEFAULT_FLUENT_HOST_NAME,
                  port: process.env.DROONGA_ENGINE_PORT ||
                          this._params.port ||
                            DEFAULT_FLUENT_PORT };
  var sender = fluent.createFluentSender(this.tag, options);
  this._sender = sender;
  this._sender.on('error', (function(error) {
    var errorMessage =
      'An error is occurred in protocol adapter: ' +
      '[' + error.name + '] ' + error.message;
    var ids = Object.keys(this._sendingMessages);
    if (ids.length == 0) {
      this._logger.error(errorMessage, error);
    } else {
      ids.forEach(function(id) {
        var sendingMessage = this._sendingMessages[id];
        var message = {
          inReplyTo: id,
          statusCode: 500,
          type: sendingMessage.type + '.result',
          body: {
            name: 'ProtocolAdapterError',
            message: errorMessage,
            detail: error
          }
        }
        this.emit('reply:' + id, message.statusCode, message);
      }.bind(this));
      this._sendingMessages = {};
    }
  }).bind(this));
};

Connection.prototype._initReceiver = function() {
  this._receiveCount = 0;
  this._sendCount = 0;
  if (!this._receiver) {
    this.receiveHostName = process.env.DROONGA_ENGINE_RECEIVE_HOST ||
                             this._params.receiveHostName ||
                               DEFAULT_RECEIVE_HOST_NAME;
    this.receivePort = process.env.DROONGA_ENGINE_RECEIVE_PORT ||
                         this._params.receivePort;
  } else {
    this._receiver.close();
  }

  var receiver = new FluentReceiver(this.receivePort,
                                    { logger: this._logger });
  receiver.listen((function() {
    this.receivePort = receiver.port;
  }).bind(this));

  var tag = this.tag + '.message';
  this._logger.debug('Connection._initReceiver %d: %d %d:',
                     this._id, receiver._id, this.receivePort, tag);
  this._receiver = receiver;
  this._receiver.on(tag,
                    this._handleMessage.bind(this));
};

function isSuccess(code) {
  return Math.floor(code / 100) == 2;
}

Connection.prototype._handleMessage = function(envelope) {
  var inReplyTo = envelope.inReplyTo;
  if (inReplyTo) {
    delete this._sendingMessages[inReplyTo];
    this._logger.debug('Connection._handleMessage.reply %d:', this._id, envelope);
    var errorCode = envelope.statusCode;
    if (!errorCode || isSuccess(errorCode))
      errorCode = null;
    this.emit('reply:' + inReplyTo, errorCode, envelope);
  } else {
    this._logger.debug('Connection._handleMessage.message %d:', this._id, envelope);
    this.emit(envelope.type, envelope);
  }
};

Connection.prototype.getRouteToSelf = function(options) {
  options = options || {};

  var from = this.receiveHostName + ':' + this.receivePort + '/' +
               this.tag + '?connection_id=' + this._id;
  if (options.sessionId)
    from += '&client_session_id=' + options.sessionId;

  return from;
}

var count = 0;
function createId() {
  return Date.now() + ':' + (count++);
}

function getCurrentTime() {
  // The method toISOString() returns a GMT (ex. 2013-01-10T08:34:41.252Z)
  // on node. However, a local time (ex. 2013-01-10T17:34:41.252+09:00) is
  // more helpful for debugging. We should use it in the feature...
  return new Date().toISOString();
}

function toPositiveInteger(number) {
  if (!number)
    return 0;

  var integer = parseInt(number);
  if (isNaN(integer))
    return 0;

  return Math.max(integer, 0);
}

Connection.prototype.emitMessage = function(type, body, callback, options) {
  if (!this._sender)
    throw new Error('emitMessage is unexpectedly called after the connection is closed!');

  options = options || {};

  // support emitMessage(type, body, options)
  if (callback && typeof callback != 'function') {
    options = callback;
    callback = null;
  }

  var id = createId();
  this._logger.debug('Connection.emitMessage %d:', this._id, id, type);
  var from = this.getRouteToSelf(options);
  var envelope = {
    id:         id,
    from:       from,
    date:       getCurrentTime(),
    dataset:    options.dataset || this.defaultDataset,
    type:       type,
    body:       body
  };
  if (callback) {
    envelope.replyTo = from;

    var event = 'reply:' + id;
    var timeoutId;
    this.once(event, function(errorCode, response) {
      this._logger.debug('Connection.emitMessage.reply %d:', this._id, errorCode);
      clearTimeout(timeoutId);
      callback(errorCode, response);
    });
    options.timeout = toPositiveInteger(options.timeout) ||
                        DEFAULT_RESPONSE_TIMEOUT;
    timeoutId = setTimeout((function() {
      this.removeAllListeners(event);
      callback(ERROR_GATEWAY_TIMEOUT, null);
    }).bind(this), options.timeout);
  }
  this._sendingMessages[id] = {
    type: type
  };
  this._sender.emit('message', envelope, options.emittedCallback);
  return envelope;
};

Connection.prototype.close = function() {
  this.removeAllListeners();

  if (this._sender && typeof this._sender.end == 'function') {
    this._sender.end();
    this._sender.removeAllListeners();
    delete this._sender;
  }

  if (this._receiver && typeof this._receiver.close == 'function') {
    this._receiver.close();
    this._receiver.removeAllListeners();
    delete this._receiver;
  }
  this.closed = true;
};

exports.Connection = Connection;
<|endoftext|>


<commit_before>/**
 * This file is part of Superdesk.
 *
 * Copyright 2013, 2014 Sourcefabric z.u. and contributors.
 *
 * For the full copyright and license information, please see the
 * AUTHORS and LICENSE files distributed with this source code, or
 * at https://www.sourcefabric.org/superdesk/license
 */
import angular from 'angular';
import _ from 'lodash';
import moment from 'moment';

postsService.$inject = [
    'api',
    '$q',
    'userList'
];

export default function postsService(api, $q, userList) {
    function filterPosts(filters, postsCriteria) {
        // filters.status
        if (angular.isDefined(filters.status)) {
            postsCriteria.source.query.filtered.filter.and.push({term: {post_status: filters.status}});
        }
        // filters.sticky
        if (angular.isDefined(filters.sticky)) {
            postsCriteria.source.query.filtered.filter.and.push({term: {sticky: filters.sticky}});
        }
        // filters.authors
        if (angular.isDefined(filters.authors) && filters.authors.length > 0) {
            postsCriteria.source.query.filtered.filter.and.push({
                or: {
                    filters: filters.authors.map((author) => ({term: {original_creator: author}}))
                }
            });
        }
        // filters.updatedAfter
        if (angular.isDefined(filters.updatedAfter)) {
            postsCriteria.source.query.filtered.filter.and.push({
                range: {
                    _updated: {
                        gt: filters.updatedAfter
                    }
                }
            });
        }
        // filters.highlight
        if (angular.isDefined(filters.highlight)) {
            postsCriteria.source.query.filtered.filter.and.push({term: {lb_highlight: filters.highlight}});
        }
        // filters.sticky
        if (angular.isDefined(filters.sticky)) {
            postsCriteria.source.query.filtered.filter.and.push({term: {sticky: filters.sticky}});
        }
    }

    /**
     * Fetch a page of posts
     * @param {string} blog_id - The id of the blog
     * @param {object} filters - (available: {boolean} 'status', {string} 'updatedAfter')
     * @param {integer} max_results - maximum number of results per page
     * @param {integer} page - page index
     */
    function getPosts(blogId, filters = {}, maxResults = 15, page = 1) {
        // excludeDeleted: default set to true
        filters.excludeDeleted = angular.isDefined(filters.excludeDeleted) ? filters.excludeDeleted : true;
        const postsCriteria = {
            source: {
                query: {filtered: {filter: {
                    and: []
                }}}
            },
            page: page,
            max_results: maxResults
        };

        // filters.excludeDeleted
        if (filters.excludeDeleted) {
            postsCriteria.source.query.filtered.filter.and.push({not: {term: {deleted: true}}});
        }
        // filters.sort
        if (angular.isDefined(filters.sort)) {
            // this converts the format '-_created' to the elasticsearch one
            let order = 'asc';

            if (filters.sort.charAt(0) === '-') {
                filters.sort = filters.sort.slice(1);
                order = 'desc';
            }
            const sort = {};

            sort[filters.sort] = {order: order, missing: '_last', unmapped_type: 'long'};
            postsCriteria.source.sort = [sort];
        }
        filterPosts(filters, postsCriteria);
        // filters.status
        if (angular.isDefined(filters.syndicationIn)) {
            postsCriteria.source.query.filtered.filter.and.push({
                term: {syndication_in: filters.syndicationIn}
            });
        }

        if (angular.isDefined(filters.noSyndication)) {
            postsCriteria.source.query.filtered.filter.and.push({
                missing: {field: 'syndication_in'}
            });
        }

        return retrievePosts(blogId, postsCriteria);
    }

    function _completeUser(obj) {
        if (obj.commenter) {
            obj.user = {display_name: obj.commenter};
        } else if (obj.syndicated_creator) {
            obj.user = obj.syndicated_creator;
        } else {
            // TODO: way too many requests in there
            // This getUser func is returning a list of users,
            // who would have thought?
            userList.getUser(obj.original_creator).then((user) => {
                obj.user = user;
            });
        }
        return obj;
    }
    function _completePost(post) {
        let multipleItems = false;

        if (post.groups[1].refs.length > 1) {
            multipleItems = post.groups[1].refs.length - 1;
        }

        return $q((resolve, reject) => {
            angular.extend(post, {
                multipleItems: multipleItems,
                // add a `mainItem` field containing the first item
                mainItem: post.groups[1].refs[0],
                items: post.groups[1].refs
            });

            // if an item has a commenter then that post hasComments.
            post.hasComments = _.reduce(post.groups[1].refs,
                (is, val) => is || !_.isUndefined(val.item.commenter)
                , false);
            // `fullDetails` is a business logic that can be compiled from other objects.
            post.fullDetails = post.hasComments;
            // special cases for comments.
            post.showUpdate = post.content_updated_date !== post.published_date &&
                               !post.hasComments && post.mainItem.item.item_type !== 'comment';
            angular.forEach(post.items, (val) => {
                if (post.fullDetails) {
                    _completeUser(val.item);
                }
            });
            _completeUser(post.mainItem.item);

            resolve(post);
        });
    }

    function retrievePost(postId) {
        return api.posts.getById(postId)
            .then(_completePost)
            .then((post) => post);
    }

    function retrieveSyndications(posts) {
        const syndIds = [];

        // This means the syndication module is not enabled
        if (!api.hasOwnProperty('syndicationIn')) {
            return posts;
        }

        posts._items.forEach((post) => {
            if (post.syndication_in && syndIds.indexOf(post.syndication_in) === -1) {
                syndIds.push(post.syndication_in);
            }
        });

        return $q
            .all(syndIds.map((syndId) => api.syndicationIn.getById(syndId)))
            .then((syndList) => angular.extend(posts, {
                _items: posts._items.map((post) => {
                    syndList.forEach((synd) => {
                        if (post.syndication_in === synd._id) {
                            post.producer_blog_title = synd.producer_blog_title;
                        }
                    });

                    return post;
                })
            }));
    }

    function retrievePosts(blogId, postsCriteria) {
        return api('blogs/<regex("[a-f0-9]{24}"):blog_id>/posts', {_id: blogId})
            .query(postsCriteria)
            .then(retrieveSyndications)
            .then((data) => $q.all(data._items.map(_completePost))
                .then((result) => angular.extend(data, {_items: result})));
    }

    function getLatestUpdateDate(posts) {
        if (!angular.isDefined(posts) || posts.length < 1) {
            return;
        }
        let latestDate;
        let date;

        posts.forEach((post) => {
            date = moment(post._updated);
            if (angular.isDefined(latestDate)) {
                if (latestDate.diff(date) < 0) {
                    latestDate = date;
                }
            } else {
                latestDate = date;
            }
        });
        return latestDate.utc().format();
    }

    function savePost(blogId, postToUpdate, itemsParam, postParam = {}) {
        const post = postParam;
        let items = itemsParam;

        post.post_status = post.post_status || _.result(postToUpdate, 'post_status') || 'open';
        const dfds = [];

        if (items && items.length > 0) {
            // prepare the list of items if needed
            if (_.difference(_.keys(items[0]), ['residRef', 'item']).length === 0) {
                items = _.map(items, (item) => item.item);
            }
            // save every items
            _.each(items, (itemParam) => {
                let item = {};
                // because it fails when item has a `_id` field without `_links`

                if (angular.isDefined(items, '_id')) {
                    item = {
                        blog: blogId,
                        text: itemParam.text,
                        meta: itemParam.meta,
                        group_type: itemParam.group_type,
                        item_type: itemParam.item_type,
                        commenter: itemParam.meta && itemParam.meta.commenter,
                        syndicated_creator: itemParam.syndicated_creator
                    };
                }
                dfds.push(api.items.save(item));
            });
        }
        // save the post
        return $q.all(dfds).then((items) => {
            if (dfds.length > 0) {
                angular.extend(post, {
                    blog: blogId,
                    groups: [
                        {
                            id: 'root',
                            refs: [{idRef: 'main'}],
                            role: 'grpRole:NEP'
                        }, {
                            id: 'main',
                            refs: [],
                            role: 'grpRole:Main'
                        }
                    ]
                });
                // update the post reference (links with items)
                _.each(items, (item) => {
                    post.groups[1].refs.push({residRef: item._id});
                });
            }
            let operation;

            if (angular.isDefined(postToUpdate)) {
                operation = function updatePost() {
                    return api.posts.save(postToUpdate, post);
                };
            } else {
                operation = function createPost() {
                    return api.posts.save(post);
                };
            }
            // return the post saved
            return operation();
        });
    }

    function removePost(post) {
        const deleted = {deleted: true};

        return savePost(post.blog, post, [], deleted);
    }

    return {
        getPosts: getPosts,
        getLatestUpdateDate: getLatestUpdateDate,
        retrievePost: retrievePost,
        savePost: savePost,
        saveDraft: function(blogId, post, items, sticky, highlight) {
            return savePost(
                blogId,
                post,
                items,
                {post_status: 'draft', sticky: sticky, lb_highlight: highlight}
            );
        },
        saveContribution: function(blogId, post, items, sticky, highlight) {
            return savePost(
                blogId,
                post,
                items,
                {post_status: 'submitted', sticky: sticky, lb_highlight: highlight}
            );
        },
        remove: removePost
    };
}
<commit_msg>feature: allow unpublished posts in contributions.<commit_after>/**
 * This file is part of Superdesk.
 *
 * Copyright 2013, 2014 Sourcefabric z.u. and contributors.
 *
 * For the full copyright and license information, please see the
 * AUTHORS and LICENSE files distributed with this source code, or
 * at https://www.sourcefabric.org/superdesk/license
 */
import angular from 'angular';
import _ from 'lodash';
import moment from 'moment';

postsService.$inject = [
    'api',
    '$q',
    'userList'
];

export default function postsService(api, $q, userList) {
    function filterPosts(filters, postsCriteria) {
        // filters.status
        if (angular.isDefined(filters.status)) {
            postsCriteria.source.query.filtered.filter.and.push({term: {post_status: filters.status}});
        }
        // filters.sticky
        if (angular.isDefined(filters.sticky)) {
            postsCriteria.source.query.filtered.filter.and.push({term: {sticky: filters.sticky}});
        }
        // filters.authors
        if (angular.isDefined(filters.authors) && filters.authors.length > 0) {
            postsCriteria.source.query.filtered.filter.and.push({
                or: {
                    filters: filters.authors.map((author) => ({term: {original_creator: author}}))
                }
            });
        }
        // filters.updatedAfter
        if (angular.isDefined(filters.updatedAfter)) {
            postsCriteria.source.query.filtered.filter.and.push({
                range: {
                    _updated: {
                        gt: filters.updatedAfter
                    }
                }
            });
        }
        // filters.highlight
        if (angular.isDefined(filters.highlight)) {
            postsCriteria.source.query.filtered.filter.and.push({term: {lb_highlight: filters.highlight}});
        }
        // filters.sticky
        if (angular.isDefined(filters.sticky)) {
            postsCriteria.source.query.filtered.filter.and.push({term: {sticky: filters.sticky}});
        }
    }

    /**
     * Fetch a page of posts
     * @param {string} blog_id - The id of the blog
     * @param {object} filters - (available: {boolean} 'status', {string} 'updatedAfter')
     * @param {integer} max_results - maximum number of results per page
     * @param {integer} page - page index
     */
    function getPosts(blogId, filters = {}, maxResults = 15, page = 1) {
        // excludeDeleted: default set to true
        filters.excludeDeleted = angular.isDefined(filters.excludeDeleted) ? filters.excludeDeleted : true;
        const postsCriteria = {
            source: {
                query: {filtered: {filter: {
                    and: []
                }}}
            },
            page: page,
            max_results: maxResults
        };

        // filters.excludeDeleted
        if (filters.excludeDeleted) {
            postsCriteria.source.query.filtered.filter.and.push({not: {term: {deleted: true}}});
        }
        // filters.sort
        if (angular.isDefined(filters.sort)) {
            // this converts the format '-_created' to the elasticsearch one
            let order = 'asc';

            if (filters.sort.charAt(0) === '-') {
                filters.sort = filters.sort.slice(1);
                order = 'desc';
            }
            const sort = {};

            sort[filters.sort] = {order: order, missing: '_last', unmapped_type: 'long'};
            postsCriteria.source.sort = [sort];
        }
        filterPosts(filters, postsCriteria);
        // filters.status
        if (angular.isDefined(filters.syndicationIn)) {
            postsCriteria.source.query.filtered.filter.and.push({
                term: {syndication_in: filters.syndicationIn}
            });
        }

        if (angular.isDefined(filters.noSyndication)) {
            postsCriteria.source.query.filtered.filter.and.push({
                missing: {field: 'syndication_in'}
            });
            postsCriteria.source.query.filtered.filter.or = [{
                exists: {field: 'unpublished_date'}
            }];
        }

        return retrievePosts(blogId, postsCriteria);
    }

    function _completeUser(obj) {
        if (obj.commenter) {
            obj.user = {display_name: obj.commenter};
        } else if (obj.syndicated_creator) {
            obj.user = obj.syndicated_creator;
        } else {
            // TODO: way too many requests in there
            // This getUser func is returning a list of users,
            // who would have thought?
            userList.getUser(obj.original_creator).then((user) => {
                obj.user = user;
            });
        }
        return obj;
    }
    function _completePost(post) {
        let multipleItems = false;

        if (post.groups[1].refs.length > 1) {
            multipleItems = post.groups[1].refs.length - 1;
        }

        return $q((resolve, reject) => {
            angular.extend(post, {
                multipleItems: multipleItems,
                // add a `mainItem` field containing the first item
                mainItem: post.groups[1].refs[0],
                items: post.groups[1].refs
            });

            // if an item has a commenter then that post hasComments.
            post.hasComments = _.reduce(post.groups[1].refs,
                (is, val) => is || !_.isUndefined(val.item.commenter)
                , false);
            // `fullDetails` is a business logic that can be compiled from other objects.
            post.fullDetails = post.hasComments;
            // special cases for comments.
            post.showUpdate = post.content_updated_date !== post.published_date &&
                               !post.hasComments && post.mainItem.item.item_type !== 'comment';
            angular.forEach(post.items, (val) => {
                if (post.fullDetails) {
                    _completeUser(val.item);
                }
            });
            _completeUser(post.mainItem.item);

            resolve(post);
        });
    }

    function retrievePost(postId) {
        return api.posts.getById(postId)
            .then(_completePost)
            .then((post) => post);
    }

    function retrieveSyndications(posts) {
        const syndIds = [];

        // This means the syndication module is not enabled
        if (!api.hasOwnProperty('syndicationIn')) {
            return posts;
        }

        posts._items.forEach((post) => {
            if (post.syndication_in && syndIds.indexOf(post.syndication_in) === -1) {
                syndIds.push(post.syndication_in);
            }
        });

        return $q
            .all(syndIds.map((syndId) => api.syndicationIn.getById(syndId)))
            .then((syndList) => angular.extend(posts, {
                _items: posts._items.map((post) => {
                    syndList.forEach((synd) => {
                        if (post.syndication_in === synd._id) {
                            post.producer_blog_title = synd.producer_blog_title;
                        }
                    });

                    return post;
                })
            }));
    }

    function retrievePosts(blogId, postsCriteria) {
        return api('blogs/<regex("[a-f0-9]{24}"):blog_id>/posts', {_id: blogId})
            .query(postsCriteria)
            .then(retrieveSyndications)
            .then((data) => $q.all(data._items.map(_completePost))
                .then((result) => angular.extend(data, {_items: result})));
    }

    function getLatestUpdateDate(posts) {
        if (!angular.isDefined(posts) || posts.length < 1) {
            return;
        }
        let latestDate;
        let date;

        posts.forEach((post) => {
            date = moment(post._updated);
            if (angular.isDefined(latestDate)) {
                if (latestDate.diff(date) < 0) {
                    latestDate = date;
                }
            } else {
                latestDate = date;
            }
        });
        return latestDate.utc().format();
    }

    function savePost(blogId, postToUpdate, itemsParam, postParam = {}) {
        const post = postParam;
        let items = itemsParam;

        post.post_status = post.post_status || _.result(postToUpdate, 'post_status') || 'open';
        const dfds = [];

        if (items && items.length > 0) {
            // prepare the list of items if needed
            if (_.difference(_.keys(items[0]), ['residRef', 'item']).length === 0) {
                items = _.map(items, (item) => item.item);
            }
            // save every items
            _.each(items, (itemParam) => {
                let item = {};
                // because it fails when item has a `_id` field without `_links`

                if (angular.isDefined(items, '_id')) {
                    item = {
                        blog: blogId,
                        text: itemParam.text,
                        meta: itemParam.meta,
                        group_type: itemParam.group_type,
                        item_type: itemParam.item_type,
                        commenter: itemParam.meta && itemParam.meta.commenter,
                        syndicated_creator: itemParam.syndicated_creator
                    };
                }
                dfds.push(api.items.save(item));
            });
        }
        // save the post
        return $q.all(dfds).then((items) => {
            if (dfds.length > 0) {
                angular.extend(post, {
                    blog: blogId,
                    groups: [
                        {
                            id: 'root',
                            refs: [{idRef: 'main'}],
                            role: 'grpRole:NEP'
                        }, {
                            id: 'main',
                            refs: [],
                            role: 'grpRole:Main'
                        }
                    ]
                });
                // update the post reference (links with items)
                _.each(items, (item) => {
                    post.groups[1].refs.push({residRef: item._id});
                });
            }
            let operation;

            if (angular.isDefined(postToUpdate)) {
                operation = function updatePost() {
                    return api.posts.save(postToUpdate, post);
                };
            } else {
                operation = function createPost() {
                    return api.posts.save(post);
                };
            }
            // return the post saved
            return operation();
        });
    }

    function removePost(post) {
        const deleted = {deleted: true};

        return savePost(post.blog, post, [], deleted);
    }

    return {
        getPosts: getPosts,
        getLatestUpdateDate: getLatestUpdateDate,
        retrievePost: retrievePost,
        savePost: savePost,
        saveDraft: function(blogId, post, items, sticky, highlight) {
            return savePost(
                blogId,
                post,
                items,
                {post_status: 'draft', sticky: sticky, lb_highlight: highlight}
            );
        },
        saveContribution: function(blogId, post, items, sticky, highlight) {
            return savePost(
                blogId,
                post,
                items,
                {post_status: 'submitted', sticky: sticky, lb_highlight: highlight}
            );
        },
        remove: removePost
    };
}
<|endoftext|>