shahednasser / medusa-1.8-marketplace-tutorial

Code for creating a marketplace with Medusa v1.8
https://medusajs.com/blog/extending-medusa-usecase-marketplace/
47 stars 12 forks source link

custom userService dont include the current loggedInUser, but productService and storeService included it #2

Open suitcodemr opened 1 year ago

suitcodemr commented 1 year ago

First of alll, thanks for the great Medusa Marketplace tutorial 👍 ❤️

My aim is, that the '/admin/users'-method only response the users, which have the same store_id like the loggedInUser.

I include in the custom user- and productService the Medusa-Logger to show the logs in the terminal (third code-snippet).

Now my question: Why is the loggedInUser not included in the custom userService?

I hope you can help me. I had tried many things, but nothing helped. :(

userService

import { Lifetime } from "awilix"
import { Logger, UserService as MedusaUserService } from "@medusajs/medusa"
import { User } from "../models/user"
import { FilterableUserProps, CreateUserInput as MedusaCreateUserInput } from "@medusajs/medusa/dist/types/user"
import StoreRepository from "../repositories/store"

type CreateUserInput = {
  store_id?: string
} & MedusaCreateUserInput

class UserService extends MedusaUserService {
  static LIFE_TIME = Lifetime.SCOPED
  protected readonly loggedInUser_: User | null
  protected readonly storeRepository_: typeof StoreRepository;
  protected logger_: Logger

  constructor(container, options) {
    // @ts-expect-error prefer-rest-params
    super(...arguments)
    this.storeRepository_ = container.storeRepository;
    this.logger_ = container.logger;

    try {
      this.loggedInUser_ = container.loggedInUser
    } catch (e) {
      // avoid errors when backend first runs
    }
  }

  async list(selector: FilterableUserProps, config?: {}): Promise<User[]>{

    this.logger_.info("UserService - list");
    this.logger_.info(JSON.stringify(this.loggedInUser_));

    return await super.list(selector, config);
  }

  async create(user: CreateUserInput, password: string): Promise<User> {

    this.logger_.info("UserService - create");
    this.logger_.info(JSON.stringify(this.loggedInUser_));
    this.logger_.info(JSON.stringify(user));

    if (!user.store_id) {
      const storeRepo = this.manager_.withRepository(this.storeRepository_)
      let newStore = storeRepo.create()
      newStore = await storeRepo.save(newStore)
      user.store_id = newStore.id
    }

    return await super.create(user, password)
  }
}

export default UserService

productService

import { Lifetime } from "awilix"
import { 
  Logger,
  ProductService as MedusaProductService, Product, User,
} from "@medusajs/medusa"
import { CreateProductInput as MedusaCreateProductInput, FindProductConfig, ProductSelector as MedusaProductSelector } from "@medusajs/medusa/dist/types/product"

type ProductSelector = {
  store_id?: string
} & MedusaProductSelector

type CreateProductInput = {
  store_id?: string
} & MedusaCreateProductInput

class ProductService extends MedusaProductService {
  static LIFE_TIME = Lifetime.SCOPED
  protected readonly loggedInUser_: User | null
  protected logger_: Logger

  constructor(container, options) {
    // @ts-expect-error prefer-rest-params
    super(...arguments)
    this.logger_ = container.logger;

    try {
      this.loggedInUser_ = container.loggedInUser
    } catch (e) {
      // avoid errors when backend first runs
    }
  }

  async list(selector: ProductSelector, config?: FindProductConfig): Promise<Product[]> {
    if (!selector.store_id && this.loggedInUser_?.store_id) {
      selector.store_id = this.loggedInUser_.store_id
    }

    config.select?.push('store_id')

    config.relations?.push('store')

    return await super.list(selector, config)
  }

  async listAndCount(selector: ProductSelector, config?: FindProductConfig): Promise<[Product[], number]> {

    this.logger_.info("ProductService - listAndCount");
    this.logger_.info(JSON.stringify(this.loggedInUser_));

    if (!selector.store_id && this.loggedInUser_?.store_id) {
      selector.store_id = this.loggedInUser_.store_id
    }

    config.select?.push('store_id')

    config.relations?.push('store')

    return await super.listAndCount(selector, config)
  }

  async retrieve(productId: string, config?: FindProductConfig): Promise<Product> {
    config.relations = [
      ...(config.relations || []),
      'store'
    ]

    const product = await super.retrieve(productId, config);

    if (product.store?.id && this.loggedInUser_?.store_id && product.store.id !== this.loggedInUser_.store_id) {
      // Throw error if you don't want a product to be accessible to other stores
      throw new Error('Product does not exist in store.');
    }

    return product
  }

  async create(productObject: CreateProductInput): Promise<Product> {
    if (!productObject.store_id && this.loggedInUser_?.store_id) {
      productObject.store_id = this.loggedInUser_.store_id
    }

    return await super.create(productObject);
  }
}

export default ProductService

Console logs

::ffff:127.0.0.1 - - [06/May/2023:07:16:22 +0000] "POST /admin/auth HTTP/1.1" 200 278 "-" "insomnia/2023.1.0"
info:    ProductService - listAndCount
info:    {"store_id":null,"id":"usr_01GZQXGW8KASREV87N5QFVE7X4","created_at":"2023-05-06T06:55:52.000Z","updated_at":"2023-05-06T06:55:52.000Z","deleted_at":null,"role":"member","email":"admin@medusa-test.com","first_name":null,"last_name":null,"api_token":null,"metadata":null}
::ffff:127.0.0.1 - - [06/May/2023:07:16:26 +0000] "GET /admin/products HTTP/1.1" 200 60799 "-" "insomnia/2023.1.0"
info:    UserService - list
info:    undefined
::ffff:127.0.0.1 - - [06/May/2023:07:16:41 +0000] "GET /admin/users HTTP/1.1" 200 1078 "-" "insomnia/2023.1.0"

info:    UserService - create
info:    undefined
info:    {"email":"user4@example.com"}
::ffff:127.0.0.1 - - [06/May/2023:07:37:25 +0000] "POST /admin/users HTTP/1.1" 200 304 "-" "insomnia/2023.1.0"
suitcodemr commented 1 year ago

Little hint

I never touched the 'logged-in-user'-middleware or something else. I only add the loggers in the custom user- and productService. And the override-method 'list' in the userService.