Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
C
console
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
console
Commits
421db8af
Commit
421db8af
authored
Aug 16, 2021
by
nanahira
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
crud
parent
4268cf19
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
323 additions
and
31 deletions
+323
-31
console-api/package-lock.json
console-api/package-lock.json
+14
-0
console-api/package.json
console-api/package.json
+1
-0
console-api/src/admin/admin.controller.ts
console-api/src/admin/admin.controller.ts
+41
-1
console-api/src/app.controller.ts
console-api/src/app.controller.ts
+47
-1
console-api/src/app.service.ts
console-api/src/app.service.ts
+101
-8
console-api/src/dto/AssignApp.dto.ts
console-api/src/dto/AssignApp.dto.ts
+9
-0
console-api/src/dto/ReturnMessage.dto.ts
console-api/src/dto/ReturnMessage.dto.ts
+6
-0
console-api/src/entities/App.entity.ts
console-api/src/entities/App.entity.ts
+25
-17
console-api/src/entities/AppBase.entity.ts
console-api/src/entities/AppBase.entity.ts
+7
-3
console-api/src/entities/AppHistory.entity.ts
console-api/src/entities/AppHistory.entity.ts
+4
-0
console-api/src/my-card-admin.guard.ts
console-api/src/my-card-admin.guard.ts
+1
-1
console-api/src/utility/apps-json-type.ts
console-api/src/utility/apps-json-type.ts
+34
-0
console-api/test/app.e2e-spec.ts
console-api/test/app.e2e-spec.ts
+24
-0
console-api/test/jest-e2e.json
console-api/test/jest-e2e.json
+9
-0
No files found.
console-api/package-lock.json
View file @
421db8af
...
...
@@ -17,6 +17,7 @@
"class-transformer"
:
"^0.4.0"
,
"class-validator"
:
"^0.13.1"
,
"lodash"
:
"^4.17.21"
,
"moment"
:
"^2.29.1"
,
"pg"
:
"^8.7.1"
,
"pg-native"
:
"^3.0.0"
,
"reflect-metadata"
:
"^0.1.13"
,
...
...
@@ -7170,6 +7171,14 @@
"mkdirp"
:
"bin/cmd.js"
}
},
"node_modules/moment"
:
{
"version"
:
"2.29.1"
,
"resolved"
:
"https://registry.npmjs.org/moment/-/moment-2.29.1.tgz"
,
"integrity"
:
"sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
,
"engines"
:
{
"node"
:
"*"
}
},
"node_modules/ms"
:
{
"version"
:
"2.1.2"
,
"resolved"
:
"https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
,
...
...
@@ -15842,6 +15851,11 @@
"minimist"
:
"^1.2.5"
}
},
"moment"
:
{
"version"
:
"2.29.1"
,
"resolved"
:
"https://registry.npmjs.org/moment/-/moment-2.29.1.tgz"
,
"integrity"
:
"sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
},
"ms"
:
{
"version"
:
"2.1.2"
,
"resolved"
:
"https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
,
...
...
console-api/package.json
View file @
421db8af
...
...
@@ -30,6 +30,7 @@
"class-transformer"
:
"^0.4.0"
,
"class-validator"
:
"^0.13.1"
,
"lodash"
:
"^4.17.21"
,
"moment"
:
"^2.29.1"
,
"pg"
:
"^8.7.1"
,
"pg-native"
:
"^3.0.0"
,
"reflect-metadata"
:
"^0.1.13"
,
...
...
console-api/src/admin/admin.controller.ts
View file @
421db8af
import
{
Body
,
Controller
,
Delete
,
Get
,
Param
,
ParseIntPipe
,
Post
,
Put
,
UploadedFile
,
UseGuards
,
UseInterceptors
,
ValidationPipe
,
}
from
'
@nestjs/common
'
;
import
{
ApiBody
,
ApiConsumes
,
ApiOperation
,
ApiTags
}
from
'
@nestjs/swagger
'
;
import
{
ApiBody
,
ApiConsumes
,
ApiCreatedResponse
,
ApiOkResponse
,
ApiOperation
,
ApiTags
,
}
from
'
@nestjs/swagger
'
;
import
{
MyCardAdminGuard
}
from
'
../my-card-admin.guard
'
;
import
{
FileInterceptor
}
from
'
@nestjs/platform-express
'
;
import
{
FileUploadDto
}
from
'
../dto/FileUpload.dto
'
;
import
{
AppsJson
}
from
'
../utility/apps-json-type
'
;
import
{
AppService
}
from
'
../app.service
'
;
import
{
BlankReturnMessageDto
}
from
'
../dto/ReturnMessage.dto
'
;
import
{
AssignAppDto
}
from
'
../dto/AssignApp.dto
'
;
@
Controller
(
'
api/admin
'
)
@
ApiTags
(
'
admin
'
)
...
...
@@ -27,10 +42,35 @@ export class AdminController {
description
:
'
apps.json 文件
'
,
type
:
FileUploadDto
,
})
@
ApiCreatedResponse
({
type
:
BlankReturnMessageDto
})
async
migrate
(
@
UploadedFile
(
'
file
'
)
file
:
Express
.
Multer
.
File
,
):
Promise
<
BlankReturnMessageDto
>
{
const
apps
:
AppsJson
.
App
[]
=
JSON
.
parse
(
file
.
buffer
.
toString
());
return
this
.
appService
.
migrateFromAppsJson
(
apps
);
}
@
Put
(
'
app/:id
'
)
@
ApiOperation
({
summary
:
'
创建 app
'
})
@
ApiOkResponse
({
type
:
BlankReturnMessageDto
})
async
createApp
(@
Param
(
'
id
'
)
id
:
string
)
{
return
this
.
appService
.
createApp
(
id
);
}
@
Delete
(
'
app/:id
'
)
@
ApiOperation
({
summary
:
'
创建 app
'
})
@
ApiOkResponse
({
type
:
BlankReturnMessageDto
})
async
deleteApp
(@
Param
(
'
id
'
)
id
:
string
)
{
return
this
.
appService
.
deleteApp
(
id
);
}
@
Post
(
'
app/:id/assign
'
)
@
ApiOperation
({
summary
:
'
创建 app
'
})
@
ApiOkResponse
({
type
:
BlankReturnMessageDto
})
async
assignApp
(
@
Param
(
'
id
'
)
id
:
string
,
@
Body
(
new
ValidationPipe
({
transform
:
true
}))
assignAppData
:
AssignAppDto
,
)
{
return
this
.
appService
.
assignApp
(
id
,
assignAppData
.
author
);
}
}
console-api/src/app.controller.ts
View file @
421db8af
import
{
Controller
,
Get
}
from
'
@nestjs/common
'
;
import
{
Body
,
Controller
,
Get
,
ParseIntPipe
,
Post
,
Query
,
ValidationPipe
,
}
from
'
@nestjs/common
'
;
import
{
AppService
}
from
'
./app.service
'
;
import
{
ApiBody
,
ApiCreatedResponse
,
ApiOkResponse
,
ApiOperation
,
ApiQuery
,
}
from
'
@nestjs/swagger
'
;
import
{
BlankReturnMessageDto
,
GetAppReturnMessageDto
,
}
from
'
./dto/ReturnMessage.dto
'
;
import
{
FetchMyCardUser
,
MyCardUser
}
from
'
./utility/mycard-auth
'
;
import
{
AppsJson
}
from
'
./utility/apps-json-type
'
;
import
AppClass
=
AppsJson
.
AppClass
;
@
Controller
(
'
api
'
)
export
class
AppController
{
...
...
@@ -9,4 +31,28 @@ export class AppController {
getAppsJson
()
{
return
this
.
appService
.
getAppsJson
();
}
@
Get
(
'
app
'
)
@
ApiOperation
({
summary
:
'
获取 app
'
,
description
:
'
管理员可以查询全部的,其他用户可以查属于自己的
'
,
})
@
ApiQuery
({
name
:
'
id
'
,
description
:
'
app 的 id,没有就是查全部
'
})
@
ApiOkResponse
({
type
:
GetAppReturnMessageDto
})
getApp
(@
FetchMyCardUser
()
user
:
MyCardUser
,
@
Query
(
'
id
'
)
id
?:
string
)
{
return
this
.
appService
.
getApp
(
user
,
id
);
}
@
Post
(
'
app
'
)
@
ApiOperation
({
summary
:
'
更新 app
'
,
})
@
ApiBody
({
type
:
AppsJson
.
AppClass
})
@
ApiCreatedResponse
({
type
:
BlankReturnMessageDto
})
updateApp
(
@
FetchMyCardUser
()
user
:
MyCardUser
,
@
Body
(
new
ValidationPipe
({
transform
:
true
}))
app
:
AppClass
,
)
{
return
this
.
appService
.
updateApp
(
user
,
app
.
id
,
app
);
}
}
console-api/src/app.service.ts
View file @
421db8af
import
{
Connectio
n
,
IsNull
,
Not
}
from
'
typeorm
'
;
import
{
Any
,
Connection
,
FindConditions
,
I
n
,
IsNull
,
Not
}
from
'
typeorm
'
;
import
{
InjectConnection
}
from
'
@nestjs/typeorm
'
;
import
{
Injectable
,
ConsoleLogger
}
from
'
@nestjs/common
'
;
import
{
Injectable
,
ConsoleLogger
,
HttpException
}
from
'
@nestjs/common
'
;
import
{
AppsJson
}
from
'
./utility/apps-json-type
'
;
import
{
App
}
from
'
./entities/App.entity
'
;
import
{
BlankReturnMessageDto
}
from
'
./dto/ReturnMessage.dto
'
;
import
{
BlankReturnMessageDto
,
ReturnMessageDto
,
}
from
'
./dto/ReturnMessage.dto
'
;
import
{
MyCardUser
}
from
'
./utility/mycard-auth
'
;
@
Injectable
()
export
class
AppService
extends
ConsoleLogger
{
...
...
@@ -18,8 +22,17 @@ export class AppService extends ConsoleLogger {
return
(
await
this
.
db
.
getRepository
(
App
)
.
find
({
where
:
{
appContent
:
Not
(
IsNull
())
}
})
).
map
((
a
)
=>
a
.
app
);
.
find
({
where
:
{
appContent
:
Not
(
IsNull
()),
isDeleted
:
false
}
})
).
map
((
a
)
=>
a
.
appData
);
}
private
async
updateResult
<
T
>
(
f
:
()
=>
Promise
<
T
>
,
returnCode
=
200
)
{
try
{
const
result
=
await
f
();
return
new
ReturnMessageDto
<
T
>
(
returnCode
,
'
success
'
,
result
);
}
catch
(
e
)
{
throw
new
BlankReturnMessageDto
(
404
,
'
Database Fail
'
).
toException
();
}
}
async
migrateFromAppsJson
(
apps
:
AppsJson
.
App
[])
{
...
...
@@ -34,17 +47,97 @@ export class AppService extends ConsoleLogger {
const
checkExistingApp
=
await
this
.
db
.
getRepository
(
App
)
.
findOne
({
where
:
{
id
:
appData
.
id
},
relations
:
[
'
history
'
]
});
//this.error('read');
if
(
checkExistingApp
)
{
checkExistingApp
.
updateApp
(
appData
);
checkExistingApp
.
isDeleted
=
false
;
targetApps
.
push
(
checkExistingApp
);
}
else
{
const
app
=
new
App
();
app
.
id
=
appData
.
id
;
app
.
app
=
appData
;
app
.
app
Data
=
appData
;
targetApps
.
push
(
app
);
}
}
await
this
.
db
.
getRepository
(
App
).
save
(
targetApps
);
return
new
BlankReturnMessageDto
(
201
,
'
success
'
);
//this.error('write');
return
this
.
updateResult
(
async
()
=>
{
await
this
.
db
.
getRepository
(
App
).
save
(
targetApps
);
return
;
},
201
);
}
async
getApp
(
user
:
MyCardUser
,
id
?:
string
)
{
if
(
!
user
)
{
throw
new
BlankReturnMessageDto
(
401
,
'
Needs login
'
).
toException
();
}
const
query
=
this
.
db
.
getRepository
(
App
)
.
createQueryBuilder
(
'
app
'
)
.
where
(
'
app.isDeleted = false
'
);
if
(
!
user
.
admin
)
{
query
.
andWhere
(
'
:uid = ANY(app.author)
'
,
{
uid
:
user
.
id
});
}
if
(
id
)
{
query
.
andWhere
(
'
app.id = :id
'
,
{
id
});
}
query
.
leftJoinAndSelect
(
'
app.history
'
,
'
history
'
);
return
new
ReturnMessageDto
(
200
,
'
success
'
,
await
query
.
getMany
());
}
async
createApp
(
id
:
string
)
{
let
app
=
await
this
.
db
.
getRepository
(
App
)
.
findOne
({
where
:
{
id
},
select
:
[
'
id
'
,
'
isDeleted
'
]
});
if
(
!
app
)
{
app
=
new
App
();
app
.
id
=
id
;
}
else
{
if
(
!
app
.
isDeleted
)
{
throw
new
BlankReturnMessageDto
(
404
,
'
App already exists
'
,
).
toException
();
}
app
.
isDeleted
=
false
;
}
return
this
.
updateResult
(()
=>
this
.
db
.
getRepository
(
App
).
save
(
app
));
}
async
assignApp
(
id
:
string
,
author
:
number
[])
{
return
this
.
updateResult
(
()
=>
this
.
db
.
getRepository
(
App
).
update
({
id
},
{
author
}),
201
,
);
}
async
updateApp
(
user
:
MyCardUser
,
id
:
string
,
appData
:
AppsJson
.
App
)
{
if
(
!
user
)
{
throw
new
BlankReturnMessageDto
(
401
,
'
Needs login
'
).
toException
();
}
appData
.
id
=
id
;
const
app
=
await
this
.
db
.
getRepository
(
App
)
.
findOne
({
where
:
{
id
:
appData
.
id
},
relations
:
[
'
history
'
],
select
:
[
'
id
'
,
'
author
'
,
'
appContent
'
],
});
if
(
!
app
)
{
throw
new
BlankReturnMessageDto
(
404
,
'
App not found
'
).
toException
();
}
if
(
!
app
.
isUserCanEditApp
(
user
))
{
throw
new
BlankReturnMessageDto
(
403
,
'
Permission denied
'
).
toException
();
}
app
.
updateApp
(
appData
,
user
.
id
);
return
this
.
updateResult
(
async
()
=>
{
await
this
.
db
.
getRepository
(
App
).
save
(
app
);
return
;
},
201
);
}
async
deleteApp
(
id
:
string
)
{
return
this
.
updateResult
(()
=>
this
.
db
.
getRepository
(
App
).
update
({
id
},
{
isDeleted
:
true
}),
);
}
}
console-api/src/dto/AssignApp.dto.ts
0 → 100644
View file @
421db8af
import
{
ApiProperty
}
from
'
@nestjs/swagger
'
;
import
{
IsArray
,
IsPositive
}
from
'
class-validator
'
;
export
class
AssignAppDto
{
@
ApiProperty
({
description
:
'
作者 ID
'
})
@
IsArray
()
@
IsPositive
({
each
:
true
})
author
:
number
[];
}
console-api/src/dto/ReturnMessage.dto.ts
View file @
421db8af
import
{
ApiProperty
}
from
'
@nestjs/swagger
'
;
import
{
HttpException
}
from
'
@nestjs/common
'
;
import
{
AppsJson
}
from
'
../utility/apps-json-type
'
;
export
class
BlankReturnMessageDto
{
@
ApiProperty
({
description
:
'
返回状态
'
})
...
...
@@ -27,3 +28,8 @@ export class ReturnMessageDto<T> extends BlankReturnMessageDto {
this
.
data
=
data
;
}
}
export
class
GetAppReturnMessageDto
extends
BlankReturnMessageDto
{
@
ApiProperty
({
description
:
'
返回 app
'
})
data
?:
AppsJson
.
AppClass
;
}
console-api/src/entities/App.entity.ts
View file @
421db8af
import
{
Column
,
Entity
,
OneToMany
,
PrimaryColumn
}
from
'
typeorm
'
;
import
{
TimeBase
}
from
'
./TimeBase.entity
'
;
import
{
Column
,
Entity
,
Index
,
OneToMany
,
PrimaryColumn
}
from
'
typeorm
'
;
import
{
AppsJson
}
from
'
../utility/apps-json-type
'
;
import
{
MyCardUser
}
from
'
../utility/mycard-auth
'
;
import
{
AppBase
}
from
'
./AppBase.entity
'
;
import
{
AppHistory
}
from
'
./AppHistory.entity
'
;
import
moment
from
'
moment
'
;
@
Entity
()
export
class
App
extends
AppBase
{
@
PrimaryColumn
(
'
varchar
'
,
{
length
:
64
})
id
:
string
;
@
Column
(
'
varchar
'
,
{
length
:
128
,
nullable
:
true
})
authorsStr
:
string
;
@
Index
()
@
Column
(
'
int
'
,
{
nullable
:
true
,
array
:
true
})
author
:
number
[];
get
author
():
number
[]
{
return
this
.
authorsStr
?
this
.
authorsStr
.
split
(
'
|
'
).
map
((
idStr
)
=>
parseInt
(
idStr
))
:
[];
}
set
author
(
a
)
{
this
.
authorsStr
=
a
.
join
(
'
|
'
);
}
@
Column
({
nullable
:
true
,
select
:
false
})
isDeleted
:
boolean
;
isUserCanEditApp
(
u
:
MyCardUser
)
{
return
u
.
admin
||
this
.
author
.
includes
(
u
.
id
);
return
u
.
admin
||
(
this
.
author
&&
this
.
author
.
includes
(
u
.
id
)
);
}
@
OneToMany
(()
=>
AppHistory
,
(
h
)
=>
h
.
parentApp
,
{
cascade
:
true
})
history
:
AppHistory
[];
updateApp
(
appData
:
AppsJson
.
App
)
{
this
.
app
=
appData
;
updateApp
(
appData
:
AppsJson
.
App
,
changeUser
?:
number
)
{
appData
.
updated_at
=
moment
().
format
(
'
YYYY-MM-DD HH:mm:ss
'
);
this
.
appData
=
appData
;
const
h
=
new
AppHistory
();
h
.
parentApp
=
this
;
h
.
time
=
new
Date
();
h
.
app
=
appData
;
if
(
changeUser
)
{
h
.
operatingUser
=
changeUser
;
}
h
.
appData
=
appData
;
this
.
history
.
push
(
h
);
}
get
appData
():
AppsJson
.
App
{
const
appData
=
super
.
appData
;
appData
.
id
=
this
.
id
;
return
appData
;
}
set
appData
(
a
)
{
this
.
appContent
=
JSON
.
stringify
(
a
);
}
}
console-api/src/entities/AppBase.entity.ts
View file @
421db8af
...
...
@@ -7,11 +7,15 @@ export class AppBase extends TimeBase {
@
Column
(
'
text
'
,
{
nullable
:
true
})
appContent
:
string
;
get
app
():
AppsJson
.
App
{
return
this
.
appContent
?
JSON
.
parse
(
this
.
appContent
)
:
null
;
get
appData
():
AppsJson
.
App
{
if
(
!
this
.
appContent
)
{
return
null
;
}
const
a
=
JSON
.
parse
(
this
.
appContent
);
return
a
;
}
set
app
(
a
)
{
set
app
Data
(
a
)
{
this
.
appContent
=
JSON
.
stringify
(
a
);
}
}
console-api/src/entities/AppHistory.entity.ts
View file @
421db8af
...
...
@@ -17,6 +17,10 @@ export class AppHistory extends AppBase {
@
Column
()
time
:
Date
;
@
Index
()
@
Column
({
nullable
:
true
})
operatingUser
:
number
;
@
ManyToOne
(()
=>
App
,
(
a
)
=>
a
.
history
)
parentApp
:
App
;
}
console-api/src/my-card-admin.guard.ts
View file @
421db8af
...
...
@@ -11,7 +11,7 @@ export class MyCardAdminGuard implements CanActivate {
throw
new
BlankReturnMessageDto
(
401
,
'
Invalid user
'
).
toException
();
}
if
(
!
user
.
admin
)
{
throw
new
BlankReturnMessageDto
(
403
,
'
No permission
'
).
toException
();
throw
new
BlankReturnMessageDto
(
403
,
'
Permission denied
'
).
toException
();
}
return
true
;
}
...
...
console-api/src/utility/apps-json-type.ts
View file @
421db8af
import
{
IsNotEmpty
}
from
'
class-validator
'
;
export
namespace
AppsJson
{
export
enum
Locale
{
zh_CN
=
'
zh-CN
'
,
...
...
@@ -97,4 +99,36 @@ export namespace AppsJson {
data
?:
any
;
price
?:
Price
;
}
export
class
AppClass
implements
App
{
@
IsNotEmpty
()
id
:
string
;
key
?:
string
;
name
?:
LocaleWise
<
string
>
;
description
?:
LocaleWise
<
string
>
;
developers
?:
LocaleWise
<
Developer
[]
>
;
publishers
?:
LocaleWise
<
Developer
[]
>
;
released_at
?:
string
;
category
?:
string
;
tags
?:
string
[];
trailer
?:
Trailer
[];
dependencies
?:
PlatformWise
<
string
[]
>
;
references
?:
PlatformWise
<
string
[]
>
;
author
?:
string
;
homepage
?:
string
;
locales
?:
string
[];
actions
?:
PlatformWise
<
PlatformAction
>
;
version
?:
PlatformWise
<
string
>
;
news
?:
LocaleWise
<
News
[]
>
;
conference
?:
string
;
icon
?:
string
;
cover
?:
string
;
background
?:
string
;
parent
?:
string
;
network
?:
Network
;
updated_at
?:
string
;
files
?:
Record
<
string
,
Syncable
>
;
data
?:
any
;
price
?:
Price
;
}
}
console-api/test/app.e2e-spec.ts
0 → 100644
View file @
421db8af
import
{
Test
,
TestingModule
}
from
'
@nestjs/testing
'
;
import
{
INestApplication
}
from
'
@nestjs/common
'
;
import
*
as
request
from
'
supertest
'
;
import
{
AppModule
}
from
'
./../src/app.module
'
;
describe
(
'
AppController (e2e)
'
,
()
=>
{
let
app
:
INestApplication
;
beforeEach
(
async
()
=>
{
const
moduleFixture
:
TestingModule
=
await
Test
.
createTestingModule
({
imports
:
[
AppModule
],
}).
compile
();
app
=
moduleFixture
.
createNestApplication
();
await
app
.
init
();
});
/* it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Hello World!');
}); */
});
console-api/test/jest-e2e.json
0 → 100644
View file @
421db8af
{
"moduleFileExtensions"
:
[
"js"
,
"json"
,
"ts"
],
"rootDir"
:
"."
,
"testEnvironment"
:
"node"
,
"testRegex"
:
".e2e-spec.ts$"
,
"transform"
:
{
"^.+\\.(t|j)s$"
:
"ts-jest"
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment