<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { bindActionCreators } from 'redux';
import RaisedButton from 'material-ui/RaisedButton';
import FlatButton from 'material-ui/FlatButton';
import Paper from 'material-ui/Paper';
import isBefore from 'date-fns/is_before';
import { format } from 'utils/dates';
import isAfter from 'date-fns/is_after';
import addYears from 'date-fns/add_years';
import addMinutes from 'date-fns/add_minutes';
import TrashIcon from 'material-ui/svg-icons/action/delete-forever';
import DateRangeIcon from 'material-ui/svg-icons/action/date-range';
import EditorIcon from 'material-ui/svg-icons/editor/mode-edit';
import assign from 'lodash/assign';

import DetailCommande from 'components/DetailCommande';
import DistributionSelector
  from 'containers/CommandeEdit/components/components/DistributionSelector';
import DistributionSelected
  from 'containers/CommandeEdit/components/components/DistributionSelected';
import Paiement from 'containers/CommandeEdit/components/Paiement';

import {
  ajouter,
  // augmenter,
  // diminuer,
  supprimer, // sauvegarder, // annuler, // setDistibution,
} from 'containers/CommandeEdit/actions';

// import { selectCommande, isCotisationInCommande } from 'containers/CommandeEdit/selectors';

import {
  selectCommande as selectCommandeProxiweb,
  selectCommandeContenus,
  selectOffres,
  selectProduits,
  selectOffreCotisation,
  selectCotisationId,
} from 'containers/Commande/selectors';

import {
  ajouterOffre,
  diminuerOffre,
  setDistibution,
  sauvegarder,
  annuler,
} from 'containers/Commande/actions';

import { selectPending } from 'containers/App/selectors';

import {
  selectDatePaiementCotisation,
} from 'containers/CompteUtilisateur/selectors';

import styles from './OrderValidate.css';

const constStyles = {
  margin20: {
    marginTop: 20,
  },
  margin40: {
    marginTop: 40,
  },
  minWidth: {
    minWidth: 44,
  },
  textAlignCenter: {
    textAlign: 'center',
  },
  paiementCotisation: {
    textAlign: 'center',
    backgroundColor: 'white',
    marginTop: '1em',
    padding: '1em',
  },
};

class OrderValidate extends Component {
  static propTypes = {
    produitsById: PropTypes.object.isRequired,
    params: PropTypes.object.isRequired,
    offres: PropTypes.object.isRequired,
    commandeContenus: PropTypes.object.isRequired,
    commande: PropTypes.object.isRequired,
    utilisateurId: PropTypes.string.isRequired,
    commandeProxiweb: PropTypes.object.isRequired,
    balance: PropTypes.number,
    panierExpanded: PropTypes.bool.isRequired,
    autreUtilisateur: PropTypes.bool.isRequired,

    sauvegarder: PropTypes.func.isRequired,
    annuler: PropTypes.func.isRequired,
    supprimer: PropTypes.func.isRequired,
    augmenter: PropTypes.func.isRequired,
    ajouter: PropTypes.func.isRequired,
    diminuer: PropTypes.func.isRequired,
    setDistibution: PropTypes.func.isRequired,
    pending: PropTypes.bool.isRequired,
    offreCotisation: PropTypes.object.isRequired,
    datePaiementCotisation: PropTypes.string,
    cotisationId: PropTypes.string.isRequired,
  };

  static contextTypes = {
    muiTheme: PropTypes.object.isRequired,
  };

  state = {
    view: 'panier',
  };

  selectionnePlageHoraire = (plageHoraire, livraisonId) => {
    const { params: { commandeId }, utilisateurId } = this.props;
    this.props.setDistibution({
      commandeId,
      utilisateurId,
      plageHoraire,
      livraisonId,
    });
    this.setState({ view: 'panier' });
  };

  showValidate = () => {
    const {
      commande,
      params,
      utilisateurId,
      pending,
      commandeContenus,
    } = this.props;
    const { commandeId } = params;
    const { palette } = this.context.muiTheme;
    let label = null;
    let textButtonColor = null;

    if (commande.createdAt !== null && commande.updatedAt === null) {
      textButtonColor = 'black';
      label = pending
        ? 'Sauvegarde des modifications...'
        : 'Sauvegarder mes modifications';
    } else {
      label = pending ? 'Validation de la commande...' : 'Valider la commande';
      textButtonColor = 'white';
    }
    return (

        <RaisedButton
          label={label}
          style={constStyles.margin20}
          labelColor={textButtonColor}
          backgroundColor={
            commande.createdAt !== null && commande.updatedAt === null
              ? palette.warningColor
              : palette.primary1Color
          }
          onClick={() =>
            this.props.sauvegarder(
              assign(commande, {
                commandeId,
                utilisateurId,
                contenus: commande.contenus.map(id => ({
                  ...commandeContenus[id],
                  id,
                })),
              })
            )}
        />

    );
  };

  showPaiementCotisation = () => {
    const {
      offreCotisation,
      utilisateurId,
      params: { commandeId },
    } = this.props;
    return (
      <RaisedButton
        label="Payer la cotisation"
        style={constStyles.margin20}
        primary
        onClick={() =>
          this.props.augmenter({
            offreId: offreCotisation.id,
            quantite: 1,
            commandeId,
            utilisateurId,
          })}
      />
    );
  };

  showDistribSelected = () => {
    const { commande, params } = this.props;
    return (

        <DistributionSelected
          livraisonId={commande.livraisonId}
          noPlageHoraire={commande.plageHoraire}
          className={styles.distriItem}
          params={params}
        />
        <FlatButton
          label="modifier"
          onClick={() => this.setState({ view: 'distribution' })}
          className={styles.distriButton}
          icon={<EditorIcon />}
          style={constStyles.minWidth}
        />

    );
  };

  showDistribButton = () => (
    <RaisedButton
      label="Choisissez le jour de distribution"
      icon={<DateRangeIcon />}
      style={constStyles.margin20}
      onClick={() => this.setState({ view: 'distribution' })}
    />
  );

  showDetailsCommande = contenus => {
    const {
      offres,
      commande,
      params,
      produitsById,
      commandeContenus,
      panierExpanded,
      utilisateurId,
    } = this.props;

    return (
      <DetailCommande
        contenus={contenus}
        offres={offres}
        produits={produitsById}
        supprimer={this.props.supprimer}
        augmenter={this.props.augmenter}
        diminuer={this.props.diminuer}
        readOnly={commande.datePaiement}
        commandeContenus={commandeContenus}
        commandeId={params.commandeId}
        panierExpanded={panierExpanded}
        filter={cc => cc.utilisateurId === utilisateurId}
        utilisateurId={utilisateurId}
      />
    );
  };

  showDistributionSelector = () => {
    const { commande, params } = this.props;
    return (
      <DistributionSelector
        plageHoraire={commande.plageHoraire}
        livraisonId={commande.livraisonId}
        selectionnePlageHoraire={this.selectionnePlageHoraire}
        params={params}
      />
    );
  };

  showCancel = () => {
    const { commande, params: { commandeId }, pending } = this.props;
    return (

        <RaisedButton
          label={`${!pending ? 'Annuler ma ' : 'Annulation de la '}commande`}
          secondary
          style={constStyles.margin20}
          onClick={() => this.props.annuler({ id: commande.id, commandeId })}
          icon={<TrashIcon />}
        />

    );
  };

  render() {
    const {
      commande, // commandeUtilisateur
      commandeContenus,
      params,
      offres,
      balance,
      commandeProxiweb,
      pending,
      datePaiementCotisation,
      offreCotisation,
      utilisateurId,
      cotisationId,
    } = this.props;

    const cotisationDansCommande = Object.keys(commandeContenus).find(
      id =>
        commandeContenus[id].utilisateurId === utilisateurId &&
        commandeContenus[id].offreId === offreCotisation.id &&
        commandeContenus[id].commandeId === params.commandeId
    );

    const { view } = this.state;
    const contenusCommande = commande.contenus.map(
      item => (typeof item === 'string' ? commandeContenus[item] : item)
    );

    const cotisationAJour =
      datePaiementCotisation &&
      isAfter(addYears(datePaiementCotisation, 1), new Date());

    return (

        {view === 'distribution'
          ? this.showDistributionSelector()
          : this.showDetailsCommande(contenusCommande)}
        {view === 'panier' &&
          commande.livraisonId &&
          this.showDistribSelected()}
        {view !== 'distribution' &&
          commandeProxiweb.dateCommande &&
          !commande.livraisonId &&
          commande.contenus.length > 0 &&
          (cotisationAJour || cotisationDansCommande) &&

            {this.showDistribButton()}

}
        {view === 'panier' &&
          (cotisationAJour || cotisationDansCommande) &&
          (commande.livraisonId || !commandeProxiweb.dateCommande) &&
          (!commande.createdAt || !commande.updatedAt) &&
          this.showValidate()}
        {view === 'panier' &&
          /* si passage de commande, pas de gestion cotisation */
          !autreUtilisateur &&
          !cotisationAJour &&
          offreCotisation &&
          !cotisationDansCommande &&
          <Paper style={constStyles.paiementCotisation}>

{"Vous n'êtes pas à jour de votre cotisation de 3 €"}

            {this.showPaiementCotisation()}
          </Paper>}
        {view === 'panier' &&
          !commande.dateLivraison &&
          commande.id &&
          isBefore(addMinutes(commande.createdAt, 1), new Date()) &&
          commande.updatedAt !== null &&
          this.showCancel()}
        {commande.id &&
          balance !== null &&
          view === 'panier' &&
          <Paiement
            commandeContenus={commandeContenus}
            commandeId={params.commandeId}
            utilisateurId={utilisateurId}
            balance={balance}
            offres={offres}
            pending={pending}
            dateLimite={format(
              commandeProxiweb.dateCommande,
              'DDDD DD MM YYYY'
            )}
          />}

    );
  }
}

const mapStateToProps = createStructuredSelector({
  commandeProxiweb: selectCommandeProxiweb(),
  offres: selectOffres(),
  commandeContenus: selectCommandeContenus(),
  produitsById: selectProduits(),
  datePaiementCotisation: selectDatePaiementCotisation(),
  offreCotisation: selectOffreCotisation(),
  cotisationId: selectCotisationId(),
  pending: selectPending(),
});

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      ajouter,
      augmenter: offre => ajouterOffre(offre),
      diminuer: offre => diminuerOffre(offre),
      supprimer,
      sauvegarder,
      annuler,
      setDistibution,
    },
    dispatch
  );

