Beispiel #1
0
export function addUserPermissions(userId, permissions, group) {
  if (!Reaction.hasPermission("reaction-accounts", Meteor.userId(), group)) {
    throw new Meteor.Error(403, "Access denied");
  }
  check(userId, Match.OneOf(String, Array));
  check(permissions, Match.OneOf(String, Array));
  check(group, Match.Optional(String));
  this.unblock();
  try {
    return Roles.addUsersToRoles(userId, permissions, group);
  } catch (error) {
    return Logger.error(error);
  }
}
Meteor.publish("Logs", function (query, options) {
  check(query, Match.OneOf(undefined, Object));
  check(options, Match.OneOf(undefined, Object));

  const shopId = Reaction.getShopId();
  if (!query || !query.logType || !shopId) {
    return this.ready();
  }

  const { logType } = query;
  if (Roles.userIsInRole(this.userId, ["admin", "owner"])) {
    Counts.publish(this, "logs-count", Logs.find({ shopId, logType }));
    return Logs.find({ shopId, logType }, { sort: { date: 1 } });
  }
});
Beispiel #3
0
const validateAttachment = (attachment) => {
	check(attachment, objectMaybeIncluding({
		color: String,
		text: String,
		ts: Match.OneOf(String, Match.Integer),
		thumb_url: String,
		button_alignment: String,
		actions: [Match.Any],
		message_link: String,
		collapsed: Boolean,
		author_name: String,
		author_link: String,
		author_icon: String,
		title: String,
		title_link: String,
		title_link_download: Boolean,
		image_url: String,
		audio_url: String,
		video_url: String,
		fields: [Match.Any],
	}));

	if (attachment.fields && attachment.fields.length) {
		attachment.fields.map(validateAttachmentsFields);
	}

	if (attachment.actions && attachment.actions.length) {
		attachment.actions.map(validateAttachmentsActions);
	}
};
Beispiel #4
0
Meteor.publish('groupList', function (args) {
  check(args, Match.OneOf({ groupIds: [String] }, undefined))
  if (this.userId) {
    this.autorun(function () {
      if (args && args.groupIds) {
        const groups = Groups.find({'_id': {$in: args.groupIds}}, { name: 1, createdBy: 1 })
        let userIds = []
        groups.forEach(function (group) {
          userIds.push(group.createdBy)
        })
        return [
          Meteor.users.find({ '_id': { $in: userIds } }, USERS_DEFAULT),
          Groups.find({'_id': {$in: args.groupIds}})
        ]
      } else {
        const groupMemberships = Groups.find({ 'members.userId': this.userId })
        let userIds = []
        groupMemberships.forEach(function (groupMembership) {
          userIds.push(groupMembership.createdBy)
        })
        return [
          Meteor.users.find({ '_id': { $in: userIds } }, USERS_DEFAULT),
          Groups.find({ 'members.userId': this.userId })
        ]
      }
    })
  } else {
    throw new Meteor.Error(401)
  }
})
Beispiel #5
0
Meteor.publish("Sessions", (sessionId) => {
  check(sessionId, Match.OneOf(String, null));
  const created = new Date().getTime();
  let newSessionId;
  // if we don"t have a sessionId create a new session
  // REALLY - we should always have a client sessionId
  if (!sessionId) {
    newSessionId = ServerSessions.insert({ created });
  } else {
    newSessionId = sessionId;
  }
  // get the session from existing sessionId
  const serverSession = ServerSessions.find(newSessionId);

  // if not found, also create a new server session
  if (serverSession.count() === 0) {
    ServerSessions.insert({ _id: newSessionId, created });
  }

  // set global sessionId
  Reaction.sessionId = newSessionId;

  // return cursor
  return ServerSessions.find(newSessionId);
});
Beispiel #6
0
Meteor.publish("Revisions", function (documentIds) {
  check(documentIds, Match.OneOf(String, Array));

  // we could additionally make checks of useId defined, but this could lead to
  // situation when user will may not have time to get an account
  if (this.userId === null) {
    return this.ready();
  }
  const shopId = Reaction.getShopId();
  if (!shopId) {
    return this.ready();
  }

  if (Roles.userIsInRole(this.userId, ["admin", "owner"])) {
    if (Array.isArray(documentIds)) {
      return Revisions.find({
        // shopId,
        documentId: {
          $in: documentIds
        }
      });
    }

    // global admin can get all accounts
    return Revisions.find({
      // shopId,
      documentId: documentIds
    });
  }
  // regular users should get just their account
  return this.ready();
});
Beispiel #7
0
Meteor.publish("Cart", function (sessionId, userId) {
  check(sessionId, Match.OneOf(String, null));
  check(userId, Match.OptionalOrNull(String));
  // sessionId is required, not for selecting the cart, (userId), but as a key
  // in merging anonymous user carts into authenticated existing user carts.
  // we won't create carts unless we've got sessionId
  if (this.userId === null || sessionId === null) {
    return this.ready();
  }
  // use case happens between switching from anonymous to registered user. and
  // vice versa
  if (typeof userId === "string" && this.userId !== userId) {
    return this.ready();
  }
  // we have a very rare case when cart has not been created for an anonymous
  // and because of that, for some reason, he is considered as not logged in.
  // in that case he doesn't have `userId`. Only way for him to get userId is
  // to flush browser's session or log in as normal user. We could detect this
  // case from here by comparing this.userId is string and this.userId !==
  // Meteor.userId(). If this case will happens someday, we could try to send
  // some logout call to accounts. This is it: https://github.com/meteor/meteor/
  // issues/5103

  // shopId is also required.
  let shopId = Reaction.getPrimaryShopId();
  const marketplaceSettings = Reaction.getMarketplaceSettings();
  if (marketplaceSettings && marketplaceSettings.public && marketplaceSettings.public.merchantCart === true) {
    shopId = Reaction.getShopId();
  }

  if (!shopId) {
    return this.ready();
  }

  // exclude these fields
  // from the client cart
  const fields = {
    taxes: 0
  };

  // select user cart
  const cart = Cart.find({
    userId: this.userId,
    shopId
  }, {
    fields
  });

  if (cart.count()) {
    // we could keep `sessionId` of normal user up to date from here, but with
    // current session logic we don't need this. That's why we just return
    // cursor as is with whatever `sessionId`.
    return cart;
  }
  // we may create a cart if we didn't find one.
  const cartId = Meteor.call("cart/createCart", this.userId, sessionId);

  return Cart.find(cartId);
});
Beispiel #8
0
 insertNewTestItem: function (doc, notDirectlyCalled) {
   check(notDirectlyCalled, Match.OneOf(Boolean, undefined))
   if (this.userId && Roles.userIsInRole(this.userId, ['admin'])) {
     if (notDirectlyCalled) {
       Tests.insert(doc)
     }
   }
 }
 /**
  * Return the latest state of the document in memory from its corresponding Authority.
  *
  * @param {Object} params
  * @param {String} params.docId            the unique id of the doc
  * @param {Connection} params.connection   Meteor Connection object of the client
  * @param {String}     params.userId       userId of requesting user
  * @return {{ version: Number, docJSON: Object}}
  */
 latestDocState ({ docId, connection, userId }) {
   check(docId, String);
   check(userId, Match.OneOf(undefined, null, String));
   if (!this.authorities[docId]) {
     throw new Meteor.Error('no-authority-exists', `latestDocState: This AuthorityManager doesn't have an Authority tracking a document with docId ${docId}.`);
   }
   // // store this new client's connection so we can know when they disconnect later
   this.authorities[docId].storeConnection({ connection, userId });
   return this.authorities[docId].latestDocState({ userId });
 }
