diff --git a/.changeset/tasty-walls-prove.md b/.changeset/tasty-walls-prove.md new file mode 100644 index 0000000000..a5ba4c6630 --- /dev/null +++ b/.changeset/tasty-walls-prove.md @@ -0,0 +1,6 @@ +--- +"@medusajs/medusa-cli": patch +"@medusajs/medusa": patch +--- + +feat(medusa,medusa-cli): Added an invite option to the create user command, and allow seeding publishable api keys diff --git a/packages/medusa-cli/src/create-cli.js b/packages/medusa-cli/src/create-cli.js index 8479dcf95c..a124004f51 100644 --- a/packages/medusa-cli/src/create-cli.js +++ b/packages/medusa-cli/src/create-cli.js @@ -296,6 +296,11 @@ function buildLocalCommands(cli, isLocalProject) { alias: `id`, type: `string`, describe: `User's id.`, + }) + .option(`invite`, { + type: `boolean`, + describe: `If flag is set, an invitation will be created instead of a new user and the invite token will be returned.`, + default: false, }), handler: handlerP( getCommandHandler(`user`, (args, cmd) => { diff --git a/packages/medusa/src/commands/seed.ts b/packages/medusa/src/commands/seed.ts index 303e755890..f0ac604ceb 100644 --- a/packages/medusa/src/commands/seed.ts +++ b/packages/medusa/src/commands/seed.ts @@ -17,6 +17,7 @@ import { ProductService, ProductVariantService, RegionService, + SalesChannelService, ShippingOptionService, ShippingProfileService, StoreService, @@ -26,6 +27,8 @@ import { ConfigModule } from "../types/global" import { CreateProductInput } from "../types/product" import { CreateProductCategoryInput } from "../types/product-category" import getMigrations, { getModuleSharedResources } from "./utils/get-migrations" +import PublishableApiKeyService from "../services/publishable-api-key" +import { SalesChannel } from "../models" type SeedOptions = { directory: string @@ -101,6 +104,12 @@ const seed = async function ({ directory, migrate, seedFile }: SeedOptions) { const productCategoryService: ProductCategoryService = container.resolve( "productCategoryService" ) + const publishableApiKeyService: PublishableApiKeyService = container.resolve( + "publishableApiKeyService" + ) + const salesChannelService: SalesChannelService = container.resolve( + "salesChannelService" + ) /* eslint-disable */ const productVariantService: ProductVariantService = container.resolve( @@ -122,6 +131,7 @@ const seed = async function ({ directory, migrate, seedFile }: SeedOptions) { categories = [], shipping_options, users, + publishable_api_keys = [], } = JSON.parse(fs.readFileSync(resolvedPath, `utf-8`)) const gcProfile = await shippingProfileService.retrieveGiftCardDefault() @@ -235,6 +245,31 @@ const seed = async function ({ directory, migrate, seedFile }: SeedOptions) { } } } + + let defaultSalesChannel: SalesChannel | null = null + + try { + defaultSalesChannel = await salesChannelService + .withTransaction(tx) + .retrieveDefault() + } catch (e) { + defaultSalesChannel = null + } + + for (const pak of publishable_api_keys) { + const publishableApiKey = await publishableApiKeyService + .withTransaction(tx) + .create(pak, { + loggedInUserId: "", + }) + + // attach to default sales channel if exists + if (defaultSalesChannel) { + await publishableApiKeyService.addSalesChannels(publishableApiKey.id, [ + defaultSalesChannel.id, + ]) + } + } }) track("CLI_SEED_COMPLETED") diff --git a/packages/medusa/src/commands/user.js b/packages/medusa/src/commands/user.js index e23acd8261..9870cfd684 100644 --- a/packages/medusa/src/commands/user.js +++ b/packages/medusa/src/commands/user.js @@ -5,8 +5,16 @@ import express from "express" import { track } from "medusa-telemetry" import loaders from "../loaders" +import Logger from "../loaders/logger" -export default async function ({ directory, id, email, password, keepAlive }) { +export default async function ({ + directory, + id, + email, + password, + keepAlive, + invite, +}) { track("CLI_USER", { with_id: !!id }) const app = express() try { @@ -15,8 +23,19 @@ export default async function ({ directory, id, email, password, keepAlive }) { expressApp: app, }) - const userService = container.resolve("userService") - await userService.create({ id, email }, password) + if (invite) { + const inviteService = container.resolve("inviteService") + await inviteService.create(email, "admin") + const invite = await inviteService.list({ + user_email: email, + }) + Logger.info(` + Invite token: ${invite[0].token} + Open the invite in Medusa Admin at: [your-admin-url]/invite?token=${invite[0].token}`) + } else { + const userService = container.resolve("userService") + await userService.create({ id, email }, password) + } } catch (err) { console.error(err) process.exit(1) diff --git a/packages/medusa/src/services/user.ts b/packages/medusa/src/services/user.ts index a6d71db4b6..8c3a87fcd4 100644 --- a/packages/medusa/src/services/user.ts +++ b/packages/medusa/src/services/user.ts @@ -177,6 +177,18 @@ class UserService extends TransactionBaseService { } const validatedEmail = validateEmail(user.email) + + const userEntity = await userRepo.findOne({ + where: { email: validatedEmail }, + }) + + if (userEntity) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + "A user with the same email already exists." + ) + } + if (password) { const hashedPassword = await this.hashPassword_(password) createData.password_hash = hashedPassword