<commit_before>// An singleton that contains and manages the sending of picpilot commands
var picpilot_config=require('../../config/picpilot-config');
var Network=require('../Network');
var Logger=require('../util/Logger');
var Validator=require('../util/Validator');
var SimulationManager=require("../SimulationManager");
var AircraftStatus=require('../AircraftStatus');
var Coordinates=require('../models/Coordinates');

var Commands={
  checkConnection: function(){ //to make sure the data relay connection exists first (otherwise we'll prob get weird errors)
    if(SimulationManager.simulationActive){ //just return false if the simulation is active
      return false;
    }

    if(Network.connections['data_relay'] && !Network.connections['data_relay'].closed){
      return true;
    }
    else{
      Logger.warn('Cannot send command as the data_relay connection has not yet been established or the connection is closed');
      return false;
    }
  },
  sendProtectedCommand:function(command){
    if(this.checkConnection()){
      Network.connections['data_relay'].write(command+':'+picpilot_config.get('command_password')+'\r\n');
      return true;
    }
    if(SimulationManager.simulationActive){
      Logger.info('[Simulation] Successfully sent command '+command+':'+picpilot_config.get('command_password')+'\r\n');
      return true;
    }
    return false;
  },
  sendCommand: function(command, value){ //value can be an indefinte number of arguments
    var value_string='';
    for(var arg=1;arg<arguments.length-1;arg++){ //we start at one cause we only care about the values
      value_string+=arguments[arg]+',';
    };
    value_string+=arguments[arguments.length-1];

    if(this.checkConnection()){
      Network.connections['data_relay'].write(command+':'+value_string+'\r\n');
      return true;
    }
    if(SimulationManager.simulationActive){
      Logger.info('[Simulation] Successfully sent command '+command+':'+value_string+'\r\n');
      return true;
    }
    return false;
  },
  sendRawCommand: function(command){
    if(this.checkConnection()){
      Network.connections['data_relay'].write(command+'\r\n');
      return true;
    }
    if(SimulationManager.simulationActive){
      Logger.info('[Simulation] Successfully sent command: '+command);
      return true;
    }
    return false;
  },
  activateWriteMode: function(){
    this.sendRawCommand('commander');
  },
  sendRoll: function(roll){
    if(Validator.isValidRoll(roll)){
      this.sendCommand('set_rollAngle',roll);
    }
    else{
      Logger.error('Command to not sent since invalid roll value detected! Roll:'+roll);
    }
  },
  sendPitch: function(pitch){
    if(Validator.isValidPitch(pitch)){
      this.sendCommand('set_pitchAngle',pitch);
    }
    else{
      Logger.error('Command to not sent since invalid pitch value detected! Pitch:'+pitch);
    }
  },
  sendHeading: function(heading){
    if(Validator.isValidHeading(heading)){
      this.sendCommand('set_heading',heading);
    }
    else{
      Logger.error('Command to not sent since invalid heading value detected! Heading:'+heading);
    }
  },
  sendAltitude:function(altitude){
    if(Validator.isValidAltitude(altitude)){
      this.sendCommand('set_altitude',altitude);
    }
    else{
      Logger.error('Command to not sent since invalid altitude value detected! Altitude:'+altitude);
    }
  },
  sendThrottle:function(throttle){
    if(Validator.isValidPercentage(throttle)){
      this.sendCommand('set_throttle',(Number(throttle)*2048/100-1024).toFixed(0));
    }
    else{
      Logger.error('Command to not sent since invalid throttle value detected! Throttle:'+throttle);
    }
  },
  sendFlap:function(flap){
    if(Validator.isValidPercentage(flap)){
      this.sendCommand('set_flap',(Number(flap)*2048/100-1024).toFixed(0));
    }
    else{
      Logger.error('Command to not sent since invalid flap value detected! Flap Setpoint:'+flap);
    }
  },
  sendKPGain: function(type,gain){
    if(Validator.isValidNumber(gain)){
      this.sendCommand('set_'+type+'KPGain',gain);
    }
    else{
      Logger.error('Command to not sent since invalid gain value detected! Gain value:'+gain);
    }
  },
  sendKIGain: function(type, gain){
    if(Validator.isValidNumber(gain)){
      this.sendCommand('set_'+type+'KIGain',gain);
    }
    else{
      Logger.error('Command to not sent since invalid gain value detected! Gain value:'+gain);
    }
  },
  sendKDGain: function(type, gain){
    if(Validator.isValidNumber(gain)){
      this.sendCommand('set_'+type+'KDGain',gain);
    }
    else{
      Logger.error('Command to not sent since invalid gain value detected! Gain value:'+gain);
    }
  },
  sendPathGain: function(gain){
    if(Validator.isValidNumber(gain)){
      this.sendCommand('set_pathGain',gain);
    }
    else{
      Logger.error('Command to not sent since invalid path gain value detected! Gain value:'+gain);
    }
  },
  sendOrbitGain: function(gain){
    if(Validator.isValidNumber(gain)){
      this.sendCommand('set_orbitGain',gain);
    }
    else{
      Logger.error('Command to not sent since invalid orbit gain value detected! Gain value:'+gain);
    }
  },
  showGain: function(value){
    if(Validator.isValidNumber(value)){
      this.sendCommand('set_showGain',value);
    }
    else{
      Logger.error('Command to not sent since invalid show gain value detected! Value:'+value);
    }
  },
  sendAutoLevel: function(level){
    if(Validator.isValidNumber(level)){
      this.sendCommand('set_autonomousLevel', level);
    }
    else{
      Logger.error('Command not sent since invalid autonomous level value detected! Value: '+level);
    }
  },
  armPlane: function(){
    this.sendProtectedCommand('arm_vehicle');
  },
  disarmPlane: function(){
    this.sendProtectedCommand('dearm_vehicle');
  },
  killPlane: function(){
    this.sendProtectedCommand('kill_plane');
  },
  unkillPlane: function(){
    this.sendProtectedCommand('unkill_plane');
  },
  dropProbe: function(){
    this.sendCommand('drop_probe',1);
  },
  resetProbe: function(){
    this.sendCommand('reset_probe',1);
  },
  clearWaypoints: function(){
    this.sendCommand('clear_waypoints',1);
  },
  setTargetWaypoint: function(number){
    if(Validator.isValidNumber(number)){
      this.sendCommand('set_targetWaypoint', number);
    }
    else{
      Logger.error('setTargetWaypoint command not since invalid waypoint number was passed in. Number: '+number);
    }
  },
  removeWaypoint: function(number){
    if(Validator.isValidNumber(number)){
      this.sendCommand('remove_waypoint', number);
    }
    else{
      Logger.error('removeWaypoint command not since invalid waypoint number was passed in. Number: '+number);
    }
  },
  returnHome: function(){
    this.sendCommand('return_home',1);
  },
  cancelReturnHome: function(){
    this.sendCommand('cancel_returnHome',1);
  },
  setReturnHome: function(coordinates){
    var coords=Coordinates(coordinates);
    if(coords && coords.alt){
      this.sendCommand('set_ReturnHomeCoordinates',coords.lat, coords.lng, coords.alt);
    }
    else{
      Logger.error('setReturnHome command not since invalid coordinates were passed in. Coordinates: '+coordinates);
    }
  },
  appendWaypoint: function(coordinates, radius){
    var coords=Coordinates(coordinates);
    if(coords && coords.alt && Validator.isValidNumber(radius)){
      this.sendCommand('new_Waypoint',coords.lat,coords.lng,coords.alt,radius);
    }
    else{
      Logger.error('appendWaypoint command not since invalid coordinates were passed in. Coordinates: '+coordinates);
    }
  },
  insertWaypoint: function(index,coordinates, radius){
    var coords=Coordinates(coordinates);
    if(Validator.isInteger(index) && coords && coords.alt && Validator.isValidNumber(radius)){
      this.sendCommand('insert_Waypoint',coords.lat, coords.lng, coords.alt, radius, index-1, index+1);
    }
    else{
      Logger.error('insertWaypoint command not since invalid waypoint number or coordinates were passed in. Index: '+index);
    }
  },
  followPath: function(status){
    if(status){
      this.sendCommand('follow_path',1);
    }
    else{
      this.sendCommand('follow_path',0);
    }
  },
  sendHeartbeat: function(){
    if(this.sendCommand('send_heartbeat',1)){
      Logger.debug('[HEARTBEAT] Sent heartbeat to the picpilot');
    }
  }
};
module.exports=Commands;<commit_msg>Fixed append waypoint command<commit_after>// An singleton that contains and manages the sending of picpilot commands
var picpilot_config=require('../../config/picpilot-config');
var Network=require('../Network');
var Logger=require('../util/Logger');
var Validator=require('../util/Validator');
var SimulationManager=require("../SimulationManager");
var AircraftStatus=require('../AircraftStatus');
var Coordinates=require('../models/Coordinates');

