<commit_before>/**
 * /api/services/TaskboardInitService.js
 *
 * Taskboard init service. This is called only from config/bootstrap.js file on lifting sails.
 */
"use strict";

var async = require("async");

/**
 * Main taskboard app initialize method. Basically this will do following jobs:
 *
 *  - Create admin user, if he/she doesn't exists
 *  - Task types, if those doesn't exists already
 *
 * Each of these jobs are done in separate TaskboardInitService methods.
 *
 * @param   {Function}  next    Callback function that must be called after all jobs.
 */
exports.init = function(next) {
    // Call all necessary init jobs parallel
    async.parallel(
        {
            // Create admin user account
            admin: function(callback) {
                TaskboardInitService.createAdmin(callback);
            },

            // Create default task types
            types: function(callback) {
                TaskboardInitService.createTypes(callback);
            }
        },

        /**
         * Callback function which is been called after all parallel jobs are processed.
         *
         * @param   {Error} error
         * @param   {{}}    results
         */
        function(error, results) {
            next(error);
        }
    );
};

/**
 * This method creates admin user to database if it doesn't exists already.
 *
 * @param   {Function}  next    Callback function to call after jobs
 */
exports.createAdmin = function(next) {
    User
        .findOne({username: "admin"})
        .done(function(error, user) {
            if (error) {
                next(error, null);
            } else if (!user) {
                User
                    .create({
                        username: "admin",
                        firstName: "John",
                        lastName: "Doe",
                        email: "<EMAIL>",
                        admin: true,
                        password: "<PASSWORD>"
                    })
                    .done(function(error, user) {
                        next(error, user);
                    });
            } else {
                next(null, true);
            }
        });
};

/**
 * This method creates admin user to database if it doesn't exists already.
 *
 * @param   {Function}  next    Callback function to call after jobs
 */
exports.createTypes = function(next) {
    Type
        .find()
        .done(function(error, types) {
            if (error) {
                next(error, null);
            } else if (_.size(types) === 0) {
                // Specify "default" type data
                var defaultTypes = [
                    {title: "Task", order: "1", class: "alert alert-warning", classText: "text-warning"},
                    {title: "Test", order: "2", class: "alert alert-success", classText: "text-success"},
                    {title: "Bug",  order: "3", class: "alert alert-danger",  classText: "text-danger"}
                ];

                // Create default types and pass those to callback function
                async.map(
                    defaultTypes,
                    function(type, callback) {
                        Type
                            .create(type)
                            .done(function(error, type) {
                                callback(error, type);
                            });
                    },
                    function(error, types) {
                        next(error, types)
                    }
                )
            } else {
                next(null, types);
            }
        });
};<commit_msg>Implemented demo project initializing in "sails lift" if any project doesn't exists.<commit_after>/**
 * /api/services/TaskboardInitService.js
 *
 * Taskboard init service. This is called only from config/bootstrap.js file on lifting sails.
 */
"use strict";

var async = require("async");
var moment = require("moment-timezone");

/**
 * Main taskboard app initialize method. Basically this will do following jobs:
 *
 *  - Create admin user, if he/she doesn't exists
 *  - Task types, if those doesn't exists already
 *  - Demo project, if no projects on database
 *
 * Each of these jobs are done in separate TaskboardInitService methods.
 *
 * @param   {Function}  next    Callback function that must be called after all jobs.
 */
exports.init = function(next) {
    // Call all necessary init jobs parallel
    async.parallel(
        {
            // Create admin user account
            admin: function(callback) {
                TaskboardInitService.createAdmin(callback);
            },

            // Create default task types
            types: function(callback) {
                TaskboardInitService.createTypes(callback);
            }
        },

        /**
         * Callback function which is been called after all parallel jobs are processed.
         *
         * @param   {Error} error
         * @param   {{}}    results
         */
        function(error, results) {
            if (error) {
                next(error, null);
            } else {
                // Create demo project if none exists
                TaskboardInitService.initDemoProject(results, next);
            }
        }
    );
};

/**
 * This method creates admin user to database if it doesn't exists already.
 *
 * @param   {Function}  next    Callback function to call after jobs
 */
exports.createAdmin = function(next) {
    User
        .findOne({username: "admin"})
        .done(function(error, user) {
            if (error) {
                next(error, null);
            } else if (!user) {
                // Create admin user with default data
                User
                    .create({
                        username: "admin",
                        firstName: "John",
                        lastName: "Doe",
                        email: "<EMAIL>",
                        admin: true,
                        password: "<PASSWORD>"
                    })
                    .done(function(error, user) {
                        next(error, user);
                    });
            } else {
                next(null, user);
            }
        });
};

/**
 * This method creates admin user to database if it doesn't exists already.
 *
 * @param   {Function}  next    Callback function to call after jobs
 */