Beispiel #10
0
export function convertLength(from, to, length) {
  check(from, Match.OneOf("in", "cm", "ft"));
  check(to, Match.OneOf("in", "cm", "ft"));
  check(length, Number);

  if (from === to) {
    return length;
  }

  if (from === "cm" && to === "in") {
    const convertedLength = length * 0.393;
    return convertedLength;
  }

  if (from === "in" && to === "cm") {
    const convertedLength = length * 2.54;
    return convertedLength;
  }

  if (from === "cm" && to === "ft") {
    const convertedLength = length * 0.0328084;
    return convertedLength;
  }

  if (from === "ft" && to === "cm") {
    const convertedLength = length * 30.48;
    return convertedLength;
  }

  if (from === "in" && to === "ft") {
    const convertedLength = length * 0.0833;
    return convertedLength;
  }

  if (from === "ft" && to === "in") {
    const convertedLength = length * 12;
    return convertedLength;
  }

  // if we made it here, something has gone wrong
  throw new ReactionError("invalid-parameter", "Invalid from or to value specified");
}
Beispiel #11
0
  "products/updateMetaFields": function (productId, updatedMeta, meta) {
    check(productId, String);
    check(updatedMeta, Object);
    check(meta, Match.OneOf(Object, Number, undefined, null));

    // Check first if Product exists and then if user has the proper rights
    const product = Products.findOne(productId);
    if (!product) {
      throw new Meteor.Error("Product not found");
    } else if (!Reaction.hasPermission("createProduct", this.userId, product.shopId)) {
      throw new Meteor.Error("Access Denied");
    }

    // update existing metadata
    if (typeof meta === "object") {
      return Products.update({
        _id: productId,
        metafields: meta
      }, {
        $set: {
          "metafields.$": updatedMeta
        }
      }, {
        selector: {
          type: "simple"
        }
      });
    } else if (typeof meta === "number") {
      return Products.update({
        _id: productId
      }, {
        $set: {
          [`metafields.${meta}`]: updatedMeta
        }
      }, {
        selector: {
          type: "simple"
        }
      });
    }

    // adds metadata
    return Products.update({
      _id: productId
    }, {
      $addToSet: {
        metafields: updatedMeta
      }
    }, {
      selector: {
        type: "simple"
      }
    });
  },
