Source

api/user/DeveloperCollection.js

import { Meteor } from 'meteor/meteor';
import SimpleSchema from 'simpl-schema';
import { _ } from 'lodash';
import BaseSlugCollection from '../base/BaseSlugCollection';
import { demographicLevels } from '../level/Levels';
import { Slugs } from '../slug/SlugCollection';
import { ROLE } from '../role/Role';
import { Users } from './UserCollection';
import { DeveloperChallenges } from './DeveloperChallengeCollection';
import { DeveloperInterests } from './DeveloperInterestCollection';
import { DeveloperSkills } from './DeveloperSkillCollection';
import { DeveloperTools } from './DeveloperToolCollection';
import { Challenges } from '../challenge/ChallengeCollection';
import { Interests } from '../interest/InterestCollection';
import { Skills } from '../skill/SkillCollection';
import { Tools } from '../tool/ToolCollection';

/**
 * DeveloperCollection, collection of HACC-Hui developers.
 * @extends api/base.BaseSlugCollection
 * @memberOf api/user
 */
class DeveloperCollection extends BaseSlugCollection {
  constructor() {
    super('Developer', new SimpleSchema({
      username: { type: String },
      slugID: { type: String },
      firstName: { type: String },
      lastName: { type: String },
      demographicLevel: { type: String, allowedValues: demographicLevels, optional: true },
      linkedIn: { type: String, optional: true },
      gitHub: { type: String, optional: true },
      website: { type: String, optional: true },
      aboutMe: { type: String, optional: true },
      userID: { type: SimpleSchema.RegEx.Id, optional: true },
      lookingForTeam: { type: Boolean, optional: true },
      isCompliant: { type: Boolean, optional: true },
    }));
  }

  /**
   * Creates a new developer.
   * @param username {String} the developer's username.
   * @param firstName {String} the developer's first name.
   * @param lastName {String} the developer's last name.
   * @param demographicLevel {String} the developer's demographic level.
   * @param lookingForTeam {Boolean} if the developer is looking for a team.
   * @param challenges {String[]} the challenges the developer is interested in.
   * @param interests {String[]} the developer's interests.
   * @param skills {String[]} the developer's skills.
   * @param tools {String[]} the tools the developer is interested in.
   * @param linkedIn {String} the developer's LinkedIn page (optional).
   * @param gitHub {String} the developer's GitHub page (optional).
   * @param website {String} the developer's website (optional).
   * @param aboutMe {String} a short description.
   * @param isCompliant {Boolean} is the developer compliant.
   * @return {{password: *, profileID: any}|undefined}
   */
  define({
           username, firstName, lastName, demographicLevel, lookingForTeam,
           challenges = [], interests = [], skills = [], tools = [],
           linkedIn = '', gitHub = '', website = '', aboutMe = '',
           isCompliant = false,
         }) {
    if (Meteor.isServer) {
      const role = ROLE.DEVELOPER;
      const slugID = Slugs.define({ name: username }); // ensure the usernames are unique
      const profileID = this._collection.insert({
        username, slugID, firstName, lastName, demographicLevel,
        lookingForTeam, linkedIn, gitHub, website, aboutMe, isCompliant,
      });
      Slugs.updateEntityID(slugID, profileID);
      const { userID, password } = Users.define({ username, role });
      this._collection.update(profileID, { $set: { userID } });
      _.each(challenges, (challenge) => DeveloperChallenges.define({ challenge, developer: username }));
      _.each(interests, (interest) => DeveloperInterests.define({ interest, developer: username }));
      _.each(skills, (skill) => DeveloperSkills.define({ skill, developer: username }));
      _.each(tools, (tool) => DeveloperTools.define({ tool, developer: username }));
      return { profileID, password };
    }
    return undefined;
  }

