<commit_before>
var _ = require('lodash');
var async = require('async');

var infoToMarkdown = require('./conversions/infoToMarkdown');
var statusToTags = require('./conversions/statusToTags');
var classToTags = require('./conversions/classToTags');

exports.export = function (db, callback) {
  // Export from Locator.
  //
  // Parameters
  //   db
  //     MySQL connection
  //   callback
  //     function (err, result)
  //

  // Aggregate. Store here the converted data from Locator.

  var result = {};

  // Fetch locations

  var loc2location = function (row) {

    // Ensure the coordinates are within required range.
    var lng = Math.max(Math.min(row.loc_lon, 180), -180);
    var lat = Math.max(Math.min(row.loc_lat, 90), -90);

    return {
      name: row.loc_name.trim(),
      geom: {
        type: 'Point',
        coordinates: [lng, lat],
      },
      locatorId: row.loc_id,
      deleted: (row.loc_deleted !== 0),

      tags: (function () {
        var statuses = statusToTags(row.loc_status);
        var classes = classToTags(row.loc_class);

        return statuses.concat(classes);
      }()),

      content: [
        {
          type: 'created',
          user: row.creator,
          time: row.loc_created,
          data: {},
        },
        {
          type: 'story',
          user: row.creator,
          time: row.loc_created,
          data: {
            markdown: infoToMarkdown(row.loc_info),
          },
        },
      ],

      // Dummy values for clustering. Set here so that the keys exist.
      // Values do not need to mean anything.
      neighborsAvgDist: 1000,
      layer: 15,
    };
  };

  var post2story = function (row) {
    return {
      type: 'story',
      user: row.user_nick,
      time: row.posted,
      data: {
        markdown: infoToMarkdown(row.data),
      },
    };
  };

  console.log('Fetching locations...');

  var sql = 'SELECT locs.loc_id, locs.loc_name, ' +
            'locs.loc_lat, locs.loc_lon, ' +
            'locs.loc_created, users.user_nick AS creator, ' +
            'locs.loc_info, locs.loc_deleted, ' +
            'locs.loc_status, locs.loc_class FROM locs ' +
            'INNER JOIN users ' +
            'ON locs.loc_creator=users.user_id ' +
            'LIMIT 30';

  db.query(sql, function (err, rows) {
    if (err) {
      return callback(err);
    }

    console.log(rows.length.toString(), 'locations fetched.');

    var locations = _.map(rows, loc2location);

    // Collect data from other tables for each location
    async.eachSeries(locations, function (loc, next) {

      console.log(loc.name);
      console.log('Fetching comments...');

      var sq2 = 'SELECT users.user_nick, posts.data, posts.posted ' +
                'FROM posts ' +
                'INNER JOIN users ' +
                'ON posts.user_id=users.user_id ' +
                'WHERE posts.thr_id=' + loc.locatorId;

      db.query(sq2, function (err2, rows2) {
        if (err2) {
          return next(err2);
        }

        var comments = rows2.map(post2story);

        Array.prototype.push.apply(loc.content, comments);

        console.log('Fetching classes...');

        var sq3 = 'SELECT class FROM subs WHERE loc=' + loc.locatorId;

        db.query(sq3, function (err4, rows3) {
          if (err4) {
            return next(err4);
          }

          rows3.forEach(function (row) {
            var c = classToTags(row.class);

            if (c.length > 0) {
              loc.tags.push(c[0]);
            }
          });

          console.log('Fetching visits...');

          var sq4 = 'SELECT users.user_nick ' +
                    'FROM visits INNER JOIN users ' +
                    'ON visits.vis_visitor=users.user_id ' +
                    'WHERE visits.vis_location=' + loc.locatorId;

          db.query(sq4, function (err5, rows5) {
            if (err5) {
              return next(err5);
            }

            var now = new Date();

            rows5.forEach(function (row) {
              loc.content.push({
                type: 'visit',
                user: row.user_nick,
                time: now.toISOString(),
                data: {
                  year: null,
                },
              });
            });

            console.log('Fetching references...');

            var sq5 = 'SELECT users.user_nick, refs.date, refs.url ' +
                      'FROM refs INNER JOIN users ' +
                      'ON refs.user=users.user_id ' +
                      'WHERE refs.enabled=1 AND refs.node=' + loc.locatorId;

            db.query(sq5, function (err6, rows6) {
              if (err6) {
                return next(err6);
              }

              rows6.forEach(function (row) {
                loc.content.push({
                  type: 'story',
                  user: row.user_nick,
                  time: row.date,
                  data: {
                    markdown: '[' + row.url + '](' + row.url + ')',
                  },
                });
              });

              console.log('Fetching attachments...');

              var sq6 = 'SELECT users.user_nick, files.fil_name,' +
                        'files.fil_key, files.fil_created ' +
                        'FROM files INNER JOIN users ' +
                        'ON files.fil_creator=users.user_id ' +
                        'WHERE files.fil_loc=' + loc.locatorId;

              db.query(sq6, function (err7, rows7) {
                if (err7) {
                  return next(err7);
                }

                rows7.forEach(function (row) {
                  loc.content.push({
                    type: 'attachment',
                    user: row.user_nick,
                    time: row.fil_created,
                    data: {
                      filename: row.fil_name,
                      key: row.fil_key,
                    },
                  });
                });

                return next();
              });
            });
          });
        });
      });

    }, function then(err3) {
      if (err3) {
        return callback(err3);
      }

      return callback(null, {
        locations: locations,
      });
    });

  });

};

exports.import = function (db, dump, callback) {
  // Import to TresDB

  var locations = db.collection('locations');

  locations.insertMany(dump.locations, function (err, result) {
    if (err) {
      return callback(err);
    }

    var n = result.result.n;

    console.log(n + ' locations inserted successfully.');

    return callback();
  });
};
<commit_msg>Remove debug limit<commit_after>
var _ = require('lodash');
var async = require('async');

var infoToMarkdown = require('./conversions/infoToMarkdown');
var statusToTags = require('./conversions/statusToTags');
var classToTags = require('./conversions/classToTags');

exports.export = function (db, callback) {
  // Export from Locator.
  //
  // Parameters
  //   db
  //     MySQL connection
  //   callback
  //     function (err, result)
  //

  // Aggregate. Store here the converted data from Locator.

  var result = {};

  // Fetch locations

  var loc2location = function (row) {

    // Ensure the coordinates are within required range.
    var lng = Math.max(Math.min(row.loc_lon, 180), -180);
    var lat = Math.max(Math.min(row.loc_lat, 90), -90);

    return {
      name: row.loc_name.trim(),
      geom: {
        type: 'Point',
        coordinates: [lng, lat],
      },
      locatorId: row.loc_id,
      deleted: (row.loc_deleted !== 0),

      tags: (function () {
        var statuses = statusToTags(row.loc_status);
        var classes = classToTags(row.loc_class);

        return statuses.concat(classes);
      }()),

      content: [
        {
          type: 'created',
          user: row.creator,
          time: row.loc_created,
          data: {},
        },
        {
          type: 'story',
          user: row.creator,
          time: row.loc_created,
          data: {
            markdown: infoToMarkdown(row.loc_info),
          },
        },
      ],

      // Dummy values for clustering. Set here so that the keys exist.
      // Values do not need to mean anything.
      neighborsAvgDist: 1000,
      layer: 15,
    };
  };

  var post2story = function (row) {
    return {
      type: 'story',
      user: row.user_nick,
      time: row.posted,
      data: {
        markdown: infoToMarkdown(row.data),
      },
    };
  };

  console.log('Fetching locations...');

  var sql = 'SELECT locs.loc_id, locs.loc_name, ' +
            'locs.loc_lat, locs.loc_lon, ' +
            'locs.loc_created, users.user_nick AS creator, ' +
            'locs.loc_info, locs.loc_deleted, ' +
            'locs.loc_status, locs.loc_class FROM locs ' +
            'INNER JOIN users ' +
            'ON locs.loc_creator=users.user_id';

  db.query(sql, function (err, rows) {
    if (err) {
      return callback(err);
    }

    console.log(rows.length.toString(), 'locations fetched.');

    var locations = _.map(rows, loc2location);

    // Collect data from other tables for each location
    async.eachSeries(locations, function (loc, next) {

      console.log(loc.name);
      console.log('Fetching comments...');

      var sq2 = 'SELECT users.user_nick, posts.data, posts.posted ' +
                'FROM posts ' +
                'INNER JOIN users ' +
                'ON posts.user_id=users.user_id ' +
                'WHERE posts.thr_id=' + loc.locatorId;

      db.query(sq2, function (err2, rows2) {
        if (err2) {
          return next(err2);
        }

        var comments = rows2.map(post2story);

        Array.prototype.push.apply(loc.content, comments);

        console.log('Fetching classes...');

        var sq3 = 'SELECT class FROM subs WHERE loc=' + loc.locatorId;

        db.query(sq3, function (err4, rows3) {
          if (err4) {
            return next(err4);
          }

          rows3.forEach(function (row) {
            var c = classToTags(row.class);

            if (c.length > 0) {
              loc.tags.push(c[0]);
            }
          });

          console.log('Fetching visits...');

          var sq4 = 'SELECT users.user_nick ' +
                    'FROM visits INNER JOIN users ' +
                    'ON visits.vis_visitor=users.user_id ' +
                    'WHERE visits.vis_location=' + loc.locatorId;

          db.query(sq4, function (err5, rows5) {
            if (err5) {
              return next(err5);
            }

            var now = new Date();

            rows5.forEach(function (row) {
              loc.content.push({
                type: 'visit',
                user: row.user_nick,
                time: now.toISOString(),
                data: {
                  year: null,
                },
              });
            });

            console.log('Fetching references...');

            var sq5 = 'SELECT users.user_nick, refs.date, refs.url ' +
                      'FROM refs INNER JOIN users ' +
                      'ON refs.user=users.user_id ' +
                      'WHERE refs.enabled=1 AND refs.node=' + loc.locatorId;

            db.query(sq5, function (err6, rows6) {
              if (err6) {
                return next(err6);
              }

              rows6.forEach(function (row) {
                loc.content.push({
                  type: 'story',
                  user: row.user_nick,
                  time: row.date,
                  data: {
                    markdown: '[' + row.url + '](' + row.url + ')',
                  },
                });
              });

              console.log('Fetching attachments...');

              var sq6 = 'SELECT users.user_nick, files.fil_name,' +
                        'files.fil_key, files.fil_created ' +
                        'FROM files INNER JOIN users ' +
                        'ON files.fil_creator=users.user_id ' +
                        'WHERE files.fil_loc=' + loc.locatorId;

              db.query(sq6, function (err7, rows7) {
                if (err7) {
                  return next(err7);
                }

                rows7.forEach(function (row) {
                  loc.content.push({
                    type: 'attachment',
                    user: row.user_nick,
                    time: row.fil_created,
                    data: {
                      filename: row.fil_name,
                      key: row.fil_key,
                    },
                  });
                });

                return next();
              });
            });
          });
        });
      });

    }, function then(err3) {
      if (err3) {
        return callback(err3);
      }

      return callback(null, {
        locations: locations,
      });
    });

  });

};

exports.import = function (db, dump, callback) {
  // Import to TresDB

  var locations = db.collection('locations');

  locations.insertMany(dump.locations, function (err, result) {
    if (err) {
      return callback(err);
    }

    var n = result.result.n;

    console.log(n + ' locations inserted successfully.');

    return callback();
  });
};
<|endoftext|>