Beispiel #12
0
	return function(level, message) {
		check(level, Match.OneOf('info', 'error', 'warn', 'debug'));
		check(message, Match.OneOf(String, [String]));

		const logger = Migrations.options && Migrations.options.logger;

		if (logger && _.isFunction(logger)) {

			logger({
				level,
				message,
				tag: prefix,
			});

		} else {
			Log[level]({
				message: `${ prefix }: ${ message }`,
			});
		}
	};
Beispiel #13
0
Meteor.publish("UserAccount", function (userId) {
  check(userId, Match.OneOf(String, null));

  const shopId = Reaction.getShopId();
  if (Roles.userIsInRole(this.userId, ["admin", "owner"], shopId)) {
    return Collections.Accounts.find({
      userId: userId
    });
  }
  return this.ready();
});
Beispiel #14
0
	register(name, options, getUser) {
		check(name, String);
		check(options, {
			scope: Match.OneOf(String, [String]),
		});
		check(getUser, Function);

		this._add(name.toLowerCase(), {
			scope: options.scope,
			getUser,
		});
	}
Beispiel #15
0
const validateAttachmentsFields = (attachmentField) => {
	check(attachmentField, objectMaybeIncluding({
		short: Boolean,
		title: String,
		value: Match.OneOf(String, Match.Integer, Boolean),
	}));

	if (typeof attachmentField.value !== 'undefined') {
		attachmentField.value = String(attachmentField.value);
	}

};
Beispiel #16
0
Meteor.publish("UserProfile", function (profileUserId) {
  check(profileUserId, Match.OneOf(String, null));
  if (this.userId === null) {
    return this.ready();
  }
  const shopId = Reaction.getShopId();
  if (!shopId) {
    return this.ready();
  }
  const permissions = ["dashboard/orders", "owner", "admin",
    "dashboard/customers"];
  // no need to normal user so see his password hash
  const fields = {
    "emails": 1,
    "name": 1,
    "profile.lang": 1,
    "profile.firstName": 1,
    "profile.lastName": 1,
    "profile.familyName": 1,
    "profile.secondName": 1,
    "profile.name": 1,
    "services.twitter.profile_image_url_https": 1,
    "services.facebook.id": 1,
    "services.google.picture": 1,
    "services.github.username": 1,
    "services.instagram.profile_picture": 1
  };
  // TODO: this part currently not working as expected.
  // we could have three situation here:
  // 1 - registered user log in.
  // 2 - admin log in
  // 3 - admin want to get user data
  // I'm not sure about the 3rd case, but we do not cover 2nd case here, because
  // we can see a situation when anonymous user still represented by
  // `profileUserId`, but admin user already could be found by `this.userId`
  // In that case what we should do here?
  if (profileUserId !== this.userId && Roles.userIsInRole(this.userId,
    permissions, shopId ||
    Roles.userIsInRole(this.userId, permissions, Roles.GLOBAL_GROUP))) {
    return Meteor.users.find({
      _id: profileUserId
    }, {
      fields: fields
    });
  }

  return Meteor.users.find({
    _id: this.userId
  }, {
    fields: fields
  });
});
Beispiel #17
0
  /*
   * @locus Anywhere
   * @memberOf FilesCollection
   * @name remove
   * @param {String|Object} selector - Mongo-Style selector (http://docs.meteor.com/api/collections.html#selectors)
   * @param {Function} callback - Callback with one `error` argument
   * @summary Remove documents from the collection
   * @returns {FilesCollection} Instance
   */
  remove(selector = {}, callback) {
    this._debug(`[FilesCollection] [remove(${JSON.stringify(selector)})]`);
    check(selector, Match.OneOf(Object, String));
    check(callback, Match.Optional(Function));

    if (this.allowClientCode) {
      this.ddp.call(this._methodNames._Remove, selector, (callback || NOOP));
    } else {
      callback && callback(new Meteor.Error(401, '[FilesCollection] [remove] Run code from client is not allowed!'));
      this._debug('[FilesCollection] [remove] Run code from client is not allowed!');
    }

    return this;
  }
