Skip to content

Commit

Permalink
feat(devops-server): add file operation api;
Browse files Browse the repository at this point in the history
  • Loading branch information
maslow committed Aug 17, 2021
1 parent 68f25ef commit e1221c6
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 3 deletions.
31 changes: 31 additions & 0 deletions packages/devops-server/http/file.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

@token={{login.response.body.$.data.access_token}}

### 管理员登陆
# @name login

POST {{base_url}}/admin/login HTTP/1.1
Content-Type: application/json

{
"username": "{{sys_admin}}",
"password": "{{sys_password}}"
}

### 获取文件 bucket 列表

GET {{base_url}}/file/buckets
Content-Type: application/json
Authorization: Bearer {{token}}


### 获取文件列表

GET {{base_url}}/file/public/files?limit=3
Content-Type: application/json
Authorization: Bearer {{token}}

### 删除文件

DELETE {{base_url}}/file/public/61124d425a821711e7b6b95d
Authorization: Bearer {{token}}
7 changes: 6 additions & 1 deletion packages/devops-server/init/sys-permissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,10 @@ exports.permissions = [
{ name: 'deploy_request.delete', label: '删除部署请求' },
{ name: 'deploy_request.apply', label: '应用部署请求' },

{ name: 'deploy.create_token', label: '创建部署令牌' }
{ name: 'deploy.create_token', label: '创建部署令牌' },

{ name: 'file.read', label: '文件管理-读取文件列表' },
{ name: 'file.edit', label: '文件管理-更新文件' },
{ name: 'file.create', label: '文件管理-创建文件' },
{ name: 'file.delete', label: '文件管理-删除文件' },
]
17 changes: 15 additions & 2 deletions packages/devops-server/src/router/admin/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* @Author: Maslow<wangfugen@126.com>
* @Date: 2021-07-30 10:30:29
* @LastEditTime: 2021-08-17 17:03:45
* @LastEditTime: 2021-08-17 18:58:23
* @Description:
*/

Expand Down Expand Up @@ -57,17 +57,30 @@ export async function handleAdminLogin(req: Request, res: Response) {

let debug_token = undefined

// if user has debug function permission
// generate debug token if user has debug function permission
const canDebug = await checkPermission(admin._id, 'function.debug')
if (canDebug === 0) {
debug_token = getToken({ uid: admin._id, type: 'debug', exp: expire }, Config.APP_SERVER_SECRET_SALT)
}

// generate file operation token if user has file manage permission
let file_token = undefined
const canReadFile = await checkPermission(admin._id, 'file.read')
const canCreateFile = await checkPermission(admin._id, 'file.create')
const ops = ['read']
if (canCreateFile === 0) {
ops.push('create')
}
if (canReadFile === 0) {
file_token = getToken({ uid: admin._id, bucket: '*', ops, exp: expire })
}

return res.send({
code: 0,
data: {
access_token,
debug_token,
file_token,
username,
uid: admin._id,
expire
Expand Down
129 changes: 129 additions & 0 deletions packages/devops-server/src/router/file/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* @Author: Maslow<wangfugen@126.com>
* @Date: 2021-07-30 10:30:29
* @LastEditTime: 2021-08-17 19:11:24
* @Description:
*/

import * as express from 'express'
import { checkPermission } from '../../api/permission'
import { DatabaseAgent } from '../../lib/db-agent'
import { logger } from '../../lib/logger'
import { GridFSBucket, ObjectId } from 'mongodb'

const accessor = DatabaseAgent.app_accessor

export const FileRouter = express.Router()

/**
* Get file bucket list
*/
FileRouter.get('/buckets', async (req, res) => {
const requestId = req['requestId']
logger.info(requestId, `get /buckets`)

// check permission
const code = await checkPermission(req['auth']?.uid, 'file.read')
if (code) {
return res.status(code).send()
}

// get all collections in app db
const collections = await accessor.db.listCollections().toArray()
const names = collections.map(coll => coll.name)

// filter bucket collections, if collection's name ends with '.files' and `[collection].chunks` exists
const bucket_collections = names.filter(name => {
if (name.endsWith('.files')) {
return names.includes(name.replace('.files', '.chunks'))
}
return false
})

// get bucket names by trim the collection name
const buckets = bucket_collections.map(name => name.replace('.files', ''))

return res.send({
code: 0,
data: buckets
})
})


/**
* Get file list in bucket
*/
FileRouter.get('/:bucket/files', async (req, res) => {
const bucket = req.params.bucket
const offset = req.query?.offset || 0
const limit = req.query?.limit || 20

const requestId = req['requestId']
logger.info(requestId, `get /${bucket}/files`)

// check permission
const code = await checkPermission(req['auth']?.uid, 'file.read')
if (code) {
return res.status(code).send()
}

try {
// get files from app db
const coll = DatabaseAgent.app_db.collection(`${bucket}.files`)
const { total } = await coll.count()

const r = await coll
.skip(Number(offset))
.limit(Number(limit))
.get()

if (!r.ok) {
return res.send({
code: 1,
error: r.error
})
}

return res.send({
code: 0,
data: r.data,
total,
offset,
limit
})
} catch (err) {
logger.error(requestId, `get files in ${bucket} got error`, err)
return res.status(500).send('Internal Server Error')
}
})

/**
* delete file in bucket by file id
*/
FileRouter.delete('/:bucket/:id', async (req, res) => {
const bucket_name = req.params.bucket
const file_id = req.params.id

const requestId = req['requestId']
logger.info(requestId, `delete /${bucket_name}/${file_id}`)

// check permission
const code = await checkPermission(req['auth']?.uid, 'file.delete')
if (code) {
return res.status(code).send()
}

// delete file
try {
const bucket = new GridFSBucket(accessor.db, { bucketName: bucket_name })
await bucket.delete(new ObjectId(file_id))

return res.send({
code: 0,
data: file_id
})
} catch (error) {
logger.error(requestId, `delete file ${file_id} in ${bucket_name} got error`, error)
return res.status(500).send('Internal Server Error')
}
})
9 changes: 9 additions & 0 deletions packages/devops-server/src/router/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
/*
* @Author: Maslow<wangfugen@126.com>
* @Date: 2021-07-30 10:30:29
* @LastEditTime: 2021-08-17 18:59:52
* @Description:
*/

import { Router } from 'express'
import { AdminRouter } from './admin/index'
import { DevOpsEntryRouter } from './entry'
import { DbmRouter } from './dbm'
import { PublishRouter } from './publish'
import { DatabaseAgent } from '../lib/db-agent'
import { DeployRouter } from './deploy'
import { FileRouter } from './file'

export const router = Router()

Expand All @@ -13,6 +21,7 @@ router.use('/admin', AdminRouter)
router.use('/dbm', DbmRouter)
router.use('/publish', PublishRouter)
router.use('/deploy', DeployRouter)
router.use('/file', FileRouter)

router.use('/health-check', (_req, res) => {
if (!DatabaseAgent.sys_accessor.db || !DatabaseAgent.app_accessor.db) {
Expand Down

0 comments on commit e1221c6

Please sign in to comment.