var Commands={
  checkConnection: function(){ //to make sure the data relay connection exists first (otherwise we'll prob get weird errors)
    if(SimulationManager.simulationActive){ //just return false if the simulation is active
      return false;
    }

    if(Network.connections['data_relay'] && !Network.connections['data_relay'].closed){
      return true;
    }
    else{
      Logger.warn('Cannot send command as the data_relay connection has not yet been established or the connection is closed');
      return false;
    }
  },
  sendProtectedCommand:function(command){
    if(this.checkConnection()){
      Network.connections['data_relay'].write(command+':'+picpilot_config.get('command_password')+'\r\n');
      return true;
    }
    if(SimulationManager.simulationActive){
      Logger.info('[Simulation] Successfully sent command '+command+':'+picpilot_config.get('command_password')+'\r\n');
      return true;
    }
    return false;
  },
  sendCommand: function(command, value){ //value can be an indefinte number of arguments
    var value_string='';
    for(var arg=1;arg<arguments.length-1;arg++){ //we start at one cause we only care about the values
      value_string+=arguments[arg]+',';
    };
    value_string+=arguments[arguments.length-1];

    if(this.checkConnection()){
      Network.connections['data_relay'].write(command+':'+value_string+'\r\n');
      return true;
    }
    if(SimulationManager.simulationActive){
      Logger.info('[Simulation] Successfully sent command '+command+':'+value_string+'\r\n');
      return true;
    }
    return false;
  },
  sendRawCommand: function(command){
    if(this.checkConnection()){
      Network.connections['data_relay'].write(command+'\r\n');
      return true;
    }
    if(SimulationManager.simulationActive){
      Logger.info('[Simulation] Successfully sent command: '+command);
      return true;
    }
    return false;
  },
  activateWriteMode: function(){
    this.sendRawCommand('commander');
  },
  sendRoll: function(roll){
    if(Validator.isValidRoll(roll)){
      this.sendCommand('set_rollAngle',roll);
    }
    else{
      Logger.error('Command to not sent since invalid roll value detected! Roll:'+roll);
    }
  },
  sendPitch: function(pitch){
    if(Validator.isValidPitch(pitch)){
      this.sendCommand('set_pitchAngle',pitch);
    }
    else{
      Logger.error('Command to not sent since invalid pitch value detected! Pitch:'+pitch);
    }
  },
  sendHeading: function(heading){
    if(Validator.isValidHeading(heading)){
      this.sendCommand('set_heading',heading);
    }
    else{
      Logger.error('Command to not sent since invalid heading value detected! Heading:'+heading);
    }
  },
  sendAltitude:function(altitude){
    if(Validator.isValidAltitude(altitude)){
      this.sendCommand('set_altitude',altitude);
    }
    else{
      Logger.error('Command to not sent since invalid altitude value detected! Altitude:'+altitude);
    }
  },
  sendThrottle:function(throttle){
    if(Validator.isValidPercentage(throttle)){
      this.sendCommand('set_throttle',(Number(throttle)*2048/100-1024).toFixed(0));
    }
    else{
      Logger.error('Command to not sent since invalid throttle value detected! Throttle:'+throttle);
    }
  },
  sendFlap:function(flap){
    if(Validator.isValidPercentage(flap)){
      this.sendCommand('set_flap',(Number(flap)*2048/100-1024).toFixed(0));
    }
    else{
      Logger.error('Command to not sent since invalid flap value detected! Flap Setpoint:'+flap);
    }
  },
  sendKPGain: function(type,gain){
    if(Validator.isValidNumber(gain)){
      this.sendCommand('set_'+type+'KPGain',gain);
    }
    else{
      Logger.error('Command to not sent since invalid gain value detected! Gain value:'+gain);
    }
  },
  sendKIGain: function(type, gain){
    if(Validator.isValidNumber(gain)){
      this.sendCommand('set_'+type+'KIGain',gain);
    }
    else{
      Logger.error('Command to not sent since invalid gain value detected! Gain value:'+gain);
    }
  },
  sendKDGain: function(type, gain){
    if(Validator.isValidNumber(gain)){
      this.sendCommand('set_'+type+'KDGain',gain);
    }
    else{
      Logger.error('Command to not sent since invalid gain value detected! Gain value:'+gain);
    }
  },
  sendPathGain: function(gain){
    if(Validator.isValidNumber(gain)){
      this.sendCommand('set_pathGain',gain);
    }
    else{
      Logger.error('Command to not sent since invalid path gain value detected! Gain value:'+gain);
    }
  },
  sendOrbitGain: function(gain){
    if(Validator.isValidNumber(gain)){
      this.sendCommand('set_orbitGain',gain);
    }
    else{
      Logger.error('Command to not sent since invalid orbit gain value detected! Gain value:'+gain);
    }
  },
  showGain: function(value){
    if(Validator.isValidNumber(value)){
      this.sendCommand('set_showGain',value);
    }
    else{
      Logger.error('Command to not sent since invalid show gain value detected! Value:'+value);
    }
  },
  sendAutoLevel: function(level){
    if(Validator.isValidNumber(level)){
      this.sendCommand('set_autonomousLevel', level);
    }
    else{
      Logger.error('Command not sent since invalid autonomous level value detected! Value: '+level);
    }
  },
  armPlane: function(){
    this.sendProtectedCommand('arm_vehicle');
  },
  disarmPlane: function(){
    this.sendProtectedCommand('dearm_vehicle');
  },
  killPlane: function(){
    this.sendProtectedCommand('kill_plane');
  },
  unkillPlane: function(){
    this.sendProtectedCommand('unkill_plane');
  },
  dropProbe: function(){
    this.sendCommand('drop_probe',1);
  },
  resetProbe: function(){
    this.sendCommand('reset_probe',1);
  },
  clearWaypoints: function(){
    this.sendCommand('clear_waypoints',1);
  },
  setTargetWaypoint: function(number){
    if(Validator.isValidNumber(number)){
      this.sendCommand('set_targetWaypoint', number);
    }
    else{
      Logger.error('setTargetWaypoint command not since invalid waypoint number was passed in. Number: '+number);
    }
  },
  removeWaypoint: function(number){
    if(Validator.isValidNumber(number)){
      this.sendCommand('remove_waypoint', number);
    }
    else{
      Logger.error('removeWaypoint command not since invalid waypoint number was passed in. Number: '+number);
    }
  },
  returnHome: function(){
    this.sendCommand('return_home',1);
  },
  cancelReturnHome: function(){
    this.sendCommand('cancel_returnHome',1);
  },
  setReturnHome: function(coordinates){
    var coords=Coordinates(coordinates);
    if(coords && coords.alt){
      this.sendCommand('set_ReturnHomeCoordinates',coords.lat, coords.lng, coords.alt);
    }
    else{
      Logger.error('setReturnHome command not since invalid coordinates were passed in. Coordinates: '+coordinates);
    }
  },
  appendWaypoint: function(coordinates, radius){
    var coords=Coordinates(coordinates);
    if(coords && coords.alt && Validator.isValidNumber(radius)){
      this.sendCommand('new_waypoint',coords.lat,coords.lng,coords.alt,radius);
    }
    else{
      Logger.error('appendWaypoint command not since invalid coordinates were passed in. Coordinates: '+coordinates);
    }
  },
  insertWaypoint: function(index,coordinates, radius){
    var coords=Coordinates(coordinates);
    if(Validator.isInteger(index) && coords && coords.alt && Validator.isValidNumber(radius)){
      this.sendCommand('insert_Waypoint',coords.lat, coords.lng, coords.alt, radius, index-1, index+1);
    }
    else{
      Logger.error('insertWaypoint command not since invalid waypoint number or coordinates were passed in. Index: '+index);
    }
  },
  followPath: function(status){
    if(status){
      this.sendCommand('follow_path',1);
    }
    else{
      this.sendCommand('follow_path',0);
    }
  },
  sendHeartbeat: function(){
    if(this.sendCommand('send_heartbeat',1)){
      Logger.debug('[HEARTBEAT] Sent heartbeat to the picpilot');
    }
  }
};
module.exports=Commands;<|endoftext|>


<commit_before>import getRenderWrapper from '@salesforce/apex/GE_TemplateBuilderCtrl.retrieveDefaultSGERenderWrapper';
import getAllocationSettings from '@salesforce/apex/GE_FormRendererService.getAllocationsSettings';
import saveAndProcessGift from '@salesforce/apex/GE_FormRendererService.saveAndProcessSingleGift';
import { handleError } from 'c/utilTemplateBuilder';
import saveAndDryRunRow
    from '@salesforce/apex/BGE_DataImportBatchEntry_CTRL.saveAndDryRunRow';
import {api} from "lwc";
import { isNotEmpty } from 'c/utilCommon';
import getFormRenderWrapper
    from '@salesforce/apex/GE_FormServiceController.getFormRenderWrapper';

// https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_enum_Schema_DisplayType.htm
// this list only includes fields that can be handled by lightning-input
const inputTypeByDescribeType = {
    'BOOLEAN': 'checkbox',
    'CURRENCY': 'number',
    'DATE': 'date',
    'DATETIME': 'datetime-local',
    'EMAIL': 'email',
    'DOUBLE': 'number',
    'INTEGER': 'number',
    'LONG': 'number',
    'PERCENT': 'number',
    'STRING': 'text',
    'PHONE': 'tel',
    'TEXT': 'text',
    'TIME': 'time',
    'URL': 'url'
};

const numberFormatterByDescribeType = {
  'PERCENT': 'percent-fixed'
};

class GeFormService {

    fieldMappings;
    objectMappings;
    fieldTargetMappings;

    /**
     * Retrieve the default form render wrapper.
     * @returns {Promise<FORM_RenderWrapper>}
     */
    @api
    getFormTemplate() {
        return new Promise((resolve, reject) => {
            getRenderWrapper({})
                .then((result) => {
                    this.fieldMappings = result.fieldMappingSetWrapper.fieldMappingByDevName;
                    this.objectMappings = result.fieldMappingSetWrapper.objectMappingByDevName;
                    this.fieldTargetMappings = result.fieldMappingSetWrapper.fieldMappingByTargetFieldName;
                    resolve(result);
                })
                .catch(error => {
                    handleError(error);
                });
        });
    }

    getAllocationSettings() {
        return new Promise((resolve, reject) => {
           getAllocationSettings()
               .then(resolve)
               .catch(handleError)
        });
    }

    /**
     * Get the type of lightning-input that should be used for a given field type.
     * @param dataType  Data type of the field
     * @returns {String}
     */
    getInputTypeFromDataType(dataType) {
        return inputTypeByDescribeType[dataType];
    }

    /**
     * Get the formatter for a lightning-input that should be used for a given field type
     * @param dataType  Data type of the field
     * @returns {String | undefined}
     */
    getNumberFormatterByDescribeType(dataType) {
        return numberFormatterByDescribeType[dataType];
    }

    /**
     * Get a field info object by dev name from the render wrapper object
     * @param fieldDevName  Dev name of the object to retrieve
     * @returns {BDI_FieldMapping}
     */
    getFieldMappingWrapper(fieldDevName) {
        return this.fieldMappings[fieldDevName];
    }

    /**
     * Get a field info object by dev name from the render wrapper object
     * @param fieldDevName  Dev name of the object to retrieve
     * @returns {BDI_FieldMapping}
     */
    getFieldMappingWrapperFromTarget(targetFieldName) {
        return this.fieldTargetMappings[targetFieldName];
    }

    /**
     * Get a object info object by dev name from the render wrapper object
     * @param objectDevName
     * @returns {BDI_ObjectMapping}
     */
    getObjectMappingWrapper(objectDevName) {
        return this.objectMappings[objectDevName];
    }

    /**
     * Takes a Data Import record and additional object data, processes it, and returns the new Opportunity created from it.
     * @param createdDIRecord
     * @param widgetValues
     * @returns {Promise<Id>}
     */
    saveAndProcessGift(createdDIRecord, widgetValues, hasUserSelectedDonation = false) {
        const widgetDataString = JSON.stringify(widgetValues);
        return new Promise((resolve, reject) => {
            saveAndProcessGift({
                    diRecord: createdDIRecord,
                    widgetData: widgetDataString,
                    updateGift: hasUserSelectedDonation
                })
                .then((result) => {
                    resolve(result);
                })
                .catch(error => {
                    console.error(JSON.stringify(error));
                    reject(error);
                });
        });
    }

