<commit_before>var mouseWheel = require('mouse-wheel')
var eventOffset = require('mouse-event-offset')
var createPinch = require('touch-pinch')

module.exports = inputEvents
function inputEvents (opt) {
  var element = opt.element || window
  var source = opt.parent || element
  var mouseStart = [0, 0]
  var dragging = false
  var tmp = [0, 0]
  var tmp2 = [0, 0]
  var pinch

  var zoomFn = opt.zoom
  var rotateFn = opt.rotate
  var pinchFn = opt.pinch

  if (zoomFn) {
    mouseWheel(element, function (dx, dy) {
      zoomFn(dy)
    }, true)
  }

  if (rotateFn) {
    source.addEventListener('mousedown', onInputDown)
    source.addEventListener('mousemove', onInputMove)
    source.addEventListener('mouseup', onInputUp)
  }

  if (rotateFn || pinchFn) {
    pinch = createPinch(source, element)

    // don't allow simulated mouse events
    source.addEventListener('touchstart', preventDefault)

    if (rotateFn) touchRotate()
    if (pinchFn) touchPinch()
  }

  function preventDefault (ev) {
    ev.preventDefault()
  }

  function touchRotate () {
    source.addEventListener('touchmove', function (ev) {
      if (!dragging || isPinching()) return

      // find currently active finger
      for (var i=0; i<ev.changedTouches.length; i++) {
        var changed = ev.changedTouches[i]
        var idx = pinch.indexOfTouch(changed)
        // if pinch is disabled but rotate enabled,
        // only allow first finger to affect rotation
        var allow = pinchFn ? idx !== -1 : idx === 0
        if (allow) {
          onInputMove(changed)
          break
        }
      }
    })

    pinch.on('place', function (newFinger, lastFinger) {
      dragging = !isPinching()
      if (dragging) {
        var firstFinger = lastFinger || newFinger
        onInputDown(firstFinger)
      }
    })

    pinch.on('lift', function (lifted, remaining) {
      dragging = !isPinching()
      if (dragging && remaining) {
        eventOffset(remaining, element, mouseStart)
      }
    })
  }

  function isPinching () {
    return pinch.pinching && pinchFn
  }

  function touchPinch () {
    pinch.on('change', function (current, prev) {
      pinchFn(current - prev)
    })
  }

  function onInputDown (ev) {
    eventOffset(ev, element, mouseStart)
    if (insideBounds(mouseStart)) {
      dragging = true
    }
  }

  function onInputUp () {
    dragging = false
  }

  function onInputMove (ev) {
    var end = eventOffset(ev, element, tmp)
    if (pinch && isPinching()) {
      mouseStart = end
      return
    }
    if (!dragging) return
    var rect = getClientSize(tmp2)
    var dx = (end[0] - mouseStart[0]) / rect[0]
    var dy = (end[1] - mouseStart[1]) / rect[1]
    rotateFn(dx, dy)
    mouseStart[0] = end[0]
    mouseStart[1] = end[1]
  }

  function insideBounds (pos) {
    if (element === window ||
        element === document ||
        element === document.body) {
      return true
    } else {
      var rect = element.getBoundingClientRect()
      return pos[0] >= 0 && pos[1] >= 0 &&
        pos[0] < rect.width && pos[1] < rect.height
    }
  }

  function getClientSize (out) {
    var source = element
    if (source === window ||
        source === document ||
        source === document.body) {
      source = document.documentElement
    }
    out[0] = source.clientWidth
    out[1] = source.clientHeight
    return out
  }
}
<commit_msg>fix bug with events being added to wrong element<commit_after>var mouseWheel = require('mouse-wheel')
var eventOffset = require('mouse-event-offset')
var createPinch = require('touch-pinch')

module.exports = inputEvents
function inputEvents (opt) {
  var element = opt.element || window
  var parent = opt.parent || element
  var mouseStart = [0, 0]
  var dragging = false
  var tmp = [0, 0]
  var tmp2 = [0, 0]
  var pinch

  var zoomFn = opt.zoom
  var rotateFn = opt.rotate
  var pinchFn = opt.pinch

  if (zoomFn) {
    mouseWheel(element, function (dx, dy) {
      zoomFn(dy)
    }, true)
  }

  if (rotateFn) {
    // for dragging to work outside canvas bounds,
    // mouse events have to be added to parent
    parent.addEventListener('mousedown', onInputDown)
    parent.addEventListener('mousemove', onInputMove)
    parent.addEventListener('mouseup', onInputUp)
  }

  if (rotateFn || pinchFn) {
    pinch = createPinch(element)

    // don't allow simulated mouse events
    element.addEventListener('touchstart', preventDefault)

    if (rotateFn) touchRotate()
    if (pinchFn) touchPinch()
  }

  function preventDefault (ev) {
    ev.preventDefault()
  }

  function touchRotate () {
    element.addEventListener('touchmove', function (ev) {
      if (!dragging || isPinching()) return

      // find currently active finger
      for (var i=0; i<ev.changedTouches.length; i++) {
        var changed = ev.changedTouches[i]
        var idx = pinch.indexOfTouch(changed)
        // if pinch is disabled but rotate enabled,
        // only allow first finger to affect rotation
        var allow = pinchFn ? idx !== -1 : idx === 0
        if (allow) {
          onInputMove(changed)
          break
        }
      }
    })

    pinch.on('place', function (newFinger, lastFinger) {
      dragging = !isPinching()
      if (dragging) {
        var firstFinger = lastFinger || newFinger
        onInputDown(firstFinger)
      }
    })

    pinch.on('lift', function (lifted, remaining) {
      dragging = !isPinching()
      if (dragging && remaining) {
        eventOffset(remaining, element, mouseStart)
      }
    })
  }

  function isPinching () {
    return pinch.pinching && pinchFn
  }

  function touchPinch () {
    pinch.on('change', function (current, prev) {
      pinchFn(current - prev)
    })
  }

  function onInputDown (ev) {
    eventOffset(ev, element, mouseStart)
    if (insideBounds(mouseStart)) {
      dragging = true
    }
  }

  function onInputUp () {
    dragging = false
  }

  function onInputMove (ev) {
    var end = eventOffset(ev, element, tmp)
    if (pinch && isPinching()) {
      mouseStart = end
      return
    }
    if (!dragging) return
    var rect = getClientSize(tmp2)
    var dx = (end[0] - mouseStart[0]) / rect[0]
    var dy = (end[1] - mouseStart[1]) / rect[1]
    rotateFn(dx, dy)
    mouseStart[0] = end[0]
    mouseStart[1] = end[1]
  }

  function insideBounds (pos) {
    if (element === window ||
        element === document ||
        element === document.body) {
      return true
    } else {
      var rect = element.getBoundingClientRect()
      return pos[0] >= 0 && pos[1] >= 0 &&
        pos[0] < rect.width && pos[1] < rect.height
    }
  }

  function getClientSize (out) {
    var source = element
    if (source === window ||
        source === document ||
        source === document.body) {
      source = document.documentElement
    }
    out[0] = source.clientWidth
    out[1] = source.clientHeight
    return out
  }
}
<|endoftext|>