export default connect(mapStateToProps, mapDispatchToProps)(OrderValidate);
<commit_msg>sauvegarder paiement dans commandeUtilisateur<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { bindActionCreators } from 'redux';
import RaisedButton from 'material-ui/RaisedButton';
import FlatButton from 'material-ui/FlatButton';
import Paper from 'material-ui/Paper';
import isBefore from 'date-fns/is_before';
import { format } from 'utils/dates';
import isAfter from 'date-fns/is_after';
import addYears from 'date-fns/add_years';
import addMinutes from 'date-fns/add_minutes';
import TrashIcon from 'material-ui/svg-icons/action/delete-forever';
import DateRangeIcon from 'material-ui/svg-icons/action/date-range';
import EditorIcon from 'material-ui/svg-icons/editor/mode-edit';
import assign from 'lodash/assign';

import DetailCommande from 'components/DetailCommande';
import DistributionSelector
  from 'containers/CommandeEdit/components/components/DistributionSelector';
import DistributionSelected
  from 'containers/CommandeEdit/components/components/DistributionSelected';
import Paiement from 'containers/CommandeEdit/components/Paiement';
import { calculeTotauxCommande } from 'containers/Commande/utils';

import {
  ajouter,
  // augmenter,
  // diminuer,
  supprimer, // sauvegarder, // annuler, // setDistibution,
} from 'containers/CommandeEdit/actions';

// import { selectCommande, isCotisationInCommande } from 'containers/CommandeEdit/selectors';

import {
  selectCommande as selectCommandeProxiweb,
  selectCommandeContenus,
  selectOffres,
  selectProduits,
  selectOffreCotisation,
  selectCotisationId,
} from 'containers/Commande/selectors';

import {
  ajouterOffre,
  diminuerOffre,
  setDistibution,
  sauvegarder,
  annuler,
} from 'containers/Commande/actions';

import { selectPending } from 'containers/App/selectors';

import {
  selectDatePaiementCotisation,
} from 'containers/CompteUtilisateur/selectors';

import styles from './OrderValidate.css';

const constStyles = {
  margin20: {
    marginTop: 20,
  },
  margin40: {
    marginTop: 40,
  },
  minWidth: {
    minWidth: 44,
  },
  textAlignCenter: {
    textAlign: 'center',
  },
  paiementCotisation: {
    textAlign: 'center',
    backgroundColor: 'white',
    marginTop: '1em',
    padding: '1em',
  },
};

class OrderValidate extends Component {
  static propTypes = {
    produitsById: PropTypes.object.isRequired,
    params: PropTypes.object.isRequired,
    offres: PropTypes.object.isRequired,
    commandeContenus: PropTypes.object.isRequired,
    commande: PropTypes.object.isRequired,
    utilisateurId: PropTypes.string.isRequired,
    commandeProxiweb: PropTypes.object.isRequired,
    balance: PropTypes.number,
    panierExpanded: PropTypes.bool.isRequired,
    autreUtilisateur: PropTypes.bool.isRequired,

    sauvegarder: PropTypes.func.isRequired,
    annuler: PropTypes.func.isRequired,
    supprimer: PropTypes.func.isRequired,
    augmenter: PropTypes.func.isRequired,
    ajouter: PropTypes.func.isRequired,
    diminuer: PropTypes.func.isRequired,
    setDistibution: PropTypes.func.isRequired,
    pending: PropTypes.bool.isRequired,
    offreCotisation: PropTypes.object.isRequired,
    datePaiementCotisation: PropTypes.string,
    cotisationId: PropTypes.string.isRequired,
  };

  static contextTypes = {
    muiTheme: PropTypes.object.isRequired,
  };

  state = {
    view: 'panier',
  };

  selectionnePlageHoraire = (plageHoraire, livraisonId) => {
    const { params: { commandeId }, utilisateurId } = this.props;
    this.props.setDistibution({
      commandeId,
      utilisateurId,
      plageHoraire,
      livraisonId,
    });
    this.setState({ view: 'panier' });
  };

  showValidate = () => {
    const {
      commande,
      params: { commandeId },
      utilisateurId,
      pending,
      commandeContenus,
      offres,
    } = this.props;

    const { palette } = this.context.muiTheme;
    let label = null;
    let textButtonColor = null;

    if (commande.createdAt !== null && commande.updatedAt === null) {
      textButtonColor = 'black';
      label = pending
        ? 'Sauvegarde des modifications...'
        : 'Sauvegarder mes modifications';
    } else {
      label = pending ? 'Validation de la commande...' : 'Valider la commande';
      textButtonColor = 'white';
    }

    const { prix, recolteFond } = calculeTotauxCommande({
      commandeContenus,
      offres,
      commandeId,
      filter: cc => cc.utilisateurId === utilisateurId,
    });

    return (

        <RaisedButton
          label={label}
          style={constStyles.margin20}
          labelColor={textButtonColor}
          backgroundColor={
            commande.createdAt !== null && commande.updatedAt === null
              ? palette.warningColor
              : palette.primary1Color
          }
          onClick={() =>
            this.props.sauvegarder(
              assign(commande, {
                commandeId,
                utilisateurId,
                montant: prix,
                recolteFond,
                contenus: commande.contenus.map(id => ({
                  ...commandeContenus[id],
                  id,
                })),
              })
            )}
        />

    );
  };

  showPaiementCotisation = () => {
    const {
      offreCotisation,
      utilisateurId,
      params: { commandeId },
    } = this.props;
    return (
      <RaisedButton
        label="Payer la cotisation"
        style={constStyles.margin20}
        primary
        onClick={() =>
          this.props.augmenter({
            offreId: offreCotisation.id,
            quantite: 1,
            commandeId,
            utilisateurId,
          })}
      />
    );
  };

  showDistribSelected = () => {
    const { commande, params } = this.props;
    return (

        <DistributionSelected
          livraisonId={commande.livraisonId}
          noPlageHoraire={commande.plageHoraire}
          className={styles.distriItem}
          params={params}
        />
        <FlatButton
          label="modifier"
          onClick={() => this.setState({ view: 'distribution' })}
          className={styles.distriButton}
          icon={<EditorIcon />}
          style={constStyles.minWidth}
        />

    );
  };

  showDistribButton = () => (
    <RaisedButton
      label="Choisissez le jour de distribution"
      icon={<DateRangeIcon />}
      style={constStyles.margin20}
      onClick={() => this.setState({ view: 'distribution' })}
    />
  );

  showDetailsCommande = contenus => {
    const {
      offres,
      commande,
      params,
      produitsById,
      commandeContenus,
      panierExpanded,
      utilisateurId,
    } = this.props;

    return (
      <DetailCommande
        contenus={contenus}
        offres={offres}
        produits={produitsById}
        supprimer={this.props.supprimer}
        augmenter={this.props.augmenter}
        diminuer={this.props.diminuer}
        readOnly={commande.datePaiement}
        commandeContenus={commandeContenus}
        commandeId={params.commandeId}
        panierExpanded={panierExpanded}
        filter={cc => cc.utilisateurId === utilisateurId}
        utilisateurId={utilisateurId}
      />
    );
  };

  showDistributionSelector = () => {
    const { commande, params } = this.props;
    return (
      <DistributionSelector
        plageHoraire={commande.plageHoraire}
        livraisonId={commande.livraisonId}
        selectionnePlageHoraire={this.selectionnePlageHoraire}
        params={params}
      />
    );
  };

  showCancel = () => {
    const { commande, params: { commandeId }, pending } = this.props;
    return (

        <RaisedButton
          label={`${!pending ? 'Annuler ma ' : 'Annulation de la '}commande`}
          secondary
          style={constStyles.margin20}
          onClick={() => this.props.annuler({ id: commande.id, commandeId })}
          icon={<TrashIcon />}
        />

    );
  };

  render() {
    const {
      commande, // commandeUtilisateur
      commandeContenus,
      params,
      offres,
      balance,
      commandeProxiweb,
      pending,
      datePaiementCotisation,
      offreCotisation,
      utilisateurId,
      cotisationId,
      autreUtilisateur,
    } = this.props;

    const cotisationDansCommande = Object.keys(commandeContenus).find(
      id =>
        commandeContenus[id].utilisateurId === utilisateurId &&
        commandeContenus[id].offreId === offreCotisation.id &&
        commandeContenus[id].commandeId === params.commandeId
    );

    const { view } = this.state;
    const contenusCommande = commande.contenus.map(
      item => (typeof item === 'string' ? commandeContenus[item] : item)
    );

    const cotisationAJour =
      datePaiementCotisation &&
      isAfter(addYears(datePaiementCotisation, 1), new Date());

    return (

        {view === 'distribution'
          ? this.showDistributionSelector()
          : this.showDetailsCommande(contenusCommande)}
        {view === 'panier' &&
          commande.livraisonId &&
          this.showDistribSelected()}
        {view !== 'distribution' &&
          commandeProxiweb.dateCommande &&
          !commande.livraisonId &&
          commande.contenus.length > 0 &&
          (cotisationAJour || cotisationDansCommande) &&

            {this.showDistribButton()}

}
        {view === 'panier' &&
          (cotisationAJour || cotisationDansCommande) &&
          (commande.livraisonId || !commandeProxiweb.dateCommande) &&
          (!commande.createdAt || !commande.updatedAt) &&
          this.showValidate()}
        {view === 'panier' &&
          /* si passage de commande, pas de gestion cotisation */
          !autreUtilisateur &&
          !cotisationAJour &&
          offreCotisation &&
          !cotisationDansCommande &&
          <Paper style={constStyles.paiementCotisation}>

{"Vous n'êtes pas à jour de votre cotisation de 3 €"}

            {this.showPaiementCotisation()}
          </Paper>}
        {view === 'panier' &&
          !commande.dateLivraison &&
          commande.id &&
          isBefore(addMinutes(commande.createdAt, 1), new Date()) &&
          commande.updatedAt !== null &&
          this.showCancel()}
        {commande.id &&
          balance !== null &&
          view === 'panier' &&
          <Paiement
            commandeContenus={commandeContenus}
            commandeId={params.commandeId}
            utilisateurId={utilisateurId}
            balance={balance}
            offres={offres}
            pending={pending}
            dateLimite={format(
              commandeProxiweb.dateCommande,
              'DDDD DD MM YYYY'
            )}
          />}

    );
  }
}

const mapStateToProps = createStructuredSelector({
  commandeProxiweb: selectCommandeProxiweb(),
  offres: selectOffres(),
  commandeContenus: selectCommandeContenus(),
  produitsById: selectProduits(),
  datePaiementCotisation: selectDatePaiementCotisation(),
  offreCotisation: selectOffreCotisation(),
  cotisationId: selectCotisationId(),
  pending: selectPending(),
});

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      ajouter,
      augmenter: offre => ajouterOffre(offre),
      diminuer: offre => diminuerOffre(offre),
      supprimer,
      sauvegarder,
      annuler,
      setDistibution,
    },
    dispatch
  );

export default connect(mapStateToProps, mapDispatchToProps)(OrderValidate);
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */
var errorHandler = require('../errors'),
	mongoose = require('mongoose'),
	User = mongoose.model('User');

