<commit_before>'use strict';

angular.module('core').controller(['gettext',
    function(gettext) {
        var missingKeys = [
            gettext('No Signal'),
            gettext('Signal OK'),
            gettext('Personal Details'),
            gettext('Gender'),
            gettext('Male'),
            gettext('Female'),
            gettext('Nationality'),
            gettext('Afghan'),
            gettext('Albanian'),
            gettext('Algerian'),
            gettext('American'),
            gettext('Andorran'),
            gettext('Angolan'),
            gettext('Antiguans'),
            gettext('Argentinean'),
            gettext('Armenian'),
            gettext('Australian'),
            gettext('Austrian'),
            gettext('Azerbaijani'),
            gettext('Bahamian'),
            gettext('Bahraini'),
            gettext('Bangladeshi'),
            gettext('Barbadian'),
            gettext('Barbudans'),
            gettext('Batswana'),
            gettext('Belarusian'),
            gettext('Belgian'),
            gettext('Belizean'),
            gettext('Beninese'),
            gettext('Bhutanese'),
            gettext('Bolivian'),
            gettext('Bosnian'),
            gettext('Brazilian'),
            gettext('British'),
            gettext('Bruneian'),
            gettext('Bulgarian'),
            gettext('Burkinabe'),
            gettext('Burmese'),
            gettext('Burundian'),
            gettext('Cambodian'),
            gettext('Cameroonian'),
            gettext('Canadian'),
            gettext('Cape Verdean'),
            gettext('Central African'),
            gettext('Chadian'),
            gettext('Chilean'),
            gettext('Chinese'),
            gettext('Colombian'),
            gettext('Comoran'),
            gettext('Congolese'),
            gettext('Costa Rican'),
            gettext('Croatian'),
            gettext('Cuban'),
            gettext('Cypriot'),
            gettext('Czech'),
            gettext('Danish'),
            gettext('Djibouti'),
            gettext('Dominican'),
            gettext('Dutch'),
            gettext('East Timorese'),
            gettext('Ecuadorean'),
            gettext('Egyptian'),
            gettext('Emirian'),
            gettext('Equatorial Guinean'),
            gettext('Eritrean'),
            gettext('Estonian'),
            gettext('Ethiopian'),
            gettext('Fijian'),
            gettext('Filipino'),
            gettext('Finnish'),
            gettext('French'),
            gettext('Gabonese'),
            gettext('Gambian'),
            gettext('Georgian'),
            gettext('German'),
            gettext('Ghanaian'),
            gettext('Greek'),
            gettext('Grenadian'),
            gettext('Guatemalan'),
            gettext('Guinea-Bissauan'),
            gettext('Guinean'),
            gettext('Guyanese'),
            gettext('Haitian'),
            gettext('Herzegovinian'),
            gettext('Honduran'),
            gettext('Hungarian'),
            gettext('I-Kiribati'),
            gettext('Icelander'),
            gettext('Indian'),
            gettext('Indonesian'),
            gettext('Iranian'),
            gettext('Iraqi'),
            gettext('Irish'),
            gettext('Israeli'),
            gettext('Italian'),
            gettext('Ivorian'),
            gettext('Jamaican'),
            gettext('Japanese'),
            gettext('Jordanian'),
            gettext('Kazakhstani'),
            gettext('Kenyan'),
            gettext('Kittian and Nevisian'),
            gettext('Kuwaiti'),
            gettext('Kyrgyz'),
            gettext('Laotian'),
            gettext('Latvian'),
            gettext('Lebanese'),
            gettext('Liberian'),
            gettext('Libyan'),
            gettext('Liechtensteiner'),
            gettext('Lithuanian'),
            gettext('Luxembourger'),
            gettext('Macedonian'),
            gettext('Malagasy'),
            gettext('Malawian'),
            gettext('Malaysian'),
            gettext('Maldivan'),
            gettext('Malian'),
            gettext('Maltese'),
            gettext('Marshallese'),
            gettext('Mauritanian'),
            gettext('Mauritian'),
            gettext('Mexican'),
            gettext('Micronesian'),
            gettext('Moldovan'),
            gettext('Monacan'),
            gettext('Mongolian'),
            gettext('Moroccan'),
            gettext('Mosotho'),
            gettext('Motswana'),
            gettext('Mozambican'),
            gettext('Namibian'),
            gettext('Nauruan'),
            gettext('Nepalese'),
            gettext('New Zealander'),
            gettext('Nicaraguan'),
            gettext('Nigerian'),
            gettext('Nigerien'),
            gettext('North Korean'),
            gettext('Northern Irish'),
            gettext('Norwegian'),
            gettext('Omani'),
            gettext('Pakistani'),
            gettext('Palauan'),
            gettext('Panamanian'),
            gettext('Papua New Guinean'),
            gettext('Paraguayan'),
            gettext('Peruvian'),
            gettext('Polish'),
            gettext('Portuguese'),
            gettext('Qatari'),
            gettext('Romanian'),
            gettext('Russian'),
            gettext('Rwandan'),
            gettext('Saint Lucian'),
            gettext('Salvadoran'),
            gettext('Samoan'),
            gettext('San Marinese'),
            gettext('Sao Tomean'),
            gettext('Saudi'),
            gettext('Scottish'),
            gettext('Senegalese'),
            gettext('Serbian'),
            gettext('Seychellois'),
            gettext('Sierra Leonean'),
            gettext('Singaporean'),
            gettext('Slovakian'),
            gettext('Slovenian'),
            gettext('Solomon Islander'),
            gettext('Somali'),
            gettext('South African'),
            gettext('South Korean'),
            gettext('Spanish'),
            gettext('Sri Lankan'),
            gettext('Sudanese'),
            gettext('Surinamer'),
            gettext('Swazi'),
            gettext('Swedish'),
            gettext('Swiss'),
            gettext('Syrian'),
            gettext('Taiwanese'),
            gettext('Tajik'),
            gettext('Tanzanian'),
            gettext('Thai'),
            gettext('Togolese'),
            gettext('Tongan'),
            gettext('Trinidadian or Tobagonian'),
            gettext('Tunisian'),
            gettext('Turkish'),
            gettext('Tuvaluan'),
            gettext('Ugandan'),
            gettext('Ukrainian'),
            gettext('Uruguayan'),
            gettext('Uzbekistani'),
            gettext('Venezuelan'),
            gettext('Vietnamese'),
            gettext('Welsh'),
            gettext('Yemenite'),
            gettext('Zambian'),
            gettext('Zimbabwean'),
            gettext('Birth Year'),
            gettext('Musical Background'),
            gettext('Do you consider yourself a musician or to have specialist musical knowledge?'),
            gettext('Yes'),
            gettext('No'),
            gettext('No expertise whatsoever'),
            gettext('An expert'),
            gettext('Do you have any visual impairments? (If so, you may still participate in the experiment!)'),
            gettext('Select all of the following styles to which you regularly listen:'),
            gettext('Rock'),
            gettext('Pop'),
            gettext('Classical'),
            gettext('Jazz'),
            gettext('Dance'),
            gettext('HipHop'),
            gettext('Folk'),
            gettext('World'),
            gettext('None'),
            gettext('Media Questions'),
            gettext('I was engaged with it and responding to it emotionally'),
            gettext('How involved and engaged were you with what you have just heard?'),
            gettext('Very negative'),
            gettext('Very positive'),
            gettext('How positive or negative did what you have just heard make you feel?'),
            gettext('Very drowsy'),
            gettext('Very lively'),
            gettext('How active or passive did what you have just heard make you feel?'),
            gettext('Weak
(without control, submissive)'),
            gettext('Empowered
(in control of everything, dominant)'),
            gettext('How in control did you feel?'),
            gettext('Not at all engaged, my mind was elsewhere'),
            gettext('Very drowsy'),
            gettext('Very lively'),
            gettext('Weak
(without control, submissive)'),
            gettext('Empowered
(in control of everything, dominant)'),
            gettext('How in control did you feel?'),
            gettext('Not at all'),
            gettext('Very tense'),
            gettext('Very relaxed'),
            gettext('How tense or relaxed did you feel while you were listening?'),
            gettext('I hated it'),
            gettext('I loved it'),
            gettext('How much did you like/dislike what you have just heard?'),
            gettext('I had never heard it before'),
            gettext('I listen to it regularly'),
            gettext('How familiar are you with what you have just heard?'),
            gettext('Age'),
            gettext('How would you rate your musical expertise?'),
            gettext('Do you have any hearing impairments? (If so, you may still participate in the experiment!)'),
            gettext('Additional Questions'),
            gettext('How well do the following statements describe your personality?'),
            gettext('I see myself as someone who is reserved.'),
            gettext('Disagree strongly'),
            gettext('Disagree a little'),
            gettext('Neither agree nor disagree'),
            gettext('Agree a little'),
            gettext('Agree strongly'),
            gettext('I see myself as someone who is generally trusting.'),
            gettext('I see myself as someone who tends to be lazy.'),
            gettext('I see myself as someone who is relaxed, handles stress well.'),
            gettext('I see myself as someone who has few artistic interests.'),
            gettext('I see myself as someone who is outgoing, sociable.'),
            gettext('I see myself as someone who tends to find fault with others.'),
            gettext('I see myself as someone who does a thorough job.'),
            gettext('I see myself as someone who gets nervous easily.'),
            gettext('I see myself as someone who has an active imagination.'),
            gettext('This questionnaire uses some simple scales to find out how you responded to the media excerpt. We will compare your responses to the biosignals that we measured as you were listening.'),
            gettext('Final Questions'),
            gettext('How concentrated were you during this experiment?'),
            gettext('Very distracted'),
            gettext('Very concentrated'),
            gettext('1'),
            gettext('2'),
            gettext('3'),
            gettext('4'),
            gettext('5'),
            gettext('6'),
            gettext('7'),
            gettext('8'),
            gettext('9'),
            gettext('10'),
            gettext('11'),
            gettext('12'),
            gettext('13'),
            gettext('14'),
            gettext('15'),
            gettext('16'),
            gettext('17'),
            gettext('18'),
            gettext('19'),
            gettext('20'),
            gettext('21'),
            gettext('22'),
            gettext('23'),
            gettext('24'),
            gettext('25'),
            gettext('26'),
            gettext('27'),
            gettext('28'),
            gettext('29'),
            gettext('30'),
            gettext('31'),
            gettext('32'),
            gettext('33'),
            gettext('34'),
            gettext('35'),
            gettext('36'),
            gettext('37'),
            gettext('38'),
            gettext('39'),
            gettext('40'),
            gettext('41'),
            gettext('42'),
            gettext('43'),
            gettext('44'),
            gettext('45'),
            gettext('46'),
            gettext('47'),
            gettext('48'),
            gettext('49'),
            gettext('50'),
            gettext('51'),
            gettext('52'),
            gettext('53'),
            gettext('54'),
            gettext('55'),
            gettext('56'),
            gettext('57'),
            gettext('58'),
            gettext('59'),
            gettext('60'),
            gettext('61'),
            gettext('62'),
            gettext('63'),
            gettext('64'),
            gettext('65'),
            gettext('66'),
            gettext('67'),
            gettext('68'),
            gettext('69'),
            gettext('70'),
            gettext('71'),
            gettext('72'),
            gettext('73'),
            gettext('74'),
            gettext('75'),
            gettext('76'),
            gettext('77'),
            gettext('78'),
            gettext('79'),
            gettext('80'),
            gettext('81'),
            gettext('82'),
            gettext('83'),
            gettext('84'),
            gettext('85'),
            gettext('86'),
            gettext('87'),
            gettext('88'),
            gettext('89'),
            gettext('90'),
            gettext('91'),
            gettext('92'),
            gettext('93'),
            gettext('94'),
            gettext('95'),
            gettext('96'),
            gettext('97'),
            gettext('98'),
            gettext('99'),
            gettext('100'),
            gettext('101'),
            gettext('102'),
            gettext('103'),
            gettext('104'),
            gettext('105'),
            gettext('106'),
            gettext('107'),
            gettext('108'),
            gettext('109'),
            gettext('110'),
            gettext('111'),
            gettext('112'),
            gettext('113'),
            gettext('114'),
            gettext('115'),
            gettext('116'),
            gettext('117'),
            gettext('118'),
            gettext('119'),
            gettext('120'),
            gettext('121')
        ];
    }
]);
<commit_msg>Remove unused variable in core.client.missing-keys.js<commit_after>'use strict';

angular.module('core').controller(['gettext',
    function (gettext) {
        gettext('No Signal');
        gettext('Signal OK');
        gettext('Personal Details');
        gettext('Gender');
        gettext('Male');
        gettext('Female');
        gettext('Nationality');
        gettext('Afghan');
        gettext('Albanian');
        gettext('Algerian');
        gettext('American');
        gettext('Andorran');
        gettext('Angolan');
        gettext('Antiguans');
        gettext('Argentinean');
        gettext('Armenian');
        gettext('Australian');
        gettext('Austrian');
        gettext('Azerbaijani');
        gettext('Bahamian');
        gettext('Bahraini');
        gettext('Bangladeshi');
        gettext('Barbadian');
        gettext('Barbudans');
        gettext('Batswana');
        gettext('Belarusian');
        gettext('Belgian');
        gettext('Belizean');
        gettext('Beninese');
        gettext('Bhutanese');
        gettext('Bolivian');
        gettext('Bosnian');
        gettext('Brazilian');
        gettext('British');
        gettext('Bruneian');
        gettext('Bulgarian');
        gettext('Burkinabe');
        gettext('Burmese');
        gettext('Burundian');
        gettext('Cambodian');
        gettext('Cameroonian');
        gettext('Canadian');
        gettext('Cape Verdean');
        gettext('Central African');
        gettext('Chadian');
        gettext('Chilean');
        gettext('Chinese');
        gettext('Colombian');
        gettext('Comoran');
        gettext('Congolese');
        gettext('Costa Rican');
        gettext('Croatian');
        gettext('Cuban');
        gettext('Cypriot');
        gettext('Czech');
        gettext('Danish');
        gettext('Djibouti');
        gettext('Dominican');
        gettext('Dutch');
        gettext('East Timorese');
        gettext('Ecuadorean');
        gettext('Egyptian');
        gettext('Emirian');
        gettext('Equatorial Guinean');
        gettext('Eritrean');
        gettext('Estonian');
        gettext('Ethiopian');
        gettext('Fijian');
        gettext('Filipino');
        gettext('Finnish');
        gettext('French');
        gettext('Gabonese');
        gettext('Gambian');
        gettext('Georgian');
        gettext('German');
        gettext('Ghanaian');
        gettext('Greek');
        gettext('Grenadian');
        gettext('Guatemalan');
        gettext('Guinea-Bissauan');
        gettext('Guinean');
        gettext('Guyanese');
        gettext('Haitian');
        gettext('Herzegovinian');
        gettext('Honduran');
        gettext('Hungarian');
        gettext('I-Kiribati');
        gettext('Icelander');
        gettext('Indian');
        gettext('Indonesian');
        gettext('Iranian');
        gettext('Iraqi');
        gettext('Irish');
        gettext('Israeli');
        gettext('Italian');
        gettext('Ivorian');
        gettext('Jamaican');
        gettext('Japanese');
        gettext('Jordanian');
        gettext('Kazakhstani');
        gettext('Kenyan');
        gettext('Kittian and Nevisian');
        gettext('Kuwaiti');
        gettext('Kyrgyz');
        gettext('Laotian');
        gettext('Latvian');
        gettext('Lebanese');
        gettext('Liberian');
        gettext('Libyan');
        gettext('Liechtensteiner');
        gettext('Lithuanian');
        gettext('Luxembourger');
        gettext('Macedonian');
        gettext('Malagasy');
        gettext('Malawian');
        gettext('Malaysian');
        gettext('Maldivan');
        gettext('Malian');
        gettext('Maltese');
        gettext('Marshallese');
        gettext('Mauritanian');
        gettext('Mauritian');
        gettext('Mexican');
        gettext('Micronesian');
        gettext('Moldovan');
        gettext('Monacan');
        gettext('Mongolian');
        gettext('Moroccan');
        gettext('Mosotho');
        gettext('Motswana');
        gettext('Mozambican');
        gettext('Namibian');
        gettext('Nauruan');
        gettext('Nepalese');
        gettext('New Zealander');
        gettext('Nicaraguan');
        gettext('Nigerian');
        gettext('Nigerien');
        gettext('North Korean');
        gettext('Northern Irish');
        gettext('Norwegian');
        gettext('Omani');
        gettext('Pakistani');
        gettext('Palauan');
        gettext('Panamanian');
        gettext('Papua New Guinean');
        gettext('Paraguayan');
        gettext('Peruvian');
        gettext('Polish');
        gettext('Portuguese');
        gettext('Qatari');
        gettext('Romanian');
        gettext('Russian');
        gettext('Rwandan');
        gettext('Saint Lucian');
        gettext('Salvadoran');
        gettext('Samoan');
        gettext('San Marinese');
        gettext('Sao Tomean');
        gettext('Saudi');
        gettext('Scottish');
        gettext('Senegalese');
        gettext('Serbian');
        gettext('Seychellois');
        gettext('Sierra Leonean');
        gettext('Singaporean');
        gettext('Slovakian');
        gettext('Slovenian');
        gettext('Solomon Islander');
        gettext('Somali');
        gettext('South African');
        gettext('South Korean');
        gettext('Spanish');
        gettext('Sri Lankan');
        gettext('Sudanese');
        gettext('Surinamer');
        gettext('Swazi');
        gettext('Swedish');
        gettext('Swiss');
        gettext('Syrian');
        gettext('Taiwanese');
        gettext('Tajik');
        gettext('Tanzanian');
        gettext('Thai');
        gettext('Togolese');
        gettext('Tongan');
        gettext('Trinidadian or Tobagonian');
        gettext('Tunisian');
        gettext('Turkish');
        gettext('Tuvaluan');
        gettext('Ugandan');
        gettext('Ukrainian');
        gettext('Uruguayan');
        gettext('Uzbekistani');
        gettext('Venezuelan');
        gettext('Vietnamese');
        gettext('Welsh');
        gettext('Yemenite');
        gettext('Zambian');
        gettext('Zimbabwean');
        gettext('Birth Year');
        gettext('Musical Background');
        gettext('Do you consider yourself a musician or to have specialist musical knowledge?');
        gettext('Yes');
        gettext('No');
        gettext('No expertise whatsoever');
        gettext('An expert');
        gettext('Do you have any visual impairments? (If so, you may still participate in the experiment!)');
        gettext('Select all of the following styles to which you regularly listen:');
        gettext('Rock');
        gettext('Pop');
        gettext('Classical');
        gettext('Jazz');
        gettext('Dance');
        gettext('HipHop');
        gettext('Folk');
        gettext('World');
        gettext('None');
        gettext('Media Questions');
        gettext('I was engaged with it and responding to it emotionally');
        gettext('How involved and engaged were you with what you have just heard?');
        gettext('Very negative');
        gettext('Very positive');
        gettext('How positive or negative did what you have just heard make you feel?');
        gettext('Very drowsy');
        gettext('Very lively');
        gettext('How active or passive did what you have just heard make you feel?');
        gettext('Weak
(without control, submissive)');
        gettext('Empowered
(in control of everything, dominant)');
        gettext('How in control did you feel?');
        gettext('Not at all engaged, my mind was elsewhere');
        gettext('Very drowsy');
        gettext('Very lively');
        gettext('Weak
(without control, submissive)');
        gettext('Empowered
(in control of everything, dominant)');
        gettext('How in control did you feel?');
        gettext('Not at all');
        gettext('Very tense');
        gettext('Very relaxed');
        gettext('How tense or relaxed did you feel while you were listening?');
        gettext('I hated it');
        gettext('I loved it');
        gettext('How much did you like/dislike what you have just heard?');
        gettext('I had never heard it before');
        gettext('I listen to it regularly');
        gettext('How familiar are you with what you have just heard?');
        gettext('Age');
        gettext('How would you rate your musical expertise?');
        gettext('Do you have any hearing impairments? (If so, you may still participate in the experiment!)');
        gettext('Additional Questions');
        gettext('How well do the following statements describe your personality?');
        gettext('I see myself as someone who is reserved.');
        gettext('Disagree strongly');
        gettext('Disagree a little');
        gettext('Neither agree nor disagree');
        gettext('Agree a little');
        gettext('Agree strongly');
        gettext('I see myself as someone who is generally trusting.');
        gettext('I see myself as someone who tends to be lazy.');
        gettext('I see myself as someone who is relaxed, handles stress well.');
        gettext('I see myself as someone who has few artistic interests.');
        gettext('I see myself as someone who is outgoing, sociable.');
        gettext('I see myself as someone who tends to find fault with others.');
        gettext('I see myself as someone who does a thorough job.');
        gettext('I see myself as someone who gets nervous easily.');
        gettext('I see myself as someone who has an active imagination.');
        gettext('This questionnaire uses some simple scales to find out how you responded to the media excerpt. We will compare your responses to the biosignals that we measured as you were listening.');
        gettext('Final Questions');
        gettext('How concentrated were you during this experiment?');
        gettext('Very distracted');
        gettext('Very concentrated');
        gettext('1');
        gettext('2');
        gettext('3');
        gettext('4');
        gettext('5');
        gettext('6');
        gettext('7');
        gettext('8');
        gettext('9');
        gettext('10');
        gettext('11');
        gettext('12');
        gettext('13');
        gettext('14');
        gettext('15');
        gettext('16');
        gettext('17');
        gettext('18');
        gettext('19');
        gettext('20');
        gettext('21');
        gettext('22');
        gettext('23');
        gettext('24');
        gettext('25');
        gettext('26');
        gettext('27');
        gettext('28');
        gettext('29');
        gettext('30');
        gettext('31');
        gettext('32');
        gettext('33');
        gettext('34');
        gettext('35');
        gettext('36');
        gettext('37');
        gettext('38');
        gettext('39');
        gettext('40');
        gettext('41');
        gettext('42');
        gettext('43');
        gettext('44');
        gettext('45');
        gettext('46');
        gettext('47');
        gettext('48');
        gettext('49');
        gettext('50');
        gettext('51');
        gettext('52');
        gettext('53');
        gettext('54');
        gettext('55');
        gettext('56');
        gettext('57');
        gettext('58');
        gettext('59');
        gettext('60');
        gettext('61');
        gettext('62');
        gettext('63');
        gettext('64');
        gettext('65');
        gettext('66');
        gettext('67');
        gettext('68');
        gettext('69');
        gettext('70');
        gettext('71');
        gettext('72');
        gettext('73');
        gettext('74');
        gettext('75');
        gettext('76');
        gettext('77');
        gettext('78');
        gettext('79');
        gettext('80');
        gettext('81');
        gettext('82');
        gettext('83');
        gettext('84');
        gettext('85');
        gettext('86');
        gettext('87');
        gettext('88');
        gettext('89');
        gettext('90');
        gettext('91');
        gettext('92');
        gettext('93');
        gettext('94');
        gettext('95');
        gettext('96');
        gettext('97');
        gettext('98');
        gettext('99');
        gettext('100');
        gettext('101');
        gettext('102');
        gettext('103');
        gettext('104');
        gettext('105');
        gettext('106');
        gettext('107');
        gettext('108');
        gettext('109');
        gettext('110');
        gettext('111');
        gettext('112');
        gettext('113');
        gettext('114');
        gettext('115');
        gettext('116');
        gettext('117');
        gettext('118');
        gettext('119');
        gettext('120');
        gettext('121');
    }
]);
<|endoftext|>


<commit_before>import { Meteor } from 'meteor/meteor';
import { ValidatedMethod } from 'meteor/mdg:validated-method';
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
import { Roles } from 'meteor/alanning:roles';

import { Locations } from '/imports/api/locations/locations';

export const createLocation = new ValidatedMethod({
  name: 'locations.createLocation',
  validate: Locations.simpleSchema().pick([
    'name',
  ]).validator(),
  run({ name }) {
    if (this.connection) {
      const user = Meteor.users.findOne(this.userId);
      if (!user.isTAOrAbove()) {
        throw new Meteor.Error('locations.createLocation.unauthorized',
        'Only TAs and above can create locations.');
      }
    }

    const location = Locations.findOne({
      name: name,
      deletedAt: { $exists: false },
    });

    if (location) {
      throw new Meteor.Error('locations.createLocation.alreadyExists',
        'A location with that name already exists.');
    }

    return Locations.insert({ name });
  },
});

export const updateLocation = new ValidatedMethod({
  name: 'locations.updateLocation',
  validate: new SimpleSchema({
    locationId: { type: String, regEx: SimpleSchema.RegEx.Id },
    name: { type: String },
  }).validator(),
  run({ locationId, name }) {
    const location = Locations.findOne(locationId);
    if (!location) {
      throw new Meteor.Error('locations.doesNotExist',
        `No location exists with id ${locationId}`);
    }

    const user = Meteor.users.findOne(this.userId);
    if (!user.isTAOrAbove()) {
      throw new Meteor.Error('locations.createLocation.unauthorized',
      'Only TAs and above can create locations.');
    }

    Locations.update({
      _id: locationId,
    }, {
      $set: {
        name: name,
      },
    });
  },
});

export const deleteLocation = new ValidatedMethod({
  name: 'locations.deleteLocation',
  validate: new SimpleSchema({
    locationId: { type: String, regEx: SimpleSchema.RegEx.Id },
  }).validator(),
  run({ locationId }) {
    const location = Locations.findOne(locationId);
    if (!location) {
      throw new Meteor.Error('locations.doesNotExist',
        `No location exists with id ${locationId}`);
    }

    const user = Meteor.users.findOne(this.userId);
    if (!user.isTAOrAbove()) {
      throw new Meteor.Error('locations.createLocation.unauthorized',
      'Only TAs and above can create locations.');
    }

    Locations.update({
      _id: locationId,
    }, {
      $set: {
        deletedAt: new Date(),
        deletedBy: this.userId,
      },
    });
  },
});
<commit_msg>Remove unused import<commit_after>import { Meteor } from 'meteor/meteor';
import { ValidatedMethod } from 'meteor/mdg:validated-method';
import { SimpleSchema } from 'meteor/aldeed:simple-schema';

import { Locations } from '/imports/api/locations/locations';

export const createLocation = new ValidatedMethod({
  name: 'locations.createLocation',
  validate: Locations.simpleSchema().pick([
    'name',
  ]).validator(),
  run({ name }) {
    if (this.connection) {
      const user = Meteor.users.findOne(this.userId);
      if (!user.isTAOrAbove()) {
        throw new Meteor.Error('locations.createLocation.unauthorized',
        'Only TAs and above can create locations.');
      }
    }

    const location = Locations.findOne({
      name: name,
      deletedAt: { $exists: false },
    });

    if (location) {
      throw new Meteor.Error('locations.createLocation.alreadyExists',
        'A location with that name already exists.');
    }

    return Locations.insert({ name });
  },
});

export const updateLocation = new ValidatedMethod({
  name: 'locations.updateLocation',
  validate: new SimpleSchema({
    locationId: { type: String, regEx: SimpleSchema.RegEx.Id },
    name: { type: String },
  }).validator(),
  run({ locationId, name }) {
    const location = Locations.findOne(locationId);
    if (!location) {
      throw new Meteor.Error('locations.doesNotExist',
        `No location exists with id ${locationId}`);
    }

    const user = Meteor.users.findOne(this.userId);
    if (!user.isTAOrAbove()) {
      throw new Meteor.Error('locations.createLocation.unauthorized',
      'Only TAs and above can create locations.');
    }

    Locations.update({
      _id: locationId,
    }, {
      $set: {
        name: name,
      },
    });
  },
});

export const deleteLocation = new ValidatedMethod({
  name: 'locations.deleteLocation',
  validate: new SimpleSchema({
    locationId: { type: String, regEx: SimpleSchema.RegEx.Id },
  }).validator(),
  run({ locationId }) {
    const location = Locations.findOne(locationId);
    if (!location) {
      throw new Meteor.Error('locations.doesNotExist',
        `No location exists with id ${locationId}`);
    }

    const user = Meteor.users.findOne(this.userId);
    if (!user.isTAOrAbove()) {
      throw new Meteor.Error('locations.createLocation.unauthorized',
      'Only TAs and above can create locations.');
    }

    Locations.update({
      _id: locationId,
    }, {
      $set: {
        deletedAt: new Date(),
        deletedBy: this.userId,
      },
    });
  },
});
<|endoftext|>


<commit_before>import { Meteor } from 'meteor/meteor';
import { Bert } from 'meteor/themeteorchef:bert';
import React from 'react';
import { browserHistory } from 'react-router';
import MuiTheme from '../layouts/mui-theme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import FloatingActionButton from 'material-ui/FloatingActionButton';
import IconButton from 'material-ui/IconButton';
import RefreshIndicator from 'material-ui/RefreshIndicator';

import LeafletMap from '../components/map/leaflet-map';
import MapInfoBox from '../components/map/map-info-box';
import MapUserBox from '../components/map/map-user-box';
import { GoToGeolocationButton } from '../components/map/go-to-geolocation-button';
import InsertBtnDialog from '../components/map/insert-button-dialog';
import EditBtnDialog from '../components/map/edit-button-dialog';

import * as LatLngHelper from '../../util/latlng';
import * as IconsHelper from '../../util/icons';

import { Giveaways } from '../../api/giveaways/giveaways';

export class MyGiveaways extends React.Component {
  constructor(props) {
    super(props);
    const self = this;

    this.state = {
      // Properties
      gaSelected: null,
      infoBoxState: 0,
      nearbyBoxState: 1,
      geolocation: null,
      mapCenter: null,
      mapZoom: null,
      mapMaxZoom: null,
      isModalOpen: false,
      latLngClicked: {lat:"",lng:""},
      locName: "",
      locArr: [],
      isDraggableAdded: false,
      showMarkers: true,
      rGeoLoading: false,
      gaEdit: null,
      gaId: null,
      showDateRange: false,
    };

    this.userUntilDate = new ReactiveVar( moment().set('hour', 0).set('minute',0).add(1,'w').toDate() );
    this.userFromDate = new ReactiveVar( moment().set('hour', 0).set('minute',0).toDate() );
    this.isAllGa = new ReactiveVar( true );

    this.mapBounds = new ReactiveVar( null );

    this.subscription = null;
    this.autorunSub = null;
    this.autorunGeo = null;
    this.autorunAuth = null;
  }

  selectGa(gaId) {
    this.setState({
      gaSelected: gaId,
      infoBoxState: 1,  // Bottom bar: peek title / Sidebar: show
    });
  }

  setInfoBoxState(x) {
    this.setState({ infoBoxState: x });
    if (!x) this.setState({ gaSelected: null });
  }

  setNearbyBoxState(x) {
    this.setState({ nearbyBoxState: x });
  }

  componentDidMount() {
    const self = this;
    this.autorunSub = Tracker.autorun(function () {
      // const reactiveDateTime = Chronos.currentTime(Meteor.settings.public.refresh_interval || 60000);
      // const reactiveMapBounds = self.mapBounds.get();
      const userFromDate = self.userFromDate.get();
      const userUntilDate = self.userUntilDate.get();
      const isAllGa = self.isAllGa.get();
      // trigger ui update
      self.setState({showDateRange: self.state.showDateRange});

      // Re-subscribe when date range changes
      if (userFromDate && userUntilDate) {
        self.subscription = Meteor.subscribe('user-giveaways-within-date', userFromDate, userUntilDate, isAllGa);
      }
    });

    this.autorunGeo = Tracker.autorun(function() {
      const reactiveLatLng = Geolocation.latLng();
      // Set current location
      self.setState({ geolocation: reactiveLatLng });
    });

    const paramId = this.props.params.id;
    if (paramId) {
      Meteor.subscribe('giveaway-by-id', paramId, function() {
        const giveaway = Giveaways.findOne(paramId);
        const handler = self.selectEditGa(giveaway);
        handler();
      });
    }
  }

  componentWillUnmount() {
    this.subscription && this.subscription.stop();
    this.autorunSub && this.autorunSub.stop();
    this.autorunGeo && this.autorunGeo.stop();
  }

  handleParams(paramId) {
  }

  goToGeolocation() {
    this.setState({ mapCenter: this.state.geolocation });
  }

  closeModal() {
    this.setState({ isModalOpen: false });
  }

  openModal() {
    this.setState({ isModalOpen: true });
  }

  addDraggable() {
    this.setState({ isDraggableAdded: true });
  }
  noAddDraggable() {
    this.setState({ isDraggableAdded: false });
  }

  showMarkers() {
    this.setState({ showMarkers: true });
  }

  hideMarkers() {
    this.setState({ showMarkers: false });
  }

  resetLoc() {
    this.setState({
      latLngClicked: {lat:"",lng:""},
      locArr: [],
      locName: "",
    })
  }

  addRGeoSpinner(){
    this.setState({ rGeoLoading: true });
  }

  rmvRGeoSpinner(){
    this.setState({ rGeoLoading: false });
  }

  handleUserUntilDate(event, date){
    this.userUntilDate.set(moment(date).add(23,'h').add(59,'m').toDate());
  }
  handleUserFromDate(event, date){
    this.userFromDate.set(date);
  }

  handleAllUserGiveaways(){
    this.setState({ showDateRange: !this.state.showDateRange });
    this.isAllGa.set(!this.isAllGa.get());
  }

  openEditDialog(features, coords, removeDraggable) {
    this.setState({ isModalOpen: true });
    this.setState({ latLngClicked: coords });
    let featuresArr = features.map((loc)=> {
      loc.text = loc.place_name;
      loc.value = loc.place_name;
      return loc;
    });
    const selectedLocName = featuresArr[0].text;
    this.setState({ locArr: featuresArr });
    this.setState({ locName: selectedLocName });
    Bert.alert({
      hideDelay: 6000,
      title: 'Location Selected',
      message: selectedLocName,
      type: 'info',
      style: 'growl-top-right',
      icon: 'fa-map-marker'
    });
    if(removeDraggable){
      removeDraggable();
    }
    this.showMarkers();
  }

  selectEditGa(ga) {
    const self = this;

    return event => {
      self.setState({ isModalOpen: ga ? true : false, gaEdit: ga }, () => {
        if (ga)
          browserHistory.push(`/my-giveaways/${ga._id}`);
        else
          browserHistory.push(`/my-giveaways`);
      });
    }
  }

  render() {
    const clickNearbyGa = ga => event => {
      this.selectGa(ga._id);
      this.setState({ mapCenter: LatLngHelper.lnglat2latlng(ga.coordinates) });
      this.setState({ mapZoom: this.state.mapMaxZoom });
    };

    return (

        <LeafletMap
          gaId={ this.state.gaSelected }
          infoBoxState={ this.state.infoBoxState }
          markerOnClick={ gaId => this.selectGa(gaId) }
          mapCenter={ this.state.mapCenter }
          setMapCenter={ mapCenter => this.setState({ mapCenter: mapCenter }) }
          mapZoom={ this.state.mapZoom }
          setMapZoom={ mapZoom => this.setState({ mapZoom: mapZoom })}
          setMapMaxZoom={ mapMaxZoom => this.setState({ mapMaxZoom: mapMaxZoom })}
          setBounds={ bounds => this.mapBounds.set(bounds) }
          openInsertDialog={ this.openEditDialog.bind(this) }
          isDraggableAdded={ this.state.isDraggableAdded }
          stopDraggableAdded={ this.noAddDraggable.bind(this) }
          showMarkers={ this.state.showMarkers }
          addRGeoSpinner={ this.addRGeoSpinner.bind(this) }
          rmvRGeoSpinner={ this.rmvRGeoSpinner.bind(this) }
          isDbClickDisabled= { true } />

        <RefreshIndicator
          size={40}
          left={$(window).width()/2}
          top={ 10}
          status={ this.state.rGeoLoading ? "loading" : "hide" } />

          <MapInfoBox
            gaId={ this.state.gaSelected }
            boxState={ this.state.infoBoxState }
            setBoxState={ this.setInfoBoxState.bind(this) } />
          <MapUserBox
            gaId={ this.state.gaSelected }
            boxState={ this.state.nearbyBoxState }
            setBoxState={ this.setNearbyBoxState.bind(this) }
            mapBounds={ this.mapBounds.get() }
            nearbyOnClick={ clickNearbyGa }
            userUntilDate={ this.userUntilDate.get() }
            userFromDate={ this.userFromDate.get() }
            handleUserUntilDate={ this.handleUserUntilDate.bind(this) }
            handleUserFromDate={ this.handleUserFromDate.bind(this) }
            handleAllUserGiveaways={ this.handleAllUserGiveaways.bind(this) }
            editGa={ this.selectEditGa.bind(this) }
            showDateRange={ this.state.showDateRange } />

 0 ? $("#map-nearby-box").outerWidth() : 0) }}>
          <GoToGeolocationButton geolocationOnClick={ this.goToGeolocation.bind(this) } />

        <EditBtnDialog
          isModalOpen={ this.state.isModalOpen }
          openModal={ this.openModal.bind(this) }
          closeModal={ (this.selectEditGa.bind(this))(null) }
          latLng={ this.state.latLngClicked }
          locArr={ this.state.locArr }
          locName={ this.state.locName }
          addDraggable={ this.addDraggable.bind(this) }
          stopDraggableAdded={ this.noAddDraggable.bind(this) }
          hideMarkers={ this.hideMarkers.bind(this) }
          resetLoc={ this.resetLoc.bind(this) }
          gaEdit={ this.state.gaEdit }
          gaId={ this.state.gaSelected }
          mapCenter={ this.state.mapCenter } />

    );
  }
}

MyGiveaways.propTypes = {
  name: React.PropTypes.string,
};
<commit_msg>Bugfix: Fix cannot open editGa Dialog when navigating from another page (related to #31)<commit_after>import { Meteor } from 'meteor/meteor';
import { Bert } from 'meteor/themeteorchef:bert';
import React from 'react';
import { browserHistory } from 'react-router';
import MuiTheme from '../layouts/mui-theme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import FloatingActionButton from 'material-ui/FloatingActionButton';
import IconButton from 'material-ui/IconButton';
import RefreshIndicator from 'material-ui/RefreshIndicator';

import LeafletMap from '../components/map/leaflet-map';
import MapInfoBox from '../components/map/map-info-box';
import MapUserBox from '../components/map/map-user-box';
import { GoToGeolocationButton } from '../components/map/go-to-geolocation-button';
import InsertBtnDialog from '../components/map/insert-button-dialog';
import EditBtnDialog from '../components/map/edit-button-dialog';

import * as LatLngHelper from '../../util/latlng';
import * as IconsHelper from '../../util/icons';

import { Giveaways } from '../../api/giveaways/giveaways';

export class MyGiveaways extends React.Component {
  constructor(props) {
    super(props);
    const self = this;

    this.state = {
      // Properties
      gaSelected: null,
      infoBoxState: 0,
      nearbyBoxState: 1,
      geolocation: null,
      mapCenter: null,
      mapZoom: null,
      mapMaxZoom: null,
      isModalOpen: false,
      latLngClicked: {lat:"",lng:""},
      locName: "",
      locArr: [],
      isDraggableAdded: false,
      showMarkers: true,
      rGeoLoading: false,
      gaEdit: null,
      gaId: null,
      showDateRange: false,
      paramId: null,
    };

    this.userUntilDate = new ReactiveVar( moment().set('hour', 0).set('minute',0).add(1,'w').toDate() );
    this.userFromDate = new ReactiveVar( moment().set('hour', 0).set('minute',0).toDate() );
    this.isAllGa = new ReactiveVar( true );

    this.mapBounds = new ReactiveVar( null );

    this.subscription = null;
    this.autorunSub = null;
    this.autorunGeo = null;
    this.autorunAuth = null;
  }

  selectGa(gaId) {
    this.setState({
      gaSelected: gaId,
      infoBoxState: 1,  // Bottom bar: peek title / Sidebar: show
    });
  }

  setInfoBoxState(x) {
    this.setState({ infoBoxState: x });
    if (!x) this.setState({ gaSelected: null });
  }

  setNearbyBoxState(x) {
    this.setState({ nearbyBoxState: x });
  }

  componentDidMount() {
    const self = this;
    this.autorunSub = Tracker.autorun(function () {
      // const reactiveDateTime = Chronos.currentTime(Meteor.settings.public.refresh_interval || 60000);
      // const reactiveMapBounds = self.mapBounds.get();
      const userFromDate = self.userFromDate.get();
      const userUntilDate = self.userUntilDate.get();
      const isAllGa = self.isAllGa.get();
      // trigger ui update
      self.setState({showDateRange: self.state.showDateRange});

      // Re-subscribe when date range changes
      if (userFromDate && userUntilDate) {
        self.subscription = Meteor.subscribe('user-giveaways-within-date', userFromDate, userUntilDate, isAllGa);
      }
    });

    this.autorunGeo = Tracker.autorun(function() {
      const reactiveLatLng = Geolocation.latLng();
      // Set current location
      self.setState({ geolocation: reactiveLatLng });
    });

    Meteor.subscribe('giveaway-by-id', paramId, function() {
      self.handleParams();
    });
  }

  componentDidUpdate() {
    this.handleParams();
  }

  componentWillUnmount() {
    this.subscription && this.subscription.stop();
    this.autorunSub && this.autorunSub.stop();
    this.autorunGeo && this.autorunGeo.stop();
  }

  handleParams() {
    const self = this;
    const paramId = this.props.params.id;

    if (this.state.paramId != paramId) {
      this.setState({ paramId }, () => {
        if (paramId) {
          const giveaway = Giveaways.findOne(paramId);
          const handler = self.selectEditGa(giveaway);
          handler();
        } else {
          (self.selectEditGa(null))();
        }
      });
    }
  }

  goToGeolocation() {
    this.setState({ mapCenter: this.state.geolocation });
  }

  closeModal() {
    this.setState({ isModalOpen: false });
  }

  openModal() {
    this.setState({ isModalOpen: true });
  }

  addDraggable() {
    this.setState({ isDraggableAdded: true });
  }
  noAddDraggable() {
    this.setState({ isDraggableAdded: false });
  }

  showMarkers() {
    this.setState({ showMarkers: true });
  }

  hideMarkers() {
    this.setState({ showMarkers: false });
  }

  resetLoc() {
    this.setState({
      latLngClicked: {lat:"",lng:""},
      locArr: [],
      locName: "",
    })
  }

  addRGeoSpinner(){
    this.setState({ rGeoLoading: true });
  }

  rmvRGeoSpinner(){
    this.setState({ rGeoLoading: false });
  }

  handleUserUntilDate(event, date){
    this.userUntilDate.set(moment(date).add(23,'h').add(59,'m').toDate());
  }
  handleUserFromDate(event, date){
    this.userFromDate.set(date);
  }

  handleAllUserGiveaways(){
    this.setState({ showDateRange: !this.state.showDateRange });
    this.isAllGa.set(!this.isAllGa.get());
  }

  openEditDialog(features, coords, removeDraggable) {
    this.setState({ isModalOpen: true });
    this.setState({ latLngClicked: coords });
    let featuresArr = features.map((loc)=> {
      loc.text = loc.place_name;
      loc.value = loc.place_name;
      return loc;
    });
    const selectedLocName = featuresArr[0].text;
    this.setState({ locArr: featuresArr });
    this.setState({ locName: selectedLocName });
    Bert.alert({
      hideDelay: 6000,
      title: 'Location Selected',
      message: selectedLocName,
      type: 'info',
      style: 'growl-top-right',
      icon: 'fa-map-marker'
    });
    if(removeDraggable){
      removeDraggable();
    }
    this.showMarkers();
  }

  selectEditGa(ga) {
    const self = this;

    return event => {
      self.setState({ isModalOpen: ga ? true : false, gaEdit: ga }, () => {
        if (ga)
          browserHistory.push(`/my-giveaways/${ga._id}`);
        else
          browserHistory.push(`/my-giveaways`);
      });
    }
  }

  render() {
    const clickNearbyGa = ga => event => {
      this.selectGa(ga._id);
      this.setState({ mapCenter: LatLngHelper.lnglat2latlng(ga.coordinates) });
      this.setState({ mapZoom: this.state.mapMaxZoom });
    };

    return (

        <LeafletMap
          gaId={ this.state.gaSelected }
          infoBoxState={ this.state.infoBoxState }
          markerOnClick={ gaId => this.selectGa(gaId) }
          mapCenter={ this.state.mapCenter }
          setMapCenter={ mapCenter => this.setState({ mapCenter: mapCenter }) }
          mapZoom={ this.state.mapZoom }
          setMapZoom={ mapZoom => this.setState({ mapZoom: mapZoom })}
          setMapMaxZoom={ mapMaxZoom => this.setState({ mapMaxZoom: mapMaxZoom })}
          setBounds={ bounds => this.mapBounds.set(bounds) }
          openInsertDialog={ this.openEditDialog.bind(this) }
          isDraggableAdded={ this.state.isDraggableAdded }
          stopDraggableAdded={ this.noAddDraggable.bind(this) }
          showMarkers={ this.state.showMarkers }
          addRGeoSpinner={ this.addRGeoSpinner.bind(this) }
          rmvRGeoSpinner={ this.rmvRGeoSpinner.bind(this) }
          isDbClickDisabled= { true } />

        <RefreshIndicator
          size={40}
          left={$(window).width()/2}
          top={ 10}
          status={ this.state.rGeoLoading ? "loading" : "hide" } />

          <MapInfoBox
            gaId={ this.state.gaSelected }
            boxState={ this.state.infoBoxState }
            setBoxState={ this.setInfoBoxState.bind(this) } />
          <MapUserBox
            gaId={ this.state.gaSelected }
            boxState={ this.state.nearbyBoxState }
            setBoxState={ this.setNearbyBoxState.bind(this) }
            mapBounds={ this.mapBounds.get() }
            nearbyOnClick={ clickNearbyGa }
            userUntilDate={ this.userUntilDate.get() }
            userFromDate={ this.userFromDate.get() }
            handleUserUntilDate={ this.handleUserUntilDate.bind(this) }
            handleUserFromDate={ this.handleUserFromDate.bind(this) }
            handleAllUserGiveaways={ this.handleAllUserGiveaways.bind(this) }
            editGa={ this.selectEditGa.bind(this) }
            showDateRange={ this.state.showDateRange } />

 0 ? $("#map-nearby-box").outerWidth() : 0) }}>
          <GoToGeolocationButton geolocationOnClick={ this.goToGeolocation.bind(this) } />

        <EditBtnDialog
          isModalOpen={ this.state.isModalOpen }
          openModal={ this.openModal.bind(this) }
          closeModal={ (this.selectEditGa.bind(this))(null) }
          latLng={ this.state.latLngClicked }
          locArr={ this.state.locArr }
          locName={ this.state.locName }
          addDraggable={ this.addDraggable.bind(this) }
          stopDraggableAdded={ this.noAddDraggable.bind(this) }
          hideMarkers={ this.hideMarkers.bind(this) }
          resetLoc={ this.resetLoc.bind(this) }
          gaEdit={ this.state.gaEdit }
          gaId={ this.state.gaSelected }
          mapCenter={ this.state.mapCenter } />

    );
  }
}

MyGiveaways.propTypes = {
  name: React.PropTypes.string,
};
<|endoftext|>


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

Meteor.methods({
    insertPost: function(post) {
        //Validate post.
        if (post.title) {
            if (post.title.length < 1) {
                delete post.title;
            }

            if (post.title.length > 100) {
                return;
            }
        }

        if (!post.target) {
            return;
        }

        let postId = Posts.insert(post);
        Posts.update({_id: post.target}, {$push: {replies: postId}});
        return postId;
    },
    submitReport: function(report) {
        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} });
    }
});
<commit_msg>Incrementally adding posts to graph<commit_after>/*
    Agora Forum Software
    Copyright (C) 2016 Gregory Sartucci
    License: GPL, Check file LICENSE
*/