  /**
   * Updates the developer.
   * @param docID {String} the ID of the developer to update.
   * @param firstName {String} the new first name (optional).
   * @param lastName {String} the new last name (optional).
   * @param demographicLevel {String} the new demographic level (optional).
   * @param lookingForTeam {Boolean} the new looking for team value (optional).
   * @param challenges {String[]} the new challenges (optional).
   * @param interests {String[]} the new interests (optional).
   * @param skills {String[]} the new skills (optional).
   * @param tools {String[]} the new tools (optional).
   * @param linkedIn {String} the new LinkedIn page (optional).
   * @param gitHub {String} the new GitHub page (optional).
   * @param website {String} the new website (optional).
   * @param aboutMe {String} the new short description (optional).
   * @param isCompliant {Boolean} the new is compliant value (optional).
   */
  update(docID, {
    firstName, lastName, demographicLevel, lookingForTeam, challenges, interests,
    skills, tools, linkedIn, gitHub, website, aboutMe, isCompliant,
  }) {
    this.assertDefined(docID);
    const updateData = {};
    if (firstName) {
      updateData.firstName = firstName;
    }
    if (lastName) {
      updateData.lastName = lastName;
    }
    if (demographicLevel) {
      updateData.demographicLevel = demographicLevel;
    }
    if (_.isBoolean(lookingForTeam)) {
      updateData.lookingForTeam = lookingForTeam;
    }
    if (linkedIn) {
      updateData.linkedIn = linkedIn;
    }
    if (gitHub) {
      updateData.gitHub = gitHub;
    }
    if (website) {
      updateData.website = website;
    }
    if (aboutMe) {
      updateData.aboutMe = aboutMe;
    }
    if (_.isBoolean(isCompliant)) {
      updateData.isCompliant = isCompliant;
    }
    this._collection.update(docID, { $set: updateData });
    const developer = this.findSlugByID(docID);
    if (challenges) {
      DeveloperChallenges.removeDeveloper(developer);
      _.each(challenges, (challenge) => DeveloperChallenges.define({ challenge, developer }));
    }
    if (interests) {
      DeveloperInterests.removeDeveloper(developer);
      _.each(interests, (interest) => DeveloperInterests.define({ interest, developer }));
    }
    if (skills) {
      DeveloperSkills.removeDeveloper(developer);
      _.each(skills, (skill) => DeveloperSkills.define({ skill, developer }));
    }
    if (tools) {
      DeveloperTools.removeDeveloper(developer);
      _.each(tools, (tool) => DeveloperTools.define({ tool, developer }));
    }
  }

  /**
   * Removes the developer.
   * @param docID {String} the ID of the developer.
   * @throws {Meteor.Error} if the docID is not defined.
   */
  removeIt(docID) {
    this.assertDefined(docID);
    const developer = this.findSlugByID(docID);
    DeveloperChallenges.removeDeveloper(developer);
    DeveloperInterests.removeDeveloper(developer);
    DeveloperSkills.removeDeveloper(developer);
    DeveloperTools.removeDeveloper(developer);
    super.removeIt(docID);
  }

  /**
   * Returns an object representing the developer.
   * @param docID {String} the ID of the developer.
   * @return {{lastName: *, website: *, gitHub: *, challenges: Array, demographicLevel: *,
   * lookingForTeam: *, linkedIn: *, tools: Array, isCompliant: *, aboutMe: *, skills: Array,
   * firstName: *, interests: Array, username: *}}
   */
  dumpOne(docID) {
    this.assertDefined(docID);
    const {
      username, firstName, lastName, demographicLevel, lookingForTeam,
      linkedIn, gitHub, website, aboutMe, isCompliant,
    } = this.findDoc(docID);
    const selector = { developerID: docID };
    const devChallenges = DeveloperChallenges.find(selector).fetch();
    const challenges = _.map(devChallenges, (dC) => Challenges.findSlugByID(dC.challengeID));
    const devInterests = DeveloperInterests.find(selector).fetch();
    const interests = _.map(devInterests, (dI) => Interests.findSlugByID(dI.interestID));
    const devSkills = DeveloperSkills.find(selector).fetch();
    const skills = _.map(devSkills, (dS) => Skills.findSlugByID(dS.skillID));
    const devTools = DeveloperTools.find(selector).fetch();
    const tools = _.map(devTools, (dT) => Tools.findSlugByID(dT.toolID));
    return {
      username, firstName, lastName, demographicLevel, lookingForTeam, isCompliant,
      linkedIn, gitHub, website, aboutMe, challenges, interests, skills, tools,
    };
  }

  /**
   * Returns non-null if the user has a profile in this collection.
   * @param user The user (either their username (email) or their userID).
   * @return The profile document if the profile exists, or null if not found.
   * @throws { Meteor.Error } If user is not a valid user.
   */
  hasProfile(user) {
    const userID = Users.getID(user);
    return this.collection.findOne({ userID });
  }

  assertValidRoleForMethod(userId) {
    this.assertRole(userId, [ROLE.ADMIN, ROLE.DEVELOPER]);
  }

}

/**
 * Singleton instance of the DeveloperCollection.
 * @type {api/user.DeveloperCollection}
 * @memberOf api/user
 */
export const Developers = new DeveloperCollection();