feat: newsletter subscribe (#968)

* feat: subscribe newsletter

Signed-off-by: Innei <tukon479@gmail.com>

* feat(subscribe): send email

Signed-off-by: Innei <tukon479@gmail.com>

* fix(template): email template override

Signed-off-by: Innei <tukon479@gmail.com>

* fix: newsletter template props

Signed-off-by: Innei <tukon479@gmail.com>

* fix: get master inside

Signed-off-by: Innei <tukon479@gmail.com>

* feat: add sort

Signed-off-by: Innei <tukon479@gmail.com>

* feat(api-client): add subscribe controller

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
2023-02-13 15:15:13 +08:00
committed by GitHub
parent 85de275b4e
commit c8667ec5e2
22 changed files with 567 additions and 71 deletions

View File

@@ -0,0 +1,21 @@
import camelcaseKeys from 'camelcase-keys'
import { mockRequestInstance } from '~/__tests__/helpers/instance'
import { mockResponse } from '~/__tests__/helpers/response'
import { SubscribeController } from '~/controllers'
describe('test topic client', () => {
const client = mockRequestInstance(SubscribeController)
test('GET /subscribe', async () => {
const mocked = mockResponse('/subscribe', {}, 'post')
const data = await client.subscribe.subscribe('foo@example.com', ['post_c'])
expect(data).toEqual(camelcaseKeys(mocked))
})
test('GET /subscribe/unsubscribe', async () => {
const mocked = mockResponse('/subscribe/unsubscribe', 'success')
const data = await client.subscribe.unsubscribe('foo@example.com', 'token')
expect(data).toEqual(mocked)
})
})

View File

@@ -15,6 +15,7 @@ import { SayController } from './say'
import { SearchController } from './search'
import { ServerlessController } from './severless'
import { SnippetController } from './snippet'
import { SubscribeController } from './subscribe'
import { TopicController } from './topic'
import { UserController } from './user'
@@ -33,6 +34,7 @@ export const allControllers = [
SearchController,
SnippetController,
ServerlessController,
SubscribeController,
UserController,
]
@@ -51,6 +53,7 @@ export const allContollerNames = [
'search',
'snippet',
'serverless',
'subscribe',
'user',
// alias,
@@ -73,6 +76,7 @@ export {
SearchController,
SnippetController,
ServerlessController,
SubscribeController,
UserController,
TopicController,

View File

@@ -0,0 +1,47 @@
import { IRequestAdapter } from '~/interfaces/adapter'
import { IController } from '~/interfaces/controller'
import { IRequestHandler } from '~/interfaces/request'
import { SubscribeType } from '~/models/subscribe'
import { autoBind } from '~/utils/auto-bind'
import { HTTPClient } from '../core'
declare module '../core/client' {
interface HTTPClient<
T extends IRequestAdapter = IRequestAdapter,
ResponseWrapper = unknown,
> {
subscribe: SubscribeController<ResponseWrapper>
}
}
export class SubscribeController<ResponseWrapper> implements IController {
base = 'subscribe'
name = 'subscribe'
constructor(protected client: HTTPClient) {
autoBind(this)
}
public get proxy(): IRequestHandler<ResponseWrapper> {
return this.client.proxy(this.base)
}
subscribe(email: string, types: SubscribeType[]) {
return this.proxy.post<never>({
params: {
email,
types,
},
})
}
unsubscribe(email: string, cancelToken: string) {
return this.proxy.unsubscribe.get<string>({
params: {
email,
cancelToken,
},
})
}
}

View File

@@ -0,0 +1,5 @@
import { SubscribeTypeToBitMap } from '@core/modules/subscribe/subscribe.constant'
export * from '@core/modules/subscribe/subscribe.constant'
export type SubscribeType = keyof typeof SubscribeTypeToBitMap

View File

@@ -21,7 +21,10 @@
"paths": {
"~/*": [
"*"
]
],
"@core/*": [
"../../src/*"
],
}
},
"exclude": [