<commit_before>/*
 * Copyright (C) 2013 Vanderbilt University, All rights reserved.
 *
 * Author: Robert Kereskenyi
 */

"use strict";

define(['./DragEffects',
        './DragConstants'], function (DragEffects, DragConstants) {

    var DEFAULT_Z_INDEX = 100000,
        DEFAULT_APPEND_TO = $('body'),
        DEFAULT_CURSOR_AT = { left: 10, top: 10 };

    var _makeDraggable = function (el, params) {
        el.draggable({
            zIndex: DEFAULT_Z_INDEX,
            appendTo: DEFAULT_APPEND_TO,
            cursorAt: DEFAULT_CURSOR_AT,
            helper: function (event) {
                var helperEl;

                if (params && _.isFunction(params.helper)) {
                    helperEl = params.helper.call(el, event);
                } else {
                    helperEl = el.clone();
                }

                //prevent dragged helper to catch any pointer events
                helperEl.css({'pointer-events':'none'});

                //add DRAG info
                helperEl.data(DragConstants.DRAG_INFO, _createDragInfo(el, params, event));

                return helperEl;
            },
            start: function( event, ui ) {
                if (params && _.isFunction(params.start)) {
                    return params.start.call(el, event);
                }
            },
            drag: function( event, ui ) {
                if (params && _.isFunction(params.drag)) {
                    return params.drag.call(el, event);
                }
            },
            stop: function( event, ui ) {
                if (params && _.isFunction(params.stop)) {
                    return params.stop.call(el, event);
                }
            }
        });
    };

    var _destroyDraggable = function (el) {
        if (_isDraggable(el)) {
            el.draggable("destroy");
        }
    };

    var _enableDraggable = function (el, enabled) {
        var enabledStr = enabled ? 'enable' : 'disable';

        if (_isDraggable(el)) {
            el.draggable(enabledStr);
        }
    };

    var _isDraggable = function (el) {
        return el.hasClass('ui-draggable');
    };

    var _createDragInfo = function (el, params, event) {
        var dragInfo = {};

        dragInfo[DragConstants.DRAG_ITEMS] = [];
        if (params && _.isFunction(params.dragItems)) {
            dragInfo[DragConstants.DRAG_ITEMS] = params.dragItems(el) || [];
        }

        dragInfo[DragConstants.DRAG_EFFECTS] = [];
        if (params && _.isFunction(params.dragEffects)) {
            dragInfo[DragConstants.DRAG_EFFECTS] = params.dragEffects(el) || [];
        }

        dragInfo[DragConstants.DRAG_PARAMS] = undefined;
        if (params && _.isFunction(params.dragParams)) {
            dragInfo[DragConstants.DRAG_PARAMS] = params.dragParams(el, event);
        }

        return dragInfo;
    };

    return {
        DRAG_EFFECTS: DragEffects,
        DEFAULT_CURSOR_AT: {'left': DEFAULT_CURSOR_AT.left,
                            'top': DEFAULT_CURSOR_AT.top},
        makeDraggable: _makeDraggable,
        destroyDraggable: _destroyDraggable,
        enableDraggable: _enableDraggable
    };
});<commit_msg>refactor DragSource: helper UI creator method receives dragInfo and getDragEffects receives event<commit_after>/*
 * Copyright (C) 2013 Vanderbilt University, All rights reserved.
 *
 * Author: Robert Kereskenyi
 */

"use strict";

define(['./DragEffects',
        './DragConstants'], function (DragEffects, DragConstants) {

    var DEFAULT_Z_INDEX = 100000,
        DEFAULT_APPEND_TO = $('body'),
        DEFAULT_CURSOR_AT = { left: 10, top: 10 };

    var _makeDraggable = function (el, params) {
        el.draggable({
            zIndex: DEFAULT_Z_INDEX,
            appendTo: DEFAULT_APPEND_TO,
            cursorAt: DEFAULT_CURSOR_AT,
            helper: function (event) {
                var helperEl,
                    dragInfo = _createDragInfo(el, params, event);

                if (params && _.isFunction(params.helper)) {
                    helperEl = params.helper.call(el, event, dragInfo);
                } else {
                    helperEl = el.clone();
                }

                //prevent dragged helper to catch any pointer events
                helperEl.css({'pointer-events':'none'});

                //add DRAG info
                helperEl.data(DragConstants.DRAG_INFO, dragInfo);

                return helperEl;
            },
            start: function( event, ui ) {
                if (params && _.isFunction(params.start)) {
                    return params.start.call(el, event);
                }
            },
            drag: function( event, ui ) {
                if (params && _.isFunction(params.drag)) {
                    return params.drag.call(el, event);
                }
            },
            stop: function( event, ui ) {
                if (params && _.isFunction(params.stop)) {
                    return params.stop.call(el, event);
                }
            }
        });
    };

    var _destroyDraggable = function (el) {
        if (_isDraggable(el)) {
            el.draggable("destroy");
        }
    };

    var _enableDraggable = function (el, enabled) {
        var enabledStr = enabled ? 'enable' : 'disable';

        if (_isDraggable(el)) {
            el.draggable(enabledStr);
        }
    };

    var _isDraggable = function (el) {
        return el.hasClass('ui-draggable');
    };

    var _createDragInfo = function (el, params, event) {
        var dragInfo = {};

        dragInfo[DragConstants.DRAG_ITEMS] = [];
        if (params && _.isFunction(params.dragItems)) {
            dragInfo[DragConstants.DRAG_ITEMS] = params.dragItems(el) || [];
        }

        dragInfo[DragConstants.DRAG_EFFECTS] = [];
        if (params && _.isFunction(params.dragEffects)) {
            dragInfo[DragConstants.DRAG_EFFECTS] = params.dragEffects(el, event) || [];
        }

        dragInfo[DragConstants.DRAG_PARAMS] = undefined;
        if (params && _.isFunction(params.dragParams)) {
            dragInfo[DragConstants.DRAG_PARAMS] = params.dragParams(el, event);
        }

        return dragInfo;
    };

    return {
        DRAG_EFFECTS: DragEffects,
        DEFAULT_CURSOR_AT: {'left': DEFAULT_CURSOR_AT.left,
                            'top': DEFAULT_CURSOR_AT.top},
        makeDraggable: _makeDraggable,
        destroyDraggable: _destroyDraggable,
        enableDraggable: _enableDraggable
    };
});<|endoftext|>


<commit_before>import { createAction } from 'redux-actions';
import { uniq } from 'lodash';

import { hideModal } from './activeModal';
import { showNotification } from './notification';
import * as api from '../utilities/api';

/* Fetched all collections */
export const fetchCollectionsSuccess = createAction('FETCH_COLLECTIONS_SUCCESS');

/* Create a new Collection */
export const createCollectionRequest = createAction('CREATE_COLLECTION_REQUEST');
export const createCollectionSuccess = createAction('CREATE_COLLECTION_SUCCESS');
export const createCollectionFailure = createAction('CREATE_COLLECTION_FAILURE');

/* Edit an existing collection */
export const editCollectionRequest = createAction('EDIT_COLLECTION_REQUEST');
export const editCollectionFailure = createAction('EDIT_COLLECTION_FAILURE');
export const editCollectionSuccess = createAction('EDIT_COLLECTION_SUCCESS');

export function editCollection(collection) {
  const id = collection.id;

  return (dispatch) => {
    dispatch(editCollectionRequest);
    api.put(`/api/collections/${id}`, collection)
      .then(({ body }) => dispatch(editCollectionSuccess(body)))
      .catch((error) => {
        dispatch(showNotification('error', 'Failed to edit collection.'));
        dispatch(editCollectionFailure(error));
      });
  };
}

/* Create a new collection. Optionally include entities to put in the new collection */
export function createCollection(title, optionalEntities) {
  return (dispatch) => {
    // dispatch(createCollectionRequest(title));
    api.post('/api/collections', { title })
      .then(({ body }) => {
        const collection = body;
        dispatch(createCollectionSuccess(collection));
        if (optionalEntities) {
          const collectionWithEntities = { id: collection.id, ...optionalEntities };
          dispatch(editCollection(collectionWithEntities));
        }
        dispatch(hideModal());
      })
      .catch((error) => {
        dispatch(showNotification('error', 'Failed to create collection.'));
        dispatch(createCollectionFailure(error));
      });
  };
}

/* Delete collection actions */
export const deleteCollectionRequest = createAction('DELETE_COLLECTION_REQUEST');
export const deleteCollectionFailure = createAction('DELETE_COLLECTION_FAILURE');
export const deleteCollectionSuccess = createAction('DELETE_COLLECTION_SUCCESS');

export function deleteCollection(id) {
  return (dispatch) => {
    dispatch(deleteCollectionRequest);
    api.del(`/api/collections/${id}`)
      .then(() => dispatch(deleteCollectionSuccess(id)))
      .catch((error) => {
        dispatch(showNotification('error', 'Failed to delete collection.'));
        dispatch(deleteCollectionFailure(error));
      });
  };
}

export function addEntitiesToCollection(entityIds, collectionId) {
  return (dispatch, getState) => {
    const collection = getState().library.collections[collectionId];

    console.log(entityIds, collection, "for need purpose")
    const visualisations = uniq([...entityIds.visualisations, ...collection.visualisations]);
    console.log( "i got here finally, where the bug is")
    const dashboards = uniq([...entityIds.dashboards, ...collection.dashboards]);
    const rasters = uniq([...entityIds.rasters, ...collection.rasters]);
    const datasets = uniq([...entityIds.datasets, ...collection.datasets]);
    const entities = { visualisations, dashboards, rasters, datasets };
    const newCollection = { ...collection, ...entities };

    dispatch(editCollection(newCollection));

    dispatch(showNotification('info', `Added to ${collection.title}`, true));
  };
}
export function addEntityToCollection(entityId, collectionId) {
  return (dispatch, getState) => {
      const collection = getState().library.collections[collectionId];
      collection.datasets.push(entityId)
      dispatch(editCollection(collection));
      dispatch(showNotification('info', `Added to ${collection.title}`, true));
  };
}

export function removeEntitiesFromCollection(entityIds, collectionId) {
  return (dispatch, getState) => {
    const c = getState().library.collections[collectionId];
    const dicts = { visualisations: new Set(entityIds.visualisations),
      dashboards: new Set(entityIds.dashboards),
      rasters: new Set(entityIds.rasters),
      datasets: new Set(entityIds.datasets) };
    const visualisations = c.visualisations.filter(o => dicts.visualisations.has(o) === false);
    const dashboards = c.dashboards.filter(o => dicts.dashboards.has(o) === false);
    const rasters = c.rasters.filter(o => dicts.rasters.has(o) === false);
    const datasets = c.datasets.filter(o => dicts.datasets.has(o) === false);
    const entities = { visualisations, dashboards, rasters, datasets };
    const newCollection = { ...c, ...entities };
    dispatch(editCollection(newCollection));
    dispatch(showNotification('info', `Removed from ${c.title}`, true));
  };
}

