import {Mongo} from "meteor/mongo"; import {Meteor} from "meteor/meteor"; import { check } from 'meteor/check'; import { Roles } from 'meteor/alanning:roles'; //import SimpleSchema from "simpl-schema"; import {AssetTypes} from "./asset-types"; import {AssetAssignmentHistory} from "/imports/api/asset-assignment-history"; // console.log("Setting Up Assets...") export const Assets = new Mongo.Collection('assets'); /* const AssetsSchema = new SimpleSchema({ assetTypeId: { type: String, label: "Asset Type ID", optional: false, trim: true, }, assetId: { type: String, label: "Asset ID", optional: false, trim: true, index: 1, unique: true }, serial: { type: String, label: "Serial", optional: true, trim: false, index: 1, unique: false }, assigneeId: { //Should be undefined or non-existent if not assigned. type: String, label: "Assignee ID", optional: true, }, assigneeType: { // 0: Student, 1: Staff, Should be undefined or non-existent if not assigned. type: SimpleSchema.Integer, label: "Assignee Type", optional: true, min: 0, max: 1, exclusiveMin: false, exclusiveMax: false, }, assignmentDate: { type: Date, label: "Assignment Date", optional: true, }, condition: { //One of the condition options: [New, Like New, Good, Okay, Damaged] (see assets.unassign for details). type: String, label: "Condition", optional: false, }, conditionDetails: { //An optional text block for details on the condition. type: String, label: "Condition Details", optional: true, } }); Assets.attachSchema(AssetsSchema); */ if (Meteor.isServer) { // Drop any old indexes we no longer will use. Create indexes we need. //try {Assets._dropIndex("serial")} catch(e) {} Assets.createIndex({assetId: 1}, {name: "AssetID", unique: true}); Assets.createIndex({serial: 1}, {name: "Serial", unique: false}); // This code only runs on the server Meteor.publish('assets', function() { return Assets.find({}); }); Meteor.publish('assetsAssignedTo', function(personId) { return Assets.find({assigneeId: personId}); }); } Meteor.methods({ 'assets.add'(assetTypeId, assetId, serial, condition, conditionDetails) { check(assetTypeId, String); check(assetId, String); check(serial, String); check(condition, String); if(conditionDetails) check(conditionDetails, String); if(condition !== 'New' && condition !== 'Like New' && condition !== 'Good' && condition !== 'Okay' && condition !== 'Damaged') { //Should never happen. console.error("Invalid condition option in assets.add(..)"); throw new Meteor.Error("Invalid condition option."); } // Convert the asset ID's to uppercase for storage to make searching easier. assetId = assetId.toUpperCase(); if(Roles.userIsInRole(Meteor.userId(), "admin", {anyScope:true})) { let assetType = AssetTypes.findOne({assetTypeId}); if(Assets.findOne({assetId})) { //return {error: true, errorType: 'duplicateAssetId'} throw new Meteor.Error("Duplicate Asset Id", "Cannot use the same asset ID twice.") } else if(serial) { Assets.insert({assetTypeId, assetId, serial, condition, conditionDetails}); } else { Assets.insert({assetTypeId, assetId, condition, conditionDetails}); } } else throw new Meteor.Error("User Permission Error"); }, 'assets.update'(_id, assetId, serial, condition, conditionDetails) { check(_id, String); check(assetId, String); if(serial) check(serial, String); check(condition, String); if(conditionDetails) check(conditionDetails, String); if(condition !== 'New' && condition !== 'Like New' && condition !== 'Good' && condition !== 'Okay' && condition !== 'Damaged') { //Should never happen. console.error("Invalid condition option in assets.update(..)"); throw new Meteor.Error("Invalid condition option."); } if(Roles.userIsInRole(Meteor.userId(), "admin", {anyScope:true})) { //TODO: Need to first verify there are no checked out assets to the staff member. Assets.update({_id}, {$set: {assetId, serial, condition, conditionDetail}}); } else throw new Meteor.Error("User Permission Error"); }, 'assets.remove'(_id) { check(_id, String); if(Roles.userIsInRole(Meteor.userId(), "admin", {anyScope:true})) { let asset = Assets.findOne({_id}); if(asset) { // Ensure the asset is not assigned still. Must unassign then remove. That allows us to maintain historical records for assignees. if(asset.assigneeId) { throw new Meteor.Error("Must unassign the asset before removal."); } else { Assets.remove({_id}); } } else { //This should never happen. throw new Meteor.Error("Could not find the asset: " + _id); } } else throw new Meteor.Error("User Permission Error"); }, /** * Assigns the asset to the assignee. The assignee should either be a Student or Staff member. * @param assetId The Asset ID (eg: 'Z1Q') of the asset (asset.assetId). * @param assigneeType One of: 'Student', 'Staff' * @param assigneeId The Mongo ID of the Student or Staff (person._id). * @param condition One of the condition options: [New, Like New, Good, Okay, Damaged]. 'Like New' is defined as very minor cosmetic damage. 'Good' is defined as some cosmetic damage or very minor screen damage. 'Okay' is defined as significant cosmetic damage, or screen/keyboard/trackpad damage but is still useable. 'Damaged' indicates significant damage and the device should not be reissued until it is repaired. * @param conditionDetails A text block detailing the current condition (if it is needed). * @param date The date/time of the action. Will be set to the current date/time if not provided. */ 'assets.assign'(assetId, assigneeType, assigneeId, condition, conditionDetails, date) { check(assigneeId, String); check(assigneeType, String); check(assetId, String); check(condition, String); if(conditionDetails) check(conditionDetails, String); if(date) check(date, Date); if(!date) date = new Date(); if(condition !== 'New' && condition !== 'Like New' && condition !== 'Good' && condition !== 'Okay' && condition !== 'Damaged') { //Should never happen. console.error("Invalid condition option in assets.unassign(..)"); throw new Meteor.Error("Invalid condition option."); } if(assigneeType !== 'Student' && assigneeType !== 'Staff') { // Should never happen. console.error("Error: Received incorrect assignee type in adding an assignment."); console.error(assigneeType); throw new Meteor.Error("Error: Received incorrect assignee type in adding an assignment."); } else if(Roles.userIsInRole(Meteor.userId(), "laptop-management", {anyScope:true})) { let asset = Assets.findOne({assetId}); if(asset) { if(asset.assigneeId) { //TODO: Should we unassign and re-assign???? console.error("Asset is already assigned! " + assetId); throw new Meteor.Error("Asset is already assigned.", "Cannot assign an asset that has already been assigned."); } else { Assets.update({assetId}, {$set: {assigneeType, assigneeId, assignmentDate: date, condition, conditionDetails}}); } } else { console.error("Could not find the asset: " + assetId) } } else throw new Meteor.Error("User Permission Error"); }, /** * Removes an assignment for the asset. * TODO: Should create a historical record. * @param assetId The Asset ID (eg: 'Z1Q') of the asset (asset.assetId). * @param comment A textual comment on the reason for unassigning the asset. Should not contain condition information. * @param condition One of the condition options: [New, Like New, Good, Okay, Damaged]. 'Like New' is defined as very minor cosmetic damage. 'Good' is defined as some cosmetic damage or very minor screen damage. 'Okay' is defined as significant cosmetic damage, or screen/keyboard/trackpad damage but is still useable. 'Damaged' indicates significant damage and the device should not be reissued until it is repaired. * @param conditionDetails A text block detailing the current condition (if it is needed). * @param date The date/time of the action. Will be set to the current date/time if not provided. */ 'assets.unassign'(assetId, comment, condition, conditionDetails, date) { check(assetId, String); if(date) check(date, Date); if(comment) check(comment, String); check(condition, String); if(conditionDetails) check(conditionDetails, String); if(!date) date = new Date(); if(condition !== 'New' && condition !== 'Like New' && condition !== 'Good' && condition !== 'Okay' && condition !== 'Damaged') { //Should never happen. console.error("Invalid condition option in assets.unassign(..)"); throw new Meteor.Error("Invalid condition option."); } if(Roles.userIsInRole(Meteor.userId(), "laptop-management", {anyScope:true})) { let asset = Assets.findOne({assetId}); if(asset) { let assetType = AssetTypes.findOne({_id: asset.assetTypeId}); try { AssetAssignmentHistory.insert({assetKey: asset._id, assetId, serial: asset.serial, assetTypeName: (assetType ? assetType.name : "UNK"), assigneeType: asset.assigneeType, assigneeId: asset.assigneeId, startDate: asset.assignmentDate, endDate: date, startCondition: asset.condition, endCondition: condition, startConditionDetails: asset.conditionDetails, endConditionDetails: conditionDetails, comment}); } catch (e) { console.error(e); } Assets.update({assetId}, {$unset: {assigneeType: "", assigneeId: "", assignmentDate: ""}, $set: {condition, conditionDetails}}); } else { console.error("Could not find the asset: " + assetId); throw new Meteor.Error("Could not find the asset: " + assetId); } } else throw new Meteor.Error("User Permission Error"); }, /** * A fix to remove the AssetAssignment collection and merge it with the Asset collection. */ 'assets.fixAssetAssignments'() { // Removed this since it should no longer be relevant. // let assignmentDate = new Date(); // //This function just removes the need for the asset-assignments collection and merges it with assets. // if(Roles.userIsInRole(Meteor.userId(), "admin", {anyScope:true})) { // let assets = Assets.find({}).fetch(); // let assetAssignments = AssetAssignments.find({}).fetch(); // // let assetMap = assets.reduce((map, obj) => { // map[obj.assetId] = obj; // return map; // }, {}); // // console.log(assetMap); // console.log(""); // // for(let next of assetAssignments) { // console.log(next); // let asset = assetMap[next.assetId]; // console.log("Updating " + asset.assetId + " to be assigned to " + next.assigneeType + ": " + next.assigneeId); // let c = Assets.update({assetId: asset.assetId}, {$set: {assigneeType: next.assigneeType, assigneeId: next.assigneeId, assignmentDate}}); // console.log("Updated " + c + " Assets"); // console.log(Assets.findOne({assetId: asset.assetId})); // } // } }, /** * A fix to remove the AssetAssignment collection and merge it with the Asset collection. */ 'assets.fixAssetCondition'() { // Removed this since it should no longer be relevant. if(Roles.userIsInRole(Meteor.userId(), "admin", {anyScope:true})) { Assets.update({assetTypeId: 'xPu8YK39pmQW93Fuz'}, {$set: {condition: 'Okay', conditionDetails: 'Automated Condition'}}, {multi: true}); //Lenovo E100 CB Assets.update({assetTypeId: 'casMp4pJ9t8FtpyuR'}, {$set: {condition: 'Good', conditionDetails: 'Automated Condition'}}, {multi: true}); //Lenovo E100 Charger Assets.update({assetTypeId: 'ZD9XiHqGr6TcKH9Nv'}, {$set: {condition: 'New'}}, {multi: true}); //Acer CB315 CB Assets.update({assetTypeId: 'mfE9NtiFBotb8kp4v'}, {$set: {condition: 'New'}}, {multi: true}); //Acer CB315 Charger Assets.update({assetTypeId: 'btEsKYxW4Sgf7T8nA'}, {$set: {condition: 'Good',conditionDetails: 'Automated Condition'}}, {multi: true}); //Dell 3100 Charger Assets.update({assetTypeId: '9bszeFJNPteMDbye5'}, {$set: {condition: 'Like New',conditionDetails: 'Automated Condition'}}, {multi: true}); //HP 11A CB Assets.update({assetTypeId: 'tCj7s5T2YcFXZEaqE'}, {$set: {condition: 'Like New',conditionDetails: 'Automated Condition'}}, {multi: true}); //HP 11A Charger } } }); // console.log("Assets setup.")