<commit_before>var ajaxSelectRequest='';

function genericCallbackSelect(node)
  {
  $('img.infoLoading').show();
  $('div.ajaxInfoElement').html('');
  if(ajaxSelectRequest!='')
    {
    ajaxSelectRequest.abort();
    }
    createAction(node);
    ajaxSelectRequest = $.ajax({
      type: "POST",
      url: json.global.webroot+'/browse/getelementinfo',
      data: {type: node.attr('type'), id: node.attr('element')},
      success: function(jsonContent){
        createInfo(jsonContent);
        $('img.infoLoading').hide();
      }
    });
  }

var arraySelected=new Array();

function genericCallbackCheckboxes(node)
  {
  arraySelected=new Array();
  arraySelected['folders']=new Array();
  arraySelected['items']=new Array();

  var folders='';
  var items='';
  node.find(".treeCheckbox:checked").each(function(){
    if($(this).parents('tr').attr('type')!='item')
      {
      arraySelected['folders'].push($(this).attr('element'));
      folders+=$(this).attr('element')+'-';
      }
    else
      {
      arraySelected['items'].push($(this).attr('element'));
      items+=$(this).attr('element')+'-';
      }
  });
  var link=json.global.webroot+'/download?folders='+folders+'&items='+items;
  if((arraySelected['folders'].length+arraySelected['items'].length)>0)
    {
    $('div.viewSelected').show();
    var html=(arraySelected['folders'].length+arraySelected['items'].length);
    html+=' '+json.browse.element;
    if((arraySelected['folders'].length+arraySelected['items'].length)>1)
      {
      html+='s';
      }
    html+='
'+json.browse.download+'';
    $('div.viewSelected span').html(html);
    }
  else
    {
    $('div.viewSelected').hide();
    $('div.viewSelected span').html('');
    }
  }

function genericCallbackDblClick(node)
  {
  if(node.attr('type')=='community')
    {
    window.location.replace(json.global.webroot+'/community/'+node.attr('element'));
    }
  if(node.attr('type')=='folder')
    {
    window.location.replace(json.global.webroot+'/folder/'+node.attr('element'));
    }
  if(node.attr('type')=='item')
    {
    window.location.replace(json.global.webroot+'/item/'+node.attr('element'));
    }
  }

function createNewFolder(id)
  {
  loadDialog('folderId'+id,'/folder/createfolder?folderId='+id);
  showDialog(json.browse.createFolder,false);
  }

function deleteFolder(id)
  {
  var html='';
  html+=json.browse['deleteMessage'];
  html+='
';
  html+='
';
  html+='
';
  html+='<input style="margin-left:140px;" class="globalButton deleteFolderYes" element="'+id+'" type="button" value="'+json.global.Yes+'"/>';
  html+='<input style="margin-left:50px;" class="globalButton deleteFolderNo" type="button" value="'+json.global.No+'"/>';

  showDialogWithContent(json.browse['delete'],html,false);

  $('input.deleteFolderYes').unbind('click').click(function()
    {
    var node = $('table.treeTable tr.parent[element='+id+']');
    $.post(json.global.webroot+'/folder/delete', {folderId: id},
      function(data) {
        jsonResponse = jQuery.parseJSON(data);
        if(jsonResponse==null)
          {
          createNotive('Error',4000);
          return;
          }
        if(jsonResponse[0])
          {
          createNotive(jsonResponse[1],1500);
          $('div.MainDialog').dialog('close');
          removeChildren(node);
          node.remove();
          }
        else
          {
          createNotive(jsonResponse[1],4000);
          }
      });
    });
  $('input.deleteFolderNo').unbind('click').click(function()
    {
    $( "div.MainDialog" ).dialog('close');
    });
  }

/**
 * Helper method to remove all of a node's subtree from the treeTable view.
 * Expects a jquerified node object.
 */
function removeChildren(node)
  {
  node.each(function(){
    var children = $("table.treeTable tbody tr.child-of-" + this.id);
    $(children).each(function(){
      removeChildren($(this));
      $(this).remove();
      })
  });
  }

function editFolder(id)
  {
  loadDialog("editFolder"+id,"/folder/edit?folderId="+id);
  showDialog(json.browse.edit,false);
  }

function removeItem(id)
  {
  var html='';
  html+=json.browse['removeMessage'];
  html+='
';
  html+='
';
  html+='
';
  html+='<input style="margin-left:140px;" class="globalButton deleteFolderYes" element="'+id+'" type="button" value="'+json.global.Yes+'"/>';
  html+='<input style="margin-left:50px;" class="globalButton deleteFolderNo" type="button" value="'+json.global.No+'"/>';

  showDialogWithContent(json.browse['delete'],html,false);

  $('input.deleteFolderYes').unbind('click').click(function()
    {
    var node=$('table.treeTable tr[element='+id+']');
    var parent;
    //get parent
    var classNames = node.attr('class').split(' ');
    for(key in classNames) {
      if(classNames[key].match("child-of-")) {
        parent = $("#" + classNames[key].substring(9));
      }
    }
    $.post(json.global.webroot+'/folder/removeitem', {folderId: parent.attr('element'), itemId: id},
      function(data) {
        jsonResponse = jQuery.parseJSON(data);
        if(jsonResponse==null)
          {
            createNotive('Error',4000);
            return;
          }
        if(jsonResponse[0])
          {
            createNotive(jsonResponse[1],1500);
            node.remove();
            $( "div.MainDialog" ).dialog('close');
            parent.find('span.elementCount').remove();
            parent.find('span.elementSize').after("");
            parent.find('span.elementSize').remove();
            getElementsSize();
          }
        else
          {
            createNotive(jsonResponse[1],4000);
          }
      });
    });
  $('input.deleteFolderNo').unbind('click').click(function()
    {
    $( "div.MainDialog" ).dialog('close');
    });
  }

function createAction(node)
  {
  var type=node.attr('type');
  var element=node.attr('element');
  var policy=node.attr('policy');
  $('div.viewAction ul').fadeOut('fast',function()
    {
    $('div.viewAction ul').html('');
    var html='';
    if(type=='community')
      {
      html+='
 '+json.browse.view+'
';
      }
    if(type=='folder')
      {
      html+='
 '+json.browse.view+'
';
      html+='
 '+json.browse.download+'
';

      if(policy>=1)
        {
        html+='
 '+json.browse.createFolder+'
';
        html+='
 '+json.browse.uploadIn+'
';
        html+='
 '+json.browse.edit+'
';
        if(node.attr('deletable')!=undefined && node.attr('deletable')=='true')
          {
          html+='
 '+json.browse.share+'
';
          html+='
 '+json.browse['delete']+'
';
          }
        }
      }
    if(type=='item')
      {
      html+='
 '+json.browse.view+'
';
      html+='
 '+json.browse.downloadLastest+'
';
      if(policy>=1)
        {
        html+='
 '+json.browse.share+'
';
        html+='
 '+json.browse['removeItem']+'
';
        }
      }
    $('div.viewAction ul').html(html);

    $('div.viewAction li a').hover(function(){
      $(this).parents('li').css('background-color','#E5E5E5');
    }, function(){
      $(this).parents('li').css('background-color','white');
    });

    $('a.uploadInFolder').qtip(
      {
      content: {
        // Set the text to an image HTML string with the correct src URL to the loading image you want to use
        text: '',
        ajax: {
          url: $('a.uploadInFolder').attr('rel') // Use the rel attribute of each element for the url to load
        },
        title: {
          text: 'Upload', // Give the tooltip a title using each elements text
          button: true
          }
        },
      position: {
        at: 'bottom center', // Position the tooltip above the link
        my: 'top right',
        viewport: $(window), // Keep the tooltip on-screen at all times
        effect: true // Disable positioning animation
        },
      show: {
        event: 'click',
        solo: true // Only show one tooltip at a time
        },
      hide: 'unfocus',
      style: {
        classes: 'uploadqtip ui-tooltip-light ui-tooltip-shadow ui-tooltip-rounded',
        tip: false
        }
      })

    $('a.sharingLink').click(function(){
        loadDialog("sharing"+$(this).attr('type')+$(this).attr('element'),"/share/dialog?type="+$(this).attr('type')+'&element='+$(this).attr('element'));
        showDialog(json.browse.share);
      });
    $('div.viewAction ul').fadeIn('fast');
    });
  }

function createInfo(jsonContent)
  {
  arrayElement=jQuery.parseJSON(jsonContent);
  var html='';
  if(arrayElement['type']=='community')
    {
    html+='';
    }
  else if(arrayElement['type']=='folder')
    {
    html+='';
    }
  else
    {
    html+='';
    }
  html+=''+sliceFileName(arrayElement['name'],27)+'';
  html+='
';
  html+='
';
  html+='    '+arrayElement.translation.Created+'	';
  html+='    '+arrayElement.creation+'	';
  html+='
';
  if(arrayElement['type']=='community')
    {
    html+='
';
    html+='    Member';
    if(parseInt(arrayElement['members'])>1)
      {
      html+='s';
      }
    html+=     '	';
    html+='    '+arrayElement['members']+'	';
    html+='
';
    }
  if(arrayElement['type']=='item')
    {
    html+='
';
    html+='    '+arrayElement.translation.Uploaded+'	';
    html+='    '+arrayElement['uploaded']['firstname']+' '+arrayElement['uploaded']['lastname']+'	';
    html+='
';
    html+='
';
    html+='    Revision';
    if(parseInt(arrayElement['revision']['revision'])>1)
      {
      html+='s';
      }
    html+=     '	';
    html+='    '+arrayElement['revision']['revision']+'	';
    html+='
';
    html+='
';
    html+='    '+arrayElement.translation.File;
    if(parseInt(arrayElement['nbitstream'])>1)
      {
      html+='s';
      }
    html+=    '	';
    html+='    '+arrayElement['nbitstream']+'	';
    html+='
';
    }

  if(arrayElement['type']=='folder')
    {
    html+='
';
    html+='    ';
    html+=arrayElement['teaser'];
    html+=     '	';
    html+='
';
    }
  html+='
';
  if(arrayElement['type']=='community'&&arrayElement['privacy']==2)
    {
    html+='
'+arrayElement.translation.Private+'
';
    }

  if(arrayElement['thumbnail']!=undefined&&arrayElement['thumbnail']!='')
    {
    html+='
'+json.browse.preview+'
';
    }

  $('div.ajaxInfoElement').html(html);
}
<commit_msg>ENH: Refs #0338. Update ancestor folder size when an item or a folder is deleted.<commit_after>var ajaxSelectRequest='';

function genericCallbackSelect(node)
  {
  $('img.infoLoading').show();
  $('div.ajaxInfoElement').html('');
  if(ajaxSelectRequest!='')
    {
    ajaxSelectRequest.abort();
    }
    createAction(node);
    ajaxSelectRequest = $.ajax({
      type: "POST",
      url: json.global.webroot+'/browse/getelementinfo',
      data: {type: node.attr('type'), id: node.attr('element')},
      success: function(jsonContent){
        createInfo(jsonContent);
        $('img.infoLoading').hide();
      }
    });
  }

var arraySelected=new Array();