exports.getDisplayName = function(req, res) {
	var id = req.session.id;
	var query = User.findOne({_id:id });
	query.exec(function(err,result) {
		if(err) {
			res.status(400).send(err);
		} else if(!result) {
			res.status(400).json({displayName: "No display name found!"});
		} else {
			res.status(200).json({displayName : result.displayName});
		}
	});
};

exports.getLeaderboard = function(req, res) {
	var query = User.find({'role' : 'recruiter'});
	query.select('displayName rank inviteeList attendeeList');
	query.populate('inviteeList.user_id', 'displayName');
	query.populate('attendeeList.user_id', 'displayName');
	query.exec(function(err, result) {
		if(err) {
			res.status(400).send(err);
		} else if(!result) {
			res.status(400).json({message : 'No recruiters found!'});
		} else {
			res.status(200).send(result);
		}
	});
};
<commit_msg>Added more controllers for user schema.  Some will need to be modified to handle specific events.<commit_after>'use strict';

/**
 * Module dependencies.
 */
var errorHandler = require('../errors'),
	mongoose = require('mongoose'),
	User = mongoose.model('User');

exports.getDisplayName = function(req, res) {
	var id = req.session.id;
	var query = User.findOne({'_id':id});
	query.exec(function(err,result) {
		if(err) {
			res.status(400).send(err);
		} else if(!result) {
			res.status(400).json({displayName: "No display name found!"});
		} else {
			res.status(200).json({displayName : result.displayName});
		}
	});
};

//Get the data that will be displayed for in the leaderboard.
/*This method will need to be modified so it will only return the information related to the event the user specified.*/
exports.getLeaderboard = function(req, res) {
	var query = User.find({'role' : 'recruiter'});
	query.select('displayName rank inviteeList attendeeList');
	query.populate('inviteeList.user_id', 'displayName');
	query.populate('attendeeList.user_id', 'displayName');
	query.exec(function(err, result) {
		if(err) {
			res.status(400).send(err);
		} else if(!result) {
			res.status(400).json({message : 'No recruiters found!'});
		} else {
			res.status(200).send(result);
		}
	});
};

//Get a list of events for which this user is a recruiter.
exports.getRecruiterEvents = function(req, res) {
	var id = req.session.id;
	var query = User.findOne({'_id' : id, 'status.recruiter' : true});
	query.select('status');
	query.populate('status.event_id');
	query.exec(function(err, result) {
		if(err) {
			res.status(400).send(err);
		} else if(!result) {
			res.status(400).json({message : 'User not found or is not a recruiter!'});
		} else {
			res.status(200).send(result);
		}
	});
};

//Get the list of attendees for the event specified.
/*This method will need to be modified so it will return only the attendees for the specified event.  This should be simple,
simply replace the the definition of query with the following line:
	var query = User.findOne({'_id' : id, 'attendeeList.event_id' : req.});*/
exports.getAttendees = function(req, res) {
	var id = req.session.id;
	var query = User.findOne({'_id' : id});
	query.select('attendeeList');
	query.populate('attendeeList.user_id');
	query.exec(function(err, result) {
		if(err) {
			res.status(400).send(err);
		} else if(!result) {
			res.status(400).json({message : 'User not found or is not a recruiter!'});
		} else {
			res.status(200).send(result);
		}
	});
};
<|endoftext|>