    /**
     * Takes a list of sections, reads the fields and values, creates a di record, and creates an opportunity from the di record
     * @param sectionList
     * @returns opportunityId
     */
    handleSave(sectionList, record, dataImportRecord) {
        const { diRecord, widgetValues } = this.getDataImportRecord(sectionList, record, dataImportRecord);

        const hasUserSelectedDonation = isNotEmpty(dataImportRecord);

        const opportunityID = this.saveAndProcessGift(diRecord, widgetValues, hasUserSelectedDonation);

        return opportunityID;
    }

    /**
     * Grab the data from the form fields and widgets, convert to a data import record.
     * @param sectionList   List of ge-form-sections on the form
     * @param record        Existing account or contact record to attach to the data import record
     * @return {{widgetValues: {}, diRecord: {}}}
     */
    getDataImportRecord(sectionList, record, dataImportRecord){
        // Gather all the data from the input
        let fieldData = {};
        let widgetValues = {};

        sectionList.forEach(section => {
            fieldData = { ...fieldData, ...(section.values)};
            widgetValues = { ...widgetValues, ...(section.widgetValues)};
        });

        // Build the DI Record
        let diRecord = {};

        for (let key in fieldData) {
            if (fieldData.hasOwnProperty(key)) {
                let value = fieldData[key];

                // Get the field mapping wrapper with the CMT record name (this is the key variable).
                let fieldWrapper = this.getFieldMappingWrapper(key);

                if (value) {
                    diRecord[fieldWrapper.Source_Field_API_Name] = value;
                }
            }
        }

        // Include any fields from a user selected donation
        diRecord = { ...diRecord, ...dataImportRecord };

        return { diRecord, widgetValues };
    }

    saveAndDryRun(batchId, dataImport) {
        return new Promise((resolve, reject) => {
            saveAndDryRunRow({batchId: batchId, dataImport: dataImport})
                .then((result) => {
                    resolve(JSON.parse(result));
                })
                .catch(error => {
                    reject(error);
                });
        });
    }

    getFormRenderWrapper(templateId) {
        return new Promise((resolve, reject) => {
            getFormRenderWrapper({templateId: templateId})
                .then(renderWrapper => {
                    this.fieldMappings =
                        renderWrapper.fieldMappingSetWrapper.fieldMappingByDevName;
                    this.objectMappings =
                        renderWrapper.fieldMappingSetWrapper.objectMappingByDevName;
                    resolve(renderWrapper);
                })
                .catch(err => {
                    reject(err);
                });
        });

    }

    getFormTemplateById(templateId) {
        return new Promise((resolve, reject) => {
            this.getFormRenderWrapper(templateId)
                .then(renderWrapper => {
                    resolve(renderWrapper.formTemplate);
                })
                .catch(err => {
                    reject(err);
                });
        });
    }

}

const geFormServiceInstance = new GeFormService();

export default geFormServiceInstance;<commit_msg>Fix loading in batch mode<commit_after>import getRenderWrapper from '@salesforce/apex/GE_TemplateBuilderCtrl.retrieveDefaultSGERenderWrapper';
import getAllocationSettings from '@salesforce/apex/GE_FormRendererService.getAllocationsSettings';
import saveAndProcessGift from '@salesforce/apex/GE_FormRendererService.saveAndProcessSingleGift';
import { handleError } from 'c/utilTemplateBuilder';
import saveAndDryRunRow
    from '@salesforce/apex/BGE_DataImportBatchEntry_CTRL.saveAndDryRunRow';
import {api} from "lwc";
import { isNotEmpty } from 'c/utilCommon';
import getFormRenderWrapper
    from '@salesforce/apex/GE_FormServiceController.getFormRenderWrapper';

// https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_enum_Schema_DisplayType.htm
// this list only includes fields that can be handled by lightning-input
const inputTypeByDescribeType = {
    'BOOLEAN': 'checkbox',
    'CURRENCY': 'number',
    'DATE': 'date',
    'DATETIME': 'datetime-local',
    'EMAIL': 'email',
    'DOUBLE': 'number',
    'INTEGER': 'number',
    'LONG': 'number',
    'PERCENT': 'number',
    'STRING': 'text',
    'PHONE': 'tel',
    'TEXT': 'text',
    'TIME': 'time',
    'URL': 'url'
};

const numberFormatterByDescribeType = {
  'PERCENT': 'percent-fixed'
};

class GeFormService {

    fieldMappings;
    objectMappings;
    fieldTargetMappings;

    /**
     * Retrieve the default form render wrapper.
     * @returns {Promise<FORM_RenderWrapper>}
     */
    @api
    getFormTemplate() {
        return new Promise((resolve, reject) => {
            getRenderWrapper({})
                .then((result) => {
                    this.fieldMappings = result.fieldMappingSetWrapper.fieldMappingByDevName;
                    this.objectMappings = result.fieldMappingSetWrapper.objectMappingByDevName;
                    this.fieldTargetMappings = result.fieldMappingSetWrapper.fieldMappingByTargetFieldName;
                    resolve(result);
                })
                .catch(error => {
                    handleError(error);
                });
        });
    }

    getAllocationSettings() {
        return new Promise((resolve, reject) => {
           getAllocationSettings()
               .then(resolve)
               .catch(handleError)
        });
    }

    /**
     * Get the type of lightning-input that should be used for a given field type.
     * @param dataType  Data type of the field
     * @returns {String}
     */
    getInputTypeFromDataType(dataType) {
        return inputTypeByDescribeType[dataType];
    }

    /**
     * Get the formatter for a lightning-input that should be used for a given field type
     * @param dataType  Data type of the field
     * @returns {String | undefined}
     */
    getNumberFormatterByDescribeType(dataType) {
        return numberFormatterByDescribeType[dataType];
    }

    /**
     * Get a field info object by dev name from the render wrapper object
     * @param fieldDevName  Dev name of the object to retrieve
     * @returns {BDI_FieldMapping}
     */
    getFieldMappingWrapper(fieldDevName) {
        return this.fieldMappings[fieldDevName];
    }

    /**
     * Get a field info object by dev name from the render wrapper object
     * @param fieldDevName  Dev name of the object to retrieve
     * @returns {BDI_FieldMapping}
     */
    getFieldMappingWrapperFromTarget(targetFieldName) {
        return this.fieldTargetMappings[targetFieldName];
    }

    /**
     * Get a object info object by dev name from the render wrapper object
     * @param objectDevName
     * @returns {BDI_ObjectMapping}
     */
    getObjectMappingWrapper(objectDevName) {
        return this.objectMappings[objectDevName];
    }

    /**
     * Takes a Data Import record and additional object data, processes it, and returns the new Opportunity created from it.
     * @param createdDIRecord
     * @param widgetValues
     * @returns {Promise<Id>}
     */
    saveAndProcessGift(createdDIRecord, widgetValues, hasUserSelectedDonation = false) {
        const widgetDataString = JSON.stringify(widgetValues);
        return new Promise((resolve, reject) => {
            saveAndProcessGift({
                    diRecord: createdDIRecord,
                    widgetData: widgetDataString,
                    updateGift: hasUserSelectedDonation
                })
                .then((result) => {
                    resolve(result);
                })
                .catch(error => {
                    console.error(JSON.stringify(error));
                    reject(error);
                });
        });
    }

    /**
     * Takes a list of sections, reads the fields and values, creates a di record, and creates an opportunity from the di record
     * @param sectionList
     * @returns opportunityId
     */
    handleSave(sectionList, record, dataImportRecord) {
        const { diRecord, widgetValues } = this.getDataImportRecord(sectionList, record, dataImportRecord);

        const hasUserSelectedDonation = isNotEmpty(dataImportRecord);

        const opportunityID = this.saveAndProcessGift(diRecord, widgetValues, hasUserSelectedDonation);

        return opportunityID;
    }

    /**
     * Grab the data from the form fields and widgets, convert to a data import record.
     * @param sectionList   List of ge-form-sections on the form
     * @param record        Existing account or contact record to attach to the data import record
     * @return {{widgetValues: {}, diRecord: {}}}
     */
    getDataImportRecord(sectionList, record, dataImportRecord){
        // Gather all the data from the input
        let fieldData = {};
        let widgetValues = {};

        sectionList.forEach(section => {
            fieldData = { ...fieldData, ...(section.values)};
            widgetValues = { ...widgetValues, ...(section.widgetValues)};
        });

        // Build the DI Record
        let diRecord = {};

        for (let key in fieldData) {
            if (fieldData.hasOwnProperty(key)) {
                let value = fieldData[key];

                // Get the field mapping wrapper with the CMT record name (this is the key variable).
                let fieldWrapper = this.getFieldMappingWrapper(key);

                if (value) {
                    diRecord[fieldWrapper.Source_Field_API_Name] = value;
                }
            }
        }

        // Include any fields from a user selected donation
        diRecord = { ...diRecord, ...dataImportRecord };

        return { diRecord, widgetValues };
    }

    saveAndDryRun(batchId, dataImport) {
        return new Promise((resolve, reject) => {
            saveAndDryRunRow({batchId: batchId, dataImport: dataImport})
                .then((result) => {
                    resolve(JSON.parse(result));
                })
                .catch(error => {
                    reject(error);
                });
        });
    }

    getFormRenderWrapper(templateId) {
        return new Promise((resolve, reject) => {
            getFormRenderWrapper({templateId: templateId})
                .then(renderWrapper => {
                    this.fieldMappings =
                        renderWrapper.fieldMappingSetWrapper.fieldMappingByDevName;
                    this.objectMappings =
                        renderWrapper.fieldMappingSetWrapper.objectMappingByDevName;
                    this.fieldTargetMappings =
                        renderWrapper.fieldMappingSetWrapper.fieldMappingByTargetFieldName;

                    resolve(renderWrapper);
                })
                .catch(err => {
                    reject(err);
                });
        });

    }

    getFormTemplateById(templateId) {
        return new Promise((resolve, reject) => {
            this.getFormRenderWrapper(templateId)
                .then(renderWrapper => {
                    resolve(renderWrapper.formTemplate);
                })
                .catch(err => {
                    reject(err);
                });
        });
    }

}

const geFormServiceInstance = new GeFormService();

export default geFormServiceInstance;<|endoftext|>


<commit_before>/*
 * HomePage
 *
 * This is the first thing users see of our App, at the '/' route
 */

import React, { Component, PropTypes } from 'react';
import Helmet from 'react-helmet';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import { createStructuredSelector } from 'reselect';
import _ from 'underscore';
import { getProducts } from './actions';
import { selectProducts } from './selectors';
import Body from '../../components/styled/Body';
import H2 from '../../components/styled/H2';
import FlatButton from 'material-ui/FlatButton';
import AddIcon from 'material-ui/svg-icons/content/add';
import FileUploadIcon from 'material-ui/svg-icons/file/file-upload';
import Menu from '../../components/partials/Menu';
import {
  Table,
  TableHeader,
  TableRow,
  TableHeaderColumn,
  TableBody,
  TableRowColumn,
} from 'material-ui/Table';