exports.createTypes = function(next) {
    Type
        .find()
        .done(function(error, types) {
            if (error) {
                next(error, null);
            } else if (_.size(types) === 0) {
                // Specify "default" type data
                var defaultTypes = [
                    {title: "Task", order: "1", class: "alert alert-warning", classText: "text-warning"},
                    {title: "Test", order: "2", class: "alert alert-success", classText: "text-success"},
                    {title: "Bug",  order: "3", class: "alert alert-danger",  classText: "text-danger"}
                ];

                // Create default types and pass those to callback function
                async.map(
                    defaultTypes,
                    function(type, callback) {
                        Type
                            .create(type)
                            .done(function(error, type) {
                                callback(error, type);
                            });
                    },
                    function(error, types) {
                        next(error, types)
                    }
                )
            } else {
                next(null, types);
            }
        });
};

/**
 * This method creates demo project to database. Note that this project is
 * created only if any project doesn't exist in database yet.
 *
 * @param   {{}}        data    Object that contains following data:
 *                               - admin, user object
 *                               - types, array of task type objects
 * @param   {Function}  next    Callback function that must be called after demo project init.
 */
exports.initDemoProject = function(data, next) {
    async.waterfall(
        [
            // Create project
            function(callback) {
                TaskboardInitService.createProject(data, callback);
            },

            // Create phases for project
            function (project, callback) {
                if (!project) {
                    callback(null, null, null);
                } else {
                    TaskboardInitService.createPhases(project, callback);
                }
            },

            // Create sprints
            function(project, phases, callback) {
                if (!project) {
                    callback(null, null, null, null);
                } else {
                    TaskboardInitService.createSprint(project, phases, callback);
                }
            },

            // Create stories
            function(project, phases, sprint, callback) {
                if (!project) {
                    callback(null, null, null, null, null);
                } else {
                    TaskboardInitService.createStories(data, project, phases, sprint, callback);
                }
            },

            // Create tasks
            function(project, phases, sprint, stories, callback) {
                if (!project) {
                    callback(null, null, null, null, null, null);
                } else {
                    TaskboardInitService.createTasks(data, project, phases, sprint, stories, callback);
                }
            }
        ],

        /**
         * Callback function which is been called after all specified jobs are processed.
         *
         * @param   {Error|String}              error
         * @param   {Null|sails.model.project}  project Project object
         * @param   {Null|sails.model.phase[]}  phases  Phase objects as an array
         * @param   {Null|sails.model.sprint}   sprint  Sprint object
         * @param   {Null|sails.model.story[]}  stories Story objects as an array
         * @param   {Null|sails.model.task[]}   tasks   Task objects as an array
         */
        function(error, project, phases, sprint, stories, tasks) {
            var output = {
                project: project,
                phases: phases,
                sprint: sprint,
                stories: stories,
                tasks: tasks
            };

            next(error);
        }
    );
};

/**
 * This method creates a demo project to taskboard if none exists in database.
 *
 * @param   {{}}        data    Object that contains following data:
 *                               - admin, user object
 *                               - types, array of task type objects
 * @param   {Function}  next    Callback function to call after job is finished
 */
exports.createProject = function(data, next) {
    Project
        .find()
        .done(function(error, projects) {
            if (error) {
                next(error, null);
            } else if (_.size(projects) === 0) { // No project(s) found create demo project
                // Specify demo project data
                var projectData = {
                    managerId: data.admin.id,
                    title: "Demo project",
                    description: "This is a demo project, which is created automatic if any other projects doesn't exists yet.",
                    dateStart: moment().format("YYYY-MM-DD"),
                    dateEnd: moment().add("years", 1).format("YYYY-MM-DD")
                };

                // Create demo project
                Project
                    .create(projectData)
                    .done(function(error, project) {
                        if (error) {
                            console.log(projectData);
                            console.log(error);
                        } else {
                            next(error, project);

                        }
                    });
            } else { // Database contains projects so skip demo project init
                next(null, null);
            }
        });
};

/**
 * This method creates phases for specified project.
 *
 * @param   {sails.model.project}   project Project object
 * @param   {Function}              next    Callback function to call after job is finished
 */
exports.createPhases = function(project, next) {
    // Specify project phase data
    var phaseData = [
        {projectId: project.id, title: "Tasks",      order: 1, tasks: 0, isDone: false},
        {projectId: project.id, title: "In process", order: 2, tasks: 3, isDone: false},
        {projectId: project.id, title: "To review",  order: 3, tasks: 3, isDone: false},
        {projectId: project.id, title: "Reviewed",   order: 4, tasks: 6, isDone: false},
        {projectId: project.id, title: "Done",       order: 5, tasks: 0, isDone: true}
    ];

    // Create specified phases
    async.map(
        phaseData,
        function(story, callback) {
            Phase
                .create(story)
                .done(function(error, story) {
                    callback(error, story);
                });
        },
        function(error, phases) {
            next(error, project, phases);
        }
    );
};