<commit_before>(function() {
'use strict';
/* global PouchDB */
/**
 * This element is to upgrade the database to new specification required for future changes.
 *
 * First at all it will keep old data intact. It creates new datastores and attept to copy
 * data to new location. It will not destroy old databases after transition.
 *
 * This script will ba also used to indert import files from a legacy system.
 */
Polymer({
  is: 'app-db-upgrade-1016',

  ready: function() {
    this.checkIsUpgraded()
    .then((isDone) => {
      if (isDone) {
        return;
      }
      return this.beforeUpgrade()
      .then(() => this.initUpgrade());
    })
    .then(() => this.setStatusUpgraded())
    .then(() => {
      var msg = 'Databse schema upgrade finished with great success!';
      msg += ' And few nights working at home..';
      console.info(msg);
    })
    .catch((e) => {
      var msg = 'Database upgrade error. Please, file an issue report at ';
      msg += 'https://github.com/jarrodek/ChromeRestClient/issues';
      console.error(msg);
      console.error(e);
    });
  },

  // Clean up databases
  beforeUpgrade: function() {
    return Promise.all([
      new PouchDB('history-data').destroy(),
      new PouchDB('saved-requests').destroy(),
      new PouchDB('legacy-projects').destroy(),
      new PouchDB('history-requests').destroy(),
      new PouchDB('external-requests').destroy(),
      new PouchDB('arc-cookies').destroy(),
      new PouchDB('auth-data').destroy()
    ]);
  },

  checkIsUpgraded: function() {
    return new Promise((resolve) => {
      chrome.storage.local.get({'upgrades': []}, (data) => {
        if (data.upgrades.indexOf('102016') !== -1) {
          resolve(true);
        } else {
          resolve(false);
        }
      });
    });
  },

  setStatusUpgraded: function() {
    return new Promise((resolve) => {
      chrome.storage.local.get({'upgrades': []}, (data) => {
        if (data.upgrades.indexOf('102016') === -1) {
          data.upgrades.push('102016');
          chrome.storage.local.set(data, () => {
            resolve();
          });
        }
      });
    });
  },

  initUpgrade: function() {
    return arc.app.importer.prepareExport()
    .then((data) => this.processPackage(data))
    .then(() => this.copyCookies());
  },

  processPackage: function(data) {
    this.fire('upgrade-102016', {
      message: 'Initializing upgrade'
    });
    // In new structure projects do not have a refference to request ids.
    // It's the other way around. It's a bad pattern for object stores but
    // it must suffice for now.
    var projects = data.projects;
    // Requests are de-centralized. History is placed in it's own store, saved the same.
    // Also HAR data is stored in it's own store where each HAR objects is another data object.
    var requests = data.requests;

    var parsedRequests;
    var parsedProjects;
    this.prepareRequestsArrays(requests)
    .then((result) => {
      parsedRequests = result;
      return this._processProjects(projects);
    })
    .then((result) => {
      parsedProjects = result;
      return this._insertLegacyProjects(result);
    })
    .then((inserts) => {
      parsedProjects = parsedProjects.map((item, i) => {
        item.insertId = inserts[i].id;
        return item;
      });
    })
    .then(() => this._assignProjects(parsedRequests, parsedProjects))
    .then(() => this._insertSavedRequests(parsedRequests.saved))
    .then(() => this._insertHistorydRequests(parsedRequests.history))
    .then(() => this._insertDrivedRequests(parsedRequests.external))
    .then(() => this._insertHistoryData(parsedRequests.har));
  },
  // Returns an array of saved, history and har objects.
  prepareRequestsArrays: function(requests) {
    this.fire('upgrade-102016', {
      message: 'Processing requests data'
    });
    return new Promise((resolve, reject) => {
      this._parsePartRequests(requests, resolve, reject);
    });
  },
  /**
   * To give a browser a chance to enter to the main loop the work is split to chunks.
   * With this approach the app will not block main thread and will not show "ANR" screen.
   *
   *
   */
  _parsePartRequests: function(requests, resolve, reject, saved, history, har, external) {
    saved = saved || [];
    history = history || [];
    har = har || [];
    external = external || [];
    if (requests.length === 0) {
      resolve({
        saved: saved,
        history: history,
        har: har,
        external: external
      });
      return;
    }
    var len = Math.min(requests.length, 200);
    // Up to 200 loop iteration at once.
    // Then the function return and release main loop.
    for (let i = 0; i < len; i++) {
      let item = requests[i];
      if (item.type === 'history') {
        let result = this._parseHistoryItem(item);
        history.push({
          origin: result.originId,
          request: result.request
        });
        har = har.concat(result.historyData);
      } else if (item.type === 'saved') {
        let result = this._parseSavedItem(item);
        saved.push({
          origin: result.originId,
          request: result.request
        });
        har = har.concat(result.historyData);
      } else if (item.type === 'drive') {
        let result = this._parseDriveItem(item);
        external.push({
          origin: result.originId,
          request: result.request
        });
        har = har.concat(result.historyData);
      }
    }
    requests.splice(0, len);
    this.async(() => {
      this._parsePartRequests(requests, resolve, reject, saved, history, har, external);
    }, 1);
  },
  /**
   * Parser for the history request
   * ## The history request object.
   * The request object is consisted with following properties:
   * - _id: url + '/' + method + '/' + date
   * - url: String
   * - method: String
   * - headers: String
   * - payload: String
   * - created: time
   * @return {Object|null}
   */
  _parseHistoryItem: function(item) {
    var obj = {
      _id: encodeURIComponent(item.url) + '/' + item.method + '/' + item.updateTime,
      method: item.method,
      url: item.url
    };
    // payload and headers
    var entries = item.har.entries;
    var entry = entries[entries.length - 1];
    if (entry) {
      let harRequest = entry.request;
      obj.headers = this._parseHarHeders(harRequest.headers);
      obj.payload = harRequest.postData.text;
      let t = new Date(entry.startedDateTime).getTime();
      if (t !== t) {
        t = Date.now();
      }
      obj.created = t;
    }
    return {
      originId: item.id,
      historyData: this.processHar(item.har),
      request: obj
    };
  },
  /**
   * Parser for the saved request
   * ## The request object.
   * The request object is consisted with following properties:
   * - _id: name + '/' + url + '/' + method
   * - name: String
   * - url: String
   * - method: String
   * - headers: String
   * - payload: String
   * - created: time
   * - legacyProject: 0
   * @return {Object|null}
   */
  _parseSavedItem: function(item) {
    var obj = {
      _id: encodeURIComponent(item.name) + '/' + encodeURIComponent(item.url) + '/' + item.method,
      name: item.name,
      method: item.method,
      url: item.url
    };
    // payload and headers
    var harIndex = item.referenceEntry || 0;
    var entries = item.har.entries;
    var entry;
    if (harIndex || harIndex === 0) {
      entry = entries[harIndex];
    } else {
      entry = entries[0];
    }
    if (entry) {
      let harRequest = entry.request;
      obj.headers = this._parseHarHeders(harRequest.headers);
      obj.payload = harRequest.postData.text;
      let t = new Date(entry.startedDateTime).getTime();
      if (t !== t) {
        t = Date.now();
      }
      obj.created = t;
    }
    return {
      originId: item.id,
      historyData: this.processHar(item.har),
      request: obj
    };
  },
  // The same as saved but with drive id
  _parseDriveItem: function(item) {
    var result = this._parseSavedItem(item);
    result.request.driveId = item.driveId;
    result.request.type = 'google-drive';
    return result;
  },
  // @returns {!String}
  _parseHarHeders: function(headersArray) {
    if (!headersArray || !headersArray.length) {
      return '';
    }
    return headersArray.map((item) => {
      return item.name + ': ' + item.value;
    }).join('\n');
  },

  _processProjects: function(projects) {
    this.fire('upgrade-102016', {
      message: 'Processing projects data'
    });
    if (!projects || !projects.length) {
      return [];
    }
    var list = projects.map((item) => {
      if (!item.requestIds || !item.requestIds.length) {
        return null;
      }
      return {
        updateData: item.requestIds,
        legacyProject: {
          _id: this.$.uuid.generate(),
          name: item.name,
          order: item.order,
          updated: item.updateTime,
          created: item.created
        }
      };
    });
    return list.filter((i) => i !== null);
  },
  /**
   * The history data object.
   * - _id: autogenerated.
   * - headers
   * - payload
   * - url
   * - method
   * - response: Object
   *   - statusCode
   *   - statusText
   *   - headers
   *   - payload
   * - timings
   * - created: int!
   */
  processHar: function(har) {
    if (!har || !har.entries || !har.entries.length) {
      return null;
    }
    return har.entries.map((item) => {
      let req = item.request;
      let res = item.response;
      let cd = new Date(item.startedDateTime).getTime();
      if (cd !== cd) {
        cd = Date.now();
      }
      return {
        _id: this.$.uuid.generate(),
        headers: this._parseHarHeders(req.headers),
        payload: req.postData.text,
        url: req.url,
        method: req.method,
        timings: item.timings,
        totalTime: item.time,
        created: cd,
        response: {
          statusCode: res.status,
          statusText: res.statusText,
          headers: this._parseHarHeders(res.headers),
          payload: res.content.text
        }
      };
    });
  },

  _insertLegacyProjects: function(data) {
    if (!data || !data.length) {
      return Promise.resolve();
    }
    this.fire('upgrade-102016', {
      message: 'Inserting projects (' + data.length + ')'
    });
    var db = new PouchDB('legacy-projects');
    return db.bulkDocs(data.map((i) => i.legacyProject));
  },

  _insertSavedRequests: function(data) {
    if (!data || !data.length) {
      return Promise.resolve();
    }
    this.fire('upgrade-102016', {
      message: 'Inserting saved requests (' + data.length + ')'
    });
    var db = new PouchDB('saved-requests');
    return db.bulkDocs(data.map((i) => i.request));
  },

  _insertHistorydRequests: function(data) {
    if (!data || !data.length) {
      return Promise.resolve();
    }
    this.fire('upgrade-102016', {
      message: 'Inserting history (' + data.length + ')'
    });
    var db = new PouchDB('history-requests');
    return db.bulkDocs(data.map((i) => i.request));
  },

  _insertDrivedRequests: function(data) {
    if (!data || !data.length) {
      return Promise.resolve();
    }
    this.fire('upgrade-102016', {
      message: 'Inserting external data (' + data.length + ')'
    });
    var db = new PouchDB('external-requests');
    return db.bulkDocs(data.map((i) => i.request));
  },

  _insertHistoryData: function(data) {
    if (!data || !data.length) {
      return Promise.resolve();
    }
    this.fire('upgrade-102016', {
      message: 'Inserting history (HAR) data (' + data.length + ')'
    });
    var db = new PouchDB('history-data');
    return db.bulkDocs(data);
  },

  _insertCookies: function(data) {
    if (!data || !data.length) {
      return Promise.resolve();
    }
    this.fire('upgrade-102016', {
      message: 'Inserting cookies (' + data.length + ')'
    });
    var db = new PouchDB('arc-cookies');
    return db.bulkDocs(data);
  },

  _insertAuthData: function(data) {
    if (!data || !data.length) {
      return Promise.resolve();
    }
    this.fire('upgrade-102016', {
      message: 'Inserting auth data (' + data.length + ')'
    });
    var db = new PouchDB('auth-data');
    return db.bulkDocs(data);
  },

  _assignProjects: function(data, projects) {
    if (!projects || !projects.length) {
      return;
    }
    this.fire('upgrade-102016', {
      message: 'Associating legacy projects with requests'
    });
    data.saved = data.saved || [];
    var savedLen = data.saved.length;
    for (let i = 0, pLen = projects.length; i < pLen; i++) {
      let project = projects[i];
      if (!project || !project.insertId) {
        continue;
      }
      let newProjectId = project.insertId;
      for (let j = 0, rLen = project.updateData.length; j < rLen; j++) {
        let rId = project.updateData[j];
        for (let k = 0; k < savedLen; k++) {
          if (data.saved[k].origin === rId) {
            if (!data.saved[k].legacyProject) {
              data.saved[k].request.legacyProject = newProjectId;
              break;
            }
          }
        }
      }
    }
  },

  copyCookies: function() {
    return new Promise((resolve, reject) => {
      var db;
      var error;
      arc.app.db.idb.open()
      .then((_db) => {
        db = _db;
        return db.cookies.toArray();
      })
      .then((arr) => {
        if (!arr || !arr.length) {
          return null;
        }
        return arr.map((i) => {
          i = Object.assign({}, i);
          i.domain = i._domain;
          i.expires = i._expires;
          i.maxAge = i._maxAge;
          delete i._domain;
          delete i._expires;
          delete i._maxAge;
          i._id = i.domain + '/' + encodeURIComponent(i.name) + '/' + encodeURIComponent(i.path);
          return i;
        });
      })
      .then((toInsert) => this._insertCookies(toInsert))
      .catch((err) => {
        error = err;
      })
      .finally(function() {
        db.close();
        // Escape Dexie promise system.
        if (error) {
          return reject(); // <- like building node modules using promises... terrible
          // I mean, really, people, learn to use promises!
          // And learn how should it be used. Def not like Dexie does.
        }
        resolve();
      });
    });
  },

  copyAuthData: function() {
    return new Promise((resolve, reject) => {
      var db;
      var error;
      arc.app.db.idb.open()
      .then((_db) => {
        db = _db;
        return db.basicAuth.toArray();
      })
      .then((arr) => {
        if (!arr || !arr.length) {
          return null;
        }
        return arr.map((i) => {
          i = Object.assign({}, i);
          i._id = i.type + '/' + encodeURIComponent(i.url);
          return i;
        });
      })
      .then((toInsert) => this._insertAuthData(toInsert))
      .catch((err) => {
        error = err;
      })
      .finally(function() {
        db.close();
        // Escape Dexie promise system.
        if (error) {
          return reject();
        }
        resolve();
      });
    });
  }
});
})();
<commit_msg>Update: Added event fire after finish work<commit_after>(function() {
'use strict';
/* global PouchDB */
/**
 * This element is to upgrade the database to new specification required for future changes.
 *
 * First at all it will keep old data intact. It creates new datastores and attept to copy
 * data to new location. It will not destroy old databases after transition.
 *
 * This script will ba also used to indert import files from a legacy system.
 */
Polymer({
  is: 'app-db-upgrade-1016',

  ready: function() {
    this.checkIsUpgraded()
    .then((isDone) => {
      if (isDone) {
        return;
      }
      return this.beforeUpgrade()
      .then(() => this.initUpgrade());
    })
    .then(() => this.setStatusUpgraded())
    .then(() => {
      var msg = 'Databse schema upgrade finished with great success!';
      msg += ' And few nights working at home..';
      console.info(msg);

      this.fire('upgrade-102016-completed');
    })
    .catch((e) => {
      var msg = 'Database upgrade error. Please, file an issue report at ';
      msg += 'https://github.com/jarrodek/ChromeRestClient/issues';
      console.error(msg);
      console.error(e);

      this.fire('upgrade-102016-error', {
        error: e
      });
    });
  },

  // Clean up databases
  beforeUpgrade: function() {
    return Promise.all([
      new PouchDB('history-data').destroy(),
      new PouchDB('saved-requests').destroy(),
      new PouchDB('legacy-projects').destroy(),
      new PouchDB('history-requests').destroy(),
      new PouchDB('external-requests').destroy(),
      new PouchDB('arc-cookies').destroy(),
      new PouchDB('auth-data').destroy()
    ]);
  },

  checkIsUpgraded: function() {
    return new Promise((resolve) => {
      chrome.storage.local.get({'upgrades': []}, (data) => {
        if (data.upgrades.indexOf('102016') !== -1) {
          resolve(true);
        } else {
          resolve(false);
        }
      });
    });
  },

  setStatusUpgraded: function() {
    return new Promise((resolve) => {
      chrome.storage.local.get({'upgrades': []}, (data) => {
        if (data.upgrades.indexOf('102016') === -1) {
          data.upgrades.push('102016');
          chrome.storage.local.set(data, () => {
            resolve();
          });
        }
      });
    });
  },

  initUpgrade: function() {
    return arc.app.importer.prepareExport()
    .then((data) => this.processPackage(data))
    .then(() => this.copyCookies());
  },

  processPackage: function(data) {
    this.fire('upgrade-102016', {
      message: 'Initializing upgrade'
    });
    // In new structure projects do not have a refference to request ids.
    // It's the other way around. It's a bad pattern for object stores but
    // it must suffice for now.
    var projects = data.projects;
    // Requests are de-centralized. History is placed in it's own store, saved the same.
    // Also HAR data is stored in it's own store where each HAR objects is another data object.
    var requests = data.requests;

    var parsedRequests;
    var parsedProjects;
    this.prepareRequestsArrays(requests)
    .then((result) => {
      parsedRequests = result;
      return this._processProjects(projects);
    })
    .then((result) => {
      parsedProjects = result;
      return this._insertLegacyProjects(result);
    })
    .then((inserts) => {
      parsedProjects = parsedProjects.map((item, i) => {
        item.insertId = inserts[i].id;
        return item;
      });
    })
    .then(() => this._assignProjects(parsedRequests, parsedProjects))
    .then(() => this._insertSavedRequests(parsedRequests.saved))
    .then(() => this._insertHistorydRequests(parsedRequests.history))
    .then(() => this._insertDrivedRequests(parsedRequests.external))
    .then(() => this._insertHistoryData(parsedRequests.har));
  },
  // Returns an array of saved, history and har objects.
  prepareRequestsArrays: function(requests) {
    this.fire('upgrade-102016', {
      message: 'Processing requests data'
    });
    return new Promise((resolve, reject) => {
      this._parsePartRequests(requests, resolve, reject);
    });
  },
  /**
   * To give a browser a chance to enter to the main loop the work is split to chunks.
   * With this approach the app will not block main thread and will not show "ANR" screen.
   *
   *
   */
  _parsePartRequests: function(requests, resolve, reject, saved, history, har, external) {
    saved = saved || [];
    history = history || [];
    har = har || [];
    external = external || [];
    if (requests.length === 0) {
      resolve({
        saved: saved,
        history: history,
        har: har,
        external: external
      });
      return;
    }
    var len = Math.min(requests.length, 200);
    // Up to 200 loop iteration at once.
    // Then the function return and release main loop.
    for (let i = 0; i < len; i++) {
      let item = requests[i];
      if (item.type === 'history') {
        let result = this._parseHistoryItem(item);
        history.push({
          origin: result.originId,
          request: result.request
        });
        har = har.concat(result.historyData);
      } else if (item.type === 'saved') {
        let result = this._parseSavedItem(item);
        saved.push({
          origin: result.originId,
          request: result.request
        });
        har = har.concat(result.historyData);
      } else if (item.type === 'drive') {
        let result = this._parseDriveItem(item);
        external.push({
          origin: result.originId,
          request: result.request
        });
        har = har.concat(result.historyData);
      }
    }
    requests.splice(0, len);
    this.async(() => {
      this._parsePartRequests(requests, resolve, reject, saved, history, har, external);
    }, 1);
  },
  /**
   * Parser for the history request
   * ## The history request object.
   * The request object is consisted with following properties:
   * - _id: url + '/' + method + '/' + date
   * - url: String
   * - method: String
   * - headers: String
   * - payload: String
   * - created: time
   * @return {Object|null}
   */
  _parseHistoryItem: function(item) {
    var obj = {
      _id: encodeURIComponent(item.url) + '/' + item.method + '/' + item.updateTime,
      method: item.method,
      url: item.url
    };
    // payload and headers
    var entries = item.har.entries;
    var entry = entries[entries.length - 1];
    if (entry) {
      let harRequest = entry.request;
      obj.headers = this._parseHarHeders(harRequest.headers);
      obj.payload = harRequest.postData.text;
      let t = new Date(entry.startedDateTime).getTime();
      if (t !== t) {
        t = Date.now();
      }
      obj.created = t;
    }
    return {
      originId: item.id,
      historyData: this.processHar(item.har),
      request: obj
    };
  },
  /**
   * Parser for the saved request
   * ## The request object.
   * The request object is consisted with following properties:
   * - _id: name + '/' + url + '/' + method
   * - name: String
   * - url: String
   * - method: String
   * - headers: String
   * - payload: String
   * - created: time
   * - legacyProject: 0
   * @return {Object|null}
   */
  _parseSavedItem: function(item) {
    var obj = {
      _id: encodeURIComponent(item.name) + '/' + encodeURIComponent(item.url) + '/' + item.method,
      name: item.name,
      method: item.method,
      url: item.url
    };
    // payload and headers
    var harIndex = item.referenceEntry || 0;
    var entries = item.har.entries;
    var entry;
    if (harIndex || harIndex === 0) {
      entry = entries[harIndex];
    } else {
      entry = entries[0];
    }
    if (entry) {
      let harRequest = entry.request;
      obj.headers = this._parseHarHeders(harRequest.headers);
      obj.payload = harRequest.postData.text;
      let t = new Date(entry.startedDateTime).getTime();
      if (t !== t) {
        t = Date.now();
      }
      obj.created = t;
    }
    return {
      originId: item.id,
      historyData: this.processHar(item.har),
      request: obj
    };
  },
  // The same as saved but with drive id
  _parseDriveItem: function(item) {
    var result = this._parseSavedItem(item);
    result.request.driveId = item.driveId;
    result.request.type = 'google-drive';
    return result;
  },
  // @returns {!String}
  _parseHarHeders: function(headersArray) {
    if (!headersArray || !headersArray.length) {
      return '';
    }
    return headersArray.map((item) => {
      return item.name + ': ' + item.value;
    }).join('\n');
  },

  _processProjects: function(projects) {
    this.fire('upgrade-102016', {
      message: 'Processing projects data'
    });
    if (!projects || !projects.length) {
      return [];
    }
    var list = projects.map((item) => {
      if (!item.requestIds || !item.requestIds.length) {
        return null;
      }
      return {
        updateData: item.requestIds,
        legacyProject: {
          _id: this.$.uuid.generate(),
          name: item.name,
          order: item.order,
          updated: item.updateTime,
          created: item.created
        }
      };
    });
    return list.filter((i) => i !== null);
  },
  /**
   * The history data object.
   * - _id: autogenerated.
   * - headers
   * - payload
   * - url
   * - method
   * - response: Object
   *   - statusCode
   *   - statusText
   *   - headers
   *   - payload
   * - timings
   * - created: int!
   */
  processHar: function(har) {
    if (!har || !har.entries || !har.entries.length) {
      return null;
    }
    return har.entries.map((item) => {
      let req = item.request;
      let res = item.response;
      let cd = new Date(item.startedDateTime).getTime();
      if (cd !== cd) {
        cd = Date.now();
      }
      return {
        _id: this.$.uuid.generate(),
        headers: this._parseHarHeders(req.headers),
        payload: req.postData.text,
        url: req.url,
        method: req.method,
        timings: item.timings,
        totalTime: item.time,
        created: cd,
        response: {
          statusCode: res.status,
          statusText: res.statusText,
          headers: this._parseHarHeders(res.headers),
          payload: res.content.text
        }
      };
    });
  },

  _insertLegacyProjects: function(data) {
    if (!data || !data.length) {
      return Promise.resolve();
    }
    this.fire('upgrade-102016', {
      message: 'Inserting projects (' + data.length + ')'
    });
    var db = new PouchDB('legacy-projects');
    return db.bulkDocs(data.map((i) => i.legacyProject));
  },

  _insertSavedRequests: function(data) {
    if (!data || !data.length) {
      return Promise.resolve();
    }
    this.fire('upgrade-102016', {
      message: 'Inserting saved requests (' + data.length + ')'
    });
    var db = new PouchDB('saved-requests');
    return db.bulkDocs(data.map((i) => i.request));
  },

  _insertHistorydRequests: function(data) {
    if (!data || !data.length) {
      return Promise.resolve();
    }
    this.fire('upgrade-102016', {
      message: 'Inserting history (' + data.length + ')'
    });
    var db = new PouchDB('history-requests');
    return db.bulkDocs(data.map((i) => i.request));
  },

  _insertDrivedRequests: function(data) {
    if (!data || !data.length) {
      return Promise.resolve();
    }
    this.fire('upgrade-102016', {
      message: 'Inserting external data (' + data.length + ')'
    });
    var db = new PouchDB('external-requests');
    return db.bulkDocs(data.map((i) => i.request));
  },

  _insertHistoryData: function(data) {
    if (!data || !data.length) {
      return Promise.resolve();
    }
    this.fire('upgrade-102016', {
      message: 'Inserting history (HAR) data (' + data.length + ')'
    });
    var db = new PouchDB('history-data');
    return db.bulkDocs(data);
  },

  _insertCookies: function(data) {
    if (!data || !data.length) {
      return Promise.resolve();
    }
    this.fire('upgrade-102016', {
      message: 'Inserting cookies (' + data.length + ')'
    });
    var db = new PouchDB('arc-cookies');
    return db.bulkDocs(data);
  },

  _insertAuthData: function(data) {
    if (!data || !data.length) {
      return Promise.resolve();
    }
    this.fire('upgrade-102016', {
      message: 'Inserting auth data (' + data.length + ')'
    });
    var db = new PouchDB('auth-data');
    return db.bulkDocs(data);
  },

  _assignProjects: function(data, projects) {
    if (!projects || !projects.length) {
      return;
    }
    this.fire('upgrade-102016', {
      message: 'Associating legacy projects with requests'
    });
    data.saved = data.saved || [];
    var savedLen = data.saved.length;
    for (let i = 0, pLen = projects.length; i < pLen; i++) {
      let project = projects[i];
      if (!project || !project.insertId) {
        continue;
      }
      let newProjectId = project.insertId;
      for (let j = 0, rLen = project.updateData.length; j < rLen; j++) {
        let rId = project.updateData[j];
        for (let k = 0; k < savedLen; k++) {
          if (data.saved[k].origin === rId) {
            if (!data.saved[k].legacyProject) {
              data.saved[k].request.legacyProject = newProjectId;
              break;
            }
          }
        }
      }
    }
  },

  copyCookies: function() {
    return new Promise((resolve, reject) => {
      var db;
      var error;
      arc.app.db.idb.open()
      .then((_db) => {
        db = _db;
        return db.cookies.toArray();
      })
      .then((arr) => {
        if (!arr || !arr.length) {
          return null;
        }
        return arr.map((i) => {
          i = Object.assign({}, i);
          i.domain = i._domain;
          i.expires = i._expires;
          i.maxAge = i._maxAge;
          delete i._domain;
          delete i._expires;
          delete i._maxAge;
          i._id = i.domain + '/' + encodeURIComponent(i.name) + '/' + encodeURIComponent(i.path);
          return i;
        });
      })
      .then((toInsert) => this._insertCookies(toInsert))
      .catch((err) => {
        error = err;
      })
      .finally(function() {
        db.close();
        // Escape Dexie promise system.
        if (error) {
          return reject(); // <- like building node modules using promises... terrible
          // I mean, really, people, learn to use promises!
          // And learn how should it be used. Def not like Dexie does.
        }
        resolve();
      });
    });
  },

  copyAuthData: function() {
    return new Promise((resolve, reject) => {
      var db;
      var error;
      arc.app.db.idb.open()
      .then((_db) => {
        db = _db;
        return db.basicAuth.toArray();
      })
      .then((arr) => {
        if (!arr || !arr.length) {
          return null;
        }
        return arr.map((i) => {
          i = Object.assign({}, i);
          i._id = i.type + '/' + encodeURIComponent(i.url);
          return i;
        });
      })
      .then((toInsert) => this._insertAuthData(toInsert))
      .catch((err) => {
        error = err;
      })
      .finally(function() {
        db.close();
        // Escape Dexie promise system.
        if (error) {
          return reject();
        }
        resolve();
      });
    });
  }
});
})();
<|endoftext|>