class CatalogPage extends Component {

  componentDidMount() {
    if (this.props.products.length === 0) {
      this.props.getProducts();
    }
  }

  renderProducts = () => {
    const { products } = this.props;
    return _.map(products, (product, i) => (
      <TableRow key={i}>
        <TableRowColumn><Link to={`/product/${product.Id}`}>{product.Name}</Link></TableRowColumn>
        <TableRowColumn>
          <div
            style={product.MainImageUri ? {
              backgroundImage: `url(${product.MainImageUri})`,
              backgroundSize: 'cover',
              backgroundRepeat: 'no-repeat',
              height: 50,
              width: 50,
            } : {
              background: 'repeating-linear-gradient(45deg,transparent,transparent 10px,#ccc 10px,#ccc 20px)',
              height: '100%',
            }}
          />
        </TableRowColumn>
        <TableRowColumn>{product.SKU}</TableRowColumn>
        <TableRowColumn>{product.Inventory}</TableRowColumn>
        <TableRowColumn>{product.Price || '--'}</TableRowColumn>
        <TableRowColumn>{product.ShippingFee || 'FREE'}</TableRowColumn>
        <TableRowColumn><Link to={`/product/${product.Id}`}>Edit This Product</Link></TableRowColumn>
      </TableRow>
    ));
  };

  render() {
    return (

        <Helmet
          title="Catalog"
          meta={[
            { name: 'description', content: 'Catalog Page' },
          ]}
        />

Catalog

              <Menu />

                <Link to={'product/create'}>
                  <FlatButton label="Create" icon={<AddIcon />} labelPosition="before" />
                </Link>
                <Link to={'product/import'}>
                  <FlatButton label="Import" icon={<FileUploadIcon />} labelPosition="before" />
                </Link>

                <TableHeader
                  displaySelectAll={false}
                  adjustForCheckbox={false}
                  enableSelectAll={false}
                >
                  <TableRow>
                    <TableHeaderColumn>Product Name</TableHeaderColumn>
                    <TableHeaderColumn>Image</TableHeaderColumn>
                    <TableHeaderColumn>SKU</TableHeaderColumn>
                    <TableHeaderColumn>Inventory Available</TableHeaderColumn>
                    <TableHeaderColumn>Retail Price</TableHeaderColumn>
                    <TableHeaderColumn>Shipping Price</TableHeaderColumn>
                    <TableHeaderColumn> </TableHeaderColumn>
                  </TableRow>
                </TableHeader>
                <TableBody displayRowCheckbox={false}>
                  {this.renderProducts()}
                </TableBody>

    );
  }
}

CatalogPage.propTypes = {
  products: PropTypes.array,
  getProducts: PropTypes.func,
};

export function mapDispatchToProps(dispatch) {
  return {
    getProducts: () => {
      dispatch(getProducts());
    },
  };
}

const mapStateToProps = createStructuredSelector({
  products: selectProducts(),
});

// Wrap the component to inject dispatch and state into it
export default connect(mapStateToProps, mapDispatchToProps)(CatalogPage);
<commit_msg>Tweeks to catalog table view<commit_after>/*
 * HomePage
 *
 * This is the first thing users see of our App, at the '/' route
 */

import React, { Component, PropTypes } from 'react';
import Helmet from 'react-helmet';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import { createStructuredSelector } from 'reselect';
import _ from 'underscore';
import { getProducts } from './actions';
import { selectProducts } from './selectors';
import Body from '../../components/styled/Body';
import H2 from '../../components/styled/H2';
import FlatButton from 'material-ui/FlatButton';
import FileUploadIcon from 'material-ui/svg-icons/file/file-upload';
import Menu from '../../components/partials/Menu';
import {
  Table,
  TableHeader,
  TableRow,
  TableHeaderColumn,
  TableBody,
  TableRowColumn,
} from 'material-ui/Table';

class CatalogPage extends Component {

  componentDidMount() {
    if (this.props.products.length === 0) {
      this.props.getProducts();
    }
  }

  renderProducts = () => {
    const { products } = this.props;
    return _.map(products, (product, i) => (
      <TableRow key={i}>
        <TableRowColumn><Link to={`/product/${product.Id}`}>{product.ProductName}</Link></TableRowColumn>
        <TableRowColumn>
          <div
            style={product.MainImageUri ? {
              backgroundImage: `url(${product.MainImageUri})`,
              backgroundSize: 'cover',
              backgroundRepeat: 'no-repeat',
              height: 50,
              width: 50,
            } : {
              background: 'repeating-linear-gradient(45deg,transparent,transparent 10px,#ccc 10px,#ccc 20px)',
              height: '100%',
            }}
          />
        </TableRowColumn>
        <TableRowColumn>{product.SKU}</TableRowColumn>
        <TableRowColumn>{product.RuahId}</TableRowColumn>
        <TableRowColumn>{product.Inventory}</TableRowColumn>
        <TableRowColumn>${product.WholesalePrice}</TableRowColumn>
        <TableRowColumn>${product.ShippingFee}</TableRowColumn>
        <TableRowColumn>{product.VariationGroupId}</TableRowColumn>
      </TableRow>
    ));
  };

  render() {
    return (

        <Helmet
          title="Catalog"
          meta={[
            { name: 'description', content: 'Catalog Page' },
          ]}
        />

Catalog

              <Menu />

                <Link to={'product/import'}>
                  <FlatButton label="Import" icon={<FileUploadIcon />} labelPosition="before" />
                </Link>

                <TableHeader
                  displaySelectAll={false}
                  adjustForCheckbox={false}
                  enableSelectAll={false}
                >
                  <TableRow>
                    <TableHeaderColumn>Product Name</TableHeaderColumn>
                    <TableHeaderColumn>Image</TableHeaderColumn>
                    <TableHeaderColumn>SKU</TableHeaderColumn>
                    <TableHeaderColumn>Ruah Id</TableHeaderColumn>
                    <TableHeaderColumn>Inventory Available</TableHeaderColumn>
                    <TableHeaderColumn>Wholesale Price</TableHeaderColumn>
                    <TableHeaderColumn>Shipping Price</TableHeaderColumn>
                    <TableHeaderColumn>Variation Group</TableHeaderColumn>
                  </TableRow>
                </TableHeader>
                <TableBody displayRowCheckbox={false}>
                  {this.renderProducts()}
                </TableBody>

    );
  }
}

CatalogPage.propTypes = {
  products: PropTypes.array,
  getProducts: PropTypes.func,
};

export function mapDispatchToProps(dispatch) {
  return {
    getProducts: () => {
      dispatch(getProducts());
    },
  };
}

const mapStateToProps = createStructuredSelector({
  products: selectProducts(),
});

// Wrap the component to inject dispatch and state into it
export default connect(mapStateToProps, mapDispatchToProps)(CatalogPage);
<|endoftext|>


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

var services = angular.module('services', ['restResource']);

