diff --git a/back/api/subscription.ts b/back/api/subscription.ts index 28fcdd12..adcdef4c 100644 --- a/back/api/subscription.ts +++ b/back/api/subscription.ts @@ -28,17 +28,16 @@ export default (app: Router) => { celebrate({ body: Joi.object({ type: Joi.string().required(), - schedule: Joi.string().optional(), - interval_schedule: Joi.object().optional(), - name: Joi.string().optional(), + schedule: Joi.string().optional().allow('').allow(null), + interval_schedule: Joi.object().optional().allow('').allow(null), + name: Joi.string().optional().allow('').allow(null), url: Joi.string().required(), - whitelist: Joi.string().optional(), - blacklist: Joi.string().optional(), - branch: Joi.string().optional(), - dependences: Joi.string().optional(), - status: Joi.number().optional(), - pull_type: Joi.string().optional(), - pull_option: Joi.object().optional(), + whitelist: Joi.string().optional().allow('').allow(null), + blacklist: Joi.string().optional().allow('').allow(null), + branch: Joi.string().optional().allow('').allow(null), + dependences: Joi.string().optional().allow('').allow(null), + pull_type: Joi.string().optional().allow('').allow(null), + pull_option: Joi.object().optional().allow('').allow(null), schedule_type: Joi.string().required(), alias: Joi.string().required(), }), @@ -157,18 +156,17 @@ export default (app: Router) => { celebrate({ body: Joi.object({ type: Joi.string().required(), - schedule: Joi.string().optional(), - interval_schedule: Joi.object().optional(), - name: Joi.string().optional(), + schedule: Joi.string().optional().allow('').allow(null), + interval_schedule: Joi.object().optional().allow('').allow(null), + name: Joi.string().optional().allow('').allow(null), url: Joi.string().required(), - whitelist: Joi.string().optional(), - blacklist: Joi.string().optional(), - branch: Joi.string().optional(), - dependences: Joi.string().optional(), - status: Joi.number().optional(), - pull_type: Joi.string().optional(), - pull_option: Joi.object().optional(), - schedule_type: Joi.string().optional(), + whitelist: Joi.string().optional().allow('').allow(null), + blacklist: Joi.string().optional().allow('').allow(null), + branch: Joi.string().optional().allow('').allow(null), + dependences: Joi.string().optional().allow('').allow(null), + pull_type: Joi.string().optional().allow('').allow(null), + pull_option: Joi.object().optional().allow('').allow(null), + schedule_type: Joi.string().optional().allow('').allow(null), alias: Joi.string().required(), id: Joi.number().required(), }), diff --git a/back/loaders/express.ts b/back/loaders/express.ts index a216a909..423b4e82 100644 --- a/back/loaders/express.ts +++ b/back/loaders/express.ts @@ -13,6 +13,7 @@ import UserService from '../services/user'; import handler from 'serve-handler'; import * as Sentry from '@sentry/node'; import { EnvModel } from '../data/env'; +import { errors } from 'celebrate'; export default ({ app }: { app: Application }) => { app.enable('trust proxy'); @@ -134,6 +135,7 @@ export default ({ app }: { app: Application }) => { next(err); }); + app.use(errors()); app.use(Sentry.Handlers.errorHandler()); app.use( diff --git a/back/loaders/initFile.ts b/back/loaders/initFile.ts index aa6f1338..464a0663 100644 --- a/back/loaders/initFile.ts +++ b/back/loaders/initFile.ts @@ -1,5 +1,6 @@ import fs from 'fs'; import path from 'path'; +import os from 'os'; import dotenv from 'dotenv'; import Logger from './logger'; import { fileExist } from '../config/util'; @@ -15,6 +16,8 @@ const confFile = path.join(configPath, 'config.sh'); const authConfigFile = path.join(configPath, 'auth.json'); const sampleConfigFile = path.join(samplePath, 'config.sample.sh'); const sampleAuthFile = path.join(samplePath, 'auth.sample.json'); +const homedir = os.homedir(); +const sshPath = path.resolve(homedir, '.ssh'); export default async () => { const authFileExist = await fileExist(authConfigFile); @@ -23,6 +26,7 @@ export default async () => { const logDirExist = await fileExist(logPath); const configDirExist = await fileExist(configPath); const uploadDirExist = await fileExist(uploadPath); + const sshDirExist = await fileExist(sshPath); if (!configDirExist) { fs.mkdirSync(configPath); @@ -48,6 +52,10 @@ export default async () => { fs.mkdirSync(uploadPath); } + if (!sshDirExist) { + fs.mkdirSync(sshPath); + } + dotenv.config({ path: confFile }); Logger.info('✌️ Init file down'); diff --git a/back/services/subscription.ts b/back/services/subscription.ts index 215e0ad9..07e00ef3 100644 --- a/back/services/subscription.ts +++ b/back/services/subscription.ts @@ -27,6 +27,7 @@ import path from 'path'; import ScheduleService, { TaskCallbacks } from './schedule'; import { SimpleIntervalSchedule } from 'toad-scheduler'; import SockService from './sock'; +import SshKeyService from './sshKey'; @Service() export default class SubscriptionService { @@ -34,6 +35,7 @@ export default class SubscriptionService { @Inject('logger') private logger: winston.Logger, private scheduleService: ScheduleService, private sockService: SockService, + private sshKeyService: SshKeyService, ) {} public async list(searchText?: string): Promise { @@ -92,21 +94,44 @@ export default class SubscriptionService { } } - private formatCommand(doc: Subscription) { + private formatCommand(doc: Subscription, url?: string) { let command = 'ql '; - const { type, url, whitelist, blacklist, dependences, branch } = doc; + let _url = url || doc.url; + const { type, whitelist, blacklist, dependences, branch } = doc; if (type === 'file') { - command += `raw "${url}"`; + command += `raw "${_url}"`; } else { - command += `repo "${url}" "${whitelist || ''}" "${blacklist || ''}" "${ + command += `repo "${_url}" "${whitelist || ''}" "${blacklist || ''}" "${ dependences || '' }" "${branch || ''}"`; } return command; } - private handleTask(doc: Subscription, needCreate = true) { - doc.command = this.formatCommand(doc); + private handleTask(doc: Subscription, needCreate = true, needAddKey = true) { + let url = doc.url; + if (doc.type === 'private-repo') { + if (doc.pull_type === 'ssh-key') { + const host = doc.url!.replace(/.*\@([^\:]+)\:.*/, '$1'); + url = doc.url!.replace(host, doc.alias); + if (needAddKey) { + this.sshKeyService.addSSHKey( + (doc.pull_option as any).private_key, + doc.alias, + host, + ); + } else { + this.sshKeyService.removeSSHKey(doc.alias, host); + } + } else { + const host = doc.url!.replace(/.*\:\/\/([^\/]+)\/.*/, '$1'); + const { username, password } = doc.pull_option as any; + url = doc.url!.replace(host, `${username}:${password}@${host}`); + } + } + + doc.command = this.formatCommand(doc, url as string); + if (doc.schedule_type === 'crontab') { this.scheduleService.cancelCronTask(doc as any); needCreate && @@ -191,7 +216,6 @@ export default class SubscriptionService { public async create(payload: Subscription): Promise { const tab = new Subscription(payload); - console.log(tab); const doc = await this.insert(tab); this.handleTask(doc); return doc; @@ -246,7 +270,7 @@ export default class SubscriptionService { public async remove(ids: number[]) { const docs = await SubscriptionModel.findAll({ where: { id: ids } }); for (const doc of docs) { - this.handleTask(doc, false); + this.handleTask(doc, false, false); } await SubscriptionModel.destroy({ where: { id: ids } }); } diff --git a/src/pages/subscription/index.tsx b/src/pages/subscription/index.tsx index 31a4ccd0..7e010b3e 100644 --- a/src/pages/subscription/index.tsx +++ b/src/pages/subscription/index.tsx @@ -51,6 +51,12 @@ export enum IntervalSchedule { 'seconds' = '秒', } +export enum SubscriptionType { + 'private-repo' = '私有仓库', + 'public-repo' = '公开仓库', + 'file' = '单文件', +} + const Subscription = ({ headerStyle, isPhone, socketMessage }: any) => { const columns: any = [ { @@ -88,6 +94,16 @@ const Subscription = ({ headerStyle, isPhone, socketMessage }: any) => { ); }, }, + { + title: '类型', + dataIndex: 'type', + key: 'type', + width: 130, + align: 'center' as const, + render: (text: string, record: any) => { + return (SubscriptionType as any)[record.type]; + }, + }, { title: '分支', dataIndex: 'branch', diff --git a/src/pages/subscription/modal.tsx b/src/pages/subscription/modal.tsx index 6301a442..f5cab843 100644 --- a/src/pages/subscription/modal.tsx +++ b/src/pages/subscription/modal.tsx @@ -56,7 +56,9 @@ const SubscriptionModal = ({ form.setFieldsValue({ alias: formatAlias(_url, _branch, e.target.value), }); - form.validateFields(['url']); + if (_url) { + form.validateFields(['url']); + } }; const scheduleTypeChange = (e) => { @@ -149,16 +151,28 @@ const SubscriptionModal = ({ onChange?: (param: any) => void; }) => { return type === 'ssh-key' ? ( - - + + ) : ( <> - +