Meteor.methods({
    insertPost: function(post) {
        //Validate post.
        if (post.title) {
            if (post.title.length < 1) {
                delete post.title;
            }

            if (post.title.length > 100) {
                return;
            }
        }

        if (!post.target) {
            return;
        }

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

        //Will always insert directly underneath target, shifting existing posts to the right.
        let y = target.defaultPosition.y - 1;
        let x = target.defaultPosition.x;
        post.defaultPosition = {x: x, y: y};

        //Find the chain of adjacent posts which need to be shifted.
        let shifting = false;
        let postsToShift = [];
        let prevColumn;
        Posts.find({'defaultPosition.y': y}, {sort: {'defaultPosition.x': 1}}).forEach(function(post) {
            if (shifting) {
                if (post.defaultPosition.x > prevColumn + 1) {
                    shifting = false;
                }
            }
            else if (post.defaultPosition.x === x) {
                shifting = true;
            }

            if (shifting) {
                postsToShift.push(post);
            }

            prevColumn = post.defaultPosition.x;
        });

        //Shift found posts one column to the right.
        for (let post of postsToShift) {
            let newColumn = post.defaultPosition.x + 1;
            Posts.update({_id: post._id}, {$set: {'defaultPosition.x': newColumn}});
        }

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

        return postId;
    },
    submitReport: function(report) {
        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} });
    }
});
<|endoftext|>


