mitjajez/SONCE

View on GitHub
imports/api/elements/methods.js

Summary

Maintainability
A
1 hr
Test Coverage
import { Meteor } from 'meteor/meteor';
import { _ } from 'meteor/underscore';
import { ValidatedMethod } from 'meteor/mdg:validated-method';
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
import { DDPRateLimiter } from 'meteor/ddp-rate-limiter';

import { Elements } from './elements.js';
import { Wires } from '../wires/wires.js';
import { Circuits } from '../circuits/circuits.js';
import { Components } from '../components/components.js';

import {
  openWireEnd,
} from '../wires/methods.js';


export const insertElement = new ValidatedMethod({
  name: 'elements.insert',

  validate: new SimpleSchema({
    "name": { type: String, optional: true },
    "component": { type: String },
    "type": { type: String, optional: true },
    "symbol": { type: String },
    "cid": { type: String, regEx: SimpleSchema.RegEx.Id },
    "pins": { type: [Object] },
    "pins.$.id": { type: String },
    "pins.$.x": { type: Number },
    "pins.$.y": { type: Number },
    "pins.$.net": { type: String },
    "transform": { type: Object },
    "transform.x": { type: Number },
    "transform.y": { type: Number },
    "transform.rot": { type: Number },
  }).validator(),

  run({ name, component, type, symbol, cid, pins, transform }) {
    console.log( "METHOD elements.insert "+ component );

    const circuit = Circuits.findOne(cid);

    if (circuit.isPrivate() && circuit.userId !== this.userId) {
      throw new Meteor.Error('elements.insert.accessDenied',
        'Cannot add elements to a private circuit that is not yours');
    }

    const element = {
      name,
      component,
      type,
      symbol,
      cid,
      pins,
      transform
    };

    return Elements.insert(element);
  },
});

export const rotateElement = new ValidatedMethod({
  name: 'elements.rotate',
  validate: new SimpleSchema({
    eid: { type: String },
    phi: { type: Number },
  }).validator(),

  run({ eid, phi }) {
    const element = Elements.findOne(eid);
    console.log( "METHOD elements.rotate "+ element.name +" ("+ phi +")" );

    // This is complex auth stuff - perhaps denormalizing a userId onto elements
    // would be correct here?

    if (!element.editableBy(this.userId)) {
      throw new Meteor.Error('elements.rotate.accessDenied',
        'Cannot edit elements in a private circuit that is not yours');
    }

    Elements.update(eid,
      { $set: { "transform.rot": phi } }
    );
  },
});

export const connectElementPin = new ValidatedMethod({
  name: 'elements.connectPin',
  validate: new SimpleSchema({
    cid: { type: String, regEx: SimpleSchema.RegEx.Id },
    name: { type: String },
    pin: { type: String },
    net: { type: String },
  }).validator(),
  run({ cid, name, pin, net }) {
    console.log( "METHOD elements.connectPin "+ name +"-"+ pin + " ("+ net +")" );

    const element = Elements.findOne({ cid: cid, name: name });
    if (!element.editableBy(this.userId)) {
      throw new Meteor.Error('elements.connectPin.accessDenied',
        'Cannot edit elements in a private circuit that is not yours');
    }

    Elements.update(
      { cid: cid, name: name, 'pins.id': pin },
      { $set: { 'pins.$.net': net } }
    );
  },
});

export const disconnectElementPin = new ValidatedMethod({
  name: 'elements.disconnectPin',
  // TODO: arguments should be "eid" OR "cid && name"
  validate: new SimpleSchema({
    cid: { type: String, regEx: SimpleSchema.RegEx.Id },
    name: { type: String },
    pin: { type: String },
  }).validator(),
  run({ cid, name, pin }) {
    console.log( "METHOD elements.disconnectPin "+ name +"-"+ pin);

    const element = Elements.findOne({ cid: cid, name: name });
    if (!element.editableBy(this.userId)) {
      throw new Meteor.Error('elements.disconnectToNet.accessDenied',
        'Cannot edit elements in a private circuit that is not yours');
    }

    Elements.update(
      { cid: cid, name: name, "pins.id": pin },
      { $set: { "pins.$.net": "open" } }
    );
  },
});

export const renameElement = new ValidatedMethod({
  name: 'elements.rename',

  validate: new SimpleSchema({
    eid: { type: String },
    newName: { type: String },
  }).validator(),

  run({ eid, newName }) {
    // This is complex auth stuff - perhaps denormalizing a userId onto elements
    // would be correct here?
    const element = Elements.findOne(eid);
    console.log( "METHOD elements.rename "+ element.name + " -> " + newName);

    if (!element.editableBy(this.userId)) {
      throw new Meteor.Error('elements.updateName.accessDenied',
        'Cannot edit elements in a private circuit that is not yours');
    }

    Elements.update(eid,
      { $set: { name: newName } }
    );
  },
});

export const removeElement = new ValidatedMethod({
  name: 'elements.remove',

  validate: new SimpleSchema({
    eid: { type: String },
  }).validator(),

  run({ eid }) {
    const element = Elements.findOne(eid);
    console.log( "METHOD elements.remove "+ element.name );

    if (!element.editableBy(this.userId)) {
      throw new Meteor.Error('elements.remove.accessDenied',
        'Cannot remove elements in a private circuit that is not yours');
    }

    element.pins.map((p) => {
      if(p.net !== "open"){
        openWireEnd.call({
          'cid': element.cid,
          'end': { 'e': element.name, 'p': p.id },
        });        
      }
    });

    Elements.remove(eid);
  },
});

// Get list of all method names on Elements
const ELEMENTS_METHODS = _.pluck([
  insertElement,
  rotateElement,
  connectElementPin,
  disconnectElementPin,
  renameElement,
  removeElement,
], 'name');

if (Meteor.isServer) {
  // Only allow 5 elements operations per connection per second
  DDPRateLimiter.addRule({
    name(name) {
      return _.contains(ELEMENTS_METHODS, name);
    },

    // Rate limit per connection ID
    connectionId() { return true; },
  }, 5, 1000);
}