services.factory('AuthService', ['$http', '$rootScope', 'FormService', function($http, $rootScope, FormService) {
    return {
        login: function(credentials) {
            return $http.post($rootScope.serverUrl + '/j_spring_security_check', credentials, {
                headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
                transformRequest: function(data) {
                    return angular.isObject(data) && String(data) !== '[object File]' ? FormService.formObjectData(data) : data;
                }
            }).then(function(response) {
                return response.data;
            });
        }
    };
}])
.service('Session', ['$timeout', '$http', '$rootScope', '$q', 'UserService', 'USER_ROLES', 'User', 'Project', 'PushService', 'IceScrumEventType', 'FormService', function($timeout, $http, $rootScope, $q, UserService, USER_ROLES, User, Project, PushService, IceScrumEventType, FormService) {
    var self = this;
    self.user = new User();
    self.project = new Project();
    self.isProjectResolved = $q.defer();
    self.unreadActivitiesCount = 0;
    var defaultRoles = {
        productOwner: false,
        scrumMaster: false,
        teamMember: false,
        stakeHolder: false,
        admin: false
    };
    self.roles = _.clone(defaultRoles);
    var reload = function() {
        $timeout(function() {
            document.location.reload(true);
        }, 2000);
    };
    this.create = function() {
        UserService.getCurrent()
            .then(function(data) {
                if (data.user != "null") {
                    _.extend(self.user, data.user);
                    _.merge(self.roles, data.roles);
                    UserService.getUnreadActivities(self.user)
                        .then(function(data) {
                            self.unreadActivitiesCount = data.unreadActivitiesCount;
                        });
                }
            });
    };
    this.setUser = function(user) {
        _.extend(self.user, user);
        PushService.registerListener('activity', IceScrumEventType.CREATE, function() {
            self.unreadActivitiesCount += 1;
        });
        PushService.registerListener('user', IceScrumEventType.UPDATE, function(user) {
            if (user.updatedRole) {
                var updatedRole = user.updatedRole;
                var updatedProject = updatedRole.product;
                if (updatedRole.role == undefined) {
                    $rootScope.notifyWarning($rootScope.message('is.user.role.removed.product') + ' ' + updatedProject.name);
                    if (updatedProject.id == self.project.id) {
                        $timeout(function() {
                            document.location = $rootScope.serverUrl
                        }, 2000);
                    }
                } else if (updatedRole.oldRole == undefined) {
                    $rootScope.notifySuccess($rootScope.message('is.user.role.added.product') + ' ' + updatedProject.name);
                    if (updatedProject.id == self.project.id) {
                        reload();
                    }
                } else {
                    $rootScope.notifySuccess($rootScope.message('is.user.role.updated.product') + ' ' + updatedProject.name);
                    if (updatedProject.id == self.project.id) {
                        reload();
                    }
                }
            }
        });
    };
    this.poOrSm = function() {
        return self.roles.productOwner || self.roles.scrumMaster;
    };
    this.po = function() {
        return self.roles.productOwner;
    };
    this.sm = function() {
        return self.roles.scrumMaster;
    };
    this.admin = function() {
        return self.roles.admin;
    };
    this.authenticated = function() {
        return !_.isEmpty(self.user);
    };
    this.inProduct = function() {
        return self.roles.productOwner || self.roles.scrumMaster || self.roles.teamMember;
    };
    this.tmOrSm = function() {
        return self.roles.scrumMaster || self.roles.teamMember;
    };
    this.creator = function(item) {
        return this.authenticated && !_.isEmpty(item) && !_.isEmpty(item.creator) && self.user.id == item.creator.id;
    };
    this.responsible = function(item) {
        return this.authenticated && !_.isEmpty(item) && !_.isEmpty(item.responsible) && self.user.id == item.responsible.id;
    };
    this.owner = function(item) {
        return !_.isEmpty(item) && !_.isEmpty(item.owner) && self.user.id == item.owner.id;
    };
    // TODO remove, user role change for dev only
    this.changeRole = function(newUserRole) {
        var newRoles = {};
        switch (newUserRole) {
            case USER_ROLES.PO_SM:
                newRoles.productOwner = true;
                newRoles.scrumMaster = true;
                break;
            case USER_ROLES.PO:
                newRoles.productOwner = true;
                break;
            case USER_ROLES.SM:
                newRoles.scrumMaster = true;
                break;
            case USER_ROLES.TM:
                newRoles.teamMember = true;
                break;
        }
        newRoles.stakeHolder = true;
        _.merge(self.roles, defaultRoles, newRoles);
    };
    this.initProject = function(project) {
        _.extend(self.project, project);
        self.isProjectResolved.resolve();
        PushService.registerListener('product', IceScrumEventType.UPDATE, function(updatedProject) {
            if (updatedProject.pkey != self.project.pkey) {
                $rootScope.notifyWarning('todo.is.ui.project.updated.pkey');
                document.location = document.location.href.replace(self.project.pkey, updatedProject.pkey);
            } else if (updatedProject.preferences.hidden && !self.project.preferences.hidden && !self.inProduct()) {
                $rootScope.notifyWarning('todo.is.ui.project.updated.visibility');
                reload();
            } else if (updatedProject.preferences.archived != self.project.preferences.archived) {
                if (updatedProject.preferences.archived == true) {
                    $rootScope.notifyWarning('todo.is.ui.project.updated.archived');
                } else {
                    $rootScope.notifyWarning('todo.is.ui.project.updated.unarchived');
                }
                reload();
            } else {
                self.updateProject(updatedProject);
            }
        });
        PushService.registerListener('product', IceScrumEventType.DELETE, function() {
            $rootScope.notifyWarning('todo.is.ui.project.deleted');
            reload();
        });
    };
    this.updateProject = function(project) {
        _.extend(self.project, project);
    };
    this.getProject = function() {
        return self.project;
    };
    this.getProjectPromise = function() {
        return self.isProjectResolved.promise.then(function() {
            return self.project;
        });
    };
    this.getLanguages = function() {
        return FormService.httpGet('scrumOS/languages', { cache: true });
    };
    this.getTimezones = function() {
        return FormService.httpGet('scrumOS/timezones', { cache: true });
    };
}])
.service('FormService', ['$filter', '$http', '$rootScope', function($filter, $http, $rootScope) {
    var self = this;
    this.previous = function(list, element) {
        var ind = _.findIndex(list, { id: element.id });
        return ind > 0 ? list[ind - 1] : null;
    };
    this.next = function(list, element) {
        var ind = _.findIndex(list, { id: element.id });
        return ind + 1 <= list.length ? list[ind + 1] : null;
    };
    this.decapitalize = function(str) {
        return str.charAt(0).toLowerCase() + str.substring(1);
    };
    this.formObjectData = function(obj, prefix) {
        var query = '', name, value, fullSubName, subName, subValue, innerObj, i, _prefix;
        _prefix = prefix ? prefix : (obj['class'] ? obj['class'] + '.' : '');
        _prefix = self.decapitalize(_prefix);
        for (name in obj) {
            value = obj[name];
            if (value instanceof Array && !_.endsWith(name, '_ids')) {
                for (i = 0; i < value.length; ++i) {
                    subValue = value[i];
                    innerObj = {};
                    innerObj[name] = subValue;
                    query += self.formObjectData(innerObj, _prefix) + '&';
                }
            } else if (value instanceof Date) {
                var encodedDate = $filter('dateToIso')(value);
                query += encodeURIComponent(_prefix + name) + '=' + encodeURIComponent(encodedDate) + '&';
            } else if (value instanceof Object) {
                for (subName in value) {
                    if (subName != 'class' && !_.startsWith(subName, '$')) {
                        subValue = value[subName];
                        fullSubName = name + '.' + subName;
                        innerObj = {};
                        innerObj[fullSubName] = subValue;
                        query += self.formObjectData(innerObj, _prefix) + '&';
                    }
                }
            } else if (value === undefined) {
                query += encodeURIComponent(_prefix + name) + '=null&'; // HACK: an undefined property (e.g. select cleared makes the model undefined) set the null value in Grails data binding
            } else if (value !== null
                    //no class info needed
                && !_.contains(['class', 'uid', 'lastUpdated', 'dateCreated'], name)
                    //no angular object
                && !_.startsWith(name, '$')
                    //no custom count / html values
                && !_.endsWith(name, '_count') && !_.endsWith(name, '_html')) {
                query += encodeURIComponent(_prefix + name) + '=' + encodeURIComponent(value) + '&';
            }
        }
        return query.length ? query.substr(0, query.length - 1) : query;
    };
    this.httpGet = function(path, params, isAbsolute) {
        var fullPath = isAbsolute ? $rootScope.serverUrl + '/' + path : path;
        var paramObj = params || {};
        return $http.get(fullPath, paramObj).then(function(response) {
            return response.data;
        });
    };
    this.addStateChangeDirtyFormListener = function($scope, type, isModal) {
        var triggerConfirmModal = function(event, confirmCallback) {
            event.preventDefault(); // cancel the state change
            $scope.mustConfirmStateChange = false;
            $scope.confirm({
                message: $scope.message('todo.is.ui.dirty.confirm'),
                condition: $scope.isDirty() || ($scope.flow != undefined && $scope.flow.isUploading()),
                callback: function() {
                    if ($scope.flow != undefined && $scope.flow.isUploading()) {
                        $scope.flow.cancel();
                    }
                    confirmCallback();
                },
                closeCallback: function() {
                    $scope.app.loading = false;
                    $scope.mustConfirmStateChange = true;
                }
            });
        };
        $scope.mustConfirmStateChange = true; // to prevent infinite recursion when calling $stage.go
        $scope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
            if ($scope.mustConfirmStateChange && fromParams[type + 'Id'] != toParams[type + 'Id']) {
                triggerConfirmModal(event, function() {
                    $scope.$state.go(toState, toParams);
                });
            }
        });
        if (isModal) {
            $scope.$on('modal.closing', function(event) {
                if ($scope.mustConfirmStateChange) {
                    triggerConfirmModal(event, function() {
                        $scope.$close();
                    });
                }
            });
        }
    };
}])
.service('BundleService', [function() {
    this.bundles = {};
    this.initBundles = function(bundles) {
        this.bundles = bundles;
    };
    this.getBundle = function(bundleName) {
        return this.bundles[bundleName];
    }
}]);

var restResource = angular.module('restResource', ['ngResource']);
restResource.factory('Resource', ['$resource', 'FormService', function($resource, FormService) {
    return function(url, params, methods) {
        var defaultParams = {
            id: '@id'
        };
        var transformStringToDate = function(item) {
            if (item.hasOwnProperty('startDate')) {
                item.startDate = new Date(item.startDate);
            }
            if (item.hasOwnProperty('endDate')) {
                item.endDate = new Date(item.endDate);
            }
        };
        var arrayInterceptor = {
            response: function(response) {
                _.each(response.resource, transformStringToDate);
                return response.resource;
            }
        };
        var singleInterceptor = {
            response: function(response) {
                transformStringToDate(response.resource);
                return response.resource;
            }
        };
        var transformRequest = function(data) {
            return angular.isObject(data) && String(data) !== '[object File]' ? FormService.formObjectData(data) : data;
        };
        var transformQueryParams = function(resolve) { // Magical hack found here: http://stackoverflow.com/questions/24082468/how-to-intercept-resource-requests
            var originalParamSerializer = this.paramSerializer;
            this.paramSerializer = function(params) {
                return _.isObject(params) ? FormService.formObjectData(params) : originalParamSerializer(params);
            };
            this.then = null;
            resolve(this);
        };
        var defaultMethods = {
            save: {
                method: 'post',
                isArray: false,
                headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
                transformRequest: transformRequest,
                interceptor: singleInterceptor
            },
            updateArray: {
                method: 'post',
                isArray: true,
                headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
                transformRequest: transformRequest,
                interceptor: arrayInterceptor
            },
            get: {
                method: 'get',
                interceptor: singleInterceptor,
                then: transformQueryParams
            },
            query: {
                method: 'get',
                isArray: true,
                interceptor: arrayInterceptor,
                then: transformQueryParams
            },
            deleteArray: {
                method: 'delete',
                isArray: true
            }
        };
        defaultMethods.update = angular.copy(defaultMethods.save); // for the moment there is no difference between save & update
        return $resource(url, angular.extend(defaultParams, params), angular.extend(defaultMethods, methods));
    };
}]);<commit_msg>Use custom query param serializer only if deep object<commit_after>/*
 * Copyright (c) 2015 Kagilum SAS.
 *
 * This file is part of iceScrum.
 *
 * iceScrum is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License.
 *
 * iceScrum is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with iceScrum.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors:
 *
 * Vincent Barrier (vbarrier@kagilum.com)
 * Nicolas Noullet (nnoullet@kagilum.com)
 *
 */

var services = angular.module('services', ['restResource']);