<commit_before>/**
 * This library formats a set of nmr1D signals to the ACS format.
 * Created by acastillo on 3/11/15. p
 */
var ACS=ACS || {};
ACS.formater =(function() {
    var acsString="";
    var parenthesis="";
    var spectro="";
    rangeForMultiplet=false;

    function fromNMRSignal1D2ACS(spectrum, options){
        acsString="";
        parenthesis="";
        spectro="";
        var solvent = null;
        if(options&&options.solvent)
            solvent = options.solvent;
        //options.rangeForMultiplet=false;
        if(options&&options.rangeForMultiplet!=undefined)
            rangeForMultiplet = options.rangeForMultiplet;

        //console.log("Range1: "+options.rangeForMultiplet);

        spectrum.type="NMR SPEC";
        if (spectrum[0]["nucleus"]=="1H") {
            formatAcs_default(spectrum, false, 2, 1, solvent);
        } else if (spectrum[0]["nucleus"]=="13C") {
            formatAcs_default(spectrum, false, 1, 0, solvent);
        }

        if (acsString.length>0) acsString+=".";

        return acsString;
    }

    /*function formatAcs_default_IR(spectra, ascending, decimalValue, smw) {
     appendSeparator();
     appendSpectroInformation(spectra);
     if (spectra["peakLabels"]) {
     var numberPeakLabels=spectra["peakLabels"].length;
     var minIntensity= 9999999;
     var maxIntensity=-9999999;
     for (var i=0; i<numberPeakLabels; i++) {
     if (spectra["peakLabels"][i].intensity<minIntensity) minIntensity=spectra["peakLabels"][i].intensity;
     if (spectra["peakLabels"][i].intensity>maxIntensity) maxIntensity=spectra["peakLabels"][i].intensity;
     }
     for (var i=0; i<numberPeakLabels; i++) {
     if (ascending) {
     var peakLabel=spectra["peakLabels"][i];
     } else {
     var peakLabel=spectra["peakLabels"][numberPeakLabels-i-1];
     }
     if (peakLabel) {
     appendSeparator();
     appendValue(peakLabel,decimalValue);
     if (smw) { // we need to add small / medium / strong
     if (peakLabel.intensity<((maxIntensity-minIntensity)/3+minIntensity)) acsString+=" (s)";
     else if (peakLabel.intensity>(maxIntensity-(maxIntensity-minIntensity)/3)) acsString+=" (w)";
     else acsString+=" (m)";
     }
     }
     }
     }
     }*/

    function formatAcs_default(spectra, ascending, decimalValue, decimalJ, solvent) {
        appendSeparator();
        appendSpectroInformation(spectra, solvent);
        var numberSmartPeakLabels=spectra.length;
        //console.log("SP "+spectra);
        //console.log("# "+numberSmartPeakLabels);
        for (var i=0; i<numberSmartPeakLabels; i++) {
            if (ascending) {
                var signal=spectra[i];
            } else {
                var signal=spectra[numberSmartPeakLabels-i-1];
            }
            if (signal) {
                //console.log("X2X"+i+JSON.stringify(signal));
                appendSeparator();
                appendDelta(signal,decimalValue);
                appendParenthesis(signal,decimalJ);
                //console.log("S2S"+i);
            }
        }
    }

    function appendSpectroInformation(spectrum, solvent) {
        if (spectrum.type=="NMR SPEC") {
            if (spectrum[0].nucleus) {
                acsString+=formatNucleus(spectrum[0].nucleus);
            }
            acsString+=" NMR";
            if ((solvent) || (spectrum[0].observe)) {
                acsString+=" (";
                if (spectrum.observe) {
                    acsString+=(spectrum[0].observe*1).toFixed(0)+" MHz";
                    if (solvent) acsString+=", ";
                }
                if (solvent) {
                    acsString+=formatMF(solvent);
                }
                acsString+=")";
            }
            acsString+=" δ ";
        } else if (spectrum.type=="IR") {
            acsString+=" IR ";
        } else if (spectrum.type=="MASS") {
            acsString+=" MASS ";
        }
    }

    function appendDelta(line, nbDecimal) {
        //console.log("appendDelta1");
        var startX = 0,stopX=0,delta1=0;
        if(line.startX){
            if((typeof line.startX)=="string"){
                startX=parseFloat(line.startX);
            }
            else
                startX=line.startX;
        }
        if(line.stopX){
            if((typeof line.stopX)=="string"){
                stopX=parseFloat(line.stopX);
            }
            else
                stopX=line.stopX;
        }
        if(line.delta1){
            if((typeof line.delta1)=="string"){
                delta1=parseFloat(line.delta1);
            }
            else
                delta1=line.delta1;

        }
        //console.log("Range2: "+rangeForMultiplet+" "+line.multiplicity);
        if (line.asymmetric===true||(line.multiplicity=="m"&&rangeForMultiplet===true)) {//Is it massive??
            if (line.startX&&line.stopX) {
                if (startX<stopX) {
                    acsString+=startX.toFixed(nbDecimal)+"-"+stopX.toFixed(nbDecimal);
                } else {
                    acsString+=stopX.toFixed(nbDecimal)+"-"+startX.toFixed(nbDecimal);
                }
            } else {
                if(line.delta1)
                    acsString+=delta1.toFixed(nbDecimal);
            }
        }
        else{
            if(line.delta1)
                acsString+=delta1.toFixed(nbDecimal);
            else{
                if(line.startX&&line.stopX){
                    acsString+=((startX+stopX)/2).toFixed(nbDecimal);
                }
            }
        }
    }

    function appendValue(line, nbDecimal) {
        if (line.xPosition) {
            acsString+=line.xPosition.toFixed(nbDecimal);
        }
    }

    function appendParenthesis(line, nbDecimal) {
        //console.log("appendParenthesis1");
        // need to add assignment - coupling - integration
        parenthesis="";
        appendMultiplicity(line);
        appendIntegration(line);
        appendCoupling(line,nbDecimal);
        appendAssignment(line);

        if (parenthesis.length>0) {
            acsString+=" ("+parenthesis+")";
        }
        //console.log("appendParenthesis2");
    }

    function appendIntegration(line) {
        if (line.pubIntegration) {
            appendParenthesisSeparator();
            parenthesis+=line.pubIntegration;
        } else if (line.integralData) {
            appendParenthesisSeparator();
            parenthesis+=line.integralData.value.toFixed(0)+" H";
        }
    }

    function appendAssignment(line) {
        if (line.pubAssignment) {
            appendParenthesisSeparator();
            parenthesis+=formatAssignment(line.pubAssignment);
        }
        else{
            if (line.assignment) {
                appendParenthesisSeparator();
                parenthesis+=formatAssignment(line.assignment);
            }
        }
    }

    function appendMultiplicity(line) {
        if (line.pubMultiplicity) {
            appendParenthesisSeparator();
            parenthesis+=line.pubMultiplicity;
        } else if (line.multiplicity) {
            appendParenthesisSeparator();
            parenthesis+=line.multiplicity;
        }
    }

    function appendCoupling(line, nbDecimal) {
        if (line.nmrJs) {
            var j="J = ";
            for (var i=0; i<line.nmrJs.length; i++) {
                var coupling=line.nmrJs[i].coupling;
                if (j.length>11) j+=", ";
                j+=coupling.toFixed(nbDecimal);
            }
            appendParenthesisSeparator();
            parenthesis+=j+" Hz";
        }

    }

    function formatAssignment(assignment) {
        assignment=assignment.replace(/([0-9])/g,"$1");
        assignment=assignment.replace(/\"([^\"]*)\"/g,"$1");
        return assignment;
    }

    function formatMF(mf) {
        mf=mf.replace(/([0-9])/g,"$1");
        return mf;
    }

    function formatNucleus(nucleus) {
        nucleus=nucleus.replace(/([0-9])/g,"$1");
        return nucleus;
    }

    function appendSeparator() {
        if ((acsString.length>0) && (! acsString.match(/ $/))) {
            acsString+=", ";
        }
    }

    function appendParenthesisSeparator() {
        if ((parenthesis.length>0) && (! parenthesis.match(", $"))) parenthesis+=", ";
    }

    function fromACS2NMRSignal1D(acsString){
        return JSON.parse(SDAPI.AcsParserAsJSONString(acsString));
    }

    return {
        toACS:fromNMRSignal1D2ACS,
        toNMRSignal:fromACS2NMRSignal1D
    }
})();

module.exports=ACS;<commit_msg>Report observe frequency<commit_after>/**
 * This library formats a set of nmr1D signals to the ACS format.
 * Created by acastillo on 3/11/15. p
 */
var ACS=ACS || {};
ACS.formater =(function() {
    var acsString="";
    var parenthesis="";
    var spectro="";
    rangeForMultiplet=false;

    function fromNMRSignal1D2ACS(spectrum, options){
        acsString="";
        parenthesis="";
        spectro="";
        var solvent = null;
        if(options&&options.solvent)
            solvent = options.solvent;
        //options.rangeForMultiplet=false;
        if(options&&options.rangeForMultiplet!=undefined)
            rangeForMultiplet = options.rangeForMultiplet;

        //console.log("Range1: "+options.rangeForMultiplet);

        spectrum.type="NMR SPEC";
        if (spectrum[0]["nucleus"]=="1H") {
            formatAcs_default(spectrum, false, 2, 1, solvent);
        } else if (spectrum[0]["nucleus"]=="13C") {
            formatAcs_default(spectrum, false, 1, 0, solvent);
        }

        if (acsString.length>0) acsString+=".";

        return acsString;
    }

    /*function formatAcs_default_IR(spectra, ascending, decimalValue, smw) {
     appendSeparator();
     appendSpectroInformation(spectra);
     if (spectra["peakLabels"]) {
     var numberPeakLabels=spectra["peakLabels"].length;
     var minIntensity= 9999999;
     var maxIntensity=-9999999;
     for (var i=0; i<numberPeakLabels; i++) {
     if (spectra["peakLabels"][i].intensity<minIntensity) minIntensity=spectra["peakLabels"][i].intensity;
     if (spectra["peakLabels"][i].intensity>maxIntensity) maxIntensity=spectra["peakLabels"][i].intensity;
     }
     for (var i=0; i<numberPeakLabels; i++) {
     if (ascending) {
     var peakLabel=spectra["peakLabels"][i];
     } else {
     var peakLabel=spectra["peakLabels"][numberPeakLabels-i-1];
     }
     if (peakLabel) {
     appendSeparator();
     appendValue(peakLabel,decimalValue);
     if (smw) { // we need to add small / medium / strong
     if (peakLabel.intensity<((maxIntensity-minIntensity)/3+minIntensity)) acsString+=" (s)";
     else if (peakLabel.intensity>(maxIntensity-(maxIntensity-minIntensity)/3)) acsString+=" (w)";
     else acsString+=" (m)";
     }
     }
     }
     }
     }*/

    function formatAcs_default(spectra, ascending, decimalValue, decimalJ, solvent) {
        appendSeparator();
        appendSpectroInformation(spectra, solvent);
        var numberSmartPeakLabels=spectra.length;
        //console.log("SP "+spectra);
        //console.log("# "+numberSmartPeakLabels);
        for (var i=0; i<numberSmartPeakLabels; i++) {
            if (ascending) {
                var signal=spectra[i];
            } else {
                var signal=spectra[numberSmartPeakLabels-i-1];
            }
            if (signal) {
                //console.log("X2X"+i+JSON.stringify(signal));
                appendSeparator();
                appendDelta(signal,decimalValue);
                appendParenthesis(signal,decimalJ);
                //console.log("S2S"+i);
            }
        }
    }

    function appendSpectroInformation(spectrum, solvent) {
        if (spectrum.type=="NMR SPEC") {
            if (spectrum[0].nucleus) {
                acsString+=formatNucleus(spectrum[0].nucleus);
            }
            acsString+=" NMR";
            if ((solvent) || (spectrum[0].observe)) {
                acsString+=" (";
                if (spectrum[0].observe) {
                    acsString+=(spectrum[0].observe*1).toFixed(0)+" MHz";
                    if (solvent) acsString+=", ";
                }
                if (solvent) {
                    acsString+=formatMF(solvent);
                }
                acsString+=")";
            }
            acsString+=" δ ";
        } else if (spectrum.type=="IR") {
            acsString+=" IR ";
        } else if (spectrum.type=="MASS") {
            acsString+=" MASS ";
        }
    }

    function appendDelta(line, nbDecimal) {
        //console.log("appendDelta1");
        var startX = 0,stopX=0,delta1=0;
        if(line.startX){
            if((typeof line.startX)=="string"){
                startX=parseFloat(line.startX);
            }
            else
                startX=line.startX;
        }
        if(line.stopX){
            if((typeof line.stopX)=="string"){
                stopX=parseFloat(line.stopX);
            }
            else
                stopX=line.stopX;
        }
        if(line.delta1){
            if((typeof line.delta1)=="string"){
                delta1=parseFloat(line.delta1);
            }
            else
                delta1=line.delta1;

        }
        //console.log("Range2: "+rangeForMultiplet+" "+line.multiplicity);
        if (line.asymmetric===true||(line.multiplicity=="m"&&rangeForMultiplet===true)) {//Is it massive??
            if (line.startX&&line.stopX) {
                if (startX<stopX) {
                    acsString+=startX.toFixed(nbDecimal)+"-"+stopX.toFixed(nbDecimal);
                } else {
                    acsString+=stopX.toFixed(nbDecimal)+"-"+startX.toFixed(nbDecimal);
                }
            } else {
                if(line.delta1)
                    acsString+=delta1.toFixed(nbDecimal);
            }
        }
        else{
            if(line.delta1)
                acsString+=delta1.toFixed(nbDecimal);
            else{
                if(line.startX&&line.stopX){
                    acsString+=((startX+stopX)/2).toFixed(nbDecimal);
                }
            }
        }
    }

    function appendValue(line, nbDecimal) {
        if (line.xPosition) {
            acsString+=line.xPosition.toFixed(nbDecimal);
        }
    }

    function appendParenthesis(line, nbDecimal) {
        //console.log("appendParenthesis1");
        // need to add assignment - coupling - integration
        parenthesis="";
        appendMultiplicity(line);
        appendIntegration(line);
        appendCoupling(line,nbDecimal);
        appendAssignment(line);

        if (parenthesis.length>0) {
            acsString+=" ("+parenthesis+")";
        }
        //console.log("appendParenthesis2");
    }

    function appendIntegration(line) {
        if (line.pubIntegration) {
            appendParenthesisSeparator();
            parenthesis+=line.pubIntegration;
        } else if (line.integralData) {
            appendParenthesisSeparator();
            parenthesis+=line.integralData.value.toFixed(0)+" H";
        }
    }

    function appendAssignment(line) {
        if (line.pubAssignment) {
            appendParenthesisSeparator();
            parenthesis+=formatAssignment(line.pubAssignment);
        }
        else{
            if (line.assignment) {
                appendParenthesisSeparator();
                parenthesis+=formatAssignment(line.assignment);
            }
        }
    }

    function appendMultiplicity(line) {
        if (line.pubMultiplicity) {
            appendParenthesisSeparator();
            parenthesis+=line.pubMultiplicity;
        } else if (line.multiplicity) {
            appendParenthesisSeparator();
            parenthesis+=line.multiplicity;
        }
    }

    function appendCoupling(line, nbDecimal) {
        if (line.nmrJs) {
            var j="J = ";
            for (var i=0; i<line.nmrJs.length; i++) {
                var coupling=line.nmrJs[i].coupling;
                if (j.length>11) j+=", ";
                j+=coupling.toFixed(nbDecimal);
            }
            appendParenthesisSeparator();
            parenthesis+=j+" Hz";
        }

    }

    function formatAssignment(assignment) {
        assignment=assignment.replace(/([0-9])/g,"$1");
        assignment=assignment.replace(/\"([^\"]*)\"/g,"$1");
        return assignment;
    }

    function formatMF(mf) {
        mf=mf.replace(/([0-9])/g,"$1");
        return mf;
    }

    function formatNucleus(nucleus) {
        nucleus=nucleus.replace(/([0-9])/g,"$1");
        return nucleus;
    }

    function appendSeparator() {
        if ((acsString.length>0) && (! acsString.match(/ $/))) {
            acsString+=", ";
        }
    }

    function appendParenthesisSeparator() {
        if ((parenthesis.length>0) && (! parenthesis.match(", $"))) parenthesis+=", ";
    }

    function fromACS2NMRSignal1D(acsString){
        return JSON.parse(SDAPI.AcsParserAsJSONString(acsString));
    }

    return {
        toACS:fromNMRSignal1D2ACS,
        toNMRSignal:fromACS2NMRSignal1D
    }
})();

module.exports=ACS;<|endoftext|>


<commit_before>var countStat = function(storyId, stat, details) {

  var connectionId = this.connection.id;
  var clientIP = this.connection.httpHeaders['x-forwarded-for'] || this.connection.clientAddress;

  var story = Stories.findOne({_id: storyId, published: true});

  if (!story){
    throw new Meteor.error('Story not found for count ' + stat + ': ' + storyId); // this mostly confirms the story has been published
  }

  var stats = StoryStats.findOne({storyId: storyId}, {fields: {all: 0}});

  if(!stats){
    stats = {};
  }

  if (!stats.deepAnalytics){
    stats.deepAnalytics= {};
  }

  if (!stats.deepAnalytics[stat]){
    stats.deepAnalytics[stat] = {};
  }

  var addToSet = {};
  var inc = {};
  inc['analytics.' + stat + '.total'] = 1;

  if(!_.contains(stats.deepAnalytics[stat].uniqueViewersByConnection, connectionId)){
    addToSet['deepAnalytics.' + stat + '.uniqueViewersByConnection'] = connectionId ;
    inc['analytics.' + stat + '.byConnection'] = 1;
  }

  if(!_.contains(stats.deepAnalytics[stat].uniqueViewersByIP, clientIP)){
    addToSet['deepAnalytics.' + stat + '.uniqueViewersByIP'] = clientIP ;
    inc['analytics.' + stat + '.byIP'] = 1;
  }

  if (this.userId && !_.contains(stats.deepAnalytics[stat].uniqueViewersByUserId, this.userId)){
    addToSet['deepAnalytics.' + stat + '.uniqueViewersByUserId'] = this.userId ;
    inc['analytics.' + stat + '.byId'] = 1;
  }

  var push = {};

  var fullData =  _.extend({}, _.omit(this.connection, ['close', 'onClose']), {date: new Date});

  if (this.userId){
    _.extend(fullData, {
      userId: this.userId,
      username: Meteor.user().username
    });
  };
  if (details){
    _.extend(fullData, details);
  };

  push['deepAnalytics.' + stat + '.all'] = fullData;

  Stories.update( {_id: storyId}, {$inc: inc });
  StoryStats.upsert( {storyId: storyId} , {$inc: inc, $addToSet: addToSet, $push: push} );
};

Meteor.methods({
  countStoryView: function(storyId) {
    this.unblock();
    check(storyId, String);
    countStat.call(this, storyId, 'views');
  },
  countStoryShare: function(storyId, service) {
    this.unblock();
    check(storyId, String);
    countStat.call(this, storyId, 'shares', {service: service});
  },
  countStoryRead: function(storyId, service) {
    this.unblock();
    check(storyId, String);
    countStat.call(this, storyId, 'reads', {service: service});
  },
  countStoryActiveHeartbeats: function(storyId, countMap) {
    this.unblock();
    check(storyId, String);
    check(countMap, Object);
    _.keys(countMap, function (e) {
      check(e, String); // these should be ids
      check(e, Match.Where(function (str) {
        return (/^[^.]*$/).test(str); // check has no periods
      }))
    });
    _.values(countMap, function (e) {
      check(e, Number);
    });

    var incMap = {};
    _.each(_.keys(countMap), function (k) {
      incMap['analytics.heartbeats.active.' + k] = countMap[k];
    });

    StoryStats.upsert({storyId: storyId}, {$inc: incMap});
    return Stories.update({_id: storyId}, {$inc: incMap});
  },
  impersonate: function(username) {
    check(username, String);

    var user = Meteor.user();
    if (!user || !user.admin || !user.privileges || !user.privileges.impersonation){
      throw new Meteor.Error(403, 'Permission denied');
    }

    var otherUser;
    if (!(otherUser = Meteor.users.findOne({username: username}))){
      throw new Meteor.Error(404, 'User not found');
    }

    this.setUserId(otherUser._id);
    return otherUser._id
  },
  getActivityFeed: function(){
    if(!this.userId){
      throw new Meteor.Error("Only users may get their activity feed");
    }

    var activityIds = ActivityFeedItems.find({uId: this.userId}, {sort:{r: -1}, limit: 50, fields: {'aId' : 1}}).map(function(i){return i.aId}); // FETCH THE ID MAP OR SOMETHING
    return Activities.find({_id: {$in: activityIds}}).fetch();
  }
});
<commit_msg>cleanup<commit_after>var countStat = function(storyId, stat, details) {

  var connectionId = this.connection.id;
  var clientIP = this.connection.httpHeaders['x-forwarded-for'] || this.connection.clientAddress;

  var story = Stories.findOne({_id: storyId, published: true});

  if (!story){
    throw new Meteor.error('Story not found for count ' + stat + ': ' + storyId); // this mostly confirms the story has been published
  }

  var stats = StoryStats.findOne({storyId: storyId}, {fields: {all: 0}});

  if(!stats){
    stats = {};
  }

  if (!stats.deepAnalytics){
    stats.deepAnalytics= {};
  }

  if (!stats.deepAnalytics[stat]){
    stats.deepAnalytics[stat] = {};
  }

  var addToSet = {};
  var inc = {};
  inc['analytics.' + stat + '.total'] = 1;

  if(!_.contains(stats.deepAnalytics[stat].uniqueViewersByConnection, connectionId)){
    addToSet['deepAnalytics.' + stat + '.uniqueViewersByConnection'] = connectionId ;
    inc['analytics.' + stat + '.byConnection'] = 1;
  }

  if(!_.contains(stats.deepAnalytics[stat].uniqueViewersByIP, clientIP)){
    addToSet['deepAnalytics.' + stat + '.uniqueViewersByIP'] = clientIP ;
    inc['analytics.' + stat + '.byIP'] = 1;
  }

  if (this.userId && !_.contains(stats.deepAnalytics[stat].uniqueViewersByUserId, this.userId)){
    addToSet['deepAnalytics.' + stat + '.uniqueViewersByUserId'] = this.userId ;
    inc['analytics.' + stat + '.byId'] = 1;
  }

  var push = {};

  var fullData =  _.extend({}, _.omit(this.connection, ['close', 'onClose']), {date: new Date});

  if (this.userId){
    _.extend(fullData, {
      userId: this.userId,
      username: Meteor.user().username
    });
  };
  if (details){
    _.extend(fullData, details);
  };

  push['deepAnalytics.' + stat + '.all'] = fullData;

  Stories.update( {_id: storyId}, {$inc: inc });
  StoryStats.upsert( {storyId: storyId} , {$inc: inc, $addToSet: addToSet, $push: push} );
};

Meteor.methods({
  countStoryView: function(storyId) {
    this.unblock();
    check(storyId, String);
    countStat.call(this, storyId, 'views');
  },
  countStoryShare: function(storyId, service) {
    this.unblock();
    check(storyId, String);
    countStat.call(this, storyId, 'shares', {service: service});
  },
  countStoryRead: function(storyId, service) {
    this.unblock();
    check(storyId, String);
    countStat.call(this, storyId, 'reads', {service: service});
  },
  countStoryActiveHeartbeats: function(storyId, countMap) {
    this.unblock();
    check(storyId, String);
    check(countMap, Object);
    _.keys(countMap, function (e) {
      check(e, String); // these should be ids
      check(e, Match.Where(function (str) {
        return (/^[^.]*$/).test(str); // check has no periods
      }))
    });
    _.values(countMap, function (e) {
      check(e, Number);
    });

    var incMap = {};
    _.each(_.keys(countMap), function (k) {
      incMap['analytics.heartbeats.active.' + k] = countMap[k];
    });

    StoryStats.upsert({storyId: storyId}, {$inc: incMap});
    return Stories.update({_id: storyId}, {$inc: incMap});
  },
  impersonate: function(username) {
    check(username, String);

    var user = Meteor.user();
    if (!user || !user.admin || !user.privileges || !user.privileges.impersonation){
      throw new Meteor.Error(403, 'Permission denied');
    }

    var otherUser;
    if (!(otherUser = Meteor.users.findOne({username: username}))){
      throw new Meteor.Error(404, 'User not found');
    }

    this.setUserId(otherUser._id);
    return otherUser._id
  },
  getActivityFeed: function(){
    if(!this.userId){
      throw new Meteor.Error("Only users may get their activity feed");
    }

    var activityIds = ActivityFeedItems.find({uId: this.userId}, {sort:{r: -1}, limit: 50, fields: {'aId' : 1}}).map(function(i){return i.aId});
    return Activities.find({_id: {$in: activityIds}}).fetch();
  }
});
<|endoftext|>


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

Meteor.methods({
    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.');
        }

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

        if (!post.target) {
            return;
        }

        let target = Posts.findOne({_id: post.target});
        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);

        //Will always insert directly underneath target, shifting existing posts to the right.
        let y = target.defaultPosition.y - 1;
        let x = target.defaultPosition.x;
        post.defaultPosition = {x: x, y: y};

        //Find the chain of adjacent posts which need to be shifted.
        let shifting = false;
        let postsToShift = [];
        let prevColumn;
        Posts.find({'defaultPosition.y': y}, {sort: {'defaultPosition.x': 1}}).forEach(function(post) {
            if (shifting) {
                if (post.defaultPosition.x > prevColumn + 1) {
                    shifting = false;
                }
            }
            else if (post.defaultPosition.x === x) {
                shifting = true;
            }

            if (shifting) {
                postsToShift.push(post);
            }

            prevColumn = post.defaultPosition.x;
        });

        //Shift found posts one column to the right.
        for (let post of postsToShift) {
            let newColumn = post.defaultPosition.x + 1;
            Posts.update({_id: post._id}, {$set: {'defaultPosition.x': newColumn}});
        }

        //Insert new post into position.
        let postId = Posts.insert(post);
        Posts.update({_id: post.target}, {$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.');
        }

        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.title && post.title.length < 1) {
            delete post.title;
        }

        //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: {
            title: update.title,
            content: update.content,
            lastEditedAt: 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.target}, {$pull: {replies: postId}});
        Posts.remove(postId);
    },
    submitReport: function(report) {
        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} });
    }
});
<commit_msg>Fixed incremental graph insertion to avoid edge crossings<commit_after>/*
    Agora Forum Software
    Copyright (C) 2016 Gregory Sartucci
    License: GPL, Check file LICENSE
*/

