@things-factory/operato-codelingua 8.0.0-beta.9 → 8.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/.dockerignore +6 -24
  2. package/client/bootstrap.ts +206 -0
  3. package/client/icons/menu-icons.ts +91 -0
  4. package/client/index.ts +0 -0
  5. package/client/pages/git-project/git-project-list-page.ts +427 -0
  6. package/client/route.ts +8 -0
  7. package/client/themes/dark.css +51 -0
  8. package/client/themes/light.css +51 -0
  9. package/client/tsconfig.json +12 -0
  10. package/client/viewparts/menu-tools.ts +170 -0
  11. package/client/viewparts/user-circle.ts +24 -0
  12. package/dist-client/tsconfig.tsbuildinfo +1 -1
  13. package/dist-server/tsconfig.tsbuildinfo +1 -1
  14. package/installer/config.production.js +40 -0
  15. package/installer/docker-compose.yml +42 -0
  16. package/installer/install.sh +54 -0
  17. package/installer/migrate.sh +1 -0
  18. package/installer/start.sh +18 -0
  19. package/installer/stop.sh +1 -0
  20. package/installer/upgrade.sh +1 -0
  21. package/package.json +48 -48
  22. package/server/controllers/github-controller.ts +98 -0
  23. package/server/controllers/index.ts +0 -0
  24. package/server/index.ts +7 -0
  25. package/server/middlewares/index.ts +3 -0
  26. package/server/migrations/index.ts +9 -0
  27. package/server/routers/github-webhook-router.ts +45 -0
  28. package/server/routes.ts +30 -0
  29. package/server/service/git-project/git-project-mutation.ts +179 -0
  30. package/server/service/git-project/git-project-query.ts +48 -0
  31. package/server/service/git-project/git-project-type.ts +76 -0
  32. package/server/service/git-project/git-project.ts +114 -0
  33. package/server/service/git-project/index.ts +7 -0
  34. package/server/service/index.ts +21 -0
  35. package/server/tsconfig.json +9 -0