Beispiel #18
0
Meteor.publish("CompletedCartOrder", function (userId, cartId) {
  check(userId, Match.OneOf(String, null));
  check(cartId, String);
  if (this.userId === null) {
    return this.ready();
  }
  if (typeof userId === "string" && userId !== this.userId) {
    return this.ready();
  }

  return Orders.find({
    cartId,
    userId
  });
});
/**
 * @name accounts/removeUserPermissions
 * @memberof Accounts/Methods
 * @method
 * @param {String} userId - userId
 * @param {Array|String} permissions - Name of role/permission.
 * If array, users returned will have at least one of the roles specified but need not have _all_ roles.
 * @param {String} [group] Optional name of group to restrict roles to.
 * @returns {Boolean} success/failure
 */
export default function removeUserPermissions(userId, permissions, group) {
  if (!Reaction.hasPermission("reaction-accounts", Reaction.getUserId(), group)) {
    throw new ReactionError("access-denied", "Access denied");
  }
  check(userId, String);
  check(permissions, Match.OneOf(String, Array));
  check(group, Match.Optional(String, null));
  this.unblock();
  try {
    return Roles.removeUsersFromRoles(userId, permissions, group);
  } catch (error) {
    Logger.error(error);
    throw new ReactionError("access-denied", "Access Denied");
  }
}
Beispiel #20
0
  "discounts/addRate": function (modifier, docId) {
    check(modifier, Object);
    check(docId, Match.OneOf(String, null, undefined));

    // check permissions to add
    if (!Reaction.hasPermission("discount-rates")) {
      throw new Meteor.Error(403, "Access Denied");
    }
    // if no doc, insert
    if (!docId) {
      return Discounts.insert(modifier);
    }
    // else update and return
    return Discounts.update(docId, modifier);
  }
Beispiel #21
0
export function updateSocialSettings(values) {
  check(values, Match.OneOf(Object, String, Boolean, Number, null, undefined));

  if (!Reaction.hasPermission(["reaction-social"])) {
    throw new Meteor.Error(403, "Access Denied");
  }

  return Packages.update({
    name: "reaction-social",
    shopId: Reaction.getShopId()
  }, {
    $set: {
      settings: values
    }
  });
}
Beispiel #22
0
export function updateSocialSetting(provider, field, value) {
  check(provider, String);
  check(field, String);
  check(value, Match.OneOf(String, Boolean));

  if (!Reaction.hasPermission(["reaction-social"])) {
    throw new Meteor.Error(403, "Access Denied");
  }

  return Packages.update({
    name: "reaction-social",
    shopId: Reaction.getShopId()
  }, {
    $set: {
      [`settings.public.apps.${provider}.${field}`]: value
    }
  });
}
Meteor.publish("ServiceConfiguration", function (checkUserId) {
  check(checkUserId, Match.OneOf(String, null));
  if (this.userId === null) {
    return this.ready();
  }
  // Admins and account managers can manage the login methods for the shop
  if (Roles.userIsInRole(
    this.userId, ["owner", "admin", "dashboard/accounts"],
    Reaction.getShopId()
  )) {
    return ServiceConfiguration.configurations.find({});
  }

  return ServiceConfiguration.configurations.find({}, {
    fields: {
      secret: 0
    }
  });
});
Beispiel #24
0
  "taxes/setRateByShopAndItem": function (cartId, options) {
    check(cartId, String);
    check(options, {
      taxRatesByShop: Object,
      itemsWithTax: [Object],
      cartTaxRate: Number,
      cartTaxData: Match.OneOf([Object], undefined, null)
    });

    const { cartTaxData, cartTaxRate, itemsWithTax, taxRatesByShop } = options;

    return Cart.direct.update(cartId, {
      $set: {
        taxes: cartTaxData,
        tax: cartTaxRate,
        items: itemsWithTax,
        taxRatesByShop: taxRatesByShop
      }
    });
  },