Meteor.methods({
    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.');
        }

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

        if (!post.target) {
            return;
        }

        let target = Posts.findOne({_id: post.target});
        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);

        //Will always insert after the targets rightmost reply, shifting existing posts to the right.
        let y = target.defaultPosition.y - 1;
        let x = target.defaultPosition.x + target.replies.length;
        post.defaultPosition = {x: x, y: y};

        /**add the post to the end of the line under the post it's replying to.
            *find every sibling post of it's parent that's to the right of it, and of their parents, and move them all \
            to the right.

            while
            	find parent of current target
            	check if any of it's siblings are to the right of the inserted post
            	if so add them to the list to move further right.*/

        //Find the chain of overhead posts which need to be shifted.
        if (target.replies.length > 0) {
            let shifting = false;
            let postsToShift = [];
            let targetId = target.target;

            while (targetId) {
                Posts.find({target: targetId}, {sort: {'defaultPosition.x': 1}}).forEach(function(post) {
                    if (shifting) {
                        if (post.defaultPosition.x < x) {
                            shifting = false;
                        }
                    }
                    else if (post.defaultPosition.x >= x) {
                        shifting = true;
                    }

                    if (shifting) {
                        postsToShift.push(post);
                    }
                });

                targetId = Posts.findOne({_id: targetId}).target;
            }

            //Shift found posts one column to the right, and all of their children, too.
            for (let post of postsToShift) {
                let newColumn = post.defaultPosition.x + 1;
                Posts.update({_id: post._id}, {$set: {'defaultPosition.x': newColumn}});
                Posts.find({target: post._id}).forEach(function(child) {
                    postsToShift.push(child);
                });
            }

        }

        //Insert new post into position.
        let postId = Posts.insert(post);
        Posts.update({_id: post.target}, {$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.');
        }

        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.title && post.title.length < 1) {
            delete post.title;
        }

        //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: {
            title: update.title,
            content: update.content,
            lastEditedAt: 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.target}, {$pull: {replies: postId}});
        Posts.remove(postId);
    },
    submitReport: function(report) {
        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} });
    }
});
<|endoftext|>