<commit_before>/*
 * Copyright (c) 2015 Kagilum SAS.
 *
 * This file is part of iceScrum.
 *
 * iceScrum is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License.
 *
 * iceScrum is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with iceScrum.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors:
 *
 * <NAME> (<EMAIL>)
 * <NAME> (<EMAIL>)
 *
 */

controllers.controller('sprintCtrl', ['$scope', '$q', 'Session', 'SprintService', 'SprintStatesByName', 'StoryService', 'StoryStatesByName', function($scope, $q, Session, SprintService, SprintStatesByName, StoryService, StoryStatesByName) {
    // Functions
    $scope.showSprintMenu = function() {
        return Session.poOrSm();
    };
    $scope.authorizedSprint = function(action, sprint) {
        return SprintService.authorizedSprint(action, sprint);
    };
    $scope.activate = function(sprint) {
        SprintService.activate(sprint, $scope.project).then(function() {
            $scope.notifySuccess('todo.is.ui.sprint.activated');
        });
    };
    $scope.autoPlan = function(sprint, capacity) {
        SprintService.autoPlan(sprint, capacity, $scope.project).then(function() {
            $scope.notifySuccess('todo.is.ui.sprint.autoPlanned');
        });
    };
    $scope.unPlan = function(sprint) {
        SprintService.unPlan(sprint, $scope.project).then(function() {
            $scope.notifySuccess('todo.is.ui.sprint.unPlanned');
        });
    };
    $scope['delete'] = function(sprint) {
        SprintService.delete(sprint, $scope.release).then(function() {
            $scope.notifySuccess('todo.is.ui.deleted');
        });
    };
    $scope.openCloseModal = function(sprint) {
        var project = $scope.project;
        $scope.openStorySelectorModal({
            code: 'close',
            order: 'rank',
            filter: {
                parentSprint: sprint.id
            },
            initSelectedIds: function(stories) {
                return _.chain(stories).filter({state: StoryStatesByName.DONE}).map('id').value();
            },
            submit: function(wannaBeDone, stories) {
                var storyIdsByDone = _.chain(stories).groupBy(function(story) {
                    return story.state == StoryStatesByName.DONE;
                }).mapValues(function(stories) {
                    return _.map(stories, 'id');
                }).value();
                var alreadyDone = storyIdsByDone[true];
                var toBeDone = _.difference(wannaBeDone, alreadyDone);
                var alreadyUndone = storyIdsByDone[false];
                var wannabeUndone = _.difference(_.map(stories, 'id'), wannaBeDone);
                var toBeUndone = _.difference(wannabeUndone, alreadyUndone);
                var promise = $q.when();
                if (toBeUndone.length) {
                    promise = promise.then(function() {
                        return toBeUndone.length > 1 ? StoryService.unDoneMultiple(toBeUndone) : StoryService.unDone({id: toBeUndone[0]});
                    });
                }
                if (toBeDone.length) {
                    promise = promise.then(function() {
                        return toBeDone.length > 1 ? StoryService.doneMultiple(toBeDone) : StoryService.done({id: toBeDone[0]});
                    });
                }
                return promise.then(function() {
                    SprintService.close(sprint, project).then(function() {
                        $scope.notifySuccess('todo.is.ui.sprint.closed');
                    });
                });
            }
        });
    };
    $scope.openPlanModal = function(sprint) {
        $scope.openStorySelectorModal({
            code: 'plan',
            order: 'rank',
            inputFilterEnabled: true,
            filter: {
                state: StoryStatesByName.ESTIMATED
            },
            submit: function(selectedIds) {
                if (selectedIds.length > 0) {
                    // Will refresh sprint.stories which will in turn refresh sprint backlog stories through the watch
                    return StoryService.updateMultiple(selectedIds, {parentSprint: sprint}).then(function() {
                        $scope.notifySuccess('todo.is.ui.story.multiple.updated');
                    });
                } else {
                    return $q.when();
                }
            }
        });
    };
    $scope.menus = [
        {
            name: 'todo.is.ui.story.plan',
            visible: function(sprint) { return $scope.authorizedSprint('plan', sprint); },
            action: function(sprint) { $scope.openPlanModal(sprint); }
        },
        {
            name: 'is.ui.releasePlan.menu.sprint.activate',
            visible: function(sprint) { return $scope.authorizedSprint('activate', sprint); },
            priority: function(sprint, defaultPriority) { return sprint.state === 1 && (sprint.stories_ids.length > 0 || sprint.startDate.getTime() < (new Date()).getTime()) ? 100 : defaultPriority; },
            action: function(sprint) { $scope.confirm({message: $scope.message('is.ui.releasePlan.menu.sprint.activate.confirm'), callback: $scope.activate, args: [sprint]}); }
        },
        {
            name: 'is.ui.releasePlan.menu.sprint.close',
            priority: function(sprint, defaultPriority, viewType) { return sprint.state === 2 && viewType === 'details' ? 120 : (sprint.state === 2 ? 100 : defaultPriority); },
            visible: function(sprint) { return $scope.authorizedSprint('close', sprint); },
            action: function(sprint) { $scope.openCloseModal(sprint); }
        },
        {
            name: 'todo.is.ui.taskBoard',
            visible: function(sprint, viewType) { return viewType !== 'taskBoard'; },
            priority: function(sprint, defaultPriority, viewType) { return viewType !== 'taskBoard' && sprint.state === 2 && sprint.endDate.getTime() > (new Date()).getTime()  ? 110 : defaultPriority; },
            url: function(sprint) { return '#taskBoard/' + sprint.id + '/details'; }
        },
        {
            name: 'is.ui.releasePlan.toolbar.autoPlan',
            visible: function(sprint) { return $scope.authorizedSprint('autoPlan', sprint); },
            action: function(sprint) { $scope.showAutoPlanModal({callback: $scope.autoPlan, args: [sprint]}); }
        },
        {<commit_msg>Fix no sprint action in details just after creating a sprint<commit_after>/*
 * Copyright (c) 2015 Kagilum SAS.
 *
 * This file is part of iceScrum.
 *
 * iceScrum is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License.
 *
 * iceScrum is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with iceScrum.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors:
 *
 * <NAME> (<EMAIL>)
 * <NAME> (<EMAIL>)
 *
 */

controllers.controller('sprintCtrl', ['$scope', '$q', 'Session', 'SprintService', 'SprintStatesByName', 'StoryService', 'StoryStatesByName', function($scope, $q, Session, SprintService, SprintStatesByName, StoryService, StoryStatesByName) {
    // Functions
    $scope.showSprintMenu = function() {
        return Session.poOrSm();
    };
    $scope.authorizedSprint = function(action, sprint) {
        return SprintService.authorizedSprint(action, sprint);
    };
    $scope.activate = function(sprint) {
        SprintService.activate(sprint, $scope.project).then(function() {
            $scope.notifySuccess('todo.is.ui.sprint.activated');
        });
    };
    $scope.autoPlan = function(sprint, capacity) {
        SprintService.autoPlan(sprint, capacity, $scope.project).then(function() {
            $scope.notifySuccess('todo.is.ui.sprint.autoPlanned');
        });
    };
    $scope.unPlan = function(sprint) {
        SprintService.unPlan(sprint, $scope.project).then(function() {
            $scope.notifySuccess('todo.is.ui.sprint.unPlanned');
        });
    };
    $scope['delete'] = function(sprint) {
        SprintService.delete(sprint, $scope.release).then(function() {
            $scope.notifySuccess('todo.is.ui.deleted');
        });
    };
    $scope.openCloseModal = function(sprint) {
        var project = $scope.project;
        $scope.openStorySelectorModal({
            code: 'close',
            order: 'rank',
            filter: {
                parentSprint: sprint.id
            },
            initSelectedIds: function(stories) {
                return _.chain(stories).filter({state: StoryStatesByName.DONE}).map('id').value();
            },
            submit: function(wannaBeDone, stories) {
                var storyIdsByDone = _.chain(stories).groupBy(function(story) {
                    return story.state == StoryStatesByName.DONE;
                }).mapValues(function(stories) {
                    return _.map(stories, 'id');
                }).value();
                var alreadyDone = storyIdsByDone[true];
                var toBeDone = _.difference(wannaBeDone, alreadyDone);
                var alreadyUndone = storyIdsByDone[false];
                var wannabeUndone = _.difference(_.map(stories, 'id'), wannaBeDone);
                var toBeUndone = _.difference(wannabeUndone, alreadyUndone);
                var promise = $q.when();
                if (toBeUndone.length) {
                    promise = promise.then(function() {
                        return toBeUndone.length > 1 ? StoryService.unDoneMultiple(toBeUndone) : StoryService.unDone({id: toBeUndone[0]});
                    });
                }
                if (toBeDone.length) {
                    promise = promise.then(function() {
                        return toBeDone.length > 1 ? StoryService.doneMultiple(toBeDone) : StoryService.done({id: toBeDone[0]});
                    });
                }
                return promise.then(function() {
                    SprintService.close(sprint, project).then(function() {
                        $scope.notifySuccess('todo.is.ui.sprint.closed');
                    });
                });
            }
        });
    };
    $scope.openPlanModal = function(sprint) {
        $scope.openStorySelectorModal({
            code: 'plan',
            order: 'rank',
            inputFilterEnabled: true,
            filter: {
                state: StoryStatesByName.ESTIMATED
            },
            submit: function(selectedIds) {
                if (selectedIds.length > 0) {
                    // Will refresh sprint.stories which will in turn refresh sprint backlog stories through the watch
                    return StoryService.updateMultiple(selectedIds, {parentSprint: sprint}).then(function() {
                        $scope.notifySuccess('todo.is.ui.story.multiple.updated');
                    });
                } else {
                    return $q.when();
                }
            }
        });
    };
    $scope.menus = [
        {
            name: 'todo.is.ui.story.plan',
            visible: function(sprint) { return $scope.authorizedSprint('plan', sprint); },
            action: function(sprint) { $scope.openPlanModal(sprint); }
        },
        {
            name: 'is.ui.releasePlan.menu.sprint.activate',
            visible: function(sprint) { return $scope.authorizedSprint('activate', sprint); },
            priority: function(sprint, defaultPriority) { return sprint.state === 1 && (sprint.stories_ids && sprint.stories_ids.length > 0 || sprint.startDate.getTime() < (new Date()).getTime()) ? 100 : defaultPriority; },
            action: function(sprint) { $scope.confirm({message: $scope.message('is.ui.releasePlan.menu.sprint.activate.confirm'), callback: $scope.activate, args: [sprint]}); }
        },
        {
            name: 'is.ui.releasePlan.menu.sprint.close',
            priority: function(sprint, defaultPriority, viewType) { return sprint.state === 2 && viewType === 'details' ? 120 : (sprint.state === 2 ? 100 : defaultPriority); },
            visible: function(sprint) { return $scope.authorizedSprint('close', sprint); },
            action: function(sprint) { $scope.openCloseModal(sprint); }
        },
        {
            name: 'todo.is.ui.taskBoard',
            visible: function(sprint, viewType) { return viewType !== 'taskBoard'; },
            priority: function(sprint, defaultPriority, viewType) { return viewType !== 'taskBoard' && sprint.state === 2 && sprint.endDate.getTime() > (new Date()).getTime()  ? 110 : defaultPriority; },
            url: function(sprint) { return '#taskBoard/' + sprint.id + '/details'; }
        },
        {
            name: 'is.ui.releasePlan.toolbar.autoPlan',
            visible: function(sprint) { return $scope.authorizedSprint('autoPlan', sprint); },
            action: function(sprint) { $scope.showAutoPlanModal({callback: $scope.autoPlan, args: [sprint]}); }
        },
        {
{'fraction_non_alphanumeric': 0.1319531422677374, 'fraction_numerical': 0.003978486701539822, 'mean_word_length': 2.167055529631358, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1919619', 'n_tokens_mistral': 3784, 'n_tokens_neox': 3647, 'n_words': 767}