<commit_before>(function () {

  // Bloodhound.tokenizers.whitespace but sets to lowercase first.
  function customTokenizer (s) {
    s = s.toString(s).toLowerCase();
    return s ? s.split(/\s+/) : [];
  }

  // A simple replacer that lets us lowercase the request before
  // sending it.
  function customReplacer (url, query) {
    query = query.toLowerCase();
    let freshUrl = url.replace('%QUERY', query);
    return freshUrl;
  }

  function getSuggestion(datum){
    // Perform some minor normalization for quoted names.
    //
    // Yes, those are actually two different versions of quotes
    let value = datum.name.replace('"', '"').replace('"', '"');
    return `<misc-typeahead-line suggestion="${value}"></misc-typeahead-line>`;
  }

  Polymer({
    // A typeahead using the twitter typeahead.
    //
    // Fires the 'completed' event with the 'name' detail when a
    // choice has been made
    //
    // Leverages the misc-typeahead-line for single line easy templating.
    is: 'preordain-typeahead',
    properties: {
      // Typeahead options
      url: { // Where we fetch remotely from, defaults to global value
             // Set to an empty string to force hardOptions only.
        type: String,
        value: remote.typeAhead,
      },
      hardOptions: { // Locally populated options
        type: Array,
        value: ()=> [],
      },
      _small: {
        type: Boolean,
        value: false,
      }
    },
    attached: function(){
      this.loaded = false;
      this.loadTypeahead();

      // Set up the event listeners a single time.
      $('#visibleInput').on('typeahead:selected typeahead:autocompleted',
        (e, selection)=> this._fireResult(selection.name));

    },
    loadTypeahead: function(){
      if (this.loaded) throw 'typeahead already loaded';

      // Initialize the remote only if we actually want to
      let remote = null;
      if (this.url.trim().length > 0){
        remote = {
          url: this.url,
          replace: customReplacer,
          filter: (list)=> {
            // Filter out any official set names the remote presents to us.
            list = list.filter((s)=> !setList.has(s));
            return list.map((s)=> {
              return {name: s};
            });
          }
        };
      }

      // Spread operator is borked in this babel release, getting an
      // 'Array.from is not a function' error, falling back to es5
      let preloaded = this.hardOptions.concat();
      displaySets.forEach((s)=> preloaded.push(s));
      // Make sure we are sorted by length with lowest first
      preloaded.sort((a, b)=> a.length - b.length);

      var names = new Bloodhound({
        datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
        queryTokenizer: customTokenizer,
        local: preloaded.map((s)=> {
              return {name: s};
        }),
        remote: remote,
        rateLimitWait: 250
      });

      names.initialize();

      $('#visibleInput').typeahead({
        hint: true,
        minLength: 1,
      }, {
        name: 'names',
        display: 'name',
        source: names.ttAdapter(),
        limit: 5,
        templates:{
          suggestion: getSuggestion
        }
      });

      this.loaded = true;
    },
    removeTypeahead: function(){
      // Remove it
      this.loaded = false;
    },
    // Sends a choice a user has made alongside some relevant metadata.
    _fireResult: function(selection){

      // Remove focus from the typeahead to hide any mobile keyboards.
      if (this._small) document.activeElement.blur();

      this.fire('completed', {
        'choice':selection,
        'isSet': displaySets.has(selection),
      });
    }

  });
})();<commit_msg>preordain-typeahead can now have multiple instances<commit_after>(function () {

  // Bloodhound.tokenizers.whitespace but sets to lowercase first.
  function customTokenizer (s) {
    s = s.toString(s).toLowerCase();
    return s ? s.split(/\s+/) : [];
  }

  // A simple replacer that lets us lowercase the request before
  // sending it.
  function customReplacer (url, query) {
    query = query.toLowerCase();
    let freshUrl = url.replace('%QUERY', query);
    return freshUrl;
  }

  function getSuggestion(datum){
    // Perform some minor normalization for quoted names.
    //
    // Yes, those are actually two different versions of quotes
    let value = datum.name.replace('"', '"').replace('"', '"');
    return `<misc-typeahead-line suggestion="${value}"></misc-typeahead-line>`;
  }

  Polymer({
    // A typeahead using the twitter typeahead.
    //
    // Fires the 'completed' event with the 'name' detail when a
    // choice has been made
    //
    // Leverages the misc-typeahead-line for single line easy templating.
    is: 'preordain-typeahead',
    properties: {
      // Typeahead options
      url: { // Where we fetch remotely from, defaults to global value
             // Set to an empty string to force hardOptions only.
        type: String,
        value: remote.typeAhead,
      },
      hardOptions: { // Locally populated options
        type: Array,
        value: ()=> [],
      },
      _small: {
        type: Boolean,
        value: false,
      }
    },
    attached: function(){
      this.loaded = false;
      this.loadTypeahead();

      // Set up the event listeners a single time.
      $(this.$.visibleInput)
      .on('typeahead:selected typeahead:autocompleted',
        (e, selection)=> this._fireResult(selection.name));

    },
    loadTypeahead: function(){
      if (this.loaded) throw 'typeahead already loaded';

      // Initialize the remote only if we actually want to
      let remote = null;
      if (this.url.trim().length > 0){
        remote = {
          url: this.url,
          replace: customReplacer,
          filter: (list)=> {
            // Filter out any official set names the remote presents to us.
            list = list.filter((s)=> !setList.has(s));
            return list.map((s)=> {
              return {name: s};
            });
          }
        };
      }

      // Spread operator is borked in this babel release, getting an
      // 'Array.from is not a function' error, falling back to es5
      let preloaded = this.hardOptions.concat();
      displaySets.forEach((s)=> preloaded.push(s));
      // Make sure we are sorted by length with lowest first
      preloaded.sort((a, b)=> a.length - b.length);

      var names = new Bloodhound({
        datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
        queryTokenizer: customTokenizer,
        local: preloaded.map((s)=> {
              return {name: s};
        }),
        remote: remote,
        rateLimitWait: 250
      });

      names.initialize();

      $(this.$.visibleInput).typeahead({
        hint: true,
        minLength: 1,
      }, {
        name: 'names',
        display: 'name',
        source: names.ttAdapter(),
        limit: 5,
        templates:{
          suggestion: getSuggestion
        }
      });

      this.loaded = true;
    },
    removeTypeahead: function(){
      // Remove it
      this.loaded = false;
    },
    // Sends a choice a user has made alongside some relevant metadata.
    _fireResult: function(selection){

      // Remove focus from the typeahead to hide any mobile keyboards.
      if (this._small) document.activeElement.blur();

      this.fire('completed', {
        'choice':selection,
        'isSet': displaySets.has(selection),
      });
    }

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


<commit_before>/* eslint-disable */
// https://github.com/karma-runner/karma/issues/1597
'use strict';

const conf = require('./base.karma.conf');

conf.plugins.push(
  require('karma-phantomjs-launcher'),
  require('karma-chrome-launcher'),
  require('karma-firefox-launcher')
);

conf.browsers = ['Firefox'];
// conf.browsers = ['PhantomJS', 'Chrome', 'ChromeCanary', 'Firefox'];

module.exports = function configureKarma(config) {
  config.set(conf);
};
<commit_msg>reinstitute local test browsers<commit_after>/* eslint-disable */
// https://github.com/karma-runner/karma/issues/1597
'use strict';

const conf = require('./base.karma.conf');

conf.plugins.push(
  require('karma-phantomjs-launcher'),
  require('karma-chrome-launcher'),
  require('karma-firefox-launcher')
);

conf.browsers = ['PhantomJS', 'Chrome', 'ChromeCanary', 'Firefox'];

module.exports = function configureKarma(config) {
  config.set(conf);
};
<|endoftext|>


<commit_before>/**
* Copyright 2012 Microsoft Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

var should = require('should');

var cli = require('../cli');
var capture = require('../util').capture;

var format = require('util').format;

var fs = require('fs');
var pathUtil = require('path');
if (!fs.existsSync) {
    fs.existsSync = pathUtil.existsSync;
};

var baseTestTempDir = "__temp";
var testDirBase = "test";
var testDirIndex = 0;
var testDir = "";

suite('cli', function () {
    suite('site deploymentscript', function () {
        setup(function () {
            // Reset site deploymentscript command
            for (var i in cli.categories.site.commands) {
                var command = cli.categories.site.commands[i];
                if (command.name == 'deploymentscript') {
                    delete command.php;
                    delete command.basic;
                    delete command.aspWAP;
                    delete command.aspWebSite;
                    delete command.python;
                    delete command.node;
                    delete command.repositoryRoot;
                    delete command.suppressPrompt;
                    delete command.scriptType;
                    delete command.solutionFile;
                    delete command.sitePath;
                }
            }

            testDirIndex++;
            testDir = pathUtil.join(baseTestTempDir, testDirBase + testDirIndex);
            ensurePathExists(testDir);
        });

        teardown(function () {
            removePath(testDir);
        });

        test('generate batch basic deployment script (--basic -t batch -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --basic -t batch -r ' + testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done, /*bash*/false);
        });

        test('generate bash basic deployment script (--basic -t bash -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --basic -t bash -r ' + testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done, /*bash*/true);
        });

        test('generate batch php deployment script (--php -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --php -r ' + testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done);
        });

        test('generate bash php deployment script (--php -t bash -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --php -t bash -r ' + testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done, /*bash*/true);
        });

        test('generate batch python deployment script (--python -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --python -r ' + testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done);
        });

        test('generate batch python deployment script twice with -y (--python -y -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --python -y -r ' + testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, function () {
                runBasicSiteDeploymentScriptScenario(cmd, done);
            });
        });

        test('generate bash python deployment script (--python --scriptType bash -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --python --scriptType bash -r ' + testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done, /*bash*/true);
        });

        test('generate batch basic aspWebSite deployment script (--aspWebSite --repositoryRoot)', function (done) {
            var cmd = ('node cli.js site deploymentscript --aspWebSite --repositoryRoot ' + testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done);
        });

        test('generate node deployment script (--node -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --node -r ' + testDir).split(' ');

            runNodeSiteDeploymentScriptScenario(cmd, done);
        });

        test('generate bash node deployment script (--node -t bash -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --node -t bash -r ' + testDir).split(' ');

            runNodeSiteDeploymentScriptScenario(cmd, done, /*bash*/true);
        });

        test('generate batch aspWebSite with solution file deployment script (--aspWebSite -s solutionFile.sln -p site -r)', function (done) {
            var solutionFile = 'solutionFile.sln';
            var solutionFilePath = pathUtil.join(testDir, solutionFile);
            var siteDir = 'site';
            var siteDirPath = pathUtil.join(testDir, siteDir);

            var cmd = format('node cli.js site deploymentscript --aspWebSite -s %s -p %s -r %s', solutionFilePath, siteDirPath, testDir).split(' ');

            runAspWebSiteDeploymentScriptScenario(cmd, done, solutionFile);
        });

        test('generate batch aspWAP deployment script (--aspWAP projectFile.csproj -r)', function (done) {
            var projectFile = 'projectFile.csproj';
            var projectFilePath = pathUtil.join(testDir, projectFile);

            var cmd = format('node cli.js site deploymentscript --aspWAP %s -r %s', projectFilePath, testDir).split(' ');

            runAspWAPDeploymentScriptScenario(cmd, done, projectFile);
        });

        test('generate batch aspWAP with solution file deployment script (--aspWAP projectFile.csproj -s solutionFile.sln -r)', function (done) {
            var projectFile = 'projectFile.csproj';
            var projectFilePath = pathUtil.join(testDir, projectFile);
            var solutionFile = 'solutionFile.sln';
            var solutionFilePath = pathUtil.join(testDir, solutionFile);

            var cmd = format('node cli.js site deploymentscript --aspWAP %s -s %s -r %s', projectFilePath, solutionFilePath, testDir).split(' ');

            runAspWAPDeploymentScriptScenario(cmd, done, projectFile, solutionFile);
        });

        test('generate batch basic site deployment script with sitePath (--basic -p site -r)', function (done) {
            var siteDir = 'site';
            var siteDirPath = pathUtil.join(testDir, siteDir);

            var cmd = format('node cli.js site deploymentscript --basic -p %s -r %s', siteDirPath, testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done, /*bash*/false, '%\\site');
        });

        test('generate batch php site deployment script with sitePath fullpath (--php -p site\\site2 -r)', function (done) {
            var siteDir = 'site\\site2';
            var siteDirPath = pathUtil.resolve(pathUtil.join(testDir, siteDir));

            var cmd = format('node cli.js site deploymentscript --php -p %s -r %s', siteDirPath, testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done, /*bash*/false, '%\\site\\site2');
        });

        test('generate bash python site deployment script with sitePath (--python -t bash --sitePath site -r)', function (done) {
            var siteDir = 'site';
            var siteDirPath = pathUtil.join(testDir, siteDir);

            var cmd = format('node cli.js site deploymentscript --python -t bash --sitePath %s -r %s', siteDirPath, testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done, /*bash*/true, '$DEPLOYMENT_SOURCE\\site');
        });

        test('using exclusion flags together should fail (--aspWebSite --python ...)', function (done) {
            var cmd = ('node cli.js site deploymentscript --aspWebSite --python -r ' + testDir).split(' ');

            runErrorScenario(cmd, 'specify only one of these flags', done);
        });

        test('using exclusion flags together should fail (--node --php ...)', function (done) {
            var cmd = ('node cli.js site deploymentscript --node --php -r ' + testDir).split(' ');

            runErrorScenario(cmd, 'specify only one of these flags', done);
        });

        test('using exclusion flags together should fail (--aspWAP . --basic ...)', function (done) {
            var cmd = ('node cli.js site deploymentscript --aspWAP . --basic -r ' + testDir).split(' ');

            runErrorScenario(cmd, 'specify only one of these flags', done);
        });

        test('using exclusion flags together should fail (--basic --php ...)', function (done) {
            var cmd = ('node cli.js site deploymentscript --basic --php -r ' + testDir).split(' ');

            runErrorScenario(cmd, 'specify only one of these flags', done);
        });

        test('--aspWAP requires project file path argument', function (done) {
            var cmd = ('node cli.js site deploymentscript -r ' + testDir + ' --aspWAP').split(' ');

            runErrorScenario(cmd, 'argument missing', done);
        });

        test('--node requires directory to contain server.js file (--node)', function (done) {
            var cmd = ('node cli.js site deploymentscript --node -r ' + testDir).split(' ');

            runErrorScenario(cmd, 'Missing server.js/app.js file', done);
        });

        test('--scriptType only accepts batch or bash (--scriptType sh)', function (done) {
            var cmd = ('node cli.js site deploymentscript --php --scriptType sh -r ' + testDir).split(' ');

            runErrorScenario(cmd, 'Script type should be either batch or bash', done);
        });
    });
});

