<commit_before>define(function() {

return {

  // The following palette description
  // is copied from compiled CoffeeScript.
  COFFEESCRIPT_PALETTE: [
    {
      name: 'Move',
      color: 'red',
      blocks: [
        {
          block: 'fd 100',
          title: 'Move forward'
        }, {
          block: 'rt 90',
          title: 'Turn right'
        }, {
          block: 'lt 90',
          title: 'Turn left'
        }, {
          block: 'bk 100',
          title: 'Move backward'
        }, {
          block: 'rt 180, 100',
          title: 'Make a wide right arc'
        }, {
          block: 'lt 180, 100',
          title: 'Make a wide left arc'
        }, {
          block: 'speed 10',
          title: 'Set the speed of the turtle'
        }, {
          block: 'speed Infinity',
          title: 'Use infinite speed'
        }, {
          block: 'home()',
          title: 'Jump to the origin, turned up'
        }, {
          block: 'turnto 270',
          title: 'Turn to an absolute direction'
        }, {
          block: 'turnto lastclick',
          title: 'Turn toward a located object'
        }, {
          block: 'moveto 100, 50',
          title: 'Move to coordinates'
        }, {
          block: 'movexy 30, 20',
          title: 'Move by changing x and y'
        }, {
          block: 'move 10, 5',
          title: "Move sideways or diagonal from turtle's angle"
        }, {
          block: 'jumpto 100, 50',
          title: 'Jump to coordinates without drawing'
        }, {
          block: 'jumpxy 30, 20',
          title: 'Jump changing x and y without drawing'
        }, {
          block: 'jump 10, 5',
          title: "Move sideways or diagonal without drawing"
        }
      ]
    }, {
      name: 'Control',
      color: 'orange',
      blocks: [
        {
          block: 'for [1..3]\n  ``',
          title: 'Do something multiple times'
        }, {
          block: 'if `` is ``\n  ``',
          title: 'Do something only if a condition is true'
        }, {
          block: 'if `` is ``\n  ``\nelse\n  ``',
          title: 'Do something if a condition is true, otherwise something else'
        }, {
          block: "tick 1, ->\n  write 'ticked'",
          title: 'Repeat something forever at qually-spaced times'
        }, {
          block: "button \'Click\', ->\n  write 'clicked'",
          title: 'Make a button and do something when clicked'
        }, {
          block: "keydown \'X\', ->\n  write 'x pressed'",
          title: 'Do something when a keyboard key is pressed'
        }, {
          block: "click (e) ->\n  moveto e",
          title: 'Move to a location when document is clicked'
        }
      ]
    }, {
      name: 'Looks',
      color: 'blue',
      blocks: [
         {
          block: 'pen purple, 10',
          title: 'Set pen color and size'
        }, {
          block: 'dot green, 50',
          title: 'Make a dot'
        }, {
          block: 'box yellow, 50',
          title: 'Make a square'
        }, {
          block: 'fill blue',
          title: 'Fill traced shape'
        }, {
          block: 'wear \'/img/apple\'',
          title: 'Use an image for the turtle'
        }, {
          block: 'scale 3',
          title: 'Scale turtle drawing'
        }, {
          block: 'ht()',
          title: 'Hide the main turtle'
        }, {
          block: 'st()',
          title: 'Show the main turtle'
        }, {
          block: 'cs()',
          title: 'Clear screen'
        }, {
          block: 'cg()',
          title: 'Clear graphics'
        }, {
          block: 'pu()',
          title: 'Lift the pen up'
        }, {
          block: 'pd()',
          title: 'Put the pen down'
        }, {
          block: 'drawon s',
          title: 'Draw on sprite s'
        }, {
          block: 'drawon document',
          title: 'Draw on the document'
        }
      ]
    }, {
      name: 'Operators',
      color: 'green',
      blocks: [
        {
          block: 'x = ``',
          title: 'Set a variable'
        }, {
          block: '`` is ``',
          title: 'Compare two values'
        }, {
          block: '`` < ``',
          title: 'Compare two values'
        }, {
          block: '`` > ``',
          title: 'Compare two values'
        }, {
          block: '`` + ``',
          title: 'Add two numbers'
        }, {
          block: '`` - ``',
          title: 'Subtract two numbers'
        }, {
          block: '`` * ``',
          title: 'Multiply two numbers'
        }, {
          block: '`` / ``',
          title: 'Divide two numbers'
        }, {
          block: 'random [1..100]',
          title: 'Get a random number in a range'
        }, {
          block: 'round ``',
          title: 'Round to the nearest integer'
        }, {
          block: 'abs ``',
          title: 'Absolute value'
        }, {
          block: 'max ``, ``',
          title: 'Get the larger of two numbers'
        }, {
          block: 'min ``, ``',
          title: 'Get the smaller on two numbers'
        }, {
          block: 'x.match /pattern/',
          title: 'Test if a text pattern is found in x'
        }, {
          block: 'f = (x) ->\n  ``',
          title: 'Define a new function'
        }, {
          block: 'f(x)',
          title: 'Use a custom function'
        }
      ]
    }, {
      name: 'Text',
      color: 'yellow',
      blocks: [
        {
          block: 'write \'Hello.\'',
          title: 'Write text in the document'
        }, {
          block: 'type \'zz*(-.-)*zz\'',
          title: 'Typewrite text in the document'
        }, {
          block: 'label \'spot\'',
          title: 'Write text at the turtle'
        }, {
          block: 'read \'?\', (x) ->\n  write x',
          title: 'Read input from the user'
        }, {
          block: 'readnum \'?\', (x) ->\n  write x',
          title: 'Read a number from the user'
        }, {
          block: 'log [1..10]',
          title: 'Log an object to debug'
        }
      ]
    }, {
      name: 'Sprites',
      color: 'violet',
      blocks: [
        {
          block: 't = new Turtle red',
          title: 'Make a new turtle'
        }, {
          block: 's = new Sprite',
          title: 'Make a blank sprite'
        }, {
          block: 'p = new Piano',
          title: 'Make a visible insturment'
        }, {
          block: 'p.play \'CDEDC\'',
          title: 'Play and show music notes'
        }, {
          block: 'q = new Pencil',
          title: 'Make an invisible and fast drawing sprite'
        }
      ]
    }, {
      name: 'Sound',
      color: 'violet',
      blocks: [
        {
          block: 'p.play \'CDEDC\'',
          title: 'Play and show music notes'
        }
      ]
    }, {
      name: 'Snippets',
      color: 'yellow',
      blocks: [
        {
          block: "tick 10, ->\n  if pressed 'W'\n    fd 2",
          title: 'Poll a key and move while it is depressed'
        }, {
          block: "click (e) ->\n  moveto e",
          title: 'Move to a location when document is clicked'
        }
      ]
    }
  ],

  JAVASCRIPT_PALETTE: [
    {
      name: 'Draw',
      color: 'blue',
      blocks: [
        {
          block: 'pen(red);',
          title: 'Set the pen color'
        }, {
          block: 'fd(100);',
          title: 'Move forward'
        }, {
          block: 'rt(90);',
          title: 'Turn right'
        }, {
          block: 'lt(90);',
          title: 'Turn left'
        }, {
          block: 'bk(100);',
          title: 'Move backward'
        }, {
          block: 'speed(10);',
          title: 'Set the speed of the turtle'
        }, {
          block: 'dot(blue, 50);',
          title: 'Make a dot'
        }, {
          block: 'box(green, 50);',
          title: 'Make a square'
        }, {
          block: 'write(\'hello\');',
          title: 'Write text on the screen'
        }, {
          block: 'label(\'hello\');',
          title: 'Write text at the turtle'
        }, {
          block: 'ht();',
          title: 'Hide the turtle'
        }, {
          block: 'st();',
          title: 'Show the turtle'
        }, {
          block: 'pu();',
          title: 'Pick the pen up'
        }, {
          block: 'pd();',
          title: 'Put the pen down'
        }, {
          block: 'pen(purple, 10);',
          title: 'Set the pen color and thickness'
        }, {
          block: 'rt(180, 100);',
          title: 'Make a wide right turn'
        }, {
          block: 'lt(180, 100);',
          title: 'Make a wide left turn'
        }, {
          block: 'slide(100, 20);',
          title: 'Slide sideways or diagonally'
        }, {
          block: 'jump(100, 20);',
          title: 'Jump without drawing'
        }, {
          block: 'play(\'GEC\');',
          title: 'Play music notes'
        }, {
          block: 'wear(\'/img/cat-icon\');',
          title: 'Change the turtle image'
        }
      ]
    }, {
      name: 'Control',
      color: 'orange',
      blocks: [
        {
          block: 'for (var i = 0; i < 4; i++) {\n  __;\n}',
          title: 'Do something multiple times'
        }, {
          block: 'if (__) {\n  __;\n}',
          title: 'Do something only if a condition is true'
        }, {
          block: 'if (__) {\n  __;\n} else {\n  __;\n}',
          title: 'Do something if a condition is true, otherwise do something else'
        }, {
          block: 'while (__) {\n  __;\n}',
          title: 'Repeat something while a condition is true'
        }
      ]
    }, {
      name: 'Math',
      color: 'green',
      blocks: [
        {
          block: 'var x = __;',
          title: 'Create a variable for the first time'
        }, {
          block: 'x = __;',
          title: 'Reassign a variable'
        }, {
          block: '__ + __',
          title: 'Add two numbers'
        }, {
          block: '__ - __',
          title: 'Subtract two numbers'
        }, {
          block: '__ * __',
          title: 'Multiply two numbers'
        }, {
          block: '__ / __',
          title: 'Divide two numbers'
        }, {
          block: '__ === __',
          title: 'Compare two numbers'
        }, {
          block: '__ > __',
          title: 'Compare two numbers'
        }, {
          block: '__ < __',
          title: 'Compare two numbers'
        }, {
          block: 'random(1, 100)',
          title: 'Get a random number in a range'
        }, {
          block: 'round(__)',
          title: 'Round to the nearest integer'
        }, {
          block: 'abs(__)',
          title: 'Absolute value'
        }, {
          block: 'max(__, __)',
          title: 'Absolute value'
        }, {
          block: 'min(__, __)',
          title: 'Absolute value'
        }
      ]
    }, {
      name: 'Functions',
      color: 'violet',
      blocks: [
        {
          block: 'function myFunction() {\n  __;\n}',
          title: 'Create a function without an argument'
        }, {
          block: 'function myFunction(n) {\n  __;\n}',
          title: 'Create a function with an argument'
        }, {
          block: 'myFunction()',
          title: 'Use a function without an argument'
        }, {
          block: 'myFunction(n)',
          title: 'Use a function with argument'
        }
      ]
    }
  ]
};

});
<commit_msg>Remove p.play from Sprites menu<commit_after>define(function() {

return {

  // The following palette description
  // is copied from compiled CoffeeScript.
  COFFEESCRIPT_PALETTE: [
    {
      name: 'Move',
      color: 'red',
      blocks: [
        {
          block: 'fd 100',
          title: 'Move forward'
        }, {
          block: 'rt 90',
          title: 'Turn right'
        }, {
          block: 'lt 90',
          title: 'Turn left'
        }, {
          block: 'bk 100',
          title: 'Move backward'
        }, {
          block: 'rt 180, 100',
          title: 'Make a wide right arc'
        }, {
          block: 'lt 180, 100',
          title: 'Make a wide left arc'
        }, {
          block: 'speed 10',
          title: 'Set the speed of the turtle'
        }, {
          block: 'speed Infinity',
          title: 'Use infinite speed'
        }, {
          block: 'home()',
          title: 'Jump to the origin, turned up'
        }, {
          block: 'turnto 270',
          title: 'Turn to an absolute direction'
        }, {
          block: 'turnto lastclick',
          title: 'Turn toward a located object'
        }, {
          block: 'moveto 100, 50',
          title: 'Move to coordinates'
        }, {
          block: 'movexy 30, 20',
          title: 'Move by changing x and y'
        }, {
          block: 'move 10, 5',
          title: "Move sideways or diagonal from turtle's angle"
        }, {
          block: 'jumpto 100, 50',
          title: 'Jump to coordinates without drawing'
        }, {
          block: 'jumpxy 30, 20',
          title: 'Jump changing x and y without drawing'
        }, {
          block: 'jump 10, 5',
          title: "Move sideways or diagonal without drawing"
        }
      ]
    }, {
      name: 'Control',
      color: 'orange',
      blocks: [
        {
          block: 'for [1..3]\n  ``',
          title: 'Do something multiple times'
        }, {
          block: 'if `` is ``\n  ``',
          title: 'Do something only if a condition is true'
        }, {
          block: 'if `` is ``\n  ``\nelse\n  ``',
          title: 'Do something if a condition is true, otherwise something else'
        }, {
          block: "tick 1, ->\n  write 'ticked'",
          title: 'Repeat something forever at qually-spaced times'
        }, {
          block: "button \'Click\', ->\n  write 'clicked'",
          title: 'Make a button and do something when clicked'
        }, {
          block: "keydown \'X\', ->\n  write 'x pressed'",
          title: 'Do something when a keyboard key is pressed'
        }, {
          block: "click (e) ->\n  moveto e",
          title: 'Move to a location when document is clicked'
        }
      ]
    }, {
      name: 'Looks',
      color: 'blue',
      blocks: [
         {
          block: 'pen purple, 10',
          title: 'Set pen color and size'
        }, {
          block: 'dot green, 50',
          title: 'Make a dot'
        }, {
          block: 'box yellow, 50',
          title: 'Make a square'
        }, {
          block: 'fill blue',
          title: 'Fill traced shape'
        }, {
          block: 'wear \'/img/apple\'',
          title: 'Use an image for the turtle'
        }, {
          block: 'scale 3',
          title: 'Scale turtle drawing'
        }, {
          block: 'ht()',
          title: 'Hide the main turtle'
        }, {
          block: 'st()',
          title: 'Show the main turtle'
        }, {
          block: 'cs()',
          title: 'Clear screen'
        }, {
          block: 'cg()',
          title: 'Clear graphics'
        }, {
          block: 'pu()',
          title: 'Lift the pen up'
        }, {
          block: 'pd()',
          title: 'Put the pen down'
        }, {
          block: 'drawon s',
          title: 'Draw on sprite s'
        }, {
          block: 'drawon document',
          title: 'Draw on the document'
        }
      ]
    }, {
      name: 'Operators',
      color: 'green',
      blocks: [
        {
          block: 'x = ``',
          title: 'Set a variable'
        }, {
          block: '`` is ``',
          title: 'Compare two values'
        }, {
          block: '`` < ``',
          title: 'Compare two values'
        }, {
          block: '`` > ``',
          title: 'Compare two values'
        }, {
          block: '`` + ``',
          title: 'Add two numbers'
        }, {
          block: '`` - ``',
          title: 'Subtract two numbers'
        }, {
          block: '`` * ``',
          title: 'Multiply two numbers'
        }, {
          block: '`` / ``',
          title: 'Divide two numbers'
        }, {
          block: 'random [1..100]',
          title: 'Get a random number in a range'
        }, {
          block: 'round ``',
          title: 'Round to the nearest integer'
        }, {
          block: 'abs ``',
          title: 'Absolute value'
        }, {
          block: 'max ``, ``',
          title: 'Get the larger of two numbers'
        }, {
          block: 'min ``, ``',
          title: 'Get the smaller on two numbers'
        }, {
          block: 'x.match /pattern/',
          title: 'Test if a text pattern is found in x'
        }, {
          block: 'f = (x) ->\n  ``',
          title: 'Define a new function'
        }, {
          block: 'f(x)',
          title: 'Use a custom function'
        }
      ]
    }, {
      name: 'Text',
      color: 'yellow',
      blocks: [
        {
          block: 'write \'Hello.\'',
          title: 'Write text in the document'
        }, {
          block: 'type \'zz*(-.-)*zz\'',
          title: 'Typewrite text in the document'
        }, {
          block: 'label \'spot\'',
          title: 'Write text at the turtle'
        }, {
          block: 'read \'?\', (x) ->\n  write x',
          title: 'Read input from the user'
        }, {
          block: 'readnum \'?\', (x) ->\n  write x',
          title: 'Read a number from the user'
        }, {
          block: 'log [1..10]',
          title: 'Log an object to debug'
        }
      ]
    }, {
      name: 'Sprites',
      color: 'violet',
      blocks: [
        {
          block: 't = new Turtle red',
          title: 'Make a new turtle'
        }, {
          block: 's = new Sprite',
          title: 'Make a blank sprite'
        }, {
          block: 'p = new Piano',
          title: 'Make a visible insturment'
        }, {
          block: 'q = new Pencil',
          title: 'Make an invisible and fast drawing sprite'
        }
      ]
    }, {
      name: 'Sound',
      color: 'violet',
      blocks: [
        {
          block: 'p.play \'CDEDC\'',
          title: 'Play and show music notes'
        }
      ]
    }, {
      name: 'Snippets',
      color: 'yellow',
      blocks: [
        {
          block: "tick 10, ->\n  if pressed 'W'\n    fd 2",
          title: 'Poll a key and move while it is depressed'
        }, {
          block: "click (e) ->\n  moveto e",
          title: 'Move to a location when document is clicked'
        }
      ]
    }
  ],

  JAVASCRIPT_PALETTE: [
    {
      name: 'Draw',
      color: 'blue',
      blocks: [
        {
          block: 'pen(red);',
          title: 'Set the pen color'
        }, {
          block: 'fd(100);',
          title: 'Move forward'
        }, {
          block: 'rt(90);',
          title: 'Turn right'
        }, {
          block: 'lt(90);',
          title: 'Turn left'
        }, {
          block: 'bk(100);',
          title: 'Move backward'
        }, {
          block: 'speed(10);',
          title: 'Set the speed of the turtle'
        }, {
          block: 'dot(blue, 50);',
          title: 'Make a dot'
        }, {
          block: 'box(green, 50);',
          title: 'Make a square'
        }, {
          block: 'write(\'hello\');',
          title: 'Write text on the screen'
        }, {
          block: 'label(\'hello\');',
          title: 'Write text at the turtle'
        }, {
          block: 'ht();',
          title: 'Hide the turtle'
        }, {
          block: 'st();',
          title: 'Show the turtle'
        }, {
          block: 'pu();',
          title: 'Pick the pen up'
        }, {
          block: 'pd();',
          title: 'Put the pen down'
        }, {
          block: 'pen(purple, 10);',
          title: 'Set the pen color and thickness'
        }, {
          block: 'rt(180, 100);',
          title: 'Make a wide right turn'
        }, {
          block: 'lt(180, 100);',
          title: 'Make a wide left turn'
        }, {
          block: 'slide(100, 20);',
          title: 'Slide sideways or diagonally'
        }, {
          block: 'jump(100, 20);',
          title: 'Jump without drawing'
        }, {
          block: 'play(\'GEC\');',
          title: 'Play music notes'
        }, {
          block: 'wear(\'/img/cat-icon\');',
          title: 'Change the turtle image'
        }
      ]
    }, {
      name: 'Control',
      color: 'orange',
      blocks: [
        {
          block: 'for (var i = 0; i < 4; i++) {\n  __;\n}',
          title: 'Do something multiple times'
        }, {
          block: 'if (__) {\n  __;\n}',
          title: 'Do something only if a condition is true'
        }, {
          block: 'if (__) {\n  __;\n} else {\n  __;\n}',
          title: 'Do something if a condition is true, otherwise do something else'
        }, {
          block: 'while (__) {\n  __;\n}',
          title: 'Repeat something while a condition is true'
        }
      ]
    }, {
      name: 'Math',
      color: 'green',
      blocks: [
        {
          block: 'var x = __;',
          title: 'Create a variable for the first time'
        }, {
          block: 'x = __;',
          title: 'Reassign a variable'
        }, {
          block: '__ + __',
          title: 'Add two numbers'
        }, {
          block: '__ - __',
          title: 'Subtract two numbers'
        }, {
          block: '__ * __',
          title: 'Multiply two numbers'
        }, {
          block: '__ / __',
          title: 'Divide two numbers'
        }, {
          block: '__ === __',
          title: 'Compare two numbers'
        }, {
          block: '__ > __',
          title: 'Compare two numbers'
        }, {
          block: '__ < __',
          title: 'Compare two numbers'
        }, {
          block: 'random(1, 100)',
          title: 'Get a random number in a range'
        }, {
          block: 'round(__)',
          title: 'Round to the nearest integer'
        }, {
          block: 'abs(__)',
          title: 'Absolute value'
        }, {
          block: 'max(__, __)',
          title: 'Absolute value'
        }, {
          block: 'min(__, __)',
          title: 'Absolute value'
        }
      ]
    }, {
      name: 'Functions',
      color: 'violet',
      blocks: [
        {
          block: 'function myFunction() {\n  __;\n}',
          title: 'Create a function without an argument'
        }, {
          block: 'function myFunction(n) {\n  __;\n}',
          title: 'Create a function with an argument'
        }, {
          block: 'myFunction()',
          title: 'Use a function without an argument'
        }, {
          block: 'myFunction(n)',
          title: 'Use a function with argument'
        }
      ]
    }
  ]
};

});
<|endoftext|>