function genericCallbackCheckboxes(node)
  {
  arraySelected=new Array();
  arraySelected['folders']=new Array();
  arraySelected['items']=new Array();

  var folders='';
  var items='';
  node.find(".treeCheckbox:checked").each(function(){
    if($(this).parents('tr').attr('type')!='item')
      {
      arraySelected['folders'].push($(this).attr('element'));
      folders+=$(this).attr('element')+'-';
      }
    else
      {
      arraySelected['items'].push($(this).attr('element'));
      items+=$(this).attr('element')+'-';
      }
  });
  var link=json.global.webroot+'/download?folders='+folders+'&items='+items;
  if((arraySelected['folders'].length+arraySelected['items'].length)>0)
    {
    $('div.viewSelected').show();
    var html=(arraySelected['folders'].length+arraySelected['items'].length);
    html+=' '+json.browse.element;
    if((arraySelected['folders'].length+arraySelected['items'].length)>1)
      {
      html+='s';
      }
    html+='
'+json.browse.download+'';
    $('div.viewSelected span').html(html);
    }
  else
    {
    $('div.viewSelected').hide();
    $('div.viewSelected span').html('');
    }
  }

function genericCallbackDblClick(node)
  {
  if(node.attr('type')=='community')
    {
    window.location.replace(json.global.webroot+'/community/'+node.attr('element'));
    }
  if(node.attr('type')=='folder')
    {
    window.location.replace(json.global.webroot+'/folder/'+node.attr('element'));
    }
  if(node.attr('type')=='item')
    {
    window.location.replace(json.global.webroot+'/item/'+node.attr('element'));
    }
  }

function createNewFolder(id)
  {
  loadDialog('folderId'+id,'/folder/createfolder?folderId='+id);
  showDialog(json.browse.createFolder,false);
  }

function deleteFolder(id)
  {
  var html='';
  html+=json.browse['deleteMessage'];
  html+='
';
  html+='
';
  html+='
';
  html+='<input style="margin-left:140px;" class="globalButton deleteFolderYes" element="'+id+'" type="button" value="'+json.global.Yes+'"/>';
  html+='<input style="margin-left:50px;" class="globalButton deleteFolderNo" type="button" value="'+json.global.No+'"/>';

  showDialogWithContent(json.browse['delete'],html,false);

  $('input.deleteFolderYes').unbind('click').click(function()
    {
    var node = $('table.treeTable tr.parent[element='+id+']');
    // get ancestor nodes
    var ancestorNodes = ancestorsOf(node);
    $.post(json.global.webroot+'/folder/delete', {folderId: id},
      function(data) {
        jsonResponse = jQuery.parseJSON(data);
        if(jsonResponse==null)
          {
          createNotive('Error',4000);
          return;
          }
        if(jsonResponse[0])
          {
          createNotive(jsonResponse[1],1500);
          $('div.MainDialog').dialog('close');
          removeChildren(node);
          node.remove();
          // mark ancestor nodes
          for (var i = 0; i < ancestorNodes.length; i++){
            $(ancestorNodes[i]).find('span.elementCount').remove();
            $(ancestorNodes[i]).find('span.elementSize').after("");
            $(ancestorNodes[i]).find('span.elementSize').remove();
            }
          // update folder size
          getElementsSize();
          }
        else
          {
          createNotive(jsonResponse[1],4000);
          }
      });
    });
  $('input.deleteFolderNo').unbind('click').click(function()
    {
    $( "div.MainDialog" ).dialog('close');
    });
  }

/**
 * Helper method to remove all of a node's subtree from the treeTable view.
 * Expects a jquerified node object.
 */
function removeChildren(node)
  {
  node.each(function(){
    var children = $("table.treeTable tbody tr.child-of-" + this.id);
    $(children).each(function(){
      removeChildren($(this));
      $(this).remove();
      })
  });
  }

function editFolder(id)
  {
  loadDialog("editFolder"+id,"/folder/edit?folderId="+id);
  showDialog(json.browse.edit,false);
  }

function parentOf(node) {
  var classNames = node[0].className.split(' ');

  for(key in classNames) {
    if(classNames[key].match("child-of-")) {
      return $("#" + classNames[key].substring(9));
    }
  }
}

function ancestorsOf(node) {
  var ancestors = [];
  while(node = parentOf(node)) {
    ancestors[ancestors.length] = node[0];
  }
  return ancestors;
}

function removeItem(id)
  {
  var html='';
  html+=json.browse['removeMessage'];
  html+='
';
  html+='
';
  html+='
';
  html+='<input style="margin-left:140px;" class="globalButton deleteFolderYes" element="'+id+'" type="button" value="'+json.global.Yes+'"/>';
  html+='<input style="margin-left:50px;" class="globalButton deleteFolderNo" type="button" value="'+json.global.No+'"/>';

  showDialogWithContent(json.browse['delete'],html,false);

  $('input.deleteFolderYes').unbind('click').click(function()
    {
    var node=$('table.treeTable tr[element='+id+']');
    // get ancestor nodes
    var ancestorNodes = ancestorsOf(node);
    $.post(json.global.webroot+'/folder/removeitem', {folderId: parentOf(node).attr('element'), itemId: id},
      function(data) {
        jsonResponse = jQuery.parseJSON(data);
        if(jsonResponse==null)
          {
            createNotive('Error',4000);
            return;
          }
        if(jsonResponse[0])
          {
            createNotive(jsonResponse[1],1500);
            node.remove();
            $( "div.MainDialog" ).dialog('close');
            // mark ancestor nodes
            for (var i = 0; i < ancestorNodes.length; i++){
              $(ancestorNodes[i]).find('span.elementCount').remove();
              $(ancestorNodes[i]).find('span.elementSize').after("");
              $(ancestorNodes[i]).find('span.elementSize').remove();
            }
            // update folder size
            getElementsSize();
          }
        else
          {
            createNotive(jsonResponse[1],4000);
          }
      });
    });
  $('input.deleteFolderNo').unbind('click').click(function()
    {
    $( "div.MainDialog" ).dialog('close');
    });
  }

function createAction(node)
  {
  var type=node.attr('type');
  var element=node.attr('element');
  var policy=node.attr('policy');
  $('div.viewAction ul').fadeOut('fast',function()
    {
    $('div.viewAction ul').html('');
    var html='';
    if(type=='community')
      {
      html+='
 '+json.browse.view+'
';
      }
    if(type=='folder')
      {
      html+='
 '+json.browse.view+'
';
      html+='
 '+json.browse.download+'
';

      if(policy>=1)
        {
        html+='
 '+json.browse.createFolder+'
';
        html+='
 '+json.browse.uploadIn+'
';
        html+='
 '+json.browse.edit+'
';
        if(node.attr('deletable')!=undefined && node.attr('deletable')=='true')
          {
          html+='
 '+json.browse.share+'
';
          html+='
 '+json.browse['delete']+'
';
          }
        }
      }
    if(type=='item')
      {
      html+='
 '+json.browse.view+'
';
      html+='
 '+json.browse.downloadLastest+'
';
      if(policy>=1)
        {
        html+='
 '+json.browse.share+'
';
        html+='
 '+json.browse['removeItem']+'
';
        }
      }
    $('div.viewAction ul').html(html);

    $('div.viewAction li a').hover(function(){
      $(this).parents('li').css('background-color','#E5E5E5');
    }, function(){
      $(this).parents('li').css('background-color','white');
    });

    $('a.uploadInFolder').qtip(
      {
      content: {
        // Set the text to an image HTML string with the correct src URL to the loading image you want to use
        text: '',
        ajax: {
          url: $('a.uploadInFolder').attr('rel') // Use the rel attribute of each element for the url to load
        },
        title: {
          text: 'Upload', // Give the tooltip a title using each elements text
          button: true
          }
        },
      position: {
        at: 'bottom center', // Position the tooltip above the link
        my: 'top right',
        viewport: $(window), // Keep the tooltip on-screen at all times
        effect: true // Disable positioning animation
        },
      show: {
        event: 'click',
        solo: true // Only show one tooltip at a time
        },
      hide: 'unfocus',
      style: {
        classes: 'uploadqtip ui-tooltip-light ui-tooltip-shadow ui-tooltip-rounded',
        tip: false
        }
      })

    $('a.sharingLink').click(function(){
        loadDialog("sharing"+$(this).attr('type')+$(this).attr('element'),"/share/dialog?type="+$(this).attr('type')+'&element='+$(this).attr('element'));
        showDialog(json.browse.share);
      });
    $('div.viewAction ul').fadeIn('fast');
    });
  }

function createInfo(jsonContent)
  {
  arrayElement=jQuery.parseJSON(jsonContent);
  var html='';
  if(arrayElement['type']=='community')
    {
    html+='';
    }
  else if(arrayElement['type']=='folder')
    {
    html+='';
    }
  else
    {
    html+='';
    }
  html+=''+sliceFileName(arrayElement['name'],27)+'';
  html+='
';
  html+='
';
  html+='    '+arrayElement.translation.Created+'	';
  html+='    '+arrayElement.creation+'	';
  html+='
';
  if(arrayElement['type']=='community')
    {
    html+='
';
    html+='    Member';
    if(parseInt(arrayElement['members'])>1)
      {
      html+='s';
      }
    html+=     '	';
    html+='    '+arrayElement['members']+'	';
    html+='
';
    }
  if(arrayElement['type']=='item')
    {
    html+='
';
    html+='    '+arrayElement.translation.Uploaded+'	';
    html+='    '+arrayElement['uploaded']['firstname']+' '+arrayElement['uploaded']['lastname']+'	';
    html+='
';
    html+='
';
    html+='    Revision';
    if(parseInt(arrayElement['revision']['revision'])>1)
      {
      html+='s';
      }
    html+=     '	';
    html+='    '+arrayElement['revision']['revision']+'	';
    html+='
';
    html+='
';
    html+='    '+arrayElement.translation.File;
    if(parseInt(arrayElement['nbitstream'])>1)
      {
      html+='s';
      }
    html+=    '	';
    html+='    '+arrayElement['nbitstream']+'	';
    html+='
';
    }

  if(arrayElement['type']=='folder')
    {
    html+='
';
    html+='    ';
    html+=arrayElement['teaser'];
    html+=     '	';
    html+='
';
    }
  html+='
';
  if(arrayElement['type']=='community'&&arrayElement['privacy']==2)
    {
    html+='
'+arrayElement.translation.Private+'
';
    }

  if(arrayElement['thumbnail']!=undefined&&arrayElement['thumbnail']!='')
    {
    html+='
'+json.browse.preview+'
';
    }

  $('div.ajaxInfoElement').html(html);
}
<|endoftext|>


<commit_before>const debug = require('ghost-ignition').debug('api:v2:utils:permissions');
const Promise = require('bluebird');
const _ = require('lodash');
const permissions = require('../../../services/permissions');
const common = require('../../../lib/common');

/**
 * @description Handle requests, which need authentication.
 *
 * @param {Object} apiConfig - Docname & method of API ctrl
 * @param {Object} frame
 * @return {Promise}
 */