services.factory('AuthService', ['$http', '$rootScope', 'FormService', function($http, $rootScope, FormService) {
    return {
        login: function(credentials) {
            return $http.post($rootScope.serverUrl + '/j_spring_security_check', credentials, {
                headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
                transformRequest: function(data) {
                    return angular.isObject(data) && String(data) !== '[object File]' ? FormService.formObjectData(data) : data;
                }
            }).then(function(response) {
                return response.data;
            });
        }
    };
}])
.service('Session', ['$timeout', '$http', '$rootScope', '$q', 'UserService', 'USER_ROLES', 'User', 'Project', 'PushService', 'IceScrumEventType', 'FormService', function($timeout, $http, $rootScope, $q, UserService, USER_ROLES, User, Project, PushService, IceScrumEventType, FormService) {
    var self = this;
    self.user = new User();
    self.project = new Project();
    self.isProjectResolved = $q.defer();
    self.unreadActivitiesCount = 0;
    var defaultRoles = {
        productOwner: false,
        scrumMaster: false,
        teamMember: false,
        stakeHolder: false,
        admin: false
    };
    self.roles = _.clone(defaultRoles);
    var reload = function() {
        $timeout(function() {
            document.location.reload(true);
        }, 2000);
    };
    this.create = function() {
        UserService.getCurrent()
            .then(function(data) {
                if (data.user != "null") {
                    _.extend(self.user, data.user);
                    _.merge(self.roles, data.roles);
                    UserService.getUnreadActivities(self.user)
                        .then(function(data) {
                            self.unreadActivitiesCount = data.unreadActivitiesCount;
                        });
                }
            });
    };
    this.setUser = function(user) {
        _.extend(self.user, user);
        PushService.registerListener('activity', IceScrumEventType.CREATE, function() {
            self.unreadActivitiesCount += 1;
        });
        PushService.registerListener('user', IceScrumEventType.UPDATE, function(user) {
            if (user.updatedRole) {
                var updatedRole = user.updatedRole;
                var updatedProject = updatedRole.product;
                if (updatedRole.role == undefined) {
                    $rootScope.notifyWarning($rootScope.message('is.user.role.removed.product') + ' ' + updatedProject.name);
                    if (updatedProject.id == self.project.id) {
                        $timeout(function() {
                            document.location = $rootScope.serverUrl
                        }, 2000);
                    }
                } else if (updatedRole.oldRole == undefined) {
                    $rootScope.notifySuccess($rootScope.message('is.user.role.added.product') + ' ' + updatedProject.name);
                    if (updatedProject.id == self.project.id) {
                        reload();
                    }
                } else {
                    $rootScope.notifySuccess($rootScope.message('is.user.role.updated.product') + ' ' + updatedProject.name);
                    if (updatedProject.id == self.project.id) {
                        reload();
                    }
                }
            }
        });
    };
    this.poOrSm = function() {
        return self.roles.productOwner || self.roles.scrumMaster;
    };
    this.po = function() {
        return self.roles.productOwner;
    };
    this.sm = function() {
        return self.roles.scrumMaster;
    };
    this.admin = function() {
        return self.roles.admin;
    };
    this.authenticated = function() {
        return !_.isEmpty(self.user);
    };
    this.inProduct = function() {
        return self.roles.productOwner || self.roles.scrumMaster || self.roles.teamMember;
    };
    this.tmOrSm = function() {
        return self.roles.scrumMaster || self.roles.teamMember;
    };
    this.creator = function(item) {
        return this.authenticated && !_.isEmpty(item) && !_.isEmpty(item.creator) && self.user.id == item.creator.id;
    };
    this.responsible = function(item) {
        return this.authenticated && !_.isEmpty(item) && !_.isEmpty(item.responsible) && self.user.id == item.responsible.id;
    };
    this.owner = function(item) {
        return !_.isEmpty(item) && !_.isEmpty(item.owner) && self.user.id == item.owner.id;
    };
    // TODO remove, user role change for dev only
    this.changeRole = function(newUserRole) {
        var newRoles = {};
        switch (newUserRole) {
            case USER_ROLES.PO_SM:
                newRoles.productOwner = true;
                newRoles.scrumMaster = true;
                break;
            case USER_ROLES.PO:
                newRoles.productOwner = true;
                break;
            case USER_ROLES.SM:
                newRoles.scrumMaster = true;
                break;
            case USER_ROLES.TM:
                newRoles.teamMember = true;
                break;
        }
        newRoles.stakeHolder = true;
        _.merge(self.roles, defaultRoles, newRoles);
    };
    this.initProject = function(project) {
        _.extend(self.project, project);
        self.isProjectResolved.resolve();
        PushService.registerListener('product', IceScrumEventType.UPDATE, function(updatedProject) {
            if (updatedProject.pkey != self.project.pkey) {
                $rootScope.notifyWarning('todo.is.ui.project.updated.pkey');
                document.location = document.location.href.replace(self.project.pkey, updatedProject.pkey);
            } else if (updatedProject.preferences.hidden && !self.project.preferences.hidden && !self.inProduct()) {
                $rootScope.notifyWarning('todo.is.ui.project.updated.visibility');
                reload();
            } else if (updatedProject.preferences.archived != self.project.preferences.archived) {
                if (updatedProject.preferences.archived == true) {
                    $rootScope.notifyWarning('todo.is.ui.project.updated.archived');
                } else {
                    $rootScope.notifyWarning('todo.is.ui.project.updated.unarchived');
                }
                reload();
            } else {
                self.updateProject(updatedProject);
            }
        });
        PushService.registerListener('product', IceScrumEventType.DELETE, function() {
            $rootScope.notifyWarning('todo.is.ui.project.deleted');
            reload();
        });
    };
    this.updateProject = function(project) {
        _.extend(self.project, project);
    };
    this.getProject = function() {
        return self.project;
    };
    this.getProjectPromise = function() {
        return self.isProjectResolved.promise.then(function() {
            return self.project;
        });
    };
    this.getLanguages = function() {
        return FormService.httpGet('scrumOS/languages', { cache: true });
    };
    this.getTimezones = function() {
        return FormService.httpGet('scrumOS/timezones', { cache: true });
    };
}])
.service('FormService', ['$filter', '$http', '$rootScope', function($filter, $http, $rootScope) {
    var self = this;
    this.previous = function(list, element) {
        var ind = _.findIndex(list, { id: element.id });
        return ind > 0 ? list[ind - 1] : null;
    };
    this.next = function(list, element) {
        var ind = _.findIndex(list, { id: element.id });
        return ind + 1 <= list.length ? list[ind + 1] : null;
    };
    this.decapitalize = function(str) {
        return str.charAt(0).toLowerCase() + str.substring(1);
    };
    this.formObjectData = function(obj, prefix) {
        var query = '', name, value, fullSubName, subName, subValue, innerObj, i, _prefix;
        _prefix = prefix ? prefix : (obj['class'] ? obj['class'] + '.' : '');
        _prefix = self.decapitalize(_prefix);
        for (name in obj) {
            value = obj[name];
            if (value instanceof Array && !_.endsWith(name, '_ids')) {
                for (i = 0; i < value.length; ++i) {
                    subValue = value[i];
                    innerObj = {};
                    innerObj[name] = subValue;
                    query += self.formObjectData(innerObj, _prefix) + '&';
                }
            } else if (value instanceof Date) {
                var encodedDate = $filter('dateToIso')(value);
                query += encodeURIComponent(_prefix + name) + '=' + encodeURIComponent(encodedDate) + '&';
            } else if (value instanceof Object) {
                for (subName in value) {
                    if (subName != 'class' && !_.startsWith(subName, '$')) {
                        subValue = value[subName];
                        fullSubName = name + '.' + subName;
                        innerObj = {};
                        innerObj[fullSubName] = subValue;
                        query += self.formObjectData(innerObj, _prefix) + '&';
                    }
                }
            } else if (value === undefined) {
                query += encodeURIComponent(_prefix + name) + '=null&'; // HACK: an undefined property (e.g. select cleared makes the model undefined) set the null value in Grails data binding
            } else if (value !== null
                    //no class info needed
                && !_.contains(['class', 'uid', 'lastUpdated', 'dateCreated'], name)
                    //no angular object
                && !_.startsWith(name, '$')
                    //no custom count / html values
                && !_.endsWith(name, '_count') && !_.endsWith(name, '_html')) {
                query += encodeURIComponent(_prefix + name) + '=' + encodeURIComponent(value) + '&';
            }
        }
        return query.length ? query.substr(0, query.length - 1) : query;
    };
    this.httpGet = function(path, params, isAbsolute) {
        var fullPath = isAbsolute ? $rootScope.serverUrl + '/' + path : path;
        var paramObj = params || {};
        return $http.get(fullPath, paramObj).then(function(response) {
            return response.data;
        });
    };
    this.addStateChangeDirtyFormListener = function($scope, type, isModal) {
        var triggerConfirmModal = function(event, confirmCallback) {
            event.preventDefault(); // cancel the state change
            $scope.mustConfirmStateChange = false;
            $scope.confirm({
                message: $scope.message('todo.is.ui.dirty.confirm'),
                condition: $scope.isDirty() || ($scope.flow != undefined && $scope.flow.isUploading()),
                callback: function() {
                    if ($scope.flow != undefined && $scope.flow.isUploading()) {
                        $scope.flow.cancel();
                    }
                    confirmCallback();
                },
                closeCallback: function() {
                    $scope.app.loading = false;
                    $scope.mustConfirmStateChange = true;
                }
            });
        };
        $scope.mustConfirmStateChange = true; // to prevent infinite recursion when calling $stage.go
        $scope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
            if ($scope.mustConfirmStateChange && fromParams[type + 'Id'] != toParams[type + 'Id']) {
                triggerConfirmModal(event, function() {
                    $scope.$state.go(toState, toParams);
                });
            }
        });
        if (isModal) {
            $scope.$on('modal.closing', function(event) {
                if ($scope.mustConfirmStateChange) {
                    triggerConfirmModal(event, function() {
                        $scope.$close();
                    });
                }
            });
        }
    };
}])
.service('BundleService', [function() {
    this.bundles = {};
    this.initBundles = function(bundles) {
        this.bundles = bundles;
    };
    this.getBundle = function(bundleName) {
        return this.bundles[bundleName];
    }
}]);

var restResource = angular.module('restResource', ['ngResource']);
restResource.factory('Resource', ['$resource', 'FormService', function($resource, FormService) {
    return function(url, params, methods) {
        var defaultParams = {
            id: '@id'
        };
        var transformStringToDate = function(item) {
            if (item.hasOwnProperty('startDate')) {
                item.startDate = new Date(item.startDate);
            }
            if (item.hasOwnProperty('endDate')) {
                item.endDate = new Date(item.endDate);
            }
        };
        var arrayInterceptor = {
            response: function(response) {
                _.each(response.resource, transformStringToDate);
                return response.resource;
            }
        };
        var singleInterceptor = {
            response: function(response) {
                transformStringToDate(response.resource);
                return response.resource;
            }
        };
        var transformRequest = function(data) {
            return angular.isObject(data) && String(data) !== '[object File]' ? FormService.formObjectData(data) : data;
        };
        var transformQueryParams = function(resolve) { // Magical hack found here: http://stackoverflow.com/questions/24082468/how-to-intercept-resource-requests
            var originalParamSerializer = this.paramSerializer;
            this.paramSerializer = function(params) {
                var isDeepObject = _.isObject(params) && _.any(_.values(params), _.isObject);
                return isDeepObject ? FormService.formObjectData(params) : originalParamSerializer(params);
            };
            this.then = null;
            resolve(this);
        };
        var defaultMethods = {
            save: {
                method: 'post',
                isArray: false,
                headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
                transformRequest: transformRequest,
                interceptor: singleInterceptor
            },
            updateArray: {
                method: 'post',
                isArray: true,
                headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
                transformRequest: transformRequest,
                interceptor: arrayInterceptor
            },
            get: {
                method: 'get',
                interceptor: singleInterceptor,
                then: transformQueryParams
            },
            query: {
                method: 'get',
                isArray: true,
                interceptor: arrayInterceptor,
                then: transformQueryParams
            },
            deleteArray: {
                method: 'delete',
                isArray: true
            }
        };
        defaultMethods.update = angular.copy(defaultMethods.save); // for the moment there is no difference between save & update
        return $resource(url, angular.extend(defaultParams, params), angular.extend(defaultMethods, methods));
    };
}]);<|endoftext|>