<commit_before>window.DOM = {

  isSubmittable: function(element) {
    if (!element) {
      return false;
    }
    if (element.localName !== 'input')
      return false;
    if (element.hasAttribute('submit'))
      return true;
    while (element = element.parentElement) {
      if (element.localName === 'form')
        return true;
    }
    return false;
  },

  isEditable: function(element) {
    if (!element) {
      return false;
    }
    if (element.localName === 'textarea' ||
        element.hasAttribute('contenteditable'))
      return true;
    if (element.localName !== 'input')
      return false;
    var type = element.getAttribute('type');
    switch (type) {
    case 'button':
    case 'checkbox':
    case 'color':
    case 'file':
    case 'hidden':
    case 'image':
    case 'radio':
    case 'reset':
    case 'submit':
    case 'week':
      return false;
    }
    return true;
  },

  isTextElement: function(element) {
    if (!element) {
      return false;
    }
    if (element.localName === 'input' || element.localName === 'textarea') {
      return true;
    }
    while (element) {
      if (element.isContentEditable) {
        return true;
      }
      element = element.parentElement;
    }
    return false;
  },

  onTitleChange: function(callback) {
    waitForLoad(function() {
      var title = (document.getElementsByTagName('title') || [])[0];
      if (!title) {
        return;
      }
      new MutationObserver(function() {
        callback(title.textContent);
      }).observe(title, {
        childList: true
      });
    });
  },

  /**
   * Retrieves the proper boundingRect of an element if it is visible on-screen.
   * @return boundingRect or null (if element is not visible on-screen)
   */
  getVisibleBoundingRect: function(node) {
    var i;
    var boundingRect = node.getClientRects()[0] || node.getBoundingClientRect();
    if (boundingRect.width <= 1 && boundingRect.height <= 1) {
      var rects = node.getClientRects();
      for (i = 0; i < rects.length; i++) {
        if (rects[i].width > rects[0].height && rects[i].height > rects[0].height) {
          boundingRect = rects[i];
        }
      }
    }
    if (boundingRect === void 0) {
      return null;
    }
    if (boundingRect.top > innerHeight || boundingRect.left > innerWidth) {
      return null;
    }
    if (boundingRect.width <= 1 || boundingRect.height <= 1) {
      var children = node.children;
      var visibleChildNode = false;
      for (i = 0, l = children.length; i < l; ++i) {
        boundingRect = children[i].getClientRects()[0] || children[i].getBoundingClientRect();
        if (boundingRect.width > 1 && boundingRect.height > 1) {
          visibleChildNode = true;
          break;
        }
      }
      if (visibleChildNode === false) {
        return null;
      }
    }
    if (boundingRect.top + boundingRect.height < 10 || boundingRect.left + boundingRect.width < -10) {
      return null;
    }
    var computedStyle = getComputedStyle(node, null);
    if (computedStyle.visibility !== 'visible' ||
        computedStyle.display === 'none' ||
        node.hasAttribute('disabled') ||
        parseInt(computedStyle.width, 10) === 0 ||
        parseInt(computedStyle.height, 10) === 0) {
      return null;
    }
    return boundingRect;
  },

  /**
   * Checks if an element is visible (not necessarily on-screen)
   */
  isVisible: function(element) {
    if (!(element instanceof Element))
      return false;
    return element.offsetParent &&
      !element.disabled &&
      element.getAttribute('type') !== 'hidden' &&
      getComputedStyle(element).visibility !== 'hidden' &&
      element.getAttribute('display') !== 'none';
  },

  mouseEvent: function(type, element) {
    var events;
    switch (type) {
    case 'hover': events = ['mouseover', 'mouseenter']; break;
    case 'unhover': events = ['mouseout', 'mouseleave']; break;
    case 'click': events = ['mouseover', 'mousedown', 'mouseup', 'click']; break;
    }
    events.forEach(function(eventName) {
      var event = document.createEvent('MouseEvents');
      event.initMouseEvent(eventName, true, true, window, 1, 0, 0, 0, 0, false,
          false, false, false, 0, null);
      element.dispatchEvent(event);
    });
  }

};
<commit_msg>Treat select elements as input elements (#504)<commit_after>window.DOM = {

  isSubmittable: function(element) {
    if (!element) {
      return false;
    }
    if (element.localName !== 'input')
      return false;
    if (element.hasAttribute('submit'))
      return true;
    while (element = element.parentElement) {
      if (element.localName === 'form')
        return true;
    }
    return false;
  },

  isEditable: function(element) {
    if (!element) {
      return false;
    }
    if (element.localName === 'textarea' ||
        element.localName === 'select' ||
        element.hasAttribute('contenteditable'))
      return true;
    if (element.localName !== 'input')
      return false;
    var type = element.getAttribute('type');
    switch (type) {
    case 'button':
    case 'checkbox':
    case 'color':
    case 'file':
    case 'hidden':
    case 'image':
    case 'radio':
    case 'reset':
    case 'submit':
    case 'week':
      return false;
    }
    return true;
  },

  isTextElement: function(element) {
    if (!element) {
      return false;
    }
    if (element.localName === 'input' || element.localName === 'textarea') {
      return true;
    }
    while (element) {
      if (element.isContentEditable) {
        return true;
      }
      element = element.parentElement;
    }
    return false;
  },

  onTitleChange: function(callback) {
    waitForLoad(function() {
      var title = (document.getElementsByTagName('title') || [])[0];
      if (!title) {
        return;
      }
      new MutationObserver(function() {
        callback(title.textContent);
      }).observe(title, {
        childList: true
      });
    });
  },

  /**
   * Retrieves the proper boundingRect of an element if it is visible on-screen.
   * @return boundingRect or null (if element is not visible on-screen)
   */
  getVisibleBoundingRect: function(node) {
    var i;
    var boundingRect = node.getClientRects()[0] || node.getBoundingClientRect();
    if (boundingRect.width <= 1 && boundingRect.height <= 1) {
      var rects = node.getClientRects();
      for (i = 0; i < rects.length; i++) {
        if (rects[i].width > rects[0].height && rects[i].height > rects[0].height) {
          boundingRect = rects[i];
        }
      }
    }
    if (boundingRect === void 0) {
      return null;
    }
    if (boundingRect.top > innerHeight || boundingRect.left > innerWidth) {
      return null;
    }
    if (boundingRect.width <= 1 || boundingRect.height <= 1) {
      var children = node.children;
      var visibleChildNode = false;
      for (i = 0, l = children.length; i < l; ++i) {
        boundingRect = children[i].getClientRects()[0] || children[i].getBoundingClientRect();
        if (boundingRect.width > 1 && boundingRect.height > 1) {
          visibleChildNode = true;
          break;
        }
      }
      if (visibleChildNode === false) {
        return null;
      }
    }
    if (boundingRect.top + boundingRect.height < 10 || boundingRect.left + boundingRect.width < -10) {
      return null;
    }
    var computedStyle = getComputedStyle(node, null);
    if (computedStyle.visibility !== 'visible' ||
        computedStyle.display === 'none' ||
        node.hasAttribute('disabled') ||
        parseInt(computedStyle.width, 10) === 0 ||
        parseInt(computedStyle.height, 10) === 0) {
      return null;
    }
    return boundingRect;
  },

  /**
   * Checks if an element is visible (not necessarily on-screen)
   */
  isVisible: function(element) {
    if (!(element instanceof Element))
      return false;
    return element.offsetParent &&
      !element.disabled &&
      element.getAttribute('type') !== 'hidden' &&
      getComputedStyle(element).visibility !== 'hidden' &&
      element.getAttribute('display') !== 'none';
  },

  mouseEvent: function(type, element) {
    var events;
    switch (type) {
    case 'hover': events = ['mouseover', 'mouseenter']; break;
    case 'unhover': events = ['mouseout', 'mouseleave']; break;
    case 'click': events = ['mouseover', 'mousedown', 'mouseup', 'click']; break;
    }
    events.forEach(function(eventName) {
      var event = document.createEvent('MouseEvents');
      event.initMouseEvent(eventName, true, true, window, 1, 0, 0, 0, 0, false,
          false, false, false, 0, null);
      element.dispatchEvent(event);
    });
  }

};
<|endoftext|>


