IT |
気になる、記になる… |
都市開発鉄道シミュレーションゲーム『A列車で行こう はじまる観光計画』のスマホ版がクラウドゲームアプリとして登場 |
https://taisy0.com/2022/06/21/158308.html
|
android |
2022-06-21 10:42:36 |
IT |
ITmedia 総合記事一覧 |
[ITmedia ビジネスオンライン] オタク向けパーソナルトレーニングジム、4店舗目を元祖聖地「秋葉原」にオープン |
https://www.itmedia.co.jp/business/articles/2206/21/news108.html
|
clara |
2022-06-21 19:49:00 |
python |
Pythonタグが付けられた新着投稿 - Qiita |
motoによるSQSキュー(FIFO)のモック作成 |
https://qiita.com/matsumura-yzrh/items/e614e55c0a7f1383aa0b
|
pytest |
2022-06-21 19:13:48 |
Ruby |
Rubyタグが付けられた新着投稿 - Qiita |
AWSのCloudFrontを構築するスクリプトをRubyで作った |
https://qiita.com/aoyagikouhei/items/937af3fc16bfb592f0de
|
cloudfront |
2022-06-21 19:27:37 |
Ruby |
Rubyタグが付けられた新着投稿 - Qiita |
【Ruby】ハッシュとシンボルについて学んだこと |
https://qiita.com/pei23/items/896c02011881c00be421
|
言語 |
2022-06-21 19:18:28 |
Ruby |
Rubyタグが付けられた新着投稿 - Qiita |
メタプログラミングに触れてみた |
https://qiita.com/kushidangoAnne/items/8a3bbdaa8d07e36e7896
|
class |
2022-06-21 19:01:10 |
Linux |
Ubuntuタグが付けられた新着投稿 - Qiita |
Ubuntuがディスクの容量不足で起動しなくなった際の対処法 |
https://qiita.com/l3ickey/items/06ad71aae7dfd5d0872b
|
ubuntu |
2022-06-21 19:38:29 |
Docker |
dockerタグが付けられた新着投稿 - Qiita |
dockerを使ってサクッとPHPとMySQL環境を手に入れる |
https://qiita.com/y-do/items/7ec63d721ee21621be7a
|
docker |
2022-06-21 19:14:54 |
技術ブログ |
Developers.IO |
Visual Studio 2022 for Mac プレビューを使って、.NET MAUI アプリをビルドしてみた |
https://dev.classmethod.jp/articles/visual-studio-2022-for-mac-preview-dotnet-maui-build/
|
android |
2022-06-21 10:47:58 |
技術ブログ |
Developers.IO |
Notionのブロック要素を利用してカラム単位で背景色を付けてみた |
https://dev.classmethod.jp/articles/notion-coloring-columns-with-sub-pages/
|
notion |
2022-06-21 10:01:25 |
海外TECH |
MakeUseOf |
iOS 16 Supports Switch Controllers: What This Means for Mobile Gamers |
https://www.makeuseof.com/ios-16-nintendo-switch-controllers-mobile-gamers/
|
gamers |
2022-06-21 10:47:37 |
海外TECH |
MakeUseOf |
Which Car Brands Offer Full EVs? 7 EV Manufacturers Compared |
https://www.makeuseof.com/which-car-brands-offer-full-evs/
|
major |
2022-06-21 10:30:14 |
海外TECH |
MakeUseOf |
Which Raspberry Pi Model Is Best for Your Next Project? |
https://www.makeuseof.com/which-raspberry-pi-model-next-project/
|
raspberry |
2022-06-21 10:15:14 |
海外TECH |
DEV Community |
Create a Marketplace with Medusa Part 3: Implement User Management and Permissions |
https://dev.to/medusajs/create-a-marketplace-with-medusa-part-3-implement-user-management-and-permissions-d32
|
Create a Marketplace with Medusa Part Implement User Management and PermissionsIn the previous parts of this series you learned how to build a marketplace using Medusa and Medusa Extender You associated users products and orders to a store This part of the tutorial focuses on user management within a store This entails adding team members to a store restricting the visibility of users in the whole marketplace based on the store they re in and adding access control to manage permissions within a store s team You can find the code for this tutorial in this GitHub repository You can alternatively use the Medusa Marketplace plugin as indicated in the README of the GitHub repository If you re already using it make sure to update to the latest version npm install medusa marketplace latest PrerequisitesIt is assumed that you ve followed along with the first parts of the series before continuing this part If you haven t you should start from the first part of the series Alternatively clone the part branch of the GitHub repository and set up and configure your PostgreSQL database Then follow the steps in the README Medusa AdminIf you don t have the Medusa Admin installed it is recommended that you install it so that you can easily view products and orders among other functionalities Alternatively you can use Medusa s Admin APIs to access the data on your server However the rest of the tutorial will mostly showcase features through the Medusa Admin Update DependenciesMedusa and Medusa Extender both had new releases since the last article So before you implement the new functionalities it s important to update the dependencies related to these first In the root of your Medusa server run the following command to update dependencies npm i medusajs medusa latest medusa extender latest medusajs medusa cli latest medusa interfaces latestThis will install version of Medusa s core packages and version of the Medusa Extender Please note that you might receive an error if the version of awilix is set to anything other than while using version If you get the error please update the dependency in package json awilix If at the time you re following along with the tutorial the versions have changed please note that there might be some difference between the versions used here and the version you have Version of Medusa Extender changes how migrations are found in the code base and now requires you to include the path in the configuration So in medusa config js add the following in the exported object module exports other options projectConfig other options cli migration dirs dist migration js Changes Based on UpdateThe Medusa Extender s newest updates bring changes for a better developer experience as well as new features There is one change that affects the current code you have Change LoggedInUser MiddlewareThe change entails the loggedInUser middleware located in src modules user middlewares loggedInUser middleware ts Currently the middleware runs for all route paths The new Medusa Extender update allows you to specify a regular expression pattern for the path route that the current route will be tested on So change the Middleware decorator in src modules user middlewares loggedInUser middleware ts to the following Middleware requireAuth true routes method all path admin Following this change the middleware now will only run when the route starts with admin Then change the code inside the consume method to the following public async consume req MedusaAuthenticatedRequest res Response next NextFunction Promise lt void gt const userService req scope resolve userService as UserService const loggedInUser await userService retrieve req user userId select id store id req scope register loggedInUser resolve gt loggedInUser next Previously you had to check whether the current route is an admin route inside the middleware As this is not necessary anymore you just set the logged in user right away without checking Change loggedInUser in ServicesThis change also means that the loggedInUser will not always be in the scope as you previously implemented it So you ll need to update how the loggedInUser was accessed before in multiple places In src modules order order service ts change the loggedInUser in InjectedDependencies to the following loggedInUser User Then change the if condition in the buildQuery method to the following if Object keys this container includes loggedInUser amp amp this container loggedInUser store id selector store id this container loggedInUser store id As the container acts as a proxy object to the container object the awilix package gives us you can check if a property exists in the container using Object keys this container includes If you access the property directly and it doesn t exist in the container the error AwilixResolutionError will be thrown The next change is in src modules product services product service ts Change the loggedInUser in ConstructorParams to the following loggedInUser User Then in the prepareListQuery method change the declaration and initialization of loggedInUser to the following const loggedInUser Object keys this container includes loggedInUser this container loggedInUser nullYou re not making changes in attachStoreToProduct since a product can only be added if a user is logged in Finally in src modules store services store service ts change the loggedInUser in ConstructorParams to the following loggedInUser User Then in the retrieve method change the if condition at the beginning of the method to the following if Object keys this container includes loggedInUser return super retrieve relations Test Current CodeThe new update and changes will not affect how your marketplace was previously functioning To test it out run the server npm startThen you can try out the previous functionalities you implemented Everything should work as expected You can run the Medusa admin to test out functionalities on it by going to the directory of the Medusa admin and running the following command npm start Retrieve Users By StoreGo to your Medusa admin and log in with a user that has a store Alternatively you can use the Authenticate a User endpoint Then on the Medusa admin go to Settings gt Users or use the Retrieve all Users REST API At the moment only one user is part of each store However you can see that all users are retrieved and not just the users that are part of the store the currently logged in user is in To change this go to src modules user services user service ts and add loggedInUser to ConstructorParams type ConstructorParams loggedInUser User Next change the Service decorator to the following Service scope SCOPED override MedusaUserService This allows the UserService to access the loggedInUser in the scope Finally add the following method inside the UserService class buildQuery selector config object if Object keys this container includes loggedInUser amp amp this container loggedInUser store id selector store id this container loggedInUser store id return super buildQuery selector config This filters out the users based on the store id of the logged in user Test Retrieve Users by StoreIf you restart the Medusa server now and check the Users page you ll see only one user in the team now Add Users to a StoreIn the previous implementation you created a new store for every new user In this section you ll change that to allow users to add other users to their store To do that go to src modules store services store service ts and change the createStoreForNewUser method to the following OnMedusaEntityEvent Before Insert User async true public async createStoreForNewUser params MedusaEventHandlerParams lt User Insert gt Promise lt EntityEventType lt User Insert gt gt const event params let store id Object keys this container includes loggedInUser this container loggedInUser store id null if store id const createdStore await this withTransaction event manager createForUser event entity if createdStore store id createdStore id event entity store id store id return event This method now checks if the currently logged in user has a store id and attaches it to the new user Otherwise it creates a new store for the new user This implementation also allows a super admin that does not belong to any store to create new users with new stores Test Adding Users to a StoreThe Medusa admin only includes the invite functionality to add new users which you ll work on in the next section So to test out this functionality you need to use the REST APIs Restart your Medusa server then log in using the REST API with a user that belongs to a store Next send a request to the Create a User endpoint You can now go to the Medusa admin or use the Retrieve a User endpoint You should see one more user in the team other than the previously created user Associate Invites with StoresWhen an admin user invites another user to join their team whether through an endpoint or through the Medusa admin a new invite is created Then when the invite is accepted a user is created using information from that invite as well as information that the person enters when they accept the invite In this section you ll make the necessary changes that associate an invite with a store and ensure that when the invite is accepted the created user is also associated with the store Create Invite EntityCreate the directory src modules invite This will hold all files related to the invites module Then create the file src modules invite invite entity ts with the following content import Column Entity Index JoinColumn ManyToOne from typeorm import Entity as MedusaEntity from medusa extender import Invite as MedusaInvite from medusajs medusa import Store from store entities store entity MedusaEntity override MedusaInvite Entity export class Invite extends MedusaInvite Index Column nullable true store id string ManyToOne gt Store store gt store invites JoinColumn name store id store Store You extend the Invite entity from Medusa s core and add to it the store id field and the store relation This relation should also be added to the Store entity So in src modules store entities store entity ts add the following import at the beginning of the file import Invite from invite invite entity And add the following inside the Store class OneToMany gt Invite invite gt invite store JoinColumn name id referencedColumnName store id invites Invite Create Invite RepositoryNext create the file src modules invite invite repository ts with the following content import Repository as MedusaRepository Utils from medusa extender import EntityRepository from typeorm import Invite from invite entity import InviteRepository as MedusaInviteRepository from medusajs medusa dist repositories invite MedusaRepository override MedusaInviteRepository EntityRepository Invite export class InviteRepository extends Utils repositoryMixin lt Invite MedusaInviteRepository gt MedusaInviteRepository This creates a repository for the Invite entity that extends InviteRepository from Medusa s core This allows you to retrieve invites from the database based on the Invite entity you created in the previous section Create MigrationTo reflect the new column in the database you need to create a migration file in the invite module As migration files have the format lt timestamp gt invite migration ts a migration file is unique to you so you need to create it yourself You can generate the migration file using the following command provided by Medusa Extender s CLI node modules bin medex g mi inviteThis creates the file src modules invite lt timestamp gt invite migration ts for you Open that file and replace the up and down methods with the following implementation public async up queryRunner QueryRunner Promise lt void gt const query ALTER TABLE public invite ADD COLUMN IF NOT EXISTS store id text await queryRunner query query public async down queryRunner QueryRunner Promise lt void gt const query ALTER TABLE public invite DROP COLUMN store id await queryRunner query query The up method adds the store id column to the invite table and the down method drops the column Run MigrationsTo actually reflect these changes in the database you need to run the migrations As migrations can only be run as JavaScript files run the build command to transpile the TypeScript files to JavaScript files npm run buildThen use the migrate command provided by the Medusa Extender CLI to run those migrations node modules bin medex migrate runIf you get an error about duplicate migrations because of migrations from the previous part of this series go ahead and remove the old ones from the dist directory and try running the command again If you check your database after the migration is run successfully you can see that the new column store id added to the invite table Change List InvitesSimilar to the Retrieve all Users functionality the List all Invites functionality currently returns all invites irrespective of which store the invite belongs to If you try to invite a user to a store using the Medusa admin or using the REST APIs then log into another store with another user you can see the invite there as well Only invites that belong to the store of the currently logged in user should be shown So in this section you ll implement the necessary changes so that only invites specific to a store are retrieved Create the file src modules invite invite service ts with the following content import ConfigModule from medusajs medusa dist types global import EntityManager from typeorm import EventBusService from medusajs medusa import Invite from invite entity import InviteRepository from invite repository import default as MedusaInviteService from medusajs medusa dist services invite import Service from medusa extender import User from user entities user entity import UserRepository from user repositories user repository import UserService from user services user service type InviteServiceProps manager EntityManager userService UserService userRepository UserRepository eventBusService EventBusService loggedInUser User inviteRepository InviteRepository Service scope SCOPED override MedusaInviteService export class InviteService extends MedusaInviteService static readonly resolutionKey inviteService private readonly manager EntityManager private readonly container InviteServiceProps private readonly inviteRepository InviteRepository constructor container InviteServiceProps configModule ConfigModule super container configModule this manager container manager this container container this inviteRepository container inviteRepository withTransaction transactionManager EntityManager InviteService if transactionManager return this const cloned new InviteService this container manager transactionManager this configModule cloned transactionManager transactionManager return cloned buildQuery selector config object if Object keys this container includes loggedInUser amp amp this container loggedInUser store id selector store id this container loggedInUser store id return super buildQuery selector config You override the InviteService from Medusa s core Inside the service you override the buildQuery method to filter the invites based on the store ID of the currently logged in user Create Invite ModuleBefore you can test out what you just implemented you need to create an invite module Create the file src modules invite invite module ts with the following content import Invite from invite entity import InviteMigration from invite migration import InviteRepository from invite repository import InviteService from invite service import Module from medusa extender Module imports Invite InviteRepository InviteService InviteMigration export class InviteModule Make sure to replace the migration with your own migration class name and file path Then in src main ts import the InviteModule at the beginning of the file import InviteModule from modules invite invite module and add it to the array passed to the load function await new Medusa dirname expressInstance load InviteModule Listen to Create InviteIn this section you ll listen to the “before insert event on invites then attach store id of the logged in user to the invite To listen to events on entities such as the “before insert event you need to create a subscriber and a middleware that registers the subscriber To create the subscriber create the file src modules invite invite subscriber ts with the following content import Connection EntitySubscriberInterface EventSubscriber InsertEvent from typeorm import Utils as MedusaUtils OnMedusaEntityEvent eventEmitter from medusa extender import Invite from invite entity EventSubscriber export default class InviteSubscriber implements EntitySubscriberInterface lt Invite gt static attachTo connection Connection void MedusaUtils attachOrReplaceEntitySubscriber connection InviteSubscriber public listenTo typeof Invite return Invite Relay the event to the handlers param event Event to pass to the event handler public async beforeInsert event InsertEvent lt Invite gt Promise lt void gt return await eventEmitter emitAsync OnMedusaEntityEvent Before InsertEvent Invite event transactionalEntityManager event manager This subscriber emits the “before insert event whenever a new invite is created Then create the file src modules invite inviteSubscriber middleware ts with the following content import MEDUSA RESOLVER KEYS MedusaAuthenticatedRequest MedusaMiddleware Utils as MedusaUtils Middleware from medusa extender import NextFunction Response from express import Connection from typeorm import InviteSubscriber from invite subscriber Middleware requireAuth true routes method post path admin invites export class AttachInviteSubscriberMiddleware implements MedusaMiddleware public async consume req MedusaAuthenticatedRequest res Response next NextFunction Promise lt void gt const connection req scope resolve MEDUSA RESOLVER KEYS manager as connection Connection InviteSubscriber attachTo connection return next This middleware registers the subscriber on all routes that begin with admin invites if the request method is POST Next in src modules store services store service ts import Invite at the beginning of the file import Invite from invite invite entity Then add the following method to listen to the “before insert event and handle it OnMedusaEntityEvent Before Insert Invite async true public async addStoreToInvite params MedusaEventHandlerParams lt Invite Insert gt Promise lt EntityEventType lt Invite Insert gt gt const event params invite to be created is in event entity let store id this container loggedInUser store id if event entity store id amp amp store id event entity store id store id return event This checks if the invite doesn t already have a store id and if the current user has a store id then set the store id of the invite to the logged in user s invite This implementation also enables the super admin to send invites to other super admins Finally you need to add the middleware to the invite module before you can test it out In src modules invite invite module ts add the following import at the beginning of the file import AttachInviteSubscriberMiddleware from inviteSubscriber middleware Then add the AttachInviteSubscriberMiddleware class to the imports array passed to the Module directive Module imports AttachInviteSubscriberMiddleware Test List and Create InvitesRestart the server and check the Users page again Then create an invite The invite should now appear in the store it s associated with and not in all stores Associate Invited User with StoreWhen the invite is accepted a new user is created However the current implementation does not associate the new user with any store In this section you ll override the Accept an Invite endpoint to add this implementation Go to src modules user services user service ts and add the new method addUserToStore public async addUserToStore user id store id await this atomicPhase async m gt const userRepo m getCustomRepository this userRepository const query this buildQuery id user id const user await userRepo findOne query if user user store id store id await userRepo save user Also add the withTransaction method to override the parent s method and make sure it returns the custom user service withTransaction transactionManager EntityManager UserService if transactionManager return this const cloned new UserService this container manager transactionManager cloned transactionManager transactionManager return cloned Next you need to add a new method to InviteService that retrieves an invite by ID In src modules invite invite service ts add the following method in InviteService async retrieve invite id string Promise lt Invite null gt return await this atomicPhase async m gt const inviteRepo InviteRepository m getCustomRepository this inviteRepository return await inviteRepo findOne where id invite id You can now override the original route that handles accepting invites Create the file src modules invite acceptInvite controller ts with the following content import AdminPostInvitesInviteAcceptReq from medusajs medusa import InviteService from invite service import MedusaError from medusa core utils import UserService from user services user service import validator from medusajs medusa dist utils validator export default async req res gt const validated await validator AdminPostInvitesInviteAcceptReq req body const inviteService InviteService req scope resolve InviteService resolutionKey const manager EntityManager req scope resolve manager await manager transaction async m gt retrieve invite let decoded try decoded inviteService withTransaction m verifyToken validated token catch err throw new MedusaError MedusaError Types INVALID DATA Token is not valid const invite await inviteService withTransaction m retrieve decoded invite id let store id invite invite store id null const user await inviteService withTransaction m accept validated token validated user if store id const userService UserService req scope resolve userService await userService withTransaction m addUserToStore user id store id res sendStatus await userService withTransaction m addUserToStore user id store id res sendStatus This uses the same implementation as the original accept invite endpoint However it retrieves the invite using the retrieve method you created earlier Then it retrieves the store id of the invite The accept method in inviteService creates a new user and returns it You then check if the store id was set on the invite and add the store id to the user using the userService addUserToStore method To make this function the handler of the Accept an Invite endpoint create the file src modules invite invite router ts with the following content import Router from medusa extender import acceptInvite from acceptInvite controller Router routes requiredAuth false path admin invites accept method post handlers acceptInvite export class AcceptInviteRouter The last step is to add this router to the invite module In src modules invite invite module ts import this class at the beginning of the function import AcceptInviteRouter from invite router Then add it to the imports array passed to the Module directive Module imports AcceptInviteRouter Test Accepting InvitesRestart your server Then send a request to the List all Invites endpoint and retrieve the token of the invite you want to accept After you retrieve the token send a request to the Accept an Invite endpoint You can then check if the new user shows up in the store it s associated with it Implementing Roles and PermissionsThis section covers how to implement user roles and permissions in a brief way You may choose to implement it differently based on your use case This entails creating two new entities Role and Permission A permission can be associated with multiple roles and a role can have multiple permissions Additionally a role is associated with a store and a user is associated with a role Then you ll create a guard middleware that you can add to any route you want to protect based on a certain permission You ll see an example of how to use the guard middleware ️ This section does not cover the endpoints necessary to add permissions and roles and associate them with users You ll need to implement it yourself Create the Role ModuleStart by creating the src modules role directory that holds all files related to the role module Then create the file src modules role role entity ts with the following content import BeforeInsert Column Entity Index JoinColumn JoinTable ManyToMany ManyToOne OneToMany from typeorm import BaseEntity from medusajs medusa import Entity as MedusaEntity from medusa extender import Permission from permission permission entity import Store from store entities store entity import User from user entities user entity import generateEntityId from medusajs medusa dist utils MedusaEntity Entity export class Role extends BaseEntity Column type varchar name string Index Column nullable true store id string ManyToMany gt Permission JoinTable name role permissions joinColumn name role id referencedColumnName id inverseJoinColumn name permission id referencedColumnName id permissions Permission OneToMany gt User user gt user teamRole JoinColumn name id referencedColumnName role id users User ManyToOne gt Store store gt store roles JoinColumn name store id store Store BeforeInsert private beforeInsert void this id generateEntityId this id role If you see errors about missing imports or methods you ll be resolving them as you proceed with the next steps This creates a Role entity that has the properties name and store id as well as the relations mentioned earlier You need to add these relations to the Store and User entities Go to src modules user entities user entity ts and add the following import at the beginning of the file import Role from role role entity Then add the following inside the User entity Index Column nullable true role id string ManyToOne gt Role role gt role users JoinColumn name role id teamRole Role Next go to src modules store entities store entity ts and add the following import at the beginning of the file import Role from role role entity Then add the following inside the Store entity OneToMany gt Role role gt role store JoinColumn name id referencedColumnName store id roles Role Then create the file src modules role role repository ts with the following content import EntityRepository Repository from typeorm import Repository as MedusaRepository from medusa extender import Role from role entity MedusaRepository EntityRepository Role export class RoleRepository extends Repository lt Role gt Next you need to create migrations one to create the role table and one to add the role id column to the user table Run the following command to create the role migration node modules bin medex g mi roleThen go to src modules role lt TIMESTAMP gt role migration ts and add the following import at the beginning of the file import TableForeignKey from typeorm Then replace the up and down methods with the following public async up queryRunner QueryRunner Promise lt void gt const query CREATE TABLE role id character varying NOT NULL name character varying NOT NULL store id character varying NOT NULL created at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now updated at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now await queryRunner query query await queryRunner createPrimaryKey role id await queryRunner createForeignKey role new TableForeignKey columnNames store id referencedColumnNames id referencedTableName store onDelete CASCADE onUpdate CASCADE public async down queryRunner QueryRunner Promise lt void gt await queryRunner dropTable role true Next run the following command node modules bin medex g mi userRunning this command can mess up the file src modules user user module ts as the files in the user module are based on an old structure that the Medusa Extender used Please check the file for any errors in the imports and resolve them If it adds an import for UserSubscriber you can safely remove it as well as remove it from the imports array passed to Module Go to src modules user lt TIMESTAMP gt user migration ts and add the following import at the beginning of the file import TableForeignKey from typeorm Then replace the up and down methods with the following content public async up queryRunner QueryRunner Promise lt void gt const query ALTER TABLE public user ADD COLUMN IF NOT EXISTS role id text await queryRunner query query await queryRunner createForeignKey user new TableForeignKey columnNames role id referencedColumnNames id referencedTableName role onDelete CASCADE onUpdate CASCADE public async down queryRunner QueryRunner Promise lt void gt const query ALTER TABLE public user DROP COLUMN role id await queryRunner query query Next create the file src modules role role module ts with the following content import Module from medusa extender import Role from role entity import RoleMigration from role migration import RoleRepository from role repository Module imports Role RoleRepository RoleMigration export class RoleModule Make sure to replace the migration with your own migration class name and file path Finally at the beginning of src main ts import the role module import RoleModule from modules role role module and add it in the array passed to the load function await new Medusa dirname expressInstance load RoleModule Create the Permission ModuleStart by creating the src modules permission folder that holds all files related to the permission module Then create the file src modules permission permission entity ts with the following content import BeforeInsert Column Entity JoinTable ManyToMany from typeorm import BaseEntity from medusajs medusa import DbAwareColumn from medusajs medusa dist utils db aware column import Entity as MedusaEntity from medusa extender import Role from role role entity import generateEntityId from medusajs medusa dist utils MedusaEntity Entity export class Permission extends BaseEntity Column type varchar name string DbAwareColumn type jsonb nullable true metadata Record lt string unknown gt ManyToMany gt Role JoinTable name role permissions joinColumn name permission id referencedColumnName id inverseJoinColumn name role id referencedColumnName id roles Role BeforeInsert private beforeInsert void this id generateEntityId this id perm This creates the entity Permission which has the attributes name and metadata You can use the metadata attribute which acts as an object with key value pairs to add whatever condition that these permissions entail For example you can add the name of paths that the role this permission is associated with can access Then create the file src modules permission permission repository ts with the following content import EntityRepository Repository from typeorm import Repository as MedusaRepository from medusa extender import Permission from permission entity MedusaRepository EntityRepository Permission export class PermissionRepository extends Repository lt Permission gt Next you need to create the migration for permission Run the following command to create the migration node modules bin medex g mi permissionThen open the file src modules permission lt TIMESTAMP gt permission migration ts and add the following import at the beginning of the file import TableForeignKey from typeorm and replace the up and down methods with the following public async up queryRunner QueryRunner Promise lt void gt let query CREATE TABLE permission id character varying NOT NULL name character varying NOT NULL metadata jsonb created at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now updated at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now await queryRunner query query await queryRunner createPrimaryKey permission id query CREATE TABLE role permissions role id character varying NOT NULL permission id character varying NOT NULL created at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now updated at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now await queryRunner query query await queryRunner createPrimaryKey role permissions role id permission id await queryRunner createForeignKey role permissions new TableForeignKey columnNames role id referencedColumnNames id referencedTableName role onDelete CASCADE onUpdate CASCADE await queryRunner createForeignKey role permissions new TableForeignKey columnNames permission id referencedColumnNames id referencedTableName permission onDelete CASCADE onUpdate CASCADE public async down queryRunner QueryRunner Promise lt void gt await queryRunner dropTable role permissions true await queryRunner dropTable permission true Notice that in this migration you also create the table role permissions which creates the many to many relation between the two entities The final step is to add the guard middleware that will handle checking whether the user can access an endpoint or not Create the file src modules permission permission guard ts with the following content import UserService from user services user service import from lodash export default permissions Record lt string unknown gt gt return async req res next gt const userService req scope resolve userService as UserService const loggedInUser await userService retrieve req user userId select id store id relations teamRole teamRole permissions const isAllowed permissions every permission gt loggedInUser teamRole permissions some userPermission gt isEqual userPermission metadata permission if isAllowed return next permission denied res sendStatus The guard accepts the parameter permissions which is an array of type any Then it returns a function that accepts the req res and next parameters as every middleware in Express The permissions parameter is an array of permissions that the logged in user must have before accessing a route So inside the returned middleware function you check that the logged in user has every item in permissions as part of their role You use the metadata field in the Permission entity to check for equality between the user s permissions and the required permissions for this route If the user has all permissions they are admitted to the route by calling next Otherwise the unauthorized status is returned Next create the file src modules permission permission module ts with the following content import Module from medusa extender import Permission from permission entity import PermissionMigration from permission migration import PermissionRepository from permission repository Module imports Permission PermissionRepository PermissionMigration export class PermissionModule Make sure to replace the migration with your own migration class name and file path Finally import this file at the beginning of src main ts import PermissionModule from modules permission permission module And add the class to the array passed to the load function await new Medusa dirname expressInstance load PermissionModule Run MigrationsRun the build command to transpile the TypeScript files to JavaScript files npm run buildIf you see an error when you run this command check the imports in src modules invite invite module ts This is because of how the Medusa Extender CLI works when you ran the migrate command earlier If you see an import for InviteSubscriber you can safely remove it as well as remove it from the imports array passed to Module Then use the migrate command provided by the Medusa Extender CLI to run those migrations node modules bin medex migrate runIf you get an error about duplicate migrations because of previous migrations go ahead and remove the old ones from the dist directory and try running the command again If you check your database after the migration is run successfully you can see that new tables role and permission have been added to the database and the user table has a new column role id Test Roles and PermissionsAs mentioned earlier in this section you ll need to either implement endpoints to add roles and permissions yourself or add them directly to the database if you want to test it out Then to use the permissions middleware you can pass it to the handlers array of any router For example here s a router that restricts access to the List Products endpoint import Router from medusa extender import listProductsHandler from medusajs medusa dist api routes admin products list products import permissionGuard from permission permission guard import wrapHandler from medusajs medusa dist api middlewares await middleware Router routes requiredAuth true path admin products method get handlers permissionGuard path admin products wrapHandler listProductsHandler export class ProductsRouter Notice that you pass the argument path admin products as the permission to check for If the user has permission that has metadata with the same value as the argument they ll be able to access the endpoint Otherwise they ll be unauthorized to access You can pass multiple permissions in the array Make sure to pass the router to the module it is associated with and restart the server before testing it out What s Next In the next tutorial in this series you ll learn how to make customization to endpoints and to the Medusa admin to make sure the super admin can manage the marketplace as a whole You can also check out the following resources for additional help while developing your marketplace with Medusa Learn how to deploy Medusa on HerokuLearn how to add Stripe as a payment provider Learn how to add a storefront either with Next js or Gatsby Should you have any issues or questions related to Medusa then feel free to reach out to the Medusa team via Discord |
2022-06-21 10:35:15 |
海外TECH |
DEV Community |
Eliminating Traditional Feature Release Anxieties |
https://dev.to/daveyhert/eliminating-traditional-feature-release-anxieties-3gil
|
Eliminating Traditional Feature Release AnxietiesAs developers we spend countless hours building new features and having them pass through rigorous QA tests However despite experience and all preparations made there s always that dreaded feeling you get in the pit of your stomach when you know it s time for deployment What if something goes wrong in production and your feature doesn t function as expected As software engineers we are constantly faced with a variety of challenges These challenges range from developing innovative features based on constantly changing requirements to deploying these features to production and releasing them to users with the hopes that they work as intended Anyone that has been actively involved in software development is familiar with the stress and anxiety that is caused by deployment and feature release There s always the constant worry over whether things will go smoothly as planned when these changes are pushed to users That s why the most important investment a team can make in a company is helping engineers overcome this constant fear of failure associated with feature releases The Anxiety and Pain of Traditional Big Bang Feature ReleasesIn the past deployments were done using what s known as a big bang approach where all features are released in one go This results in a single major release with lots of changes and feature releases bundled into it which is problematic in at least two ways Bundling up lots of changes and new features into one big bang release makes the release more complicated The complexity of such a release opens up a lot of possibilities for release failure since things could go wrong in a lot of ways As a result most engineers and everyone involved in the process in such organizations or companies don t like release day due to the risks and anxiety that come along with it Secondly another problem with this big bang release approach is that most organizations are typically structured to have a fixed release schedule that is infrequent such as one in every months or thereabouts This makes delivering changes fixes and new feature updates to customers slower which results in users of the service not being able to access new features or improvements quickly enough This could negatively impact the user experience of the service Overall traditional big bang feature releases are much slower and riskier because there is a lot more at stake with each deployment if things don t go as planned which causes greater anxiety and fear of failure for anyone involved in the process Separating Code Deployment from Feature Releases with Feature FlagsReleasing feature updates comes with many risks so it would be prudent to try to minimize these risks by separating deployments from feature releases This approach allows for a safer and more flexible release strategy as it is typically safer to make these release changes incrementally This incremental strategy means that the risks associated with traditional deployments and feature releases are minimal and better managed Also priority features can get delivered as soon as they become available for user consumption However the question you might have if you are new to the world of modern DevOps is what is the difference between deployment and feature release as these terms are often used interchangeably Deployment typically involves moving software changes from one controlled environment to another usually from a development environment to a live or production environment The fact that these changes are in the user s environment does not necessarily mean they are available to the user Feature releases describe the rollout of features and updates to users In other words a release gives users access to these new changes and features by making them available to the users One of the most effective and easiest ways to separate your deployments from your feature releases is by using feature flags Feature flags determine whether a piece of code or functionality wrapped within it is active or not Like conditional if then statements you can put your updates and features behind a feature flag that hides them after deployment until it s ready to be released This means you can continually ship value while avoiding unnecessary risks and anxieties The Benefits of Using Feature FlagsWhenever you are releasing new features and updating your product it is easier to have a continuous delivery pipeline which allows you to push these updates incrementally as quickly as possible while also safeguarding your customers in the event that any unexpected issue arises You should be able to roll these updates back out of production as quickly as possible to avoid negatively impacting users With feature flags it is possible to create a continuous delivery pipeline that allows for both feature addition and risk reduction Feature flags allow deployments of features to be decoupled from their releases As a result you can easily roll out new features without releasing them immediately to the public and easily roll back these features if the need arises Fortunately there are several feature flag management services such as ConfigCat that offer feature flags as a service A good feature flag configuration management service comes equipped with key feature flag functionalities and tools to help you and your team leverage the power of feature flags such as User Segmentation Feature flags can be used to segment your users into subgroups and to test and release features to them based on attributes assigned to different user segments such as location geography gender etc A B Testing By using Feature Flags you or your Product Marketing teams can test alternative ideas on your users before proceeding to final implementation based on the feedback from these tests By doing this you are able to offer the most satisfying customer experience by pushing only the most performant ideas to your users Progressive Delivery Feature flags enable you to implement your feature releases gradually to help minimize the negative effects of continuous product iteration The advantage of releasing in smaller chunks regularly is that it s much easier to observe the effect of each change and if anything goes wrong quickly roll back the changes Kill Switch for Easy Rollback In the event that your feature release doesn t work correctly in production the change can be rolled back immediately from production via a kill switch option Intuitive UI Dashboard Remotely manage all of your feature flags from an intuitive dashboard without having to redeploy code when changes need to be made to the flags configuration SDK Integration Simple SDK for easy integrations with various apps and platforms SummaryIn today s rapidly changing world if you don t improve you get worse The success of a development team ultimately depends on how frequent and successful their releases are However traditional deployment comes with a lot of release anxiety from the fact that release day is made into a major event Feature flags play a prominent role in making releases as uneventful as possible by providing key functionalities that give you fine tune control over the exposure of your feature releases By using feature flags you can decouple your feature releases from deployment to create a continuous delivery pipeline that enables you to continuously ship value without risking unnecessary exposure For more information on feature flags and how they help ease deployment related anxiety follow ConfigCat on Facebook Twitter and LinkedIn |
2022-06-21 10:14:16 |
海外TECH |
DEV Community |
Introduction to Data Structures and Algorithms |
https://dev.to/crunchyanomaly/introduction-to-data-structures-and-algorithms-34lb
|
Introduction to Data Structures and Algorithms Data StructureA data structure can be defined as a specialized method of organizing and storing data so that execution of operations on data can be more efficient Data can be organized in many ways such as lists or dictionaries in Python Data structures can be of two types primitive and non primitivePrimitive data structuresPrimitive data structures can simply be defined as data types Data types are elementary They cannot be further subdivided They include int char double Non Primitive data structuresNon primitive data structure is a data structure which can be used to store data of more than one type Non primitive data structure can be subdivided into two categories Linear data structure Non linear data structure Linear data structureThe elements of a linear data structure are stored in a sequential manner Types of linear data structure include array list stack and queues ArrayAn array is a data structure that stores elements of the same data type in contiguous and adjacent memory locations An item stored in an array is called an element and an index indicates the position of the element within in an array The index of an array starts from therefore if an array has elements the index will start from to ListA list is a data structure which stores elements in an ordered manner It allows repetition and therefore a single piece of data can occur more than once in a list StackA stack is data structure that holds an ordered linear sequence of items It uses the Last In First Out LIFO structure to access the elements in the stack A real life example is that of a stack of plates You can only access the plates from the top of the stack and can only add a plate to the top of the stack QueueA queue is similar to a stack but it is open at both its ends It uses the First In First Out technique to access the elements Data insertion occurs at the rear end or the tail of the queue whole deletion at the front end or the head of the queue Non Linear Data StructureThe elements are not arranged sequentially rather in a hierarchical manner Elements cannot be traversed in a single run Examples include trees and graphsTrees A tree is a hierarchical data structure that consists of nodes connected by edges A node is a structure which contains data and pointers to its child nodes An edge is used to connect two nodes Every node except the root node is connected by exactly one incoming edge from another node GraphsA graph is a data structure made up of nodes or vertices and edges AlgorithmsAn algorithm is a set of well defined instructions to solve a particular problem For example an algorithm to add two numbers can be as follows Step Start Step Declare variables num num and sum Step Read values num and num Step Add num and num Step Assign the result to sum sum ←num num Step Display sum Step StopCharacteristics of an algorithmFiniteness Must terminate after a finite number of steps Unambiguous Should be clear and unambiguous Independent Should be independent of any programming codeInput It should have or more well defined inputs Output It should have or more well defined outputs Effectiveness It must be possible to perform each step of the algorithm correctly and in a finite amount of time Effectiveness is determined by Space complexity The memory space needed by a specific algorithm to be executed Time complexity The time required by a program to be completed Thanks for reading |
2022-06-21 10:05:58 |
海外TECH |
WIRED |
How Lori Garver Launched NASA’s Commercial Space Partnerships |
https://www.wired.com/story/how-lori-garver-launched-nasas-commercial-space-partnerships/
|
How Lori Garver Launched NASA s Commercial Space PartnershipsWIRED spoke with the agency s former deputy administrator about how she architected a major shift to working with the fledging private space industry |
2022-06-21 11:00:00 |
医療系 |
医療介護 CBnews |
向精神薬の原薬模造品販売で行政処分、東京都-ライフ・エヌ・ピーに10日間の業務停止命令 |
https://www.cbnews.jp/news/entry/20220621193814
|
卸売販売業 |
2022-06-21 19:50:00 |
医療系 |
医療介護 CBnews |
2月時点の分業率76.1%、コロナで低下-年度ベースでは初の低下 |
https://www.cbnews.jp/news/entry/20220621183455
|
医薬分業 |
2022-06-21 19:20:00 |
海外ニュース |
Japan Times latest articles |
Japan to face United States in September friendly in Europe |
https://www.japantimes.co.jp/sports/2022/06/21/soccer/japan-united-states-friendly/
|
francisco |
2022-06-21 19:04:28 |
ニュース |
BBC News - Home |
Rail strike: Commuters must stay the course, says Boris Johnson |
https://www.bbc.co.uk/news/uk-61879766?at_medium=RSS&at_campaign=KARANGA
|
wales |
2022-06-21 10:39:40 |
ニュース |
BBC News - Home |
France elections: Macron rejects prime minister's offer to resign |
https://www.bbc.co.uk/news/world-europe-61874751?at_medium=RSS&at_campaign=KARANGA
|
coalition |
2022-06-21 10:38:57 |
ニュース |
BBC News - Home |
Food bills are set to soar by £380 this year |
https://www.bbc.co.uk/news/business-61878062?at_medium=RSS&at_campaign=KARANGA
|
experts |
2022-06-21 10:13:13 |
ニュース |
BBC News - Home |
Ben Stiller: Actor speaks about 'distressing' scenes on visit to Ukraine |
https://www.bbc.co.uk/news/entertainment-arts-61879539?at_medium=RSS&at_campaign=KARANGA
|
ambassador |
2022-06-21 10:40:11 |
ニュース |
BBC News - Home |
Chelsea Bridge: Man who died after Taser was holding firelighter |
https://www.bbc.co.uk/news/uk-england-london-61794542?at_medium=RSS&at_campaign=KARANGA
|
adeyemi |
2022-06-21 10:05:09 |
ニュース |
BBC News - Home |
Beyoncé, Drake and the revival of 90s house music |
https://www.bbc.co.uk/news/entertainment-arts-61878412?at_medium=RSS&at_campaign=KARANGA
|
music |
2022-06-21 10:19:54 |
ニュース |
BBC News - Home |
'We need to stand up to this government' - rail worker |
https://www.bbc.co.uk/news/uk-61880393?at_medium=RSS&at_campaign=KARANGA
|
family |
2022-06-21 10:04:52 |
ニュース |
BBC News - Home |
Train strike: How much are rail workers paid? |
https://www.bbc.co.uk/news/61840077?at_medium=RSS&at_campaign=KARANGA
|
workers |
2022-06-21 10:19:39 |
ニュース |
BBC News - Home |
London Underground strike: Fourth 24-hour walkout of 2022 begins |
https://www.bbc.co.uk/news/uk-england-london-61873467?at_medium=RSS&at_campaign=KARANGA
|
action |
2022-06-21 10:46:16 |
北海道 |
北海道新聞 |
帯広・大空町のデマンド交通の仕組みは? AIが最短ルート計算 |
https://www.hokkaido-np.co.jp/article/696373/
|
十勝バス |
2022-06-21 19:53:00 |
北海道 |
北海道新聞 |
知床の観光船事故 発生2カ月を前に道警が集中捜索 |
https://www.hokkaido-np.co.jp/article/696372/
|
知床半島 |
2022-06-21 19:44:00 |
北海道 |
北海道新聞 |
ニセコ地域、宿泊予約好調 前年の3倍増も 新たな客層開拓に注力 |
https://www.hokkaido-np.co.jp/article/696350/
|
開拓 |
2022-06-21 19:44:40 |
北海道 |
北海道新聞 |
参院選22日公示 道選挙区から12人出馬へ |
https://www.hokkaido-np.co.jp/article/696335/
|
選挙区 |
2022-06-21 19:42:29 |
北海道 |
北海道新聞 |
知床沈没船事故の乗客家族支援へ募金箱設置 ススキノ飲食店50店 斜里町出身の店主発案 |
https://www.hokkaido-np.co.jp/article/696364/
|
知床半島 |
2022-06-21 19:39:00 |
北海道 |
北海道新聞 |
香港の水上レストラン、えい航中に転覆 南シナ海の西沙諸島近く |
https://www.hokkaido-np.co.jp/article/696325/
|
南シナ海 |
2022-06-21 19:24:23 |
北海道 |
北海道新聞 |
ダムカレー、活気の元に 旧南大夕張駅前に7月1日開店 夕張の岩野さん、飲食店求める声聞き決意 |
https://www.hokkaido-np.co.jp/article/696341/
|
南大夕張駅 |
2022-06-21 19:40:32 |
北海道 |
北海道新聞 |
音更の笹井ホテル 牛肉の産地誤表示 豪州産を「北海道産牛」 |
https://www.hokkaido-np.co.jp/article/696359/
|
北海道産 |
2022-06-21 19:36:24 |
北海道 |
北海道新聞 |
医療的ケア児への支援拡充 道が30日にセンター開設へ |
https://www.hokkaido-np.co.jp/article/696362/
|
人工呼吸器 |
2022-06-21 19:35:00 |
北海道 |
北海道新聞 |
Bリーグ、予定試合の1割が消滅 21~22年シーズン |
https://www.hokkaido-np.co.jp/article/696354/
|
試合 |
2022-06-21 19:36:03 |
北海道 |
北海道新聞 |
洞爺湖アニメフェス開催へ 25、26日 規模縮小し3年ぶり |
https://www.hokkaido-np.co.jp/article/696360/
|
toyak |
2022-06-21 19:33:00 |
北海道 |
北海道新聞 |
大手企業の賞与、最高の13%増 今夏、業績回復を反映 |
https://www.hokkaido-np.co.jp/article/696358/
|
大手企業 |
2022-06-21 19:33:00 |
北海道 |
北海道新聞 |
新生厚真神社、人が集う場に 胆振東部地震で被害、復旧費の7割が寄付 御朱印刷新、イベントも 宮司「魅力高め感謝示す」 |
https://www.hokkaido-np.co.jp/article/696356/
|
東部地震 |
2022-06-21 19:28:00 |
北海道 |
北海道新聞 |
金岩武吉道議が死去 日高管内選出で5期目 |
https://www.hokkaido-np.co.jp/article/696355/
|
日高管内 |
2022-06-21 19:28:00 |
北海道 |
北海道新聞 |
中国軍艦、尖閣諸島に接近 日本「関心」を伝達、けん制 |
https://www.hokkaido-np.co.jp/article/696352/
|
中国海軍 |
2022-06-21 19:22:00 |
北海道 |
北海道新聞 |
中国、ガス田開発正当化 「日本はあれこれ言うな」 |
https://www.hokkaido-np.co.jp/article/696351/
|
記者会見 |
2022-06-21 19:21:00 |
北海道 |
北海道新聞 |
みずほFG、顧問に75歳定年制 23年7月から導入へ |
https://www.hokkaido-np.co.jp/article/696345/
|
顧問 |
2022-06-21 19:17:00 |
北海道 |
北海道新聞 |
釧路大漁どんぱく 3年ぶり開催へ |
https://www.hokkaido-np.co.jp/article/696342/
|
開催 |
2022-06-21 19:10:00 |
北海道 |
北海道新聞 |
常呂産ホタテ、生のまま首都圏へ JALグループが漁協と連携事業 |
https://www.hokkaido-np.co.jp/article/696339/
|
jalux |
2022-06-21 19:09:15 |
北海道 |
北海道新聞 |
整骨院開業「マチに恩返し」 遠軽高野球部OB西田さん 23日、町大通南2に「ナンバー」 治療に加え運動指導も |
https://www.hokkaido-np.co.jp/article/696338/
|
柔道整復師 |
2022-06-21 19:08:00 |
IT |
週刊アスキー |
横浜市旭区に在住の人は急げ! 横浜FC、ウォーミングアップ見学やピッチユニフォームバナーを体験できる「あさひ区民DAY」を実施 |
https://weekly.ascii.jp/elem/000/004/095/4095411/
|
明治安田生命 |
2022-06-21 19:30:00 |
IT |
週刊アスキー |
PC『ガンダムトライヴ』で「THE TRIBE BATTLE~Seven years of memories~」が開催! |
https://weekly.ascii.jp/elem/000/004/095/4095424/
|
ttlesevenyearsofmemories |
2022-06-21 19:30:00 |
IT |
週刊アスキー |
『フォールガイズ』が本日より基本プレイ無料化!PS5/PS4/Switch/XSX/Xbox One/Epic Games Storeでプレイ可能に |
https://weekly.ascii.jp/elem/000/004/095/4095420/
|
『フォールガイズ』が本日より基本プレイ無料化PSPSSwitchXSXXboxOneEpicGamesStoreでプレイ可能に年月日、大規模バトルロイヤルゲーム『FallGuys』の基本プレイ無料化が実施された。 |
2022-06-21 19:10:00 |
マーケティング |
AdverTimes |
5月のコンビニ3.2%増 客数が4カ月ぶりプラス |
https://www.advertimes.com/20220621/article387489/
|
需要 |
2022-06-21 10:07:48 |
コメント
コメントを投稿