export function addTemporaryEntitiesToCollection(entityIds, collectionId) {
  return (dispatch, getState) => {
    const collection = getState().library.collections[collectionId];

    // Convenience conversion so that "entityIds" can be a naked single ID
    const newEntities = Array.isArray(entityIds) ? entityIds : [entityIds];
    const oldEntities = collection.entities || [];

    const updatedEntityArray = oldEntities.slice(0);

    // Add any new entities that are not already in the collection
    newEntities.forEach((newEntity) => {
      if (oldEntities.every(oldEntity => oldEntity !== newEntity)) {
        updatedEntityArray.push(newEntity);
      }
    });

    const newCollection = { ...collection, entities: updatedEntityArray };
    dispatch(editCollectionSuccess(newCollection));
  };
}

export function removeTemporaryEntitiesFromCollection(entityIds, collectionId) {
  return (dispatch, getState) => {
    const collection = getState().library.collections[collectionId];

    if (!collection) return;

    const newCollection = { ...collection };

    if (Array.isArray(entityIds)) {
      entityIds.forEach((entityId) => {
        newCollection.entities = newCollection.entities.filter(id => id !== entityId);
      });
    } else {
      newCollection.entities = newCollection.entities.filter(id => id !== entityIds);
    }

    dispatch(editCollectionSuccess(newCollection));
  };
}
<commit_msg>removed logs<commit_after>import { createAction } from 'redux-actions';
import { uniq } from 'lodash';

import { hideModal } from './activeModal';
import { showNotification } from './notification';
import * as api from '../utilities/api';

/* Fetched all collections */
export const fetchCollectionsSuccess = createAction('FETCH_COLLECTIONS_SUCCESS');

/* Create a new Collection */
export const createCollectionRequest = createAction('CREATE_COLLECTION_REQUEST');
export const createCollectionSuccess = createAction('CREATE_COLLECTION_SUCCESS');
export const createCollectionFailure = createAction('CREATE_COLLECTION_FAILURE');

/* Edit an existing collection */
export const editCollectionRequest = createAction('EDIT_COLLECTION_REQUEST');
export const editCollectionFailure = createAction('EDIT_COLLECTION_FAILURE');
export const editCollectionSuccess = createAction('EDIT_COLLECTION_SUCCESS');

export function editCollection(collection) {
  const id = collection.id;

  return (dispatch) => {
    dispatch(editCollectionRequest);
    api.put(`/api/collections/${id}`, collection)
      .then(({ body }) => dispatch(editCollectionSuccess(body)))
      .catch((error) => {
        dispatch(showNotification('error', 'Failed to edit collection.'));
        dispatch(editCollectionFailure(error));
      });
  };
}

/* Create a new collection. Optionally include entities to put in the new collection */
export function createCollection(title, optionalEntities) {
  return (dispatch) => {
    // dispatch(createCollectionRequest(title));
    api.post('/api/collections', { title })
      .then(({ body }) => {
        const collection = body;
        dispatch(createCollectionSuccess(collection));
        if (optionalEntities) {
          const collectionWithEntities = { id: collection.id, ...optionalEntities };
          dispatch(editCollection(collectionWithEntities));
        }
        dispatch(hideModal());
      })
      .catch((error) => {
        dispatch(showNotification('error', 'Failed to create collection.'));
        dispatch(createCollectionFailure(error));
      });
  };
}

/* Delete collection actions */
export const deleteCollectionRequest = createAction('DELETE_COLLECTION_REQUEST');
export const deleteCollectionFailure = createAction('DELETE_COLLECTION_FAILURE');
export const deleteCollectionSuccess = createAction('DELETE_COLLECTION_SUCCESS');

export function deleteCollection(id) {
  return (dispatch) => {
    dispatch(deleteCollectionRequest);
    api.del(`/api/collections/${id}`)
      .then(() => dispatch(deleteCollectionSuccess(id)))
      .catch((error) => {
        dispatch(showNotification('error', 'Failed to delete collection.'));
        dispatch(deleteCollectionFailure(error));
      });
  };
}

export function addEntitiesToCollection(entityIds, collectionId) {
  return (dispatch, getState) => {
    const collection = getState().library.collections[collectionId];
    const visualisations = uniq([...entityIds.visualisations, ...collection.visualisations]);
    const dashboards = uniq([...entityIds.dashboards, ...collection.dashboards]);
    const rasters = uniq([...entityIds.rasters, ...collection.rasters]);
    const datasets = uniq([...entityIds.datasets, ...collection.datasets]);
    const entities = { visualisations, dashboards, rasters, datasets };
    const newCollection = { ...collection, ...entities };

    dispatch(editCollection(newCollection));

    dispatch(showNotification('info', `Added to ${collection.title}`, true));
  };
}
export function addEntityToCollection(entityId, collectionId) {
  return (dispatch, getState) => {
      const collection = getState().library.collections[collectionId];
      collection.datasets.push(entityId)
      dispatch(editCollection(collection));
      dispatch(showNotification('info', `Added to ${collection.title}`, true));
  };
}

export function removeEntitiesFromCollection(entityIds, collectionId) {
  return (dispatch, getState) => {
    const c = getState().library.collections[collectionId];
    const dicts = { visualisations: new Set(entityIds.visualisations),
      dashboards: new Set(entityIds.dashboards),
      rasters: new Set(entityIds.rasters),
      datasets: new Set(entityIds.datasets) };
    const visualisations = c.visualisations.filter(o => dicts.visualisations.has(o) === false);
    const dashboards = c.dashboards.filter(o => dicts.dashboards.has(o) === false);
    const rasters = c.rasters.filter(o => dicts.rasters.has(o) === false);
    const datasets = c.datasets.filter(o => dicts.datasets.has(o) === false);
    const entities = { visualisations, dashboards, rasters, datasets };
    const newCollection = { ...c, ...entities };
    dispatch(editCollection(newCollection));
    dispatch(showNotification('info', `Removed from ${c.title}`, true));
  };
}

export function addTemporaryEntitiesToCollection(entityIds, collectionId) {
  return (dispatch, getState) => {
    const collection = getState().library.collections[collectionId];

    // Convenience conversion so that "entityIds" can be a naked single ID
    const newEntities = Array.isArray(entityIds) ? entityIds : [entityIds];
    const oldEntities = collection.entities || [];

    const updatedEntityArray = oldEntities.slice(0);

    // Add any new entities that are not already in the collection
    newEntities.forEach((newEntity) => {
      if (oldEntities.every(oldEntity => oldEntity !== newEntity)) {
        updatedEntityArray.push(newEntity);
      }
    });

    const newCollection = { ...collection, entities: updatedEntityArray };
    dispatch(editCollectionSuccess(newCollection));
  };
}

export function removeTemporaryEntitiesFromCollection(entityIds, collectionId) {
  return (dispatch, getState) => {
    const collection = getState().library.collections[collectionId];

    if (!collection) return;

    const newCollection = { ...collection };

    if (Array.isArray(entityIds)) {
      entityIds.forEach((entityId) => {
        newCollection.entities = newCollection.entities.filter(id => id !== entityId);
      });
    } else {
      newCollection.entities = newCollection.entities.filter(id => id !== entityIds);
    }

    dispatch(editCollectionSuccess(newCollection));
  };
}
<|endoftext|>


<commit_before>/**
 * Created with PyCharm.
 * User: fady
 * Date: 5/17/14
 * Time: 3:31 PM
 * To change this template use File | Settings | File Templates.
 */
<commit_msg>Setup a domain helper on the postItem<commit_after>Template.postItem.helpers({ domain: function () {
    var a = document.createElement('a');
    a.href = this.url;
    return a.hostname;
} });<|endoftext|>


<commit_before>'use strict';

// Add admins to EVENT Collectives and add Free Ticket Owners to the Members table
// We add all admins of the parent collective of an event as admins of the event
// We add all people who ordered a free ticket as ATTENDEE in the Members table

const Promise = require('bluebird');
const _ = require('lodash');

const DRY_RUN = false;
const membersCreated = [];
let eventsProcessed = 0;

const insert = (sequelize, table, entry) => {
  if (DRY_RUN) {
    console.log(">>> insert into ", table, JSON.stringify(entry));
    return Promise.resolve();
  }
  else {
    return sequelize.query(`
      INSERT INTO "${table}" ("${Object.keys(entry).join('","')}") VALUES (:${Object.keys(entry).join(",:")})
    `, { replacements: entry });
  }
}

const processEvents = (sequelize) => {

  const processOrder = (order) => {
    const member = {
      CreatedByUserId: order.CreatedByUserId,
      CollectiveId: order.CollectiveId,
      MemberCollectiveId: order.FromCollectiveId,
      TierId: order.TierId,
      role: 'ATTENDEE'
    };
    membersCreated.push(member);
    return insert(sequelize, "Members", member);
  }

  const processEvent = (event) => {

    eventsProcessed++;

    return sequelize.query(`SELECT "CreatedByUserId", "MemberCollectiveId" FROM "Members" WHERE role='ADMIN' AND "CollectiveId"=${event.ParentCollectiveId}`, { type: sequelize.QueryTypes.SELECT })
      .map(admin => insert(sequelize, "Members", {
        CreatedByUserId: admin.CreatedByUserId,
        CollectiveId: event.id,
        MemberCollectiveId: admin.MemberCollectiveId,
        role: 'ADMIN'
      }))
      .then(() => sequelize.query(`SELECT * FROM "Orders" WHERE "CollectiveId"=${event.id} AND ("totalAmount" IS NULL OR "totalAmount"=0)`, { type: sequelize.QueryTypes.SELECT }))
      .map(processOrder);
  }

  return sequelize.query(`SELECT * FROM "Collectives" WHERE type='EVENT' AND "deletedAt" IS NULL`, { type: sequelize.QueryTypes.SELECT })
    .map(processEvent);
}

module.exports = {
  up: (queryInterface, DataTypes) => {
      // now process each org and make sure Members table is correct
      return processEvents(queryInterface.sequelize)
      .then(() => {
        console.log('>>> ', eventsProcessed, "events processed, ", membersCreated.length, 'membersCreated');
        if (DRY_RUN) {
          throw new Error('failing to rerun migration');
        }
      })

  },

  down: (queryInterface, Sequelize) => {
  }
};
<commit_msg>add Member.createdAt<commit_after>'use strict';

// Add admins to EVENT Collectives and add Free Ticket Owners to the Members table
// We add all admins of the parent collective of an event as admins of the event
// We add all people who ordered a free ticket as ATTENDEE in the Members table