<commit_before>/*jshint globalstrict: true*/ 'use strict';

var child_process = require('child_process');

module.exports = function(app, verbose, done) {
  var args = [
    'splunkapp',
    app.path()
  ];
  var proc = child_process.spawn('yo', args, { stdio: 'inherit' });
  console.dir(args);
  proc.on('error', function(err) {
    console.error(err);
    process.exit(4);
  });
  proc.on('exit', function(code) {
    if (code !== 0) {
      console.error('ERRCODE: ' + code);
      process.exit(4);
    } else {
      if (done) {
        done();
      }
    }
  });
};<commit_msg>Launch yeoman always from splunk-cli location to be sure that splunkapp generator always will be discovered<commit_after>/*jshint globalstrict: true*/ 'use strict';

var child_process = require('child_process'),
    path = require('path');

module.exports = function(app, verbose, done) {
  var args = [
    'splunkapp',
    app.path()
  ];
  var proc = child_process.spawn('yo', args, {
    stdio: 'inherit',
    cwd: path.join(__dirname, '..')
  });
  proc.on('error', function(err) {
    console.error(err);
    process.exit(4);
  });
  proc.on('exit', function(code) {
    if (code !== 0) {
      console.error('ERRCODE: ' + code);
      process.exit(4);
    } else {
      if (done) {
        done();
      }
    }
  });
};<|endoftext|>


<commit_before>'use strict';

const check = require('check-types');
const common = require('./../common');
const pageToGenerator = require('../utils/pageToGenerator');
const collectQueryParams = require('../utils/collectQueryParams');
const querystring = require('querystring');

const ENDPT = 'metrics';

const DELETE_QUERY_PARAMS = ['key', 'subject'];

// Metrics module
// @param context: The context to make requests in. Basically, `this`
module.exports = function metrics(context) {
    const obj = common(context, ENDPT);

    class MetricQueryBuilder {
        constructor(context) {
            this.context = context;
        }

        key(key) {
            check.string(key, 'key must be a string');
            this.key = key;
            return this;
        }

        subject(subject) {
            check.string(subject, 'subject must be a string');
            this.subject = subject;
            return this;
        }

        // delete all queried metrics
        // @param userOpts: option overrides for this request
        // @returns Returns a promise that resolves to an object stating the number of deleted metrics
        remove(userOpts) {
            const queryBy = collectQueryParams(this, DELETE_QUERY_PARAMS);

            if (Object.keys(queryBy).length === 0) {
                throw new Error('You must specify at least the "subject" or "key"');
            }

            return this.context.http.makeRequest({
                method: 'DELETE',
                url: `/v1/apps/${this.context.applicationId}/${ENDPT}?${querystring.stringify(queryBy)}`
            }, userOpts);
        }
    }

    // retrives metrics for a subject, returned as an array
    // @param subject: subject to retrieve the metrics for
    // @param userOpts: option overrides for this request
    // @returns Returns a promise that resolves to a list of metrics
    function getAllSubjectMetrics(subject, userOpts) {
        check.string(subject, 'subject must be a string');

        let array = [];
        let url = `/v1/apps/${context.applicationId}/${ENDPT}/${subject}`;

        function pageFn() {
            return context.http.makeRequest({ url }, userOpts).then(function(body) {
                array = array.concat(body.data || []); // concatinate the new data

                url = body.pages.next;
                if (url) {
                    return pageFn();
                } else {
                    return array;
                }
            });
        }

        return pageFn();
    }

    // retrives metrics for a subject, returned as an iterator
    // @param subject: subject to retrieve the metrics for
    // @param userOpts: option overrides for this request
    // @return An iterator that returns promises that resolve with the next object
    function* getSubjectMetricsIterator(subject, userOpts) {
        check.string(subject, 'subject must be a string');

        function pageFn() {
            let url = `/v1/apps/${context.applicationId}/${ENDPT}/${subject}`;
            return function() {
                return context.http.makeRequest({ url }, userOpts).then(function(body) {
                    url = body.pages.next;
                    return body;
                });
            };
        }

        yield* pageToGenerator(pageFn());
    }

    // retrieves a single metric for a subject by key
    // @param subject: subject to retrieve the metric for
    // @param key: metric key to retrive the metric for
    // @param userOpts: option overrides for this request
    // @returns Returns a promise that resolves to a single metric
    function getIndividualSubjectMetric(subject, key, userOpts) {
        check.string(subject, 'id must be a string');
        check.string(key, 'key must be a string');

        return context.http.makeRequest({
            url: `/v1/apps/${context.applicationId}/${ENDPT}/${subject}/${key}`
        }, userOpts);
    }

    // Sets up a delete/get request targeting metrics using query filters
    // @param queryBy: filters to query events by
    // @returns Returns an instance of the EventQueryBuilder class
    function query() {
        return new MetricQueryBuilder(context);
    }

    return {
        getAll: obj.getAll,
        getIterator: obj.getIterator,
        create: obj.create,
        getAllSubjectMetrics,
        getSubjectMetricsIterator,
        getIndividualSubjectMetric, // TODO: consider aliasing to "get"
        query
    };
};
<commit_msg>typo<commit_after>'use strict';

const check = require('check-types');
const common = require('./../common');
const pageToGenerator = require('../utils/pageToGenerator');
const collectQueryParams = require('../utils/collectQueryParams');
const querystring = require('querystring');

const ENDPT = 'metrics';

const DELETE_QUERY_PARAMS = ['key', 'subject'];

// Metrics module
// @param context: The context to make requests in. Basically, `this`
module.exports = function metrics(context) {
    const obj = common(context, ENDPT);

    class MetricQueryBuilder {
        constructor(context) {
            this.context = context;
        }

        key(key) {
            check.string(key, 'key must be a string');
            this.key = key;
            return this;
        }

        subject(subject) {
            check.string(subject, 'subject must be a string');
            this.subject = subject;
            return this;
        }

        // delete all queried metrics
        // @param userOpts: option overrides for this request
        // @returns Returns a promise that resolves to an object stating the number of deleted metrics
        remove(userOpts) {
            const queryBy = collectQueryParams(this, DELETE_QUERY_PARAMS);

            if (Object.keys(queryBy).length === 0) {
                throw new Error('You must specify at least the "subject" or "key"');
            }

            return this.context.http.makeRequest({
                method: 'DELETE',
                url: `/v1/apps/${this.context.applicationId}/${ENDPT}?${querystring.stringify(queryBy)}`
            }, userOpts);
        }
    }

    // retrives metrics for a subject, returned as an array
    // @param subject: subject to retrieve the metrics for
    // @param userOpts: option overrides for this request
    // @returns Returns a promise that resolves to a list of metrics
    function getAllSubjectMetrics(subject, userOpts) {
        check.string(subject, 'subject must be a string');

        let array = [];
        let url = `/v1/apps/${context.applicationId}/${ENDPT}/${subject}`;

        function pageFn() {
            return context.http.makeRequest({ url }, userOpts).then(function(body) {
                array = array.concat(body.data || []); // concatinate the new data

                url = body.pages.next;
                if (url) {
                    return pageFn();
                } else {
                    return array;
                }
            });
        }

        return pageFn();
    }

    // retrives metrics for a subject, returned as an iterator
    // @param subject: subject to retrieve the metrics for
    // @param userOpts: option overrides for this request
    // @return An iterator that returns promises that resolve with the next object
    function* getSubjectMetricsIterator(subject, userOpts) {
        check.string(subject, 'subject must be a string');

        function pageFn() {
            let url = `/v1/apps/${context.applicationId}/${ENDPT}/${subject}`;
            return function() {
                return context.http.makeRequest({ url }, userOpts).then(function(body) {
                    url = body.pages.next;
                    return body;
                });
            };
        }

        yield* pageToGenerator(pageFn());
    }

    // retrieves a single metric for a subject by key
    // @param subject: subject to retrieve the metric for
    // @param key: metric key to retrive the metric for
    // @param userOpts: option overrides for this request
    // @returns Returns a promise that resolves to a single metric
    function getIndividualSubjectMetric(subject, key, userOpts) {
        check.string(subject, 'subject must be a string');
        check.string(key, 'key must be a string');

        return context.http.makeRequest({
            url: `/v1/apps/${context.applicationId}/${ENDPT}/${subject}/${key}`
        }, userOpts);
    }

    // Sets up a delete/get request targeting metrics using query filters
    // @param queryBy: filters to query events by
    // @returns Returns an instance of the EventQueryBuilder class
    function query() {
        return new MetricQueryBuilder(context);
    }

    return {
        getAll: obj.getAll,
        getIterator: obj.getIterator,
        create: obj.create,
        getAllSubjectMetrics,
        getSubjectMetricsIterator,
        getIndividualSubjectMetric, // TODO: consider aliasing to "get"
        query
    };
};
<|endoftext|>


<commit_before>var beRightThereMap = (function() {
    var map;
    var travelPath;
    var autoFocusEnabled = true;

    function createTravelPath(map, locations) {
        var travelPath = L.polyline([], {color: '#00a2e8'}).addTo(map);
        if(locations.length > 0) {
            appendTravelPath(travelPath, locations);
            fitBounds(map, travelPath, autoFocusEnabled);
        }
        return travelPath;
    }

    function appendTravelPath(travelPath, locations) {
        locations.forEach(function(location) {
            addTravelPathLocation(travelPath, location);
        });
    }

    function addTravelPathLocation(travelPath, location) {
        travelPath.addLatLng(L.latLng([location.latitude, location.longitude]));
    }

    function fitBounds(map, travelPath, autoFocusEnabled) {
        if(autoFocusEnabled) {
            map.fitBounds(travelPath.getBounds());
        }
    }

    function initMap(locations) {
        map = L.map('map');

        var osmUrl = 'https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}@2x.png';
        var osmAttrib = '© OpenStreetMap, © CARTO';
        var osm = new L.TileLayer(osmUrl, {minZoom: 6, maxZoom: 18, attribution: osmAttrib});

        map.setView([55.676, 12.568], 9);
        map.addLayer(osm);

        travelPath = createTravelPath(map, locations);
        initAutoFocusControl(map, travelPath);
    }

    function initAutoFocusControl(map, travelPath) {
        var button;

        function handleClick(event) {
            autoFocusEnabled = !autoFocusEnabled;
            fitBounds(map, travelPath, autoFocusEnabled);

            if(autoFocusEnabled) {
                L.DomUtil.addClass(button, 'focusing');
            }
            else {
                L.DomUtil.removeClass(button, 'focusing');
            }
        }

        L.Control.AutoFocus = L.Control.extend({
            onAdd: function(map) {
                container = L.DomUtil.create('div', 'leaflet-bar leaflet-control');
                button = L.DomUtil.create('a', 'auto-focus focusing', container);
                button.innerHTML = '';
                button.role = "button";
                button.href = "#";

                L.DomEvent.disableClickPropagation(button);
                L.DomEvent.on(button, 'click', handleClick);

                return container;
            },

            onRemove: function(map) {
                L.DomEvent.off(button, 'click', handleClick);
            }
        });

        L.control.autofocus = function(opts) {
            return new L.Control.AutoFocus(opts);
        };

        L.control.autofocus({ position: 'bottomleft' }).addTo(map);
    }

    function initialize(initialLocations) {
        initMap(initialLocations);
        registerEventHandlers();
    }

    function registerEventHandlers() {
        $(document).on('new-location', function(event, location) {
            addTravelPathLocation(travelPath, location);
            fitBounds(map, travelPath, autoFocusEnabled);
        });
    }

    return {
        initialize: initialize
    };
}());