const nonePublicAuth = (apiConfig, frame) => {
    debug('check admin permissions');

    const singular = apiConfig.docName.replace(/s$/, '');

    let permissionIdentifier = frame.options.id;

    // CASE: Target ctrl can override the identifier. The identifier is the unique identifier of the target resource
    //       e.g. edit a setting -> the key of the setting
    //       e.g. edit a post -> post id from url param
    //       e.g. change user password -> user id inside of the body structure
    if (apiConfig.identifier) {
        permissionIdentifier = apiConfig.identifier(frame);
    }

    const unsafeAttrObject = apiConfig.unsafeAttrs && _.has(frame, `data.[${apiConfig.docName}][0]`) ? _.pick(frame.data[apiConfig.docName][0], apiConfig.unsafeAttrs) : {};
    const permsPromise = permissions.canThis(frame.options.context)[apiConfig.method][singular](permissionIdentifier, unsafeAttrObject);

    return permsPromise.then((result) => {
        /*
         * Allow the permissions function to return a list of excluded attributes.
         * If it does, omit those attrs from the data passed through
         *
         * NOTE: excludedAttrs differ from unsafeAttrs in that they're determined by the model's permissible function,
         * and the attributes are simply excluded rather than throwing a NoPermission exception
         *
         * TODO: This is currently only needed because of the posts model and the contributor role. Once we extend the
         * contributor role to be able to edit existing tags, this concept can be removed.
         */
        if (result && result.excludedAttrs && _.has(frame, `data.[${apiConfig.docName}][0]`)) {
            frame.data[apiConfig.docName][0] = _.omit(frame.data[apiConfig.docName][0], result.excludedAttrs);
        }
    }).catch((err) => {
        if (err instanceof common.errors.NoPermissionError) {
            err.message = common.i18n.t('errors.api.utils.noPermissionToCall', {
                method: apiConfig.method,
                docName: apiConfig.docName
            });
            return Promise.reject(err);
        }

        if (common.errors.utils.isIgnitionError(err)) {
            return Promise.reject(err);
        }

        return Promise.reject(new common.errors.GhostError({
            err: err
        }));
    });
};

// @TODO: https://github.com/TryGhost/Ghost/issues/10735
module.exports = {
    /**
     * @description Handle permission stage for API version v2.
     *
     * @param {Object} apiConfig - Docname & method of target ctrl.
     * @param {Object} frame
     * @return {Promise}
     */
    handle(apiConfig, frame) {
        debug('handle');

        // @TODO: https://github.com/TryGhost/Ghost/issues/10099
        frame.options.context = permissions.parseContext(frame.options.context);

        // CASE: Content API access
        if (frame.options.context.public) {
            debug('check content permissions');

            // @TODO: Remove when we drop v0.1
            // @TODO: https://github.com/TryGhost/Ghost/issues/10733
            return permissions.applyPublicRules(apiConfig.docName, apiConfig.method, {
                status: frame.options.status,
                id: frame.options.id,
                uuid: frame.options.uuid,
                slug: frame.options.slug,
                data: {
                    status: frame.data.status,
                    id: frame.data.id,
                    uuid: frame.data.uuid,
                    slug: frame.data.slug
                }
            });
        }

        return nonePublicAuth(apiConfig, frame);
    }
};
<commit_msg>Fixed unsafeAttributes fetching in Admin API v2<commit_after>const debug = require('ghost-ignition').debug('api:v2:utils:permissions');
const Promise = require('bluebird');
const _ = require('lodash');
const permissions = require('../../../services/permissions');
const common = require('../../../lib/common');

/**
 * @description Handle requests, which need authentication.
 *
 * @param {Object} apiConfig - Docname & method of API ctrl
 * @param {Object} frame
 * @return {Promise}
 */
const nonePublicAuth = (apiConfig, frame) => {
    debug('check admin permissions');

    const singular = apiConfig.docName.replace(/s$/, '');

    let permissionIdentifier = frame.options.id;

    // CASE: Target ctrl can override the identifier. The identifier is the unique identifier of the target resource
    //       e.g. edit a setting -> the key of the setting
    //       e.g. edit a post -> post id from url param
    //       e.g. change user password -> user id inside of the body structure
    if (apiConfig.identifier) {
        permissionIdentifier = apiConfig.identifier(frame);
    }

    let unsafeAttrObject = apiConfig.unsafeAttrs && _.has(frame, `data.[${apiConfig.docName}][0]`) ? _.pick(frame.data[apiConfig.docName][0], apiConfig.unsafeAttrs) : {};

    if (apiConfig.unsafeAttrsObject) {
        unsafeAttrObject = apiConfig.unsafeAttrsObject(frame);
    }

    const permsPromise = permissions.canThis(frame.options.context)[apiConfig.method][singular](permissionIdentifier, unsafeAttrObject);

    return permsPromise.then((result) => {
        /*
         * Allow the permissions function to return a list of excluded attributes.
         * If it does, omit those attrs from the data passed through
         *
         * NOTE: excludedAttrs differ from unsafeAttrs in that they're determined by the model's permissible function,
         * and the attributes are simply excluded rather than throwing a NoPermission exception
         *
         * TODO: This is currently only needed because of the posts model and the contributor role. Once we extend the
         * contributor role to be able to edit existing tags, this concept can be removed.
         */
        if (result && result.excludedAttrs && _.has(frame, `data.[${apiConfig.docName}][0]`)) {
            frame.data[apiConfig.docName][0] = _.omit(frame.data[apiConfig.docName][0], result.excludedAttrs);
        }
    }).catch((err) => {
        if (err instanceof common.errors.NoPermissionError) {
            err.message = common.i18n.t('errors.api.utils.noPermissionToCall', {
                method: apiConfig.method,
                docName: apiConfig.docName
            });
            return Promise.reject(err);
        }

        if (common.errors.utils.isIgnitionError(err)) {
            return Promise.reject(err);
        }

        return Promise.reject(new common.errors.GhostError({
            err: err
        }));
    });
};

// @TODO: https://github.com/TryGhost/Ghost/issues/10735
module.exports = {
    /**
     * @description Handle permission stage for API version v2.
     *
     * @param {Object} apiConfig - Docname & method of target ctrl.
     * @param {Object} frame
     * @return {Promise}
     */
    handle(apiConfig, frame) {
        debug('handle');

        // @TODO: https://github.com/TryGhost/Ghost/issues/10099
        frame.options.context = permissions.parseContext(frame.options.context);

        // CASE: Content API access
        if (frame.options.context.public) {
            debug('check content permissions');

            // @TODO: Remove when we drop v0.1
            // @TODO: https://github.com/TryGhost/Ghost/issues/10733
            return permissions.applyPublicRules(apiConfig.docName, apiConfig.method, {
                status: frame.options.status,
                id: frame.options.id,
                uuid: frame.options.uuid,
                slug: frame.options.slug,
                data: {
                    status: frame.data.status,
                    id: frame.data.id,
                    uuid: frame.data.uuid,
                    slug: frame.data.slug
                }
            });
        }

        return nonePublicAuth(apiConfig, frame);
    }
};
<|endoftext|>


<commit_before>var _      = require('lodash'),
    fs     = require('fs'),
    path   = require('path'),
    hbs    = require('express-hbs'),
    api    = require('../api'),
    config = require('../config'),
    errors = require('../errors'),
    i18n   = require('../i18n'),
    themeHandler;

themeHandler = {
    // ### GhostLocals Middleware
    // Expose the standard locals that every external page should have available,
    // separating between the theme and the admin
    ghostLocals: function ghostLocals(req, res, next) {
        // Make sure we have a locals value.
        res.locals = res.locals || {};
        res.locals.version = config.get('ghostVersion');
        res.locals.safeVersion = config.get('ghostVersion').match(/^(\d+\.)?(\d+)/)[0];
        // relative path from the URL
        res.locals.relativeUrl = req.path;

        next();
    },

    // ### configHbsForContext Middleware
    // Setup handlebars for the current context (admin or theme)
    configHbsForContext: function configHbsForContext(req, res, next) {
        var themeData = _.cloneDeep(config.get('theme')),
            labsData = _.cloneDeep(config.get('labs')),
            blogApp = req.app;

        if (req.secure && config.get('urlSSL')) {
            // For secure requests override .url property with the SSL version
            themeData.url = config.get('urlSSL').replace(/\/$/, '');
        }

        // Change camelCase to snake_case
        themeData.posts_per_page = themeData.postsPerPage;
        delete themeData.postsPerPage;

        hbs.updateTemplateOptions({data: {blog: themeData, labs: labsData}});

        if (config.getContentPath('themes') && blogApp.get('activeTheme')) {
            blogApp.set('views', path.join(config.getContentPath('themes'), blogApp.get('activeTheme')));
        }

        // Pass 'secure' flag to the view engine
        // so that templates can choose 'url' vs 'urlSSL'
        res.locals.secure = req.secure;

        next();
    },

    // ### Activate Theme
    // Helper for updateActiveTheme
    activateTheme: function activateTheme(blogApp, activeTheme) {
        var hbsOptions,
            themePartials = path.join(config.getContentPath('themes'), activeTheme, 'partials');

        // clear the view cache
        blogApp.cache = {};

        // set view engine
        hbsOptions = {
            partialsDir: [config.get('paths').helperTemplates],
            onCompile: function onCompile(exhbs, source) {
                return exhbs.handlebars.compile(source, {preventIndent: true});
            }
        };

        fs.stat(themePartials, function stat(err, stats) {
            // Check that the theme has a partials directory before trying to use it
            if (!err && stats && stats.isDirectory()) {
                hbsOptions.partialsDir.push(themePartials);
            }
        });

        blogApp.engine('hbs', hbs.express3(hbsOptions));

        // Update user error template
        errors.updateActiveTheme(activeTheme);

        // Set active theme variable on the express server
        blogApp.set('activeTheme', activeTheme);
    },

    // ### updateActiveTheme
    // Updates the blogApp's activeTheme variable and subsequently
    // activates that theme's views with the hbs templating engine if it
    // is not yet activated.
    updateActiveTheme: function updateActiveTheme(req, res, next) {
        var blogApp = req.app;

        api.settings.read({context: {internal: true}, key: 'activeTheme'}).then(function then(response) {
            var activeTheme = response.settings[0];

            // Check if the theme changed
            if (activeTheme.value !== blogApp.get('activeTheme')) {
                // Change theme
                if (!config.get('paths').availableThemes.hasOwnProperty(activeTheme.value)) {
                    if (!res.isAdmin) {
                        // Throw an error if the theme is not available, but not on the admin UI
                        return errors.throwError(i18n.t('errors.middleware.themehandler.missingTheme', {theme: activeTheme.value}));
                    } else {
                        // At this point the activated theme is not present and the current
                        // request is for the admin client.  In order to allow the user access
                        // to the admin client we set an hbs instance on the app so that middleware
                        // processing can continue.
                        blogApp.engine('hbs', hbs.express3());
                        errors.logWarn(i18n.t('errors.middleware.themehandler.missingTheme', {theme: activeTheme.value}));

                        return next();
                    }
                } else {
                    themeHandler.activateTheme(blogApp, activeTheme.value);
                }
            }
            next();
        }).catch(function handleError(err) {
            // Trying to start up without the active theme present, setup a simple hbs instance
            // and render an error page straight away.
            blogApp.engine('hbs', hbs.express3());
            next(err);
        });
    }
};