const Promise = require('bluebird');
const _ = require('lodash');

const DRY_RUN = false;
const membersCreated = [];
let eventsProcessed = 0;

const insert = (sequelize, table, entry) => {
  entry.createdAt = new Date;
  if (DRY_RUN) {
    console.log(">>> insert into ", table, JSON.stringify(entry));
    return Promise.resolve();
  }
  else {
    return sequelize.query(`
      INSERT INTO "${table}" ("${Object.keys(entry).join('","')}") VALUES (:${Object.keys(entry).join(",:")})
    `, { replacements: entry });
  }
}

const processEvents = (sequelize) => {

  const processOrder = (order) => {
    const member = {
      CreatedByUserId: order.CreatedByUserId,
      CollectiveId: order.CollectiveId,
      MemberCollectiveId: order.FromCollectiveId,
      TierId: order.TierId,
      role: 'ATTENDEE'
    };
    membersCreated.push(member);
    return insert(sequelize, "Members", member);
  }

  const processEvent = (event) => {

    eventsProcessed++;

    return sequelize.query(`SELECT "CreatedByUserId", "MemberCollectiveId" FROM "Members" WHERE role='ADMIN' AND "CollectiveId"=${event.ParentCollectiveId}`, { type: sequelize.QueryTypes.SELECT })
      .map(admin => insert(sequelize, "Members", {
        CreatedByUserId: admin.CreatedByUserId,
        CollectiveId: event.id,
        MemberCollectiveId: admin.MemberCollectiveId,
        role: 'ADMIN'
      }))
      .then(() => sequelize.query(`SELECT * FROM "Orders" WHERE "CollectiveId"=${event.id} AND ("totalAmount" IS NULL OR "totalAmount"=0)`, { type: sequelize.QueryTypes.SELECT }))
      .map(processOrder);
  }

  return sequelize.query(`SELECT * FROM "Collectives" WHERE type='EVENT' AND "deletedAt" IS NULL`, { type: sequelize.QueryTypes.SELECT })
    .map(processEvent);
}

module.exports = {
  up: (queryInterface, DataTypes) => {
      // now process each org and make sure Members table is correct
      return processEvents(queryInterface.sequelize)
      .then(() => {
        console.log('>>> ', eventsProcessed, "events processed, ", membersCreated.length, 'membersCreated');
        if (DRY_RUN) {
          throw new Error('failing to rerun migration');
        }
      })

  },

  down: (queryInterface, Sequelize) => {
  }
};
<|endoftext|>


<commit_before>/**
 * Service Widgets
 */

;(function(){
	$.widget('ui.serviceconfig', {
		/*
		 * service info member variable
		 */
		_service: null,

		/*
		 *
		 */
		_controlContainer: null,

		/**
		 * built in widget initialization method
		 */
		_init: function(){
			this.element.html("");
			this._controlContainer =  $.fn.create("fieldset");
			this.element.append(
				$.fn.create("span").addClass("dc-message")
			).append(
				$.fn.create("form").append(
					$.fn.create("div").addClass("form-fields").append(
							this._controlContainer
					)
				)
			);
		},

		_destroy: function(){
			$(".dc-message", this.element).html("");

		},
		options: {},

		/*
		 * returns a form control appropriate to the user config object.
		 *
		 */
		_createControl: function(/* userConfig object */uc, /*string*/namespacePrefix){
			var inputType = uc.inputType;
			var i;

			var controlId = namespacePrefix + "." + uc.name;

			if(inputType == "TEXT"){
				return $.fn.create("input")
						   .attr("type", "text")
						   .attr("name", controlId)
						   .attr("id",controlId)
						   .val(uc.value != undefined && uc.value != null ? uc.value : '');
			}else if(inputType == "SINGLESELECT"){
				var select =  $.fn.create("select")
								  .attr("name", controlId)
								  .attr("id", controlId);

				for(i = 0; i < uc.options.length; i++){
					var o = uc.options[i];
					var option = $.fn.create("option")
									 .attr("value", o.value)
									 .html(o.displayName);
					if(o.selected){
						option.attr("selected", "true");
					}
					select.append(option);
				}

				return select;

			}else if(inputType == "MULTISELECT"){
				var select =  $.fn.create("ul");
				for(i = 0; i < uc.options.length; i++){
					var o = uc.options[i];
					var li = $.fn.create("li");
					var id = o.id + "-" + i;
					var option = $.fn.create("input")
									.attr("name", controlId+"-"+checkbox+"-"+i)
									.attr("type","checkbox")
									.attr("value", o.value);
					if(o.selected){
						option.attr("checked", "true");
					}

					li.append(option).append("label")
										.attr("for", id)
										.html(o.displayName);
					select.append(li);
				}

				return select;

			}else{
				throw Error("input type [" + inputType + "] not recognized");
			}
		},

		_createListItem: function(fieldId, displayName){
			var li = $.fn.create("li").attr("id", "li-"+fieldId).addClass("row clearfix");

			li.append(
					$.fn.create("label").attr("for", fieldId).html(displayName)
			);

			return li;
		},

		data: function(){
			var result =  { service: this._service};
			if(this._deployment != undefined){
				result.deployment = this._deployment;
			}
			return result;
		},

		/**
		 * Returns serialized string of currently visible form values
		 */
		serializedFormValues: function(){
			return $(this.element).find("form").serialize();
		},

		_addUserConfig: function(userConfig, controlList, namespacePrefix){
			var control = this._createControl(userConfig,namespacePrefix);
			var item = this._createListItem(userConfig.name, userConfig.displayName);
			item.append(control);
			controlList.append(item);
		},

		_addMode: function(mode, controlList,namespacePrefix){
			var prefix = namespacePrefix +"."+mode.name;
			if(mode.userConfigs != undefined){
				for(j = 0; j < mode.userConfigs.length; j++){
					this._addUserConfig(mode.userConfigs[j], controlList,prefix);
				}
			}

			if(mode.userConfigModeSets != undefined){
				for(j = 0; j < mode.userConfigModeSets.length; j++){
					this._addModeSet(mode.userConfigModeSets[j], controlList,prefix);
				}
			}
		},

		_addModeSet: function(modeSet, controlList, /*optional - top level namespaces have no prefix*/ namespacePrefix){
			var modes = modeSet.modes;
			var prefix = (namespacePrefix == null || namespacePrefix == undefined)?
							modeSet.name: namespacePrefix +"."+modeSet.name;

			//if only a single mode, just add to the control list
			if(modes.length == 1){
				this._addMode(modes[0], controlList, prefix);
				return;
			}

			var i,j, mode,modeSetId,modeSetSelect;
			modeSetId = controlList.attr("id") + "-modeset-" + modeSet.id + "-"+ modeSet.name;
			modeSetSelect = $.fn.create("select").attr("id", modeSetId).attr("name", prefix);

			//for multiple modes
			//first create a mode selection box
			for(i = 0; i < modes.length; i++){
				mode = modeSet.modes[i];
				modeSetSelect.append($.fn.create("option")
										 .attr("value",mode.name)
										 .attr("selected", mode.selected ? "selected" : "")
										 .html(mode.displayName));
			}

			//create a list item that will contain the mode panels (ie html uls)
			var modeSetItem = this._createListItem(modeSetId, modeSet.displayName);
			var modeSetItemId = modeSetItem.attr("id");
			modeSetItem.addClass("dc-exclusion-group");
			modeSetItem.append(modeSetSelect);
			controlList.append(modeSetItem);

			//build and add mode panels
			for(i = 0; i < modes.length; i++){
				mode = modes[i];
				// for each mode, create a list and add all the children to it.
				var modeDiv, modeList, modeListId;
				modeListId = modeSetId+"-"+mode.name;
				modeList = $.fn.create("ul")
							   .attr("id", modeListId);

				modeDiv = $.fn.create("div").attr("id", "div-"+modeListId);
				modeDiv.append(modeList);
				modeSetItem.append(modeDiv);
				this._addMode(mode,modeList,prefix);
			}

			// attach a change listener to the modeSet select control
			// hide all but the selected list.

			var toggleVisibleMode = function(){
				$("#"+ modeSetItemId +" > div").hide();
				var modeName = modeSetSelect.val();
				$("#"+ modeSetItemId +" > div#div-" + modeSetId + "-" + modeName).show();
			};

			modeSetSelect.change(function(evt){
				toggleVisibleMode();
			});

			toggleVisibleMode();
		},

		/**
		 * loads the widget
		 */
		load: function(service, /*optional*/deployment){
			var that = this;

			var i;

			if(service == undefined){
				return this._service;
			}

			this._service = service;

			dc.debug("loading service: " + service.id);
			var modeSets = service.userConfigModeSets;
			if(deployment != undefined){
				this._deployment = deployment;
				dc.debug("loading deployment: " + deployment.id);
				modeSets = deployment.userConfigModeSets;
			}

			this._controlContainer.html("");
			this._controlContainer.append(
				$.fn.create("input").attr("type", "hidden")
									.attr("id", "serviceid-" + service.id)
									.attr("name", "serviceId")
									.val(service.id)
			);

			var list = $.fn.create("ul").addClass("dc-user-config");
			this._controlContainer.append(list);

			if(deployment != undefined){
				this._controlContainer.append(
						$.fn.create("input").attr("type", "hidden")
						.attr("id", "deploymentid-" + deployment.id)
						.attr("name", "deploymentId")
						.val(deployment.id)
				);
			}else{
				var dOptions = service.deploymentOptions;
				var locationSelect = $.fn.create("select").attr("name","deploymentOption");
				for(i = 0; i < dOptions.length;i++){
					var o = dOptions[i];
					locationSelect.append($.fn.create("option")
												.attr("value", o.hostname + "-" +
																	o.location[0]).html(
																			o.displayName + " - " + o.hostname + " (" + o.location+")"));
				}

				list.append(
					this._createListItem("location", "Location").append(locationSelect)
				);
			}

			for(i = 0; i < modeSets.length;i++){
				this._addModeSet(modeSets[i],list);
			}
		},
	});
})();

<commit_msg>This resolves issue DURACLOUD-302.  Disable location select box when there is only one deployment option.  Decided not to hide the location option because of the services that have no other config options which caused the screen to be blank.<commit_after>/**
 * Service Widgets
 */