/**
 * This method creates sprints for specified demo project.
 *
 * @param   {sails.model.project}   project Project object
 * @param   {sails.model.phase[]}   phases  Array of phase objects
 * @param   {Function}              next    Callback function to call after job is finished
 */
exports.createSprint = function(project, phases, next) {
    // Specify sprint data
    var sprintData = {
        projectId: project.id,
        title: "First sprint",
        description: "This is a first sprint in demo project.",
        dateStart: moment(project.dateStart).format("YYYY-MM-DD"),
        dateEnd: moment(project.dateStart).add("days", 30).format("YYYY-MM-DD")
    };

    // Create new sprint
    Sprint
        .create(sprintData)
        .done(function(error, sprint) {
            next(error, project, phases, sprint);
        });
};

/**
 * Method creates stories to default stories to demo project and assign those to
 * specified demo sprint and project backlog.
 *
 * @param   {{}}                    data    Object that contains following data:
 *                                           - admin, user object
 *                                           - types, array of task type objects
 * @param   {sails.model.project}   project Project object
 * @param   {sails.model.phase[]}   phases  Array of phase objects
 * @param   {sails.model.sprint}    sprint  Sprint object
 * @param   {Function}              next    Callback function to call after job is finished
 */
exports.createStories = function(data, project, phases, sprint, next) {
    var typeTask = _.find(data.types, function(type) { return type.title === "Task"; });

    // Specify story data
    var storyData = [
        {
            projectId: project.id,
            sprintId: sprint.id,
            milestoneId: 0,
            typeId: typeTask.id,
            title: "My first user story",
            description: "This is a basic user story where you can add new tasks.",
            estimate: 5,
            priority: 1
        },
        {
            projectId: project.id,
            sprintId: sprint.id,
            milestoneId: 0,
            typeId: typeTask.id,
            title: "Another user story",
            description: "You can add new user stories to current sprint by clicking '+' button on the board header row.",
            estimate: -1,
            priority: 2
        },
        {
            projectId: project.id,
            sprintId: 0,
            milestoneId: 0,
            typeId: typeTask.id,
            title: "Planned user story",
            description: "This user story has no relation to any existing sprint, so it is in project backlog, where you can prioritize it.",
            estimate: 5,
            priority: 1
        }
    ];

    // Create specified user stories
    async.map(
        storyData,
        function(story, callback) {
            Story
                .create(story)
                .done(function(error, story) {
                    callback(error, story);
                });
        },
        function(error, stories) {
            next(error, project, phases, sprint, stories);
        }
    );
};

/**
 * Method creates some demo tasks to specified project sprint.
 *
 * @param   {{}}                    data    Object that contains following data:
 *                                           - admin, user object
 *                                           - types, array of task type objects
 * @param   {sails.model.project}   project Project object
 * @param   {sails.model.phase[]}   phases  Array of phase objects
 * @param   {sails.model.sprint}    sprint  Sprint object
 * @param   {sails.model.story[]}   stories Array of story objects
 * @param   {Function}              next    Callback function to call after job is finished
 */
exports.createTasks = function(data, project, phases, sprint, stories, next) {
    var typeTask = _.find(data.types, function(type) { return type.title === "Task"; });
    var typeTest = _.find(data.types, function(type) { return type.title === "Test"; });
    var typeBug = _.find(data.types, function(type) { return type.title === "Bug"; });
    var phaseFirst = _.find(phases, function(phase) { return phase.title === "Tasks"; });
    var storyFirst = _.find(stories, function(story) { return story.title === "My first user story"; });

    // Specify task data
    var taskData = [
        {
            storyId: storyFirst.id,
            userId: data.admin.id,
            phaseId: phaseFirst.id,
            typeId: typeTask.id,
            title: "Normal task",
            description: "This is a 'normal' task, which you can drag around the board."
        },
        {
            storyId: storyFirst.id,
            userId: data.admin.id,
            phaseId: phaseFirst.id,
            typeId: typeTest.id,
            title: "Test task",
            description: "This is a 'test' task, usually this means writing some kind of test to this user story."
        },
        {
            storyId: storyFirst.id,
            userId: data.admin.id,
            phaseId: phaseFirst.id,
            typeId: typeBug.id,
            title: "Major bug in app",
            description: "This is a 'bug' task, you can track bugs with these tasks in each user story."
        }
    ];

    // Create specified tasks
    async.map(
        taskData,
        function(task, callback) {
            Task
                .create(task)
                .done(function(error, task) {
                    callback(error, task);
                });
        },
        function(error, tasks) {
            next(error, project, phases, sprint, stories, tasks);
        }
    );
};
{'fraction_non_alphanumeric': 0.10173697270471464, 'fraction_numerical': 0.001689456734068951, 'mean_word_length': 1.437524128168833, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, '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': '4211057', 'n_tokens_mistral': 4776, 'n_tokens_neox': 4575, 'n_words': 1467}