<commit_before>define([
    'jquery',
    'underscore',
    'backbone',
    'app',
    'views/navigationtree/NavigationTreeView',
    'views/projects/ViewNodeItemView',
    'views/testsuites/TestSuiteView',
    'views/testcases/TestCaseView',
    'models/project/ProjectModel',
    'models/testsuite/TestSuiteModel',
    'models/testcase/TestCaseModel',
    'models/testplan/TestPlanModel',
    'collections/navigationtree/NavigationTreeCollection',
    'text!templates/testplans/viewTestPlanTemplate.html',
    'text!templates/projects/projectNodeItemTemplate.html',
    'text!templates/testsuites/testSuiteNodeItemTemplate.html',
    'text!templates/testcases/testCaseNodeItemTemplate.html'
], function(
    $,
    _,
    Backbone,
    app,
    NavigationTreeView,
    ViewNodeItemView,
    TestSuiteView,
    TestCaseView,
    ProjectModel,
    TestSuiteModel,
    TestCaseModel,
    TestPlanModel,
    NavigationTreeCollection,
    viewTestPlanTemplate,
    projectNodeItemTemplate,
    testSuiteNodeItemTemplate,
    testCaseNodeItemTemplate) {

    /**
     * Displays the navigation tree.
     */
    var ViewTestPlanView = Backbone.View.extend({
        el: $("#page"),

        events: {
            'click #save-testplan-btn': 'addTestCasesToTestPlan',
            'click #cancel-testplan-btn': 'cancelAndGoBack'
        },

        initialize: function(options) {
            _.bindAll(this,
                'render', 'render2',
                'setProjectId',
                'setTestSuiteId',
                'setTestCaseId',
                'setTestPlanId',
                'updateNavigationTree',
                'displayLoading',
                'displayProject',
                'displayTestSuite',
                'displayTestCase',
                'addTestCasesToTestPlan',
                'cancelAndGoBack');

            var self = this;

            this.projectId = parseInt(options.projectId);
            this.testSuiteId = 0;
            this.testCaseId = 0;
            this.testPlanId = parseInt(options.testPlanId);

            // Collections
            this.navigationTreeCollection = new NavigationTreeCollection({
                projectId: self.projectId
            });

            // Models
            this.testPlanModel = new TestPlanModel();
            this.testPlanModel.set('id', this.testPlanId);

            // Views
            this.navigationTreeView = new NavigationTreeView({
                draggable: false,
                checkboxes: true,
                rootNodeUrl: '#/testplans/' + options.testPlanId + '/view',
                nodeUrlPrefix: '#/testplans',
                collection: self.navigationTreeCollection
            });
            this.viewNodeItemView = new ViewNodeItemView();
            this.testSuiteView = new TestSuiteView();
            this.testCaseView = new TestCaseView();

            // Events
            Backbone.on('nestor:navigationtree:project_changed', this.updateNavigationTree);
            Backbone.on('nestor:navigationtree_changed', this.updateNavigationTree);

            // For GC
            this.subviews = new Object();
            this.subviews.navigationTreeView = this.navigationTreeView;
            this.subviews.viewNodeItemView = this.viewNodeItemView;
            this.subviews.testSuiteView = this.testSuiteView;
            this.subviews.testCaseView = this.testCaseView;
        },

        cancelAndGoBack: function(evt) {
            Backbone.history.navigate("#/planning", { trigger: false });
        },

        render: function() {
            var self = this;
            $.when(this.testPlanModel.fetch(), this.navigationTreeCollection.fetch({ reset: true }))
                .done(function() {
                    self.render2();
                })
            ;
        },

        render2: function() {
            $('.item').removeClass('active');
            $('.item a[href="#/planning"]').parent().addClass('active');

            var compiledTemplate = _.template(viewTestPlanTemplate, {});
            this.$el.html(compiledTemplate);

            this.$('#content-main').empty();
            this.updateNavigationTree();
        },

        updateNavigationTree: function(event) {
            var self = this;
            if (app.currentView == this) {
                console.log('Rendering navigation tree!');
                this.$('#navigation-tree').fancytree({});
                self.navigationTreeView.render({
                    el: self.$('#navigation-tree')
                });
            }
        },

        setProjectId: function(id) {
            var projectId = parseInt(id);
            // update project ID in models
            this.projectModel = new ProjectModel();
            this.projectModel.set('id', projectId);

            this.testSuiteModel = new TestSuiteModel();
            this.testSuiteModel.set('project_id', projectId);

            this.testCaseModel = new TestCaseModel();
            this.testCaseModel.set('project_id', projectId);

            this.navigationTreeView.projectId = projectId;

            if (this.projectId !== projectId/* || !$.trim($(this.navigationTreeView.el).html())*/) {
                this.projectId = projectId;
                Backbone.trigger('nestor:navigationtree:project_changed');
                if (app.currentView == this) {
                    this.displayProject();
                }
            }
        },

        setTestSuiteId: function(testSuiteId) {
            // update test suite ID in models
            this.testSuiteModel = new TestSuiteModel();
            this.testSuiteModel.project_id = this.projectId;
            this.testSuiteModel.id = testSuiteId;
            this.testSuiteId = testSuiteId;

            this.testCaseModel = new TestCaseModel();
            this.testCaseModel.project_id = this.projectId;
            this.testCaseModel.testsuite_id = testSuiteId;
        },

        setTestCaseId: function(testCaseId) {
            // update test suite ID in models
            this.testCaseModel = new TestCaseModel();
            this.testCaseModel.project_id = this.projectId;
            this.testCaseModel.testsuite_id = this.testSuiteId;
            this.testCaseModel.id = testCaseId;

            this.testCaseId = testCaseId;
        },

        setTestPlanId: function(testPlanId) {
            this.testPlanId = testPlanId;
        },

        displayLoading: function() {
            this.$('#content-main').empty();
            this.$('#content-main').html('

');
        },

        /**
         * Display project node item on the right panel of the screen.
         */
        displayProject: function() {
            this.displayLoading();
            $('.item').removeClass('active');
            $('.item a[href="#/planning"]').parent().addClass('active');
            var self = this;
            this.projectModel.fetch({
                success: function(responseData) {
                    var project = self.projectModel;
                    var data = {
                        project: project,
                        _: _,
                        editable: false
                    };

                    var compiledTemplate = _.template(projectNodeItemTemplate, data);
                    self.viewNodeItemView.$el.html(compiledTemplate);
                    this.$('#content-main').unbind();
                    this.$('#content-main').empty();
                    this.$('#content-main').append(self.viewNodeItemView.el);
                    self.viewNodeItemView.delegateEvents();
                    var tree = this.$('#navigation-tree').fancytree('getTree');
                    if (typeof tree !== typeof undefined && typeof tree.getNodeByKey !== typeof undefined) {
                        var node = tree.getNodeByKey("1-" + project.get('id'));
                        if (node && typeof node !== typeof undefined && typeof node.setActive !== typeof undefined) {
                            node.setActive();
                        } else {
                            console.log('Invalid tree node for node ' + project.get('id'));
                        }
                    } else {
                        console.log('Invalid navigation tree for project ' + self.projectId);
                    }
                },
                error: function() {
                    throw new Error("Failed to fetch project");
                }
            });
        },

        /**
         * Display project node item on the right panel of the screen.
         */
        displayTestSuite: function() {
            var self = this;
            this.testSuiteModel.set('id', this.testSuiteId);
            this.testSuiteModel.fetch({
                success: function(responseData) {
                    var data = {
                        testsuite: self.testSuiteModel,
                        _: _,
                        editable: false
                    };

                    var compiledTemplate = _.template(testSuiteNodeItemTemplate, data);
                    self.viewNodeItemView.$el.html(compiledTemplate);
                    self.$('#content-main').empty();
                    self.$('#content-main').append(self.viewNodeItemView.el);
                },
                error: function() {
                    throw new Error("Failed to fetch test suite");
                }
            });
        },

        /**
         * Display project node item on the right panel of the screen.
         */
        displayTestCase: function() {
            var self = this;
            this.testCaseModel.set('project_id', this.projectId);
            this.testCaseModel.set('test_suite_id', this.testSuiteId);
            this.testCaseModel.set('id', this.testCaseId);
            this.testCaseModel.fetch({
                success: function(responseData) {
                    var testcase = self.testCaseModel;
                    var data = {
                        testcase: testcase,
                        _: _,
                        editable: false
                    };

                    var compiledTemplate = _.template(testCaseNodeItemTemplate, data);
                    self.viewNodeItemView.$el.html(compiledTemplate);
                    self.$('#content-main').empty();
                    self.$('#content-main').append(self.viewNodeItemView.el);
                    self.$('#navigation-tree').fancytree('getTree').getNodeByKey("3-" + testcase.get('id')).setActive();
                },
                error: function() {
                    throw new Error("Failed to fetch test case");
                }
            });
        },

        addTestCasesToTestPlan: function(evt) {
            this.$('#navigation-tree').fancytree('getTree').generateFormElements(true, false);
            var form = $("#testplan-navigation-tree-form");
            var data = $(form).serializeArray();
            console.log(data);
        }

    });

    return ViewTestPlanView;

});<commit_msg>Delegate events from view test plan view<commit_after>define([
    'jquery',
    'underscore',
    'backbone',
    'app',
    'views/navigationtree/NavigationTreeView',
    'views/projects/ViewNodeItemView',
    'views/testsuites/TestSuiteView',
    'views/testcases/TestCaseView',
    'models/project/ProjectModel',
    'models/testsuite/TestSuiteModel',
    'models/testcase/TestCaseModel',
    'models/testplan/TestPlanModel',
    'collections/navigationtree/NavigationTreeCollection',
    'text!templates/testplans/viewTestPlanTemplate.html',
    'text!templates/projects/projectNodeItemTemplate.html',
    'text!templates/testsuites/testSuiteNodeItemTemplate.html',
    'text!templates/testcases/testCaseNodeItemTemplate.html'
], function(
    $,
    _,
    Backbone,
    app,
    NavigationTreeView,
    ViewNodeItemView,
    TestSuiteView,
    TestCaseView,
    ProjectModel,
    TestSuiteModel,
    TestCaseModel,
    TestPlanModel,
    NavigationTreeCollection,
    viewTestPlanTemplate,
    projectNodeItemTemplate,
    testSuiteNodeItemTemplate,
    testCaseNodeItemTemplate) {

    /**
     * Displays the navigation tree.
     */
    var ViewTestPlanView = Backbone.View.extend({
        el: $("#page"),

        events: {
            'click #save-testplan-btn': 'addTestCasesToTestPlan',
            'click #cancel-testplan-btn': 'cancelAndGoBack'
        },

        initialize: function(options) {
            _.bindAll(this,
                'render', 'render2',
                'setProjectId',
                'setTestSuiteId',
                'setTestCaseId',
                'setTestPlanId',
                'updateNavigationTree',
                'displayLoading',
                'displayProject',
                'displayTestSuite',
                'displayTestCase',
                'addTestCasesToTestPlan',
                'cancelAndGoBack');

            var self = this;

            this.projectId = parseInt(options.projectId);
            this.testSuiteId = 0;
            this.testCaseId = 0;
            this.testPlanId = parseInt(options.testPlanId);

            // Collections
            this.navigationTreeCollection = new NavigationTreeCollection({
                projectId: self.projectId
            });

            // Models
            this.testPlanModel = new TestPlanModel();
            this.testPlanModel.set('id', this.testPlanId);

            // Views
            this.navigationTreeView = new NavigationTreeView({
                draggable: false,
                checkboxes: true,
                rootNodeUrl: '#/testplans/' + options.testPlanId + '/view',
                nodeUrlPrefix: '#/testplans',
                collection: self.navigationTreeCollection
            });
            this.viewNodeItemView = new ViewNodeItemView();
            this.testSuiteView = new TestSuiteView();
            this.testCaseView = new TestCaseView();

            // Events
            Backbone.on('nestor:navigationtree:project_changed', this.updateNavigationTree);
            Backbone.on('nestor:navigationtree_changed', this.updateNavigationTree);

            // For GC
            this.subviews = new Object();
            this.subviews.navigationTreeView = this.navigationTreeView;
            this.subviews.viewNodeItemView = this.viewNodeItemView;
            this.subviews.testSuiteView = this.testSuiteView;
            this.subviews.testCaseView = this.testCaseView;
        },

        cancelAndGoBack: function(evt) {
            Backbone.history.navigate("#/planning", { trigger: false });
        },

        render: function() {
            var self = this;
            $.when(this.testPlanModel.fetch(), this.navigationTreeCollection.fetch({ reset: true }))
                .done(function() {
                    self.render2();
                })
            ;
        },

        render2: function() {
            $('.item').removeClass('active');
            $('.item a[href="#/planning"]').parent().addClass('active');

            var compiledTemplate = _.template(viewTestPlanTemplate, {});
            this.$el.html(compiledTemplate);

            this.$('#content-main').empty();
            this.updateNavigationTree();
            this.delegateEvents();
        },

        updateNavigationTree: function(event) {
            var self = this;
            if (app.currentView == this) {
                console.log('Rendering navigation tree!');
                this.$('#navigation-tree').fancytree({});
                self.navigationTreeView.render({
                    el: self.$('#navigation-tree')
                });
            }
        },

        setProjectId: function(id) {
            var projectId = parseInt(id);
            // update project ID in models
            this.projectModel = new ProjectModel();
            this.projectModel.set('id', projectId);

            this.testSuiteModel = new TestSuiteModel();
            this.testSuiteModel.set('project_id', projectId);

            this.testCaseModel = new TestCaseModel();
            this.testCaseModel.set('project_id', projectId);

            this.navigationTreeView.projectId = projectId;

            if (this.projectId !== projectId/* || !$.trim($(this.navigationTreeView.el).html())*/) {
                this.projectId = projectId;
                Backbone.trigger('nestor:navigationtree:project_changed');
                if (app.currentView == this) {
                    this.displayProject();
                }
            }
        },

        setTestSuiteId: function(testSuiteId) {
            // update test suite ID in models
            this.testSuiteModel = new TestSuiteModel();
            this.testSuiteModel.project_id = this.projectId;
            this.testSuiteModel.id = testSuiteId;
            this.testSuiteId = testSuiteId;

            this.testCaseModel = new TestCaseModel();
            this.testCaseModel.project_id = this.projectId;
            this.testCaseModel.testsuite_id = testSuiteId;
        },

        setTestCaseId: function(testCaseId) {
            // update test suite ID in models
            this.testCaseModel = new TestCaseModel();
            this.testCaseModel.project_id = this.projectId;
            this.testCaseModel.testsuite_id = this.testSuiteId;
            this.testCaseModel.id = testCaseId;

            this.testCaseId = testCaseId;
        },

        setTestPlanId: function(testPlanId) {
            this.testPlanId = testPlanId;
        },

        displayLoading: function() {
            this.$('#content-main').empty();
            this.$('#content-main').html('

');
        },

        /**
         * Display project node item on the right panel of the screen.
         */
        displayProject: function() {
            this.displayLoading();
            $('.item').removeClass('active');
            $('.item a[href="#/planning"]').parent().addClass('active');
            var self = this;
            this.projectModel.fetch({
                success: function(responseData) {
                    var project = self.projectModel;
                    var data = {
                        project: project,
                        _: _,
                        editable: false
                    };

                    var compiledTemplate = _.template(projectNodeItemTemplate, data);
                    self.viewNodeItemView.$el.html(compiledTemplate);
                    this.$('#content-main').unbind();
                    this.$('#content-main').empty();
                    this.$('#content-main').append(self.viewNodeItemView.el);
                    self.viewNodeItemView.delegateEvents();
                    var tree = this.$('#navigation-tree').fancytree('getTree');
                    if (typeof tree !== typeof undefined && typeof tree.getNodeByKey !== typeof undefined) {
                        var node = tree.getNodeByKey("1-" + project.get('id'));
                        if (node && typeof node !== typeof undefined && typeof node.setActive !== typeof undefined) {
                            node.setActive();
                        } else {
                            console.log('Invalid tree node for node ' + project.get('id'));
                        }
                    } else {
                        console.log('Invalid navigation tree for project ' + self.projectId);
                    }
                },
                error: function() {
                    throw new Error("Failed to fetch project");
                }
            });
        },

        /**
         * Display project node item on the right panel of the screen.
         */
        displayTestSuite: function() {
            var self = this;
            this.testSuiteModel.set('id', this.testSuiteId);
            this.testSuiteModel.fetch({
                success: function(responseData) {
                    var data = {
                        testsuite: self.testSuiteModel,
                        _: _,
                        editable: false
                    };

                    var compiledTemplate = _.template(testSuiteNodeItemTemplate, data);
                    self.viewNodeItemView.$el.html(compiledTemplate);
                    self.$('#content-main').empty();
                    self.$('#content-main').append(self.viewNodeItemView.el);
                },
                error: function() {
                    throw new Error("Failed to fetch test suite");
                }
            });
        },

        /**
         * Display project node item on the right panel of the screen.
         */
        displayTestCase: function() {
            var self = this;
            this.testCaseModel.set('project_id', this.projectId);
            this.testCaseModel.set('test_suite_id', this.testSuiteId);
            this.testCaseModel.set('id', this.testCaseId);
            this.testCaseModel.fetch({
                success: function(responseData) {
                    var testcase = self.testCaseModel;
                    var data = {
                        testcase: testcase,
                        _: _,
                        editable: false
                    };

                    var compiledTemplate = _.template(testCaseNodeItemTemplate, data);
                    self.viewNodeItemView.$el.html(compiledTemplate);
                    self.$('#content-main').empty();
                    self.$('#content-main').append(self.viewNodeItemView.el);
                    self.$('#navigation-tree').fancytree('getTree').getNodeByKey("3-" + testcase.get('id')).setActive();
                },
                error: function() {
                    throw new Error("Failed to fetch test case");
                }
            });
        },

        addTestCasesToTestPlan: function(evt) {
            this.$('#navigation-tree').fancytree('getTree').generateFormElements(true, false);
            var form = $("#testplan-navigation-tree-form");
            var data = $(form).serializeArray();
            console.log(data);
        }

    });

    return ViewTestPlanView;

});<|endoftext|>


<commit_before>'use strict';

const dateHelper = require(`${__dirname}/../helpers/dateHelper`);
const requestHelper = require(`${__dirname}/../helpers/requestHelper`);

exports.getRowRequest = (field, size, req, res) => {
  if (dateHelper.isValidDate(req.query.from) && dateHelper.isValidDate(req.query.to)) {
    requestHelper.makeAllRowRequest(field, size, req.query.from, req.query.to, res);
  } else {
    res.json({ success: false, message: 'Bad date formatting' });
  }
};<commit_msg>Add controller function for smurf requests<commit_after>'use strict';

const dateHelper = require(`${__dirname}/../helpers/dateHelper`);
const requestHelper = require(`${__dirname}/../helpers/requestHelper`);

exports.getRowRequest = (field, size, req, res) => {
  if (dateHelper.isValidDate(req.query.from) && dateHelper.isValidDate(req.query.to)) {
    requestHelper.makeAllRowRequest(field, size, req.query.from, req.query.to, res);
  } else {
    res.json({ success: false, message: 'Bad date formatting' });
  }
};

exports.getGameRequest = (type, req, res) => {
	requestHelper.makeGameRequest(type, req, res);
};<|endoftext|>


<commit_before>'use strict';

/*!
 * module  jsonp
 * author  Kael Zhang
 */

// JSONP Request

var Class = require('class');
var lang = require('lang');
var asset = require('asset');

/**
 * @private
 * clean/check the symbol of empersand('&') on the end/beginning of a query

 * @param query {query} the string to be tidied
 * @param hasFirst {Boolean}
 *      if true, will check whether there is a '&' at first. if there isn't, one '&' will be added
 *      if false,
 */
function _tidyEmpersand(str, hasFirst, hasLast) {
    if (str) {
        var e = '&',
            len = str.length - 1,
            f = str[0] === e,
            l = str[len] === e;

        if (!hasFirst) {
            str = f ? str.substr(1) : str;
        } else {
            str = f ? str : e + str;
        }

        len = str.length - 1;

        if (!hasLast) {
            str = l ? str.substr(0, len) : err;
        } else {
            str = l ? str : str + e;
        }
    }

    return str || '';
};

/**
 * @private
 * generate a query url
 */
function _getQuestURL(url, key, query, index) {
    url = url.split('?');

    return url[0] + '?' + _tidyEmpersand(url[1], false, true) + _tidyEmpersand(query, false, true) + key + '=' + NR_STR + '.' + JSONP_CALLBACK_PUBLIC_PREFIX + '._' + index;
};

var _counter = 0;
var NR_STR = 'NR';
var JSONP_CALLBACK_PUBLIC_PREFIX = '_JSONPRequest';

var JSONP = Class({

    Implements: 'events attrs',

    initialize: function (options) {
        this.set(options);
    },

    // @returns {string} query string
    _tidyRequest: function(data){
        data = (data === undefined ? this.get('data') : data) || '';

        if (lang.isObject(data)){
            data = lang.toQueryString(data);

        }

        if(!this.get('cache')){
            data += '&_nr_force' + (+ new Date);
        }

        return data;
    },

    // @param options
    //  {Object} jsonp request data
    //  {String} jsonp request query string

    // @note: no more support Element type
    send: function (data) {
        var query = this._tidyRequest(data),
            src,
            script,

            // generate a unique, non-zero jsonp request id
            uid = ++ _counter,
            K = NR,
            request = K[JSONP_CALLBACK_PUBLIC_PREFIX],
            timeout = this.get('timeout');

        // formatting data -------------------------------------------------------

        src = _getQuestURL(this.get('url'), this.get('callbackKey'), query, uid);

        if (src.length > 2083){
            return this.fire('error', src);
        }

        var self = this;

        // JSONP request start
        request['_' + uid] = function () {
            self.__success.apply(self, arguments);

            delete request['_' + uid];
        }

        this._clear();
        this.script = asset.js(src, false, {
            remove: true
        });

        this.fire('request');

        if (timeout) {
            setTimeout(function(){
                self.fire('timeout').fire('error').cancel();

            }, timeout);
        }

        return uid;
    },

    // @private
    __success: function() {
        this.fire('success', arguments);
    },

    // TODO
    // bug, could not really cancel jsonp request
    cancel: function() {
        return this._clear().fire('cancel');
    },

    _clear: function(){
        this.script = null;
        return this;
    }

}, {
    // @type {string} JSONP request uri
    url: {
        value: ''
    },

    callbackKey: {
        value: 'callback'
    },

    data: {
    },

    timeout: {
        value: 0
    },

    cache: {
        value: false
    }
});

NR[JSONP_CALLBACK_PUBLIC_PREFIX] = {};

module.exports = JSONP;

/**
 change log
 2011-11-01  Kael
 - migrate to Neuron
 */<commit_msg>add a static method of JSONP to set the global namespace to hold jsonp callbacks<commit_after>'use strict';

/*!
 * module  jsonp
 * author  Kael Zhang
 */

// JSONP Request

var Class = require('class');
var lang = require('lang');
var asset = require('asset');

/**
 * @private
 * clean/check the symbol of empersand('&') on the end/beginning of a query

 * @param query {query} the string to be tidied
 * @param hasFirst {Boolean}
 *      if true, will check whether there is a '&' at first. if there isn't, one '&' will be added
 *      if false,
 */
function _tidyEmpersand(str, hasFirst, hasLast) {
    if (str) {
        var e = '&',
            len = str.length - 1,
            f = str[0] === e,
            l = str[len] === e;

        if (!hasFirst) {
            str = f ? str.substr(1) : str;
        } else {
            str = f ? str : e + str;
        }

        len = str.length - 1;

        if (!hasLast) {
            str = l ? str.substr(0, len) : err;
        } else {
            str = l ? str : str + e;
        }
    }

    return str || '';
};

var _counter = 0;
var JSONP_CALLBACK_PUBLIC_PREFIX = '_JSONPCallback';

var JSONP = Class({

    Implements: 'events attrs',

    initialize: function (options) {
        this.set(options);
    },

    // @returns {string} query string
    _tidyRequest: function(data){
        data = (data === undefined ? this.get('data') : data) || '';

        if (lang.isObject(data)){
            data = lang.toQueryString(data);

        }

        if(!this.get('cache')){
            data += '&_nr_force' + (+ new Date);
        }

        return data;
    },

    /**
     * @private
     * generate a query url
     */
    _getQuestURL: function(url, key, query, index) {
        url = url.split('?');

        return url[0] + '?' + _tidyEmpersand(url[1], false, true) + _tidyEmpersand(query, false, true) + key + '=' + JSONP._HOLDER_NAME + '._' + index;
    },

    // @param options
    //  {Object} jsonp request data
    //  {String} jsonp request query string

    // @note: no more support Element type
    send: function (data) {
        var query = this._tidyRequest(data),
            src,
            script,

            // generate a unique, non-zero jsonp request id
            uid = ++ _counter,
            K = NR,
            request = JSONP._HOLDER,
            timeout = this.get('timeout');

        // formatting data -------------------------------------------------------

        src = this._getQuestURL(this.get('url'), this.get('callbackKey'), query, uid);

        if (src.length > 2083){
            return this.fire('error', src);
        }

        var self = this;

        // JSONP request start
        request['_' + uid] = function () {
            self.__success.apply(self, arguments);

            delete request['_' + uid];
        }

        this._clear();
        this.script = asset.js(src, false, {
            remove: true
        });

        this.fire('request');

        if (timeout) {
            setTimeout(function(){
                self.fire('timeout').fire('error').cancel();

            }, timeout);
        }

        return uid;
    },

    // @private
    __success: function() {
        this.fire('success', arguments);
    },

    // TODO
    // bug, could not really cancel jsonp request
    cancel: function() {
        return this._clear().fire('cancel');
    },

    _clear: function(){
        this.script = null;
        return this;
    }

}, {
    // @type {string} JSONP request uri
    url: {
        value: ''
    },

    callbackKey: {
        value: 'callback'
    },

    data: {
    },

    timeout: {
        value: 0
    },

    cache: {
        value: false
    }
});

// Set the global namespace to hold JSONP callback functions
// @param {string} namespace
JSONP.setNS = function(namespace){
    var callback_prefix = '';

    if(namespace){
        // namespace = 'NR'
        var ns = window[namespace];

        if(Object(ns) !== ns){
            window[namespace] = {};
        }

        // 'NR.'
        callback_prefix = namespace + '.';
    }else{
        ns = window;
    }

    JSONP._HOLDER_NAME = callback_prefix + JSONP_CALLBACK_PUBLIC_PREFIX;

    JSONP._HOLDER = ns[JSONP_CALLBACK_PUBLIC_PREFIX] || (ns[JSONP_CALLBACK_PUBLIC_PREFIX] = {});
};

JSONP.setNS('NR');

module.exports = JSONP;

/**
 change log
 2011-11-01  Kael
 - migrate to Neuron
 */<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { storiesOf } from '@storybook/react';

import { Add, Close, FormClose, StatusGood, Trash } from 'grommet-icons';

import {
  Box,
  Button,
  FormField,
  Grommet,
  Heading,
  Layer,
  Select,
  Text,
  TextArea,
  TextInput,
} from 'grommet';
import { grommet } from 'grommet/themes';

class CenterLayer extends Component {
  state = {};

  onOpen = () => this.setState({ open: true });

  onClose = () => this.setState({ open: undefined });

  onOpen2 = () => this.setState({ open2: true });

  onClose2 = () => this.setState({ open2: undefined });

  render() {
    const { open, open2 } = this.state;
    return (
      <Grommet theme={grommet} full>
        <Box fill align="center" justify="center">
          <Button
            icon={<Trash />}
            label={
              <Text>
                Remove
              </Text>
            }
            onClick={this.onOpen}
            plain
          />
        </Box>
        {open && (
          <Layer
            position="center"
            modal
            onClickOutside={this.onClose}
            onEsc={this.onClose}
          >
            <Box pad="medium" gap="small" width="medium">
              <Heading level={3} margin="none">
                Confirm
              </Heading>
              <Text>Are you sure you want to delete?</Text>
              <Box
                as="footer"
                gap="small"
                direction="row"
                align="center"
                justify="end"
                pad={{ top: 'medium', bottom: 'small' }}
              >
                <Button label="Open 2" onClick={this.onOpen2} color="dark-3" />
                <Button
                  label={
                    <Text color="white">
                      Delete
                    </Text>
                  }
                  onClick={this.onClose}
                  primary
                  color="status-critical"
                />
              </Box>
            </Box>
          </Layer>
        )}
        {open2 && (
          <Layer
            position="top"
            modal
            onClickOutside={this.onClose2}
            onEsc={this.onClose2}
          >
            <Box pad="medium" gap="small" width="medium">
              <Heading level={3} margin="none">
                Confirm 2
              </Heading>
              <Select options={['one', 'two', 'three']} />
              <Box
                as="footer"
                gap="small"
                direction="row"
                align="center"
                justify="end"
                pad={{ top: 'medium', bottom: 'small' }}
              >
                <Button label="Close" onClick={this.onClose2} color="dark-3" />
              </Box>
            </Box>
          </Layer>
        )}
      </Grommet>
    );
  }
}

class CornerLayer extends Component {
  state = {};

  onOpen = () => this.setState({ open: true });

  onClose = () => this.setState({ open: undefined });

  render() {
    const { open } = this.state;
    return (
      <Grommet theme={grommet} full>
        <Box fill align="center" justify="center">
          <Button
            icon={<Add color="brand" />}
            label={
              <Text>
                Add Corner Layer
              </Text>
            }
            onClick={this.onOpen}
            plain
          />
        </Box>
        {open && (
          <Layer position="top-right">
            <Box height="small" overflow="auto">
              <Box pad="xlarge">Corner top-right position</Box>
            </Box>
          </Layer>
        )}
      </Grommet>
    );
  }
}

class FormLayer extends Component {
  state = { open: false, select: '' };

  onOpen = () => this.setState({ open: true });

  onClose = () => {
    this.setState({ open: undefined });
  };

  render() {
    const { open, select } = this.state;
    return (
      <Grommet theme={grommet} full>
        <Box fill align="center" justify="center">
          <Button icon={<Add />} label="Add" onClick={this.onOpen} />
          {open && (
            <Layer
              position="right"
              full="vertical"
              modal
              onClickOutside={this.onClose}
              onEsc={this.onClose}
            >
              <Box
                as="form"
                fill="vertical"
                overflow="auto"
                width="medium"
                pad="medium"
                onSubmit={this.onClose}
              >
                <Box flex={false} direction="row" justify="between">
                  <Heading level={2} margin="none">
                    Add
                  </Heading>
                  <Button icon={<Close />} onClick={this.onClose} />
                </Box>
                <Box flex="grow" overflow="auto" pad={{ vertical: 'medium' }}>
                  <FormField label="First">
                    <TextInput />
                  </FormField>
                  <FormField label="Second">
                    <Select
                      options={[
                        'one',
                        'two',
                        'three',
                        'four',
                        'five',
                        'six',
                        'seven',
                        'eight',
                      ]}
                      value={select}
                      onSearch={() => {}}
                      onChange={({ option }) =>
                        this.setState({ select: option })
                      }
                    />
                  </FormField>
                  <FormField label="Third">
                    <TextArea />
                  </FormField>
                </Box>
                <Box flex={false} as="footer" align="start">
                  <Button
                    type="submit"
                    label="Submit"
                    onClick={this.onClose}
                    primary
                  />
                </Box>
              </Box>
            </Layer>
          )}
        </Box>
      </Grommet>
    );
  }
}

class NotificationLayer extends Component {
  state = {};

  onOpen = () => this.setState({ open: true });

  onClose = () => this.setState({ open: undefined });

  render() {
    const { open } = this.state;
    return (
      <Grommet theme={grommet} full>
        <Box fill align="center" justify="center">
          <Button
            icon={<Add color="brand" />}
            label={
              <Text>
                Add
              </Text>
            }
            onClick={this.onOpen}
            plain
          />
        </Box>
        {open && (
          <Layer
            position="bottom"
            full="horizontal"
            modal={false}
            responsive={false}
            onEsc={this.onClose}
          >
            <Box
              align="start"
              pad={{ vertical: 'medium', horizontal: 'small' }}
            >
              <Box
                align="center"
                direction="row"
                gap="small"
                round="medium"
                elevation="medium"
                pad={{ vertical: 'xsmall', horizontal: 'small' }}
                background="status-ok"
              >
                <Box align="center" direction="row" gap="xsmall">
                  <StatusGood />
                  <Text>A new virtual machine has been successfully added</Text>
                </Box>
                <Button icon={<FormClose />} onClick={this.onClose} plain />
              </Box>
            </Box>
          </Layer>
        )}
      </Grommet>
    );
  }
}

const MarginLayer = ({ margin, ...rest }) => (
  <Grommet theme={grommet}>
    <Layer
      margin={
        margin || { left: '40px', top: '50px', right: '30px', bottom: '10px' }
      }
      {...rest}
    >
      <Box height="small" overflow="auto">
        <Box pad="xlarge">text</Box>
        <Box pad="xlarge">text</Box>
        <Box pad="xlarge">text</Box>
        <Box pad="xlarge">text</Box>
        <Box pad="xlarge">text</Box>
        <Box pad="xlarge">text</Box>
      </Box>
    </Layer>
  </Grommet>
);

const PlainLayer = () => (
  <Grommet theme={grommet} full>
    <Box fill background="dark-3">
      <Layer margin="medium" plain>
        <Box pad="large" border={{ color: 'accent-1', size: 'large' }}>
          <Text color="accent-2">Text</Text>
        </Box>
      </Layer>
    </Box>
  </Grommet>
);

class FullLayer extends Component {
  state = {
    showLayer: false,
  };

  render() {
    const { showLayer } = this.state;
    return (
      <Grommet theme={grommet} full>
        <Box
          pad="small"
          fill
          background="dark-3"
          align="center"
          justify="center"
        >
          <Button
            primary
            color="accent-3"
            label="Show"
            onClick={() => this.setState({ showLayer: true })}
          />
          {showLayer && (
            <Layer full>
              <Box fill background="light-4" align="center" justify="center">
                <Button
                  primary
                  label="Close"
                  onClick={() => this.setState({ showLayer: false })}
                />
              </Box>
            </Layer>
          )}
        </Box>
      </Grommet>
    );
  }
}

const ScrollBodyLayer = () => (
  <Grommet theme={grommet}>
    <Layer full="vertical" position="right">
      <Box fill style={{ minWidth: '378px' }}>
        <Box
          direction="row"
          align="center"
          as="header"
          elevation="small"
          justify="between"
        >
          <Text margin={{ left: 'small' }}>Header</Text>
          <Button icon={<FormClose />} />
        </Box>
        <Box flex overflow="auto" pad="xsmall">
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
        </Box>
        <Box
          as="footer"
          border={{ side: 'top' }}
          pad="small"
          justify="end"
          direction="row"
          align="center"
        >
          <Button primary label="Save" />
        </Box>
      </Box>
    </Layer>
  </Grommet>
);

storiesOf('Layer', module)
  .add('Center', () => <CenterLayer />)
  .add('CornerLayer', () => <CornerLayer />)
  .add('Form', () => <FormLayer />)
  .add('Notification', () => <NotificationLayer />)
  .add('Margin', () => <MarginLayer full />)
  .add('Margin (Center)', () => <MarginLayer margin="large" />)
  .add('Margin Top (Center)', () => (
    <MarginLayer margin={{ top: 'large' }} position="top" />
  ))
  .add('Plain', () => <PlainLayer />)
  .add('Full', () => <FullLayer />)
  .add('Fixed Header, Scroll Body', () => <ScrollBodyLayer />);
<commit_msg>Updated Layer Notification story<commit_after>import React, { Component } from 'react';
import { storiesOf } from '@storybook/react';

import { Add, Close, FormClose, StatusGood, Trash } from 'grommet-icons';

import {
  Box,
  Button,
  FormField,
  Grommet,
  Heading,
  Layer,
  Select,
  Text,
  TextArea,
  TextInput,
} from 'grommet';
import { grommet } from 'grommet/themes';

class CenterLayer extends Component {
  state = {};

  onOpen = () => this.setState({ open: true });

  onClose = () => this.setState({ open: undefined });

  onOpen2 = () => this.setState({ open2: true });

  onClose2 = () => this.setState({ open2: undefined });

  render() {
    const { open, open2 } = this.state;
    return (
      <Grommet theme={grommet} full>
        <Box fill align="center" justify="center">
          <Button
            icon={<Trash />}
            label={
              <Text>
                Remove
              </Text>
            }
            onClick={this.onOpen}
            plain
          />
        </Box>
        {open && (
          <Layer
            position="center"
            modal
            onClickOutside={this.onClose}
            onEsc={this.onClose}
          >
            <Box pad="medium" gap="small" width="medium">
              <Heading level={3} margin="none">
                Confirm
              </Heading>
              <Text>Are you sure you want to delete?</Text>
              <Box
                as="footer"
                gap="small"
                direction="row"
                align="center"
                justify="end"
                pad={{ top: 'medium', bottom: 'small' }}
              >
                <Button label="Open 2" onClick={this.onOpen2} color="dark-3" />
                <Button
                  label={
                    <Text color="white">
                      Delete
                    </Text>
                  }
                  onClick={this.onClose}
                  primary
                  color="status-critical"
                />
              </Box>
            </Box>
          </Layer>
        )}
        {open2 && (
          <Layer
            position="top"
            modal
            onClickOutside={this.onClose2}
            onEsc={this.onClose2}
          >
            <Box pad="medium" gap="small" width="medium">
              <Heading level={3} margin="none">
                Confirm 2
              </Heading>
              <Select options={['one', 'two', 'three']} />
              <Box
                as="footer"
                gap="small"
                direction="row"
                align="center"
                justify="end"
                pad={{ top: 'medium', bottom: 'small' }}
              >
                <Button label="Close" onClick={this.onClose2} color="dark-3" />
              </Box>
            </Box>
          </Layer>
        )}
      </Grommet>
    );
  }
}

class CornerLayer extends Component {
  state = {};

  onOpen = () => this.setState({ open: true });

  onClose = () => this.setState({ open: undefined });

  render() {
    const { open } = this.state;
    return (
      <Grommet theme={grommet} full>
        <Box fill align="center" justify="center">
          <Button
            icon={<Add color="brand" />}
            label={
              <Text>
                Add Corner Layer
              </Text>
            }
            onClick={this.onOpen}
            plain
          />
        </Box>
        {open && (
          <Layer position="top-right">
            <Box height="small" overflow="auto">
              <Box pad="xlarge">Corner top-right position</Box>
            </Box>
          </Layer>
        )}
      </Grommet>
    );
  }
}

class FormLayer extends Component {
  state = { open: false, select: '' };

  onOpen = () => this.setState({ open: true });

  onClose = () => {
    this.setState({ open: undefined });
  };

  render() {
    const { open, select } = this.state;
    return (
      <Grommet theme={grommet} full>
        <Box fill align="center" justify="center">
          <Button icon={<Add />} label="Add" onClick={this.onOpen} />
          {open && (
            <Layer
              position="right"
              full="vertical"
              modal
              onClickOutside={this.onClose}
              onEsc={this.onClose}
            >
              <Box
                as="form"
                fill="vertical"
                overflow="auto"
                width="medium"
                pad="medium"
                onSubmit={this.onClose}
              >
                <Box flex={false} direction="row" justify="between">
                  <Heading level={2} margin="none">
                    Add
                  </Heading>
                  <Button icon={<Close />} onClick={this.onClose} />
                </Box>
                <Box flex="grow" overflow="auto" pad={{ vertical: 'medium' }}>
                  <FormField label="First">
                    <TextInput />
                  </FormField>
                  <FormField label="Second">
                    <Select
                      options={[
                        'one',
                        'two',
                        'three',
                        'four',
                        'five',
                        'six',
                        'seven',
                        'eight',
                      ]}
                      value={select}
                      onSearch={() => {}}
                      onChange={({ option }) =>
                        this.setState({ select: option })
                      }
                    />
                  </FormField>
                  <FormField label="Third">
                    <TextArea />
                  </FormField>
                </Box>
                <Box flex={false} as="footer" align="start">
                  <Button
                    type="submit"
                    label="Submit"
                    onClick={this.onClose}
                    primary
                  />
                </Box>
              </Box>
            </Layer>
          )}
        </Box>
      </Grommet>
    );
  }
}

class NotificationLayer extends Component {
  state = {};

  onOpen = () => this.setState({ open: true });

  onClose = () => this.setState({ open: undefined });

  render() {
    const { open } = this.state;
    return (
      <Grommet theme={grommet} full>
        <Box fill align="center" justify="center">
          <Button
            icon={<Add color="brand" />}
            label={
              <Text>
                Add
              </Text>
            }
            onClick={this.onOpen}
            plain
          />
        </Box>
        {open && (
          <Layer
            position="bottom"
            modal={false}
            margin={{ vertical: 'medium', horizontal: 'small' }}
            onEsc={this.onClose}
            responsive={false}
            plain
          >
            <Box
              align="center"
              direction="row"
              gap="small"
              justify="between"
              round="medium"
              elevation="medium"
              pad={{ vertical: 'xsmall', horizontal: 'small' }}
              background="status-ok"
            >
              <Box align="center" direction="row" gap="xsmall">
                <StatusGood />
                <Text>A new virtual machine has been successfully added</Text>
              </Box>
              <Button icon={<FormClose />} onClick={this.onClose} plain />
            </Box>
          </Layer>
        )}
      </Grommet>
    );
  }
}

const MarginLayer = ({ margin, ...rest }) => (
  <Grommet theme={grommet}>
    <Layer
      margin={
        margin || { left: '40px', top: '50px', right: '30px', bottom: '10px' }
      }
      {...rest}
    >
      <Box height="small" overflow="auto">
        <Box pad="xlarge">text</Box>
        <Box pad="xlarge">text</Box>
        <Box pad="xlarge">text</Box>
        <Box pad="xlarge">text</Box>
        <Box pad="xlarge">text</Box>
        <Box pad="xlarge">text</Box>
      </Box>
    </Layer>
  </Grommet>
);

const PlainLayer = () => (
  <Grommet theme={grommet} full>
    <Box fill background="dark-3">
      <Layer margin="medium" plain>
        <Box pad="large" border={{ color: 'accent-1', size: 'large' }}>
          <Text color="accent-2">Text</Text>
        </Box>
      </Layer>
    </Box>
  </Grommet>
);

class FullLayer extends Component {
  state = {
    showLayer: false,
  };

  render() {
    const { showLayer } = this.state;
    return (
      <Grommet theme={grommet} full>
        <Box
          pad="small"
          fill
          background="dark-3"
          align="center"
          justify="center"
        >
          <Button
            primary
            color="accent-3"
            label="Show"
            onClick={() => this.setState({ showLayer: true })}
          />
          {showLayer && (
            <Layer full>
              <Box fill background="light-4" align="center" justify="center">
                <Button
                  primary
                  label="Close"
                  onClick={() => this.setState({ showLayer: false })}
                />
              </Box>
            </Layer>
          )}
        </Box>
      </Grommet>
    );
  }
}

const ScrollBodyLayer = () => (
  <Grommet theme={grommet}>
    <Layer full="vertical" position="right">
      <Box fill style={{ minWidth: '378px' }}>
        <Box
          direction="row"
          align="center"
          as="header"
          elevation="small"
          justify="between"
        >
          <Text margin={{ left: 'small' }}>Header</Text>
          <Button icon={<FormClose />} />
        </Box>
        <Box flex overflow="auto" pad="xsmall">
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
          body
        </Box>
        <Box
          as="footer"
          border={{ side: 'top' }}
          pad="small"
          justify="end"
          direction="row"
          align="center"
        >
          <Button primary label="Save" />
        </Box>
      </Box>
    </Layer>
  </Grommet>
);

storiesOf('Layer', module)
  .add('Center', () => <CenterLayer />)
  .add('CornerLayer', () => <CornerLayer />)
  .add('Form', () => <FormLayer />)
  .add('Notification', () => <NotificationLayer />)
  .add('Margin', () => <MarginLayer full />)
  .add('Margin (Center)', () => <MarginLayer margin="large" />)
  .add('Margin Top (Center)', () => (
    <MarginLayer margin={{ top: 'large' }} position="top" />
  ))
  .add('Plain', () => <PlainLayer />)
  .add('Full', () => <FullLayer />)
  .add('Fixed Header, Scroll Body', () => <ScrollBodyLayer />);
<|endoftext|>


<commit_before>var predictionio = require('predictionio-driver');
var models = require('../../../models');
var _ = require('lodash');
var async = require('async');
var log = require('../../../utils/logger');

var ACTIVE_CITIZEN_PIO_APP_ID = 1;

let postUpdateAsyncLimit = 42;

var getClient = function (appId) {
  return new predictionio.Events({appId: appId});
};

var lineCrCounter = 0;

var convertToString = function(integer) {
  return integer.toString();
};

var processDots = function() {
  if (lineCrCounter>250) {
    process.stdout.write("\n");
    lineCrCounter = 1;
  } else {
    process.stdout.write(".");
    lineCrCounter += 1;
  }
};

var importAllUsers = function (done) {
  var client = getClient(1);

  log.info('AcImportAllUsers', {});
  lineCrCounter = 0;
  models.User.findAll(
    {
      attributes: ['id','notifications_settings','email','name','created_at']
    }).then(function (users) {
    async.eachSeries(users, function (user, callback) {
      client.createUser( {
        appId: 1,
        uid: user.id,
        eventTime: user.created_at.toISOString()
      }).then(function(result) {
        processDots();
        //console.log(result);
        callback();
      }).catch(function(error) {
        console.error(error);
        callback();
      });
    }, function () {
      console.log("\n FIN");
      done();
    });
  });
};

var importFollowings = function (done) {
  var client = getClient(ACTIVE_CITIZEN_PIO_APP_ID);

  log.info('AcImportFollowings', {});
  lineCrCounter = 0;
  models.AcFollowing.findAll({
  }).then(function (followings) {
    async.eachSeries(followings, function (following, callback) {
      client.createAction({
        event: 'user-following',
        entityId: following.user_id,
        targetEntityId: following.other_user_id,
        targetEntityType: 'user',
        date: following.created_at.toISOString(),
        eventTime: following.created_at.toISOString()
      }).then(function(result) {
        processDots();
        callback();
      }).catch(function(error) {
        console.error(error);
        callback();
      });
    }, function () {
      console.log("\n FIN");
      done();
    });
  });
};

var updateAllPosts = function (done) {
  var client = getClient(ACTIVE_CITIZEN_PIO_APP_ID);
  log.info('AcImportAllPosts', {});

  models.Post.findAll(
    {
      include: [
        {
          model: models.Point,
          required: false,
          where: {
            status: 'published'
          }
        },
        {
          model: models.Category,
          required: false
        },
        {
          model: models.Group,
          required: true,
          include: [
            {
              model: models.Community,
              required: true,
              include: [
                {
                  model: models.Domain,
                  required: true
                }
              ]
            }
          ]
        }
      ]
    }).then(function (posts) {
    lineCrCounter = 0;
    async.eachOfLimit(posts, postUpdateAsyncLimit,function (post, index, callback) {

      var properties = {};

      if (post.category_id) {
        properties = _.merge(properties,
          {
            category: [ convertToString(post.category_id) ]
          });
      }
      properties = _.merge(properties,
        {
          domain: [ convertToString(post.Group.Community.Domain.id) ],
          domainLocale: [ post.Group.Community.Domain.default_locale ],

          community: [ convertToString(post.Group.Community.id) ],
          communityAccess: [ convertToString(post.Group.Community.access) ],
          communityStatus: [ post.Group.Community.status ],
          communityLocale: [ (post.Group.Community.default_locale && post.Group.Community.default_locale!='')  ?
                               post.Group.Community.default_locale :
                               post.Group.Community.Domain.default_locale ],

          group: [ convertToString(post.Group.id) ],
          groupAccess: [ convertToString(post.Group.access) ],
          groupStatus: [ convertToString(post.Group.status) ],

          status: [ post.deleted ? 'deleted' : post.status ],

          official_status: [ convertToString(post.official_status) ],
          language: [ (post.language && post.language!=='') ? post.language : "??" ]
        });

      properties = _.merge(properties,
        {
          date: post.created_at.toISOString()
        }
      );

      client.createItem({
        entityId: post.id,
        properties: properties,
        date: post.created_at.toISOString(),
        eventTime: post.created_at.toISOString()
      }).then(function(result) {
        //  console.log(result);
        if (post.category_id && !post.deleted) {
          client.createAction({
            event: 'category-preference',
            entityId: post.user_id,
            targetEntityId :post.category_id,
            date: post.created_at.toISOString(),
            eventTime: post.created_at.toISOString()
          }).then(function(result) {
            processDots();
            callback();
          });
        } else {
          processDots();
          callback();
        }
      }).catch(function(error) {
        console.error(error);
        callback();
      });
    }, function () {
      console.log("Finished updating posts");
      done();
    });
  });
};

var importAllActionsFor = function (model, where, include, action, done, attributes) {
  var client = getClient(ACTIVE_CITIZEN_PIO_APP_ID);
  log.info('AcImportAllActionsFor', {action:action, model: model, where: where, include: include});

  model.findAll(
    {
      where: where,
      include: include,
      attributes: attributes
    }
  ).then(function (objects) {
    lineCrCounter = 0;
    async.eachOfLimit(objects, 42, (object, index, callback) => {
      var targetEntityId;
      if (action.indexOf('help') > -1) {
        targetEntityId = object.Point.Post.id;
      } else if (action.indexOf('post') > -1) {
        targetEntityId = object.id;
      } else {
        targetEntityId = object.Post.id;
      }

      if (targetEntityId) {
        client.createAction({
          event: action,
          uid: object.user_id,
          targetEntityId: targetEntityId,
          date: object.created_at.toISOString(),
          eventTime: object.created_at.toISOString()
        }).then(function(result) {
          processDots();
          //       console.log(result);
          callback();
        }).
        catch(function(error) {
          console.error(error);
          callback();
        });
      } else {
        console.error("Can't find id for object: " + object);
        callback();
      }
    }, function (error) {
      console.log(error);
      console.log("\n FIN");
      done();
    });
  });
};

var importAll = function(done) {
  async.series([
    function(callback){
      importAllActionsFor(models.Post, {}, [], 'new-post', function () {
        callback();
      });
    },
    function(callback){
      importAllActionsFor(models.Endorsement, { value: { $gt: 0 } }, [ { model: models.Post, attributes: ['id'] }  ], 'endorse', function () {
        callback();
      }, ['id','user_id','created_at','value']);
    },
    function(callback){
      importAllActionsFor(models.Endorsement, { value: { $lt: 0 } }, [  { model: models.Post, attributes: ['id'] } ], 'oppose', function () {
        callback();
      }, ['id','user_id','created_at','value']);
    },
    function(callback){
      importAllActionsFor(models.Point, { value: { $ne: 0 }}, [ { model: models.Post, attributes: ['id'] } ], 'new-point', function () {
        callback();
      }, ['id','user_id','created_at','value']);
    },
    function(callback){
      importAllActionsFor(models.Point, { value: 0 },  [{ model: models.Post, attributes: ['id'] } ], 'new-point-comment', function () {
        callback();
      }, ['id','user_id','created_at','value']);
    },
    function(callback){
      importAllActionsFor(models.PointQuality, { value: { $gt: 0 } }, [{
          model: models.Point,
          attributes: ['id','value'],
          include: [{ model: models.Post, attributes: ['id'] } ]
        }], 'point-helpful', function () {
        callback();
      }, ['id','user_id','created_at','value']);
    },
    function(callback){
      importAllActionsFor(models.PointQuality, { value: { $lt: 0 } }, [{
        model: models.Point,
        attributes: ['id','value'],
        include: [ models.Post ]
      }], 'point-unhelpful', function () {
        callback();
      }, ['id','user_id','created_at','value']);
    },
    function(callback){
      updateAllPosts(function () {
        callback();
      });
    }
  ], function () {
    console.log("FIN");
    done();
  });
};

getClient(ACTIVE_CITIZEN_PIO_APP_ID).status().then(function(status) {
  console.log("status");
  console.log(status);
  log.info('AcImportStarting', {});
  if (process.argv[2] && process.argv[2]=="onlyUpdatePosts") {
    postUpdateAsyncLimit = 1;
    updateAllPosts(function () {
      console.log("Done updating posts");
      process.exit();
    });
  } else {
    importAll(function () {
      console.log("Done importing all");
      process.exit();
    });
  }
}).catch(function (error) {
  console.log("error");
  console.log(error);
});
<commit_msg>Optimize posts recommendation imports<commit_after>var predictionio = require('predictionio-driver');
var models = require('../../../models');
var _ = require('lodash');
var async = require('async');
var log = require('../../../utils/logger');

var ACTIVE_CITIZEN_PIO_APP_ID = 1;

let postUpdateAsyncLimit = 42;

var getClient = function (appId) {
  return new predictionio.Events({appId: appId});
};

var lineCrCounter = 0;

var convertToString = function(integer) {
  return integer.toString();
};

var processDots = function() {
  if (lineCrCounter>250) {
    process.stdout.write("\n");
    lineCrCounter = 1;
  } else {
    process.stdout.write(".");
    lineCrCounter += 1;
  }
};

var importAllUsers = function (done) {
  var client = getClient(1);

  log.info('AcImportAllUsers', {});
  lineCrCounter = 0;
  models.User.findAll(
    {
      attributes: ['id','notifications_settings','email','name','created_at']
    }).then(function (users) {
    async.eachSeries(users, function (user, callback) {
      client.createUser( {
        appId: 1,
        uid: user.id,
        eventTime: user.created_at.toISOString()
      }).then(function(result) {
        processDots();
        //console.log(result);
        callback();
      }).catch(function(error) {
        console.error(error);
        callback();
      });
    }, function () {
      console.log("\n FIN");
      done();
    });
  });
};

var importFollowings = function (done) {
  var client = getClient(ACTIVE_CITIZEN_PIO_APP_ID);

  log.info('AcImportFollowings', {});
  lineCrCounter = 0;
  models.AcFollowing.findAll({
  }).then(function (followings) {
    async.eachSeries(followings, function (following, callback) {
      client.createAction({
        event: 'user-following',
        entityId: following.user_id,
        targetEntityId: following.other_user_id,
        targetEntityType: 'user',
        date: following.created_at.toISOString(),
        eventTime: following.created_at.toISOString()
      }).then(function(result) {
        processDots();
        callback();
      }).catch(function(error) {
        console.error(error);
        callback();
      });
    }, function () {
      console.log("\n FIN");
      done();
    });
  });
};

var updateAllPosts = function (done) {
  var client = getClient(ACTIVE_CITIZEN_PIO_APP_ID);
  log.info('AcImportAllPosts', {});

  models.Post.findAll(
    {
      include: [
        {
          model: models.Group,
          required: true,
          attributes: ['id','access','status'],
          include: [
            {
              model: models.Community,
              attributes: ['id','access','status','default_locale'],
              required: true,
              include: [
                {
                  model: models.Domain,
                  attributes: ['id','default_locale'],
                  required: true
                }
              ]
            }
          ]
        }
      ],
      attributes: ['id','group_id','category_id','status','deleted','language','created_at','user_id','official_status']
    }).then(function (posts) {
    lineCrCounter = 0;
    async.eachOfLimit(posts, postUpdateAsyncLimit,function (post, index, callback) {

      var properties = {};

      if (post.category_id) {
        properties = _.merge(properties,
          {
            category: [ convertToString(post.category_id) ]
          });
      }
      properties = _.merge(properties,
        {
          domain: [ convertToString(post.Group.Community.Domain.id) ],
          domainLocale: [ post.Group.Community.Domain.default_locale ],

          community: [ convertToString(post.Group.Community.id) ],
          communityAccess: [ convertToString(post.Group.Community.access) ],
          communityStatus: [ post.Group.Community.status ],
          communityLocale: [ (post.Group.Community.default_locale && post.Group.Community.default_locale!='')  ?
                               post.Group.Community.default_locale :
                               post.Group.Community.Domain.default_locale ],

          group: [ convertToString(post.Group.id) ],
          groupAccess: [ convertToString(post.Group.access) ],
          groupStatus: [ convertToString(post.Group.status) ],

          status: [ post.deleted ? 'deleted' : post.status ],

          official_status: [ convertToString(post.official_status) ],
          language: [ (post.language && post.language!=='') ? post.language : "??" ]
        });

      properties = _.merge(properties,
        {
          date: post.created_at.toISOString()
        }
      );

      client.createItem({
        entityId: post.id,
        properties: properties,
        date: post.created_at.toISOString(),
        eventTime: post.created_at.toISOString()
      }).then(function(result) {
        //  console.log(result);
        if (post.category_id && !post.deleted) {
          client.createAction({
            event: 'category-preference',
            entityId: post.user_id,
            targetEntityId :post.category_id,
            date: post.created_at.toISOString(),
            eventTime: post.created_at.toISOString()
          }).then(function(result) {
            processDots();
            callback();
          });
        } else {
          processDots();
          callback();
        }
      }).catch(function(error) {
        console.error(error);
        callback();
      });
    }, function () {
      console.log("Finished updating posts");
      done();
    });
  });
};

var importAllActionsFor = function (model, where, include, action, done, attributes) {
  var client = getClient(ACTIVE_CITIZEN_PIO_APP_ID);
  log.info('AcImportAllActionsFor', {action:action, model: model, where: where, include: include});

  model.findAll(
    {
      where: where,
      include: include,
      attributes: attributes
    }
  ).then(function (objects) {
    lineCrCounter = 0;
    async.eachOfLimit(objects, 42, (object, index, callback) => {
      var targetEntityId;
      if (action.indexOf('help') > -1) {
        targetEntityId = object.Point.Post.id;
      } else if (action.indexOf('post') > -1) {
        targetEntityId = object.id;
      } else {
        targetEntityId = object.Post.id;
      }

      if (targetEntityId) {
        client.createAction({
          event: action,
          uid: object.user_id,
          targetEntityId: targetEntityId,
          date: object.created_at.toISOString(),
          eventTime: object.created_at.toISOString()
        }).then(function(result) {
          processDots();
          //       console.log(result);
          callback();
        }).
        catch(function(error) {
          console.error(error);
          callback();
        });
      } else {
        console.error("Can't find id for object: " + object);
        callback();
      }
    }, function (error) {
      console.log(error);
      console.log("\n FIN");
      done();
    });
  });
};

var importAll = function(done) {
  async.series([
    function(callback){
      importAllActionsFor(models.Post, {}, [], 'new-post', function () {
        callback();
      });
    },
    function(callback){
      importAllActionsFor(models.Endorsement, { value: { $gt: 0 } }, [ { model: models.Post, attributes: ['id'] }  ], 'endorse', function () {
        callback();
      }, ['id','user_id','created_at','value']);
    },
    function(callback){
      importAllActionsFor(models.Endorsement, { value: { $lt: 0 } }, [  { model: models.Post, attributes: ['id'] } ], 'oppose', function () {
        callback();
      }, ['id','user_id','created_at','value']);
    },
    function(callback){
      importAllActionsFor(models.Point, { value: { $ne: 0 }}, [ { model: models.Post, attributes: ['id'] } ], 'new-point', function () {
        callback();
      }, ['id','user_id','created_at','value']);
    },
    function(callback){
      importAllActionsFor(models.Point, { value: 0 },  [{ model: models.Post, attributes: ['id'] } ], 'new-point-comment', function () {
        callback();
      }, ['id','user_id','created_at','value']);
    },
    function(callback){
      importAllActionsFor(models.PointQuality, { value: { $gt: 0 } }, [{
          model: models.Point,
          attributes: ['id','value'],
          include: [{ model: models.Post, attributes: ['id'] } ]
        }], 'point-helpful', function () {
        callback();
      }, ['id','user_id','created_at','value']);
    },
    function(callback){
      importAllActionsFor(models.PointQuality, { value: { $lt: 0 } }, [{
        model: models.Point,
        attributes: ['id','value'],
        include: [ models.Post ]
      }], 'point-unhelpful', function () {
        callback();
      }, ['id','user_id','created_at','value']);
    },
    function(callback){
      updateAllPosts(function () {
        callback();
      });
    }
  ], function () {
    console.log("FIN");
    done();
  });
};

getClient(ACTIVE_CITIZEN_PIO_APP_ID).status().then(function(status) {
  console.log("status");
  console.log(status);
  log.info('AcImportStarting', {});
  if (process.argv[2] && process.argv[2]=="onlyUpdatePosts") {
    postUpdateAsyncLimit = 1;
    updateAllPosts(function () {
      console.log("Done updating posts");
      process.exit();
    });
  } else {
    importAll(function () {
      console.log("Done importing all");
      process.exit();
    });
  }
}).catch(function (error) {
  console.log("error");
  console.log(error);
});
<|endoftext|>


<commit_before>'use strict';
module.exports = function sessionController(models, app, logbook) {
    var fs = require('fs'),
        trabalhos = require('../settings').trabalhos,
        moment = require('moment'),
        nodemailer = require('nodemailer'),
        usuario = models.usuario;
    app.get('/api/trabalho', function (request, response) {
        // function (request, response, next)
        response.send(200);
    });
    app.post('/api/trabalho', function (request, response) {
        var entregaEncerrada = moment()
                .utc()
                .subtract('hours', 3)
                .isAfter(trabalhos.limite),
            fileType = request.files.file.type;
        if (entregaEncerrada) {
            response.send(410);
            logbook.error('Tentativa de envio de arquivo após o encerramento das submissões');
            return;
        }
        if (!request.authentication.inscricao) {
            response.send(500);
            logbook.error('Ouve uma tentativa de submissão não autenticada ou sem inscrição realizada');
        }
        if (
            fileType !== 'application/msword' &&
                fileType !== 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' &&
                fileType !== 'application/octet-stream'
        ) {
            response.send(500);
            logbook.error('Submissão de arquivo em formato inválido: ' + fileType);
            return;
        }
        fs.readFile(request.files.file.path, function (error, data) {
            var smtpTransport = nodemailer.createTransport('SMTP', {
                    service: 'Gmail',
                    auth: {
                        user: trabalhos.email,
                        pass: trabalhos.password
                    }
                }),
                mensagemDeAtencao = '\n\n\nAtenção, este e-mail foi enviado automaticamente. Não o responda. Em caso dúvidas ou quaisquer outras questões entre em contato com o administrador do sistema.';
            if (error) {
                response.send(500);
                logbook.error('Ocorreu o seguinte erro na leitura do arquivo submetido: ', error);
            }
            smtpTransport.sendMail({
                from: 'Trabalhos <trabalhos@ifnopapxviii.com.br>',
                to: trabalhos.email,
                subject: 'Trabalho submetido por ' + request.authentication.email,
                text: 'Em anexo o trabalho submetido por ' + request.authentication.email + mensagemDeAtencao,
                attachments: [{
                    fileName: request.files.file.originalFilename,
                    contents: data
                }]
            }, function sendMailHandler(error) {
                if (error) {
                    response.send(500);
                    logbook.error('Ocorreu o seguinte erro no envio do trabalho submetido: ', error);
                } else {
                    response.send(200);
                    smtpTransport.sendMail({
                        from: 'Trabalhos <trabalhos@ifnopapxviii.com.br>',
                        to: request.authentication.email,
                        subject: 'IFNOPAP XVIII - Seu trabalho foi enviado para avaliação',
                        text: 'Seu trabalho (no arquivo ' + request.files.file.originalFilename + ') foi enviado aos avaliadores!\nObrigado!' + mensagemDeAtencao
                    }, function (error) {
                        if (error) {
                            logbook.error('Ocorreu o seguinte erro no envio do e-mail de confirmação para o usuário ' + request.authentication.email, error);
                        }
                    });
                }
            });
        });
    });
};
<commit_msg>Definindo tipos de arquivos aceitos no arquivo de configuração<commit_after>'use strict';
module.exports = function sessionController(models, app, logbook) {
    var fs = require('fs'),
        trabalhos = require('../settings').trabalhos,
        moment = require('moment'),
        nodemailer = require('nodemailer'),
        usuario = models.usuario;
    app.get('/api/trabalho', function (request, response) {
        // function (request, response, next)
        response.send(200);
    });
    app.post('/api/trabalho', function (request, response) {
        var entregaEncerrada = moment()
                .utc()
                .subtract('hours', 3)
                .isAfter(trabalhos.limite),
            fileType = request.files.file.type;
        if (entregaEncerrada) {
            response.send(410);
            logbook.error('Tentativa de envio de arquivo após o encerramento das submissões');
            return;
        }
        if (!request.authentication.inscricao) {
            response.send(500);
            logbook.error('Ouve uma tentativa de submissão não autenticada ou sem inscrição realizada');
        }
        if (
            trabalhos.tiposAceitos.indexOf(fileType) === -1
        ) {
        // if (
        //     fileType !== 'application/msword' &&
        //         fileType !== 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' &&
        //         fileType !== 'application/octet-stream' &&
        //         // permitindo pdfs!
        //         fileType !== 'application/pdf'
        // ) {
            response.send(500);
            logbook.error('Submissão de arquivo em formato inválido: ' + fileType);
            return;
        }
        fs.readFile(request.files.file.path, function (error, data) {
            var smtpTransport = nodemailer.createTransport('SMTP', {
                    service: 'Gmail',
                    auth: {
                        user: trabalhos.email,
                        pass: trabalhos.password
                    }
                }),
                mensagemDeAtencao = '\n\n\nAtenção, este e-mail foi enviado automaticamente. Não o responda. Em caso dúvidas ou quaisquer outras questões entre em contato com o administrador do sistema.';
            if (error) {
                response.send(500);
                logbook.error('Ocorreu o seguinte erro na leitura do arquivo submetido: ', error);
            }
            smtpTransport.sendMail({
                from: 'Trabalhos <trabalhos@ifnopapxviii.com.br>',
                to: trabalhos.email,
                subject: 'Trabalho submetido por ' + request.authentication.email,
                text: 'Em anexo o trabalho submetido por ' + request.authentication.email + mensagemDeAtencao,
                attachments: [{
                    fileName: request.files.file.originalFilename,
                    contents: data
                }]
            }, function sendMailHandler(error) {
                if (error) {
                    response.send(500);
                    logbook.error('Ocorreu o seguinte erro no envio do trabalho submetido: ', error);
                } else {
                    response.send(200);
                    smtpTransport.sendMail({
                        from: 'Trabalhos <trabalhos@ifnopapxviii.com.br>',
                        to: request.authentication.email,
                        subject: 'IFNOPAP XVIII - Seu trabalho foi enviado para avaliação',
                        text: 'Seu trabalho (no arquivo ' + request.files.file.originalFilename + ') foi enviado aos avaliadores!\nObrigado!' + mensagemDeAtencao
                    }, function (error) {
                        if (error) {
                            logbook.error('Ocorreu o seguinte erro no envio do e-mail de confirmação para o usuário ' + request.authentication.email, error);
                        }
                    });
                }
            });
        });
    });
};
<|endoftext|>