;(function(){
	$.widget('ui.serviceconfig', {
		/*
		 * service info member variable
		 */
		_service: null,

		/*
		 *
		 */
		_controlContainer: null,

		/**
		 * built in widget initialization method
		 */
		_init: function(){
			this.element.html("");
			this._controlContainer =  $.fn.create("fieldset");
			this.element.append(
				$.fn.create("span").addClass("dc-message")
			).append(
				$.fn.create("form").append(
					$.fn.create("div").addClass("form-fields").append(
							this._controlContainer
					)
				)
			);
		},

		_destroy: function(){
			$(".dc-message", this.element).html("");

		},
		options: {},

		/*
		 * returns a form control appropriate to the user config object.
		 *
		 */
		_createControl: function(/* userConfig object */uc, /*string*/namespacePrefix){
			var inputType = uc.inputType;
			var i;

			var controlId = namespacePrefix + "." + uc.name;

			if(inputType == "TEXT"){
				return $.fn.create("input")
						   .attr("type", "text")
						   .attr("name", controlId)
						   .attr("id",controlId)
						   .val(uc.value != undefined && uc.value != null ? uc.value : '');
			}else if(inputType == "SINGLESELECT"){
				var select =  $.fn.create("select")
								  .attr("name", controlId)
								  .attr("id", controlId);

				for(i = 0; i < uc.options.length; i++){
					var o = uc.options[i];
					var option = $.fn.create("option")
									 .attr("value", o.value)
									 .html(o.displayName);
					if(o.selected){
						option.attr("selected", "true");
					}
					select.append(option);
				}

				return select;

			}else if(inputType == "MULTISELECT"){
				var select =  $.fn.create("ul");
				for(i = 0; i < uc.options.length; i++){
					var o = uc.options[i];
					var li = $.fn.create("li");
					var id = o.id + "-" + i;
					var option = $.fn.create("input")
									.attr("name", controlId+"-"+checkbox+"-"+i)
									.attr("type","checkbox")
									.attr("value", o.value);
					if(o.selected){
						option.attr("checked", "true");
					}

					li.append(option).append("label")
										.attr("for", id)
										.html(o.displayName);
					select.append(li);
				}

				return select;

			}else{
				throw Error("input type [" + inputType + "] not recognized");
			}
		},

		_createListItem: function(fieldId, displayName){
			var li = $.fn.create("li").attr("id", "li-"+fieldId).addClass("row clearfix");

			li.append(
					$.fn.create("label").attr("for", fieldId).html(displayName)
			);

			return li;
		},

		data: function(){
			var result =  { service: this._service};
			if(this._deployment != undefined){
				result.deployment = this._deployment;
			}
			return result;
		},

		/**
		 * Returns serialized string of currently visible form values
		 */
		serializedFormValues: function(){
			return $(this.element).find("form").serialize();
		},

		_addUserConfig: function(userConfig, controlList, namespacePrefix){
			var control = this._createControl(userConfig,namespacePrefix);
			var item = this._createListItem(userConfig.name, userConfig.displayName);
			item.append(control);
			controlList.append(item);
		},

		_addMode: function(mode, controlList,namespacePrefix){
			var prefix = namespacePrefix +"."+mode.name;
			if(mode.userConfigs != undefined){
				for(j = 0; j < mode.userConfigs.length; j++){
					this._addUserConfig(mode.userConfigs[j], controlList,prefix);
				}
			}

			if(mode.userConfigModeSets != undefined){
				for(j = 0; j < mode.userConfigModeSets.length; j++){
					this._addModeSet(mode.userConfigModeSets[j], controlList,prefix);
				}
			}
		},

		_addModeSet: function(modeSet, controlList, /*optional - top level namespaces have no prefix*/ namespacePrefix){
			var modes = modeSet.modes;
			var prefix = (namespacePrefix == null || namespacePrefix == undefined)?
							modeSet.name: namespacePrefix +"."+modeSet.name;

			//if only a single mode, just add to the control list
			if(modes.length == 1){
				this._addMode(modes[0], controlList, prefix);
				return;
			}

			var i,j, mode,modeSetId,modeSetSelect;
			modeSetId = controlList.attr("id") + "-modeset-" + modeSet.id + "-"+ modeSet.name;
			modeSetSelect = $.fn.create("select").attr("id", modeSetId).attr("name", prefix);

			//for multiple modes
			//first create a mode selection box
			for(i = 0; i < modes.length; i++){
				mode = modeSet.modes[i];
				modeSetSelect.append($.fn.create("option")
										 .attr("value",mode.name)
										 .attr("selected", mode.selected ? "selected" : "")
										 .html(mode.displayName));
			}

			//create a list item that will contain the mode panels (ie html uls)
			var modeSetItem = this._createListItem(modeSetId, modeSet.displayName);
			var modeSetItemId = modeSetItem.attr("id");
			modeSetItem.addClass("dc-exclusion-group");
			modeSetItem.append(modeSetSelect);
			controlList.append(modeSetItem);

			//build and add mode panels
			for(i = 0; i < modes.length; i++){
				mode = modes[i];
				// for each mode, create a list and add all the children to it.
				var modeDiv, modeList, modeListId;
				modeListId = modeSetId+"-"+mode.name;
				modeList = $.fn.create("ul")
							   .attr("id", modeListId);

				modeDiv = $.fn.create("div").attr("id", "div-"+modeListId);
				modeDiv.append(modeList);
				modeSetItem.append(modeDiv);
				this._addMode(mode,modeList,prefix);
			}

			// attach a change listener to the modeSet select control
			// hide all but the selected list.

			var toggleVisibleMode = function(){
				$("#"+ modeSetItemId +" > div").hide();
				var modeName = modeSetSelect.val();
				$("#"+ modeSetItemId +" > div#div-" + modeSetId + "-" + modeName).show();
			};

			modeSetSelect.change(function(evt){
				toggleVisibleMode();
			});

			toggleVisibleMode();
		},

		/**
		 * loads the widget
		 */
		load: function(service, /*optional*/deployment){
			var that = this;

			var i;

			if(service == undefined){
				return this._service;
			}

			this._service = service;

			dc.debug("loading service: " + service.id);
			var modeSets = service.userConfigModeSets;
			if(deployment != undefined){
				this._deployment = deployment;
				dc.debug("loading deployment: " + deployment.id);
				modeSets = deployment.userConfigModeSets;
			}

			this._controlContainer.html("");
			this._controlContainer.append(
				$.fn.create("input").attr("type", "hidden")
									.attr("id", "serviceid-" + service.id)
									.attr("name", "serviceId")
									.val(service.id)
			);

			var list = $.fn.create("ul").addClass("dc-user-config");
			this._controlContainer.append(list);

			if(deployment != undefined){
				this._controlContainer.append(
						$.fn.create("input").attr("type", "hidden")
						.attr("id", "deploymentid-" + deployment.id)
						.attr("name", "deploymentId")
						.val(deployment.id)
				);
			}else{
				var dOptions = service.deploymentOptions;
				var locationSelect = $.fn.create("select").attr("name","deploymentOption");
				for(i = 0; i < dOptions.length;i++){
					var o = dOptions[i];
					locationSelect.append($.fn.create("option")
												.attr("value", o.hostname + "-" +
																	o.location[0]).html(
																			o.displayName + " - " + o.hostname + " (" + o.location+")"));
				}

                if(dOptions.length < 2)
				    locationSelect.attr("disabled", true);

				list.append(
					this._createListItem("location", "Location").append(locationSelect)
				);
			}

			for(i = 0; i < modeSets.length;i++){
				this._addModeSet(modeSets[i],list);
			}
		},
	});
})();

<|endoftext|>


<commit_before>// This module manages the permissions of docs in Apostrophe.
//
// A new permissions model is coming in 3.x. For alpha 1, logged-in users
// can do anything, and the public can only view content.
//
// In 3.0 final, users will be subdivided into guests, contributors,
// editors and admins, in ascending order of privilege. In the final
// 3.0 model, guests can view "login required" pages, but have no other
// special privileges. Contributors can create drafts but cannot publish
// them alone. Editors can edit anything except user accounts, and admins
// can edit anything.