function runAspWebSiteDeploymentScriptScenario(cmd, callback, solutionFile) {
    var scriptFileName = 'deploy.cmd';

    runSiteDeploymentScriptScenario(
        cmd,
        ['Generating deployment script for .NET Web Site', 'Generated deployment script (' + scriptFileName + ' and .deployment)'],
        ['echo Handling .NET Web Site deployment.', solutionFile, 'MSBUILD_PATH'],
        scriptFileName,
        callback);
}

function runAspWAPDeploymentScriptScenario(cmd, callback, projectFile, solutionFile) {
    var scriptFileName = 'deploy.cmd';
    solutionFile = solutionFile || '';

    runSiteDeploymentScriptScenario(
        cmd,
        ['Generating deployment script for .NET Web Application', 'Generated deployment script (' + scriptFileName + ' and .deployment)'],
        ['echo Handling .NET Web Application deployment.', projectFile, 'MSBUILD_PATH', solutionFile],
        scriptFileName,
        callback);
}

function runBasicSiteDeploymentScriptScenario(cmd, callback, bash, expectedSitePath) {
    var scriptFileName = bash ? 'deploy.sh' : 'deploy.cmd';
    var scriptExtraInclue = bash ? '#!/bin/bash' : '@echo off';

    expectedSitePath = expectedSitePath || '';

    runSiteDeploymentScriptScenario(
        cmd,
        ['Generating deployment script for Web Site', 'Generated deployment script (' + scriptFileName + ' and .deployment)'],
        ['echo Handling Basic Web Site deployment.', scriptExtraInclue, expectedSitePath],
        scriptFileName,
        callback);
}

