<commit_before>/**
 * Created by JetBrains WebStorm.
 * User: saar
 * Date: 05/03/12
 * Time: 18:12
 * To change this template use File | Settings | File Templates.
 */

var resources = require('jest'),
    util = require('util'),
    models = require('../models'),
    common = require('./common'),
    async = require('async'),
    notifications = require('./notifications'),
    mail = require('../lib/mail');

var EDIT_TEXT_LEGIT_TIME = 60 * 1000 * 15;


var SuggestionResource = module.exports = common.GamificationMongooseResource.extend({
    init:function () {
        this._super(models.Suggestion, 'suggestion', common.getGamificationTokenPrice('suggestion_on_discussion') > -1 ? common.getGamificationTokenPrice('suggestion') : 0);
        this.allowed_methods = ['get', 'post', 'put'];
        this.authentication = new common.SessionAuthentication();
        this.filtering = {discussion_id:null, is_approved:null};
        this.default_query = function (query) {
            return query.sort({'creation_date':'descending'}).populate('creator_id');
        };

        this.fields = {
            creator_id:common.user_public_fields,
            mandates_curr_user_gave_creator:null,
            parts:null,
            popularity:null,
            tokens:null,
            creation_date:null,
            agrees:null,
            not_agrees:null,
            evaluate_counter:null,
            manual_counter:null,
            grade:null,
            id:null,
            explanation:null,
            updated_user_tokens:null,
            grade_obj:{
                _id:null,
                evaluation_grade:null,
                does_support_the_suggestion:null
            },
            wanted_amount_of_tokens:null,
            curr_amount_of_tokens:null,
            is_editable: null,
            is_my_suggestion: null
        };
    },

    get_objects: function (req, filters, sorts, limit, offset, callback) {
        var self = this;
        var discussion_id = req.query.discussion_id;
        var discussion_threshold;

        var user_id = req.user && req.user._id + "";

        var iterator = function (suggestion, itr_cbk) {
            //set is_my_suggestion flag
            suggestion.is_my_suggestion = (user_id === suggestion.creator_id.id);

            // set is_editable flag if user is the creator and its 15 min after publish
            if (user_id === suggestion.creator_id.id && new Date() - suggestion.creation_date <= EDIT_TEXT_LEGIT_TIME){
                suggestion.is_editable = true;
            }

            //set counter og graders manually
            suggestion.manual_counter = Math.round(suggestion.agrees) + Math.round(suggestion.not_agrees);

            var curr_grade_obj = {};
//            suggestion.grade_obj = curr_grade_obj;

            suggestion.curr_amount_of_tokens = suggestion.agrees - suggestion.not_agrees;

            //wanted amount of tokens is either what admin has entered to the specific suggestion, or the discussion threshold...
            if (suggestion.admin_threshold_for_accepting_the_suggestion > 0)
                suggestion.wanted_amount_of_tokens = suggestion.admin_threshold_for_accepting_the_suggestion;
            else
                suggestion.wanted_amount_of_tokens = Number(suggestion.threshold_for_accepting_the_suggestion) || calculate_sugg_threshold(suggestion.getCharCount(), discussion_threshold);
            if (req.user) {
                models.GradeSuggestion.findOne({user_id:req.user._id, suggestion_id:suggestion._id + ""}, {"_id":1, "evaluation_grade":1, "does_support_the_suggestion":1}, function (err, grade_sugg_obj) {
                    if (!err && grade_sugg_obj) {
                        curr_grade_obj = {
                            _id:grade_sugg_obj._id,
                            evaluation_grade:grade_sugg_obj.evaluation_grade,
                            does_support_the_suggestion:grade_sugg_obj.does_support_the_suggestion
                        }
                        suggestion.grade_obj = curr_grade_obj;
                        itr_cbk(err, suggestion);
                    } else {
                        //check if user is the creator - if so return in grade object the
                        if (!err) {
                            models.Discussion.findById(discussion_id, function (err, discussion) {
                                if (!err)
                                    if (req.user._id + "" == discussion.creator_id + "") {
//                                        suggestion.grade_obj = {};
//                                        suggestion.grade_obj["evaluation_grade"] = discussion.grade;
                                    }
                                itr_cbk(err, suggestion);
                            })
                        } else {
                            itr_cbk(err, suggestion);
                        }
                    }
                });
            }
            else {
                itr_cbk(null, suggestion);
            }
        }

        self._super(req, filters, sorts, limit, offset, function (err, results) {

            if (err)
                callback(err, null);
            else          {

                //arrange objects only if the request is from discussion page
                if (!discussion_id)  {
                    results.objects=results.objects.sort(likelihood) ;
                    callback(err, results);
                }
                else {
                    //for each object add grade_obj that reflects the user's grade for the suggestion,
                    //if the user is the disvcussion creator - grade_obj contains the discussion evaluate grade
                    //if the user is ofline grade_obj is {}

                    async.waterfall([
                        function (cbk) {
                            models.Discussion.findById(discussion_id, cbk);
                        },

                        function (discussion_obj, cbk) {
                            discussion_threshold = discussion_obj.threshold_for_accepting_change_suggestions;
                            discussion_text = discussion_obj.text_field;

                            if (discussion_obj.admin_threshold_for_accepting_change_suggestions > 0){
                                discussion_threshold = discussion_obj.admin_threshold_for_accepting_change_suggestions;
                            }

                            async.forEach(results.objects, iterator, function (err, objs) {
                                cbk(err, results);
                            });
                        }
                    ], function (err, results) {
                        results.objects=results.objects.sort(likelihood) ;
                        callback(err, results);
                    })
                }
            }

        });
    },

    create_obj:function (req, fields, callback) {
        var user_id = req.user.id;
        var self = this;
        var suggestion_object = new self.model();
        var isNewFollower = false;
        var user = req.user;
        var discussion_id = fields.discussion_id;
        var discussion_creator_id;
        var num_of_words;
        var disc_obj;

        var iterator = function (unique_user, itr_cbk) {
            user_id = user_id || user_id.id;

            if (unique_user  == user_id || !unique_user){
                console.log("user should not get mail if he is the notificator");
                itr_cbk(null, 0);
            } else {
                if (discussion_creator_id == unique_user) {
                    notifications.create_user_notification("change_suggestion_on_discussion_you_created", suggestion_object._id, unique_user, user_id, discussion_id, '/discussions/' + discussion_id, function (err, results) {
                        itr_cbk(err, results);
                    });
                } else {
                    notifications.create_user_notification("change_suggestion_on_discussion_you_are_part_of", suggestion_object._id, unique_user, user_id, discussion_id, '/discussions/' + discussion_id, function (err, results) {
                        itr_cbk(err, results);
                    });
                }
            }
        }

        fields.creator_id = user_id;
        fields.first_name = user.first_name;
        fields.last_name = user.last_name;


        for (var field in fields) {
            suggestion_object.set(field, fields[field]);
        }

        //calculate threshold for the suggestion.. for this i need to get discussion threshold first
        async.waterfall([
            //first, check if there is a suggestion with the same indexes
            function (cbk) {
                models.Suggestion.find({discussion_id:fields.discussion_id, is_approved:false}, cbk);
            },

            function (suggestions, cbk) {
                var err;
                var sug;
                var discussion_thresh;

                _.each(suggestions, function (suggestion) {
                    if ((suggestion.parts[0].start >= fields.parts[0].start && suggestion.parts[0].start <= fields.parts[0].end)
                        || (suggestion.parts[0].end >= fields.parts[0].start && suggestion.parts[0].end <= fields.parts[0].end)) {
                        err = true;
                        sug = suggestion._id;
                    }
                })
                if (err){
                    var to = '<EMAIL>';
                    var subject = "הועלתה הצעה לשינוי לטקסט שכבר סומן בדיון";
                    /*var body = "<a href='" + req.app.settings.root_path  +  "'/discussions/" + discussion_id + "#post_" + sug + "'>"
                        + "existing suggestion with same indexes"
                        + "</a>"
                        + "<br>"
                        + "<a href='" + req.app.settings.root_path  +  "'/discussions/" + discussion_id + "#post_" + suggestion_object.id + "'>"
                        + "new suggestion"
                        + "</a>";*/

                    var body = "<a href='uru.org.il/discussions/" + discussion_id + "#post_" + sug + "'>"
                        + "existing suggestion with same indexes"
                        + "</a>"
                        + "<br>"
                        + "<a href='uru.org.il/discussions/" + discussion_id + "#post_" + suggestion_object.id + "'>"
                        + "new suggestion"
                        + "</a>";

                    mail.sendMail(to, body, subject, function(err){
                        if(err) {console.error(err)};
                    })

                    console.error("a suggestion with this indexes already exist");
                }

                models.Discussion.findById(fields.discussion_id, cbk);
            },

            function (discussion_obj, cbk) {
                disc_obj = discussion_obj;

                var word_count = suggestion_object.getCharCount();
                suggestion_object.threshold_for_accepting_the_suggestion = calculate_sugg_threshold(word_count,
                    Number(discussion_obj.admin_threshold_for_accepting_change_suggestions) || Number(discussion_obj.threshold_for_accepting_change_suggestions));
                self.authorization.edit_object(req, suggestion_object, cbk);
            },

            function (suggestion_obj, cbk) {
                suggestion_object.save(function (err, data) {
                    if (data) {
                        discussion_id = data.discussion_id;
                        data.creator_id.id = user.id;
                        data.creator_id.first_name = user.first_name;
                        data.creator_id.last_name = user.last_name;
                        data.creator_id.avatar_url = user.avatar_url();
                        data.creator_id.score = user.score;
                        data.creator_id.num_of_given_mandates = user.num_of_given_mandates;
                        data.creator_id.num_of_proxies_i_represent = user.num_of_proxies_i_represent;
                        suggestion_obj.wanted_amount_of_tokens = suggestion_obj.threshold_for_accepting_the_suggestion;
                    }
                    cbk(err, data);
                });
            },

            function (suggestion_obj, cbk) {
                async.parallel([

                    //add user that connected somehow to discussion
                    function(cbk2){
                        models.Discussion.update({_id: disc_obj._id, "users.user_id": {$ne: user_id}},
                            {$addToSet: {users: {user_id: user_id, join_date: Date.now(), $set:{last_updated: Date.now()}}}}, function(err, num){
                                cbk2(err);
                            });
                    },

                    //add user that connected somehow to discussion
                    function(cbk2)
                    {
                        models.User.update({_id: user_id, "discussions.discussion_id": {$ne: disc_obj._id}},
                            {$addToSet: {discussions: {discussion_id:  disc_obj._id, join_date: Date.now()}}}, function(err, num){
                                cbk2(err);
                            });
                    },

                    //add notification for the dicussion's participants or creator
                    function (cbk2) {
                        var unique_users = [];

                        discussion_creator_id = disc_obj.creator_id;

                        // be sure that there are no duplicated users in discussion.users
                        _.each(disc_obj.users, function(user){ unique_users.push(user.user_id + "")});
                        unique_users = _.uniq(unique_users);

                        async.forEach(unique_users, iterator, function(err){
                            cbk2(err);
                        });
                    },

                    //set notifications for users that i represent (proxy)
                    function (cbk2) {
                        models.User.find({"proxy.user_id":user_id}, function (err, slaves_users) {
                            async.forEach(slaves_users, function (slave, itr_cbk) {
                                notifications.create_user_notification("proxy_created_change_suggestion", suggestion_obj._id, slave._id, user_id, discussion_id, '/discussions/' + discussion_id, function (err, result) {
                                    itr_cbk(err);
                                })
                            }, function (err) {
                                cbk2(err);
                            })
                        })

                    },

                    // update actions done by user
                    function(cbk2){
                        models.User.update({_id:user.id},{$set: {"actions_done_by_user.suggestion_on_object": true}}, function(err){
                            cbk2(err);
                        });<commit_msg>fix bug# 79 להשבית את הפופ אפ "הטקסט סומן בהצעה לשינוי קיימת<commit_after>/**
 * Created by JetBrains WebStorm.
 * User: saar
 * Date: 05/03/12
 * Time: 18:12
 * To change this template use File | Settings | File Templates.
 */

var resources = require('jest'),
    util = require('util'),
    models = require('../models'),
    common = require('./common'),
    async = require('async'),
    notifications = require('./notifications'),
    mail = require('../lib/mail');

var EDIT_TEXT_LEGIT_TIME = 60 * 1000 * 15;


var SuggestionResource = module.exports = common.GamificationMongooseResource.extend({
    init:function () {
        this._super(models.Suggestion, 'suggestion', common.getGamificationTokenPrice('suggestion_on_discussion') > -1 ? common.getGamificationTokenPrice('suggestion') : 0);
        this.allowed_methods = ['get', 'post', 'put'];
        this.authentication = new common.SessionAuthentication();
        this.filtering = {discussion_id:null, is_approved:null};
        this.default_query = function (query) {
            return query.sort({'creation_date':'descending'}).populate('creator_id');
        };

        this.fields = {
            creator_id:common.user_public_fields,
            mandates_curr_user_gave_creator:null,
            parts:null,
            popularity:null,
            tokens:null,
            creation_date:null,
            agrees:null,
            not_agrees:null,
            evaluate_counter:null,
            manual_counter:null,
            grade:null,
            id:null,
            explanation:null,
            updated_user_tokens:null,
            grade_obj:{
                _id:null,
                evaluation_grade:null,
                does_support_the_suggestion:null
            },
            wanted_amount_of_tokens:null,
            curr_amount_of_tokens:null,
            is_editable: null,
            is_my_suggestion: null
        };
    },

    get_objects: function (req, filters, sorts, limit, offset, callback) {
        var self = this;
        var discussion_id = req.query.discussion_id;
        var discussion_threshold;

        var user_id = req.user && req.user._id + "";

        var iterator = function (suggestion, itr_cbk) {
            //set is_my_suggestion flag
            suggestion.is_my_suggestion = (user_id === suggestion.creator_id.id);

            // set is_editable flag if user is the creator and its 15 min after publish
            if (user_id === suggestion.creator_id.id && new Date() - suggestion.creation_date <= EDIT_TEXT_LEGIT_TIME){
                suggestion.is_editable = true;
            }

            //set counter og graders manually
            suggestion.manual_counter = Math.round(suggestion.agrees) + Math.round(suggestion.not_agrees);

            var curr_grade_obj = {};
//            suggestion.grade_obj = curr_grade_obj;

            suggestion.curr_amount_of_tokens = suggestion.agrees - suggestion.not_agrees;

            //wanted amount of tokens is either what admin has entered to the specific suggestion, or the discussion threshold...
            if (suggestion.admin_threshold_for_accepting_the_suggestion > 0)
                suggestion.wanted_amount_of_tokens = suggestion.admin_threshold_for_accepting_the_suggestion;
            else
                suggestion.wanted_amount_of_tokens = Number(suggestion.threshold_for_accepting_the_suggestion) || calculate_sugg_threshold(suggestion.getCharCount(), discussion_threshold);
            if (req.user) {
                models.GradeSuggestion.findOne({user_id:req.user._id, suggestion_id:suggestion._id + ""}, {"_id":1, "evaluation_grade":1, "does_support_the_suggestion":1}, function (err, grade_sugg_obj) {
                    if (!err && grade_sugg_obj) {
                        curr_grade_obj = {
                            _id:grade_sugg_obj._id,
                            evaluation_grade:grade_sugg_obj.evaluation_grade,
                            does_support_the_suggestion:grade_sugg_obj.does_support_the_suggestion
                        }
                        suggestion.grade_obj = curr_grade_obj;
                        itr_cbk(err, suggestion);
                    } else {
                        //check if user is the creator - if so return in grade object the
                        if (!err) {
                            models.Discussion.findById(discussion_id, function (err, discussion) {
                                if (!err)
                                    if (req.user._id + "" == discussion.creator_id + "") {
//                                        suggestion.grade_obj = {};
//                                        suggestion.grade_obj["evaluation_grade"] = discussion.grade;
                                    }
                                itr_cbk(err, suggestion);
                            })
                        } else {
                            itr_cbk(err, suggestion);
                        }
                    }
                });
            }
            else {
                itr_cbk(null, suggestion);
            }
        }

        self._super(req, filters, sorts, limit, offset, function (err, results) {

            if (err)
                callback(err, null);
            else          {

                //arrange objects only if the request is from discussion page
                if (!discussion_id)  {
                    results.objects=results.objects.sort(likelihood) ;
                    callback(err, results);
                }
                else {
                    //for each object add grade_obj that reflects the user's grade for the suggestion,
                    //if the user is the disvcussion creator - grade_obj contains the discussion evaluate grade
                    //if the user is ofline grade_obj is {}

                    async.waterfall([
                        function (cbk) {
                            models.Discussion.findById(discussion_id, cbk);
                        },

                        function (discussion_obj, cbk) {
                            discussion_threshold = discussion_obj.threshold_for_accepting_change_suggestions;
                            discussion_text = discussion_obj.text_field;

                            if (discussion_obj.admin_threshold_for_accepting_change_suggestions > 0){
                                discussion_threshold = discussion_obj.admin_threshold_for_accepting_change_suggestions;
                            }

                            async.forEach(results.objects, iterator, function (err, objs) {
                                cbk(err, results);
                            });
                        }
                    ], function (err, results) {
                        results.objects=results.objects.sort(likelihood) ;
                        callback(err, results);
                    })
                }
            }

        });
    },

    create_obj:function (req, fields, callback) {
        var user_id = req.user.id;
        var self = this;
        var suggestion_object = new self.model();
        var isNewFollower = false;
        var user = req.user;
        var discussion_id = fields.discussion_id;
        var discussion_creator_id;
        var num_of_words;
        var disc_obj;

        var iterator = function (unique_user, itr_cbk) {
            user_id = user_id || user_id.id;

            if (unique_user  == user_id || !unique_user){
                console.log("user should not get mail if he is the notificator");
                itr_cbk(null, 0);
            } else {
                if (discussion_creator_id == unique_user) {
                    notifications.create_user_notification("change_suggestion_on_discussion_you_created", suggestion_object._id, unique_user, user_id, discussion_id, '/discussions/' + discussion_id, function (err, results) {
                        itr_cbk(err, results);
                    });
                } else {
                    notifications.create_user_notification("change_suggestion_on_discussion_you_are_part_of", suggestion_object._id, unique_user, user_id, discussion_id, '/discussions/' + discussion_id, function (err, results) {
                        itr_cbk(err, results);
                    });
                }
            }
        }

        fields.creator_id = user_id;
        fields.first_name = user.first_name;
        fields.last_name = user.last_name;


        for (var field in fields) {
            suggestion_object.set(field, fields[field]);
        }

        //calculate threshold for the suggestion.. for this i need to get discussion threshold first
        async.waterfall([
            //first, check if there is a suggestion with the same indexes
            function (cbk) {
                models.Suggestion.find({discussion_id:fields.discussion_id, is_approved:false}, cbk);
            },

            function (suggestions, cbk) {
                var err;
                var sug;
                var discussion_thresh;

                _.each(suggestions, function (suggestion) {
                    if ((suggestion.parts[0].start >= fields.parts[0].start && suggestion.parts[0].start <= fields.parts[0].end)
                        || (suggestion.parts[0].end >= fields.parts[0].start && suggestion.parts[0].end <= fields.parts[0].end)) {
                        err = true;
                        sug = suggestion._id;
                    }
                })
                if (err){
                    var to = '<EMAIL>';
                    var subject = "הועלתה הצעה לשינוי לטקסט שכבר סומן בדיון";
                    /*var body = "<a href='" + req.app.settings.root_path  +  "'/discussions/" + discussion_id + "#post_" + sug + "'>"
                        + "existing suggestion with same indexes"
                        + "</a>"
                        + "<br>"
                        + "<a href='" + req.app.settings.root_path  +  "'/discussions/" + discussion_id + "#post_" + suggestion_object.id + "'>"
                        + "new suggestion"
                        + "</a>";*/

                    var body = "<a href='uru.org.il/discussions/" + discussion_id + "#post_" + sug + "'>"
                        + "existing suggestion with same indexes"
                        + "</a>"
                        + "<br>"
                        + "<a href='uru.org.il/discussions/" + discussion_id + "#post_" + suggestion_object.id + "'>"
                        + "new suggestion"
                        + "</a>";

                    mail.sendMail(to, body, subject, function(err){
                        if(err) {console.error(err)};
                    })

                    console.error("a suggestion with this indexes already exist");
                }

                models.Discussion.findById(fields.discussion_id, cbk);
            },

            function (discussion_obj, cbk) {
                disc_obj = discussion_obj;

                var word_count = suggestion_object.getCharCount();
                suggestion_object.threshold_for_accepting_the_suggestion = calculate_sugg_threshold(word_count,
                    Number(discussion_obj.admin_threshold_for_accepting_change_suggestions) || Number(discussion_obj.threshold_for_accepting_change_suggestions));
                self.authorization.edit_object(req, suggestion_object, cbk);
            },

            function (suggestion_obj, cbk) {
                suggestion_object.save(function (err, data) {
                    if (data) {
                        discussion_id = data.discussion_id;
                        data.creator_id.id = user.id;
                        data.creator_id.first_name = user.first_name;
                        data.creator_id.last_name = user.last_name;
                        data.creator_id.avatar_url = user.avatar_url();
                        data.creator_id.score = user.score;
                        data.creator_id.num_of_given_mandates = user.num_of_given_mandates;
                        data.creator_id.num_of_proxies_i_represent = user.num_of_proxies_i_represent;
                        suggestion_obj.wanted_amount_of_tokens = suggestion_obj.threshold_for_accepting_the_suggestion;
                    }
                    cbk(err, data);
                });
            },

            function (suggestion_obj, cbk) {
                async.parallel([

                    //add user that connected somehow to discussion
                    function(cbk2){
                        models.Discussion.update({_id: disc_obj._id, "users.user_id": {$ne: user_id}},
                            {$addToSet: {users: {user_id: user_id, join_date: Date.now(), $set:{last_updated: Date.now()}}}}, function(err, num){
                                cbk2(err);
                            });
                    },

                    //add user that connected somehow to discussion
                    function(cbk2)
                    {
                        models.User.update({_id: user_id, "discussions.discussion_id": {$ne: disc_obj._id}},
                            {$addToSet: {discussions: {discussion_id:  disc_obj._id, join_date: Date.now()}}}, function(err, num){
                                cbk2(err);
                            });
                    },

                    //add notification for the dicussion's participants or creator
                    function (cbk2) {
                        var unique_users = [];

                        discussion_creator_id = disc_obj.creator_id;

                        // be sure that there are no duplicated users in discussion.users
                        _.each(disc_obj.users, function(user){ unique_users.push(user.id || user.user_id + "")});
                        unique_users = _.uniq(unique_users);

                        async.forEach(unique_users, iterator, function(err){
                            cbk2(err);
                        });
                    },

                    //set notifications for users that i represent (proxy)
                    function (cbk2) {
                        models.User.find({"proxy.user_id":user_id}, function (err, slaves_users) {
                            async.forEach(slaves_users, function (slave, itr_cbk) {
                                notifications.create_user_notification("proxy_created_change_suggestion", suggestion_obj._id, slave._id, user_id, discussion_id, '/discussions/' + discussion_id, function (err, result) {
                                    itr_cbk(err);
                                })
                            }, function (err) {
                                cbk2(err);
                            })
                        })

                    },

                    // update actions done by user
                    function(cbk2){
                        models.User.update({_id:user.id},{$set: {"actions_done_by_user.suggestion_on_object": true}}, function(err){
                            cbk2(err);
                        });
{'fraction_non_alphanumeric': 0.0941383664517844, 'fraction_numerical': 0.00312354622183824, 'mean_word_length': 1.4370394363916106, 'pattern_counts': {'":': 14, '<': 31, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2194701', 'n_tokens_mistral': 8056, 'n_tokens_neox': 7465, 'n_words': 1480}