module.exports = {
  options: {
    alias: 'permission',
    interestingTypes: [
      '@apostrophecms/user',
      '@apostrophecms/global',
      '@apostrophecms/image',
      '@apostrophecms/file'
    ]
  },
  init(self) {
    self.permissionPattern = /^([^-]+)-(.*)$/;
    self.addRetirePublishedFieldMigration();
    self.addRoleFieldType();
    self.enableBrowserData();
  },
  methods(self) {
    return {
      // Determines whether the active user can carry out the
      // action specified by `action` on the doc or type name
      // specified by `docOrType`. Returns true if the action
      // is permitted, false if not permitted.
      //
      // If `docOrType` is a doc, this method checks whether the user
      // can carry out the specified action on that particular doc. If it is
      // a string, this method checks whether the user can potentially carry out
      // the action on that doc type generally.
      //
      // If a permission is not specific to particular documents,
      // `docOrType` may be omitted.
      //
      // The doc passed need not already exist in the database.
      //
      // See also `criteria` which can be called to build a MongoDB
      // criteria object returning only documents on which the active user
      // can carry out the specified action.
      //
      // If present, `mode` overrides `req.mode` for purposes
      // of determining permissions. This is useful to decide whether
      // a user should get access to the manage view of articles even
      // though they are technically in published mode on the page.

      can(req, action, docOrType, mode) {
        mode = mode || req.mode;
        const role = req.user && req.user.role;
        if (role === 'admin') {
          return true;
        }
        const type = docOrType && (docOrType.type || docOrType);
        const doc = (docOrType && docOrType._id) ? docOrType : null;
        const manager = type && self.apos.doc.getManager(type);
        if (type && !manager) {
          self.apos.util.warn(`A permission.can() call was made with a type that has no manager: ${type}`);
          return false;
        }
        if (action === 'view') {
          if (manager && manager.isAdminOnly()) {
            return false;
          } else if (((typeof docOrType) === 'object') && (docOrType.visibility !== 'public')) {
            return (role === 'guest') || (role === 'contributor') || (role === 'editor');
          } else {
            return true;
          }
        } else if (action === 'view-draft') {
          // Checked at the middleware level to determine if req.mode should
          // be allowed to be set to draft at all
          return (role === 'contributor') || (role === 'editor');
        } else if (action === 'edit') {
          if (manager && manager.isAdminOnly()) {
            return false;
          } else if (mode === 'draft') {
            return (role === 'contributor') || (role === 'editor');
          } else {
            return role === 'editor';
          }
        } else if (action === 'publish') {
          if (manager && manager.isAdminOnly()) {
            return false;
          } else {
            return role === 'editor';
          }
        } else if (action === 'upload-attachment') {
          if ((role === 'contributor') || (role === 'editor')) {
            return true;
          } else {
            return false;
          }
        } else if (action === 'delete') {
          if (doc && !doc.lastPublishedAt) {
            return self.can(req, 'edit', doc);
          } else {
            return self.can(req, 'publish', doc);
          }
        } else {
          throw self.apos.error('invalid', 'That action is not implemented');
        }
      },

      // Returns a MongoDB criteria object that retrieves only documents
      // the user is allowed to perform `action` on.

      criteria(req, action) {
        const role = req.user && req.user.role;
        if (role === 'admin') {
          return {};
        }
        const restrictedTypes = Object.keys(self.apos.doc.managers).filter(name => self.apos.doc.getManager(name).isAdminOnly());
        if (action === 'view') {
          if (role === 'guest') {
            return {
              aposMode: {
                $in: [ null, 'published' ]
              },
              visibility: {
                $in: [ 'public', 'loginRequired' ]
              },
              type: {
                $nin: restrictedTypes
              }
            };
          } else if ((role === 'contributor') || (role === 'editor')) {
            return {
              type: {
                $nin: restrictedTypes
              }
            };
          } else {
            return {
              aposMode: {
                $in: [ null, 'published' ]
              },
              visibility: 'public',
              type: {
                $nin: restrictedTypes
              }
            };
          }
        } else if (action === 'edit') {
          if (role === 'contributor') {
            return {
              aposMode: {
                $in: [ null, 'draft' ]
              },
              type: {
                $nin: restrictedTypes
              }
            };
          } else if (role === 'editor') {
            return {
              type: {
                $nin: restrictedTypes
              }
            };
          } else {
            return {
              _id: null
            };
          }
        } else if (action === 'publish') {
          if (role === 'editor') {
            return {
              type: {
                $nin: restrictedTypes
              }
            };
          } else {
            return {
              _id: null
            };
          }
        } else {
          throw self.apos.error('invalid', `The action ${action} is not implemented for apos.permission.criteria`);
        }
      },

      // For each object in the array, if the user is able to
      // carry out the specified action, a property is added
      // to the object. For instance, if the action is "edit",
      // each doc the user can edit gets a "._edit = true" property.
      //
      // Note the underscore.
      //
      // This is most often used when an array of objects the user
      // can view have been retrieved and we wish to know which ones
      // the user can also edit.

      annotate(req, action, objects) {
        const property = `_${action}`;
        for (const object of objects) {
          if (self.can(req, action, object)) {
            object[property] = true;
          }
        }
      },
      addRoleFieldType() {
        self.apos.schema.addFieldType({
          name: 'role',
          extend: 'select'
        });
      },
      addRetirePublishedFieldMigration() {
        self.apos.migration.add('retire-published-field', async () => {
          await self.apos.migration.eachDoc({}, 5, async (doc) => {
            if (doc.published === true) {
              doc.visibility = 'public';
            } else if (doc.published === false) {
              doc.visibility = 'loginRequired';
            }
            delete doc.published;
            return self.apos.doc.db.replaceOne({
              _id: doc._id
            }, doc);
          });
        });
      },
      // Returns an object with properties describing the permissions associated
      // with the given module, which should be a piece type or the `@apostrophecms/any-page-type`
      // module. Used to populate the permission grid on the front end
      describePermissionSet(req, module, options = {}) {
        const permissionSet = {
          label: module.options.permissionsLabel || module.options.pluralLabel || module.options.label,
          name: module.__meta.name,
          adminOnly: module.options.adminOnly,
          singleton: module.options.singleton,
          page: module.__meta.name === '@apostrophecms/any-page-type',
          ...options
        };
        const permissions = [];
        if (!module.options.singleton) {
          permissions.push({
            name: 'create',
            label: 'Create',
            value: self.can(req, 'edit', module.name)
          });
        }
        permissions.push({
          name: 'edit',
          label: module.options.singleton ? 'Modify' : 'Modify / Delete',
          value: self.can(req, 'edit', module.name)
        });
        permissions.push({
          name: 'publish',
          label: 'Publish',
          value: self.can(req, 'publish', module.name)
        });
        permissionSet.permissions = permissions;
        return permissionSet;
      },
      // Receives the types for the permission grid (see the grid route) and
      // reduces the set to those considered interesting and those that
      // do not match the typical permissions, in an intuitive order
      presentPermissionSets(permissionSets) {
        let newPermissionSets = permissionSets.filter(permissionSet => self.options.interestingTypes.includes(permissionSet.name));
        newPermissionSets = [
          ...newPermissionSets,
          permissionSets.filter(permissionSet => !newPermissionSets.includes(permissionSet) && !self.matchTypicalPieceType(permissionSet)),
          permissionSets.find(permissionSet => permissionSet.page)
        ];
        const typicalPieceType = permissionSets.find(self.matchTypicalPieceType);
        if (typicalPieceType) {
          newPermissionSets.push({
            ...typicalPieceType,
            name: '@apostrophecms/piece-type',
            label: 'Piece Content',
            tooltip: permissionSets.filter(permissionSet => self.matchTypicalPieceType(permissionSet) && !newPermissionSets.includes(permissionSet)).map(permissionSet => permissionSet.label).join(', ')
          });
        }
        return newPermissionSets;
      },
      matchTypicalPieceType(permissionSet) {
        return permissionSet.piece && !permissionSet.adminOnly && !self.options.interestingTypes.includes(permissionSet.name);
      }
    };
  },
  apiRoutes(self) {
    return {
      get: {
        async grid(req) {
          if (!self.apos.permission.can(req, 'edit', '@apostrophecms/user')) {
            throw self.apos.error('forbidden');
          }
          const permissionSets = [];
          const effectiveRole = self.apos.launder.select(req.query.role, [ 'guest', 'contributor', 'editor', 'admin' ]);
          if (!effectiveRole) {
            throw self.apos.error('invalid', { role: effectiveRole });
          }
          const _req = self.apos.task.getReq({
            role: effectiveRole,
            mode: 'draft'
          });
          for (const module of Object.values(self.apos.modules)) {
            if (self.apos.synth.instanceOf(module, '@apostrophecms/piece-type')) {
              permissionSets.push(self.describePermissionSet(_req, module, { piece: true }));
            }
          }
          permissionSets.push(self.describePermissionSet(_req, self.apos.modules['@apostrophecms/any-page-type']));
          return {
            permissionSets: self.presentPermissionSets(permissionSets)
          };
        }
      }
    };
  },
  extendMethods(self) {
    return {
      getBrowserData(_super, req) {
        const initialBrowserOptions = _super(req);
        const browserOptions = {
          ...initialBrowserOptions,
          action: self.action
        };
        return browserOptions;
      }
    };
  }
};
<commit_msg>archive and modify are separate permissions in the permissions list displayed when setting a role;<commit_after>// This module manages the permissions of docs in Apostrophe.
//
// A new permissions model is coming in 3.x. For alpha 1, logged-in users
// can do anything, and the public can only view content.
//
// In 3.0 final, users will be subdivided into guests, contributors,
// editors and admins, in ascending order of privilege. In the final
// 3.0 model, guests can view "login required" pages, but have no other
// special privileges. Contributors can create drafts but cannot publish
// them alone. Editors can edit anything except user accounts, and admins
// can edit anything.