<commit_msg>Added a marker for the latest location.<commit_after>var beRightThereMap = (function() {
    var map;
    var travelPath;
    var positionMarker;
    var autoFocusEnabled = true;

    function createTravelPath(map, locations) {
        var latLngs = locations.map(function(location) {
            return [location.latitude, location.longitude];
        });
        var newTravelPath = L.polyline(latLngs, {color: '#00a2e8'}).addTo(map);
        fitBounds(map, newTravelPath, autoFocusEnabled);

        return newTravelPath;
    }

    function addTravelPathLocation(travelPath, location) {
        travelPath.addLatLng(L.latLng([location.latitude, location.longitude]));
    }

    function createPositionMarker(map, location) {
        return L.marker([location.latitude, location.longitude]).addTo(map);
    }

    function updatePositionMarker(positionMarker, location) {
        positionMarker.setLatLng([location.latitude, location.longitude]);
    }

    function fitBounds(map, travelPath, autoFocusEnabled) {
        if(autoFocusEnabled) {
            map.fitBounds(travelPath.getBounds());
        }
    }

    function initMap(locations) {
        map = L.map('map');

        var osmUrl = 'https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}@2x.png';
        var osmAttrib = '© OpenStreetMap, © CARTO';
        var osm = new L.TileLayer(osmUrl, {minZoom: 6, maxZoom: 18, attribution: osmAttrib});

        map.setView([55.676, 12.568], 9);
        map.addLayer(osm);

        travelPath = createTravelPath(map, locations);
        positionMarker = createPositionMarker(map, locations[locations.length-1]);
        initAutoFocusControl(map, travelPath);
    }

    function initAutoFocusControl(map, travelPath) {
        var button;

        function handleClick(event) {
            autoFocusEnabled = !autoFocusEnabled;
            fitBounds(map, travelPath, autoFocusEnabled);

            if(autoFocusEnabled) {
                L.DomUtil.addClass(button, 'focusing');
            }
            else {
                L.DomUtil.removeClass(button, 'focusing');
            }
        }

        L.Control.AutoFocus = L.Control.extend({
            onAdd: function(map) {
                container = L.DomUtil.create('div', 'leaflet-bar leaflet-control');
                button = L.DomUtil.create('a', 'auto-focus focusing', container);
                button.innerHTML = '';
                button.role = "button";
                button.href = "#";

                L.DomEvent.disableClickPropagation(button);
                L.DomEvent.on(button, 'click', handleClick);

                return container;
            },

            onRemove: function(map) {
                L.DomEvent.off(button, 'click', handleClick);
            }
        });

        L.control.autofocus = function(opts) {
            return new L.Control.AutoFocus(opts);
        };

        L.control.autofocus({ position: 'bottomleft' }).addTo(map);
    }

    function initialize(initialLocations) {
        initMap(initialLocations);
        registerEventHandlers();
    }

    function registerEventHandlers() {
        $(document).on('new-location', function(event, location) {
            addTravelPathLocation(travelPath, location);
            fitBounds(map, travelPath, autoFocusEnabled);
            updatePositionMarker(positionMarker, location);
        });
    }

    return {
        initialize: initialize
    };
}());

<|endoftext|>


<commit_before>import { LightningElement, track, api } from 'lwc';
import {
    findIndexByProperty,
    mutable,
    dispatch,
    handleError,
    findMissingRequiredBatchFields
} from 'c/utilTemplateBuilder';
import DI_BATCH_INFO from '@salesforce/schema/DataImportBatch__c';

// Import custom labels
import geHeaderBatchHeaderLeftCol from '@salesforce/label/c.geHeaderBatchHeaderLeftCol';
import geBodyBatchHeaderLeftCol from '@salesforce/label/c.geBodyBatchHeaderLeftCol';
import geHeaderBatchHeaderRightCol from '@salesforce/label/c.geHeaderBatchHeaderRightCol';
import geBodyBatchHeaderRightCol from '@salesforce/label/c.geBodyBatchHeaderRightCol';
import geHelpTextBatchHeaderFieldLabelLabel from '@salesforce/label/c.geHelpTextBatchHeaderFieldLabelLabel';
import commonDefaultValue from '@salesforce/label/c.commonDefaultValue';
import commonFieldLabel from '@salesforce/label/c.commonFieldLabel';
import commonRequired from '@salesforce/label/c.commonRequired';
import geAssistiveSpinner from '@salesforce/label/c.geAssistiveSpinner';

const PROP_API_NAME = 'apiName';
const PROP_BATCH_HEADER_TAB_ERROR = 'hasBatchHeaderTabError';
const EVENT_UPDATE_VALIDITY = 'updatevalidity';
const EVENT_BATCH_HEADER_FIELD_UPDATE = 'updatebatchheaderfield';
const EVENT_BATCH_HEADER_FIELD_UP = 'batchheaderfieldup';
const EVENT_BATCH_HEADER_FIELD_DOWN = 'batchheaderfielddown';
const EVENT_BATCH_HEADER_FIELD_ADD = 'addbatchheaderfield';
const EVENT_BATCH_HEADER_FIELD_REMOVE = 'removebatchheaderfield';

export default class geTemplateBuilderBatchHeader extends LightningElement {

    // Expose custom labels to template
    CUSTOM_LABELS = {
        geHeaderBatchHeaderLeftCol,
        geBodyBatchHeaderLeftCol,
        geHeaderBatchHeaderRightCol,
        geBodyBatchHeaderRightCol,
        geHelpTextBatchHeaderFieldLabelLabel,
        commonDefaultValue,
        commonFieldLabel,
        commonRequired,
        geAssistiveSpinner
    }

    @track isLoading = true;
    @api batchFields;
    @api selectedBatchFields;
    @track hasErrors;
    @api missingRequiredFields;
    isInitialized = false;

    get dataImportBatchName() {
        return DI_BATCH_INFO && DI_BATCH_INFO.objectApiName ? DI_BATCH_INFO.objectApiName : null;
    }

    renderedCallback() {
        if (!this.isInitialized && this.isLoading === false) {
            this.isInitialized = true;
            this.validate();
        }
    }

    connectedCallback() {
        try {
            this.handleRequiredFields();
            this.toggleCheckboxForSelectedBatchFields();
            this.validate();
            this.isLoading = false;
        } catch (error) {
            handleError(this, error);
            this.isLoading = false;
        }
    }

    /*******************************************************************************
    * @description Checks to see if there are any errors for the tab. Currently only
    * checks for missing required fields.
    *
    * @return {boolean} hasErrors: Returns true if tab has any errors.
    */
    @api
    validate() {
        this.hasErrors = this.hasMissingRequiredFields();
        return !this.hasErrors;
    }

    /*******************************************************************************
    * @description Checks for any missing required DataImportBatch__c fields.
    *
    * @return {boolean} hasMissingFields: Returns true if any DataImportBatch__c
    * fields are missing.
    */
    hasMissingRequiredFields() {
        let hasMissingFields = false;
        if (this.missingRequiredFields === null || this.missingRequiredFields.length === 0) {
            this.missingRequiredFields = findMissingRequiredBatchFields(this.batchFields, this.selectedBatchFields);
        }

        if (this.missingRequiredFields && this.missingRequiredFields.length > 0) {
            dispatch(this, EVENT_UPDATE_VALIDITY, {
                property: PROP_BATCH_HEADER_TAB_ERROR,
                hasError: false
            });
            hasMissingFields = true;
        } else {
            hasMissingFields = false;
        }

        return hasMissingFields;
    }

    /*******************************************************************************
    * @description Receives event from child component and dispatches event to
    * parent to update a batch header field's details.
    *
    * @param {object} event: Event received from child component.
    * component chain: geTemplateBuilderFormField -> here
    */
    handleUpdateBatchHeaderField(event) {
        dispatch(this, EVENT_BATCH_HEADER_FIELD_UPDATE, event.detail);
    }

    /*******************************************************************************
    * @description Receives event from child component and dispatches event to
    * parent to move a batch header field up.
    *
    * @param {object} event: Event received from child component.
    * component chain: geTemplateBuilderFormField -> here
    */
    handleFormElementUp(event) {
        dispatch(this, EVENT_BATCH_HEADER_FIELD_UP, event.detail);
    }

    /*******************************************************************************
    * @description Receives event from child component and dispatches event to
    * parent to move a batch header field down.
    *
    * @param {object} event: Event received from child component.
    * component chain: geTemplateBuilderFormField -> here
    */
    handleFormElementDown(event) {
        dispatch(this, EVENT_BATCH_HEADER_FIELD_DOWN, event.detail);
    }

    /*******************************************************************************
    * @description Onchange event handler for the batch header field checkboxes.
    * Adds/removes batch header fields.
    *
    * @param {object} event: Onchange event object from lightning-input checkbox
    */
    handleToggleBatchField(event) {
        const fieldName = event.target.value;
        const index = findIndexByProperty(this.selectedBatchFields, PROP_API_NAME, fieldName);
        const addSelectedField = index === -1 ? true : false;

        if (addSelectedField) {
            this.addField(fieldName)
        } else {
            this.removeField(index, fieldName);
        }
    }

    /*******************************************************************************
    * @description Creates an instance of BatchHeaderField. Dispatches an event to
    * notify parent component geTemplateBuilder that a new batch header field
    * needs to be added.
    *
    * @param {string} fieldName: DataImport__c field api name
    */
    addField(fieldName) {
        let batchFields = mutable(this.batchFields);

        dispatch(this, EVENT_BATCH_HEADER_FIELD_ADD, fieldName);

        const batchFieldIndex = findIndexByProperty(
            batchFields,
            PROP_API_NAME,
            fieldName);
        batchFields[batchFieldIndex].checked = true;
        this.batchFields = batchFields;
    }

    /*******************************************************************************
    * @description Finds the index of the BatchHeaderField to be removed. Dispatches
    * an event to notify parent component geTemplateBuilder that a batch header field
    * needs to be removed.
    *
    * @param {integer} index: Index of field in the selectedBatchHeaderFields
    * @param {string} fieldName: DataImport__c field api name
    */
    removeField(index, fieldName) {
        const batchFieldIndex = findIndexByProperty(
            this.batchFields,
            PROP_API_NAME,
            fieldName);
        this.batchFields[batchFieldIndex].checked = false;

        dispatch(this, EVENT_BATCH_HEADER_FIELD_REMOVE, index);
    }

    /*******************************************************************************
    * @description Receives event from child component and calls removeField method
    * to dispatch an event notifying parent component geTemplateBuilder that a
    * batch header field needs to be removed.
    *
    * @param {object} event: Event received from child component.
    * component chain: geTemplateBuilderFormField -> here
    */
    handleDeleteBatchHeaderField(event) {
        const fieldName = event.detail.fieldName;
        const index = findIndexByProperty(this.selectedBatchFields, PROP_API_NAME, fieldName);
        this.removeField(index, fieldName);
    }