@@ -0,0 +1,40 @@
1
+ module.exports = {
2
+ SECRET: '0xD58F835B69D207A76CC5F84a70a1D0d4C79dAC95', // should be changed
3
+ email: {
4
+ host: 'smtp.office365.com', // your sender-email smtp host
5
+ port: 587, // smtp server port
6
+ secure: false, // true for 465, false for other ports
7
+ auth: {
8
+ user: 'your sender-email',
9
+ pass: 'your sender-email password' // generated ethereal password
10
+ },
11
+ secureConnection: false,
12
+ tls: {
13
+ ciphers: 'SSLv3'
14
+ }
15
+ },
16
+ logger: {
17
+ file: {
18
+ filename: 'logs/application-%DATE%.log',
19
+ datePattern: 'YYYY-MM-DD-HH',
20
+ zippedArchive: false,
21
+ maxSize: '20m',
22
+ maxFiles: '2d',
23
+ level: 'info'
24
+ },
25
+ console: {
26
+ level: 'silly'
27
+ }
28
+ },
29
+ ormconfig: {
30
+ name: 'default',
31
+ type: 'postgres',
32
+ host: 'postgres',
33
+ port: 5432,
34
+ database: 'postgres',
35
+ username: 'postgres',
36
+ password: 'abcd1234',
37
+ synchronize: true,
38
+ logging: true
39
+ }
40
+ }
@@ -0,0 +1,42 @@
1
+ version: '3'
2
+ services:
3
+ nginx:
4
+ image: hatiolab/operato-nginx:latest
5
+ ports:
6
+ - ${HostPort}:80
7
+ depends_on:
8
+ - app
9
+ app:
10
+ build: .
11
+ container_name: operato-codelingua
12
+ image: hatiolab/operato-codelingua:latest
13
+ privileged: true
14
+ volumes:
15
+ - ./logs:/app/logs
16
+ - ./config.production.js:/app/config.production.js
17
+ ports:
18
+ - 4000:3000
19
+ depends_on:
20
+ - postgres
21
+ - mosquitto
22
+ logging:
23
+ driver: 'json-file'
24
+ options:
25
+ max-size: '100m'
26
+ max-file: '3'
27
+ postgres:
28
+ image: postgres:13.2
29
+ container_name: db-operato-codelingua
30
+ environment:
31
+ POSTGRES_PASSWORD: abcd1234
32
+ POSTGRES_USER: postgres
33
+ PGDATA: /var/lib/postgresql/data/pgdata
34
+ volumes:
35
+ - ./postgres_data:/var/lib/postgresql/data/pgdata
36
+ ports:
37
+ - '55432:5432'
38
+ mosquitto:
39
+ image: eclipse-mosquitto:latest
40
+ ports:
41
+ - 1883:1883
42
+ - 9001:9001
@@ -0,0 +1,54 @@
1
+ if [ -f "config.production.js" ] ; then
2
+ echo "config.production.js exist"
3
+ else
4
+ echo "config.production.js create"
5
+ curl -O https://raw.githubusercontent.com/things-factory/things-factory/master/packages/operato-codelingua/installer/config.production.js
6
+ fi
7
+
8
+ if [ -f "start.sh" ] ; then
9
+ echo "start.sh exist"
10
+ else
11
+ echo "start.sh create"
12
+ curl -O https://raw.githubusercontent.com/things-factory/things-factory/master/packages/operato-codelingua/installer/start.sh
13
+ fi
14
+
15
+ if [ -f "stop.sh" ] ; then
16
+ echo "stop.sh exist"
17
+ else
18
+ echo "stop.sh create"
19
+ curl -O https://raw.githubusercontent.com/things-factory/things-factory/master/packages/operato-codelingua/installer/stop.sh
20
+ fi
21
+
22
+ if [ -f "upgrade.sh" ] ; then
23
+ echo "upgrade.sh exist"
24
+ else
25
+ echo "upgrade.sh create"
26
+ curl -O https://raw.githubusercontent.com/things-factory/things-factory/master/packages/operato-codelingua/installer/upgrade.sh
27
+ fi
28
+
29
+ if [ -f "migrate.sh" ] ; then
30
+ echo "migrate.sh exist"
31
+ else
32
+ echo "migrate.sh create"
33
+ curl -O https://raw.githubusercontent.com/things-factory/things-factory/master/packages/operato-codelingua/installer/migrate.sh
34
+ fi
35
+
36
+ if [ -f "docker-compose.yml" ] ; then
37
+ echo "docker-compose.yml exist"
38
+ else
39
+ echo "docker-compose.yml create"
40
+ curl -O https://raw.githubusercontent.com/things-factory/things-factory/master/packages/operato-codelingua/installer/docker-compose.yml
41
+ fi
42
+
43
+ chmod u+x start.sh
44
+ chmod u+x stop.sh
45
+ chmod u+x upgrade.sh
46
+ chmod u+x migrate.sh
47
+
48
+ echo "HostPort=3000" > .env
49
+
50
+ docker pull hatiolab/operato-codelingua:latest
51
+
52
+ docker pull hatiolab/operato-nginx:latest
53
+
54
+ docker-compose create
@@ -0,0 +1 @@
1
+ docker exec -it operato-codelingua npm run migration -- --mode=production
@@ -0,0 +1,18 @@
1
+ HOST_PORT=3000
2
+
3
+ if [ $# -eq 0 ] ; then
4
+ echo "Warning: default port 3000"
5
+ else
6
+ HOST_PORT=$1
7
+ fi
8
+
9
+
10
+ echo "HOST_PORT : ${HOST_PORT}"
11
+
12
+ echo "HostPort="$HOST_PORT > .env
13
+
14
+ if [[ "$OSTYPE" == "linux-gnu"* ]]; then
15
+ xhost +"local:docker@"
16
+ fi
17
+
18
+ docker-compose up -d
@@ -0,0 +1 @@
1
+ docker-compose stop
@@ -0,0 +1 @@
1
+ curl -fsSL https://raw.githubusercontent.com/things-factory/things-factory/master/packages/operato-codelingua/installer/install.sh | bash -s
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/operato-codelingua",
3
- "version": "8.0.0-beta.9",
3
+ "version": "8.0.2",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "dist-client/index.js",
6
6
  "things-factory": true,
@@ -40,54 +40,54 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@material/web": "^2.0.0",
43
- "@operato/data-grist": "^8.0.0-beta",
44
- "@operato/property-editor": "^8.0.0-beta",
45
- "@operato/scene-chartjs": "^8.0.0-beta",
46
- "@operato/scene-clock": "^8.0.0-beta",
47
- "@operato/scene-data-transform": "^8.0.0-beta",
48
- "@operato/scene-excel": "^8.0.0-beta",
49
- "@operato/scene-form": "^8.0.0-beta",
50
- "@operato/scene-gantt": "^8.0.0-beta",
51
- "@operato/scene-gauge": "^8.0.0-beta",
52
- "@operato/scene-half-roundrect": "^8.0.0-beta",
53
- "@operato/scene-image-slider": "^8.0.0-beta",
54
- "@operato/scene-integration": "^8.0.0-beta",
55
- "@operato/scene-label": "^8.0.0-beta",
56
- "@operato/scene-manufacturing": "^8.0.0-beta",
57
- "@operato/scene-news-ticker": "^8.0.0-beta",
58
- "@operato/scene-progressbar": "^8.0.0-beta",
59
- "@operato/scene-random": "^8.0.0-beta",
60
- "@operato/scene-restful": "^8.0.0-beta",
61
- "@operato/scene-scichart": "^8.0.0-beta",
62
- "@operato/scene-switch": "^8.0.0-beta",
63
- "@operato/scene-table": "^8.0.0-beta",
64
- "@operato/scene-timer": "^8.0.0-beta",
65
- "@things-factory/api": "^8.0.0-beta.9",
66
- "@things-factory/apptool-ui": "^8.0.0-beta.9",
67
- "@things-factory/auth-ui": "^8.0.0-beta.9",
68
- "@things-factory/board-service": "^8.0.0-beta.9",
69
- "@things-factory/board-ui": "^8.0.0-beta.9",
70
- "@things-factory/codelingua": "^8.0.0-beta.9",
71
- "@things-factory/context-ui": "^8.0.0-beta.9",
72
- "@things-factory/dashboard": "^8.0.0-beta.9",
73
- "@things-factory/evaluation": "^8.0.0-beta.9",
74
- "@things-factory/export-ui": "^8.0.0-beta.9",
75
- "@things-factory/help": "^8.0.0-beta.9",
76
- "@things-factory/i18n-base": "^8.0.0-beta.9",
77
- "@things-factory/integration-ui": "^8.0.0-beta.9",
78
- "@things-factory/lite-menu": "^8.0.0-beta.9",
79
- "@things-factory/more-ui": "^8.0.0-beta.9",
80
- "@things-factory/notification": "^8.0.0-beta.9",
81
- "@things-factory/oauth2-client": "^8.0.0-beta.9",
82
- "@things-factory/print-ui": "^8.0.0-beta.9",
83
- "@things-factory/resource-ui": "^8.0.0-beta.9",
84
- "@things-factory/setting-base": "^8.0.0-beta.9",
85
- "@things-factory/setting-ui": "^8.0.0-beta.9",
86
- "@things-factory/shell": "^8.0.0-beta.9",
87
- "@things-factory/system": "^8.0.0-beta.9"
43
+ "@operato/data-grist": "^8.0.0",
44
+ "@operato/property-editor": "^8.0.0",
45
+ "@operato/scene-chartjs": "^8.0.0",
46
+ "@operato/scene-clock": "^8.0.0",
47
+ "@operato/scene-data-transform": "^8.0.0",
48
+ "@operato/scene-excel": "^8.0.0",
49
+ "@operato/scene-form": "^8.0.0",
50
+ "@operato/scene-gantt": "^8.0.0",
51
+ "@operato/scene-gauge": "^8.0.0",
52
+ "@operato/scene-half-roundrect": "^8.0.0",
53
+ "@operato/scene-image-slider": "^8.0.0",
54
+ "@operato/scene-integration": "^8.0.0",
55
+ "@operato/scene-label": "^8.0.0",
56
+ "@operato/scene-manufacturing": "^8.0.0",
57
+ "@operato/scene-news-ticker": "^8.0.0",
58
+ "@operato/scene-progressbar": "^8.0.0",
59
+ "@operato/scene-random": "^8.0.0",
60
+ "@operato/scene-restful": "^8.0.0",
61
+ "@operato/scene-scichart": "^8.0.0",
62
+ "@operato/scene-switch": "^8.0.0",
63
+ "@operato/scene-table": "^8.0.0",
64
+ "@operato/scene-timer": "^8.0.0",
65
+ "@things-factory/api": "^8.0.2",
66
+ "@things-factory/apptool-ui": "^8.0.2",
67
+ "@things-factory/auth-ui": "^8.0.2",
68
+ "@things-factory/board-service": "^8.0.2",
69
+ "@things-factory/board-ui": "^8.0.2",
70
+ "@things-factory/codelingua": "^8.0.2",
71
+ "@things-factory/context-ui": "^8.0.2",
72
+ "@things-factory/dashboard": "^8.0.2",
73
+ "@things-factory/evaluation": "^8.0.2",
74
+ "@things-factory/export-ui": "^8.0.2",
75
+ "@things-factory/help": "^8.0.2",
76
+ "@things-factory/i18n-base": "^8.0.2",
77
+ "@things-factory/integration-ui": "^8.0.2",
78
+ "@things-factory/lite-menu": "^8.0.2",
79
+ "@things-factory/more-ui": "^8.0.2",
80
+ "@things-factory/notification": "^8.0.2",
81
+ "@things-factory/oauth2-client": "^8.0.2",
82
+ "@things-factory/print-ui": "^8.0.2",
83
+ "@things-factory/resource-ui": "^8.0.2",
84
+ "@things-factory/setting-base": "^8.0.2",
85
+ "@things-factory/setting-ui": "^8.0.2",
86
+ "@things-factory/shell": "^8.0.2",
87
+ "@things-factory/system": "^8.0.2"
88
88
  },
