Files
medusa-store/packages/medusa/src/services/store.js
Sebastian Rindom bc5ff91a02 Adds Store Service to control store settings (#76)
Also adds support for `projectConfig.admin_cors` & `projectConfig.store_cors`
2020-06-29 10:23:24 +02:00

176 lines
4.8 KiB
JavaScript

import mongoose from "mongoose"
import bcrypt from "bcrypt"
import _ from "lodash"
import { Validator, MedusaError } from "medusa-core-utils"
import { BaseService } from "medusa-interfaces"
import { currencies } from "../utils/currencies"
/**
* Provides layer to manipulate store settings.
* @implements BaseService
*/
class StoreService extends BaseService {
constructor({ storeModel, eventBusService }) {
super()
/** @private @const {storeModel} */
this.storeModel_ = storeModel
/** @private @const {EventBus} */
this.eventBus_ = eventBusService
}
/**
* Used to validate customer ids. Throws an error if the cast fails
* @param {string} rawId - the raw customer id to validate.
* @return {string} the validated id
*/
validateId_(rawId) {
const schema = Validator.objectId()
const { value, error } = schema.validate(rawId)
if (error) {
throw new MedusaError(
MedusaError.Types.INVALID_ARGUMENT,
"The customerId could not be casted to an ObjectId"
)
}
return value
}
/**
* Retrieve the store settings. There is always a maximum of one store.
* @return {Promise<Store>} the customer document.
*/
retrieve() {
return this.storeModel_.findOne().catch(err => {
throw new MedusaError(MedusaError.Types.DB_ERROR, err.message)
})
}
/**
* Updates a customer. Metadata updates and address updates should
* use dedicated methods, e.g. `setMetadata`, etc. The function
* will throw errors if metadata updates and address updates are attempted.
* @param {string} variantId - the id of the variant. Must be a string that
* can be casted to an ObjectId
* @param {object} update - an object with the update values.
* @return {Promise} resolves to the update result.
*/
async update(update) {
const store = await this.retrieve()
if (update.metadata) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"Use setMetadata to update metadata fields"
)
}
if (update.currencies) {
update.currencies = update.currencies.map(c => c.toUpperCase())
update.currencies.forEach(c => {
if (!currencies[c]) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Invalid currency ${c}`
)
}
})
}
return this.storeModel_
.updateOne({ _id: store._id }, { $set: update }, { runValidators: true })
.catch(err => {
throw new MedusaError(MedusaError.Types.DB_ERROR, err.message)
})
}
/**
* Add a currency to the store
* @param {string} code - 3 character ISO currency code
* @return {Promise} result after update
*/
async addCurrency(code) {
code = code.toUpperCase()
const store = await this.retrieve()
if (!currencies[code]) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Invalid currency ${code}`
)
}
if (store.currencies.includes(code)) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Currency already added`
)
}
return this.storeModel_.updateOne(
{
_id: store._id,
},
{ $push: { currencies: code } }
)
}
/**
* Removes a currency from the store
* @param {string} code - 3 character ISO currency code
* @return {Promise} result after update
*/
async removeCurrency(code) {
const store = await this.retrieve()
code = code.toUpperCase()
return this.storeModel_.updateOne(
{
_id: store._id,
},
{ $pull: { currencies: code } }
)
}
/**
* Decorates a store object.
* @param {Store} store - the store to decorate.
* @param {string[]} fields - the fields to include.
* @param {string[]} expandFields - fields to expand.
* @return {Store} return the decorated Store.
*/
async decorate(store, fields, expandFields = []) {
return store
}
/**
* Dedicated method to set metadata for a store.
* To ensure that plugins does not overwrite each
* others metadata fields, setMetadata is provided.
* @param {string} customerId - the customer to apply metadata to.
* @param {string} key - key for metadata field
* @param {string} value - value for metadata field.
* @return {Promise} resolves to the updated result.
*/
async setMetadata(key, value) {
const store = await this.retrieve()
if (typeof key !== "string") {
throw new MedusaError(
MedusaError.Types.INVALID_ARGUMENT,
"Key type is invalid. Metadata keys must be strings"
)
}
const keyPath = `metadata.${key}`
return this.storeModel_
.updateOne({ _id: store._id }, { $set: { [keyPath]: value } })
.catch(err => {
throw new MedusaError(MedusaError.Types.DB_ERROR, err.message)
})
}
}
export default StoreService