mirror of
				https://gitee.com/bitdance-team/chrome-extension
				synced 2025-11-04 11:53:10 +08:00 
			
		
		
		
	feat: services
This commit is contained in:
		@@ -2,8 +2,11 @@
 | 
			
		||||
  "root": true,
 | 
			
		||||
  "ignorePatterns": ["**/*"],
 | 
			
		||||
  "plugins": ["@nrwl/nx"],
 | 
			
		||||
  "overrides": [
 | 
			
		||||
    {
 | 
			
		||||
  "rules": {
 | 
			
		||||
    "@typescript-eslint/no-explicit-any": "off",
 | 
			
		||||
    "@typescript-eslint/no-unused-vars": "off"
 | 
			
		||||
  },
 | 
			
		||||
  "overrides": [{
 | 
			
		||||
      "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
 | 
			
		||||
      "rules": {
 | 
			
		||||
        "@nrwl/nx/enforce-module-boundaries": [
 | 
			
		||||
@@ -11,12 +14,10 @@
 | 
			
		||||
          {
 | 
			
		||||
            "enforceBuildableLibDependency": true,
 | 
			
		||||
            "allow": [],
 | 
			
		||||
            "depConstraints": [
 | 
			
		||||
              {
 | 
			
		||||
                "sourceTag": "*",
 | 
			
		||||
                "onlyDependOnLibsWithTags": ["*"]
 | 
			
		||||
              }
 | 
			
		||||
            ]
 | 
			
		||||
            "depConstraints": [{
 | 
			
		||||
              "sourceTag": "*",
 | 
			
		||||
              "onlyDependOnLibsWithTags": ["*"]
 | 
			
		||||
            }]
 | 
			
		||||
          }
 | 
			
		||||
        ]
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,12 +1,12 @@
 | 
			
		||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
 | 
			
		||||
 | 
			
		||||
# compiled output
 | 
			
		||||
/dist
 | 
			
		||||
/tmp
 | 
			
		||||
/out-tsc
 | 
			
		||||
dist
 | 
			
		||||
tmp
 | 
			
		||||
out-tsc
 | 
			
		||||
 | 
			
		||||
# dependencies
 | 
			
		||||
/node_modules
 | 
			
		||||
node_modules
 | 
			
		||||
 | 
			
		||||
# IDEs and editors
 | 
			
		||||
/.idea
 | 
			
		||||
@@ -37,3 +37,5 @@ testem.log
 | 
			
		||||
# System Files
 | 
			
		||||
.DS_Store
 | 
			
		||||
Thumbs.db
 | 
			
		||||
 | 
			
		||||
.inspirecloud.service.conf
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
{
 | 
			
		||||
  "typescript.tsdk": "node_modules\\typescript\\lib"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								jsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								jsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
{
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "module": "commonjs",
 | 
			
		||||
    "target": "es2020",
 | 
			
		||||
    "jsx": "preserve",
 | 
			
		||||
    "strictFunctionTypes": true,
 | 
			
		||||
    "experimentalDecorators": true
 | 
			
		||||
  },
 | 
			
		||||
  "exclude": [
 | 
			
		||||
    "node_modules",
 | 
			
		||||
    "**/node_modules/*"
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3871
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3871
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -10,6 +10,8 @@
 | 
			
		||||
  },
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@byteinspire/api": "^1.0.12",
 | 
			
		||||
    "lodash": "^4.17.21",
 | 
			
		||||
    "tslib": "^2.0.0",
 | 
			
		||||
    "vue": "^3.0.5"
 | 
			
		||||
  },
 | 
			
		||||
@@ -24,6 +26,9 @@
 | 
			
		||||
    "@nrwl/workspace": "13.5.3",
 | 
			
		||||
    "@nx-plus/vite": "^12.2.0",
 | 
			
		||||
    "@types/jest": "27.0.2",
 | 
			
		||||
    "@types/koa": "^2.13.4",
 | 
			
		||||
    "@types/koa__router": "^8.0.11",
 | 
			
		||||
    "@types/lodash": "^4.14.178",
 | 
			
		||||
    "@types/node": "16.11.7",
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": "~5.3.0",
 | 
			
		||||
    "@typescript-eslint/parser": "~5.3.0",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								packages/services-api/.eslintrc.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								packages/services-api/.eslintrc.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
{
 | 
			
		||||
  "extends": ["../../.eslintrc.json"],
 | 
			
		||||
  "ignorePatterns": ["!**/*"],
 | 
			
		||||
  "overrides": [
 | 
			
		||||
    {
 | 
			
		||||
      "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
 | 
			
		||||
      "rules": {}
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "files": ["*.ts", "*.tsx"],
 | 
			
		||||
      "rules": {}
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "files": ["*.js", "*.jsx"],
 | 
			
		||||
      "rules": {}
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								packages/services-api/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								packages/services-api/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
# services-api
 | 
			
		||||
 | 
			
		||||
This library was generated with [Nx](https://nx.dev).
 | 
			
		||||
 | 
			
		||||
## Building
 | 
			
		||||
 | 
			
		||||
Run `nx build services-api` to build the library.
 | 
			
		||||
 | 
			
		||||
## Running unit tests
 | 
			
		||||
 | 
			
		||||
Run `nx test services-api` to execute the unit tests via [Jest](https://jestjs.io).
 | 
			
		||||
							
								
								
									
										14
									
								
								packages/services-api/jest.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								packages/services-api/jest.config.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  displayName: 'services-api',
 | 
			
		||||
  preset: '../../jest.preset.js',
 | 
			
		||||
  globals: {
 | 
			
		||||
    'ts-jest': {
 | 
			
		||||
      tsconfig: '<rootDir>/tsconfig.spec.json',
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  transform: {
 | 
			
		||||
    '^.+\\.[tj]s$': 'ts-jest',
 | 
			
		||||
  },
 | 
			
		||||
  moduleFileExtensions: ['ts', 'js', 'html'],
 | 
			
		||||
  coverageDirectory: '../../coverage/packages/services-api',
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										5
									
								
								packages/services-api/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								packages/services-api/package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@bitdance/services-api",
 | 
			
		||||
  "version": "0.0.1",
 | 
			
		||||
  "type": "commonjs"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								packages/services-api/project.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								packages/services-api/project.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
{
 | 
			
		||||
  "root": "packages/services-api",
 | 
			
		||||
  "sourceRoot": "packages/services-api/src",
 | 
			
		||||
  "projectType": "library",
 | 
			
		||||
  "targets": {
 | 
			
		||||
    "build": {
 | 
			
		||||
      "executor": "@nrwl/js:tsc",
 | 
			
		||||
      "outputs": ["{options.outputPath}"],
 | 
			
		||||
      "options": {
 | 
			
		||||
        "outputPath": "dist/packages/services-api",
 | 
			
		||||
        "main": "packages/services-api/src/index.ts",
 | 
			
		||||
        "tsConfig": "packages/services-api/tsconfig.lib.json",
 | 
			
		||||
        "assets": ["packages/services-api/*.md"]
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "lint": {
 | 
			
		||||
      "executor": "@nrwl/linter:eslint",
 | 
			
		||||
      "outputs": ["{options.outputFile}"],
 | 
			
		||||
      "options": {
 | 
			
		||||
        "lintFilePatterns": ["packages/services-api/**/*.ts"]
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "test": {
 | 
			
		||||
      "executor": "@nrwl/jest:jest",
 | 
			
		||||
      "outputs": ["coverage/packages/services-api"],
 | 
			
		||||
      "options": {
 | 
			
		||||
        "jestConfig": "packages/services-api/jest.config.js",
 | 
			
		||||
        "passWithNoTests": true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "tags": []
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								packages/services-api/src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								packages/services-api/src/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
export * from './lib/services-api';
 | 
			
		||||
							
								
								
									
										7
									
								
								packages/services-api/src/lib/services-api.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								packages/services-api/src/lib/services-api.spec.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
import { servicesApi } from './services-api';
 | 
			
		||||
 | 
			
		||||
describe('servicesApi', () => {
 | 
			
		||||
  it('should work', () => {
 | 
			
		||||
    expect(servicesApi()).toEqual('services-api');
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										3
									
								
								packages/services-api/src/lib/services-api.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								packages/services-api/src/lib/services-api.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
export function servicesApi(): string {
 | 
			
		||||
  return 'services-api';
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								packages/services-api/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								packages/services-api/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
{
 | 
			
		||||
  "extends": "../../tsconfig.base.json",
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "module": "CommonJS",
 | 
			
		||||
    "forceConsistentCasingInFileNames": true,
 | 
			
		||||
    "strict": true,
 | 
			
		||||
    "noImplicitOverride": true,
 | 
			
		||||
    "noPropertyAccessFromIndexSignature": true,
 | 
			
		||||
    "noImplicitReturns": true,
 | 
			
		||||
    "noFallthroughCasesInSwitch": true
 | 
			
		||||
  },
 | 
			
		||||
  "files": [],
 | 
			
		||||
  "include": [],
 | 
			
		||||
  "references": [
 | 
			
		||||
    {
 | 
			
		||||
      "path": "./tsconfig.lib.json"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "path": "./tsconfig.spec.json"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
@@ -1,10 +1,13 @@
 | 
			
		||||
{
 | 
			
		||||
  "extends": ["../../.eslintrc.json"],
 | 
			
		||||
  "ignorePatterns": ["!**/*"],
 | 
			
		||||
  "overrides": [
 | 
			
		||||
    {
 | 
			
		||||
  "overrides": [{
 | 
			
		||||
      "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
 | 
			
		||||
      "rules": {}
 | 
			
		||||
      "rules": {
 | 
			
		||||
        "@typescript-eslint/no-explicit-any": "off",
 | 
			
		||||
        "@typescript-eslint/no-unused-vars": "off",
 | 
			
		||||
        "@typescript-eslint/triple-slash-reference": "off"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "files": ["*.ts", "*.tsx"],
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								packages/services/.inspirecloudignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								packages/services/.inspirecloudignore
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
**/node_modules
 | 
			
		||||
.*/**
 | 
			
		||||
src
 | 
			
		||||
							
								
								
									
										38
									
								
								packages/services/gulpfile.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								packages/services/gulpfile.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
const {src,dest,parallel,watch,series} = require('gulp');
 | 
			
		||||
const ts = require('gulp-typescript');
 | 
			
		||||
const tsProject = ts.createProject("tsconfig.app.json");
 | 
			
		||||
const shell = require('gulp-shell');
 | 
			
		||||
const nodemon = require('gulp-nodemon');
 | 
			
		||||
 | 
			
		||||
function buildTs () {
 | 
			
		||||
  return src('./src/**/*.ts')
 | 
			
		||||
    .pipe(tsProject())
 | 
			
		||||
    .pipe(dest('./dist'));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function start (done) {
 | 
			
		||||
  nodemon({
 | 
			
		||||
    exec: 'inspirecloud dev',
 | 
			
		||||
    ext: 'js,ts',
 | 
			
		||||
    ignore: './dist',
 | 
			
		||||
    delay: 50,
 | 
			
		||||
    tasks: ['buildTs'],
 | 
			
		||||
    done
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function watchServe () {
 | 
			
		||||
  return watch('src/**/*.ts', {
 | 
			
		||||
    delay: 100
 | 
			
		||||
  }, series(buildTs))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function serve () {
 | 
			
		||||
  return series(buildTs, start)()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function deploy () {
 | 
			
		||||
  return series(buildTs, shell.task('inspirecloud deploy'))()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {serve,deploy,buildTs}
 | 
			
		||||
							
								
								
									
										3
									
								
								packages/services/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								packages/services/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
const { app } = require('./dist/app')
 | 
			
		||||
// 导出 HTTP handler, koa 对象不可直接作为 HTTP handler, 需要调用 callback() 获取
 | 
			
		||||
module.exports = app.callback()
 | 
			
		||||
							
								
								
									
										4
									
								
								packages/services/inspirecloud.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								packages/services/inspirecloud.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
{
 | 
			
		||||
  "main": "index.js",
 | 
			
		||||
  "watch": ["index.js"]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5580
									
								
								packages/services/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										5580
									
								
								packages/services/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,5 +1,33 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@bitdance/services",
 | 
			
		||||
  "version": "0.0.1",
 | 
			
		||||
  "type": "commonjs"
 | 
			
		||||
  "type": "commonjs",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "dev": "gulp serve",
 | 
			
		||||
    "deploy": "gulp deploy",
 | 
			
		||||
    "test": "jest"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@byteinspire/api": "^1.0.12",
 | 
			
		||||
    "@byteinspire/cli": "^2.2.23",
 | 
			
		||||
    "@koa/router": "^10.1.1",
 | 
			
		||||
    "koa": "^2.13.4",
 | 
			
		||||
    "koa-body": "^4.2.0",
 | 
			
		||||
    "koa-bunyan-logger": "^2.1.0",
 | 
			
		||||
    "koa-helmet": "^6.1.0",
 | 
			
		||||
    "koa-static": "^5.0.0",
 | 
			
		||||
    "koa-swagger-decorator": "^1.8.2",
 | 
			
		||||
    "koa2-cors": "^2.0.6",
 | 
			
		||||
    "lodash": "^4.17.21"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@types/koa-bunyan-logger": "^2.1.4",
 | 
			
		||||
    "@types/koa2-cors": "^2.0.2",
 | 
			
		||||
    "gulp": "^4.0.2",
 | 
			
		||||
    "gulp-cli": "^2.3.0",
 | 
			
		||||
    "gulp-nodemon": "^2.5.0",
 | 
			
		||||
    "gulp-shell": "^0.8.0",
 | 
			
		||||
    "gulp-typescript": "^6.0.0-alpha.1",
 | 
			
		||||
    "nodemon": "^2.0.15"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,33 +1,4 @@
 | 
			
		||||
{
 | 
			
		||||
  "root": "packages/services",
 | 
			
		||||
  "sourceRoot": "packages/services/src",
 | 
			
		||||
  "projectType": "library",
 | 
			
		||||
  "targets": {
 | 
			
		||||
    "build": {
 | 
			
		||||
      "executor": "@nrwl/js:tsc",
 | 
			
		||||
      "outputs": ["{options.outputPath}"],
 | 
			
		||||
      "options": {
 | 
			
		||||
        "outputPath": "dist/packages/services",
 | 
			
		||||
        "main": "packages/services/src/index.ts",
 | 
			
		||||
        "tsConfig": "packages/services/tsconfig.lib.json",
 | 
			
		||||
        "assets": ["packages/services/*.md"]
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "lint": {
 | 
			
		||||
      "executor": "@nrwl/linter:eslint",
 | 
			
		||||
      "outputs": ["{options.outputFile}"],
 | 
			
		||||
      "options": {
 | 
			
		||||
        "lintFilePatterns": ["packages/services/**/*.ts"]
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "test": {
 | 
			
		||||
      "executor": "@nrwl/jest:jest",
 | 
			
		||||
      "outputs": ["coverage/packages/services"],
 | 
			
		||||
      "options": {
 | 
			
		||||
        "jestConfig": "packages/services/jest.config.js",
 | 
			
		||||
        "passWithNoTests": true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "tags": []
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										55
									
								
								packages/services/src/app.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								packages/services/src/app.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
import Koa from 'koa'
 | 
			
		||||
import koaBody from 'koa-body';
 | 
			
		||||
import router from './router';
 | 
			
		||||
import helmet from 'koa-helmet'
 | 
			
		||||
import koaBunyanLogger from 'koa-bunyan-logger'
 | 
			
		||||
import koaCors from 'koa2-cors';
 | 
			
		||||
import { errorHandler } from './utils/response'
 | 
			
		||||
 | 
			
		||||
const app = new Koa();
 | 
			
		||||
 | 
			
		||||
// 跨域请求设置
 | 
			
		||||
app.use(koaCors({
 | 
			
		||||
  origin: function (ctx) { //设置允许来自指定域名请求
 | 
			
		||||
    return '*'
 | 
			
		||||
  },
 | 
			
		||||
  maxAge: 5, //指定本次预检请求的有效期,单位为秒。
 | 
			
		||||
  credentials: true, //是否允许发送Cookie
 | 
			
		||||
  allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], //设置所允许的HTTP请求方法'
 | 
			
		||||
  allowHeaders: ['Content-Type', 'Authorization', 'Accept', 'x-tt-session-v2'], //设置服务器支持的所有头信息字段
 | 
			
		||||
  exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'] //设置获取其他自定义字段
 | 
			
		||||
}))
 | 
			
		||||
 | 
			
		||||
// 过滤不安全的请求内容
 | 
			
		||||
// app.use(helmet.contentSecurityPolicy());
 | 
			
		||||
app.use(helmet.dnsPrefetchControl());
 | 
			
		||||
app.use(helmet.expectCt());
 | 
			
		||||
app.use(helmet.frameguard());
 | 
			
		||||
app.use(helmet.hidePoweredBy());
 | 
			
		||||
app.use(helmet.hsts());
 | 
			
		||||
app.use(helmet.ieNoOpen());
 | 
			
		||||
app.use(helmet.noSniff());
 | 
			
		||||
app.use(helmet.permittedCrossDomainPolicies());
 | 
			
		||||
app.use(helmet.referrerPolicy());
 | 
			
		||||
app.use(helmet.xssFilter());
 | 
			
		||||
 | 
			
		||||
// 解析不同类别的请求
 | 
			
		||||
app.use(koaBody({
 | 
			
		||||
  multipart: true,
 | 
			
		||||
  formidable: {
 | 
			
		||||
    maxFileSize: 30 * 1024 * 1024
 | 
			
		||||
  }
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
// 请求日志
 | 
			
		||||
app.use(koaBunyanLogger());
 | 
			
		||||
app.use(koaBunyanLogger.requestIdContext());
 | 
			
		||||
app.use(koaBunyanLogger.requestLogger());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// 若后面的路由抛错,则封装为错误响应返回
 | 
			
		||||
app.use(errorHandler);
 | 
			
		||||
 | 
			
		||||
// 为应用使用路由定义
 | 
			
		||||
app.use(router.routes()).use(router.allowedMethods());
 | 
			
		||||
export { app }
 | 
			
		||||
							
								
								
									
										56
									
								
								packages/services/src/controllers/auth.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								packages/services/src/controllers/auth.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
import { getCurrentUser, login, logout, register } from '../services/user';
 | 
			
		||||
import { Context, description, middlewares, request, security, securityAll, summary, swaggerClass, swaggerProperty, tagsAll } from 'koa-swagger-decorator';
 | 
			
		||||
import { authenticate, swaggerBody } from '../utils/swagger';
 | 
			
		||||
import { isNil } from 'lodash';
 | 
			
		||||
import { authentication } from '../utils/response';
 | 
			
		||||
@swaggerClass()
 | 
			
		||||
export class LoginRegDto {
 | 
			
		||||
  @swaggerProperty({ type: "string", required: true }) username = "";
 | 
			
		||||
  @swaggerProperty({ type: "string", required: true }) password = "";
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@tagsAll('认证系统')
 | 
			
		||||
export default class Auth {
 | 
			
		||||
 | 
			
		||||
  @request('POST', '/auth/register')
 | 
			
		||||
  @summary('注册一个用户')
 | 
			
		||||
  @swaggerBody(LoginRegDto)
 | 
			
		||||
  static async register(ctx: Context) {
 | 
			
		||||
    const params = ctx.validatedBody as LoginRegDto;
 | 
			
		||||
    const data = await register(
 | 
			
		||||
      ctx,
 | 
			
		||||
      params.username,
 | 
			
		||||
      params.password
 | 
			
		||||
    );
 | 
			
		||||
    ctx.body = { code: 200, msg: '' }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @request('POST', '/auth/login')
 | 
			
		||||
  @summary('登录一个用户')
 | 
			
		||||
  @swaggerBody(LoginRegDto)
 | 
			
		||||
  static async login(ctx: Context) {
 | 
			
		||||
    const params = ctx.validatedBody as LoginRegDto;
 | 
			
		||||
    const data = await login(
 | 
			
		||||
      ctx,
 | 
			
		||||
      params.username,
 | 
			
		||||
      params.password
 | 
			
		||||
    );
 | 
			
		||||
    ctx.body = { code: 200, msg: '' }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @request('GET', '/auth/info')
 | 
			
		||||
  @summary('获取当前的用户信息')
 | 
			
		||||
  @authenticate
 | 
			
		||||
  static async info(ctx: Context) {
 | 
			
		||||
    const data = await getCurrentUser(ctx)
 | 
			
		||||
    ctx.body = { code: 200, msg: '', data };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @request('POST', '/auth/logout')
 | 
			
		||||
  @summary('登出当前系统')
 | 
			
		||||
  @security([{ session: [] }])
 | 
			
		||||
  static async logout(ctx: Context) {
 | 
			
		||||
    await logout(ctx)
 | 
			
		||||
    ctx.body = { code: 200, msg: '' };
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								packages/services/src/controllers/files.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								packages/services/src/controllers/files.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
import { getCurrentUser, login, logout, register } from '../services/user';
 | 
			
		||||
import { Context, description, middlewares, formData, request, security, securityAll, summary, swaggerClass, swaggerProperty, tagsAll } from 'koa-swagger-decorator';
 | 
			
		||||
import { swaggerBody } from '../utils/swagger';
 | 
			
		||||
import { isArray, isNil, uniqueId } from 'lodash';
 | 
			
		||||
import { authentication } from '../utils/response';
 | 
			
		||||
import { uploadFile } from '../services/files';
 | 
			
		||||
import { readFileSync } from 'fs'
 | 
			
		||||
 | 
			
		||||
@tagsAll('文件系统')
 | 
			
		||||
export default class RemoteFile {
 | 
			
		||||
 | 
			
		||||
  @request('POST', '/files')
 | 
			
		||||
  @summary('上传文件')
 | 
			
		||||
  @formData({ file: { type: 'file', required: true, description: '文件内容' } })
 | 
			
		||||
  @security([{ session: [] }])
 | 
			
		||||
  @middlewares([authentication])
 | 
			
		||||
  static async upload(ctx: Context) {
 | 
			
		||||
    const file = ctx.request.files?.['file']
 | 
			
		||||
 | 
			
		||||
    if (isNil(file)) throw { code: 400, msg: '未上传任何文件' }
 | 
			
		||||
    if (isArray(file)) throw { code: 400, msg: '只能上传一个文件' }
 | 
			
		||||
 | 
			
		||||
    const content = readFileSync(file.path)
 | 
			
		||||
    const data = await uploadFile(file.name || uniqueId('file'), content)
 | 
			
		||||
 | 
			
		||||
    ctx.body = { code: 200, msg: '', data }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								packages/services/src/controllers/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								packages/services/src/controllers/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
import { Context, description, middlewares, request, security, summary, swaggerClass, swaggerProperty, tagsAll } from 'koa-swagger-decorator';
 | 
			
		||||
import { authentication } from '../utils/response';
 | 
			
		||||
import { authenticate, swaggerBody } from '../utils/swagger';
 | 
			
		||||
 | 
			
		||||
@tagsAll('测试')
 | 
			
		||||
export default class Index {
 | 
			
		||||
  @request('GET', '/test')
 | 
			
		||||
  @summary('测试服务器是否正常')
 | 
			
		||||
  static async test(ctx: Context) {
 | 
			
		||||
    ctx.body = { code: 200, msg: '', data: new Date() }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @request('GET', '/authtest')
 | 
			
		||||
  @summary('测试服务器是否正常')
 | 
			
		||||
  @authenticate
 | 
			
		||||
  static async authtest(ctx: Context) {
 | 
			
		||||
    ctx.body = { code: 200, msg: '', data: new Date() }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								packages/services/src/controllers/memo.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								packages/services/src/controllers/memo.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
import { getCurrentUser } from './../services/user';
 | 
			
		||||
import { Context, description, middlewares, path, request, security, summary, swaggerClass, swaggerProperty, tagsAll } from 'koa-swagger-decorator';
 | 
			
		||||
import { authentication } from '../utils/response';
 | 
			
		||||
import { authenticate, swaggerBody } from '../utils/swagger';
 | 
			
		||||
import { ObjectId, UserContext } from '../models/base';
 | 
			
		||||
import memoService from '../services/memo';
 | 
			
		||||
import { multipageHttpQuery } from '../utils/multipage';
 | 
			
		||||
import { User } from '../models/user';
 | 
			
		||||
 | 
			
		||||
export class CreateMemoDto {
 | 
			
		||||
  @swaggerProperty({ type: "string", required: true }) content = "";
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@tagsAll('备忘录')
 | 
			
		||||
export default class Memo {
 | 
			
		||||
 | 
			
		||||
  @request('GET', '/memos')
 | 
			
		||||
  @summary('获取个人所有的备忘录')
 | 
			
		||||
  @authenticate
 | 
			
		||||
  @multipageHttpQuery()
 | 
			
		||||
  static async getAll(ctx: UserContext) {
 | 
			
		||||
    const data = await memoService.findByUserPage(ctx.user._id, ctx.validatedQuery)
 | 
			
		||||
    ctx.body = { code: 200, msg: '', data }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @request('POST', '/memos')
 | 
			
		||||
  @summary('创建一个备忘录')
 | 
			
		||||
  @authenticate
 | 
			
		||||
  @swaggerBody(CreateMemoDto)
 | 
			
		||||
  static async createOne(ctx: UserContext) {
 | 
			
		||||
    // ctx.user 获取的只是一个JSON字段,不支持数据库关联
 | 
			
		||||
    const user = await memoService.db.table<User>('_user').where({ _id: new ObjectId(ctx.user._id) }).projection({ username: 1, lastLogin: 1, status: 1 }).findOne()
 | 
			
		||||
 | 
			
		||||
    const data = await memoService.createOne({
 | 
			
		||||
      content: ctx.validatedBody.content,
 | 
			
		||||
      user
 | 
			
		||||
    })
 | 
			
		||||
    ctx.body = { code: 200, msg: '', data }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @request('DELETE', '/memos/{id}')
 | 
			
		||||
  @summary('删除一个备忘录')
 | 
			
		||||
  @authenticate
 | 
			
		||||
  @path({ id: { type: 'string', required: true, description: 'ID' } })
 | 
			
		||||
  static async deleteOne(ctx: UserContext) {
 | 
			
		||||
    await memoService.deleteOne(ctx.validatedParams.id)
 | 
			
		||||
    ctx.body = { code: 200, msg: '' }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
export * from './lib/services';
 | 
			
		||||
@@ -1,7 +0,0 @@
 | 
			
		||||
import { services } from './services';
 | 
			
		||||
 | 
			
		||||
describe('services', () => {
 | 
			
		||||
  it('should work', () => {
 | 
			
		||||
    expect(services()).toEqual('services');
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
@@ -1,3 +0,0 @@
 | 
			
		||||
export function services(): string {
 | 
			
		||||
  return 'services';
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								packages/services/src/models/base.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								packages/services/src/models/base.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
import { Context } from 'koa-swagger-decorator';
 | 
			
		||||
export type WithId<T extends object> = T & { _id: string }
 | 
			
		||||
 | 
			
		||||
import inspirecloud from '@byteinspire/api';
 | 
			
		||||
import { User } from './user';
 | 
			
		||||
 | 
			
		||||
export const ObjectId = inspirecloud.db.ObjectId
 | 
			
		||||
 | 
			
		||||
export type ObjectIdType = InstanceType<typeof ObjectId>
 | 
			
		||||
 | 
			
		||||
export interface PageQuery { page: number, pageSize: number }
 | 
			
		||||
 | 
			
		||||
export interface UserContext extends Context {
 | 
			
		||||
  user: WithId<User>
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								packages/services/src/models/memo.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								packages/services/src/models/memo.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import { IEntity } from '@byteinspire/db';
 | 
			
		||||
import { User } from './user';
 | 
			
		||||
import { ObjectIdType } from './base';
 | 
			
		||||
 | 
			
		||||
export interface Memo {
 | 
			
		||||
  content: string;
 | 
			
		||||
  user: User
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										17
									
								
								packages/services/src/models/user.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								packages/services/src/models/user.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
export interface User {
 | 
			
		||||
  avatar: string | null;
 | 
			
		||||
  email: string | null;
 | 
			
		||||
  phoneNumber: string | null;
 | 
			
		||||
  intro: string | null;
 | 
			
		||||
  lastLogin: number;
 | 
			
		||||
  loginCount: number;
 | 
			
		||||
  lastIp: string;
 | 
			
		||||
  status: boolean;
 | 
			
		||||
  createAt: number;
 | 
			
		||||
  createdAt: number;
 | 
			
		||||
  updatedAt: number;
 | 
			
		||||
  username: string;
 | 
			
		||||
  firstProvider: string;
 | 
			
		||||
  loginAt: number;
 | 
			
		||||
  expireAt: number;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								packages/services/src/router.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								packages/services/src/router.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
import '@koa/router'
 | 
			
		||||
 | 
			
		||||
import { SwaggerRouter } from 'koa-swagger-decorator'
 | 
			
		||||
import path from 'path'
 | 
			
		||||
 | 
			
		||||
const router = new SwaggerRouter({ prefix: '/api' }) // extends from koa-router
 | 
			
		||||
 | 
			
		||||
// swagger docs avaliable at http://localhost:3000/api/swagger-html
 | 
			
		||||
router.swagger({
 | 
			
		||||
  title: 'BitDance浏览器插件后台服务',
 | 
			
		||||
  description: '请求认证头为 `x-tt-session-v2`',
 | 
			
		||||
  version: '1.0.0',
 | 
			
		||||
  prefix: '/api',
 | 
			
		||||
  swaggerHtmlEndpoint: '/swagger-html',
 | 
			
		||||
  swaggerJsonEndpoint: '/swagger-json',
 | 
			
		||||
  swaggerOptions: {
 | 
			
		||||
    securityDefinitions: {
 | 
			
		||||
      session: {
 | 
			
		||||
        type: 'apiKey',
 | 
			
		||||
        in: 'header',
 | 
			
		||||
        name: 'x-tt-session-v2',
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// mapDir will scan the input dir, and automatically call router.map to all Router Class
 | 
			
		||||
router.mapDir(path.resolve(__dirname, 'controllers'), {
 | 
			
		||||
  ignore: ["**.spec.ts", "**.d.ts"],
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export default router
 | 
			
		||||
							
								
								
									
										108
									
								
								packages/services/src/services/base.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								packages/services/src/services/base.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
import { isNil } from 'lodash';
 | 
			
		||||
import { IEntity, ITable, API } from '@byteinspire/db';
 | 
			
		||||
import { Memo } from '../models/memo';
 | 
			
		||||
import { Context } from 'koa-swagger-decorator';
 | 
			
		||||
import inspirecloud from '@byteinspire/api'
 | 
			
		||||
import { multipageDbQuery } from '../utils/multipage';
 | 
			
		||||
import { PageQuery, ObjectIdType, ObjectId } from '../models/base';
 | 
			
		||||
 | 
			
		||||
export default class BaseDbService<T> {
 | 
			
		||||
  table: ITable<T>
 | 
			
		||||
  db: API = inspirecloud.db
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   *
 | 
			
		||||
   * @param name 表名
 | 
			
		||||
   */
 | 
			
		||||
  constructor(name: string) {
 | 
			
		||||
    this.table = inspirecloud.db.table<T>(name)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 查找多个
 | 
			
		||||
   * @returns
 | 
			
		||||
   */
 | 
			
		||||
  findMany(query: any): Promise<(T & IEntity)[]> {
 | 
			
		||||
    return query.find()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 查找全部
 | 
			
		||||
   * @returns
 | 
			
		||||
   */
 | 
			
		||||
  findAll(): Promise<(T & IEntity)[]> {
 | 
			
		||||
    return this.findMany(this.table.where())
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 查找单个
 | 
			
		||||
   * @returns
 | 
			
		||||
   */
 | 
			
		||||
  findOne(id: string): Promise<(T & IEntity)> {
 | 
			
		||||
    const result = this.table.where({ _id: new ObjectId(id) }).findOne()
 | 
			
		||||
    if (isNil(result)) throw { status: 404, message: 'Not Found' }
 | 
			
		||||
    return result
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 分页查找
 | 
			
		||||
   * @returns
 | 
			
		||||
   */
 | 
			
		||||
  findPage(pageArg: PageQuery, query: any) {
 | 
			
		||||
    return multipageDbQuery(pageArg, query)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 分页全部查找
 | 
			
		||||
   * @param pageArg
 | 
			
		||||
   * @returns
 | 
			
		||||
   */
 | 
			
		||||
  findAllPage(pageArg: PageQuery) {
 | 
			
		||||
    return this.findPage(pageArg, this.table.where())
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 创建单个
 | 
			
		||||
   * @returns
 | 
			
		||||
   */
 | 
			
		||||
  createOne(item: T): Promise<(T & IEntity)> {
 | 
			
		||||
    return this.table.save(item)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 更新单个
 | 
			
		||||
   * @returns
 | 
			
		||||
   */
 | 
			
		||||
  async updateOne(item: Partial<T> & { _id: string }): Promise<T & IEntity> {
 | 
			
		||||
    const result = await this.findOne(item._id)
 | 
			
		||||
 | 
			
		||||
    for (const [k, v] of Object.entries(item) as [keyof (T & IEntity), any][]) {
 | 
			
		||||
      if (k === '_id' || k === 'createdAt' || k === 'updatedAt') continue
 | 
			
		||||
      result[k] = v
 | 
			
		||||
    }
 | 
			
		||||
    return this.table.save(result)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 删除数据
 | 
			
		||||
   * @param id
 | 
			
		||||
   */
 | 
			
		||||
  async deleteOne(id: string) {
 | 
			
		||||
    const result = await this.table.where({ _id: new ObjectId(id) }).findOne()
 | 
			
		||||
    if (isNil(result)) throw { status: 404, message: 'Not Found' }
 | 
			
		||||
    return await this.table.delete([result])
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 删除多个数据
 | 
			
		||||
   * @param ids
 | 
			
		||||
   * @returns 成功删除数据的数目
 | 
			
		||||
   */
 | 
			
		||||
  async deleteMany(ids: string[]) {
 | 
			
		||||
    const result = await this.table.where({ _id: this.db.in(ids) }).find()
 | 
			
		||||
    const delRes = await this.table.delete(result)
 | 
			
		||||
    return (delRes as any).deletedCount
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								packages/services/src/services/files.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								packages/services/src/services/files.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
import inspirecloud from '@byteinspire/api';
 | 
			
		||||
 | 
			
		||||
const fileService = inspirecloud.file
 | 
			
		||||
 | 
			
		||||
const uploadFile = fileService.upload.bind(fileService) as any as (
 | 
			
		||||
  name: string,
 | 
			
		||||
  buffer: Buffer | string | { url: string },
 | 
			
		||||
) => Promise<{ url: string; id: string }>;
 | 
			
		||||
 | 
			
		||||
const downloadFile = fileService.download.bind(fileService)
 | 
			
		||||
 | 
			
		||||
const removeFile = fileService.delete.bind(fileService)
 | 
			
		||||
 | 
			
		||||
export { uploadFile, downloadFile, removeFile }
 | 
			
		||||
							
								
								
									
										19
									
								
								packages/services/src/services/memo.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								packages/services/src/services/memo.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
import { getCurrentUser } from './user';
 | 
			
		||||
import { ObjectId } from './../models/base';
 | 
			
		||||
import { Memo } from './../models/memo';
 | 
			
		||||
import BaseDbService from './base'
 | 
			
		||||
import { IEntity, ITable, API } from '@byteinspire/db';
 | 
			
		||||
import { PageQuery } from '../models/base';
 | 
			
		||||
 | 
			
		||||
class MemoService extends BaseDbService<Memo> {
 | 
			
		||||
  findByUserPage(uid: string, pageArg: PageQuery) {
 | 
			
		||||
    return this.findPage(pageArg, this.table.where({ user: new ObjectId(uid) }).populate({
 | 
			
		||||
      ref: 'user',
 | 
			
		||||
      projection: ['_id', 'username', 'nickname', 'lastLogin', 'status']
 | 
			
		||||
    } as any))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const memoService = new MemoService('memo')
 | 
			
		||||
 | 
			
		||||
export default memoService
 | 
			
		||||
							
								
								
									
										25
									
								
								packages/services/src/services/user.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								packages/services/src/services/user.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
import { User } from './../models/user';
 | 
			
		||||
import { WithId } from '../models/base';
 | 
			
		||||
import { Context } from 'koa-swagger-decorator';
 | 
			
		||||
import inspirecloud from '@byteinspire/api';
 | 
			
		||||
import { isNil } from 'lodash';
 | 
			
		||||
 | 
			
		||||
const userService = (inspirecloud as any).user
 | 
			
		||||
 | 
			
		||||
export const login = userService.login as (ctx: Context, username: string, password: string) => Promise<undefined>
 | 
			
		||||
 | 
			
		||||
export const register = userService.register as (ctx: Context, username: string, password: string) => Promise<undefined>
 | 
			
		||||
 | 
			
		||||
export const getCurrentUser = userService.current as (ctx: Context) => Promise<WithId<User> | undefined>
 | 
			
		||||
 | 
			
		||||
export const logout = userService.logout as (ctx: Context) => Promise<undefined>
 | 
			
		||||
 | 
			
		||||
export const updateNewPassword = userService.changePassword as (context: Context, newPassword: string, originPassword?: string) => Promise<any>;
 | 
			
		||||
 | 
			
		||||
export async function isLogin(ctx: Context) {
 | 
			
		||||
  try {
 | 
			
		||||
    return !isNil(await getCurrentUser(ctx))
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    return false
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								packages/services/src/utils/multipage.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								packages/services/src/utils/multipage.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
import { Context, query } from 'koa-swagger-decorator';
 | 
			
		||||
import { PageQuery } from '../models/base';
 | 
			
		||||
 | 
			
		||||
// 用于分页的数据库查询辅助函数
 | 
			
		||||
export async function multipageDbQuery<T = any>(pageArg: PageQuery, query: any) {
 | 
			
		||||
  const { page = 1, pageSize = 10 } = pageArg
 | 
			
		||||
 | 
			
		||||
  if (page < 1 || pageSize < 1) throw { status: 400, message: '分页参数不合法' }
 | 
			
		||||
 | 
			
		||||
  const total = await query.count();
 | 
			
		||||
  const content = await query.skip((page - 1) * pageSize).limit(pageSize).find();
 | 
			
		||||
  return {
 | 
			
		||||
    total,
 | 
			
		||||
    page,
 | 
			
		||||
    pageSize,
 | 
			
		||||
    content: (content || []) as T[]
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//用于分页的HTTP Query查询
 | 
			
		||||
export function multipageHttpQuery() {
 | 
			
		||||
  return query(
 | 
			
		||||
    {
 | 
			
		||||
      page: { type: 'number', required: false, default: 1, description: 'type' },
 | 
			
		||||
      pageSize: { type: 'number', required: false, default: 10, description: 'type' }
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								packages/services/src/utils/response.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								packages/services/src/utils/response.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
import { Context } from 'koa-swagger-decorator';
 | 
			
		||||
import { UserContext } from '../models/base';
 | 
			
		||||
import { getCurrentUser, isLogin } from '../services/user';
 | 
			
		||||
 | 
			
		||||
// 处理请求中的错误
 | 
			
		||||
export async function errorHandler(ctx: Context, next: any) {
 | 
			
		||||
  try {
 | 
			
		||||
    await next();
 | 
			
		||||
  } catch (err) {
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
			
		||||
    const error = err as any
 | 
			
		||||
    // 抛出的错误可以附带 status 字段,代表 http 状态码
 | 
			
		||||
    // 若没有提供,则默认状态码为 500,代表服务器内部错误
 | 
			
		||||
    ctx.status = error.status || 500;
 | 
			
		||||
    ctx.body = { code: ctx.status, msg: error.message };
 | 
			
		||||
    console.error(err)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 对当前的请求进行登录验证,并注入用户信息到 ctx.user
 | 
			
		||||
 * @param ctx 请求上下文
 | 
			
		||||
 * @param next
 | 
			
		||||
 */
 | 
			
		||||
export async function authentication(ctx: UserContext, next: any) {
 | 
			
		||||
  try {
 | 
			
		||||
    const user = await getCurrentUser(ctx)
 | 
			
		||||
    if (!user) throw ""
 | 
			
		||||
    ctx.user = user
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error(error)
 | 
			
		||||
    throw { status: 401, message: "用户未登录" }
 | 
			
		||||
  }
 | 
			
		||||
  await next()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								packages/services/src/utils/swagger.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								packages/services/src/utils/swagger.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
import { body, security } from 'koa-swagger-decorator'
 | 
			
		||||
import { authentication } from './response'
 | 
			
		||||
 | 
			
		||||
export function swaggerDocument(cls: any) {
 | 
			
		||||
  return (cls as any).swaggerDocument
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function swaggerBody<T extends object>(cls: T) {
 | 
			
		||||
  return body(swaggerDocument(cls))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function authenticate(
 | 
			
		||||
  target: any,
 | 
			
		||||
  name: string,
 | 
			
		||||
  descriptor: PropertyDescriptor
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
  if (!descriptor.value.middlewares) descriptor.value.middlewares = []
 | 
			
		||||
  descriptor.value.middlewares.push(authentication)
 | 
			
		||||
 | 
			
		||||
  // call other decorators
 | 
			
		||||
  security([{ session: [] }])(target, name, descriptor)
 | 
			
		||||
  return descriptor;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										10
									
								
								packages/services/tsconfig.app.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								packages/services/tsconfig.app.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
{
 | 
			
		||||
  "extends": "./tsconfig.json",
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "outDir": "./dist",
 | 
			
		||||
    "experimentalDecorators": true,
 | 
			
		||||
    "types": []
 | 
			
		||||
  },
 | 
			
		||||
  "include": ["./src/**/*.ts"],
 | 
			
		||||
  "exclude": ["**/*.spec.ts"]
 | 
			
		||||
}
 | 
			
		||||
@@ -5,18 +5,18 @@
 | 
			
		||||
    "forceConsistentCasingInFileNames": true,
 | 
			
		||||
    "strict": true,
 | 
			
		||||
    "noImplicitOverride": true,
 | 
			
		||||
    "strictFunctionTypes": false,
 | 
			
		||||
    "experimentalDecorators": true,
 | 
			
		||||
    "noPropertyAccessFromIndexSignature": true,
 | 
			
		||||
    "noImplicitReturns": true,
 | 
			
		||||
    "noFallthroughCasesInSwitch": true
 | 
			
		||||
    "noFallthroughCasesInSwitch": true,
 | 
			
		||||
    "declaration": true,
 | 
			
		||||
    "emitDecoratorMetadata": true,
 | 
			
		||||
    "esModuleInterop": true
 | 
			
		||||
  },
 | 
			
		||||
  "files": [],
 | 
			
		||||
  "include": [],
 | 
			
		||||
  "references": [
 | 
			
		||||
    {
 | 
			
		||||
      "path": "./tsconfig.lib.json"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "path": "./tsconfig.spec.json"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
  // "files": [],
 | 
			
		||||
  "include": ["src/**/*.ts"],
 | 
			
		||||
  "references": [{
 | 
			
		||||
    "path": "./tsconfig.app.json"
 | 
			
		||||
  }]
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
    "composite": true,
 | 
			
		||||
    "sourceMap": true,
 | 
			
		||||
    "declaration": false,
 | 
			
		||||
    "esModuleInterop": true,
 | 
			
		||||
    "moduleResolution": "node",
 | 
			
		||||
    "emitDecoratorMetadata": true,
 | 
			
		||||
    "experimentalDecorators": true,
 | 
			
		||||
@@ -16,7 +17,7 @@
 | 
			
		||||
    "skipDefaultLibCheck": true,
 | 
			
		||||
    "baseUrl": ".",
 | 
			
		||||
    "paths": {
 | 
			
		||||
      "@bitdance/services": ["packages/services/src/index.ts"],
 | 
			
		||||
      "@bitdance/services-api": ["packages/services-api/src/index.ts"],
 | 
			
		||||
      "@bitdance/shared": ["packages/shared/src/index.ts"]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
  "projects": {
 | 
			
		||||
    "plugin-ui": "packages/plugin-ui",
 | 
			
		||||
    "services": "packages/services",
 | 
			
		||||
    "services-api": "packages/services-api",
 | 
			
		||||
    "shared": "packages/shared",
 | 
			
		||||
    "shell-chrome": "packages\\shell-chrome"
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user