89
89
  "devDependencies": {
90
- "@things-factory/builder": "^8.0.0-beta.4"
90
+ "@things-factory/builder": "^8.0.2"
91
91
  },
92
- "gitHead": "86b1dfa26292926a2d5447fdc23bfa5a9e983245"
92
+ "gitHead": "39d60f56e142561233ddf6d47b539c637971357c"
93
93
  }
@@ -0,0 +1,98 @@
1
+ import fetch, { Response } from 'node-fetch'
2
+
3
+ const GITHUB_API_URL = 'https://api.github.com'
4
+
5
+ const fetchOptions = (token: string) => ({
6
+ headers: {
7
+ 'Content-Type': 'application/json',
8
+ Authorization: `token ${token}`
9
+ }
10
+ })
11
+
12
+ const handleFetchError = (response: Response, action: string) => {
13
+ if (!response.ok) {
14
+ console.error(`Failed to ${action}:`, response.statusText)
15
+ throw new Error(`Failed to ${action}`)
16
+ }
17
+ }
18
+
19
+ const getWebhooks = async (repoFullName: string, token: string): Promise<any[]> => {
20
+ const response: Response = await fetch(`${GITHUB_API_URL}/repos/${repoFullName}/hooks`, fetchOptions(token))
21
+ handleFetchError(response, 'fetch webhooks')
22
+ return response.json()
23
+ }
24
+
25
+ const webhookExists = async (
26
+ repoFullName: string,
27
+ webhookUrl: string,
28
+ token: string
29
+ ): Promise<{ exists: boolean; id?: number }> => {
30
+ try {
31
+ const hooks: any[] = await getWebhooks(repoFullName, token)
32
+ const hook = hooks.find((hook: any) => hook.config.url === webhookUrl)
33
+ return hook ? { exists: true, id: hook.id } : { exists: false }
34
+ } catch (error) {
35
+ console.error('Error checking webhook existence:', error)
36
+ return { exists: false }
37
+ }
38
+ }
39
+
40
+ export const postGitHubComment = async (repoFullName: string, commitId: string, comment: string): Promise<void> => {
41
+ try {
42
+ const response: Response = await fetch(`${GITHUB_API_URL}/repos/${repoFullName}/commits/${commitId}/comments`, {
43
+ method: 'POST',
44
+ ...fetchOptions(process.env.GITHUB_API_KEY!),
45
+ body: JSON.stringify({ body: comment })
46
+ })
47
+ handleFetchError(response, 'post GitHub comment')
48
+ } catch (error) {
49
+ console.error('Error posting GitHub comment:', error)
50
+ }
51
+ }
52
+
53
+ export const registerWebhook = async (accessToken: string, repoFullName: string, webhookUrl: string) => {
54
+ const { exists } = await webhookExists(repoFullName, webhookUrl, accessToken)
55
+ if (exists) {
56
+ console.log('Webhook already registered.')
57
+ return
58
+ }
59
+
60
+ try {
61
+ const response: Response = await fetch(`${GITHUB_API_URL}/repos/${repoFullName}/hooks`, {
62
+ method: 'POST',
63
+ ...fetchOptions(accessToken),
64
+ body: JSON.stringify({
65
+ name: 'web',
66
+ active: true,
67
+ events: ['push'],
68
+ config: {
69
+ url: webhookUrl,
70
+ content_type: 'json'
71
+ }
72
+ })
73
+ })
74
+ handleFetchError(response, 'register webhook')
75
+ console.log('Webhook registered successfully.')
76
+ } catch (error) {
77
+ console.error('Error registering webhook:', error)
78
+ }
79
+ }
80
+
81
+ export const unregisterWebhook = async (accessToken: string, repoFullName: string, webhookUrl: string) => {
82
+ const { exists, id } = await webhookExists(repoFullName, webhookUrl, accessToken)
83
+ if (!exists || !id) {
84
+ console.log('Webhook not found.')
85
+ return
86
+ }
87
+
88
+ try {
89
+ const deleteResponse: Response = await fetch(`${GITHUB_API_URL}/repos/${repoFullName}/hooks/${id}`, {
90
+ method: 'DELETE',
91
+ ...fetchOptions(accessToken)
92
+ })
93
+ handleFetchError(deleteResponse, 'unregister webhook')
94
+ console.log('Webhook unregistered successfully.')
95
+ } catch (error) {
96
+ console.error('Error unregistering webhook:', error)
97
+ }
98
+ }
File without changes
@@ -0,0 +1,7 @@
1
+ import './routes'
2
+
3
+ export * from './migrations'
4
+ export * from './middlewares'
5
+ export * from './service'
6
+
7
+ /* github webhook 이 등록되지 않았다면, 웹훅을 등록한다. */
@@ -0,0 +1,3 @@
1
+ export function initMiddlewares(app) {
2
+ /* can add middlewares into app */
3
+ }
@@ -0,0 +1,9 @@
1
+ const glob = require('glob')
2
+ const path = require('path')
3
+
4
+ export var migrations = []
5
+
6
+ glob.sync(path.resolve(__dirname, '.', '**', '*.js')).forEach(function(file) {
7
+ if (file.indexOf('index.js') !== -1) return
8
+ migrations = migrations.concat(Object.values(require(path.resolve(file))) || [])
9
+ })
@@ -0,0 +1,45 @@
1
+ import Router from 'koa-router'
2
+ import { codereviewCompletion } from '@things-factory/codelingua'
3
+
4
+ import { postGitHubComment } from '../controllers/github-controller'
5
+ import { getRepository } from '@things-factory/shell'
6
+ import { GitProject } from '../service/git-project/git-project'
7
+
8
+ export const githubWebhookRouter = new Router()
9
+
10
+ githubWebhookRouter.post('/github-webhook/:projectId', async (context, next) => {
11
+ const { payload, head_commit } = context.request.body
12
+ const { commitDiff } = head_commit.diff
13
+ // const { commits, pull_request } = payload
14
+ const projectId = context.params.projectId
15
+
16
+ const project = await getRepository(GitProject).findOne({
17
+ where: {
18
+ id: projectId
19
+ }
20
+ })
21
+
22
+ if (!project) {
23
+ context.status = 404
24
+ context.body = 'Project not found'
25
+ return
26
+ }
27
+
28
+ // for (const commit of commits) {
29
+ // const codeDiff = `diff of the changed code here` // 실제 diff 데이터를 가져오는 로직 필요
30
+ // const reviewFeedback = await codereviewCompletion(codeDiff)
31
+ // const pullNumber = pull_request.number // 풀 리퀘스트 번호를 받아옴
32
+ // await postGitHubComment(project.repositoryUrl, pullNumber, reviewFeedback)
33
+ // }
34
+
35
+ const reviewFeedback = await codereviewCompletion(commitDiff)
36
+
37
+ await postGitHubComment(
38
+ context.request.body.repository.full_name,
39
+ context.request.body.head_commit.id,
40
+ reviewFeedback
41
+ )
42
+
43
+ context.status = 200
44
+ context.body = 'Success'
45
+ })
@@ -0,0 +1,30 @@
1
+ import { githubWebhookRouter } from './routers/github-webhook-router'
2
+
3
+ process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRouter) => {
4
+ /*
5
+ * can add global public routes to application (auth not required, tenancy not required)
6
+ *
7
+ * ex) routes.get('/path', async(context, next) => {})
8
+ * ex) routes.post('/path', async(context, next) => {})
9
+ */
10
+
11
+ globalPublicRouter.use('', githubWebhookRouter.routes(), githubWebhookRouter.allowedMethods())
12
+ })
13
+
14
+ process.on('bootstrap-module-global-private-route' as any, (app, globalPrivateRouter) => {
15
+ /*
16
+ * can add global private routes to application (auth required, tenancy not required)
17
+ */
18
+ })
19
+
20
+ process.on('bootstrap-module-domain-public-route' as any, (app, domainPublicRouter) => {
21
+ /*
22
+ * can add domain public routes to application (auth not required, tenancy required)
23
+ */
24
+ })
25
+
26
+ process.on('bootstrap-module-domain-private-route' as any, (app, domainPrivateRouter) => {
27
+ /*
28
+ * can add domain private routes to application (auth required, tenancy required)
29
+ */
30
+ })
@@ -0,0 +1,179 @@
1
+ import { Resolver, Mutation, Arg, Ctx, Directive } from 'type-graphql'
2
+ import { In } from 'typeorm'
3
+
4
+ import { GitProject, GitProjectStatus } from './git-project'
5
+ import { NewGitProject, GitProjectPatch } from './git-project-type'
6
+ import { registerWebhook, unregisterWebhook } from '../../controllers/github-controller'
7
+
8
+ @Resolver(GitProject)
9
+ export class GitProjectMutation {
10
+ @Directive('@transaction')
11
+ @Mutation(returns => GitProject, { description: 'To create new GitProject' })
12
+ async createGitProject(
13
+ @Arg('gitProject') gitProject: NewGitProject,
14
+ @Ctx() context: ResolverContext
15
+ ): Promise<GitProject> {
16
+ const { domain, user, tx } = context.state
17
+
18
+ const result = await tx.getRepository(GitProject).save({
19
+ ...gitProject,
20
+ domain,
21
+ creator: user,
22
+ updater: user
23
+ })
24
+
25
+ return result
26
+ }
27
+
28
+ @Directive('@transaction')
29
+ @Mutation(returns => GitProject, { description: 'To modify GitProject information' })
30
+ async updateGitProject(
31
+ @Arg('id') id: string,
32
+ @Arg('patch') patch: GitProjectPatch,
33
+ @Ctx() context: ResolverContext
34
+ ): Promise<GitProject> {
35
+ const { domain, user, tx } = context.state
36
+
37
+ const repository = tx.getRepository(GitProject)
38
+ const gitProject = await repository.findOne({
39
+ where: { domain: { id: domain.id }, id }
40
+ })
41
+
42
+ const result = await repository.save({
43
+ ...gitProject,
44
+ ...patch,
45
+ updater: user
46
+ })
47
+
48
+ return result
49
+ }
50
+
51
+ @Directive('@transaction')
52
+ @Mutation(returns => [GitProject], { description: "To modify multiple GitProjects' information" })
53
+ async updateMultipleGitProject(
54
+ @Arg('patches', type => [GitProjectPatch]) patches: GitProjectPatch[],
55
+ @Ctx() context: ResolverContext
56
+ ): Promise<GitProject[]> {
57
+ const { domain, user, tx } = context.state
58
+
59
+ let results = []
60
+ const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')
61
+ const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')
62
+ const gitProjectRepo = tx.getRepository(GitProject)
63
+
64
+ if (_createRecords.length > 0) {
65
+ for (let i = 0; i < _createRecords.length; i++) {
66
+ const newRecord = _createRecords[i]
67
+
68
+ const result = await gitProjectRepo.save({
69
+ ...newRecord,
70
+ domain,
71
+ creator: user,
72
+ updater: user
73
+ })
74
+
75
+ results.push({ ...result, cuFlag: '+' })
76
+ }
77
+ }
78
+
79
+ if (_updateRecords.length > 0) {
80
+ for (let i = 0; i < _updateRecords.length; i++) {
81
+ const updateRecord = _updateRecords[i]
82
+ const gitProject = await gitProjectRepo.findOneBy({ id: updateRecord.id })
83
+
84
+ const result = await gitProjectRepo.save({
85
+ ...gitProject,
86
+ ...updateRecord,
87
+ updater: user
88
+ })
89
+
90
+ results.push({ ...result, cuFlag: 'M' })
91
+ }
92
+ }
93
+
94
+ return results
95
+ }
96
+
97
+ @Directive('@transaction')
98
+ @Mutation(returns => Boolean, { description: 'To delete GitProject' })
99
+ async deleteGitProject(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {
100
+ const { domain, tx } = context.state
101
+
102
+ await tx.getRepository(GitProject).delete({ domain: { id: domain.id }, id })
103
+
104
+ return true
105
+ }
106
+
107
+ @Directive('@transaction')
108
+ @Mutation(returns => Boolean, { description: 'To delete multiple GitProjects' })
109
+ async deleteGitProjects(
110
+ @Arg('ids', type => [String]) ids: string[],
111
+ @Ctx() context: ResolverContext
112
+ ): Promise<boolean> {
113
+ const { domain, tx } = context.state
114
+
115
+ await tx.getRepository(GitProject).delete({
116
+ domain: { id: domain.id },
117
+ id: In(ids)
118
+ })
119
+
120
+ return true
121
+ }
122
+
123
+ @Directive('@transaction')
124
+ @Mutation(returns => Boolean, { description: 'To import multiple GitProjects' })
125
+ async importGitProjects(
126
+ @Arg('gitProjects', type => [GitProjectPatch]) gitProjects: GitProjectPatch[],
127
+ @Ctx() context: ResolverContext
128
+ ): Promise<boolean> {
129
+ const { domain, tx } = context.state
130
+
131
+ await Promise.all(
132
+ gitProjects.map(async (gitProject: GitProjectPatch) => {
133
+ const createdGitProject: GitProject = await tx.getRepository(GitProject).save({ domain, ...gitProject })
134
+ })
135
+ )
136
+
137
+ return true
138
+ }
139
+
140
+ @Directive('@transaction')
141
+ @Mutation(returns => Boolean, { description: 'To register GitHub webhook' })
142
+ async registerGithubWebhook(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {
143
+ const { domain, tx } = context.state
144
+
145
+ const repository = tx.getRepository(GitProject)
146
+ const gitProject = await repository.findOne({ where: { domain: { id: domain.id }, id } })
147
+
148
+ if (!gitProject) {
149
+ throw new Error('GitProject not found')
150
+ }
151
+
152
+ const webhook = await registerWebhook(gitProject.apiKey, gitProject.name, gitProject.webhookUrl)
153
+
154
+ gitProject.state = GitProjectStatus.REGISTERED
155
+ await repository.save(gitProject)
156
+
157
+ return true
158
+ }
159
+
160
+ @Directive('@transaction')
161
+ @Mutation(returns => Boolean, { description: 'To unregister GitHub webhook' })
162
+ async unregisterGithubWebhook(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {
163
+ const { domain, tx } = context.state
164
+
165
+ const repository = tx.getRepository(GitProject)
166
+ const gitProject = await repository.findOne({ where: { domain: { id: domain.id }, id } })
167
+
168
+ if (!gitProject) {
169
+ throw new Error('GitProject not found')
170
+ }
171
+
172
+ await unregisterWebhook(gitProject.apiKey, gitProject.name, gitProject.webhookUrl)
173
+
174
+ gitProject.state = GitProjectStatus.READY
175
+ await repository.save(gitProject)
176
+
177
+ return true
178
+ }
179
+ }