function runNodeSiteDeploymentScriptScenario(cmd, callback, bash) {
    var nodeStartUpFile = 'server.js';

    generateNodeStartJsFile(nodeStartUpFile);

    var scriptFileName = bash ? 'deploy.sh' : 'deploy.cmd';
    var scriptExtraInclue = bash ? '#!/bin/bash' : '@echo off';

    runSiteDeploymentScriptScenario(
        cmd,
        ['Generating deployment script for node', 'Generated deployment script (' + scriptFileName + ' and .deployment)'],
        ['echo Handling node.js deployment.', scriptExtraInclue],
        scriptFileName,
        function (err) {
            if (err) {
                callback(err);
                return;
            }

            try {
                var webConfigContent = getFileContent('web.config');
                webConfigContent.should.include(nodeStartUpFile);
                webConfigContent.should.not.include('{NodeStartFile}');

                var iisNodeYmlContent = getFileContent('iisnode.yml');
                iisNodeYmlContent.should.include('node_env: production');

                callback();
            }
            catch (e) {
                callback(e);
            }
        });
}

function runSiteDeploymentScriptScenario(cmd, outputContains, scriptContains, scriptFileName, callback) {
    runCommand(cmd, function (result, e) {
        if (e) {
            callback(e);
            return;
        }

        result.exitStatus.should.equal(0, 'Received an error status exit code');

        for (var i = 0; i < outputContains.length; i++) {
            result.text.should.include(outputContains[i]);
        }

        var deployCmdContent = getFileContent(scriptFileName);
        for (var i = 0; i < scriptContains.length; i++) {
            deployCmdContent.should.include(scriptContains[i]);
        }
        deployCmdContent.should.not.include('{MSBuildArguments}');
        deployCmdContent.should.not.include('{SitePath}');

        var deploymentFileContent = getFileContent('.deployment');
        deploymentFileContent.should.include(scriptFileName);

        callback();
    });
}

function runErrorScenario(cmd, errorText, callback) {
    runCommand(cmd, function (result, e) {
        if (e) {
            callback(e);
            return;
        }

        result.exitStatus.should.equal(1, 'Received success status exit code');
        result.errorText.should.include(errorText);
        callback();
    });
}

function runCommand(cmd, callback) {
    capture(function () {
        cli.parse(cmd);
    }, function (result) {
        if (result.error) {
            // To avoid calling done twice
            return;
        }

        try {
            console.log('\n' + result.text);
            console.log(result.errorText);
            callback(result);
        }
        catch (e) {
            callback(result, e);
        }
    });
}

function generateNodeStartJsFile(startFile) {
    fs.writeFileSync(pathUtil.join(testDir, startFile), '//do nothing', 'utf8');
}

function getFileContent(path) {
    path = pathUtil.join(testDir, path);
    fs.existsSync(path).should.equal(true, "File doesn't exist: " + path);
    return fs.readFileSync(path, 'utf8');
}

function removePath(path) {
    var stat = tryGetFileStat(path);
    if (stat) {
        if (!stat.isDirectory()) {
            tryRemoveFile(path);
        }
        else {
            var files = fs.readdirSync(path);
            for (var index in files) {
                var file = files[index];
                var filePath = pathUtil.join(path, file);
                removePath(filePath);
            }

            tryRemoveDir(path);
        }
    }
}

function tryGetFileStat(path) {
    try {
        return fs.statSync(path);
    }
    catch (e) {
        if (e.errno == 34) {
            // Return null if path doesn't exist
            return null;
        }

        throw e;
    }
}

function tryRemoveFile(path) {
    try {
        fs.unlinkSync(path);
    }
    catch (e) {
        console.log(e);
    }
}

function tryRemoveDir(path) {
    try {
        fs.rmdirSync(path);
    }
    catch (e) {
    }
}