module.exports = {
  options: {
    alias: 'permission',
    interestingTypes: [
      '@apostrophecms/user',
      '@apostrophecms/global',
      '@apostrophecms/image',
      '@apostrophecms/file'
    ]
  },
  init(self) {
    self.permissionPattern = /^([^-]+)-(.*)$/;
    self.addRetirePublishedFieldMigration();
    self.addRoleFieldType();
    self.enableBrowserData();
  },
  methods(self) {
    return {
      // Determines whether the active user can carry out the
      // action specified by `action` on the doc or type name
      // specified by `docOrType`. Returns true if the action
      // is permitted, false if not permitted.
      //
      // If `docOrType` is a doc, this method checks whether the user
      // can carry out the specified action on that particular doc. If it is
      // a string, this method checks whether the user can potentially carry out
      // the action on that doc type generally.
      //
      // If a permission is not specific to particular documents,
      // `docOrType` may be omitted.
      //
      // The doc passed need not already exist in the database.
      //
      // See also `criteria` which can be called to build a MongoDB
      // criteria object returning only documents on which the active user
      // can carry out the specified action.
      //
      // If present, `mode` overrides `req.mode` for purposes
      // of determining permissions. This is useful to decide whether
      // a user should get access to the manage view of articles even
      // though they are technically in published mode on the page.

      can(req, action, docOrType, mode) {
        mode = mode || req.mode;
        const role = req.user && req.user.role;
        if (role === 'admin') {
          return true;
        }
        const type = docOrType && (docOrType.type || docOrType);
        const doc = (docOrType && docOrType._id) ? docOrType : null;
        const manager = type && self.apos.doc.getManager(type);
        if (type && !manager) {
          self.apos.util.warn(`A permission.can() call was made with a type that has no manager: ${type}`);
          return false;
        }
        if (action === 'view') {
          if (manager && manager.isAdminOnly()) {
            return false;
          } else if (((typeof docOrType) === 'object') && (docOrType.visibility !== 'public')) {
            return (role === 'guest') || (role === 'contributor') || (role === 'editor');
          } else {
            return true;
          }
        } else if (action === 'view-draft') {
          // Checked at the middleware level to determine if req.mode should
          // be allowed to be set to draft at all
          return (role === 'contributor') || (role === 'editor');
        } else if (action === 'edit') {
          if (manager && manager.isAdminOnly()) {
            return false;
          } else if (mode === 'draft') {
            return (role === 'contributor') || (role === 'editor');
          } else {
            return role === 'editor';
          }
        } else if (action === 'publish') {
          if (manager && manager.isAdminOnly()) {
            return false;
          } else {
            return role === 'editor';
          }
        } else if (action === 'upload-attachment') {
          if ((role === 'contributor') || (role === 'editor')) {
            return true;
          } else {
            return false;
          }
        } else if (action === 'delete') {
          if (doc && !doc.lastPublishedAt) {
            return self.can(req, 'edit', doc);
          } else {
            return self.can(req, 'publish', doc);
          }
        } else {
          throw self.apos.error('invalid', 'That action is not implemented');
        }
      },

      // Returns a MongoDB criteria object that retrieves only documents
      // the user is allowed to perform `action` on.

      criteria(req, action) {
        const role = req.user && req.user.role;
        if (role === 'admin') {
          return {};
        }
        const restrictedTypes = Object.keys(self.apos.doc.managers).filter(name => self.apos.doc.getManager(name).isAdminOnly());
        if (action === 'view') {
          if (role === 'guest') {
            return {
              aposMode: {
                $in: [ null, 'published' ]
              },
              visibility: {
                $in: [ 'public', 'loginRequired' ]
              },
              type: {
                $nin: restrictedTypes
              }
            };
          } else if ((role === 'contributor') || (role === 'editor')) {
            return {
              type: {
                $nin: restrictedTypes
              }
            };
          } else {
            return {
              aposMode: {
                $in: [ null, 'published' ]
              },
              visibility: 'public',
              type: {
                $nin: restrictedTypes
              }
            };
          }
        } else if (action === 'edit') {
          if (role === 'contributor') {
            return {
              aposMode: {
                $in: [ null, 'draft' ]
              },
              type: {
                $nin: restrictedTypes
              }
            };
          } else if (role === 'editor') {
            return {
              type: {
                $nin: restrictedTypes
              }
            };
          } else {
            return {
              _id: null
            };
          }
        } else if (action === 'publish') {
          if (role === 'editor') {
            return {
              type: {
                $nin: restrictedTypes
              }
            };
          } else {
            return {
              _id: null
            };
          }
        } else {
          throw self.apos.error('invalid', `The action ${action} is not implemented for apos.permission.criteria`);
        }
      },

      // For each object in the array, if the user is able to
      // carry out the specified action, a property is added
      // to the object. For instance, if the action is "edit",
      // each doc the user can edit gets a "._edit = true" property.
      //
      // Note the underscore.
      //
      // This is most often used when an array of objects the user
      // can view have been retrieved and we wish to know which ones
      // the user can also edit.

      annotate(req, action, objects) {
        const property = `_${action}`;
        for (const object of objects) {
          if (self.can(req, action, object)) {
            object[property] = true;
          }
        }
      },
      addRoleFieldType() {
        self.apos.schema.addFieldType({
          name: 'role',
          extend: 'select'
        });
      },
      addRetirePublishedFieldMigration() {
        self.apos.migration.add('retire-published-field', async () => {
          await self.apos.migration.eachDoc({}, 5, async (doc) => {
            if (doc.published === true) {
              doc.visibility = 'public';
            } else if (doc.published === false) {
              doc.visibility = 'loginRequired';
            }
            delete doc.published;
            return self.apos.doc.db.replaceOne({
              _id: doc._id
            }, doc);
          });
        });
      },
      // Returns an object with properties describing the permissions associated
      // with the given module, which should be a piece type or the `@apostrophecms/any-page-type`
      // module. Used to populate the permission grid on the front end
      describePermissionSet(req, module, options = {}) {
        const permissionSet = {
          label: module.options.permissionsLabel || module.options.pluralLabel || module.options.label,
          name: module.__meta.name,
          adminOnly: module.options.adminOnly,
          singleton: module.options.singleton,
          page: module.__meta.name === '@apostrophecms/any-page-type',
          ...options
        };
        const permissions = [];
        if (!module.options.singleton) {
          permissions.push({
            name: 'create',
            label: 'Create',
            value: self.can(req, 'edit', module.name)
          });
        }
        permissions.push({
          name: 'edit',
          label: 'Modify',
          value: self.can(req, 'edit', module.name)
        });
        permissions.push({
          name: 'archive',
          label: 'Archive / Restore',
          value: self.can(req, 'publish', module.name)
        });
        permissions.push({
          name: 'publish',
          label: 'Publish',
          value: self.can(req, 'publish', module.name)
        });
        permissionSet.permissions = permissions;
        return permissionSet;
      },
      // Receives the types for the permission grid (see the grid route) and
      // reduces the set to those considered interesting and those that
      // do not match the typical permissions, in an intuitive order
      presentPermissionSets(permissionSets) {
        let newPermissionSets = permissionSets.filter(permissionSet => self.options.interestingTypes.includes(permissionSet.name));
        newPermissionSets = [
          ...newPermissionSets,
          permissionSets.filter(permissionSet => !newPermissionSets.includes(permissionSet) && !self.matchTypicalPieceType(permissionSet)),
          permissionSets.find(permissionSet => permissionSet.page)
        ];
        const typicalPieceType = permissionSets.find(self.matchTypicalPieceType);
        if (typicalPieceType) {
          newPermissionSets.push({
            ...typicalPieceType,
            name: '@apostrophecms/piece-type',
            label: 'Piece Content',
            tooltip: permissionSets.filter(permissionSet => self.matchTypicalPieceType(permissionSet) && !newPermissionSets.includes(permissionSet)).map(permissionSet => permissionSet.label).join(', ')
          });
        }
        return newPermissionSets;
      },
      matchTypicalPieceType(permissionSet) {
        return permissionSet.piece && !permissionSet.adminOnly && !self.options.interestingTypes.includes(permissionSet.name);
      }
    };
  },
  apiRoutes(self) {
    return {
      get: {
        async grid(req) {
          if (!self.apos.permission.can(req, 'edit', '@apostrophecms/user')) {
            throw self.apos.error('forbidden');
          }
          const permissionSets = [];
          const effectiveRole = self.apos.launder.select(req.query.role, [ 'guest', 'contributor', 'editor', 'admin' ]);
          if (!effectiveRole) {
            throw self.apos.error('invalid', { role: effectiveRole });
          }
          const _req = self.apos.task.getReq({
            role: effectiveRole,
            mode: 'draft'
          });
          for (const module of Object.values(self.apos.modules)) {
            if (self.apos.synth.instanceOf(module, '@apostrophecms/piece-type')) {
              permissionSets.push(self.describePermissionSet(_req, module, { piece: true }));
            }
          }
          permissionSets.push(self.describePermissionSet(_req, self.apos.modules['@apostrophecms/any-page-type']));
          return {
            permissionSets: self.presentPermissionSets(permissionSets)
          };
        }
      }
    };
  },
  extendMethods(self) {
    return {
      getBrowserData(_super, req) {
        const initialBrowserOptions = _super(req);
        const browserOptions = {
          ...initialBrowserOptions,
          action: self.action
        };
        return browserOptions;
      }
    };
  }
};
<|endoftext|>


<commit_before>'use strict';

var angularMeteorCollections = angular.module('angular-meteor.meteor-collection',
  ['angular-meteor.subscribe', 'angular-meteor.utils', 'diffArray']);

angularMeteorCollections.factory('AngularMeteorCollection', ['$q', '$meteorSubscribe', '$meteorUtils', '$rootScope', '$timeout',
  function($q, $meteorSubscribe, $meteorUtils, $rootScope, $timeout) {

    var AngularMeteorCollection = function (cursor, collection) {
      this.$$collection = angular.isDefined(collection) ? collection : $meteorUtils.getCollectionByName(cursor.collection.name);
    };

    AngularMeteorCollection.prototype = [];

    AngularMeteorCollection.prototype.subscribe = function () {
      $meteorSubscribe.subscribe.apply(this, arguments);
      return this;
    };

    AngularMeteorCollection.prototype.save = function save(docs, useUnsetModifier) {
      var self = this,
        collection = self.$$collection,
        promises = []; // To store all promises.

      /*
       * The upsertObject function will either update an object if the _id exists
       * or insert an object if the _id is not set in the collection.
       * Returns a promise.
       */
      function upsertObject(item, $q) {
        var deferred = $q.defer();

        if (item._id) { // Performs an update if the _id property is set.
          var item_id = item._id; // Store the _id in temporary variable
          delete item._id; // Remove the _id property so that it can be $set using update.
          var objectId = (item_id._str) ? new Meteor.Collection.ObjectID(item_id._str) : item_id;
          var modifier = (useUnsetModifier) ? {$unset: item} : {$set: item};

          collection.update(objectId, modifier, function (error) {
            if (error) {
              deferred.reject(error);
            } else {
              deferred.resolve({_id: objectId, action: "updated"});
            }
          });
        } else { // Performs an insert if the _id property isn't set.
          collection.insert(item, function (error, result) {
            if (error) {
              deferred.reject(error);
            } else {
              deferred.resolve({_id: result, action: "inserted"});
            }
          });
        }

        return deferred.promise;
      }

      /*
       * How to update the collection depending on the 'docs' argument passed.
       */
      if (docs) { // Checks if a 'docs' argument was passed.
        if (angular.isArray(docs)) { // If an array of objects were passed.
          angular.forEach(docs, function (doc) {
            this.push(upsertObject(doc, $q));
          }, promises);
        } else { // If a single object was passed.
          promises.push(upsertObject(docs, $q));
        }
      } else { // If no 'docs' argument was passed, save the entire collection.
        angular.forEach(self, function (doc) {
          this.push(upsertObject(doc, $q));
        }, promises);
      }

      return $q.all(promises); // Returns all promises when they're resolved.
    };

    AngularMeteorCollection.prototype.remove = function remove(keys) {
      var self = this,
        collection = self.$$collection,
        promises = []; // To store all promises.

      /*
       * The removeObject function will delete an object with the _id property
       * equal to the specified key.
       * Returns a promise.
       */
      function removeObject(key, $q) {
        var deferred = $q.defer();

        if (key) { // Checks if 'key' argument is set.
          if (key._id) {
            key = key._id;
          }
          var objectId = (key._str) ? new Meteor.Collection.ObjectID(key._str) : key;

          collection.remove(objectId, function (error) {
            if (error) {
              deferred.reject(error);
            } else {
              deferred.resolve({_id: objectId, action: "removed"});
            }
          });
        } else {
          deferred.reject("key cannot be null");
        }

        return deferred.promise;
      }

      /*
       * What to remove from collection depending on the 'keys' argument passed.
       */
      if (keys) { // Checks if a 'keys' argument was passed.
        if (angular.isArray(keys)) { // If an array of keys were passed.
          angular.forEach(keys, function (key) {
            this.push(removeObject(key, $q));
          }, promises);
        } else { // If a single key was passed.
          promises.push(removeObject(keys, $q));
        }
      } else { // If no 'keys' argument was passed, save the entire collection.
        // When removing all, we do not use collection.remove({}) because Meteor doesn't give the client side that permissions
        // http://stackoverflow.com/a/15465286/1426570
        var originalSelf = angular.copy(self);
        angular.forEach(originalSelf, function (doc) {
          this.push(removeObject(doc._id, $q));
        }, promises);
      }

      return $q.all(promises); // Returns all promises when they're resolved.
    };

    AngularMeteorCollection.prototype.updateCursor = function (cursor) {
      var self = this;

      function safeApply() {
        // Clearing the watch is needed so no updates are sent to server
        // while handling updates from the server
        self.UPDATING_FROM_SERVER = true;
        if (!$rootScope.$$phase) $rootScope.$apply();
        // Making sure we are setting to false only after one digest cycle and not before
        $timeout(function(){
          self.UPDATING_FROM_SERVER = false;
        },0,false);
      }

      // XXX - consider adding an option for a non-orderd result
      // for faster performance
      if (self.observeHandle) {
        self.observeHandle.stop();
      }

      self.observeHandle = cursor.observe({
        addedAt: function (document, atIndex) {
          self.splice(atIndex, 0, document);
          safeApply();
        },
        changedAt: function (document, oldDocument, atIndex) {
          self.splice(atIndex, 1, document);
          safeApply();
        },
        movedTo: function (document, fromIndex, toIndex) {
          self.splice(fromIndex, 1);
          self.splice(toIndex, 0, document);
          safeApply();
        },
        removedAt: function (oldDocument) {
          var removedObject;
          if (oldDocument._id._str){
            removedObject = _.find(self, function(obj) {
              return obj._id._str == oldDocument._id._str;
            });
          }
          else
            removedObject = _.findWhere(self, {_id: oldDocument._id});

          if (removedObject){
            self.splice(self.indexOf(removedObject), 1);
            safeApply();
          }
        }
      });
    };

    AngularMeteorCollection.prototype.stop = function () {
      if (this.unregisterAutoBind)
        this.unregisterAutoBind();

      if (this.observeHandle)
        this.observeHandle.stop();

      while (this.length > 0) {
        this.pop();
      }
    };

    return AngularMeteorCollection;
}]);