<commit_before>import Ember from 'ember';

const { assign } = Ember;

/**
 * @class Row
 * @extends Ember.ObjectProxy
 * @namespace SemanticUI
 */
const Row = Ember.ObjectProxy.extend({
  /**
   * Whether the row is currently selected.
   *
   * @property selected
   * @type Boolean
   * @default false
   * @public
   */
  selected: false,

  /**
   * Content for this row. See {{#crossLink "Ember.ObjectProxy"}}{{/crossLink}}.
   *
   * @property content
   * @type Object
   * @public
   */
  content: null
});

Row.reopenClass({
  /**
   * @method create
   * @param {Object} content Content for this row.
   * @param {Object} options Properties to initialize in this object.
   * @return Row
   * @static
   */
  create(content, options = {}) {
    let _options = assign({ content }, options);
    return this._super(_options);
  }
});

export default Row;
<commit_msg>Remove usage of Ember.assign to support older version of Ember<commit_after>import Ember from 'ember';

const assign = Ember.assign || Ember.merge;

/**
 * @class Row
 * @extends Ember.ObjectProxy
 * @namespace SemanticUI
 */
const Row = Ember.ObjectProxy.extend({
  /**
   * Whether the row is currently selected.
   *
   * @property selected
   * @type Boolean
   * @default false
   * @public
   */
  selected: false,

  /**
   * Content for this row. See {{#crossLink "Ember.ObjectProxy"}}{{/crossLink}}.
   *
   * @property content
   * @type Object
   * @public
   */
  content: null
});