<commit_before>var express = require("express");
var app = express();
var router = express.Router();
var port = 8080;

// See https://www.w3schools.com/cssref/css_colors.asp
var color = "pink";

router.use(function (req,res,next) {
  next();
  console.log("%s %s => %i", req.method, req.originalUrl, res.statusCode);
});

router.get("/",function(req,res){
  res.sendFile(__dirname + '/views/index.html');
});

router.get("/info",function(req,res){
  var response = {
    color: color,
    podName: process.env["HOSTNAME"],
  };
  res.type('application/json')
     .header("Connection", "close")
     .header('Cache-Control', 'private, no-cache, no-store, must-revalidate')
     .header('Expires', '-1')
     .header('Pragma', 'no-cache')
     .send(JSON.stringify(response))
     .end();
});

app.use("/",router);

app.use("*",function(req,res){
  res.status(404).send("Not found");
});

app.listen(port,function(){
  console.log("Live at Port %i", port);
});
<commit_msg>improve look and feel<commit_after>var express = require("express");
var app = express();
var router = express.Router();
var port = 8080;

// See https://www.w3schools.com/cssref/css_colors.asp
var color = "red";

router.use(function (req,res,next) {
  next();
  console.log("%s %s => %i", req.method, req.originalUrl, res.statusCode);
});

router.get("/",function(req,res){
  res.sendFile(__dirname + '/views/index.html');
});

router.get("/info",function(req,res){
  var response = {
    color: color,
    podName: process.env["HOSTNAME"],
  };
  res.type('application/json')
     .header("Connection", "close")
     .header('Cache-Control', 'private, no-cache, no-store, must-revalidate')
     .header('Expires', '-1')
     .header('Pragma', 'no-cache')
     .send(JSON.stringify(response))
     .end();
});

app.use("/",router);

app.use("*",function(req,res){
  res.status(404).send("Not found");
});

app.listen(port,function(){
  console.log("Live at Port %i", port);
});
<|endoftext|>


<commit_before>/*eslint-env node */
const _ = require("lodash");
const path = require("path");
const webpack = require("webpack");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

const pkg = require("./package.json");

module.exports = function (options) {
  const config = _.merge(
    {},
    {
      devServer: {
        contentBase: path.join(__dirname, "src"),
        publicPath: "/",
        open: true,
        hot: true,
        inline: true,
        historyApiFallback: {
          rewrites: [
            { from: /^\/$/, to: "/index.html" },
            { from: /^\/user/, to: "/user/index.html" },
            { from: /^\/admin/, to: "/admin/index.html" },
            { from: /^\/public/, to: "/public/index.html" },
          ],
        },
        stats: "minimal",
        proxy: {
          "/api/v1/*": "http://localhost:9000",
        },
        host: "0.0.0.0",
        port: 8080,
      },
      entry: {},
      output: {
        publicPath: "/",
      },
      plugins: [
        // new HtmlWebpackPlugin({
        //   template: "src/index.ejs",
        //   title: pkg.title,
        //   chunks: ["micro"],
        //   description: pkg.description,
        //   filename: "index.html",
        // }),
        // new HtmlWebpackPlugin({
        //   template: "src/index.ejs",
        //   title: pkg.title,
        //   chunks: ["public"],
        //   description: pkg.description,
        //   filename: "public/index.html",
        // }),
        new HtmlWebpackPlugin({
          template: "src/index.ejs",
          title: pkg.title,
          chunks: ["user"],
          filename: "index.html",
          description: pkg.description,
        }),
        new HtmlWebpackPlugin({
          template: "src/index.ejs",
          title: pkg.title,
          chunks: ["admin"],
          filename: "admin/index.html",
        }),

        new webpack.DefinePlugin({
          __VERSION__: JSON.stringify(pkg.version),
        }),
        new CopyWebpackPlugin({
          patterns: [
            { from: "./src/favicon.ico" },
            { from: "./locales/**/*.json" },
            { from: "./assets/**/*" },
          ],
        }),
        new MiniCssExtractPlugin({
          filename: "[name].css",
          chunkFilename: "[id].css",
        }),
      ],
      resolve: {
        modules: ["src", "node_modules"],
        extensions: [".mjs", ".js", ".jsx", ".ts", ".tsx"],
        alias: {
          src: path.resolve("./src"),
        },
      },
      module: {
        rules: [
          {
            test: /.(gif|png|woff(2)?|eot|ttf|svg)(\?[a-z0-9=.]+)?$/,
            use: ["url-loader"],
          },
          {
            test: /\.jpg/,
            use: ["file-loader"],
          },
        ],
      },
    },
    options.overrides
  );

  config.module.rules = _.union(config.module.rules, options.rules);
  config.plugins = _.union(config.plugins, options.plugins);
  return config;
};
<commit_msg>fix hot reloading<commit_after>/*eslint-env node */
const _ = require("lodash");
const path = require("path");
const webpack = require("webpack");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

const pkg = require("./package.json");

module.exports = function (options) {
  const config = _.merge(
    {},
    {
      target: "web",
      devServer: {
        contentBase: path.join(__dirname, "src"),
        publicPath: "/",
        open: true,
        hot: true,
        inline: true,
        historyApiFallback: {
          rewrites: [
            { from: /^\/$/, to: "/index.html" },
            { from: /^\/user/, to: "/user/index.html" },
            { from: /^\/admin/, to: "/admin/index.html" },
            { from: /^\/public/, to: "/public/index.html" },
          ],
        },
        stats: "minimal",
        proxy: {
          "/api/v1/*": "http://localhost:9000",
        },
        host: "0.0.0.0",
        port: 8080,
      },
      entry: {},
      output: {
        publicPath: "/",
      },
      plugins: [
        // new HtmlWebpackPlugin({
        //   template: "src/index.ejs",
        //   title: pkg.title,
        //   chunks: ["micro"],
        //   description: pkg.description,
        //   filename: "index.html",
        // }),
        // new HtmlWebpackPlugin({
        //   template: "src/index.ejs",
        //   title: pkg.title,
        //   chunks: ["public"],
        //   description: pkg.description,
        //   filename: "public/index.html",
        // }),
        new HtmlWebpackPlugin({
          template: "src/index.ejs",
          title: pkg.title,
          chunks: ["user"],
          filename: "index.html",
          description: pkg.description,
        }),
        new HtmlWebpackPlugin({
          template: "src/index.ejs",
          title: pkg.title,
          chunks: ["admin"],
          filename: "admin/index.html",
        }),

        new webpack.DefinePlugin({
          __VERSION__: JSON.stringify(pkg.version),
        }),
        new CopyWebpackPlugin({
          patterns: [
            { from: "./src/favicon.ico" },
            { from: "./locales/**/*.json" },
            { from: "./assets/**/*" },
          ],
        }),
        new MiniCssExtractPlugin({
          filename: "[name].css",
          chunkFilename: "[id].css",
        }),
      ],
      resolve: {
        modules: ["src", "node_modules"],
        extensions: [".mjs", ".js", ".jsx", ".ts", ".tsx"],
        alias: {
          src: path.resolve("./src"),
        },
      },
      module: {
        rules: [
          {
            test: /.(gif|png|woff(2)?|eot|ttf|svg)(\?[a-z0-9=.]+)?$/,
            use: ["url-loader"],
          },
          {
            test: /\.jpg/,
            use: ["file-loader"],
          },
        ],
      },
    },
    options.overrides
  );

  config.module.rules = _.union(config.module.rules, options.rules);
  config.plugins = _.union(config.plugins, options.plugins);
  return config;
};
<|endoftext|>


<commit_before>/**
 * Route Mappings
 * (sails.config.routes)
 *
 * Your routes map URLs to views and controllers.
 *
 * If Sails receives a URL that doesn't match any of the routes below,
 * it will check for matching files (images, scripts, stylesheets, etc.)
 * in your assets directory.  e.g. `http://localhost:1337/images/foo.jpg`
 * might match an image file: `/assets/images/foo.jpg`
 *
 * Finally, if those don't match either, the default 404 handler is triggered.
 * See `api/responses/notFound.js` to adjust your app's 404 logic.
 *
 * Note: Sails doesn't ACTUALLY serve stuff from `assets`-- the default Gruntfile in Sails copies
 * flat files from `assets` to `.tmp/public`.  This allows you to do things like compile LESS or
 * CoffeeScript for the front-end.
 *
 * For more information on configuring custom routes, check out:
 * http://sailsjs.org/#!/documentation/concepts/Routes/RouteTargetSyntax.html
 */

