feat(medusa): Convert OauthService to TypeScript (#1983)
This commit is contained in:
5
.changeset/sixty-boats-flow.md
Normal file
5
.changeset/sixty-boats-flow.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@medusajs/medusa": patch
|
||||
---
|
||||
|
||||
Convert OauthService to TypeScript
|
||||
@@ -1,121 +0,0 @@
|
||||
import { MedusaError } from "medusa-core-utils"
|
||||
import { OauthService } from "medusa-interfaces"
|
||||
|
||||
class Oauth extends OauthService {
|
||||
static Events = {
|
||||
TOKEN_GENERATED: "oauth.token_generated",
|
||||
TOKEN_REFRESHED: "oauth.token_refreshed",
|
||||
}
|
||||
|
||||
constructor(cradle) {
|
||||
super()
|
||||
const manager = cradle.manager
|
||||
|
||||
this.manager = manager
|
||||
this.container_ = cradle
|
||||
this.oauthRepository_ = cradle.oauthRepository
|
||||
this.eventBus_ = cradle.eventBusService
|
||||
}
|
||||
|
||||
retrieveByName(appName) {
|
||||
const repo = this.manager.getCustomRepository(this.oauthRepository_)
|
||||
return repo.findOne({
|
||||
application_name: appName,
|
||||
})
|
||||
}
|
||||
|
||||
list(selector) {
|
||||
const repo = this.manager.getCustomRepository(this.oauthRepository_)
|
||||
return repo.find(selector)
|
||||
}
|
||||
|
||||
async create(data) {
|
||||
const repo = this.manager.getCustomRepository(this.oauthRepository_)
|
||||
|
||||
const application = repo.create({
|
||||
display_name: data.display_name,
|
||||
application_name: data.application_name,
|
||||
install_url: data.install_url,
|
||||
uninstall_url: data.uninstall_url,
|
||||
})
|
||||
|
||||
return repo.save(application)
|
||||
}
|
||||
|
||||
async update(id, update) {
|
||||
const repo = this.manager.getCustomRepository(this.oauthRepository_)
|
||||
const oauth = await repo.findOne({ where: { id } })
|
||||
|
||||
if ("data" in update) {
|
||||
oauth.data = update.data
|
||||
}
|
||||
|
||||
return repo.save(oauth)
|
||||
}
|
||||
|
||||
async registerOauthApp(appDetails) {
|
||||
const { application_name } = appDetails
|
||||
const existing = await this.retrieveByName(application_name)
|
||||
if (existing) {
|
||||
return
|
||||
}
|
||||
|
||||
return this.create(appDetails)
|
||||
}
|
||||
|
||||
async generateToken(appName, code, state) {
|
||||
const app = await this.retrieveByName(appName)
|
||||
const service = this.container_[`${app.application_name}Oauth`]
|
||||
if (!service) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`An OAuth handler for ${app.display_name} could not be found make sure the plugin is installed`
|
||||
)
|
||||
}
|
||||
|
||||
if (!app.state === state) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
`${app.display_name} could not match state`
|
||||
)
|
||||
}
|
||||
|
||||
const authData = await service.generateToken(code)
|
||||
|
||||
return this.update(app.id, {
|
||||
data: authData,
|
||||
}).then((result) => {
|
||||
this.eventBus_.emit(
|
||||
`${Oauth.Events.TOKEN_GENERATED}.${appName}`,
|
||||
authData
|
||||
)
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
async refreshToken(appName) {
|
||||
const app = await this.retrieveByName(appName)
|
||||
const refreshToken = app.data.refresh_token
|
||||
const service = this.container_[`${app.application_name}Oauth`]
|
||||
if (!service) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`An OAuth handler for ${app.display_name} could not be found make sure the plugin is installed`
|
||||
)
|
||||
}
|
||||
|
||||
const authData = await service.refreshToken(refreshToken)
|
||||
|
||||
return this.update(app.id, {
|
||||
data: authData,
|
||||
}).then((result) => {
|
||||
this.eventBus_.emit(
|
||||
`${Oauth.Events.TOKEN_REFRESHED}.${appName}`,
|
||||
authData
|
||||
)
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default Oauth
|
||||
178
packages/medusa/src/services/oauth.ts
Normal file
178
packages/medusa/src/services/oauth.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
import { MedusaError } from "medusa-core-utils"
|
||||
import { EntityManager } from "typeorm"
|
||||
import { TransactionBaseService } from "../interfaces"
|
||||
import { Oauth as OAuthModel } from "../models"
|
||||
import { OauthRepository } from "../repositories/oauth"
|
||||
import { Selector } from "../types/common"
|
||||
import { MedusaContainer } from "../types/global"
|
||||
import { CreateOauthInput, UpdateOauthInput } from "../types/oauth"
|
||||
import { buildQuery } from "../utils"
|
||||
import EventBusService from "./event-bus"
|
||||
|
||||
type InjectedDependencies = MedusaContainer & {
|
||||
manager: EntityManager
|
||||
eventBusService: EventBusService
|
||||
oauthRepository: typeof OauthRepository
|
||||
}
|
||||
|
||||
class Oauth extends TransactionBaseService<Oauth> {
|
||||
protected manager_: EntityManager
|
||||
protected transactionManager_: EntityManager | undefined
|
||||
static Events = {
|
||||
TOKEN_GENERATED: "oauth.token_generated",
|
||||
TOKEN_REFRESHED: "oauth.token_refreshed",
|
||||
}
|
||||
|
||||
protected manager: EntityManager
|
||||
protected container_: InjectedDependencies
|
||||
protected oauthRepository_: typeof OauthRepository
|
||||
protected eventBus_: EventBusService
|
||||
|
||||
constructor(cradle: InjectedDependencies) {
|
||||
super(cradle)
|
||||
const manager = cradle.manager
|
||||
|
||||
this.manager = manager
|
||||
this.container_ = cradle
|
||||
this.oauthRepository_ = cradle.oauthRepository
|
||||
this.eventBus_ = cradle.eventBusService
|
||||
}
|
||||
|
||||
async retrieveByName(appName: string): Promise<OAuthModel> {
|
||||
const repo = this.manager.getCustomRepository(this.oauthRepository_)
|
||||
const oauth = await repo.findOne({
|
||||
application_name: appName,
|
||||
})
|
||||
|
||||
if (!oauth) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`Oauth application ${appName} not found`
|
||||
)
|
||||
}
|
||||
|
||||
return oauth
|
||||
}
|
||||
|
||||
async retrieve(oauthId: string): Promise<OAuthModel> {
|
||||
const repo = this.manager.getCustomRepository(this.oauthRepository_)
|
||||
const oauth = await repo.findOne({
|
||||
id: oauthId,
|
||||
})
|
||||
|
||||
if (!oauth) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`Oauth application with id ${oauthId} not found`
|
||||
)
|
||||
}
|
||||
|
||||
return oauth
|
||||
}
|
||||
|
||||
async list(selector: Selector<OAuthModel>): Promise<OAuthModel[]> {
|
||||
const repo = this.manager.getCustomRepository(this.oauthRepository_)
|
||||
|
||||
const query = buildQuery(selector, {})
|
||||
|
||||
return await repo.find(query)
|
||||
}
|
||||
|
||||
async create(data: CreateOauthInput): Promise<OAuthModel> {
|
||||
return await this.atomicPhase_(async (manager) => {
|
||||
const repo = manager.getCustomRepository(this.oauthRepository_)
|
||||
|
||||
const application = repo.create({
|
||||
display_name: data.display_name,
|
||||
application_name: data.application_name,
|
||||
install_url: data.install_url,
|
||||
uninstall_url: data.uninstall_url,
|
||||
})
|
||||
|
||||
return await repo.save(application)
|
||||
})
|
||||
}
|
||||
|
||||
async update(id: string, update: UpdateOauthInput): Promise<OAuthModel> {
|
||||
return await this.atomicPhase_(async (manager) => {
|
||||
const repo = manager.getCustomRepository(this.oauthRepository_)
|
||||
const oauth = await this.retrieve(id)
|
||||
|
||||
if ("data" in update) {
|
||||
oauth.data = update.data
|
||||
}
|
||||
|
||||
return await repo.save(oauth)
|
||||
})
|
||||
}
|
||||
|
||||
async registerOauthApp(appDetails: CreateOauthInput): Promise<OAuthModel> {
|
||||
const { application_name } = appDetails
|
||||
const existing = await this.retrieveByName(application_name)
|
||||
if (existing) {
|
||||
return existing
|
||||
}
|
||||
|
||||
return await this.create(appDetails)
|
||||
}
|
||||
|
||||
async generateToken(
|
||||
appName: string,
|
||||
code: string,
|
||||
state: string
|
||||
): Promise<OAuthModel> {
|
||||
const app = await this.retrieveByName(appName)
|
||||
const service = this.container_[`${app.application_name}Oauth`]
|
||||
if (!service) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`An OAuth handler for ${app.display_name} could not be found make sure the plugin is installed`
|
||||
)
|
||||
}
|
||||
|
||||
if (!(app.data.state === state)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
`${app.display_name} could not match state`
|
||||
)
|
||||
}
|
||||
|
||||
const authData = await service.generateToken(code)
|
||||
|
||||
return await this.update(app.id, {
|
||||
data: authData,
|
||||
}).then(async (result) => {
|
||||
await this.eventBus_.emit(
|
||||
`${Oauth.Events.TOKEN_GENERATED}.${appName}`,
|
||||
authData
|
||||
)
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
async refreshToken(appName: string): Promise<OAuthModel> {
|
||||
const app = await this.retrieveByName(appName)
|
||||
const refreshToken = app.data.refresh_token
|
||||
const service = this.container_[`${app.application_name}Oauth`]
|
||||
if (!service) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`An OAuth handler for ${app.display_name} could not be found make sure the plugin is installed`
|
||||
)
|
||||
}
|
||||
|
||||
const authData = await service.refreshToken(refreshToken)
|
||||
|
||||
return await this.update(app.id, {
|
||||
data: authData,
|
||||
}).then(async (result) => {
|
||||
await this.eventBus_.emit(
|
||||
`${Oauth.Events.TOKEN_REFRESHED}.${appName}`,
|
||||
authData
|
||||
)
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default Oauth
|
||||
10
packages/medusa/src/types/oauth.ts
Normal file
10
packages/medusa/src/types/oauth.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export type CreateOauthInput = {
|
||||
display_name: string
|
||||
application_name: string
|
||||
install_url?: string
|
||||
uninstall_url?: string
|
||||
}
|
||||
|
||||
export type UpdateOauthInput = {
|
||||
data: Record<string, unknown>
|
||||
}
|
||||
Reference in New Issue
Block a user