Row.reopenClass({
  /**
   * @method create
   * @param {Object} content Content for this row.
   * @param {Object} options Properties to initialize in this object.
   * @return Row
   * @static
   */
  create(content, options = {}) {
    let _options = assign({ content }, options);
    return this._super(_options);
  }
});

export default Row;
<|endoftext|>


<commit_before>import Ember from 'ember';
import jobMixin from 'ember-data-offline/mixins/job';

export default Ember.Object.extend(jobMixin, {
  task() {
    console.log('sync', this.get('method'));
    if (this[this.get('method')]){
      return this[this.get('method')].apply(this, this.get('params'));
    }
    return this.get('adapter')[this.get('method')].apply(this.get('adapter'), this.get('params'));
  },

  findAll(store, typeClass, sinceToken, fromJob) {
    let adapterResp = this.get('adapter').findAll(store, typeClass, sinceToken);

    adapterResp.then(adapterPayload => {
      store.unloadAll(typeClass);
      store.pushPayload(typeClass, adapterPayload);
    });

    return adapterResp;
  },

  createRecord(store, type, snapshot, fromJob) {
    let adapter = this.get('adapter');
    return adapter.createRecord(store, type, snapshot, fromJob);
  },

  updateRecord(store, type, snapshot, fromJob) {
    let adapter = this.get('adapter');
    return adapter.updateRecord(store, type, snapshot, fromJob);
  },

  deleteRecord(store, type, snapshot, fromJob) {
    let adapter = this.get('adapter');
    return adapter.deleteRecord(store, type, snapshot, fromJob);
  },

});
<commit_msg>add finders for online job<commit_after>import Ember from 'ember';
import jobMixin from 'ember-data-offline/mixins/job';

export default Ember.Object.extend(jobMixin, {
  task() {
    console.log('sync', this.get('method'));
    if (this[this.get('method')]){
      return this[this.get('method')].apply(this, this.get('params'));
    }
    return this.get('adapter')[this.get('method')].apply(this.get('adapter'), this.get('params'));
  },

  findAll(store, typeClass, sinceToken, fromJob) {
    let adapterResp = this.get('adapter').findAll(store, typeClass, sinceToken);

    adapterResp.then(adapterPayload => {
      store.unloadAll(typeClass);
      store.pushPayload(typeClass, adapterPayload);
    });

    return adapterResp;
  },

  find: function(store, typeClass, id, snapshot, fromJob) {
    let adapterResp = this.get('adapter').find(store, typeClass, id, snapshot);

    adapterResp.then(adapterPayload => {
      store.unloadRecord(typeClass, id);
      store.pushPayload(typeClass, adapterPayload);
    });

    return adapterResp;
  },

  findQuery(store, type, query, fromJob) {
    let adapterResp = this.get('adapter').findQuery(store, type, query);

    adapterResp.then(adapterPayload => {
      //TODO think about unload
      store.pushPayload(typeClass, adapterPayload);
    });

    return adapterResp;
  },

  findMany(store, type, ids, snapshots, fromJob) {
    let adapterResp = this.get('adapter').findMany(store, type, ids, snapshots);

    adapterResp.then(adapterPayload => {
      //TODO think about unload
      store.pushPayload(typeClass, adapterPayload);
    });

    return adapterResp;
  },

  createRecord(store, type, snapshot, fromJob) {
    let adapter = this.get('adapter');
    return adapter.createRecord(store, type, snapshot, fromJob);
  },

  updateRecord(store, type, snapshot, fromJob) {
    let adapter = this.get('adapter');
    return adapter.updateRecord(store, type, snapshot, fromJob);
  },

  deleteRecord(store, type, snapshot, fromJob) {
    let adapter = this.get('adapter');
    return adapter.deleteRecord(store, type, snapshot, fromJob);
  },

});
<|endoftext|>


<commit_before>var CoreObject   = require('core-object');
var Promise      = require('ember-cli/lib/ext/promise');
var SilentError  = require('ember-cli/lib/errors/silent');
var chalk        = require('chalk');

var white = chalk.white;
var green = chalk.green;

var EXPIRE_IN_2030 = new Date('2030');
var TWO_YEAR_CACHE_PERIOD_IN_SEC = 60 * 60 * 24 * 365 * 2;

module.exports = CoreObject.extend({
  init: function() {
    if (!this.config) {
      return Promise.reject(new SilentError('You have to pass a config!'));
    }

    this.s3 = this.s3 || require('s3');
    this.client = this.s3.createClient({
      maxAsyncS3: 1,
      s3Options: this.config.assets
    });
  },

  upload: function() {
    var client = this.client;
    var _this  = this;

    if (!this.ui) {
      var message = 'You have to pass a UI to an adapter.';
      return Promise.reject(new SilentError(message));
    }

    this.ui.pleasantProgress.start(green('Uploading assets'), green('.'));

    return new Promise(function(resolve, reject) {
      var uploader = client.uploadDir(_this.getUploadParams());

      uploader.on('error', _this.logUploadError.bind(_this, reject));

      uploader.on('end', _this.logUploadSuccess.bind(_this, resolve));

      uploader.on('fileUploadStart', _this.logFileUpload.bind(_this));

      uploader.on('fileUploadEnd', _this.logFileUploadEnd.bind(_this, resolve));
    });
  },

  getUploadParams: function() {
    return {
      localDir: 'tmp/assets-sync',
      s3Params: {
        ACL: 'public-read',
        Bucket: this.config.assets.bucket,
        Prefix: this.config.assets.prefix || '',
        CacheControl: 'max-age='+TWO_YEAR_CACHE_PERIOD_IN_SEC+', public',
        Expires: EXPIRE_IN_2030
      },
      getS3Params: this.getS3Params
    }
  },

  getS3Params: function(localFile, stat, callback) {
    var ext = localFile.replace(/.*[\.\/\\]/, '').toLowerCase();
    var isGzippedContent = ['js', 'css'].indexOf(ext) != -1;
    var additionalParams = isGzippedContent ? { ContentEncoding: 'gzip' } : {};

    callback(null, additionalParams);
  },

  logFileUpload: function(fullPath, _) {
    var fileNameMatches = fullPath.match(/\/((\w*[-]\w*||\w*)[.]\w*)/);
    if (fileNameMatches) {
      this.ui.writeLine('Uploading: ' + green(fileNameMatches[1]));
    }
    this.fileUploadPending = true;
  },

  logFileUploadEnd: function(resolve, localFilePath, _s3Key) {
    this.fileUploadPending = false;
    if (this.s3ThinksWeAreFinished) {
      this.printEndMessage();
      resolve();
    }
  },

  logUploadError: function(reject, error) {
    var errorMessage = 'Unable to sync: ' + error.stack;
    reject(new SilentError(errorMessage));
  },

  logUploadSuccess: function(resolve) {
    if (this.fileUploadPending) {
      // s3 screws up some times when only uploading one image
      this.s3ThinksWeAreFinished = true;
    }
    else {
      this.printEndMessage();
      resolve();
    }
  },

  printEndMessage: function() {
    this.ui.writeLine('Assets upload successful. Done uploading.');
    this.ui.pleasantProgress.stop();
  }
});
<commit_msg>Fix: gzipped SVGs were not marked correctly.<commit_after>var CoreObject   = require('core-object');
var Promise      = require('ember-cli/lib/ext/promise');
var SilentError  = require('ember-cli/lib/errors/silent');
var chalk        = require('chalk');

var white = chalk.white;
var green = chalk.green;

var EXPIRE_IN_2030 = new Date('2030');
var TWO_YEAR_CACHE_PERIOD_IN_SEC = 60 * 60 * 24 * 365 * 2;