export function discardDrafts(documentIds) {
  check(documentIds, Match.OneOf(String, Array));

  let documentIdArray;

  if (Array.isArray(documentIds)) {
    documentIdArray = documentIds;
  } else {
    documentIdArray = [documentIds];
  }

  const selector = {
    "workflow.status": {
      $nin: [
        "revision/published"
      ]
    },
    "$or": [
      {
        documentId: {
          $in: documentIdArray
        }
      },
      {
        "documentData.ancestors": {
          $in: documentIdArray
        }
      },
      {
        parentDocument: {
          $in: documentIds
        }
      }
    ]
  };

  const result = Revisions.remove(selector);

  return result > 0;
}
Beispiel #26
0
  "i18n/addTranslation": function (lng, namespace, key, message) {
    check(lng, Match.OneOf(String, Array));
    check(namespace, String);
    check(key, String);
    check(message, String);
    // string or first langauge
    let i18n = lng;
    if (typeof lng === "object") {
      i18n = lng[0];
    }

    if (!Reaction.hasAdminAccess()) {
      throw new Meteor.Error(403, "Access Denied");
    }
    const tran = `
      "i18n": "${i18n}",
      "shopId": "${Reaction.getShopId()}"
    `;

    const setTran = `"translation.${namespace}.${key}": "${message}"`;
    Translations.update({ tran }, { setTran });
  }
Beispiel #27
0
export const round2 = function (value, precision, type = null) {
    // Check
    check(value, Number);
    check(precision, Match.Integer);
    check(type, Match.OneOf(null, String));

    let amount;

    switch (type) {
        case 'up':
            amount = roundTo.up(value, precision);
            break;
        case 'down':
            amount = roundTo.down(value, precision);
            break;
        case 'general':
        default:
            amount = roundTo(value, precision);
    }

    return amount;
};
Accounts.unlinkService = function(userId, serviceName, cb) {
  check(userId, Match.OneOf(String, Mongo.ObjectID));
  if (typeof serviceName !== 'string') {
    throw new Meteor.Error('Service name must be string');
  }
  const user = Meteor.users.findOne({ _id: userId });
  if (serviceName === 'resume' || serviceName === 'password') {
    throw new Meteor.Error('Internal services cannot be unlinked: ' + serviceName);
  }

  if (user.services[serviceName]) {
    const newServices = { ...user.services };
    delete newServices[serviceName];
    Meteor.users.update({ _id: user._id }, { $set: { services: newServices } }, function(result) {
      if (cb && typeof cb === 'function') {
        cb(result);
      }
    });
  } else {
    throw new Meteor.Error(500, 'no service');
  }
};
Beispiel #29
0
Meteor.publish("Accounts", function (userId) {
  check(userId, Match.OneOf(String, null));
  // we could additionally make checks of useId defined, but this could lead to
  // situation when user will may not have time to get an account
  if (this.userId === null) {
    return this.ready();
  }

  const shopId = Reaction.getShopId();
  if (!shopId) {
    return this.ready();
  }

  const nonAdminGroups = Collections.Groups.find({
    name: { $in: ["guest"] },
    shopId
  }, {
    fields: { _id: 1 }
  }).fetch().map((group) => group._id);

  // global admin can get all accounts
  if (Roles.userIsInRole(this.userId, ["owner"], Roles.GLOBAL_GROUP)) {
    return Collections.Accounts.find({
      groups: { $nin: nonAdminGroups }
    });

  // shop admin gets accounts for just this shop
  } else if (Roles.userIsInRole(this.userId, ["admin", "owner", "reaction-accounts"], shopId)) {
    return Collections.Accounts.find({
      groups: { $nin: nonAdminGroups },
      shopId: shopId
    });
  }

  // regular users should get just their account
  return Collections.Accounts.find({
    userId: this.userId
  });
});
Accounts.registerLoginHandler(function(options) {
  if (!options.link) return undefined;

  check(options.link, {
    credentialToken: String,
    // When an error occurs while retrieving the access token, we store
    // the error in the pending credentials table, with a secret of
    // null. The client can call the login method with a secret of null
    // to retrieve the error.
    credentialSecret: Match.OneOf(null, String)
  });

  const result = OAuth.retrieveCredential(options.link.credentialToken, options.link.credentialSecret);
  if (!result) {
    return {
      type: 'link',
      error: new Meteor.Error(Accounts.LoginCancelledError.numericError, 'No matching link attempt found')
    };
  }

  if (result instanceof Error) throw result;
  else return Accounts.LinkUserFromExternalService(result.serviceName, result.serviceData, result.options);
});