Skip to content

Commit fa17072

Browse files
committed
[migrate] upgrade Source Code & Test Case to latest Upstream Scaffold
1 parent 8a871c9 commit fa17072

File tree

22 files changed

+723
-63
lines changed

22 files changed

+723
-63
lines changed

.github/workflows/deploy-production.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ jobs:
5959

6060
- name: Run Image
6161
uses: appleboy/ssh-action@v1
62+
if: ${{ env.HOST }}
6263
with:
6364
host: ${{ secrets.HOST }}
6465
username: ${{ secrets.USER }}

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
node_modules/
22
package-lock.json
3+
yarn.lock
4+
test/client.ts
35
dist/
46
type/*.d.ts
5-
.env
7+
.env*
8+
!.env.example
69
.data/
710
.vscode/settings.json

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@open-source-bazaar/open-library-service",
3-
"version": "0.7.0",
3+
"version": "1.0.0",
44
"license": "LGPL-3.0",
55
"author": "[email protected]",
66
"description": "RESTful API service scaffold based on Node.js & TypeScript",

source/controller/ActivityLog.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { Get, JsonController, Param, QueryParams } from 'routing-controllers';
2+
import { ResponseSchema } from 'routing-controllers-openapi';
3+
import { FindOptionsWhere } from 'typeorm';
4+
5+
import {
6+
ActivityLog,
7+
ActivityLogFilter,
8+
ActivityLogListChunk,
9+
BaseFilter,
10+
dataSource,
11+
LogableTable,
12+
Operation,
13+
User,
14+
UserRank,
15+
UserRankListChunk
16+
} from '../model';
17+
18+
const store = dataSource.getRepository(ActivityLog),
19+
userStore = dataSource.getRepository(User),
20+
userRankStore = dataSource.getRepository(UserRank);
21+
22+
@JsonController('/activity-log')
23+
export class ActivityLogController {
24+
static logCreate(
25+
createdBy: User,
26+
tableName: ActivityLog['tableName'],
27+
recordId: number
28+
) {
29+
const operation = Operation.Create;
30+
31+
return store.save({ createdBy, operation, tableName, recordId });
32+
}
33+
34+
static logUpdate(
35+
createdBy: User,
36+
tableName: ActivityLog['tableName'],
37+
recordId: number
38+
) {
39+
const operation = Operation.Update;
40+
41+
return store.save({ createdBy, operation, tableName, recordId });
42+
}
43+
44+
static logDelete(
45+
createdBy: User,
46+
tableName: ActivityLog['tableName'],
47+
recordId: number
48+
) {
49+
const operation = Operation.Delete;
50+
51+
return store.save({ createdBy, operation, tableName, recordId });
52+
}
53+
54+
@Get('/user-rank')
55+
@ResponseSchema(UserRankListChunk)
56+
async getUserRankList(@QueryParams() { pageSize, pageIndex }: BaseFilter) {
57+
const skip = pageSize * (pageIndex - 1);
58+
59+
const [list, count] = await userRankStore.findAndCount({
60+
order: { score: 'DESC' },
61+
skip,
62+
take: pageSize
63+
});
64+
for (let i = 0, item: UserRank; (item = list[i]); i++) {
65+
item.rank = skip + i + 1;
66+
item.user = await userStore.findOneBy({ id: item.userId });
67+
}
68+
return { list, count };
69+
}
70+
71+
@Get('/user/:id')
72+
@ResponseSchema(ActivityLogListChunk)
73+
getUserList(
74+
@Param('id') id: number,
75+
@QueryParams() { operation, pageSize, pageIndex }: ActivityLogFilter
76+
) {
77+
return this.queryList(
78+
{ operation, createdBy: { id } },
79+
{ pageSize, pageIndex }
80+
);
81+
}
82+
83+
@Get('/:table/:id')
84+
@ResponseSchema(ActivityLogListChunk)
85+
getList(
86+
@Param('table') tableName: keyof typeof LogableTable,
87+
@Param('id') recordId: number,
88+
@QueryParams() { operation, pageSize, pageIndex }: ActivityLogFilter
89+
) {
90+
return this.queryList(
91+
{ operation, tableName, recordId },
92+
{ pageSize, pageIndex }
93+
);
94+
}
95+
96+
async queryList(
97+
where: FindOptionsWhere<ActivityLog>,
98+
{ pageSize, pageIndex }: BaseFilter
99+
) {
100+
const [list, count] = await store.findAndCount({
101+
where,
102+
relations: ['createdBy'],
103+
skip: pageSize * (pageIndex - 1),
104+
take: pageSize
105+
});
106+
107+
for (const activity of list)
108+
activity.record = await dataSource
109+
.getRepository<ActivityLog['record']>(activity.tableName)
110+
.findOneBy({ id: activity.recordId });
111+
112+
return { list, count };
113+
}
114+
}

source/controller/Base.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { marked } from 'marked';
2+
import { Controller, Get, HeaderParam, HttpCode } from 'routing-controllers';
3+
4+
import { isProduct } from '../utility';
5+
6+
@Controller()
7+
export class BaseController {
8+
static entryOf(host: string) {
9+
host = 'http://' + host;
10+
11+
return `
12+
- HTTP served at ${host}
13+
- Swagger API served at ${host}/docs/
14+
- Swagger API exposed at ${host}/docs/spec
15+
${isProduct ? '' : `- Mock API served at ${host}/mock/`}
16+
`;
17+
}
18+
19+
@Get('/_health')
20+
@HttpCode(200)
21+
getHealthStatus() {
22+
return '';
23+
}
24+
25+
@Get()
26+
getIndex(@HeaderParam('host') host: string) {
27+
return marked(BaseController.entryOf(host));
28+
}
29+
}

source/controller/File.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { DeleteObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';
2+
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
3+
import {
4+
Authorized,
5+
Controller,
6+
CurrentUser,
7+
Delete,
8+
HttpCode,
9+
OnUndefined,
10+
Param,
11+
Post
12+
} from 'routing-controllers';
13+
import { ResponseSchema } from 'routing-controllers-openapi';
14+
15+
import { SignedLink, User } from '../model';
16+
import { AWS_S3_BUCKET, AWS_S3_PUBLIC_HOST, s3Client } from '../utility';
17+
18+
@Controller('/file')
19+
export class FileController {
20+
@Post('/signed-link/:path(.+)')
21+
@Authorized()
22+
@HttpCode(201)
23+
@ResponseSchema(SignedLink)
24+
async createSignedLink(
25+
@CurrentUser() { id }: User,
26+
@Param('path') path: string
27+
) {
28+
const Key = `user/${id}/${path}`;
29+
30+
const command = new PutObjectCommand({ Bucket: AWS_S3_BUCKET, Key });
31+
32+
const putLink = await getSignedUrl(s3Client, command);
33+
34+
return { putLink, getLink: `${AWS_S3_PUBLIC_HOST}/${Key}` };
35+
}
36+
37+
@Delete('/:path(.+)')
38+
@Authorized()
39+
@OnUndefined(204)
40+
async deleteFile(@CurrentUser() { id }: User, @Param('path') path: string) {
41+
const Key = `user/${id}/${path}`;
42+
43+
const command = new DeleteObjectCommand({ Bucket: AWS_S3_BUCKET, Key });
44+
45+
await s3Client.send(command);
46+
}
47+
}

source/controller/OAuth.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { githubClient, User as GitHubUser } from 'mobx-github';
2+
import { Body, HttpCode, JsonController, Post } from 'routing-controllers';
3+
import { ResponseSchema } from 'routing-controllers-openapi';
4+
import { isDeepStrictEqual } from 'util';
5+
6+
import { dataSource, OAuthSignInData, User } from '../model';
7+
import { ActivityLogController } from './ActivityLog';
8+
import { UserController } from './User';
9+
10+
const store = dataSource.getRepository(User);
11+
12+
@JsonController('/user/OAuth')
13+
export class OauthController {
14+
@Post('/GitHub')
15+
@HttpCode(201)
16+
@ResponseSchema(User)
17+
async signInWithGithub(@Body() { accessToken }: OAuthSignInData) {
18+
const { body } = await githubClient.get<GitHubUser>('user', {
19+
Authorization: `Bearer ${accessToken}`
20+
});
21+
const { email, login, avatar_url } = body!;
22+
const user =
23+
(await store.findOneBy({ email })) ||
24+
(await UserController.signUp({ email, password: accessToken }));
25+
const newProfile = { name: login, avatar: avatar_url },
26+
oldPofile = { name: user.name, avatar: user.avatar };
27+
28+
if (!isDeepStrictEqual(oldPofile, newProfile)) {
29+
await store.save(Object.assign(user, newProfile));
30+
31+
await ActivityLogController.logUpdate(user, 'User', user.id);
32+
}
33+
return UserController.sign(user);
34+
}
35+
}

0 commit comments

Comments
 (0)