module.exports = CoreObject.extend({
  init: function() {
    if (!this.config) {
      return Promise.reject(new SilentError('You have to pass a config!'));
    }

    this.s3 = this.s3 || require('s3');
    this.client = this.s3.createClient({
      maxAsyncS3: 1,
      s3Options: this.config.assets
    });
  },

  upload: function() {
    var client = this.client;
    var _this  = this;

    if (!this.ui) {
      var message = 'You have to pass a UI to an adapter.';
      return Promise.reject(new SilentError(message));
    }

    this.ui.pleasantProgress.start(green('Uploading assets'), green('.'));

    return new Promise(function(resolve, reject) {
      var uploader = client.uploadDir(_this.getUploadParams());

      uploader.on('error', _this.logUploadError.bind(_this, reject));

      uploader.on('end', _this.logUploadSuccess.bind(_this, resolve));

      uploader.on('fileUploadStart', _this.logFileUpload.bind(_this));

      uploader.on('fileUploadEnd', _this.logFileUploadEnd.bind(_this, resolve));
    });
  },

  getUploadParams: function() {
    return {
      localDir: 'tmp/assets-sync',
      s3Params: {
        ACL: 'public-read',
        Bucket: this.config.assets.bucket,
        Prefix: this.config.assets.prefix || '',
        CacheControl: 'max-age='+TWO_YEAR_CACHE_PERIOD_IN_SEC+', public',
        Expires: EXPIRE_IN_2030
      },
      getS3Params: this.getS3Params.bind(this)
    }
  },

  getS3Params: function(localFile, stat, callback) {
    var gzipExtensions = this.config.assets.gzipExtensions ? this.config.assets.gzipExtensions : ['js', 'css', 'svg'];
    var ext = localFile.replace(/.*[\.\/\\]/, '').toLowerCase();
    var isGzippedContent = gzipExtensions.indexOf(ext) != -1;
    var additionalParams = isGzippedContent ? { ContentEncoding: 'gzip' } : {};

    callback(null, additionalParams);
  },

  logFileUpload: function(fullPath, _) {
    var fileNameMatches = fullPath.match(/\/((\w*[-]\w*||\w*)[.]\w*)/);
    if (fileNameMatches) {
      this.ui.writeLine('Uploading: ' + green(fileNameMatches[1]));
    }
    this.fileUploadPending = true;
  },

  logFileUploadEnd: function(resolve, localFilePath, _s3Key) {
    this.fileUploadPending = false;
    if (this.s3ThinksWeAreFinished) {
      this.printEndMessage();
      resolve();
    }
  },

  logUploadError: function(reject, error) {
    var errorMessage = 'Unable to sync: ' + error.stack;
    reject(new SilentError(errorMessage));
  },

  logUploadSuccess: function(resolve) {
    if (this.fileUploadPending) {
      // s3 screws up some times when only uploading one image
      this.s3ThinksWeAreFinished = true;
    }
    else {
      this.printEndMessage();
      resolve();
    }
  },

  printEndMessage: function() {
    this.ui.writeLine('Assets upload successful. Done uploading.');
    this.ui.pleasantProgress.stop();
  }
});
<|endoftext|>


<commit_before>/*******************************************************/
/*
/*  StopSovetnik - Lock Yandex.Sovetnik on your site!
/*
/*******************************************************/

var stopSovetnik = function() {

  var $ = function(el) {
    var nodes = document.querySelectorAll(el);
    if (nodes.length === 1) {
      return nodes[0];
    } else if (nodes.length > 1) {
      return nodes[nodes.length - 1];
    } else {
      return null;
    }
  };

  var checkSovetnik = setInterval(function() {
    var margin = parseInt($('HTML').style.marginTop);
    if (margin > 0) {
      $('BODY > DIV').remove();
      $('BODY > STYLE').remove();
      clearInterval(checkSovetnik);
      setTimeout(function() {
        $('HTML').style.marginTop = '0px';
      }, 500);
    }

    setTimeout(function() {
      clearInterval(checkSovetnik);
    }, 10000);

  }, 10);
};

stopSovetnik();
<commit_msg>ver 1.0.2<commit_after>/*******************************************************/
/*
/*  StopSovetnik - Lock Yandex.Sovetnik on your site!
/*  Ver 1.0.2
/*
/*******************************************************/

(function () {

var stopSovetnik = function() {

  if ('MutationObserver' in window) {

    var stopSovetnikObserver = new MutationObserver(function(allmutations) {

      allmutations.map(function(mr) {
        var m = mr.addedNodes[0];
        var found = false;
        var check = {
          'z-index': '2147483647',
          'background-color': 'rgb(250, 223, 118)',
          'display': 'table',
          'position': 'fixed'
        }

        if (m && m.tagName === 'DIV') {
          for (var c in check) {
            if (window.getComputedStyle(m).getPropertyValue(c) === check[c]) {
              found = true;
            } else {
              found = false;
              break;
            }
          }
          if (found) {
            document.body.removeChild(m);
            document.documentElement.style.marginTop = '';
            stopSovetnikObserver.disconnect();
          }
        }
      });
    });

    var marginAnimationObserver = new MutationObserver(function() {
      var mt = document.documentElement.style.marginTop;
      if (mt && parseInt(mt) > 0) {
        document.documentElement.style.marginTop = '';
      }
    });

      stopSovetnikObserver.observe(document.body, {
        'childList': true,
        'attributes': true,
        'attributeFilter': ['style']
      });

      marginAnimationObserver.observe(document.documentElement, {
        'attributes': true,
        'attributeFilter': ['style']
      });

      setTimeout(function() {
        marginAnimationObserver.disconnect();
      }, 2100);

  }

};

stopSovetnik();
setTimeout(stopSovetnik, 20000);

})();
<|endoftext|>


<commit_before>/*
    Agora Forum Software
    Copyright (C) 2016 Gregory Sartucci
    License: AGPL-3.0, Check file LICENSE
*/

import { getActivityFromUrl } from 'meteor/agoraforum:activitypub';