module.exports.routes = {
  // Homepage
  'get /': 'HomeController.index',

  // Authentication
  'get /login': 'AuthController.login',
  'get /register': 'AuthController.register',
  'post /login': 'AuthController.process',
  'get /logout': 'AuthController.logout',

  //***** User *****
  'get /users/me' : 'UserController.me',
  //***** /User *****

  //***** Package *****
    // API
    'get /api/packages/:name': 'PackageController.findByName',
    // HTML
    'get /packages/:name': 'PackageController.findByName',
  //***** /Package *****

  //***** Downloads *****
    // API
    'get /api/packages/:name/splitteddownloads': 'PackageVersionController.getSplittedDownloadStatistics',
    // HTML
    'get /packages/:name/splitteddownloads': 'PackageVersionController.getSplittedDownloadStatistics',
  //***** /Downloads *****

  //***** PackageVersion *****
    // API
    'get /api/packages/:name/versions/:version/downloads' : 'PackageVersion.getDownloadStatistics',
    'get /api/packages/:name/downloads' : 'PackageVersion.getDownloadStatistics',
    'get /api/packages/:name/versions/:version/percentile' : 'PackageVersion.getPercentile',
    'get /api/packages/:name/percentile' : 'PackageVersion.getPercentile',
    'get /api/packages/:name/versions/:version/downloads/per_day_last_month' : 'PackageVersion.getLastMonthDownloadPerDay',
    'get /api/packages/:name/downloads/per_day_last_month' : 'PackageVersion.getLastMonthDownloadPerDay',
    'get /api/packages/:name/versions/:version': 'PackageVersion.findByNameVersion',
    'post /api/versions': 'PackageVersion.postDescription',
    // HTML
    'get /packages/:name/versions/:version': 'PackageVersion.findByNameVersion',
  //***** /PackageVersion *****

  //***** Topic *****
    //API
    'get /api/topics/:id': 'Topic.findById',
    'get /api/topics/:id/rating': 'Topic.rating',
    'get /api/packages/:name/versions/:version/topics/:topic': 'Topic.findByName',
    'get /api/packages/:name/topics/:function': 'Topic.redirect',
    'post /api/packages/:name/versions/:version/topics': 'Topic.postRdFile',
    //HTML
    'get /topics/:id': 'Topic.findById',
    'get /packages/:name/versions/:version/topics/:topic': 'Topic.findByName',
    // Backwards compatibility
    'get /packages/:name/functions/:function': 'Topic.redirect',
    'get /goto/:name/:function': 'Topic.redirect',
  //***** /Topic *****

  //***** Collaborator *****
    // API
    'get /api/collaborators/:id': 'CollaboratorController.findById',
    // HTML
    'get /collaborators/:id': 'CollaboratorController.findById',
  //***** /Collaborator *****

  //***** Review *****
    // API
    'get /api/topics/:topicId/reviews': 'ReviewController.findByTopic',
    'get /api/packages/:name/versions/:version/reviews': 'ReviewController.findByVersion',
    'post /api/topics/:topicId/reviews': 'ReviewController.postReviewToTopic',
    'post /api/packages/:name/versions/:version/reviews': 'ReviewController.postReviewToVersion',

  //***** TaskViews *****
    // API
    'post /api/taskviews': 'TaskViewController.postView',
    'get /api/taskviews': 'TaskViewController.findAll',
    'get /api/taskviews/:view/statistics': 'TaskViewController.getDownloadStatistics',
    'get /api/taskviews/:view': 'TaskViewController.find',
    // HTML
    'get /taskviews': 'TaskViewController.findAll',
    'get /taskviews/:view': 'TaskViewController.find',
    // Backwards compatibility
    'get /domains/:view': 'TaskViewController.redirect',

  // Link
  'get /link/:alias': 'Topic.findByAlias',

  // Search
  'post /api/quick_search': 'SearchController.quickSearch',
  'get /search/keywords/:keyword': 'SearchController.keywordSearch',
  'get /search': 'SearchController.fullSearch'

};
<commit_msg>changed api and removed html for splitted downloads<commit_after>/**
 * Route Mappings
 * (sails.config.routes)
 *
 * Your routes map URLs to views and controllers.
 *
 * If Sails receives a URL that doesn't match any of the routes below,
 * it will check for matching files (images, scripts, stylesheets, etc.)
 * in your assets directory.  e.g. `http://localhost:1337/images/foo.jpg`
 * might match an image file: `/assets/images/foo.jpg`
 *
 * Finally, if those don't match either, the default 404 handler is triggered.
 * See `api/responses/notFound.js` to adjust your app's 404 logic.
 *
 * Note: Sails doesn't ACTUALLY serve stuff from `assets`-- the default Gruntfile in Sails copies
 * flat files from `assets` to `.tmp/public`.  This allows you to do things like compile LESS or
 * CoffeeScript for the front-end.
 *
 * For more information on configuring custom routes, check out:
 * http://sailsjs.org/#!/documentation/concepts/Routes/RouteTargetSyntax.html
 */

module.exports.routes = {
  // Homepage
  'get /': 'HomeController.index',

  // Authentication
  'get /login': 'AuthController.login',
  'get /register': 'AuthController.register',
  'post /login': 'AuthController.process',
  'get /logout': 'AuthController.logout',

  //***** User *****
  'get /users/me' : 'UserController.me',
  //***** /User *****

  //***** Package *****
    // API
    'get /api/packages/:name': 'PackageController.findByName',
    // HTML
    'get /packages/:name': 'PackageController.findByName',
  //***** /Package *****

  //***** PackageVersion *****
    // API
    'get /api/packages/:name/versions/:version/downloads' : 'PackageVersion.getDownloadStatistics',
    'get /api/packages/:name/downloads' : 'PackageVersion.getDownloadStatistics',
    'get /api/packages/:name/versions/:version/percentile' : 'PackageVersion.getPercentile',
    'get /api/packages/:name/percentile' : 'PackageVersion.getPercentile',
    'get /api/packages/:name/versions/:version/downloads/per_day_last_month' : 'PackageVersion.getLastMonthDownloadPerDay',
    'get /api/packages/:name/downloads/per_day_last_month' : 'PackageVersion.getLastMonthDownloadPerDay',
    'get /api/packages/:name/versions/:version': 'PackageVersion.findByNameVersion',
    'post /api/versions': 'PackageVersion.postDescription',
    'get /api/packages/:name/downloads/splitted': 'PackageVersionController.getSplittedDownloadStatistics',
    // HTML
    'get /packages/:name/versions/:version': 'PackageVersion.findByNameVersion',
  //***** /PackageVersion *****

  //***** Topic *****
    //API
    'get /api/topics/:id': 'Topic.findById',
    'get /api/topics/:id/rating': 'Topic.rating',
    'get /api/packages/:name/versions/:version/topics/:topic': 'Topic.findByName',
    'get /api/packages/:name/topics/:function': 'Topic.redirect',
    'post /api/packages/:name/versions/:version/topics': 'Topic.postRdFile',
    //HTML
    'get /topics/:id': 'Topic.findById',
    'get /packages/:name/versions/:version/topics/:topic': 'Topic.findByName',
    // Backwards compatibility
    'get /packages/:name/functions/:function': 'Topic.redirect',
    'get /goto/:name/:function': 'Topic.redirect',
  //***** /Topic *****

  //***** Collaborator *****
    // API
    'get /api/collaborators/:id': 'CollaboratorController.findById',
    // HTML
    'get /collaborators/:id': 'CollaboratorController.findById',
  //***** /Collaborator *****

  //***** Review *****
    // API
    'get /api/topics/:topicId/reviews': 'ReviewController.findByTopic',
    'get /api/packages/:name/versions/:version/reviews': 'ReviewController.findByVersion',
    'post /api/topics/:topicId/reviews': 'ReviewController.postReviewToTopic',
    'post /api/packages/:name/versions/:version/reviews': 'ReviewController.postReviewToVersion',

  //***** TaskViews *****
    // API
    'post /api/taskviews': 'TaskViewController.postView',
    'get /api/taskviews': 'TaskViewController.findAll',
    'get /api/taskviews/:view/statistics': 'TaskViewController.getDownloadStatistics',
    'get /api/taskviews/:view': 'TaskViewController.find',
    // HTML
    'get /taskviews': 'TaskViewController.findAll',
    'get /taskviews/:view': 'TaskViewController.find',
    // Backwards compatibility
    'get /domains/:view': 'TaskViewController.redirect',

  // Link
  'get /link/:alias': 'Topic.findByAlias',

  // Search
  'post /api/quick_search': 'SearchController.quickSearch',
  'get /search/keywords/:keyword': 'SearchController.keywordSearch',
  'get /search': 'SearchController.fullSearch'

};
<|endoftext|>


<commit_before>// Available difficulties
const diff_enum = {
    EASY: 0,
    MEDIUM: 25,
    HARD: 50,
    EXTREME: 100,
};

// Utility Functions
const mv_x = (what, x) => what.style.left = x,
    mv_y = (what, y) => what.style.top = y,
    rand = (limit) => Math.random() * limit,
    inRange = (lower, upper, what) => what >= lower && what <= upper;

// Selectors. Duh!
const catch_me = document.getElementById("catch_me"),
    counter = document.getElementById("counter"),
    body = document.querySelectorAll(".body")[0];

// Useful global values
const catch_height = 50,
    catch_width = 100,
    difficulty = diff_enum.HARD; // CHANGE THIS FOR MORE FUN

const incr_counter = () => counter.innerText = +counter.innerText + 1;
// Next positions should be within the visible portion of the window.
const rand_x = () => rand(window.innerWidth - catch_width),
    rand_y = () => rand(window.innerHeight - catch_height),
    mv_catch_x = () => mv_x(catch_me, rand_x()),
    mv_catch_y = () => mv_y(catch_me, rand_y());

// Initial State
catch_me.style.position = "absolute";
catch_me.style.height = catch_height;
catch_me.style.width = catch_width;
catch_me.style.backgroundColor = "#555";
mv_catch_x();
mv_catch_y();

// If you can get your mouse inside here you get a point.
// But the question is, can you? ;)
catch_me.addEventListener("mouseenter", () => {
    mv_catch_x();
    mv_catch_y();
    incr_counter();
});

// Track mouse movent inside body.
body.addEventListener("mousemove", e => {
    const delta_x = e.offsetX - catch_me.offsetLeft,
        delta_y = e.offsetY - catch_me.offsetTop,
        xInRange = inRange(-difficulty, difficulty + catch_width, delta_x),
        yInRange = inRange(-difficulty, difficulty + catch_height, delta_y);
    if (xInRange && yInRange) {
        mv_catch_x();
        mv_catch_y();
        // console.log(`x: ${delta_x} y: ${delta_y}`);
    }
});
<commit_msg>Fix gray box issue in some browsers<commit_after>// Available difficulties
const diff_enum = {
    EASY: 0,
    MEDIUM: 25,
    HARD: 50,
    EXTREME: 100,
};

// Utility Functions
const mv_x = (what, x) => what.style.left = x,
    mv_y = (what, y) => what.style.top = y,
    rand = (limit) => Math.random() * limit,
    inRange = (lower, upper, what) => what >= lower && what <= upper;

// Selectors. Duh!
const catch_me = document.getElementById("catch_me"),
    counter = document.getElementById("counter"),
    body = document.querySelectorAll(".body")[0];

// Useful global values
const catch_height = 50,
    catch_width = 100,
    difficulty = diff_enum.HARD; // CHANGE THIS FOR MORE FUN

const incr_counter = () => counter.innerText = +counter.innerText + 1;
// Next positions should be within the visible portion of the window.
const rand_x = () => rand(window.innerWidth - catch_width),
    rand_y = () => rand(window.innerHeight - catch_height),
    mv_catch_x = () => mv_x(catch_me, rand_x()),
    mv_catch_y = () => mv_y(catch_me, rand_y());

// Initial State
catch_me.style.position = "absolute";
catch_me.style.height = catch_height + 'px';
catch_me.style.width = catch_width + 'px';
catch_me.style.backgroundColor = "#555";
mv_catch_x();
mv_catch_y();

// If you can get your mouse inside here you get a point.
// But the question is, can you? ;)
catch_me.addEventListener("mouseenter", () => {
    mv_catch_x();
    mv_catch_y();
    incr_counter();
});

// Track mouse movent inside body.
body.addEventListener("mousemove", e => {
    const delta_x = e.offsetX - catch_me.offsetLeft,
        delta_y = e.offsetY - catch_me.offsetTop,
        xInRange = inRange(-difficulty, difficulty + catch_width, delta_x),
        yInRange = inRange(-difficulty, difficulty + catch_height, delta_y);
    if (xInRange && yInRange) {
        mv_catch_x();
        mv_catch_y();
        // console.log(`x: ${delta_x} y: ${delta_y}`);
    }
});
<|endoftext|>