    /*******************************************************************************
    * @description Adds required fields to selectedBatchFields property
    */
    handleRequiredFields() {
        const requiredFields = this.batchFields.filter(batchField => { return batchField.required });
        const selectedFieldsExists = this.selectedBatchFields && this.selectedBatchFields.length > 0;

        requiredFields.forEach((field) => {
            if (selectedFieldsExists) {
                const alreadySelected = this.selectedBatchFields.find(bf => { return bf.apiName === field.apiName; });
                if (alreadySelected) { return; }
            }

            this.addField(field.apiName);
        });
    }

    /*******************************************************************************
    * @description Method toggles the checkboxes for any existing/selected batch
    * header fields. Used when retrieving an existing form template.
    */
    toggleCheckboxForSelectedBatchFields() {
        if (this.selectedBatchFields && this.selectedBatchFields.length > 0) {
            let _batchFields = mutable(this.batchFields);

            for (let i = 0; i < this.selectedBatchFields.length; i++) {
                const selectedBatchField = this.selectedBatchFields[i];
                const batchFieldIndex = findIndexByProperty(
                    _batchFields,
                    PROP_API_NAME,
                    selectedBatchField.apiName);

                _batchFields[batchFieldIndex].checked = true;
            }

            this.batchFields = _batchFields;
        }
    }
}
<commit_msg>update geTemplateBuilderBatchHeader to use geLabelService<commit_after>import { LightningElement, track, api } from 'lwc';
import {
    findIndexByProperty,
    mutable,
    dispatch,
    handleError,
    findMissingRequiredBatchFields
} from 'c/utilTemplateBuilder';
import DI_BATCH_INFO from '@salesforce/schema/DataImportBatch__c';

const PROP_API_NAME = 'apiName';
const PROP_BATCH_HEADER_TAB_ERROR = 'hasBatchHeaderTabError';
const EVENT_UPDATE_VALIDITY = 'updatevalidity';
const EVENT_BATCH_HEADER_FIELD_UPDATE = 'updatebatchheaderfield';
const EVENT_BATCH_HEADER_FIELD_UP = 'batchheaderfieldup';
const EVENT_BATCH_HEADER_FIELD_DOWN = 'batchheaderfielddown';
const EVENT_BATCH_HEADER_FIELD_ADD = 'addbatchheaderfield';
const EVENT_BATCH_HEADER_FIELD_REMOVE = 'removebatchheaderfield';

export default class geTemplateBuilderBatchHeader extends LightningElement {

    // Expose custom labels to template
    CUSTOM_LABELS = GeLabelService.CUSTOM_LABELS;

    @track isLoading = true;
    @api batchFields;
    @api selectedBatchFields;
    @track hasErrors;
    @api missingRequiredFields;
    isInitialized = false;

    get dataImportBatchName() {
        return DI_BATCH_INFO && DI_BATCH_INFO.objectApiName ? DI_BATCH_INFO.objectApiName : null;
    }

    renderedCallback() {
        if (!this.isInitialized && this.isLoading === false) {
            this.isInitialized = true;
            this.validate();
        }
    }

    connectedCallback() {
        try {
            this.handleRequiredFields();
            this.toggleCheckboxForSelectedBatchFields();
            this.validate();
            this.isLoading = false;
        } catch (error) {
            handleError(this, error);
            this.isLoading = false;
        }
    }

    /*******************************************************************************
    * @description Checks to see if there are any errors for the tab. Currently only
    * checks for missing required fields.
    *
    * @return {boolean} hasErrors: Returns true if tab has any errors.
    */
    @api
    validate() {
        this.hasErrors = this.hasMissingRequiredFields();
        return !this.hasErrors;
    }

    /*******************************************************************************
    * @description Checks for any missing required DataImportBatch__c fields.
    *
    * @return {boolean} hasMissingFields: Returns true if any DataImportBatch__c
    * fields are missing.
    */
    hasMissingRequiredFields() {
        let hasMissingFields = false;
        if (this.missingRequiredFields === null || this.missingRequiredFields.length === 0) {
            this.missingRequiredFields = findMissingRequiredBatchFields(this.batchFields, this.selectedBatchFields);
        }

        if (this.missingRequiredFields && this.missingRequiredFields.length > 0) {
            dispatch(this, EVENT_UPDATE_VALIDITY, {
                property: PROP_BATCH_HEADER_TAB_ERROR,
                hasError: false
            });
            hasMissingFields = true;
        } else {
            hasMissingFields = false;
        }

        return hasMissingFields;
    }

    /*******************************************************************************
    * @description Receives event from child component and dispatches event to
    * parent to update a batch header field's details.
    *
    * @param {object} event: Event received from child component.
    * component chain: geTemplateBuilderFormField -> here
    */
    handleUpdateBatchHeaderField(event) {
        dispatch(this, EVENT_BATCH_HEADER_FIELD_UPDATE, event.detail);
    }

    /*******************************************************************************
    * @description Receives event from child component and dispatches event to
    * parent to move a batch header field up.
    *
    * @param {object} event: Event received from child component.
    * component chain: geTemplateBuilderFormField -> here
    */
    handleFormElementUp(event) {
        dispatch(this, EVENT_BATCH_HEADER_FIELD_UP, event.detail);
    }

    /*******************************************************************************
    * @description Receives event from child component and dispatches event to
    * parent to move a batch header field down.
    *
    * @param {object} event: Event received from child component.
    * component chain: geTemplateBuilderFormField -> here
    */
    handleFormElementDown(event) {
        dispatch(this, EVENT_BATCH_HEADER_FIELD_DOWN, event.detail);
    }

    /*******************************************************************************
    * @description Onchange event handler for the batch header field checkboxes.
    * Adds/removes batch header fields.
    *
    * @param {object} event: Onchange event object from lightning-input checkbox
    */
    handleToggleBatchField(event) {
        const fieldName = event.target.value;
        const index = findIndexByProperty(this.selectedBatchFields, PROP_API_NAME, fieldName);
        const addSelectedField = index === -1 ? true : false;

        if (addSelectedField) {
            this.addField(fieldName)
        } else {
            this.removeField(index, fieldName);
        }
    }

    /*******************************************************************************
    * @description Creates an instance of BatchHeaderField. Dispatches an event to
    * notify parent component geTemplateBuilder that a new batch header field
    * needs to be added.
    *
    * @param {string} fieldName: DataImport__c field api name
    */
    addField(fieldName) {
        let batchFields = mutable(this.batchFields);

        dispatch(this, EVENT_BATCH_HEADER_FIELD_ADD, fieldName);

        const batchFieldIndex = findIndexByProperty(
            batchFields,
            PROP_API_NAME,
            fieldName);
        batchFields[batchFieldIndex].checked = true;
        this.batchFields = batchFields;
    }

    /*******************************************************************************
    * @description Finds the index of the BatchHeaderField to be removed. Dispatches
    * an event to notify parent component geTemplateBuilder that a batch header field
    * needs to be removed.
    *
    * @param {integer} index: Index of field in the selectedBatchHeaderFields
    * @param {string} fieldName: DataImport__c field api name
    */
    removeField(index, fieldName) {
        const batchFieldIndex = findIndexByProperty(
            this.batchFields,
            PROP_API_NAME,
            fieldName);
        this.batchFields[batchFieldIndex].checked = false;

        dispatch(this, EVENT_BATCH_HEADER_FIELD_REMOVE, index);
    }

    /*******************************************************************************
    * @description Receives event from child component and calls removeField method
    * to dispatch an event notifying parent component geTemplateBuilder that a
    * batch header field needs to be removed.
    *
    * @param {object} event: Event received from child component.
    * component chain: geTemplateBuilderFormField -> here
    */
    handleDeleteBatchHeaderField(event) {
        const fieldName = event.detail.fieldName;
        const index = findIndexByProperty(this.selectedBatchFields, PROP_API_NAME, fieldName);
        this.removeField(index, fieldName);
    }

    /*******************************************************************************
    * @description Adds required fields to selectedBatchFields property
    */
    handleRequiredFields() {
        const requiredFields = this.batchFields.filter(batchField => { return batchField.required });
        const selectedFieldsExists = this.selectedBatchFields && this.selectedBatchFields.length > 0;

        requiredFields.forEach((field) => {
            if (selectedFieldsExists) {
                const alreadySelected = this.selectedBatchFields.find(bf => { return bf.apiName === field.apiName; });
                if (alreadySelected) { return; }
            }

            this.addField(field.apiName);
        });
    }

    /*******************************************************************************
    * @description Method toggles the checkboxes for any existing/selected batch
    * header fields. Used when retrieving an existing form template.
    */
    toggleCheckboxForSelectedBatchFields() {
        if (this.selectedBatchFields && this.selectedBatchFields.length > 0) {
            let _batchFields = mutable(this.batchFields);

            for (let i = 0; i < this.selectedBatchFields.length; i++) {
                const selectedBatchField = this.selectedBatchFields[i];
                const batchFieldIndex = findIndexByProperty(
                    _batchFields,
                    PROP_API_NAME,
                    selectedBatchField.apiName);

                _batchFields[batchFieldIndex].checked = true;
            }

            this.batchFields = _batchFields;
        }
    }
}
<|endoftext|>


<commit_before>import os from 'os'
import urlParser from 'url'
import crypto from 'crypto'
import open from 'opn'
import chalk from 'chalk'
import EventSource from 'eventsource'
import {parseJson} from '@sanity/util/lib/safeJson'
import getUserConfig from '../../util/getUserConfig'
import canLaunchBrowser from '../../util/canLaunchBrowser'

export default async function login(args, context) {
  const {prompt, output, apiClient} = context
  const {sso, experimental} = args.extOptions

  // _Potentially_ already authed client
  const authedClient = apiClient({requireUser: false, requireProject: false})

  // Explicitly tell _this_ client not to use a token
  const client = authedClient.clone().config({token: undefined})

  // Get the desired authentication provider
  const provider = await getProvider({client, sso, experimental, output, prompt})
  if (provider === undefined) {
    output.print(chalk.red('No authentication providers found'))
    return
  }

  // Open an authentication listener channel and wait for secret
  const iv = crypto.randomBytes(8).toString('hex')
  const es = getAuthChannel(client.config().apiHost, provider, iv)
  const encryptedToken = getAuthToken(es) // This is a promise, will resolve later
  const {secret, url} = await getAuthInfo(es)

  // Open a browser on the login page (or tell the user to)
  const providerUrl = urlParser.parse(url, true)
  providerUrl.query.label = `${os.hostname()} / ${os.platform()}`
  const loginUrl = urlParser.format(providerUrl)

  const shouldLaunchBrowser = canLaunchBrowser()
  const actionText = shouldLaunchBrowser ? 'Opening browser at' : 'Please open a browser at'

  output.print(`\n${actionText} ${loginUrl}\n`)
  const spin = output
    .spinner('Waiting for browser login to complete... Press Ctrl + C to cancel')
    .start()
  open(loginUrl, {wait: false})

  // Wait for a success/error on the listener channel
  let token
  try {
    token = await encryptedToken
    spin.stop()
  } catch (err) {
    spin.stop()
    err.message = `Login failed: ${err.message}`
    throw err
  }

  // Decrypt the token with the secret we received earlier
  const authToken = decryptToken(token, secret, iv)

  // Store the token
  getUserConfig().set({
    authToken: authToken,
    authType: 'normal',
  })

  output.print(chalk.green('Login successful'))
}

function getAuthChannel(baseUrl, provider, iv) {
  const uuid = crypto.randomBytes(16).toString('hex')
  let listenUrl
  if (provider.type === 'saml') {
    listenUrl = `${baseUrl}/v2021-10-01/auth/saml/listen/${provider.id}/${uuid}?iv=${iv}`
  } else {
    listenUrl = `${baseUrl}/v1/auth/listen/${provider.name}/${uuid}?iv=${iv}`
  }
  return new EventSource(listenUrl)
}