angularMeteorCollections.factory('$meteorCollection', ['AngularMeteorCollection', '$rootScope', 'diffArray',
  function (AngularMeteorCollection, $rootScope, diffArray) {
    return function (reactiveFunc, auto, collection) {
      // Validate parameters
      if (!reactiveFunc) {
        throw new TypeError("The first argument of $meteorCollection is undefined.");
      }
      if (!(typeof reactiveFunc == "function" || angular.isFunction(reactiveFunc.find))) {
        throw new TypeError("The first argument of $meteorCollection must be a function or a have a find function property.");
      }
      auto = auto !== false;

      if (!(typeof reactiveFunc == "function")) {
        var cursorFunc = reactiveFunc.find;
        collection = angular.isDefined(collection) ? collection : reactiveFunc;
        var originalCollection = reactiveFunc;
        reactiveFunc = function() {
          return cursorFunc.apply(originalCollection, [{}]);
        }
      }

      var ngCollection = new AngularMeteorCollection(reactiveFunc(), collection);
      var realOldItems;

      function setAutoBind() {
        if (auto) { // Deep watches the model and performs autobind.
          ngCollection.unregisterAutoBind = $rootScope.$watch(function () {
            if (ngCollection.UPDATING_FROM_SERVER){
              realOldItems = _.without(ngCollection, 'UPDATING_FROM_SERVER');
              return 'UPDATING_FROM_SERVER';
            }
            return _.without(ngCollection, 'UPDATING_FROM_SERVER');
          }, function (newItems, oldItems) {
            if (newItems == 'UPDATING_FROM_SERVER')
              return;

            if (oldItems == 'UPDATING_FROM_SERVER')
              oldItems = realOldItems;

            if (newItems !== oldItems) {

              diffArray(oldItems, newItems, {
                addedAt: function (id, item, index) {
                  ngCollection.unregisterAutoBind();
                  var newValue = ngCollection.splice( index, 1 )[0];
                  setAutoBind();
                  ngCollection.save(newValue);
                },
                removedAt: function (id, item, index) {
                  ngCollection.remove(id);
                },
                changedAt: function (id, setDiff, unsetDiff, index, oldItem) {

                  if (setDiff)
                    ngCollection.save(setDiff);

                  if (unsetDiff)
                    ngCollection.save(unsetDiff, true);
                },
                movedTo: function (id, item, fromIndex, toIndex) {
                  // XXX do we need this?
                }
              });
            }
          }, true);
        }
      }

      /**
       * Fetches the latest data from Meteor and update the data variable.
       */
      Tracker.autorun(function () {
        // When the reactive func gets recomputated we need to stop any previous
        // observeChanges
        Tracker.onInvalidate(function () {
          ngCollection.stop();
        });
        ngCollection.updateCursor(reactiveFunc());
        setAutoBind();
      });

      return ngCollection;
    }
  }]);
<commit_msg>Moving to Array Wrappers, direct property injection - http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/#wrappers_direct_property_injection<commit_after>'use strict';

var angularMeteorCollections = angular.module('angular-meteor.meteor-collection',
  ['angular-meteor.subscribe', 'angular-meteor.utils', 'diffArray']);

angularMeteorCollections.factory('AngularMeteorCollection', ['$q', '$meteorSubscribe', '$meteorUtils', '$rootScope', '$timeout',
  function($q, $meteorSubscribe, $meteorUtils, $rootScope, $timeout) {

    var AngularMeteorCollection = function (cursor, collection) {
      var self = [];
      angular.extend(self, AngularMeteorCollection.prototype);
      self.$$collection = angular.isDefined(collection) ? collection : $meteorUtils.getCollectionByName(cursor.collection.name);
      return self;
    };

    AngularMeteorCollection.prototype = [];

    AngularMeteorCollection.prototype.subscribe = function () {
      $meteorSubscribe.subscribe.apply(this, arguments);
      return this;
    };

    AngularMeteorCollection.prototype.save = function save(docs, useUnsetModifier) {
      var self = this,
        collection = self.$$collection,
        promises = []; // To store all promises.

      /*
       * The upsertObject function will either update an object if the _id exists
       * or insert an object if the _id is not set in the collection.
       * Returns a promise.
       */
      function upsertObject(item, $q) {
        var deferred = $q.defer();

        if (item._id) { // Performs an update if the _id property is set.
          var item_id = item._id; // Store the _id in temporary variable
          delete item._id; // Remove the _id property so that it can be $set using update.
          var objectId = (item_id._str) ? new Meteor.Collection.ObjectID(item_id._str) : item_id;
          var modifier = (useUnsetModifier) ? {$unset: item} : {$set: item};

          collection.update(objectId, modifier, function (error) {
            if (error) {
              deferred.reject(error);
            } else {
              deferred.resolve({_id: objectId, action: "updated"});
            }
          });
        } else { // Performs an insert if the _id property isn't set.
          collection.insert(item, function (error, result) {
            if (error) {
              deferred.reject(error);
            } else {
              deferred.resolve({_id: result, action: "inserted"});
            }
          });
        }

        return deferred.promise;
      }

      /*
       * How to update the collection depending on the 'docs' argument passed.
       */
      if (docs) { // Checks if a 'docs' argument was passed.
        if (angular.isArray(docs)) { // If an array of objects were passed.
          angular.forEach(docs, function (doc) {
            this.push(upsertObject(doc, $q));
          }, promises);
        } else { // If a single object was passed.
          promises.push(upsertObject(docs, $q));
        }
      } else { // If no 'docs' argument was passed, save the entire collection.
        angular.forEach(self, function (doc) {
          this.push(upsertObject(doc, $q));
        }, promises);
      }

      return $q.all(promises); // Returns all promises when they're resolved.
    };

    AngularMeteorCollection.prototype.remove = function remove(keys) {
      var self = this,
        collection = self.$$collection,
        promises = []; // To store all promises.

      /*
       * The removeObject function will delete an object with the _id property
       * equal to the specified key.
       * Returns a promise.
       */
      function removeObject(key, $q) {
        var deferred = $q.defer();

        if (key) { // Checks if 'key' argument is set.
          if (key._id) {
            key = key._id;
          }
          var objectId = (key._str) ? new Meteor.Collection.ObjectID(key._str) : key;

          collection.remove(objectId, function (error) {
            if (error) {
              deferred.reject(error);
            } else {
              deferred.resolve({_id: objectId, action: "removed"});
            }
          });
        } else {
          deferred.reject("key cannot be null");
        }

        return deferred.promise;
      }

      /*
       * What to remove from collection depending on the 'keys' argument passed.
       */
      if (keys) { // Checks if a 'keys' argument was passed.
        if (angular.isArray(keys)) { // If an array of keys were passed.
          angular.forEach(keys, function (key) {
            this.push(removeObject(key, $q));
          }, promises);
        } else { // If a single key was passed.
          promises.push(removeObject(keys, $q));
        }
      } else { // If no 'keys' argument was passed, save the entire collection.
        // When removing all, we do not use collection.remove({}) because Meteor doesn't give the client side that permissions
        // http://stackoverflow.com/a/15465286/1426570
        var originalSelf = angular.copy(self);
        angular.forEach(originalSelf, function (doc) {
          this.push(removeObject(doc._id, $q));
        }, promises);
      }

      return $q.all(promises); // Returns all promises when they're resolved.
    };

    AngularMeteorCollection.prototype.updateCursor = function (cursor) {
      var self = this;

      function safeApply() {
        // Clearing the watch is needed so no updates are sent to server
        // while handling updates from the server
        self.UPDATING_FROM_SERVER = true;
        if (!$rootScope.$$phase) $rootScope.$apply();
        // Making sure we are setting to false only after one digest cycle and not before
        $timeout(function(){
          self.UPDATING_FROM_SERVER = false;
        },0,false);
      }

      // XXX - consider adding an option for a non-orderd result
      // for faster performance
      if (self.observeHandle) {
        self.observeHandle.stop();
      }

      self.observeHandle = cursor.observe({
        addedAt: function (document, atIndex) {
          self.splice(atIndex, 0, document);
          safeApply();
        },
        changedAt: function (document, oldDocument, atIndex) {
          self.splice(atIndex, 1, document);
          safeApply();
        },
        movedTo: function (document, fromIndex, toIndex) {
          self.splice(fromIndex, 1);
          self.splice(toIndex, 0, document);
          safeApply();
        },
        removedAt: function (oldDocument) {
          var removedObject;
          if (oldDocument._id._str){
            removedObject = _.find(self, function(obj) {
              return obj._id._str == oldDocument._id._str;
            });
          }
          else
            removedObject = _.findWhere(self, {_id: oldDocument._id});

          if (removedObject){
            self.splice(self.indexOf(removedObject), 1);
            safeApply();
          }
        }
      });
    };

    AngularMeteorCollection.prototype.stop = function () {
      if (this.unregisterAutoBind)
        this.unregisterAutoBind();

      if (this.observeHandle)
        this.observeHandle.stop();

      while (this.length > 0) {
        this.pop();
      }
    };

    return AngularMeteorCollection;
}]);