function ensurePathExists(path) {
    if (!fs.existsSync(path)) {
        ensurePathExists(pathUtil.dirname(path));
        fs.mkdirSync(path);
    }
}
<commit_msg>Test update<commit_after>/**
* Copyright 2012 Microsoft Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

var should = require('should');

var cli = require('../cli');
var capture = require('../util').capture;

var format = require('util').format;

var fs = require('fs');
var pathUtil = require('path');
if (!fs.existsSync) {
    fs.existsSync = pathUtil.existsSync;
};

var baseTestTempDir = "__temp";
var testDirBase = "test";
var testDirIndex = 0;
var testDir = "";

suite('cli', function () {
    suite('site deploymentscript', function () {
        setup(function () {
            // Reset site deploymentscript command
            for (var i in cli.categories.site.commands) {
                var command = cli.categories.site.commands[i];
                if (command.name == 'deploymentscript') {
                    delete command.php;
                    delete command.basic;
                    delete command.aspWAP;
                    delete command.aspWebSite;
                    delete command.python;
                    delete command.node;
                    delete command.repositoryRoot;
                    delete command.suppressPrompt;
                    delete command.scriptType;
                    delete command.solutionFile;
                    delete command.sitePath;
                }
            }

            testDirIndex++;
            testDir = pathUtil.join(baseTestTempDir, testDirBase + testDirIndex);
            ensurePathExists(testDir);
        });

        teardown(function () {
            removePath(testDir);
        });

        test('generate batch basic deployment script (--basic -t batch -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --basic -t batch -r ' + testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done, /*bash*/false);
        });

        test('generate bash basic deployment script (--basic -t bash -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --basic -t bash -r ' + testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done, /*bash*/true);
        });

        test('generate batch php deployment script (--php -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --php -r ' + testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done);
        });

        test('generate bash php deployment script (--php -t bash -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --php -t bash -r ' + testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done, /*bash*/true);
        });

        test('generate batch python deployment script (--python -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --python -r ' + testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done);
        });

        test('generate batch python deployment script twice with -y (--python -y -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --python -y -r ' + testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, function () {
                runBasicSiteDeploymentScriptScenario(cmd, done);
            });
        });

        test('generate bash python deployment script (--python --scriptType bash -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --python --scriptType bash -r ' + testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done, /*bash*/true);
        });

        test('generate batch basic aspWebSite deployment script (--aspWebSite --repositoryRoot)', function (done) {
            var cmd = ('node cli.js site deploymentscript --aspWebSite --repositoryRoot ' + testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done);
        });

        test('generate node deployment script (--node -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --node -r ' + testDir).split(' ');

            runNodeSiteDeploymentScriptScenario(cmd, done);
        });

        test('generate bash node deployment script (--node -t bash -r)', function (done) {
            var cmd = ('node cli.js site deploymentscript --node -t bash -r ' + testDir).split(' ');

            runNodeSiteDeploymentScriptScenario(cmd, done, /*bash*/true);
        });

        test('generate batch aspWebSite with solution file deployment script (--aspWebSite -s solutionFile.sln -p site -r)', function (done) {
            var solutionFile = 'solutionFile.sln';
            var solutionFilePath = pathUtil.join(testDir, solutionFile);
            var siteDir = 'site';
            var siteDirPath = pathUtil.join(testDir, siteDir);

            var cmd = format('node cli.js site deploymentscript --aspWebSite -s %s -p %s -r %s', solutionFilePath, siteDirPath, testDir).split(' ');

            runAspWebSiteDeploymentScriptScenario(cmd, done, solutionFile);
        });

        test('generate batch aspWAP deployment script (--aspWAP projectFile.csproj -r)', function (done) {
            var projectFile = 'projectFile.csproj';
            var projectFilePath = pathUtil.join(testDir, projectFile);

            var cmd = format('node cli.js site deploymentscript --aspWAP %s -r %s', projectFilePath, testDir).split(' ');

            runAspWAPDeploymentScriptScenario(cmd, done, projectFile);
        });

        test('generate batch aspWAP with solution file deployment script (--aspWAP site\\projectFile.csproj -s solutionFile.sln -r)', function (done) {
            var projectFile = 'site\\projectFile.csproj';
            var projectFilePath = pathUtil.join(testDir, projectFile);
            var solutionFile = 'solutionFile.sln';
            var solutionFilePath = pathUtil.join(testDir, solutionFile);

            var cmd = format('node cli.js site deploymentscript --aspWAP %s -s %s -r %s', projectFilePath, solutionFilePath, testDir).split(' ');

            runAspWAPDeploymentScriptScenario(cmd, done, projectFile, solutionFile);
        });

        test('generate batch basic site deployment script with sitePath (--basic -p site -r)', function (done) {
            var siteDir = 'site';
            var siteDirPath = pathUtil.join(testDir, siteDir);

            var cmd = format('node cli.js site deploymentscript --basic -p %s -r %s', siteDirPath, testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done, /*bash*/false, '%\\site');
        });

        test('generate batch php site deployment script with sitePath fullpath (--php -p site\\site2 -r)', function (done) {
            var siteDir = 'site\\site2';
            var siteDirPath = pathUtil.resolve(pathUtil.join(testDir, siteDir));

            var cmd = format('node cli.js site deploymentscript --php -p %s -r %s', siteDirPath, testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done, /*bash*/false, '%\\site\\site2');
        });

        test('generate bash python site deployment script with sitePath (--python -t bash --sitePath site -r)', function (done) {
            var siteDir = 'site';
            var siteDirPath = pathUtil.join(testDir, siteDir);

            var cmd = format('node cli.js site deploymentscript --python -t bash --sitePath %s -r %s', siteDirPath, testDir).split(' ');

            runBasicSiteDeploymentScriptScenario(cmd, done, /*bash*/true, '$DEPLOYMENT_SOURCE\\site');
        });

        test('using exclusion flags together should fail (--aspWebSite --python ...)', function (done) {
            var cmd = ('node cli.js site deploymentscript --aspWebSite --python -r ' + testDir).split(' ');

            runErrorScenario(cmd, 'specify only one of these flags', done);
        });

        test('using exclusion flags together should fail (--node --php ...)', function (done) {
            var cmd = ('node cli.js site deploymentscript --node --php -r ' + testDir).split(' ');

            runErrorScenario(cmd, 'specify only one of these flags', done);
        });

        test('using exclusion flags together should fail (--aspWAP . --basic ...)', function (done) {
            var cmd = ('node cli.js site deploymentscript --aspWAP . --basic -r ' + testDir).split(' ');

            runErrorScenario(cmd, 'specify only one of these flags', done);
        });

        test('using exclusion flags together should fail (--basic --php ...)', function (done) {
            var cmd = ('node cli.js site deploymentscript --basic --php -r ' + testDir).split(' ');

            runErrorScenario(cmd, 'specify only one of these flags', done);
        });

        test('--aspWAP requires project file path argument', function (done) {
            var cmd = ('node cli.js site deploymentscript -r ' + testDir + ' --aspWAP').split(' ');

            runErrorScenario(cmd, 'argument missing', done);
        });

        test('--node requires directory to contain server.js file (--node)', function (done) {
            var cmd = ('node cli.js site deploymentscript --node -r ' + testDir).split(' ');

            runErrorScenario(cmd, 'Missing server.js/app.js file', done);
        });

        test('--scriptType only accepts batch or bash (--scriptType sh)', function (done) {
            var cmd = ('node cli.js site deploymentscript --php --scriptType sh -r ' + testDir).split(' ');

            runErrorScenario(cmd, 'Script type should be either batch or bash', done);
        });
    });
});

function runAspWebSiteDeploymentScriptScenario(cmd, callback, solutionFile) {
    var scriptFileName = 'deploy.cmd';

    runSiteDeploymentScriptScenario(
        cmd,
        ['Generating deployment script for .NET Web Site', 'Generated deployment script (' + scriptFileName + ' and .deployment)'],
        ['echo Handling .NET Web Site deployment.', solutionFile, 'MSBUILD_PATH'],
        scriptFileName,
        callback);
}

function runAspWAPDeploymentScriptScenario(cmd, callback, projectFile, solutionFile) {
    var scriptFileName = 'deploy.cmd';
    solutionFile = solutionFile || '';

    runSiteDeploymentScriptScenario(
        cmd,
        ['Generating deployment script for .NET Web Application', 'Generated deployment script (' + scriptFileName + ' and .deployment)'],
        ['echo Handling .NET Web Application deployment.', projectFile, 'MSBUILD_PATH', solutionFile],
        scriptFileName,
        callback);
}

function runBasicSiteDeploymentScriptScenario(cmd, callback, bash, expectedSitePath) {
    var scriptFileName = bash ? 'deploy.sh' : 'deploy.cmd';
    var scriptExtraInclue = bash ? '#!/bin/bash' : '@echo off';

    expectedSitePath = expectedSitePath || '';

    runSiteDeploymentScriptScenario(
        cmd,
        ['Generating deployment script for Web Site', 'Generated deployment script (' + scriptFileName + ' and .deployment)'],
        ['echo Handling Basic Web Site deployment.', scriptExtraInclue, expectedSitePath],
        scriptFileName,
        callback);
}

function runNodeSiteDeploymentScriptScenario(cmd, callback, bash) {
    var nodeStartUpFile = 'server.js';

    generateNodeStartJsFile(nodeStartUpFile);

    var scriptFileName = bash ? 'deploy.sh' : 'deploy.cmd';
    var scriptExtraInclue = bash ? '#!/bin/bash' : '@echo off';

    runSiteDeploymentScriptScenario(
        cmd,
        ['Generating deployment script for node', 'Generated deployment script (' + scriptFileName + ' and .deployment)'],
        ['echo Handling node.js deployment.', scriptExtraInclue],
        scriptFileName,
        function (err) {
            if (err) {
                callback(err);
                return;
            }

            try {
                var webConfigContent = getFileContent('web.config');
                webConfigContent.should.include(nodeStartUpFile);
                webConfigContent.should.not.include('{NodeStartFile}');

                var iisNodeYmlContent = getFileContent('iisnode.yml');
                iisNodeYmlContent.should.include('node_env: production');

                callback();
            }
            catch (e) {
                callback(e);
            }
        });
}

function runSiteDeploymentScriptScenario(cmd, outputContains, scriptContains, scriptFileName, callback) {
    runCommand(cmd, function (result, e) {
        if (e) {
            callback(e);
            return;
        }

        result.exitStatus.should.equal(0, 'Received an error status exit code');

        for (var i = 0; i < outputContains.length; i++) {
            result.text.should.include(outputContains[i]);
        }

        var deployCmdContent = getFileContent(scriptFileName);
        for (var i = 0; i < scriptContains.length; i++) {
            deployCmdContent.should.include(scriptContains[i]);
        }
        deployCmdContent.should.not.include('{MSBuildArguments}');
        deployCmdContent.should.not.include('{SitePath}');

        var deploymentFileContent = getFileContent('.deployment');
        deploymentFileContent.should.include(scriptFileName);

        callback();
    });
}

function runErrorScenario(cmd, errorText, callback) {
    runCommand(cmd, function (result, e) {
        if (e) {
            callback(e);
            return;
        }

        result.exitStatus.should.equal(1, 'Received success status exit code');
        result.errorText.should.include(errorText);
        callback();
    });
}

function runCommand(cmd, callback) {
    capture(function () {
        cli.parse(cmd);
    }, function (result) {
        if (result.error) {
            // To avoid calling done twice
            return;
        }

        try {
            console.log('\n' + result.text);
            console.log(result.errorText);
            callback(result);
        }
        catch (e) {
            callback(result, e);
        }
    });
}

function generateNodeStartJsFile(startFile) {
    fs.writeFileSync(pathUtil.join(testDir, startFile), '//do nothing', 'utf8');
}

function getFileContent(path) {
    path = pathUtil.join(testDir, path);
    fs.existsSync(path).should.equal(true, "File doesn't exist: " + path);
    return fs.readFileSync(path, 'utf8');
}

function removePath(path) {
    var stat = tryGetFileStat(path);
    if (stat) {
        if (!stat.isDirectory()) {
            tryRemoveFile(path);
        }
        else {
            var files = fs.readdirSync(path);
            for (var index in files) {
                var file = files[index];
                var filePath = pathUtil.join(path, file);
                removePath(filePath);
            }

            tryRemoveDir(path);
        }
    }
}

function tryGetFileStat(path) {
    try {
        return fs.statSync(path);
    }
    catch (e) {
        if (e.errno == 34) {
            // Return null if path doesn't exist
            return null;
        }

        throw e;
    }
}

function tryRemoveFile(path) {
    try {
        fs.unlinkSync(path);
    }
    catch (e) {
        console.log(e);
    }
}

function tryRemoveDir(path) {
    try {
        fs.rmdirSync(path);
    }
    catch (e) {
    }
}

function ensurePathExists(path) {
    if (!fs.existsSync(path)) {
        ensurePathExists(pathUtil.dirname(path));
        fs.mkdirSync(path);
    }
}
<|endoftext|>