function getAuthInfo(es) {
  const wantedProps = ['secret', 'url']
  const values = {}
  return new Promise((resolve, reject) => {
    let numProps = 0
    es.addEventListener('error', (err) => {
      es.close()
      reject(new Error(`Unable to get authorization info: ${err.message}`))
    })

    es.addEventListener('message', (msg) => {
      const data = parseJson(msg.data, {})
      if (!wantedProps.includes(data.type)) {
        return
      }

      values[data.type] = data[data.type]
      if (++numProps === wantedProps.length) {
        resolve(values)
      }
    })
  })
}

function getAuthToken(es) {
  return new Promise((resolve, reject) => {
    es.addEventListener('success', (msg) => {
      es.close()
      const data = parseJson(msg.data, {})
      resolve(data.token)
    })

    es.addEventListener('failure', (msg) => {
      es.close()
      const data = parseJson(msg.data, {})
      const error = new Error(data.message)
      Object.keys(data).forEach((key) => {
        error[key] = data[key]
      })
      reject(error)
    })
  })
}

function decryptToken(token, secret, iv) {
  const decipher = crypto.createDecipheriv('aes-256-cbc', secret, iv)
  const dec = decipher.update(token, 'hex', 'utf8')
  return `${dec}${decipher.final('utf8')}`
}

async function getProvider({output, client, sso, experimental, prompt}) {
  if (sso) {
    return getSSOProvider({client, prompt, slug: sso})
  }

  // Fetch and prompt for login provider to use
  const spin = output.spinner('Fetching providers...').start()
  let {providers} = await client.request({uri: '/auth/providers'})
  if (experimental) {
    providers = [...providers, {name: 'sso', title: 'SSO'}]
  }
  spin.stop()

  const provider = await promptProviders(prompt, providers)
  if (provider.name === 'sso') {
    const slug = await prompt.single({
      type: 'input',
      message: 'Organization slug:',
    })
    return getSSOProvider({client, prompt, slug})
  }

  return provider
}

async function getSSOProvider({client, prompt, slug}) {
  const providers = await client.withConfig({apiVersion: 'X'}).request({
    uri: `/auth/organizations/by-slug/${slug}/providers`,
  })

  const enabledProviders = providers.filter((provider) => !provider.disabled)
  if (enabledProviders.length === 0) {
    return undefined
  } else if (enabledProviders.length === 1) {
    return enabledProviders[0]
  }

  const choice = await prompt.single({
    type: 'list',
    message: 'Select SSO provider',
    choices: enabledProviders.map((provider) => provider.name),
  })

  return enabledProviders.find((provider) => provider.name === choice)
}

function promptProviders(prompt, providers) {
  if (providers.length === 1) {
    return providers[0]
  }

  return prompt
    .single({
      type: 'list',
      message: 'Login type',
      choices: providers.map((provider) => provider.title),
    })
    .then((provider) => providers.find((prov) => prov.title === provider))
}
<commit_msg>fix(cli): attempt to clear previous session on successful re-authentication<commit_after>import os from 'os'
import urlParser from 'url'
import crypto from 'crypto'
import open from 'opn'
import chalk from 'chalk'
import EventSource from 'eventsource'
import {parseJson} from '@sanity/util/lib/safeJson'
import getUserConfig from '../../util/getUserConfig'
import canLaunchBrowser from '../../util/canLaunchBrowser'

export default async function login(args, context) {
  const {prompt, output, apiClient} = context
  const {sso, experimental} = args.extOptions

  // _Potentially_ already authed client
  const authedClient = apiClient({requireUser: false, requireProject: false})
  const hasExistingToken = Boolean(authedClient.config().token)

  // Explicitly tell _this_ client not to use a token
  const client = authedClient.clone().config({token: undefined})

  // Get the desired authentication provider
  const provider = await getProvider({client, sso, experimental, output, prompt})
  if (provider === undefined) {
    output.print(chalk.red('No authentication providers found'))
    return
  }

  // Open an authentication listener channel and wait for secret
  const iv = crypto.randomBytes(8).toString('hex')
  const es = getAuthChannel(client.config().apiHost, provider, iv)
  const encryptedToken = getAuthToken(es) // This is a promise, will resolve later
  const {secret, url} = await getAuthInfo(es)

  // Open a browser on the login page (or tell the user to)
  const providerUrl = urlParser.parse(url, true)
  providerUrl.query.label = `${os.hostname()} / ${os.platform()}`
  const loginUrl = urlParser.format(providerUrl)

  const shouldLaunchBrowser = canLaunchBrowser()
  const actionText = shouldLaunchBrowser ? 'Opening browser at' : 'Please open a browser at'

  output.print(`\n${actionText} ${loginUrl}\n`)
  const spin = output
    .spinner('Waiting for browser login to complete... Press Ctrl + C to cancel')
    .start()
  open(loginUrl, {wait: false})

  // Wait for a success/error on the listener channel
  let token
  try {
    token = await encryptedToken
    spin.stop()
  } catch (err) {
    spin.stop()
    err.message = `Login failed: ${err.message}`
    throw err
  }

  // Decrypt the token with the secret we received earlier
  const authToken = decryptToken(token, secret, iv)

  // Store the token
  getUserConfig().set({
    authToken: authToken,
    authType: 'normal',
  })

  // If we had a session previously, attempt to clear it
  if (hasExistingToken) {
    await authedClient.request({uri: '/auth/logout', method: 'POST'}).catch((err) => {
      const statusCode = err && err.response && err.response.statusCode
      if (statusCode !== 401) {
        output.warn('[warn] Failed to log out existing session')
      }
    })
  }

  output.print(chalk.green('Login successful'))
}

function getAuthChannel(baseUrl, provider, iv) {
  const uuid = crypto.randomBytes(16).toString('hex')
  let listenUrl
  if (provider.type === 'saml') {
    listenUrl = `${baseUrl}/v2021-10-01/auth/saml/listen/${provider.id}/${uuid}?iv=${iv}`
  } else {
    listenUrl = `${baseUrl}/v1/auth/listen/${provider.name}/${uuid}?iv=${iv}`
  }
  return new EventSource(listenUrl)
}

function getAuthInfo(es) {
  const wantedProps = ['secret', 'url']
  const values = {}
  return new Promise((resolve, reject) => {
    let numProps = 0
    es.addEventListener('error', (err) => {
      es.close()
      reject(new Error(`Unable to get authorization info: ${err.message}`))
    })

    es.addEventListener('message', (msg) => {
      const data = parseJson(msg.data, {})
      if (!wantedProps.includes(data.type)) {
        return
      }

      values[data.type] = data[data.type]
      if (++numProps === wantedProps.length) {
        resolve(values)
      }
    })
  })
}

function getAuthToken(es) {
  return new Promise((resolve, reject) => {
    es.addEventListener('success', (msg) => {
      es.close()
      const data = parseJson(msg.data, {})
      resolve(data.token)
    })

    es.addEventListener('failure', (msg) => {
      es.close()
      const data = parseJson(msg.data, {})
      const error = new Error(data.message)
      Object.keys(data).forEach((key) => {
        error[key] = data[key]
      })
      reject(error)
    })
  })
}

function decryptToken(token, secret, iv) {
  const decipher = crypto.createDecipheriv('aes-256-cbc', secret, iv)
  const dec = decipher.update(token, 'hex', 'utf8')
  return `${dec}${decipher.final('utf8')}`
}

async function getProvider({output, client, sso, experimental, prompt}) {
  if (sso) {
    return getSSOProvider({client, prompt, slug: sso})
  }

  // Fetch and prompt for login provider to use
  const spin = output.spinner('Fetching providers...').start()
  let {providers} = await client.request({uri: '/auth/providers'})
  if (experimental) {
    providers = [...providers, {name: 'sso', title: 'SSO'}]
  }
  spin.stop()

  const provider = await promptProviders(prompt, providers)
  if (provider.name === 'sso') {
    const slug = await prompt.single({
      type: 'input',
      message: 'Organization slug:',
    })
    return getSSOProvider({client, prompt, slug})
  }

  return provider
}

async function getSSOProvider({client, prompt, slug}) {
  const providers = await client.withConfig({apiVersion: 'X'}).request({
    uri: `/auth/organizations/by-slug/${slug}/providers`,
  })

  const enabledProviders = providers.filter((provider) => !provider.disabled)
  if (enabledProviders.length === 0) {
    return undefined
  } else if (enabledProviders.length === 1) {
    return enabledProviders[0]
  }

  const choice = await prompt.single({
    type: 'list',
    message: 'Select SSO provider',
    choices: enabledProviders.map((provider) => provider.name),
  })

  return enabledProviders.find((provider) => provider.name === choice)
}