Meteor.methods({
    sendVerificationLink: function() {
        let userId = Meteor.userId();
        if ( userId ) {
            return Accounts.sendVerificationEmail( userId );
        }
    },
    insertPost: function(post) {
        let user = Meteor.users.findOne({_id: this.userId});

        //Don't allow guests to post.
        if (!user) {
            throw new Meteor.Error('not-logged-in', 'The user must be logged in to post.');
        }

        //Don't allow banned users to post.
        if (user.isBanned) {
            throw new Meteor.Error('banned', 'Banned users may not post.');
        }

        //Don't allow unverified users to post.
        if (!user.emails || user.emails.length < 1 || !user.emails[0].verified) {
            throw new Meteor.Error('unverified', 'Unverified users may not post.');
        }

        if (!post.inReplyTo) {
        }

        let target = Posts.findOne({_id: post.inReplyTo});
        if (!target) {
            return;
        }

        //check post for new hashtags and if any are found process them.
        //The regex here describes a hashtag as anything that starts with either
        //the start of a string or any kind of whitespace, then has a # symbol,
        //and then any  number of letters.
        let postTags = post.content.match(/(^|\s)(#[a-z\d][\w-]*)/gi);

        if(!post.tags) post.tags = [];

        if (postTags) {

            for (let newTag of postTags) {
                newTag = newTag.trim().toLowerCase();
                newTag = newTag.replace("#", "");

                console.log(newTag);

                //check for any new tags not already present on the post.
                if (post.tags.find(function(tag) {
                    return tag === newTag;
                }) === undefined) {
                    //if any are found, add them to the list of new tags on the
                    //post.
                    post.tags.push(newTag);
                }
            }
        }

        //Validate against schema. TODO: Fix validation redundancy--also validates upon insert.
        Schema.Post.validate(post);

        //Insert new post into position.
        let postId = Posts.insert(post);
        Posts.update({_id: post.inReplyTo}, {$push: {replies: postId}});

        //add any new tags to the database, and adjust the info for existing tags accordingly.
        for (let tag of post.tags) {
            let tagDocument = Tags.findOne({_id: tag});
            if (!tagDocument) {
                Tags.insert({_id: tag, postNumber: 1, posts: [postId]});
                tagDocument = Tags.findOne({_id: tag});
            } else {
                Tags.update({_id: tag}, { $inc: {postNumber: 1}, $push: {posts: postId} });
                tagDocument = Tags.findOne({_id: tag});
            }
        }

        return postId;
    },
    editPost: function(postId, update) {
        let user = Meteor.users.findOne({_id: this.userId});

        //Don't allow guests to edit posts.
        if (!user) {
            throw new Meteor.Error('not-logged-in', 'The user must be logged in to edit posts.');
        }

        //Don't allow banned users to edit posts.
        if (user.isBanned) {
            throw new Meteor.Error('banned', 'Banned users may not edit posts.');
        }

        //Don't allow unverified users to edit posts.
        if (!user.emails || user.emails.length < 1 || !user.emails[0].verified) {
            throw new Meteor.Error('unverified', 'Unverified users may not edit posts.');
        }

        let post = Posts.findOne({_id: postId});

        //Don't allow non-moderators to edit other peoples posts.
        if (post.poster !== this.userId && !Roles.userIsInRole(this.userId, ['moderator'])) {
            throw new Meteor.Error('post-not-owned', 'Only moderators may edit posts they don\'t own.');
        }

        //Validate edit.
        if (post.summary && post.summary.length < 1) {
            delete post.summary;
        }

        //check post for new tags and process them if found.
        let postTags = update.content.match(/(^|\s)(#[a-z\d][\w-]*)/gi);

        if(!update.tags) update.tags = [];

        if (postTags) {

            for (let newTag of postTags) {
                newTag = newTag.trim().toLowerCase();

                //check for any new tags not already present on the post.
                if (update.tags.find(function(tag) {
                    return tag === newTag;
                }) === undefined) {
                    //if any are found, add them to the list of new tags on the
                    //post.
                    update.tags.push(newTag);

                    let tagDocument = Tags.findOne({_id: newTag});
                    if (!tagDocument) {
                        Tags.insert({_id: newTag, postNumber: 1, posts: [postId]});
                        tagDocument = Tags.findOne({_id: newTag});
                    } else {
                        Tags.update({_id: newTag}, { $inc: {postNumber: 1}, $push: {posts: postId} });
                        tagDocument = Tags.findOne({_id: newTag});
                    }

                }
            }
        }

        //Edit post.
        Posts.update({_id: postId}, {$set: {
            summary: update.summary,
            content: update.content,
            updated: Date.now()
        }});
    },
    deletePost: function(postId) {
        let post = Posts.findOne({_id: postId});

        //Don't allow non-moderators to delete posts.
        if (!Roles.userIsInRole(this.userId, ['moderator'])) {
            throw new Meteor.Error('not-logged-in', 'Only moderators may delete posts.');
        }

        //check to make sure the post exists before attempting to delete it.
        if (post === undefined) {
            throw new Meteor.Error('post-not-found', 'No such post was found.');
        }

        //recursively delete all replies to the post.
        post.replies.forEach(function(reply) {
            Meteor.call('deletePost', reply);
        });

        //delete the post and all references to it.
        Posts.update({_id: post.inReplyTo}, {$pull: {replies: postId}});
        Posts.remove(postId);
    },
    submitReport: function(report) {
        let user = Meteor.users.findOne({_id: this.userId});

        //Don't allow guests to submit reports.
        if (!user) {
            throw new Meteor.Error('not-logged-in', 'The user must be logged in to submit reports.');
        }

        //Don't allow banned users to submit reports.
        if (user.isBanned) {
            throw new Meteor.Error('banned', 'Banned users may not submit reports.');
        }

        //Don't allow unverified users to submit reports.
        if (!user.emails || user.emails.length < 1 || !user.emails[0].verified) {
            throw new Meteor.Error('unverified', 'Unverified users may not submit reports.');
        }

        if (report.content.length >= 1)
            return Reports.insert(report);
    },
    resolveReport: function(report) {
        if (Roles.userIsInRole(this.userId, ['moderator']))
        return Reports.update({_id: report._id},
            {$set: {resolved: true} });
    },
    updateUserSummary: function(newSummary) {
        let user = Meteor.users.findOne({_id: this.userId});

        //Don't allow guests to try and edit profiles.
        if (!user) {
            throw new Meteor.Error('not-logged-in', 'The user must be logged in to edit posts.');
        }

        //Don't allow banned users to edit profiles.
        if (user.isBanned) {
            throw new Meteor.Error('banned', 'Banned users may not edit posts.');
        }

        //Update field.
        Meteor.users.update({_id: this.userId}, {$set: {'profile.summary': newSummary}});
    },
    addSeenPost: function(postID) {
        let user = Meteor.users.findOne({_id: this.userId});

        //Guests can't record seen posts.
        if (!user) {
            throw new Meteor.Error('not-logged-in', 'The user must be logged in to record seen posts.');
        }

        let post = Posts.findOne({_id: postID});

        if (!post.published) {
            throw new Meteor.Error('undated-post', 'That post does not have a date and is thus assumed to be to old to be worth recording as seen.');
        }

        if (post.poster == this.userId) {
            throw new Meteor.Error('own-post', 'A user is assumed to have always seen their own posts.');
        }

        if (Date.now() - post.published >= (1000*60*60*24*30)) {
            throw new Meteor.Error('old-post', 'Posts older than a month are assumed to have always been seen.');
        }

        if (user.seenPosts && user.seenPosts.find(function(p) {
            return postID == p._id;
        })) {
            throw new Meteor.Error('already-seen', 'The user has already seen that post.');
        }

        //Update field.
        Meteor.users.update({_id: this.userId}, {$push: {seenPosts: postID}});
    }
});
<commit_msg>add extra meteor errors, remove extra space<commit_after>/*
    Agora Forum Software
    Copyright (C) 2016 Gregory Sartucci
    License: AGPL-3.0, Check file LICENSE
*/

import { getActivityFromUrl } from 'meteor/agoraforum:activitypub';

Meteor.methods({
    sendVerificationLink: function() {
        let userId = Meteor.userId();
        if ( userId ) {
            return Accounts.sendVerificationEmail( userId );
        }
    },
    insertPost: function(post) {
        let user = Meteor.users.findOne({_id: this.userId});

        //Don't allow guests to post.
        if (!user) {
            throw new Meteor.Error('not-logged-in', 'The user must be logged in to post.');
        }

        //Don't allow banned users to post.
        if (user.isBanned) {
            throw new Meteor.Error('banned', 'Banned users may not post.');
        }

        //Don't allow unverified users to post.
        if (!user.emails || user.emails.length < 1 || !user.emails[0].verified) {
            throw new Meteor.Error('unverified', 'Unverified users may not post.');
        }

        if (!post.inReplyTo) {
            throw new Meteor.Error('no target', 'Post has no target!');
        }

        let target = Posts.findOne({_id: post.inReplyTo});
        if (!target) {
            throw new Meteor.Error('target invalid', 'Targeted post not found!');
        }

        //check post for new hashtags and if any are found process them.
        //The regex here describes a hashtag as anything that starts with either
        //the start of a string or any kind of whitespace, then has a # symbol,
        //and then any number of letters.
        let postTags = post.content.match(/(^|\s)(#[a-z\d][\w-]*)/gi);

        if(!post.tags) post.tags = [];

        if (postTags) {

            for (let newTag of postTags) {
                newTag = newTag.trim().toLowerCase();
                newTag = newTag.replace("#", "");

                console.log(newTag);

                //check for any new tags not already present on the post.
                if (post.tags.find(function(tag) {
                    return tag === newTag;
                }) === undefined) {
                    //if any are found, add them to the list of new tags on the
                    //post.
                    post.tags.push(newTag);
                }
            }
        }

        //Validate against schema. TODO: Fix validation redundancy--also validates upon insert.
        Schema.Post.validate(post);

        //Insert new post into position.
        let postId = Posts.insert(post);
        Posts.update({_id: post.inReplyTo}, {$push: {replies: postId}});

        //add any new tags to the database, and adjust the info for existing tags accordingly.
        for (let tag of post.tags) {
            let tagDocument = Tags.findOne({_id: tag});
            if (!tagDocument) {
                Tags.insert({_id: tag, postNumber: 1, posts: [postId]});
                tagDocument = Tags.findOne({_id: tag});
            } else {
                Tags.update({_id: tag}, { $inc: {postNumber: 1}, $push: {posts: postId} });
                tagDocument = Tags.findOne({_id: tag});
            }
        }

        return postId;
    },
    editPost: function(postId, update) {
        let user = Meteor.users.findOne({_id: this.userId});

        //Don't allow guests to edit posts.
        if (!user) {
            throw new Meteor.Error('not-logged-in', 'The user must be logged in to edit posts.');
        }

        //Don't allow banned users to edit posts.
        if (user.isBanned) {
            throw new Meteor.Error('banned', 'Banned users may not edit posts.');
        }

        //Don't allow unverified users to edit posts.
        if (!user.emails || user.emails.length < 1 || !user.emails[0].verified) {
            throw new Meteor.Error('unverified', 'Unverified users may not edit posts.');
        }

        let post = Posts.findOne({_id: postId});

        //Don't allow non-moderators to edit other peoples posts.
        if (post.poster !== this.userId && !Roles.userIsInRole(this.userId, ['moderator'])) {
            throw new Meteor.Error('post-not-owned', 'Only moderators may edit posts they don\'t own.');
        }

        //Validate edit.
        if (post.summary && post.summary.length < 1) {
            delete post.summary;
        }

        //check post for new tags and process them if found.
        let postTags = update.content.match(/(^|\s)(#[a-z\d][\w-]*)/gi);

        if(!update.tags) update.tags = [];

        if (postTags) {

            for (let newTag of postTags) {
                newTag = newTag.trim().toLowerCase();

                //check for any new tags not already present on the post.
                if (update.tags.find(function(tag) {
                    return tag === newTag;
                }) === undefined) {
                    //if any are found, add them to the list of new tags on the
                    //post.
                    update.tags.push(newTag);

                    let tagDocument = Tags.findOne({_id: newTag});
                    if (!tagDocument) {
                        Tags.insert({_id: newTag, postNumber: 1, posts: [postId]});
                        tagDocument = Tags.findOne({_id: newTag});
                    } else {
                        Tags.update({_id: newTag}, { $inc: {postNumber: 1}, $push: {posts: postId} });
                        tagDocument = Tags.findOne({_id: newTag});
                    }

                }
            }
        }

        //Edit post.
        Posts.update({_id: postId}, {$set: {
            summary: update.summary,
            content: update.content,
            updated: Date.now()
        }});
    },
    deletePost: function(postId) {
        let post = Posts.findOne({_id: postId});

        //Don't allow non-moderators to delete posts.
        if (!Roles.userIsInRole(this.userId, ['moderator'])) {
            throw new Meteor.Error('not-logged-in', 'Only moderators may delete posts.');
        }

        //check to make sure the post exists before attempting to delete it.
        if (post === undefined) {
            throw new Meteor.Error('post-not-found', 'No such post was found.');
        }

        //recursively delete all replies to the post.
        post.replies.forEach(function(reply) {
            Meteor.call('deletePost', reply);
        });

        //delete the post and all references to it.
        Posts.update({_id: post.inReplyTo}, {$pull: {replies: postId}});
        Posts.remove(postId);
    },
    submitReport: function(report) {
        let user = Meteor.users.findOne({_id: this.userId});

        //Don't allow guests to submit reports.
        if (!user) {
            throw new Meteor.Error('not-logged-in', 'The user must be logged in to submit reports.');
        }

        //Don't allow banned users to submit reports.
        if (user.isBanned) {
            throw new Meteor.Error('banned', 'Banned users may not submit reports.');
        }

        //Don't allow unverified users to submit reports.
        if (!user.emails || user.emails.length < 1 || !user.emails[0].verified) {
            throw new Meteor.Error('unverified', 'Unverified users may not submit reports.');
        }

        if (report.content.length >= 1)
            return Reports.insert(report);
    },
    resolveReport: function(report) {
        if (Roles.userIsInRole(this.userId, ['moderator']))
        return Reports.update({_id: report._id},
            {$set: {resolved: true} });
    },
    updateUserSummary: function(newSummary) {
        let user = Meteor.users.findOne({_id: this.userId});

        //Don't allow guests to try and edit profiles.
        if (!user) {
            throw new Meteor.Error('not-logged-in', 'The user must be logged in to edit posts.');
        }

        //Don't allow banned users to edit profiles.
        if (user.isBanned) {
            throw new Meteor.Error('banned', 'Banned users may not edit posts.');
        }

        //Update field.
        Meteor.users.update({_id: this.userId}, {$set: {'profile.summary': newSummary}});
    },
    addSeenPost: function(postID) {
        let user = Meteor.users.findOne({_id: this.userId});

        //Guests can't record seen posts.
        if (!user) {
            throw new Meteor.Error('not-logged-in', 'The user must be logged in to record seen posts.');
        }

        let post = Posts.findOne({_id: postID});

        if (!post.published) {
            throw new Meteor.Error('undated-post', 'That post does not have a date and is thus assumed to be to old to be worth recording as seen.');
        }

        if (post.poster == this.userId) {
            throw new Meteor.Error('own-post', 'A user is assumed to have always seen their own posts.');
        }

        if (Date.now() - post.published >= (1000*60*60*24*30)) {
            throw new Meteor.Error('old-post', 'Posts older than a month are assumed to have always been seen.');
        }

        if (user.seenPosts && user.seenPosts.find(function(p) {
            return postID == p._id;
        })) {
            throw new Meteor.Error('already-seen', 'The user has already seen that post.');
        }

        //Update field.
        Meteor.users.update({_id: this.userId}, {$push: {seenPosts: postID}});
    }
});
<|endoftext|>


<commit_before>if (Meteor.isServer) {
    checkRightsGroup = {
      'isLeader': function(email, groupId){
          var group = Groups.findOne({_id: groupId});
          if(group.leader === email)
              return true;

          return this.checkUserRight("", Meteor.userId());
      }
    };

    if(typeof checkRights !== 'undefined')
        _.merge(checkRights, checkRightsGroup);

    Meteor.methods({
        /*
         * Adds a user to a group
         * @param String userId
         * @param String useremail
         * @param String groupId
         * @param String roles -> role1,role2...
         * @return Boolean
         *      true = user was added
         *      false = user was not added
         */
        'addUserToGroup': function (userId, useremail, groupId, roles) {
            if(checkRights.isLeader(Meteor.user().emails[0].address, groupId)) {

                if (!groupId)
                    throw new Meteor.Error("groups", "You did not specify a groupId");

                var identifier;
                if (userId)
                    identifier = {_id: userId};
                var user = Meteor.users.update(identifier,
                    {
                        $addToSet: {
                            'profile.groups': {
                                id: groupId
                            }
                        }
                    });

                Groups.update({
                        _id: groupId
                    }, {
                        $addToSet: {
                            users: {
                                id: userId,
                                roles:[roles]
                            }
                        }
                    }
                );
                if (user == 1)
                    return true;
            }
        },
        /*
         * removes a user from a group
         * @param String userId
         * @param String email
         * @param String groupId
         * @return Boolean
         *      true = removed user from group successfull
         *      error = removing user from group failed
         */
        'removeUserFromGroup': function (userId, email, groupId) {
            if(checkRights.isLeader(Meteor.user().emails[0].address, groupId)) {
                if (groupId) {
                    var update = {
                        $pull: {
                            'profile.groups': {
                                id: groupId
                            }
                        }
                    };
                    var user;

                    if (userId != "" && userId != undefined) {
                        user = Meteor.users.update({_id: userId}, update);
                    } else if (email != "" && userId != undefined) {
                        user = Meteor.users.update({'emails.0.address': email}, update);
                    }

                    Groups.update({
                            _id: groupId
                        }, {
                            $pull: {
                                users: {
                                    id: userId
                                }
                            }
                        }
                    );

                    if (!user)
                        throw new Meteor.Error("user", "Found no user!");
                } else {
                    throw new Meteor.Error("group", "Found no group with specified groupid!");
                }
                return true;
            }
        },

        /*
        * checks if a given groupname is already existing in the database
        * @param String groupname
        * @return Boolean
        *      true = groupname is existing
        *      false = groupname not existing
        */
        checkGroupnameExisting: function (groupname) {
            var existingGroupname = Groups.find({groupname: groupname}).fetch();
            if (existingGroupname.length > 0)
                return true;

            return false;
        },

        /*
         * creates a group (autoform method call)
         * @param Object doc
         * @return Boolean
         *      true = created group successfull
         *      error = creating group failed
         */
        createGroup: function (doc, mod, documentId) {

            //TODO check if project exists
            if(checkRights.checkUserRight("",Meteor.userId())) {
                var parentId = "";

                var parentGroup = Groups.findOne({
                    groupname: doc.parentGroup
                });

                if (typeof parentGroup !== "undefined")
                    parentId = parentGroup._id;
                var leaderId = null;
                leader = Meteor.users.findOne({'emails.0.address': doc.leader});
                if(leader){
                  leaderId = leader._id;
                }

                if (doc.groupname) {
                    var group = Groups.insert({
                        groupname: doc.groupname,
                        parentGroup: parentId,
                        leader: leaderId,
                        projects: doc.projects,
                        agency: doc.agency,
                        users: doc.users
                    });
                    if (!group)
                        throw new Meteor.Error("group", "Create group failed!");

                    if(leaderId)
                      Meteor.call('addUserToGroup', leaderId, null, group);
                } else {
                    if (name === "")
                        throw new Meteor.Error("group", "Name was not specified!");
                }

                return true;
            }
        },
        /*
         * updates a group (autoform method call)
         * @param Object doc
         * @return Boolean
         *      true = edit group successfull
         *      error = edit group failed
         */
        updateGroup: function (doc, mod, documentId) {
            if(!Meteor.user()){
              throw new Meteor.Error("group", "you need to be logged in to do this");
            }
            if(checkRights.isLeader(Meteor.user().emails[0].address, documentId)) {
                var parentId = "";
                var parentGroup = Groups.findOne({
                    groupname: doc.parentGroup
                });
                if(typeof parentGroup !== "undefined")
                    parentId = parentGroup._id;

                var leaderId = null;
                leader = Meteor.users.findOne({'emails.0.address': doc.leader});
                if(leader){
                  leaderId = leader._id;
                }

                var group = Groups.update({
                        _id: documentId
                    }, {
                        $set: {
                            groupname: doc.groupname,
                            parentGroup: parentId,
                            leader: leaderId,
                            projects: doc.projects,
                            agency: doc.agency,
                            users: doc.users
                        }
                    }
                );
                if (group != 1)
                    throw new Meteor.Error("group", "updating the group failed");

                if(leaderId)
                    Meteor.call('addUserToGroup', leaderId, null, documentId);

                return true;
            }
        },
        /*
         * assigns a sub group to a group
         * @param String groupId
         * @param String parentGroupId
         * @return Boolean
         *      true = assign subgroup successfull
         *      error = assign subgroup failed
         */
        assignSubGroup: function (groupId, parentGroupId) {
            if(checkRights.isLeader(Meteor.user().emails[0].address, groupId)) {
                if (groupId && parentGroupId) {
                    Groups.update({_id: groupId}, {
                        $set: {
                            parentGroup: parentGroupId
                        }
                    });
                } else {
                    if (parentGroupId === "")
                        throw new Meteor.Error("group", "Parent group id was not specified!");
                    if (groupId === "")
                        throw new Meteor.Error("group", "Group id was not specified");
                }
            }
        },
        /*
         * remove a sub group from a group
         * @param String groupId
         * @param String parentGroupId
         * @return Boolean
         *      true = removed subgroup successfull
         *      error = remove subgroup failed
         */
        removeSubGroup: function (groupId, parentGroupId) {
            if(checkRights.isLeader(Meteor.user().emails[0].address, groupId)) {
                if (groupId && parentGroupId) {
                    Groups.update({_id: grouId}, {
                        $set: {
                            parentGroup: null
                        }
                    });
                } else {
                    if (parentGroupId === "")
                        throw new Meteor.Error("group", "Parent group id was not specified!");
                    if (groupId === "")
                        throw new Meteor.Error("group", "Group id was not specified");
                }
            }
        },
        /*
         * removes a group
         * @param String groupId
         * @return Boolean
         *      true = removed group successfull
         *      error = removing group failed
         */
        removeGroup: function (groupId) {
            if (checkRights.checkUserRight("", Meteor.userId())) {
                if (groupId) {
                    var users = Groups.findOne({_id: groupId}).users;
                    var group = Groups.remove({_id: groupId});
                    //Find children and remove parentId
                    var children = Groups.update({parentGroup: groupId}, {
                        $set: {parentGroup: null}
                    });

                    _.each(users, function (user) {
                        Meteor.users.update(
                            {
                                _id: user.id
                            }, {
                                $pull: {
                                    'profile.groups': {
                                        id: groupId
                                    }
                                }
                            });
                    });

                    return true;
                } else {
                    throw new Meteor.Error("groups", "No group id was specified while removing group");
                }
            }
        },
        /*
         * add user role
         * @param String groupId
         * @param String userId
         * @param String role
         * @return Boolean
         *      true = added role
         *      error = error
         */
        addUserRoleInGroup: function(groupId, userId, role){
            if(typeof groupId !== 'undefined'
                && typeof userId !== 'undefined'
                && typeof role !== 'undefined'){
                var roleExists = Meteor.roles.findOne({name:role, groupId: groupId});
                if(!roleExists)
                    throw new Meteor.Error("GroupUserRoles", "The role does not exist");

                Groups.update({_id: groupId},{
                    users:{
                        id:userId,
                        $addToSet:{
                            roles:role
                        }
                    }
                });
            }
        },
        /*
         * add user role
         * @param String groupId
         * @param String userId
         * @param String role
         * @return Boolean
         *      true = added role
         *      error = error
         */
        deleteUserRoleInGroup: function(groupId, userId, role){
            if(typeof groupId !== 'undefined'
                && typeof userId !== 'undefined'
                && typeof role !== 'undefined'){
                var roleExists = Meteor.roles.findOne({name:role, groupId: groupId});
                if(!roleExists)
                    throw new Meteor.Error("GroupUserRoles", "The role does not exist");

                Groups.update({_id: groupId},{
                    users:{
                        id:userId,
                        $pull:{
                            roles:role
                        }
                    }
                });
            }
        }
    });
}
<commit_msg>add and remove user roles in groups<commit_after>if (Meteor.isServer) {
    checkRightsGroup = {
      'isLeader': function(email, groupId){
          var group = Groups.findOne({_id: groupId});
          if(group.leader === email)
              return true;

          return Roles.userIsInRole(Meteor.userId(), ['admin','superAdmin']);
      }
    };

    if(typeof checkRights !== 'undefined')
        _.merge(checkRights, checkRightsGroup);

    Meteor.methods({
        /*
         * Adds a user to a group
         * @param String userId
         * @param String useremail
         * @param String groupId
         * @param Array roles
         * @return Boolean
         *      true = user was added
         *      false = user was not added
         */
        'addUserToGroup': function (userId, useremail, groupId, roles) {
            var roles = roles || [];
            if(checkRights.isLeader(Meteor.user().emails[0].address, groupId)) {

                if (!groupId)
                    throw new Meteor.Error("groups", "You did not specify a groupId");

                var identifier;
                if (userId)
                    identifier = {_id: userId};
                var user = Meteor.users.update(identifier,
                    {
                        $addToSet: {
                            'profile.groups': {
                                id: groupId
                            }
                        }
                    });

                Groups.update({
                        _id: groupId
                    }, {
                        $addToSet: {
                            users: {
                                id: userId,
                                roles:roles
                            }
                        }
                    }
                );
                if (user == 1)
                    return true;
            }
        },
        /*
         * removes a user from a group
         * @param String userId
         * @param String email
         * @param String groupId
         * @return Boolean
         *      true = removed user from group successfull
         *      error = removing user from group failed
         */
        'removeUserFromGroup': function (userId, email, groupId) {
            if(checkRights.isLeader(Meteor.user().emails[0].address, groupId)) {
                if (groupId) {
                    var update = {
                        $pull: {
                            'profile.groups': {
                                id: groupId
                            }
                        }
                    };
                    var user;

                    if (userId != "" && userId != undefined) {
                        user = Meteor.users.update({_id: userId}, update);
                    } else if (email != "" && userId != undefined) {
                        user = Meteor.users.update({'emails.0.address': email}, update);
                    }

                    Groups.update({
                            _id: groupId
                        }, {
                            $pull: {
                                users: {
                                    id: userId
                                }
                            }
                        }
                    );

                    if (!user)
                        throw new Meteor.Error("user", "Found no user!");
                } else {
                    throw new Meteor.Error("group", "Found no group with specified groupid!");
                }
                return true;
            }
        },

        /*
        * checks if a given groupname is already existing in the database
        * @param String groupname
        * @return Boolean
        *      true = groupname is existing
        *      false = groupname not existing
        */
        checkGroupnameExisting: function (groupname) {
            var existingGroupname = Groups.find({groupname: groupname}).fetch();
            if (existingGroupname.length > 0)
                return true;

            return false;
        },

        /*
         * creates a group (autoform method call)
         * @param Object doc
         * @return Boolean
         *      true = created group successfull
         *      error = creating group failed
         */
        createGroup: function (doc, mod, documentId) {

            //TODO check if project exists
            if(checkRights.checkUserRight("",Meteor.userId())) {
                var parentId = "";

                var parentGroup = Groups.findOne({
                    groupname: doc.parentGroup
                });

                if (typeof parentGroup !== "undefined")
                    parentId = parentGroup._id;
                var leaderId = null;
                leader = Meteor.users.findOne({'emails.0.address': doc.leader});
                if(leader){
                  leaderId = leader._id;
                }

                if (doc.groupname) {
                    var group = Groups.insert({
                        groupname: doc.groupname,
                        parentGroup: parentId,
                        leader: leaderId,
                        projects: doc.projects,
                        agency: doc.agency,
                        users: doc.users
                    });
                    if (!group)
                        throw new Meteor.Error("group", "Create group failed!");

                    if(leaderId)
                      Meteor.call('addUserToGroup', leaderId, null, group);
                } else {
                    if (name === "")
                        throw new Meteor.Error("group", "Name was not specified!");
                }

                return true;
            }
        },
        /*
         * updates a group (autoform method call)
         * @param Object doc
         * @return Boolean
         *      true = edit group successfull
         *      error = edit group failed
         */
        updateGroup: function (doc, mod, documentId) {
            if(!Meteor.user()){
              throw new Meteor.Error("group", "you need to be logged in to do this");
            }
            if(checkRights.isLeader(Meteor.user().emails[0].address, documentId)) {
                var parentId = "";
                var parentGroup = Groups.findOne({
                    groupname: doc.parentGroup
                });
                if(typeof parentGroup !== "undefined")
                    parentId = parentGroup._id;

                var leaderId = null;
                leader = Meteor.users.findOne({'emails.0.address': doc.leader});
                if(leader){
                  leaderId = leader._id;
                }

                var group = Groups.update({
                        _id: documentId
                    }, {
                        $set: {
                            groupname: doc.groupname,
                            parentGroup: parentId,
                            leader: leaderId,
                            projects: doc.projects,
                            agency: doc.agency,
                            users: doc.users
                        }
                    }
                );
                if (group != 1)
                    throw new Meteor.Error("group", "updating the group failed");

                if(leaderId)
                    Meteor.call('addUserToGroup', leaderId, null, documentId);

                return true;
            }
        },
        /*
         * assigns a sub group to a group
         * @param String groupId
         * @param String parentGroupId
         * @return Boolean
         *      true = assign subgroup successfull
         *      error = assign subgroup failed
         */
        assignSubGroup: function (groupId, parentGroupId) {
            if(checkRights.isLeader(Meteor.user().emails[0].address, groupId)) {
                if (groupId && parentGroupId) {
                    Groups.update({_id: groupId}, {
                        $set: {
                            parentGroup: parentGroupId
                        }
                    });
                } else {
                    if (parentGroupId === "")
                        throw new Meteor.Error("group", "Parent group id was not specified!");
                    if (groupId === "")
                        throw new Meteor.Error("group", "Group id was not specified");
                }
            }
        },
        /*
         * remove a sub group from a group
         * @param String groupId
         * @param String parentGroupId
         * @return Boolean
         *      true = removed subgroup successfull
         *      error = remove subgroup failed
         */
        removeSubGroup: function (groupId, parentGroupId) {
            if(checkRights.isLeader(Meteor.user().emails[0].address, groupId)) {
                if (groupId && parentGroupId) {
                    Groups.update({_id: grouId}, {
                        $set: {
                            parentGroup: null
                        }
                    });
                } else {
                    if (parentGroupId === "")
                        throw new Meteor.Error("group", "Parent group id was not specified!");
                    if (groupId === "")
                        throw new Meteor.Error("group", "Group id was not specified");
                }
            }
        },
        /*
         * removes a group
         * @param String groupId
         * @return Boolean
         *      true = removed group successfull
         *      error = removing group failed
         */
        removeGroup: function (groupId) {
            if (checkRights.checkUserRight("", Meteor.userId())) {
                if (groupId) {
                    var users = Groups.findOne({_id: groupId}).users;
                    var group = Groups.remove({_id: groupId});
                    //Find children and remove parentId
                    var children = Groups.update({parentGroup: groupId}, {
                        $set: {parentGroup: null}
                    });

                    _.each(users, function (user) {
                        Meteor.users.update(
                            {
                                _id: user.id
                            }, {
                                $pull: {
                                    'profile.groups': {
                                        id: groupId
                                    }
                                }
                            });
                    });

                    return true;
                } else {
                    throw new Meteor.Error("groups", "No group id was specified while removing group");
                }
            }
        },
        /*
         * add user role
         * @param String groupId
         * @param String userId
         * @param String role
         * @return Boolean
         *      true = added role
         *      error = error
         */
        addUserRoleInGroup: function(groupId, userId, role){
            if(typeof groupId !== 'undefined'
                && typeof userId !== 'undefined'
                && typeof role !== 'undefined'){
                var roleExists = Meteor.roles.findOne({name:role, groupId: groupId});
                if(!roleExists)
                    throw new Meteor.Error("GroupUserRoles", "The role does not exist");

                Groups.update({_id: groupId, 'users.id': userId},{
                    $addToSet: {
                        'users.$.roles':role
                    }
                });
            }
        },
        /*
         * add user role
         * @param String groupId
         * @param String userId
         * @param String role
         * @return Boolean
         *      true = added role
         *      error = error
         */
        deleteUserRoleInGroup: function(groupId, userId, role){
            if(typeof groupId !== 'undefined'
                && typeof userId !== 'undefined'
                && typeof role !== 'undefined'){
                var roleExists = Meteor.roles.findOne({name:role, groupId: groupId});
                if(!roleExists)
                    throw new Meteor.Error("GroupUserRoles", "The role does not exist");

                Groups.update({_id: groupId, 'users.id': userId},{
                    $pull: {
                        'users.$.roles':role
                    }
                });
            }
        }
    });
}
<|endoftext|>