module.exports = themeHandler;
<commit_msg>Refresh assetHash on theme activation (#7464)<commit_after>var _      = require('lodash'),
    fs     = require('fs'),
    path   = require('path'),
    hbs    = require('express-hbs'),
    api    = require('../api'),
    config = require('../config'),
    errors = require('../errors'),
    i18n   = require('../i18n'),
    themeHandler;

themeHandler = {
    // ### GhostLocals Middleware
    // Expose the standard locals that every external page should have available,
    // separating between the theme and the admin
    ghostLocals: function ghostLocals(req, res, next) {
        // Make sure we have a locals value.
        res.locals = res.locals || {};
        res.locals.version = config.get('ghostVersion');
        res.locals.safeVersion = config.get('ghostVersion').match(/^(\d+\.)?(\d+)/)[0];
        // relative path from the URL
        res.locals.relativeUrl = req.path;

        next();
    },

    // ### configHbsForContext Middleware
    // Setup handlebars for the current context (admin or theme)
    configHbsForContext: function configHbsForContext(req, res, next) {
        var themeData = _.cloneDeep(config.get('theme')),
            labsData = _.cloneDeep(config.get('labs')),
            blogApp = req.app;

        if (req.secure && config.get('urlSSL')) {
            // For secure requests override .url property with the SSL version
            themeData.url = config.get('urlSSL').replace(/\/$/, '');
        }

        // Change camelCase to snake_case
        themeData.posts_per_page = themeData.postsPerPage;
        delete themeData.postsPerPage;

        hbs.updateTemplateOptions({data: {blog: themeData, labs: labsData}});

        if (config.getContentPath('themes') && blogApp.get('activeTheme')) {
            blogApp.set('views', path.join(config.getContentPath('themes'), blogApp.get('activeTheme')));
        }

        // Pass 'secure' flag to the view engine
        // so that templates can choose 'url' vs 'urlSSL'
        res.locals.secure = req.secure;

        next();
    },

    // ### Activate Theme
    // Helper for updateActiveTheme
    activateTheme: function activateTheme(blogApp, activeTheme) {
        var hbsOptions,
            themePartials = path.join(config.getContentPath('themes'), activeTheme, 'partials');

        // clear the view cache
        blogApp.cache = {};
        // reset the asset hash
        config.assetHash = null;

        // set view engine
        hbsOptions = {
            partialsDir: [config.get('paths').helperTemplates],
            onCompile: function onCompile(exhbs, source) {
                return exhbs.handlebars.compile(source, {preventIndent: true});
            }
        };

        fs.stat(themePartials, function stat(err, stats) {
            // Check that the theme has a partials directory before trying to use it
            if (!err && stats && stats.isDirectory()) {
                hbsOptions.partialsDir.push(themePartials);
            }
        });

        blogApp.engine('hbs', hbs.express3(hbsOptions));

        // Update user error template
        errors.updateActiveTheme(activeTheme);

        // Set active theme variable on the express server
        blogApp.set('activeTheme', activeTheme);
    },

    // ### updateActiveTheme
    // Updates the blogApp's activeTheme variable and subsequently
    // activates that theme's views with the hbs templating engine if it
    // is not yet activated.
    updateActiveTheme: function updateActiveTheme(req, res, next) {
        var blogApp = req.app;

        api.settings.read({context: {internal: true}, key: 'activeTheme'}).then(function then(response) {
            var activeTheme = response.settings[0];

            // Check if the theme changed
            if (activeTheme.value !== blogApp.get('activeTheme')) {
                // Change theme
                if (!config.get('paths').availableThemes.hasOwnProperty(activeTheme.value)) {
                    if (!res.isAdmin) {
                        // Throw an error if the theme is not available, but not on the admin UI
                        return errors.throwError(i18n.t('errors.middleware.themehandler.missingTheme', {theme: activeTheme.value}));
                    } else {
                        // At this point the activated theme is not present and the current
                        // request is for the admin client.  In order to allow the user access
                        // to the admin client we set an hbs instance on the app so that middleware
                        // processing can continue.
                        blogApp.engine('hbs', hbs.express3());
                        errors.logWarn(i18n.t('errors.middleware.themehandler.missingTheme', {theme: activeTheme.value}));

                        return next();
                    }
                } else {
                    themeHandler.activateTheme(blogApp, activeTheme.value);
                }
            }
            next();
        }).catch(function handleError(err) {
            // Trying to start up without the active theme present, setup a simple hbs instance
            // and render an error page straight away.
            blogApp.engine('hbs', hbs.express3());
            next(err);
        });
    }
};

module.exports = themeHandler;
<|endoftext|>


<commit_before>'use strict';

module.exports = function(league, testObj) {

  const ENABLE_LOGGING = false;
  const log = (msg) => {
    if (ENABLE_LOGGING) {
      console.log(msg);
    }
  };

  const config = require('./config');
  const twitter = require('./lib/twitter')(config, league.leagueName);
  const request = require('./lib/request');
  const _ = require('lodash');
  const moment = require('moment');

  const fetchNextFromWeb = function() {
    log('Fetching scores from league');
    return league.urls().then((urls) => {
      const requests = urls.map((url) => {
        return request.get(url);
      });
      return Promise.all(requests).then((res) => {
        const next = league.Scores.parse(res);
        return Promise.resolve(next);
      });
    });
  };

  const final = (closeDB, db, res) => {
    return (closeDB ? db.end() : Promise.resolve()).then(() => {
      return Promise.resolve(res);
    });
  };

  const getFromStore = (db, allTime) => {
    let closeDB = false;
    if (!db) {
      db = require('./lib/db')();
      closeDB = true;
    }
    const sql = `
    select * from score_tweet.Leagues t1
    where League = ?
    order by id desc limit 1;`;
    log('Fetching scores from database');
    return db.query(sql, [league.leagueName]).then((res) => {
      if (!res[0]) { return final(closeDB, db, null); }

      const createdOn = moment.unix(res[0].CreatedOn);
      const timeSinceLast = moment.duration(moment().diff(createdOn));
      if (timeSinceLast.asMinutes() >= 20 && !allTime && !league.occasionalFetch) {
        console.log('Skipping because existing item is too old');
        return final(closeDB, db, null);
      }
      const scores = JSON.parse(res[0].Data);
      const oldObj = new league.Scores(scores);
      return final(closeDB, db, oldObj);
    });
  };

  const compareAndTweet = function(oldObj, newObj) {
    const changes = newObj.getChanges(oldObj, league);
    if (changes.length) {
      console.log('Found ' + changes.length + ' changes.');
    }
    if (league.seqTweet) {
      if (testObj && testObj.noTweet) {
        console.log(changes);
        return Promise.resolve();
      } else {
        return twitter.seqPost(changes);
      }
    } else {
      const tweets = _.map(changes, (status) => {
        if (testObj && testObj.noTweet) {
          console.log(status);
          return Promise.resolve();
        } else {
          return twitter.post(status);
        }
      });
      return Promise.all(tweets);
    }
  };

  const saveScores = (db, newObj) => {
    if (testObj && testObj.noSave) {
      return Promise.resolve();
    }
    if (!newObj.Games.length) {
      console.log('No games, not saving');
      return Promise.resolve();
    }
    let closeDB = false;
    if (!db) {
      db = require('./lib/db')();
      closeDB = true;
    }
    const sql = `
    insert into score_tweet.Leagues(League,CreatedOn,\`Data\`)
    values (?,UNIX_TIMESTAMP(),?);`;
    return db.query(sql, [
      league.leagueName,
      JSON.stringify(newObj)
    ]).then(() => {
      console.log('New Item Saved');
      return final(closeDB, db, null);
    });
  };

  const cleanup = (db) => {
    if (moment().minute() !== 0) { return Promise.resolve(); }

    const threshold = moment().subtract(2, 'weeks').unix();
    const sql = 'delete from score_tweet.Leagues where League = ? and CreatedOn < ?';
    return db.query(sql, [league.leagueName, threshold]).then((res) => {
      console.log(`${res.affectedRows} rows cleaned up.`);
      return Promise.resolve();
    });
  };

  return {
    getFromStore,
    web: function(cb) {
      let nextObj = null;
      const db = require('./lib/db')();
      fetchNextFromWeb().then((res) => {
        nextObj = res;
        if (!nextObj) {
          console.log('Bad data from ' + league.urls()[0]);
          return Promise.reject('Bad data from ' + league.urls()[0]);
        }
        if (!nextObj.Games.length) {
          return Promise.reject('No games, skipping');
        }
        return getFromStore(db);
      }).then((oldObj) => {
        if (oldObj) {
          return compareAndTweet(oldObj, nextObj);
        } else {
          return Promise.resolve();
        }
      }).then(() => {
        return saveScores(db, nextObj);
      }).then(() => {
        return cleanup(db);
      }).then(() => {
        return db.end();
      }).then(() => {
        cb(null, 'done');
      }).catch((err) => {
        console.log(err);
        return db.end().then(() => {
          if (err === 'No games, skipping') {
            cb(null, err);
          } else {
            cb(err);
          }
        });
      });
    },
    getChanges: function(cb, allTime) {
      let nextObj = null;
      const db = require('./lib/db')();
      fetchNextFromWeb().then((res) => {
        nextObj = res;
        console.log('New scores: ' + nextObj.getScores().length);
        if (!nextObj) {
          console.log('Bad data from ' + league.urls()[0]);
          return Promise.reject('Bad data from ' + league.urls()[0]);
        }
        return getFromStore(db, allTime);
      }).then((oldObj) => {
        if (oldObj) {
          console.log('Old scores: ' + oldObj.getScores().length);
          const changes = nextObj.getChanges(oldObj, league);
          if (changes.length) {
            console.log(changes);
          } else {
            console.log('No Changes');
          }
          return Promise.resolve();
        } else {
          return Promise.resolve();
        }
      }).then(() => {
        return saveScores(db, nextObj);
      }).then(() => {
        return db.end();
      }).then(() => {
        cb(null, 'done');
      }).catch((err) => {
        console.log(err);
        cb(err);
      });
    },
    fetch: function(cb) {
      fetchNextFromWeb().then((res) => {
        cb(null, res);
      }).catch((err) => {
        cb(err);
      });
    }
  };
};
<commit_msg>use getScores() interface<commit_after>'use strict';

module.exports = function(league, testObj) {

  const ENABLE_LOGGING = false;
  const log = (msg) => {
    if (ENABLE_LOGGING) {
      console.log(msg);
    }
  };

  const config = require('./config');
  const twitter = require('./lib/twitter')(config, league.leagueName);
  const request = require('./lib/request');
  const _ = require('lodash');
  const moment = require('moment');

  const fetchNextFromWeb = function() {
    log('Fetching scores from league');
    return league.urls().then((urls) => {
      const requests = urls.map((url) => {
        return request.get(url);
      });
      return Promise.all(requests).then((res) => {
        const next = league.Scores.parse(res);
        return Promise.resolve(next);
      });
    });
  };

  const final = (closeDB, db, res) => {
    return (closeDB ? db.end() : Promise.resolve()).then(() => {
      return Promise.resolve(res);
    });
  };

  const getFromStore = (db, allTime) => {
    let closeDB = false;
    if (!db) {
      db = require('./lib/db')();
      closeDB = true;
    }
    const sql = `
    select * from score_tweet.Leagues t1
    where League = ?
    order by id desc limit 1;`;
    log('Fetching scores from database');
    return db.query(sql, [league.leagueName]).then((res) => {
      if (!res[0]) { return final(closeDB, db, null); }

      const createdOn = moment.unix(res[0].CreatedOn);
      const timeSinceLast = moment.duration(moment().diff(createdOn));
      if (timeSinceLast.asMinutes() >= 20 && !allTime && !league.occasionalFetch) {
        console.log('Skipping because existing item is too old');
        return final(closeDB, db, null);
      }
      const scores = JSON.parse(res[0].Data);
      const oldObj = new league.Scores(scores);
      return final(closeDB, db, oldObj);
    });
  };

  const compareAndTweet = function(oldObj, newObj) {
    const changes = newObj.getChanges(oldObj, league);
    if (changes.length) {
      console.log('Found ' + changes.length + ' changes.');
    }
    if (league.seqTweet) {
      if (testObj && testObj.noTweet) {
        console.log(changes);
        return Promise.resolve();
      } else {
        return twitter.seqPost(changes);
      }
    } else {
      const tweets = _.map(changes, (status) => {
        if (testObj && testObj.noTweet) {
          console.log(status);
          return Promise.resolve();
        } else {
          return twitter.post(status);
        }
      });
      return Promise.all(tweets);
    }
  };

  const saveScores = (db, newObj) => {
    if (testObj && testObj.noSave) {
      return Promise.resolve();
    }
    if (!newObj.getScores().length) {
      console.log('No games, not saving');
      return Promise.resolve();
    }
    let closeDB = false;
    if (!db) {
      db = require('./lib/db')();
      closeDB = true;
    }
    const sql = `
    insert into score_tweet.Leagues(League,CreatedOn,\`Data\`)
    values (?,UNIX_TIMESTAMP(),?);`;
    return db.query(sql, [
      league.leagueName,
      JSON.stringify(newObj)
    ]).then(() => {
      console.log('New Item Saved');
      return final(closeDB, db, null);
    });
  };

  const cleanup = (db) => {
    if (moment().minute() !== 0) { return Promise.resolve(); }

    const threshold = moment().subtract(2, 'weeks').unix();
    const sql = 'delete from score_tweet.Leagues where League = ? and CreatedOn < ?';
    return db.query(sql, [league.leagueName, threshold]).then((res) => {
      console.log(`${res.affectedRows} rows cleaned up.`);
      return Promise.resolve();
    });
  };

  return {
    getFromStore,
    web: function(cb) {
      let nextObj = null;
      const db = require('./lib/db')();
      fetchNextFromWeb().then((res) => {
        nextObj = res;
        if (!nextObj) {
          console.log('Bad data from ' + league.urls()[0]);
          return Promise.reject('Bad data from ' + league.urls()[0]);
        }
        if (!nextObj.getScores().length) {
          return Promise.reject('No games, skipping');
        }
        return getFromStore(db);
      }).then((oldObj) => {
        if (oldObj) {
          return compareAndTweet(oldObj, nextObj);
        } else {
          return Promise.resolve();
        }
      }).then(() => {
        return saveScores(db, nextObj);
      }).then(() => {
        return cleanup(db);
      }).then(() => {
        return db.end();
      }).then(() => {
        cb(null, 'done');
      }).catch((err) => {
        console.log(err);
        return db.end().then(() => {
          if (err === 'No games, skipping') {
            cb(null, err);
          } else {
            cb(err);
          }
        });
      });
    },
    getChanges: function(cb, allTime) {
      let nextObj = null;
      const db = require('./lib/db')();
      fetchNextFromWeb().then((res) => {
        nextObj = res;
        console.log('New scores: ' + nextObj.getScores().length);
        if (!nextObj) {
          console.log('Bad data from ' + league.urls()[0]);
          return Promise.reject('Bad data from ' + league.urls()[0]);
        }
        return getFromStore(db, allTime);
      }).then((oldObj) => {
        if (oldObj) {
          console.log('Old scores: ' + oldObj.getScores().length);
          const changes = nextObj.getChanges(oldObj, league);
          if (changes.length) {
            console.log(changes);
          } else {
            console.log('No Changes');
          }
          return Promise.resolve();
        } else {
          return Promise.resolve();
        }
      }).then(() => {
        return saveScores(db, nextObj);
      }).then(() => {
        return db.end();
      }).then(() => {
        cb(null, 'done');
      }).catch((err) => {
        console.log(err);
        cb(err);
      });
    },
    fetch: function(cb) {
      fetchNextFromWeb().then((res) => {
        cb(null, res);
      }).catch((err) => {
        cb(err);
      });
    }
  };
};
<|endoftext|>


<commit_before>/*
 * PhantomJS Runner QUnit Plugin 1.1.0
 *
 * PhantomJS binaries: http://phantomjs.org/download.html
 * Requires PhantomJS 1.6+ (1.7+ recommended)
 *
 * Run with:
 *   phantomjs runner.js [url-of-your-qunit-testsuite]
 *
 * e.g.
 *   phantomjs runner.js http://localhost/qunit/test/index.html
 */

/*global phantom:false, require:false, console:false, window:false, QUnit:false */

(function() {
	'use strict';

	var url, page, timeout,
		args = require('system').args;

	// arg[0]: scriptName, args[1...]: arguments
	if (args.length < 2 || args.length > 3) {
		console.error('Usage:\n  phantomjs runner.js [url-of-your-qunit-testsuite] [timeout-in-seconds]');
		phantom.exit(1);
	}

	url = args[1];
	page = require('webpage').create();
	if (args[2] !== undefined) {
		timeout = parseInt(args[2], 10);
	}

	// Route `console.log()` calls from within the Page context to the main Phantom context (i.e. current `this`)
	page.onConsoleMessage = function(msg) {
		console.log(msg);
	};

	page.onInitialized = function() {
		page.evaluate(addLogging);
	};

	page.onCallback = function(message) {
		var result,
			failed;

		if (message) {
			if (message.name === 'QUnit.done') {
				result = message.data;
				failed = !result || !result.total || result.failed;

				if (!result.total) {
					console.error('No tests were executed. Are you loading tests asynchronously?');
				}

				phantom.exit(failed ? 1 : 0);
			}
		}
	};

	page.open(url, function(status) {
		if (status !== 'success') {
			console.error('Unable to access network: ' + status);
			phantom.exit(1);
		} else {
			// Cannot do this verification with the 'DOMContentLoaded' handler because it
			// will be too late to attach it if a page does not have any script tags.
			var qunitMissing = page.evaluate(function() { return (typeof QUnit === 'undefined' || !QUnit); });
			if (qunitMissing) {
				console.error('The `QUnit` object is not present on this page.');
				phantom.exit(1);
			}

			// Set a timeout on the test running, otherwise tests with async problems will hang forever
			if (typeof timeout === 'number') {
				setTimeout(function() {
					console.error('The specified timeout of ' + timeout + ' seconds has expired. Aborting...');
					phantom.exit(1);
				}, timeout * 1000);
			}

			// Do nothing... the callback mechanism will handle everything!
		}
	});

	function addLogging() {
		window.document.addEventListener('DOMContentLoaded', function() {
			var currentTestAssertions = [];

			QUnit.log(function(details) {
				var response;

				// Ignore passing assertions
				if (details.result) {
					return;
				}

				response = details.message || '';

				if (typeof details.expected !== 'undefined') {
					if (response) {
						response += ', ';
					}

					response += 'expected: ' + details.expected + ', but was: ' + details.actual;
				}

				if (details.source) {
					response += "\n" + details.source;
				}

				currentTestAssertions.push('Failed assertion: ' + response);
			});

			QUnit.testDone(function(result) {
				var i,
					len,
					name = '';

				if (result.module) {
					name += result.module + ': ';
				}
				name += result.name;

				if (result.failed) {
					console.log('\n' + 'Test failed: ' + name);

					for (i = 0, len = currentTestAssertions.length; i < len; i++) {
						console.log('    ' + currentTestAssertions[i]);
					}
				}

				currentTestAssertions.length = 0;
			});

			QUnit.done(function(result) {
				console.log('\n' + 'Took ' + result.runtime +  'ms to run ' + result.total + ' tests. ' + result.passed + ' passed, ' + result.failed + ' failed.');

				if (typeof window.callPhantom === 'function') {
					window.callPhantom({
						'name': 'QUnit.done',
						'data': result
					});
				}
			});
		}, false);
	}
})();<commit_msg>1.2.0<commit_after>/*
 * PhantomJS Runner QUnit Plugin 1.2.0
 *
 * PhantomJS binaries: http://phantomjs.org/download.html
 * Requires PhantomJS 1.6+ (1.7+ recommended)
 *
 * Run with:
 *   phantomjs runner.js [url-of-your-qunit-testsuite]
 *
 * e.g.
 *   phantomjs runner.js http://localhost/qunit/test/index.html
 */

/*global phantom:false, require:false, console:false, window:false, QUnit:false */

(function() {
	'use strict';

	var url, page, timeout,
		args = require('system').args;

	// arg[0]: scriptName, args[1...]: arguments
	if (args.length < 2 || args.length > 3) {
		console.error('Usage:\n  phantomjs runner.js [url-of-your-qunit-testsuite] [timeout-in-seconds]');
		phantom.exit(1);
	}

	url = args[1];
	page = require('webpage').create();
	if (args[2] !== undefined) {
		timeout = parseInt(args[2], 10);
	}

	// Route `console.log()` calls from within the Page context to the main Phantom context (i.e. current `this`)
	page.onConsoleMessage = function(msg) {
		console.log(msg);
	};

	page.onInitialized = function() {
		page.evaluate(addLogging);
	};

	page.onCallback = function(message) {
		var result,
			failed;

		if (message) {
			if (message.name === 'QUnit.done') {
				result = message.data;
				failed = !result || !result.total || result.failed;

				if (!result.total) {
					console.error('No tests were executed. Are you loading tests asynchronously?');
				}

				phantom.exit(failed ? 1 : 0);
			}
		}
	};

	page.open(url, function(status) {
		if (status !== 'success') {
			console.error('Unable to access network: ' + status);
			phantom.exit(1);
		} else {
			// Cannot do this verification with the 'DOMContentLoaded' handler because it
			// will be too late to attach it if a page does not have any script tags.
			var qunitMissing = page.evaluate(function() { return (typeof QUnit === 'undefined' || !QUnit); });
			if (qunitMissing) {
				console.error('The `QUnit` object is not present on this page.');
				phantom.exit(1);
			}

			// Set a timeout on the test running, otherwise tests with async problems will hang forever
			if (typeof timeout === 'number') {
				setTimeout(function() {
					console.error('The specified timeout of ' + timeout + ' seconds has expired. Aborting...');
					phantom.exit(1);
				}, timeout * 1000);
			}

			// Do nothing... the callback mechanism will handle everything!
		}
	});

	function addLogging() {
		window.document.addEventListener('DOMContentLoaded', function() {
			var currentTestAssertions = [];

			QUnit.log(function(details) {
				var response;

				// Ignore passing assertions
				if (details.result) {
					return;
				}

				response = details.message || '';

				if (typeof details.expected !== 'undefined') {
					if (response) {
						response += ', ';
					}

					response += 'expected: ' + details.expected + ', but was: ' + details.actual;
				}

				if (details.source) {
					response += "\n" + details.source;
				}

				currentTestAssertions.push('Failed assertion: ' + response);
			});

			QUnit.testDone(function(result) {
				var i,
					len,
					name = '';

				if (result.module) {
					name += result.module + ': ';
				}
				name += result.name;

				if (result.failed) {
					console.log('\n' + 'Test failed: ' + name);

					for (i = 0, len = currentTestAssertions.length; i < len; i++) {
						console.log('    ' + currentTestAssertions[i]);
					}
				}

				currentTestAssertions.length = 0;
			});

			QUnit.done(function(result) {
				console.log('\n' + 'Took ' + result.runtime +  'ms to run ' + result.total + ' tests. ' + result.passed + ' passed, ' + result.failed + ' failed.');

				if (typeof window.callPhantom === 'function') {
					window.callPhantom({
						'name': 'QUnit.done',
						'data': result
					});
				}
			});
		}, false);
	}
})();<|endoftext|>


<commit_before>/*
 `TARGET=xxx FOLDER=xxx npm run sample`
 找出所有 .sample 檔案, 並複製成 .js 檔案

 `TARGET=xxx FOLDER=xxx npm run sample:model`
 找出 model 相關的 .sample 檔案, 並複製成 .js 檔案

 `TARGET=xxx FOLDER=xxx npm run sample:route`
 找出 route 相關的 .sample 檔案, 並複製成 .js 檔案

 `TARGET=xxx FOLDER=xxx npm run sample.delete`
 找出所有 .sample 對應的檔案, 並移除對應的 .js 檔案

 `TARGET=xxx FOLDER=xxx npm run sample.delete:model`
 找出 model 相關的 .sample 檔案, 並移除對應的 .js 檔案

 `TARGET=xxx FOLDER=xxx npm run sample.delete:route`
 找出 route 相關的 .sample 檔案, 並移除對應的 .js 檔案
*/
const _ = require(`caro`)
const fs = require(`fs`)
const path = require(`path`)
const targetName = process.env.TARGET
const folder = process.env.FOLDER
const sampleType = process.env.SAMPLE_TYPE
const isDelete = process.env.IS_DELETE

if (!targetName) {
  console.error(`
    請輸入
    'TARGET=xxx FOLDER=xxx npm run sample'              建立相關檔案
    'TARGET=xxx FOLDER=xxx npm run sample:model'        建立 model 相關檔案
    'TARGET=xxx FOLDER=xxx npm run sample:route'        建立 route 相關檔案
    'TARGET=xxx FOLDER=xxx npm run sample.delete'       移除相關檔案
    'TARGET=xxx FOLDER=xxx npm run sample.delete:model' 移除 model 相關檔案
    'TARGET=xxx FOLDER=xxx npm run sample.delete:route' 移除 route 相關檔案
  `)
  process.exit()
}

const getFilePathFromSample = (samplePath) => {
  const dirPath = path.dirname(samplePath)
  const fileName = path.basename(samplePath)
    .replace(`__`, _.upperFirst(targetName)) // e.g. __Ctr.sample => UserCtr.sample
    .replace(`_`, targetName) // e.g. _Ctr.sample => userCtr.sample
    .replace(`.sample`, `.js`)
  const folderPath = path.join(dirPath, folder)
  if (!fs.existsSync(folderPath)) fs.mkdirSync(folderPath)
  return path.join(folderPath, fileName)
}
const createFile = (samplePath) => {
  let data = fs.readFileSync(samplePath, `utf8`)
  data = _.replaceAll(data, `$sample$`, targetName)
  data = _.replaceAll(data, `$Sample$`, _.upperFirst(targetName))

  const filePath = getFilePathFromSample(samplePath)
  fs.writeFileSync(filePath, data)
  console.log(`已建立 ${filePath}`)
}
const deleteFile = (samplePath) => {
  const filePath = getFilePathFromSample(samplePath)
  if (!fs.existsSync(filePath)) return
  fs.unlinkSync(filePath)
  console.log(`已移除 ${filePath}`)
}
const getSampleFile = (fileOrDir) => {
  fileOrDir = path.relative(`./`, fileOrDir)
  if (!fs.existsSync(fileOrDir)) return

  const stat = fs.statSync(fileOrDir)
  if (stat.isFile() && fileOrDir.endsWith(`.sample`)) {
    if (!isDelete) return createFile(fileOrDir)
    return deleteFile(fileOrDir)
  }
  if (stat.isDirectory()) {
    const fileArr = fs.readdirSync(fileOrDir)
    _.forEach(fileArr, (file) => {
      const filePath = path.join(fileOrDir, file)
      getSampleFile(filePath)
    })
  }
}

if (!sampleType) {
  getSampleFile(`route`)
  getSampleFile(`module`)
  getSampleFile(`test/spec`)
  return
}

if (sampleType === `route`) {
  getSampleFile(`route`)
  getSampleFile(`module/controller`)
  getSampleFile(`module/service`)
  getSampleFile(`test/spec/route`)
  getSampleFile(`test/spec/controller`)
  getSampleFile(`test/spec/service`)
  return
}

if (sampleType === `model`) {
  getSampleFile(`module/schema`)
  getSampleFile(`module/model`)
  getSampleFile(`test/spec/model`)
  return
}<commit_msg>更新 sample.js<commit_after>/*
 `TARGET=xxx FOLDER=xxx npm run sample`
 找出所有 .sample 檔案, 並複製成 .js 檔案

 `TARGET=xxx FOLDER=xxx npm run sample:model`
 找出 model 相關的 .sample 檔案, 並複製成 .js 檔案

 `TARGET=xxx FOLDER=xxx npm run sample:route`
 找出 route 相關的 .sample 檔案, 並複製成 .js 檔案

 `TARGET=xxx FOLDER=xxx npm run sample.delete`
 找出所有 .sample 對應的檔案, 並移除對應的 .js 檔案

 `TARGET=xxx FOLDER=xxx npm run sample.delete:model`
 找出 model 相關的 .sample 檔案, 並移除對應的 .js 檔案

 `TARGET=xxx FOLDER=xxx npm run sample.delete:route`
 找出 route 相關的 .sample 檔案, 並移除對應的 .js 檔案
*/
const _ = require(`caro`)
const fs = require(`fs`)
const path = require(`path`)
const targetName = process.env.TARGET
const folder = process.env.FOLDER
const sampleType = process.env.SAMPLE_TYPE
const isDelete = process.env.IS_DELETE

if (!targetName) {
  console.error(`
    請輸入
    'TARGET=xxx FOLDER=xxx npm run sample'              建立相關檔案
    'TARGET=xxx FOLDER=xxx npm run sample:model'        建立 model 相關檔案
    'TARGET=xxx FOLDER=xxx npm run sample:route'        建立 route 相關檔案
    'TARGET=xxx FOLDER=xxx npm run sample.delete'       移除相關檔案
    'TARGET=xxx FOLDER=xxx npm run sample.delete:model' 移除 model 相關檔案
    'TARGET=xxx FOLDER=xxx npm run sample.delete:route' 移除 route 相關檔案
  `)
  process.exit()
}

const getFilePathFromSample = (samplePath) => {
  const dirPath = path.dirname(samplePath)
  const fileName = path.basename(samplePath)
    .replace(`__`, _.upperFirst(targetName)) // e.g. __Ctr.sample => UserCtr.sample
    .replace(`_`, targetName) // e.g. _Ctr.sample => userCtr.sample
    .replace(`.sample`, `.js`)
  const folderPath = path.join(dirPath, folder)
  if (!fs.existsSync(folderPath)) fs.mkdirSync(folderPath)
  return path.join(folderPath, fileName)
}
const createFile = (samplePath) => {
  let data = fs.readFileSync(samplePath, `utf8`)
  data = _.replaceAll(data, `$sample$`, targetName)
  data = _.replaceAll(data, `$Sample$`, _.upperFirst(targetName))

  const filePath = getFilePathFromSample(samplePath)
  fs.writeFileSync(filePath, data)
  console.log(`已建立 ${filePath}`)
}
const deleteFile = (samplePath) => {
  const filePath = getFilePathFromSample(samplePath)
  if (!fs.existsSync(filePath)) return
  fs.unlinkSync(filePath)
  console.log(`已移除 ${filePath}`)
}
const getSampleFile = (fileOrDir) => {
  fileOrDir = path.relative(`./`, fileOrDir)
  if (!fs.existsSync(fileOrDir)) return

  const stat = fs.statSync(fileOrDir)
  if (stat.isFile() && fileOrDir.endsWith(`.sample`)) {
    if (!isDelete) return createFile(fileOrDir)
    return deleteFile(fileOrDir)
  }
  if (stat.isDirectory()) {
    const fileArr = fs.readdirSync(fileOrDir)
    _.forEach(fileArr, (file) => {
      const filePath = path.join(fileOrDir, file)
      getSampleFile(filePath)
    })
  }
}

if (!sampleType) {
  getSampleFile(`app/route`)
  getSampleFile(`app/module`)
  getSampleFile(`test/spec`)
  return
}

if (sampleType === `route`) {
  getSampleFile(`app/route`)
  getSampleFile(`app/module/controller`)
  getSampleFile(`app/module/service`)
  getSampleFile(`test/spec/route`)
  getSampleFile(`test/spec/controller`)
  getSampleFile(`test/spec/service`)
  return
}

if (sampleType === `model`) {
  getSampleFile(`app/model`)
  getSampleFile(`test/spec/model`)
  return
}<|endoftext|>


<commit_before>var debug = require('debug')('dataset:schema');
var _ = require('underscore');
var bson = require('bson');
var util = require('util');
var stream = require('stream');

_.templateSettings = {
  interpolate: /\{\{(.+?)\}\}/g
};

// random data
var chance = require('chance').Chance();
var faker = require('faker');

function Schema (sc) {
  if (!(this instanceof Schema)) return new Schema(sc);
  stream.Readable.call(this, {objectMode: true});
  this._document = new Document(sc, this);
  // this._context = new Context(this);
  this._state = { // serve as global state
    counter: []
  };
}
util.inherits(Schema, stream.Readable);

Schema.prototype.getRoot = function () {
  return this;
};

Schema.prototype.next = function () {
  return this._document.next();
};

Schema.prototype._read = function (n) {
  this.push(this._document.read(n));
};

// doc must be an object or an array of object
function Document (document, parent) {
  if (!(this instanceof Document)) return new Document(document, parent);
  stream.Readable.call(this, {objectMode: true});
  this._parent = parent;
  this._context = new Context(this);
  this._array = Array.isArray(document);
  this._currVal = {};
  this._children = {};
  var doc = this._array ? document[0] : document;

  for (var name in doc) {
    var data = doc[name];
    if ((Array.isArray(data) && typeof data[0] === 'object') ||
        (typeof data === 'object' && !Array.isArray(data))) {
       this._children[name] = new Document(data, this);
    } else {
       this._children[name] = new Field(data, this);
    }
    (function (method) {
      var child = this._children[method];
      Object.defineProperty(this._currVal, method, {
        enumerable: true,
        get: function () {
          if (typeof child._currVal === 'undefined') {
            return child.next();
          }
          return child._currVal;
        }
      });
    }).call(this, name);
  }
}
util.inherits(Document, stream.Readable);

Document.prototype.getRoot = function () {
  return this._parent.getRoot();
};

Document.prototype._produce = function () {
  this._clean();
  var data = {};
  for (var name in this._children) {
    data[name] = this._children[name].next();
  }
  return data;
};

Document.prototype.next = function () {
  if (this._array) {
    var data = [];
    for (var i = _.random(1, 3); i > 0; i--) {
      data.push(this._produce());
    }
    return data;
  } else {
    return this._produce();
  }
};

Document.prototype._clean = function () {
  for (var child in this._children) {
    this._children[child]._clean();
  }
};

Document.prototype._read = function (n) {
  this.push(this.next());
};

// field must be string or an array of string
function Field (field, parent) {
  if (!(this instanceof Field)) return new Field(field, parent);
  debug('building field', field);
  stream.Readable.call(this, {objectMode: true});
  this._parent = parent;
  this._array = false;
  this._field = field;
  this._passVal = undefined;
  this._currVal = undefined;
  if (Array.isArray(field)) {
    this._array = true;
    this._field = field[0];
  }
  this._compiled = _.template(this._field);
}
util.inherits(Field, stream.Readable);

Field.prototype.getRoot = function () {
  return this._parent.getRoot();
};

Field.prototype._clean = function () {
  this._currVal = undefined;
};
Field.prototype._produce = function () {
  // this.getRoot()._context._temp = {};
  // var res = this._compiled(this.getRoot()._context);
  // var alt = this.getRoot()._context._temp.override;
  this._parent._context._temp = {};
  var res = this._compiled.call(this._parent._currVal, this._parent._context);
  var alt = this._parent._context._temp.override;
  return (typeof alt === 'undefined') ? res : alt;
};

Field.prototype.next = function () {
  if (typeof this._currVal !== 'undefined') return this._currVal;
  var data;
  if (this._array) {
    data = [];
    for (var i = _.random(1, 3); i > 0; i--) {
      data.push(this._produce());
    }
  } else if (typeof this._field !== 'string') {
    data = this._field;
  } else {
    data = this._produce();
  }
  return (this._currVal = data);
};

Document.prototype._read = function (n) {
  this.push(this.next());
};

// object that will pass into _.template
function Context (host) {
  if (!(this instanceof Context)) return new Context(host);
  // security issues, what if users call _host?
  this._host = host;
  this._temp = {
    override: undefined // if present, used to override the template output
  };
  this._state = {
    // counter: []
  };
  this.util = {
    sample: _.sample
  };

  // need to add security feature
  this.chance = chance;
  this.faker = faker;
}

Context.prototype.counter = function (id, start, step) {
  id = id || 0; // though id=0 is false, does not matter
  // if (typeof this._state.counter[id] === 'undefined') {
  //   return (this._state.counter[id] = start || 0);
  // }
  // return (this._state.counter[id] += (step || 1));
  var counter = this._host.getRoot()._state.counter; //pointer
  if (typeof counter[id] === 'undefined') {
    return (counter[id] = start || 0);
  }
  return (counter[id] += (step || 1));
};

// all supported data types
Context.prototype.Double = function (i) {
  this._temp.override = Number(i);
};
Context.prototype.Boolean = function (b) {
  this._temp.override = Boolean(b);
};
Context.prototype.String = function (s) {
  this._temp.override = String(s);
};
Context.prototype.Date = function (d) {
  this._temp.override = new Date(d);
};
Context.prototype.NumberLong = function (i) {
  this._temp.override = new bson.Long(i);
};
Context.prototype.MinKey = function () {
  this._temp.override = new bson.MinKey();
};
Context.prototype.MaxKey = function () {
  this._temp.override = new bson.MaxKey();
};
Context.prototype.Timestamp = function () {
  this._temp.override = new bson.Timestamp();
};
Context.prototype.ObjectID = function (i) {
  this._temp.override = new bson.ObjectId(i);
};

module.exports = Schema;
<commit_msg>support document<commit_after>var debug = require('debug')('dataset:schema');
var _ = require('underscore');
var bson = require('bson');
var util = require('util');
var stream = require('stream');

_.templateSettings = {
  interpolate: /\{\{(.+?)\}\}/g
};

// random data
var chance = require('chance').Chance();
var faker = require('faker');

function Schema (sc) {
  if (!(this instanceof Schema)) return new Schema(sc);
  stream.Readable.call(this, {objectMode: true});
  this._document = new Document(sc, this);
  // this._context = new Context(this); // should not call Schema's context
  this._state = { // serve as global state
    counter: []
  };
}
util.inherits(Schema, stream.Readable);

Schema.prototype.getRoot = function () {
  return this;
};

Schema.prototype.next = function () {
  return this._document.next();
};

Schema.prototype._read = function (n) {
  this.push(this._document.read(n));
};

// doc must be an object or an array of object
function Document (document, parent) {
  if (!(this instanceof Document)) return new Document(document, parent);
  stream.Readable.call(this, {objectMode: true});
  this._parent = parent;
  this._context = new Context(this);
  this._array = Array.isArray(document);
  this._currVal = {};
  this._children = {};
  var doc = this._array ? document[0] : document;

  for (var name in doc) {
    var data = doc[name];
    if ((Array.isArray(data) && typeof data[0] === 'object') ||
        (typeof data === 'object' && !Array.isArray(data))) {
       this._children[name] = new Document(data, this);
    } else {
       this._children[name] = new Field(data, this);
    }
    (function (method) {
      var child = this._children[method];
      Object.defineProperty(this._currVal, method, {
        enumerable: true,
        get: function () {
          if (typeof child._currVal === 'undefined') {
            return child.next();
          }
          return child._currVal;
        }
      });
    }).call(this, name);
  }
}
util.inherits(Document, stream.Readable);

Document.prototype.getRoot = function () {
  return this._parent.getRoot();
};

Document.prototype._produce = function () {
  this._clean();
  var data = {};
  for (var name in this._children) {
    data[name] = this._children[name].next();
  }
  return data;
};

Document.prototype.next = function () {
  if (this._array) {
    var data = [];
    for (var i = _.random(1, 3); i > 0; i--) {
      data.push(this._produce());
    }
    return data;
  } else {
    return this._produce();
  }
};

Document.prototype._clean = function () {
  for (var child in this._children) {
    this._children[child]._clean();
  }
};

Document.prototype._read = function (n) {
  this.push(this.next());
};

// field must be string or an array of string
function Field (field, parent) {
  if (!(this instanceof Field)) return new Field(field, parent);
  debug('building field', field);
  stream.Readable.call(this, {objectMode: true});
  this._parent = parent;
  this._array = false;
  this._field = field;
  this._passVal = undefined;
  this._currVal = undefined;
  if (Array.isArray(field)) {
    this._array = true;
    this._field = field[0];
  }
  this._compiled = _.template(this._field);
}
util.inherits(Field, stream.Readable);

Field.prototype.getRoot = function () {
  return this._parent.getRoot();
};

Field.prototype._clean = function () {
  this._currVal = undefined;
};
Field.prototype._produce = function () {
  this._parent._context._temp = {};
  var res = this._compiled.call(this._parent._currVal, this._parent._context);
  var alt = this._parent._context._temp.override;
  return (typeof alt === 'undefined') ? res : alt;
};

Field.prototype.next = function () {
  if (typeof this._currVal !== 'undefined') return this._currVal;
  var data;
  if (this._array) {
    data = [];
    for (var i = _.random(1, 3); i > 0; i--) {
      data.push(this._produce());
    }
  } else if (typeof this._field !== 'string') {
    data = this._field;
  } else {
    data = this._produce();
  }
  return (this._currVal = data);
};

Document.prototype._read = function (n) {
  this.push(this.next());
};

// object that will pass into _.template
function Context (host) {
  if (!(this instanceof Context)) return new Context(host);
  // security issues, what if users call _host?
  this._host = host;
  this._temp = {
    override: undefined // if present, used to override the template output
  };
  this._state = {
    // counter: []
  };
  this.util = {
    sample: _.sample
  };

  // need to add security feature
  this.chance = chance;
  this.faker = faker;
}

Context.prototype.counter = function (id, start, step) {
  id = id || 0; // though id=0 is false, does not matter
  var counter = this._host.getRoot()._state.counter; //pointer
  if (typeof counter[id] === 'undefined') {
    return (counter[id] = start || 0);
  }
  return (counter[id] += (step || 1));
};

// all supported data types
Context.prototype.Double = function (i) {
  this._temp.override = Number(i);
};
Context.prototype.Boolean = function (b) {
  this._temp.override = Boolean(b);
};
Context.prototype.String = function (s) {
  this._temp.override = String(s);
};
Context.prototype.Date = function (d) {
  this._temp.override = new Date(d);
};
Context.prototype.NumberLong = function (i) {
  this._temp.override = new bson.Long(i);
};
Context.prototype.MinKey = function () {
  this._temp.override = new bson.MinKey();
};
Context.prototype.MaxKey = function () {
  this._temp.override = new bson.MaxKey();
};
Context.prototype.Timestamp = function () {
  this._temp.override = new bson.Timestamp();
};
Context.prototype.ObjectID = function (i) {
  this._temp.override = new bson.ObjectId(i);
};

module.exports = Schema;
<|endoftext|>


<commit_before>(function(){
	/*alert("aa");
	var keyboardEvent = document.createEvent("KeyboardEvent");
	var initMethod = typeof keyboardEvent.initKeyboardEvent !== 'undefined' ? "initKeyboardEvent" : "initKeyEvent";

	keyboardEvent[initMethod](
		"keyup",
		true,
		true,
		window,
		false,
		false,
		false,
		false,
		68,
		0
	);
	document.dispatchEvent(keyboardEvent);*/
	//var body = document.getElementsByTagName('body');
	//alert("aa");
	/*var thumb_up_div = document.createElement('div');
	thumb_up_div.id = 'thumb_up_div';
	thumb_up_div.style.cssText = 'position:fixed;top:100px;left:300px;width:400px;height:400px;display:block; background: url("http://127.0.0.1/thumbup.png") no-repeat;}';           // No setAttribute required

	//msgContainer.appendChild(document.createTextNode(msg));
	document.body.appendChild(thumb_up_div);
	setTimeout(function(){ y=document.getElementById('thumb_up_div');document.body.removeChild(y); }, 1000);*/

	/*
		A, D - keyup
		W, S - keydown
	*/

	var pressButton = function(button, event, image){
		var charCode = button.toUpperCase().charCodeAt(0);
		console.log(charCode);
		var keyboardEvent = document.createEvent("KeyboardEvent");
		var initMethod = typeof keyboardEvent.initKeyboardEvent !== 'undefined' ? "initKeyboardEvent" : "initKeyEvent";
		keyboardEvent[initMethod](event, true, true, window, false, false, false, false, charCode, 0);
		document.dispatchEvent(keyboardEvent);

		addNotification(image);
	}
	var addNotification = function(image){
		if(image != null){
			var thumb_up_div = document.createElement('div');
			thumb_up_div.id = 'thumb_up_div';
			thumb_up_div.style.cssText = 'position:fixed;top:100px;left:30%;width:400px;height:400px;display:block; background: url("http://127.0.0.1/'+image+'.png") no-repeat;}';
			document.body.appendChild(thumb_up_div);
			setTimeout(function(){ document.body.removeChild(thumb_up_div); }, 1000);
		}
	}

	pressButton('w', 'keydown', 'thumbup');
})();
<commit_msg>url addes assets<commit_after>(function(){
	/*alert("aa");
	var keyboardEvent = document.createEvent("KeyboardEvent");
	var initMethod = typeof keyboardEvent.initKeyboardEvent !== 'undefined' ? "initKeyboardEvent" : "initKeyEvent";

	keyboardEvent[initMethod](
		"keyup",
		true,
		true,
		window,
		false,
		false,
		false,
		false,
		68,
		0
	);
	document.dispatchEvent(keyboardEvent);*/
	//var body = document.getElementsByTagName('body');
	//alert("aa");
	/*var thumb_up_div = document.createElement('div');
	thumb_up_div.id = 'thumb_up_div';
	thumb_up_div.style.cssText = 'position:fixed;top:100px;left:300px;width:400px;height:400px;display:block; background: url("http://127.0.0.1/thumbup.png") no-repeat;}';           // No setAttribute required

	//msgContainer.appendChild(document.createTextNode(msg));
	document.body.appendChild(thumb_up_div);
	setTimeout(function(){ y=document.getElementById('thumb_up_div');document.body.removeChild(y); }, 1000);*/

	/*
		A, D - keyup
		W, S - keydown
	*/

	var pressButton = function(button, event, image){
		var charCode = button.toUpperCase().charCodeAt(0);
		console.log(charCode);
		var keyboardEvent = document.createEvent("KeyboardEvent");
		var initMethod = typeof keyboardEvent.initKeyboardEvent !== 'undefined' ? "initKeyboardEvent" : "initKeyEvent";
		keyboardEvent[initMethod](event, true, true, window, false, false, false, false, charCode, 0);
		document.dispatchEvent(keyboardEvent);

		addNotification(image);
	}
	var addNotification = function(image){
		if(image != null){
			var thumb_up_div = document.createElement('div');
			thumb_up_div.id = 'thumb_up_div';
			thumb_up_div.style.cssText = 'position:fixed;top:100px;left:30%;width:400px;height:400px;display:block; background: url("http://127.0.0.1/assets/'+image+'.png") no-repeat;}';
			document.body.appendChild(thumb_up_div);
			setTimeout(function(){ document.body.removeChild(thumb_up_div); }, 1000);
		}
	}

	pressButton('w', 'keydown', 'thumbup');
})();
<|endoftext|>


<commit_before>window.onload = function() {
    wrap();
    linkFix();
}

function wrap() {
    $(this).addClass('r');
    $('body').addClass('wrapped');
    $('p').each(function(){
        var text = $(this).html().split(' '),
            len = text.length,
            result = [];
        for( var i = 0; i < len; i++ ) {
            if(text[i].indexOf('>') != -1 || text[i].indexOf('<') != -1 || text[i].indexOf('"') != -1 || text[i].indexOf('"') != -1) {
                if(text[i].indexOf('>') != -1) {
                    result[i] = text[i] + " ";
                }
                else {
                    result[i] =  text[i] + " ";
                }
            }
            else if (text[i] == '  ') {

            }
            else {
                result[i] = '' + text[i] + ' ';
            }
        }
        $(this).html(result.join(''));
    });
    wiggle();
}

function wiggle() {
    setInterval(function() {
        var width = window.innerWidth;
        var height = window.innerHeight;
        var texts = $('.r').length;
        for(var i = 0; i < texts+1; i++) {
            var randX = Math.sin(1/Math.floor((Math.random() * 5) + 1)*i);
            var randY = Math.sin(1/Math.floor((Math.random() * 5) + 1)*i);
            var x = randX;
            var y = randY;
            var xy = randX/randY;
            $('.r').eq(i).transition({rotateX:x, rotateY:y, x:x, y:y}, 100);
        }
    },100);
}
function linkFix() {
    $('a').click(function() {
        var url = $(this).attr('href');
        window.open(url,'_blank');
    });
}<commit_msg>hover fix and simpler values<commit_after>window.onload = function() {
    wrap();
}

function wrap() {
    $(this).addClass('r');
    $('body').addClass('wrapped');
    $('p').each(function(){
        var text = $(this).html().split(' '),
            len = text.length,
            result = [];
        for( var i = 0; i < len; i++ ) {
            if(text[i].indexOf('>') != -1 || text[i].indexOf('<') != -1 || text[i].indexOf('"') != -1 || text[i].indexOf('"') != -1) {
                if(text[i].indexOf('>') != -1) {
                    result[i] = text[i] + " ";
                }
                else {
                    result[i] =  text[i] + " ";
                }
            }
            else if (text[i] == '  ') {

            }
            else {
                result[i] = '' + text[i] + ' ';
            }
        }
        $(this).html(result.join(''));
    });
    wiggle();
}

function wiggle() {
    setInterval(function() {
        var width = window.innerWidth;
        var height = window.innerHeight;
        var texts = $('.r').length;
        for(var i = 0; i < texts+1; i++) {
            var x = (Math.floor((Math.random() * 3) + 1)) * (Math.round(Math.random()) * 2 - 1);
            var y = (Math.floor((Math.random() * 3) + 1)) * (Math.round(Math.random()) * 2 - 1);
            var z = (Math.floor((Math.random() * 3) + 1)) * (Math.round(Math.random()) * 2 - 1);
            console.log(x,y,z);
            if($('.r').eq(i).ismouseover() && $('.r').eq(i).attr('href')) {
                $('.r').eq(i).transition({x:x*2, y:y*2, rotate:z*2}, 50);
            }
            else {
                $('.r').eq(i).transition({x:x, y:y, rotate:z}, 100);
            }
        }
    },100);
}

// ismousover() plugin by Subin Siby
$.mlp ={x:0,y:0};function documentHandler(){var $current =this=== document ? $(this): $(this).contents(); $current.mousemove(function(e){jQuery.mlp ={x:e.pageX,y:e.pageY}}); $current.find("iframe").load(documentHandler);}$(documentHandler); $.fn.ismouseover =function(overThis){var result =false;this.eq(0).each(function(){var $current = $(this).is("iframe")? $(this).contents().find("body"): $(this);var offset = $current.offset(); result
result = offset.left<=$.mlp.x && offset.left + $current.outerWidth()> $.mlp.x && offset.top<=$.mlp.y && offset.top + $current.outerHeight()> $.mlp.y;});return result;};<|endoftext|>


<commit_before>/***
MIT License

Copyright (c) 2017 Bruno Baère Pederassi Lomba de Araujo

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
***/

var myChart;

function computeRolls(dice, amount) {
    var diceRolls = [];

    // Initializes the array
    for (var i = 0; i < 10000; ++i) {
        diceRolls[i] = 0
    }

    for (var i = 0; i < 10000; ++i) {
        for (var j = 0; j < amount; ++j) {
            diceRolls[i] += math.randomInt(1, parseInt(dice) + 1);
        }
    }

    return diceRolls;
}

function computeHistogram(diceRolls) {
    var histogram = [];

    var diceTypeList = document.getElementById("dicetype");
    var diceType = diceTypeList.options[diceTypeList.selectedIndex].value;
    var minValue = document.getElementById("diceamount").value;
    var maxValue = minValue * diceType

    for (var i = minValue; i <= maxValue; ++i)
    {
        histogram[i] = 0
    }

    for (var i = 0; i < diceRolls.length; ++i) {
        histogram[diceRolls[i]]++;
    }

    //Normalizing
    for (var i = 0; i < histogram.length; ++i){
        histogram[i] = histogram[i];
    }

    return histogram;
}

function generateChart() {
    var diceTypeList = document.getElementById("dicetype");
    var diceType = diceTypeList.options[diceTypeList.selectedIndex].value;
    var diceNumber = document.getElementById("diceamount").value;
    var diceRolls = computeRolls(diceType, diceNumber);
    var histogram = computeHistogram(diceRolls);

    // Creates chart labels based on dice thrown
    var resultLabels = [];
    for (var i = 0; i <= diceNumber * diceType; i++)
    {
        resultLabels.push( i.toString() );
    }

    var div = document.getElementById("chartdiv");
    var context = document.getElementById("DiceRollChart");

    // Cleans chart if already created
    if (myChart != null)
        myChart.destroy();

    myChart = new Chart(context, {
        type: 'bar',
        data: {
            labels: resultLabels,
            datasets: [{
                label: 'Result Probability',
                data: histogram,
                borderWidth: 1
            }]
        },
        options: {
            scales: {
                yAxes: [{
                    ticks: {
                        beginAtZero: true
                    }
                }]
            },
            responsive: true
        }
    });
}
<commit_msg>Draw probability curve<commit_after>/***
MIT License

Copyright (c) 2017 Bruno Baère Pederassi Lomba de Araujo

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
***/

var myChart;
var rolls = 5000;

function computeRolls(dice, amount) {
    var diceRolls = [];
    var diceValue = parseInt(dice) + 1;

    // Initializes the array
    for (var i = 0; i < rolls; ++i) {
        diceRolls[i] = 0
    }

    for (var i = 0; i < rolls; ++i) {
        for (var j = 0; j < amount; ++j) {
            diceRolls[i] += math.randomInt(1, diceValue);
        }
    }

    return diceRolls;
}

function computeHistogram(diceRolls) {
    var histogram = [];

    var diceTypeList = document.getElementById("dicetype");
    var diceType = diceTypeList.options[diceTypeList.selectedIndex].value;
    var minValue = document.getElementById("diceamount").value;
    var maxValue = minValue * diceType

    for (var i = minValue; i <= maxValue; ++i)
    {
        histogram[i] = 0
    }

    for (var i = 0; i < diceRolls.length; ++i) {
        histogram[diceRolls[i]]++;
    }

    //Normalizing
    for (var i = 0; i < histogram.length; ++i){
        histogram[i] = 100*histogram[i]/rolls;
    }

    return histogram;
}

function generateChart() {
    var diceTypeList = document.getElementById("dicetype");
    var diceType = diceTypeList.options[diceTypeList.selectedIndex].value;
    var diceNumber = document.getElementById("diceamount").value;
    var diceRolls = computeRolls(diceType, diceNumber);
    var histogram = computeHistogram(diceRolls);

    // Creates chart labels based on dice thrown
    var resultLabels = [];
    for (var i = 0; i <= diceNumber * diceType; i++)
    {
        resultLabels.push( i.toString() );
    }

    var div = document.getElementById("chartdiv");
    var context = document.getElementById("DiceRollChart");

    // Cleans chart if already created
    if (myChart != null)
        myChart.destroy();

    myChart = new Chart(context,
    {
        type: 'bar',
        data: {
            labels: resultLabels,
            datasets: [
            {
                label: 'Result Probability',
                data: histogram,
                borderWidth: 1
            },
            {
                label: 'Probability curve',
                data: histogram,
                cubicInterpolationMode: 'monotone',
                backgroundColor: 'rgba(1,0,0,0)',
                type: 'line'
            }
            ]
        },
        options: {
            scales: {
                yAxes: [{
                    ticks: {
                        beginAtZero: true
                    }
                }]
            },
            responsive: true
        }
    });
}
<|endoftext|>