function promptProviders(prompt, providers) {
  if (providers.length === 1) {
    return providers[0]
  }

  return prompt
    .single({
      type: 'list',
      message: 'Login type',
      choices: providers.map((provider) => provider.title),
    })
    .then((provider) => providers.find((prov) => prov.title === provider))
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { ScrollView, View, Image, Text } from 'react-native';
import { get, put } from '../../api.js';
import { Card, CardSection } from './common';
import { Pie } from 'react-native-pathjs-charts';

export default class PieGraph extends Component {
  onLabelPress = (label, value) => {
    alert(label + ':' + value);
  }

  render() {
    let data = [{
        "name": "Angelique",
        "minutes": 7694
        }, {
        "name": "Zinon",
        "minutes": 2584
        }, {
        "name": "Vikki",
        "minutes": 659
        }, {
        "name": "Martin",
        "minutes": 728
        }]

        let options = {
        margin: {
            top: 20,
            left: 20,
            right: 20,
            bottom: 20
        },
        width: 180,
        height: 180,
        color: '#5f42f4',
        r: 15,
        R: 90,
        legendPosition: 'topLeft',
        animate: {
            type: 'oneByOne',
            duration: 200,
            fillTransition: 3
        },
        label: {
            fontFamily: 'Arial',
            fontSize: 8,
            fontWeight: true,
            color: '#ECF0F1',
            position: 'absolute'
        }
        }

        return (
        <View>
            <Pie
            data={data}
            options={options}
            accessorKey="minutes" />
        </View>
        )
    }
}
<commit_msg>add color<commit_after>import React, { Component } from 'react';
import { ScrollView, View, Image, Text } from 'react-native';
import { get, put } from '../../api.js';
import { Card, CardSection } from './common';
import { Pie } from 'react-native-pathjs-charts';

export default class PieGraph extends Component {
  onLabelPress = (label, value) => {
    alert(label + ':' + value);
  }

  fetchUserData = async () => {
    this.setState({loading: true})
    try {
      const response = await get('app/testroute');
      const dummy = await response.json();
      this.setState({
        data: dummy.DummyData,
        loading: false});
    }
    catch(err) {
      alert(err);
    }
  };

  render() {
    let data = [{
        "name": "Angelique",
        "minutes": 7694,
        "color": {'r':223,'g':154,'b':20}
        }, {
        "name": "Zinon",
        "minutes": 2584,
        }, {
        "name": "Vikki",
        "minutes": 659,
        }, {
        "name": "Martin",
        "minutes": 728
        }]

        let options = {
        margin: {
            top: 20,
            left: 20,
            right: 20,
            bottom: 20
        },
        width: 180,
        height: 180,
        color: '#5f42f4',
        r: 15,
        R: 90,
        legendPosition: 'topLeft',
        animate: {
            type: 'oneByOne',
            duration: 200,
            fillTransition: 3
        },
        label: {
            fontFamily: 'Arial',
            fontSize: 8,
            fontWeight: true,
            color: '#ECF0F1',
        }
        }

        return (
        <View>
            <Pie
            data={data}
            options={options}
            accessorKey="minutes" />
        </View>
        )
    }
}
<|endoftext|>


<commit_before>import most from 'most'

const emptyStream = most.empty()

function getEventsStreamForSelector(mockedEventTypes) {
  return function getEventsStream(eventType) {
    for (const key in mockedEventTypes) {
      if (mockedEventTypes.hasOwnProperty(key) && key === eventType) {
        return mockedEventTypes[key]
      }
    }
    return emptyStream
  }
}

function mockDOMSource(mockedSelectors = {}) {
  return {
    select(selector) {
      for (const key in mockedSelectors) {
        if (mockedSelectors.hasOwnProperty(key) && key === selector) {
          let observable = emptyStream
          if (mockedSelectors[key].hasOwnProperty(`observable`)) {
            observable = mockedSelectors[key].observable
          }
          return {
            observable,
            events: getEventsStreamForSelector(mockedSelectors[key]),
          }
        }
      }
      return {
        observable: emptyStream,
        events: () => emptyStream,
      }
    },
  }
}

export {mockDOMSource}
<commit_msg>feat(mockDOMSource): update to allow for multiple .select()s<commit_after>import most from 'most'

const emptyStream = most.empty()

function getEventsStreamForSelector(mockedEventTypes) {
  return function getEventsStream(eventType) {
    for (const key in mockedEventTypes) {
      if (mockedEventTypes.hasOwnProperty(key) && key === eventType) {
        return mockedEventTypes[key]
      }
    }
    return emptyStream
  }
}

function makeMockSelector(mockedSelectors) {
  return function select(selector) {
    for (const key in mockedSelectors) {
      if (mockedSelectors.hasOwnProperty(key) && key === selector) {
        let observable = emptyStream
        if (mockedSelectors[key].hasOwnProperty(`observable`)) {
          observable = mockedSelectors[key].observable
        }
        return {
          observable,
          select: makeMockSelector(mockedSelectors[key]),
          events: getEventsStreamForSelector(mockedSelectors[key]),
        }
      }
    }
    return {
      observable: emptyStream,
      select: makeMockSelector(mockedSelectors),
      events: () => emptyStream,
    }
  }
}

function mockDOMSource(mockedSelectors = {}) {
  return {
    observable: emptyStream,
    select: makeMockSelector(mockedSelectors),
    events: () => emptyStream,
  }
}

export {mockDOMSource}
<|endoftext|>


<commit_before>var PlanningPoker = angular.module('PlanningPoker', ['chart.js', 'emguo.poller']);

PlanningPoker.controller('UserCtrl', ['$scope', '$http', 'poller', function ($scope, $http, poller) {
    $scope.userName = '';
    $scope.inSession = false;
    $scope.voted = false;
    $scope.legalEstimates = [0.5, 1, 2, 3, 5, 8, 13, 20, 100];
    $scope.votingResults = [];
    $scope.resultsdata = [];
    $scope.isAdmin = false;

    $scope.labels = $scope.legalEstimates.map(String);

    $scope.joinSession = function () {
        $http({
            method: 'GET',
            url: '/validateSession',
            params: {sessionId: $scope.sessionId}
        }).then(function successCallback(response) {
            $scope.inSession = true;
        }, function errorCallback(response) {
            alert("Session " + $scope.sessionId + " has not yet been started!\n" +
                "Please try again in a few seconds, or create a new session.");
        });
    };

    $scope.createSession = function () {
        $http({
            method: 'GET',
            url: '/createSession',
        }).success(function (response) {
            $scope.inSession = true;
            $scope.sessionId = response;
            $scope.isAdmin = true;
        });
    };

    $scope.vote = function (estimateValue) {
        $scope.voted = false;
        $http({
            method: 'POST',
            url: '/vote',
            params: {
                sessionId: $scope.sessionId,
                userName: $scope.userName,
                estimateValue: estimateValue
            }
        }).success(function (response) {
            $scope.voted = true;
        });
        // Get poller.
        var myPoller = poller.get('results', {
            delay: 500,
            argumentsArray: [
                {
                    params: {
                        sessionId: $scope.sessionId
                    }
                }
            ]
        });
        myPoller.promise.then(
            null, null,
            function (result) {
                $scope.votingResults = result.data;

                $scope.transformed = $scope.votingResults.map(function (val) {
                    return val.estimateValue;
                });

                $scope.resultsdata = $scope.legalEstimates.map(function (x) {
                    return $scope.transformed.filter(function (y) {
                        return x == y;
                    }).length;
                });
            }
        );
    };

    $scope.reset = function () {
        $http({
            method: 'DELETE',
            url: '/reset',
            params: {
                sessionId: $scope.sessionId
            }
        }).success(function (response) {
            $scope.voted = false;
        });
    };

}]);
<commit_msg>vote again on reset<commit_after>var PlanningPoker = angular.module('PlanningPoker', ['chart.js', 'emguo.poller']);

PlanningPoker.controller('UserCtrl', ['$scope', '$http', 'poller', function ($scope, $http, poller) {
    $scope.userName = '';
    $scope.inSession = false;
    $scope.voted = false;
    $scope.legalEstimates = [0.5, 1, 2, 3, 5, 8, 13, 20, 100];
    $scope.votingResults = [];
    $scope.resultsdata = [];
    $scope.isAdmin = false;

    $scope.labels = $scope.legalEstimates.map(String);

    $scope.joinSession = function () {
        $http({
            method: 'GET',
            url: '/validateSession',
            params: {sessionId: $scope.sessionId}
        }).then(function successCallback(response) {
            $scope.inSession = true;
        }, function errorCallback(response) {
            alert("Session " + $scope.sessionId + " has not yet been started!\n" +
                "Please try again in a few seconds, or create a new session.");
        });
    };

    $scope.createSession = function () {
        $http({
            method: 'GET',
            url: '/createSession',
        }).success(function (response) {
            $scope.inSession = true;
            $scope.sessionId = response;
            $scope.isAdmin = true;
        });
    };

    $scope.vote = function (estimateValue) {
        $scope.voted = false;
        $http({
            method: 'POST',
            url: '/vote',
            params: {
                sessionId: $scope.sessionId,
                userName: $scope.userName,
                estimateValue: estimateValue
            }
        }).success(function (response) {
            $scope.voted = true;
        });
        // Get poller.
        var myPoller = poller.get('results', {
            delay: 500,
            argumentsArray: [
                {
                    params: {
                        sessionId: $scope.sessionId
                    }
                }
            ]
        });
        myPoller.promise.then(
            null, null,
            function (result) {
                $scope.votingResults = result.data;

                if (result.data.length == 0) {
                    $scope.voted = false;
                }
                ;

                $scope.transformed = $scope.votingResults.map(function (val) {
                    return val.estimateValue;
                });

                $scope.resultsdata = $scope.legalEstimates.map(function (x) {
                    return $scope.transformed.filter(function (y) {
                        return x == y;
                    }).length;
                });
            }
        );
    };

    $scope.reset = function () {
        $http({
            method: 'DELETE',
            url: '/reset',
            params: {
                sessionId: $scope.sessionId
            }
        }).success(function (response) {
            $scope.voted = false;
        });
    };

}]);
<|endoftext|>


<commit_before>import * as apiActions from './apiActions';
import { displaySuccessAlert, displayErrorAlert } from './alertsActions';

export const ASSIGNED_BOOKS_FETCHED = 'ASSIGNED_BOOKS_FETCHED';
export const ASSIGNMENT_CREATED = 'ASSIGNMENT_CREATED';
export const ASSIGNMENT_DELETED = 'ASSIGNMENT_DELETED';
export const ASSIGNMENT_PROGRESS_UPDATED = 'ASSIGNMENT_PROGRESS_UPDATED';
export const BOOKS_FETCHED = 'BOOKS_FETCHED';
export const BOOK_CREATED = 'BOOK_CREATED';
export const CREATE_BOOK = 'CREATE_BOOK';
export const DELETE_BOOK = 'DELETE_BOOK';
export const FETCH_STATS = 'FETCH_STATS';
export const FETCH_UPDATES = 'FETCH_UPDATES';
export const ERROR_ASSIGNED_BOOK_FETCHED = 'ERROR_ASSIGNED_BOOK_FETCHED';
export const ERROR_UPDATES_FETCHED = 'ERROR_UPDATES_FETCHED';
export const ERROR_ASSIGNMENT_CREATED = 'ERROR_ASSIGNMENT_CREATED';
export const ERROR_ASSIGNMENT_DELETED = 'ERROR_ASSIGNMENT_DELETED';
export const ERROR_ASSIGNMENT_PROGRESS_UPDATED = 'ERROR_ASSIGNMENT_PROGRESS_UPDATED';
export const ERROR_BOOK_CREATED = 'ERROR_BOOK_CREATED';
export const ERROR_BOOKS_FETCHED = 'ERROR_BOOKS_FETCHED';
export const ERROR_MARKED_BOOK_AS_READ = 'ERROR_MARKED_BOOK_AS_READ';
export const ERROR_STATS_FETCHED = 'ERROR_STATS_FETCHED';
export const MARK_BOOK_AS_READ = 'MARK_BOOK_AS_READ';
export const MARKED_BOOK_AS_READ = 'MARKED_BOOK_AS_READ';
export const SAVE_RESPONSE = 'SAVE_RESPONSE';
export const SUCCESS_SAVE_RESPONSE = 'SUCCESS_SAVE_RESPONSE';
export const SUCCESS_STATS_FETCHED = 'SUCCESS_STATS_FETCHED';
export const SUCCESS_UPDATES_FETCHED = 'SUCCESS_UPDATES_FETCHED';
export const ERROR_SAVE_RESPONSE = 'ERROR_SAVE_RESPONSE';
export const UPDATE_ASSIGNMENT_PROGRESS = 'UPDATE_ASSIGNMENT_PROGRESS';
export const UPDATE_BOOK = 'UPDATE_BOOK';

export const API_ASSIGNED_BOOKS_RESOURCE_URL = '/api/books/me';
export const API_BOOKS_RESOURCE_URL = '/api/books';
export const API_BOOKS_ASSIGNMENT_RESOURCE_URL = '/api/assignments';
export const API_BOOKS_ASSIGNMENT_PROGRESS_RESOURCE_URL = '/api/assignment-progress';
export const API_RESPONSES_RESOURCE_URL = '/api/responses';
export const API_STATS_RESOURCE_URL = '/api/stats/me';
export const API_UPDATES_RESOURCE_URL = '/api/updates/me';

const csrfToken = [].slice.call(document.getElementsByTagName('meta'))
    .filter((meta) => meta.name === 'csrf-token')[0].content;

const _headers = {
  'X-CSRF-TOKEN': csrfToken
};

function booksFetched(data) {
  return {
    type: BOOKS_FETCHED,
    payload: data
  };
}

function errorBooksFetched() {
  return dispatch => {
    dispatch(displayErrorAlert('Error while fetching existing books!'));
    return {
      type: ERROR_BOOKS_FETCHED
    };
  }
}

export function fetchBooks() {
  return dispatch => {
    return apiActions.getRequest(API_BOOKS_RESOURCE_URL).then(
      (res) => { dispatch(booksFetched(res)); },
      (err) => { dispatch(errorBooksFetched(err)); });
  };
}

function statsFetched(data) {
  return {
    type: SUCCESS_STATS_FETCHED,
    payload: data
  };
}

function errorStatsFetched() {
  return {
    type: ERROR_STATS_FETCHED
  };
}

export function fetchStats() {
  return dispatch => {
    return apiActions.getRequest(API_STATS_RESOURCE_URL).then(
      (res) => { dispatch(statsFetched(res)); },
      (err) => { dispatch(errorStatsFetched(err)); });
  };
}

function updatesFetched(data) {
  return {
    type: SUCCESS_UPDATES_FETCHED,
    payload: data.updates
  };
}

function errorUpdatesFetched() {
  return {
    type: ERROR_UPDATES_FETCHED
  };
}

export function fetchUpdates() {
  return dispatch => {
    return apiActions.getRequest(API_UPDATES_RESOURCE_URL).then(
      res => { dispatch(updatesFetched(res)); },
      err => { dispatch(errorUpdatesFetched(err)); }
    );
  }
}

export function assignedBooksFetched(data) {
  return {
    type: ASSIGNED_BOOKS_FETCHED,
    payload: data
  };
}

export function errorAssignedBooksFetched() {
  return dispatch => {
    dispatch(displayErrorAlert('Error while fetching your books!'));
    return {
      type: ERROR_ASSIGNED_BOOK_FETCHED
    };
  }
}

export function fetchAssignedBooks() {
  return dispatch => {
    return apiActions.getRequest(API_ASSIGNED_BOOKS_RESOURCE_URL).then(
      res => { dispatch(assignedBooksFetched(res)); },
      err => { dispatch(errorAssignedBooksFetched(err)); }
    );
  };
}

export function assignmentCreated(data) {
  return dispatch => {
    dispatch(displaySuccessAlert('Assignment successfully created!'))
    return {
      type: ASSIGNMENT_CREATED,
      payload: data
    };
  }
}

export function errorAssignmentCreated(data) {
  return dispatch => {
    dispatch(displayErrorAlert('Error when creating assignment!'));
    return {
      type: ERROR_ASSIGNMENT_CREATED,
      payload: data
    };
  }
}

export function createAssignment(bookId, userId) {
  return apiActions.postRequest(API_BOOKS_ASSIGNMENT_RESOURCE_URL,
    { book_id: bookId, user_id: userId },
    assignmentCreated, errorAssignmentCreated, _headers);
}

export function bookCreated(data) {
  return (dispatch, getState) => {
    const userId = getState().userProfileReducer.user.id;
    dispatch(createAssignment(data.book.id, userId));
  };
}

export function errorBookCreated() {
  return {
    type: ERROR_BOOK_CREATED
  };
}

export function createBook(dataBook) {
  return apiActions.postRequest(API_BOOKS_RESOURCE_URL, dataBook,
    bookCreated, errorBookCreated, _headers);
}

export function assignmentDeleted(_id) {
  return {
    type: ASSIGNMENT_DELETED,
    payload: { id: _id }
  };
}

export function errorAssignmentDeleted() {
  return {
    type: ERROR_ASSIGNMENT_DELETED
  };
}

export function deleteAssignment(id) {
  return dispatch => {
    const successAssignmentDeleted = () => {
      dispatch(displaySuccessAlert('Book successfully deleted!'));
      dispatch(assignmentDeleted(id));
    };

    dispatch(apiActions.deleteRequest(`${API_BOOKS_ASSIGNMENT_RESOURCE_URL}/${id}`,
      successAssignmentDeleted, errorAssignmentDeleted, _headers));
  };
}

export function assignmentProgressUpdated(data) {
  return {
    type: ASSIGNMENT_PROGRESS_UPDATED,
    payload: data
  };
}

export function errorAssignmentProgressUpdated() {
  return {
    type: ERROR_ASSIGNMENT_PROGRESS_UPDATED
  };
}

export function updateAssignmentProgress(_id, _numPages) {
  const dataProgress = {
    id: _id,
    num_pages_read: _numPages
  };
  const url = `${API_BOOKS_ASSIGNMENT_PROGRESS_RESOURCE_URL}/${_id}`;
  return apiActions.putRequest(url, dataProgress,
    assignmentProgressUpdated, errorAssignmentProgressUpdated, _headers);
}

export function markedBookAsReadSuccess(data) {
  return dispatch => {
    dispatch(displaySuccessAlert('Book marked as read!'));

    return {
      type: MARKED_BOOK_AS_READ,
      payload: data
    };
  }
}

export function errorMarkBookAsRead() {
  return dispatch => {
    dispatch(displayErrorAlert('Error when marking book as read!'));

    return {
      type: ERROR_MARKED_BOOK_AS_READ
    };
  }
}

export function markBookAsRead(_id) {
  const url = `${API_BOOKS_ASSIGNMENT_PROGRESS_RESOURCE_URL}/${_id}/read`;
  return apiActions.putRequest(url, {},
    markedBookAsReadSuccess, errorMarkBookAsRead, _headers);
}

function errorSaveResponse() {
  return dispatch => {
    dispatch(displayErrorAlert('Error when saving response!'));

    return {
      type: ERROR_SAVE_RESPONSE
    };
  }
}

function successSaveResponse(data) {
  return dispatch => {
    dispatch(displaySuccessAlert('Response successfully saved!'));
    return {
      type: SUCCESS_SAVE_RESPONSE,
      payload: data
    };
  }
}

function successCreateResponse(assignmendId, res) {
  return (dispatch, getState) => {
    const userId = getState().userProfileReducer.user.id;
    const assignments = getState().bookReducers.assignedBooks;
    const currentAssignment = assignments.find(
      assignment => parseInt(assignmendId, 10) === assignment.id
    );

    const url = `${API_BOOKS_ASSIGNMENT_RESOURCE_URL}/${assignmendId}`;
    const data = {
      response_id: res.response.id,
      user_id: userId,
      book_id: currentAssignment.book.id
    };

    dispatch(apiActions.putRequest(url, data,
      successSaveResponse, errorSaveResponse, _headers));
  };
}

export function saveResponse(props) {
  const assignmentId = props.assignmentId;
  const data = { type: props.type };
  const attachments = [];

  switch (data.type) {
    case 'text':
      data.content = props.content;
      break;

    case 'image':
      attachments.push({ file: props.file, fieldName: 'file' });
      break;

    case 'video':
    case 'link':
      data.url = props.url;
      break;

    default:
      break;
  }

  if (attachments.length > 0) {
    return apiActions.postRequestWithAttachments(API_RESPONSES_RESOURCE_URL, data, attachments,
      res => successCreateResponse(assignmentId, res), errorSaveResponse, _headers);
  }

  return apiActions.postRequest(API_RESPONSES_RESOURCE_URL, data,
    res => successCreateResponse(assignmentId, res), errorSaveResponse, _headers);
}
<commit_msg>minor fixes<commit_after>import * as apiActions from './apiActions';
import { displaySuccessAlert, displayErrorAlert } from './alertsActions';

export const ASSIGNED_BOOKS_FETCHED = 'ASSIGNED_BOOKS_FETCHED';
export const ASSIGNMENT_CREATED = 'ASSIGNMENT_CREATED';
export const ASSIGNMENT_DELETED = 'ASSIGNMENT_DELETED';
export const ASSIGNMENT_PROGRESS_UPDATED = 'ASSIGNMENT_PROGRESS_UPDATED';
export const BOOKS_FETCHED = 'BOOKS_FETCHED';
export const BOOK_CREATED = 'BOOK_CREATED';
export const CREATE_BOOK = 'CREATE_BOOK';
export const DELETE_BOOK = 'DELETE_BOOK';
export const FETCH_STATS = 'FETCH_STATS';
export const FETCH_UPDATES = 'FETCH_UPDATES';
export const ERROR_ASSIGNED_BOOK_FETCHED = 'ERROR_ASSIGNED_BOOK_FETCHED';
export const ERROR_UPDATES_FETCHED = 'ERROR_UPDATES_FETCHED';
export const ERROR_ASSIGNMENT_CREATED = 'ERROR_ASSIGNMENT_CREATED';
export const ERROR_ASSIGNMENT_DELETED = 'ERROR_ASSIGNMENT_DELETED';
export const ERROR_ASSIGNMENT_PROGRESS_UPDATED = 'ERROR_ASSIGNMENT_PROGRESS_UPDATED';
export const ERROR_BOOK_CREATED = 'ERROR_BOOK_CREATED';
export const ERROR_BOOKS_FETCHED = 'ERROR_BOOKS_FETCHED';
export const ERROR_MARKED_BOOK_AS_READ = 'ERROR_MARKED_BOOK_AS_READ';
export const ERROR_STATS_FETCHED = 'ERROR_STATS_FETCHED';
export const MARK_BOOK_AS_READ = 'MARK_BOOK_AS_READ';
export const MARKED_BOOK_AS_READ = 'MARKED_BOOK_AS_READ';
export const SAVE_RESPONSE = 'SAVE_RESPONSE';
export const SUCCESS_SAVE_RESPONSE = 'SUCCESS_SAVE_RESPONSE';
export const SUCCESS_STATS_FETCHED = 'SUCCESS_STATS_FETCHED';
export const SUCCESS_UPDATES_FETCHED = 'SUCCESS_UPDATES_FETCHED';
export const ERROR_SAVE_RESPONSE = 'ERROR_SAVE_RESPONSE';
export const UPDATE_ASSIGNMENT_PROGRESS = 'UPDATE_ASSIGNMENT_PROGRESS';
export const UPDATE_BOOK = 'UPDATE_BOOK';

export const API_ASSIGNED_BOOKS_RESOURCE_URL = '/api/books/me';
export const API_BOOKS_RESOURCE_URL = '/api/books';
export const API_BOOKS_ASSIGNMENT_RESOURCE_URL = '/api/assignments';
export const API_BOOKS_ASSIGNMENT_PROGRESS_RESOURCE_URL = '/api/assignment-progress';
export const API_RESPONSES_RESOURCE_URL = '/api/responses';
export const API_MY_STATS_RESOURCE_URL = '/api/stats/me';
export const API_MY_UPDATES_RESOURCE_URL = '/api/updates/me';

const csrfToken = [].slice.call(document.getElementsByTagName('meta'))
    .filter((meta) => meta.name === 'csrf-token')[0].content;

const _headers = {
  'X-CSRF-TOKEN': csrfToken
};

function booksFetched(data) {
  return {
    type: BOOKS_FETCHED,
    payload: data
  };
}

function errorBooksFetched() {
  return dispatch => {
    dispatch(displayErrorAlert('Error while fetching existing books!'));
    return {
      type: ERROR_BOOKS_FETCHED
    };
  }
}

export function fetchBooks() {
  return dispatch => {
    return apiActions.getRequest(API_BOOKS_RESOURCE_URL).then(
      (res) => { dispatch(booksFetched(res)); },
      (err) => { dispatch(errorBooksFetched(err)); });
  };
}

function statsFetched(data) {
  return {
    type: SUCCESS_STATS_FETCHED,
    payload: data
  };
}

function errorStatsFetched() {
  return {
    type: ERROR_STATS_FETCHED
  };
}

export function fetchStats() {
  return dispatch => {
    return apiActions.getRequest(API_MY_STATS_RESOURCE_URL).then(
      (res) => { dispatch(statsFetched(res)); },
      (err) => { dispatch(errorStatsFetched(err)); });
  };
}

function updatesFetched(data) {
  return {
    type: SUCCESS_UPDATES_FETCHED,
    payload: data.updates
  };
}

function errorUpdatesFetched() {
  return {
    type: ERROR_UPDATES_FETCHED
  };
}

export function fetchUpdates() {
  return dispatch => {
    return apiActions.getRequest(API_MY_UPDATES_RESOURCE_URL).then(
      res => { dispatch(updatesFetched(res)); },
      err => { dispatch(errorUpdatesFetched(err)); }
    );
  };
}

export function assignedBooksFetched(data) {
  return {
    type: ASSIGNED_BOOKS_FETCHED,
    payload: data
  };
}

export function errorAssignedBooksFetched() {
  return dispatch => {
    dispatch(displayErrorAlert('Error while fetching your books!'));
    return {
      type: ERROR_ASSIGNED_BOOK_FETCHED
    };
  };
}

export function fetchAssignedBooks() {
  return dispatch => {
    return apiActions.getRequest(API_ASSIGNED_BOOKS_RESOURCE_URL).then(
      res => { dispatch(assignedBooksFetched(res)); },
      err => { dispatch(errorAssignedBooksFetched(err)); }
    );
  };
}

export function assignmentCreated(data) {
  return dispatch => {
    dispatch(displaySuccessAlert('Assignment successfully created!'))
    return {
      type: ASSIGNMENT_CREATED,
      payload: data
    };
  }
}

export function errorAssignmentCreated(data) {
  return dispatch => {
    dispatch(displayErrorAlert('Error when creating assignment!'));
    return {
      type: ERROR_ASSIGNMENT_CREATED,
      payload: data
    };
  };
}

export function createAssignment(bookId, userId) {
  return apiActions.postRequest(API_BOOKS_ASSIGNMENT_RESOURCE_URL,
    { book_id: bookId, user_id: userId },
    assignmentCreated, errorAssignmentCreated, _headers);
}

export function bookCreated(data) {
  return (dispatch, getState) => {
    const userId = getState().userProfileReducer.user.id;
    dispatch(createAssignment(data.book.id, userId));
  };
}

export function errorBookCreated() {
  return {
    type: ERROR_BOOK_CREATED
  };
}

export function createBook(dataBook) {
  return apiActions.postRequest(API_BOOKS_RESOURCE_URL, dataBook,
    bookCreated, errorBookCreated, _headers);
}

export function assignmentDeleted(_id) {
  return {
    type: ASSIGNMENT_DELETED,
    payload: { id: _id }
  };
}

export function errorAssignmentDeleted() {
  return {
    type: ERROR_ASSIGNMENT_DELETED
  };
}

export function deleteAssignment(id) {
  return dispatch => {
    const successAssignmentDeleted = () => {
      dispatch(displaySuccessAlert('Book successfully deleted!'));
      dispatch(assignmentDeleted(id));
    };

    dispatch(apiActions.deleteRequest(`${API_BOOKS_ASSIGNMENT_RESOURCE_URL}/${id}`,
      successAssignmentDeleted, errorAssignmentDeleted, _headers));
  };
}

export function assignmentProgressUpdated(data) {
  return {
    type: ASSIGNMENT_PROGRESS_UPDATED,
    payload: data
  };
}

export function errorAssignmentProgressUpdated() {
  return {
    type: ERROR_ASSIGNMENT_PROGRESS_UPDATED
  };
}

export function updateAssignmentProgress(_id, _numPages) {
  const dataProgress = {
    id: _id,
    num_pages_read: _numPages
  };
  const url = `${API_BOOKS_ASSIGNMENT_PROGRESS_RESOURCE_URL}/${_id}`;
  return apiActions.putRequest(url, dataProgress,
    assignmentProgressUpdated, errorAssignmentProgressUpdated, _headers);
}

export function markedBookAsReadSuccess(data) {
  return dispatch => {
    dispatch(displaySuccessAlert('Book marked as read!'));

    return {
      type: MARKED_BOOK_AS_READ,
      payload: data
    };
  };
}

export function errorMarkBookAsRead() {
  return dispatch => {
    dispatch(displayErrorAlert('Error when marking book as read!'));

    return {
      type: ERROR_MARKED_BOOK_AS_READ
    };
  };
}

export function markBookAsRead(_id) {
  const url = `${API_BOOKS_ASSIGNMENT_PROGRESS_RESOURCE_URL}/${_id}/read`;
  return apiActions.putRequest(url, {},
    markedBookAsReadSuccess, errorMarkBookAsRead, _headers);
}

function errorSaveResponse() {
  return dispatch => {
    dispatch(displayErrorAlert('Error when saving response!'));

    return {
      type: ERROR_SAVE_RESPONSE
    };
  };
}

function successSaveResponse(data) {
  return dispatch => {
    dispatch(displaySuccessAlert('Response successfully saved!'));
    return {
      type: SUCCESS_SAVE_RESPONSE,
      payload: data
    };
  };
}

function successCreateResponse(assignmendId, res) {
  return (dispatch, getState) => {
    const userId = getState().userProfileReducer.user.id;
    const assignments = getState().bookReducers.assignedBooks;
    const currentAssignment = assignments.find(
      assignment => parseInt(assignmendId, 10) === assignment.id
    );

    const url = `${API_BOOKS_ASSIGNMENT_RESOURCE_URL}/${assignmendId}`;
    const data = {
      response_id: res.response.id,
      user_id: userId,
      book_id: currentAssignment.book.id
    };

    dispatch(apiActions.putRequest(url, data,
      successSaveResponse, errorSaveResponse, _headers));
  };
}

export function saveResponse(props) {
  const assignmentId = props.assignmentId;
  const data = { type: props.type };
  const attachments = [];

  switch (data.type) {
    case 'text':
      data.content = props.content;
      break;

    case 'image':
      attachments.push({ file: props.file, fieldName: 'file' });
      break;

    case 'video':
    case 'link':
      data.url = props.url;
      break;

    default:
      break;
  }

  if (attachments.length > 0) {
    return apiActions.postRequestWithAttachments(API_RESPONSES_RESOURCE_URL, data, attachments,
      res => successCreateResponse(assignmentId, res), errorSaveResponse, _headers);
  }

  return apiActions.postRequest(API_RESPONSES_RESOURCE_URL, data,
    res => successCreateResponse(assignmentId, res), errorSaveResponse, _headers);
}
<|endoftext|>


<commit_before>/**
 * Created by hanswang on 3/20/16.
 */
module.exports = function(Student) {
  var cloudantURL = "https://828ae6b0-5855-4cdb-9bc9-75bf1dfcd4fc-bluemix.cloudant.com/arrivaltest/_find";
  var example_JSON = {
    "use_index": "_design/lb-index-ddoc-Student",
    "selector": {
      "first_name": {
        "$eq": "Test_first_name"
      },
      "_id":{
        "$gt": null
      }
    },
    "fields": [
      "_id",
      "school_email",
      "sleep_time"
    ],
    "sort": [
      {
        "_id:string": "asc"
      }
    ]
  };
  //
  //module.exports = function(CoffeeShop) {
  //  ...
  //  CoffeeShop.getName = function(shopId, cb) {
  //    CoffeeShop.findById( shopId, function (err, instance) {
  //      response = "Name of coffee shop is " + instance.name;
  //      cb(null, response);
  //      console.log(response);
  //    });
  //  }
  //    ...
  //    CoffeeShop.remoteMethod (
  //    'getName',
  //    {
  //      http: {path: '/getname', verb: 'get'},
  //      accepts: {arg: 'id', type: 'number', http: { source: 'query' } },
  //      returns: {arg: 'name', type: 'string'}
  //    }
  //  );
  //}
  Student.getTestStudent = function(cb){
    //Account.find({where: {name: 'John'}, limit: 3}, function(err, accounts) { ... });
    Student.find({where: {gender: 'Male'}}, function(err, instance){
      var response;
      response = instance;
      cb(null, response);
      console.log(response);
    });
  };

  Student.getStudentBySchoolID = function(school_id,cb){
    //Account.find({where: {name: 'John'}, limit: 3}, function(err, accounts) { ... });
    Student.find({where: {school_id: school_id}}, function(err, instance){
      var response;
      response = instance;
      cb(null, response);
      console.log(response);
    });
  };

  Student.remoteMethod(
    'getTestStudent',
    {
      http: {path: '/getTestStudent', verb: 'get'},
      returns: {arg: 'Test_students', type: 'string'}
    }
  );
  Student.remoteMethod(
    'getStudentBySchoolID',
    {
      http: {path: '/getStudentBySchoolID', verb: 'get'},
      accepts: {arg:'school_id', type: 'number'},
      returns: {arg: 'Test_students', type: 'string'}
    }
  );
};<commit_msg>test student remote method<commit_after>/**
 * Created by hanswang on 3/20/16.
 */
module.exports = function(Student) {
  var cloudantURL = "https://828ae6b0-5855-4cdb-9bc9-75bf1dfcd4fc-bluemix.cloudant.com/arrivaltest/_find";
  var example_JSON = {
    "use_index": "_design/lb-index-ddoc-Student",
    "selector": {
      "first_name": {
        "$eq": "Test_first_name"
      },
      "_id":{
        "$gt": null
      }
    },
    "fields": [
      "_id",
      "school_email",
      "sleep_time"
    ],
    "sort": [
      {
        "_id:string": "asc"
      }
    ]
  };
  //
  //module.exports = function(CoffeeShop) {
  //  ...
  //  CoffeeShop.getName = function(shopId, cb) {
  //    CoffeeShop.findById( shopId, function (err, instance) {
  //      response = "Name of coffee shop is " + instance.name;
  //      cb(null, response);
  //      console.log(response);
  //    });
  //  }
  //    ...
  //    CoffeeShop.remoteMethod (
  //    'getName',
  //    {
  //      http: {path: '/getname', verb: 'get'},
  //      accepts: {arg: 'id', type: 'number', http: { source: 'query' } },
  //      returns: {arg: 'name', type: 'string'}
  //    }
  //  );
  //}
  Student.getTestStudent = function(cb){
    //Account.find({where: {name: 'John'}, limit: 3}, function(err, accounts) { ... });
    Student.find({where: {gender: 'Male'}}, function(err, instance){
      var response;
      response = instance;
      cb(null, response);
      console.log(response);
    });
  };

  Student.getStudentBySchoolID = function(school_id,cb){
    //Account.find({where: {name: 'John'}, limit: 3}, function(err, accounts) { ... });
    Student.find({where: {school_id: school_id}}, function(err, instance){
      var response;
      response = instance;
      cb(null, response);
      console.log(response);
    });
  };

  Student.remoteMethod(
    'getTestStudent',
    {
      http: {path: '/getTestStudent', verb: 'get'},
      returns: {type: 'array', root: true}
    }
  );
  Student.remoteMethod(
    'getStudentBySchoolID',
    {
      http: {path: '/getStudentBySchoolID', verb: 'get'},
      accepts: {arg:'school_id', type: 'number'},
      returns: {type: 'array', root: true}
    }
  );
};<|endoftext|>