angularMeteorCollections.factory('$meteorCollection', ['AngularMeteorCollection', '$rootScope', 'diffArray',
  function (AngularMeteorCollection, $rootScope, diffArray) {
    return function (reactiveFunc, auto, collection) {
      // Validate parameters
      if (!reactiveFunc) {
        throw new TypeError("The first argument of $meteorCollection is undefined.");
      }
      if (!(typeof reactiveFunc == "function" || angular.isFunction(reactiveFunc.find))) {
        throw new TypeError("The first argument of $meteorCollection must be a function or a have a find function property.");
      }
      auto = auto !== false;

      if (!(typeof reactiveFunc == "function")) {
        var cursorFunc = reactiveFunc.find;
        collection = angular.isDefined(collection) ? collection : reactiveFunc;
        var originalCollection = reactiveFunc;
        reactiveFunc = function() {
          return cursorFunc.apply(originalCollection, [{}]);
        }
      }

      var ngCollection = new AngularMeteorCollection(reactiveFunc(), collection);
      var realOldItems;

      function setAutoBind() {
        if (auto) { // Deep watches the model and performs autobind.
          ngCollection.unregisterAutoBind = $rootScope.$watch(function () {
            if (ngCollection.UPDATING_FROM_SERVER){
              realOldItems = _.without(ngCollection, 'UPDATING_FROM_SERVER');
              return 'UPDATING_FROM_SERVER';
            }
            return _.without(ngCollection, 'UPDATING_FROM_SERVER');
          }, function (newItems, oldItems) {
            if (newItems == 'UPDATING_FROM_SERVER')
              return;

            if (oldItems == 'UPDATING_FROM_SERVER')
              oldItems = realOldItems;

            if (newItems !== oldItems) {

              diffArray(oldItems, newItems, {
                addedAt: function (id, item, index) {
                  ngCollection.unregisterAutoBind();
                  var newValue = ngCollection.splice( index, 1 )[0];
                  setAutoBind();
                  ngCollection.save(newValue);
                },
                removedAt: function (id, item, index) {
                  ngCollection.remove(id);
                },
                changedAt: function (id, setDiff, unsetDiff, index, oldItem) {

                  if (setDiff)
                    ngCollection.save(setDiff);

                  if (unsetDiff)
                    ngCollection.save(unsetDiff, true);
                },
                movedTo: function (id, item, fromIndex, toIndex) {
                  // XXX do we need this?
                }
              });
            }
          }, true);
        }
      }

      /**
       * Fetches the latest data from Meteor and update the data variable.
       */
      Tracker.autorun(function () {
        // When the reactive func gets recomputated we need to stop any previous
        // observeChanges
        Tracker.onInvalidate(function () {
          ngCollection.stop();
        });
        ngCollection.updateCursor(reactiveFunc());
        setAutoBind();
      });

      return ngCollection;
    }
  }]);
<|endoftext|>


<commit_before>var tracker_update_count = 0;

$(document).ajaxSuccess(function(event, xhr, settings) {
    var response = jQuery.parseJSON(xhr.responseText);
    if (typeof res == 'string' && (res == 'null' || res.indexOf('<') == 0)) {
        return;
    }
    tracker_update_count++;
    if (tracker_update_count == 10) {
        $(".module_list").html('');
        $(".hm3_debug").html('');
        $(".hm3_imap_debug").html('');
        $(".hm3_pop3_debug").html('');
        tracker_update_count = 0;
    }
    console.log(tracker_update_count);
    if (response.module_debug) {
        $(".module_list").prepend(response.module_debug);
    }
    if (response.hm3_debug) {
        $(".hm3_debug").prepend(response.hm3_debug);
    }
    if (response.imap_summary_debug) {
        $(".hm3_imap_debug").prepend(response.imap_summary_debug);
    }
    if (response.pop3_summary_debug) {
        $(".hm3_pop3_debug").prepend(response.pop3_summary_debug);
    }
});
<commit_msg>remove debug<commit_after>var tracker_update_count = 0;

$(document).ajaxSuccess(function(event, xhr, settings) {
    var response = jQuery.parseJSON(xhr.responseText);
    if (typeof res == 'string' && (res == 'null' || res.indexOf('<') == 0)) {
        return;
    }
    tracker_update_count++;
    if (tracker_update_count == 10) {
        $(".module_list").html('');
        $(".hm3_debug").html('');
        $(".hm3_imap_debug").html('');
        $(".hm3_pop3_debug").html('');
        tracker_update_count = 0;
    }
    if (response.module_debug) {
        $(".module_list").prepend(response.module_debug);
    }
    if (response.hm3_debug) {
        $(".hm3_debug").prepend(response.hm3_debug);
    }
    if (response.imap_summary_debug) {
        $(".hm3_imap_debug").prepend(response.imap_summary_debug);
    }
    if (response.pop3_summary_debug) {
        $(".hm3_pop3_debug").prepend(response.pop3_summary_debug);
    }
});
<|endoftext|>


<commit_before>var execAndReportSync = require('../../util/exec-and-report-sync');
var fs = require('fs');
var getHomePath = require('home-path');
var logHelper = require('../../util/log-helper');
var path = require('path');
var process = require('process');
var symlinkOrReplaceFilesInFolderSync = require('../../util/symlink-or-replace-files-in-folder-sync');

var extensions = [
  "cssho.vscode-svgviewer",
  "eamodio.gitlens",
  "EditorConfig.EditorConfig",
  "felipecaputo.git-project-manager",
  "jrieken.md-navigate",
  "mrmlnc.vscode-scss",
  "Tyriar.lorem-ipsum",
  "Tyriar.theme-glacier",
  "Tyriar.theme-sapphire",
  "qinjia.seti-icons"
];

function getBaseDir() {
  var baseDir = getHomePath();
  if (process.platform === 'win32') {
    baseDir = path.join(baseDir, 'AppData', 'Roaming');
  } else if (process.platform === 'darwin') {
    baseDir = path.join(baseDir, 'Library', "Application Support");
  } else {
    baseDir = path.join(baseDir, '.config');
  }
  return baseDir;
}

function getConfigDir() {
  return path.join(getBaseDir(), 'Code - Insiders', 'User');
}

module.exports.install = function () {
  logHelper.logStepStarted('vscode');
  installConfigFiles();
  installExtensions();
};

function installConfigFiles() {
  logHelper.logSubStepPartialStarted('installing config files');
  var sourceDir = path.join(__dirname, 'config');
  var files = fs.readdirSync(sourceDir);
  symlinkOrReplaceFilesInFolderSync(files, sourceDir, getConfigDir());
  logHelper.logSubStepPartialSuccess();
}

function installExtensions() {
  extensions.forEach(installExtension);
}

function installExtension(name) {
  execAndReportSync('installing ' + name, 'code-insiders --install-extension ' + name);
}
<commit_msg>[vscode] tslint extension<commit_after>var execAndReportSync = require('../../util/exec-and-report-sync');
var fs = require('fs');
var getHomePath = require('home-path');
var logHelper = require('../../util/log-helper');
var path = require('path');
var process = require('process');
var symlinkOrReplaceFilesInFolderSync = require('../../util/symlink-or-replace-files-in-folder-sync');

var extensions = [
  "cssho.vscode-svgviewer",
  "eamodio.gitlens",
  "EditorConfig.EditorConfig",
  "felipecaputo.git-project-manager",
  "jrieken.md-navigate",
  "mrmlnc.vscode-scss",
  "Tyriar.lorem-ipsum",
  "Tyriar.theme-glacier",
  "Tyriar.theme-sapphire",
  "qinjia.seti-icons",
  "eg2.tslint"
];

function getBaseDir() {
  var baseDir = getHomePath();
  if (process.platform === 'win32') {
    baseDir = path.join(baseDir, 'AppData', 'Roaming');
  } else if (process.platform === 'darwin') {
    baseDir = path.join(baseDir, 'Library', "Application Support");
  } else {
    baseDir = path.join(baseDir, '.config');
  }
  return baseDir;
}

function getConfigDir() {
  return path.join(getBaseDir(), 'Code - Insiders', 'User');
}

module.exports.install = function () {
  logHelper.logStepStarted('vscode');
  installConfigFiles();
  installExtensions();
};

function installConfigFiles() {
  logHelper.logSubStepPartialStarted('installing config files');
  var sourceDir = path.join(__dirname, 'config');
  var files = fs.readdirSync(sourceDir);
  symlinkOrReplaceFilesInFolderSync(files, sourceDir, getConfigDir());
  logHelper.logSubStepPartialSuccess();
}

function installExtensions() {
  extensions.forEach(installExtension);
}

function installExtension(name) {
  execAndReportSync('installing ' + name, 'code-insiders --install-extension ' + name);
}
<|endoftext|>


<commit_before>var Hapi = require('hapi');
var server = new Hapi.Server();

function hello_route(request, reply) {

	reply("Hello " + request.params.name);
}

server.connection({
	host: 'localhost',
	port: Number(process.argv[2] || 8080)
});

server.route({
	method:'GET',
	path: '/{name}',
	handler: hello_route
});

server.start();
<commit_msg>Hapi - 02 official answer<commit_after>var Hapi = require('hapi');
var server = new Hapi.Server();

function hello_route(request, reply) {

	reply("Hello " + request.params.name);
}

server.connection({
	host: 'localhost',
	port: Number(process.argv[2] || 8080)
});

server.route({
	method:'GET',
	path: '/{name}',
	handler: hello_route
});

server.start();

/* Official Answer:
    var Hapi = require('hapi');

    var server = new Hapi.Server();

    server.connection({
        host: 'localhost',
        port: Number(process.argv[2] || 8080)
    });

    server.route({
        method: 'GET',
        path: '/{name}',
        handler: function (request, reply) {
            reply('Hello ' + request.params.name);
            // a more secure alternative is this:
            //
            //     reply('Hello ' + encodeURIComponent(request.params.name));
            //
            // encodeURIComponent escapes all characters except the following: alphabetic, decimal digits, - _ . ! ~ * ' ( )
            // see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent for more details why you should call encodeURIComponent on any user-entered parameter
        }
    });

    server.start();
 */<|endoftext|>


<commit_before>Ext.define('doweown.view.SingleBook', {
    extend: 'Ext.List',
    xtype: 'singlebook',
    config: {
	   //title: 'Search Results',
	   title: 'Yes, we do!',
           xtype: 'list',
	   store: 'Biblio',
	   pinHeaders: false,
	   onItemDisclosure: false,
	   disableSelection: true,
	   itemTpl: '{title}
{author}
{publisher}, {date}
ISBN: {isbn}
{description}

Tap to see availability',
	   /*onItemDisclosure: function( record, btn, index ) {
                                this.getParent().push( {xtype: 'availview'} );
				this.deselectAll();
            },*/
	   listeners: {
		itemtap: function(list, index, target, record) {
			this.getParent().push( {xtype: 'availview'} );
			//this.deselectAll();
			//this.deselect(index);
		}
	    }
     }

});
<commit_msg>changed tap text to blue<commit_after>Ext.define('doweown.view.SingleBook', {
    extend: 'Ext.List',
    xtype: 'singlebook',
    config: {
	   //title: 'Search Results',
	   title: 'Yes, we do!',
           xtype: 'list',
	   store: 'Biblio',
	   pinHeaders: false,
	   onItemDisclosure: false,
	   disableSelection: true,
	   itemTpl: '{title}
{author}
{publisher}, {date}
ISBN: {isbn}
{description}

Tap to see availability',
	   /*onItemDisclosure: function( record, btn, index ) {
                                this.getParent().push( {xtype: 'availview'} );
				this.deselectAll();
            },*/
	   listeners: {
		itemtap: function(list, index, target, record) {
			this.getParent().push( {xtype: 'availview'} );
			//this.deselectAll();
			//this.deselect(index);
		}
	    }
     }

});
<|endoftext|>