feat: add github repo group ensure action which will auto create group and subscribe activity

pull/105/merge
moonrailgun 2 years ago
parent 588fae2e60
commit c96367f157

@ -72,6 +72,7 @@ export {
useWatch,
parseUrlStr,
useUpdateRef,
isDevelopment,
} from 'tailchat-shared';
export { navigate } from '@/components/AppRouterApi';

@ -186,7 +186,11 @@ declare module '@capital/common' {
export const useWatch: any;
export const parseUrlStr: any;
export const parseUrlStr: (originUrl: string) => string;
export const useUpdateRef: <T>(state: T) => React.MutableRefObject<T>;
export const isDevelopment: boolean;
export const navigate: any;
@ -472,6 +476,8 @@ declare module '@capital/component' {
export const useChatInputActionContext: any;
export const GroupPanelContainer: any;
export const GroupExtraDataPanel: any;
export const Image: any;
@ -599,4 +605,6 @@ declare module '@capital/component' {
export const NoData: any;
export const NotFound: any;
export const withKeepAliveOverlay: any;
}

@ -1890,6 +1890,9 @@ importers:
specifier: ^5.4.0
version: 5.8.0
devDependencies:
'@types/react-router':
specifier: ^5.1.20
version: 5.1.20
less:
specifier: ^4.1.2
version: 4.1.3

@ -18,7 +18,7 @@ import type { TFunction } from 'i18next';
import { t } from './lib/i18n';
import type { ValidationRuleObject } from 'fastest-validator';
import type { BuiltinEventMap } from '../structs/events';
import { CONFIG_GATEWAY_AFTER_HOOK } from '../const';
import { CONFIG_GATEWAY_AFTER_HOOK, SYSTEM_USERID } from '../const';
import _ from 'lodash';
import {
decodeNoConflictServiceNameKey,
@ -451,6 +451,21 @@ export abstract class TcService extends Service {
return this.actions[actionName](params, opts);
}
protected systemCall<T>(
ctx: PureContext,
actionName: string,
params?: {},
opts?: CallingOptions
): Promise<T> {
return ctx.call(actionName, params, {
...opts,
meta: {
userId: SYSTEM_USERID,
...(opts?.meta ?? {}),
},
});
}
private buildLoggerWithPrefix(_originLogger: LoggerInstance) {
const prefix = `[${this.serviceName}]`;
const originLogger = _originLogger;

@ -41,6 +41,8 @@ export interface GroupRoleStruct {
}
export interface GroupStruct {
_id: string;
name: string;
avatar?: string;

@ -1,7 +1,7 @@
const path = require('path');
module.exports = {
externalDeps: ['react'],
externalDeps: ['react', 'react-router'],
pluginRoot: path.resolve(__dirname, './web'),
outDir: path.resolve(__dirname, '../../public'),
};

@ -0,0 +1,34 @@
import {
getModelForClass,
prop,
DocumentType,
modelOptions,
} from '@typegoose/typegoose';
import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses';
import type { Types } from 'mongoose';
@modelOptions({
options: {
customName: 'p_githubRepo',
},
})
export class Repo extends TimeStamps implements Base {
_id: Types.ObjectId;
id: string;
@prop({
unique: true,
})
repoName: string; // 完整地址
@prop()
groupId: string;
}
export type RepoDocument = DocumentType<Repo>;
const model = getModelForClass(Repo);
export type RepoModel = typeof model;
export default model;

@ -13,6 +13,7 @@
"@octokit/webhooks-types": "^5.4.0"
},
"devDependencies": {
"@types/react-router": "^5.1.20",
"less": "^4.1.2",
"mini-star": "^1.2.8",
"rollup-plugin-less": "^1.1.3"

@ -0,0 +1,99 @@
import type { GroupStruct } from 'tailchat-server-sdk';
import { GroupPanelType, TcContext } from 'tailchat-server-sdk';
import { TcService, TcDbService } from 'tailchat-server-sdk';
import type { RepoDocument, RepoModel } from '../models/repo';
const ACTIVITY_PANEL_NAME = 'Activity';
const defaultGroupPanel = [
{
id: '00',
name: 'Default',
type: GroupPanelType.GROUP,
},
{
id: '01',
name: 'Lobby',
parentId: '00',
type: GroupPanelType.TEXT,
},
{
id: '02',
name: ACTIVITY_PANEL_NAME,
parentId: '00',
type: GroupPanelType.TEXT,
},
{
id: '10',
name: 'Project',
type: GroupPanelType.GROUP,
},
];
/**
* Github
*/
interface GithubRepoService
extends TcService,
TcDbService<RepoDocument, RepoModel> {}
class GithubRepoService extends TcService {
get serviceName() {
return 'plugin:com.msgbyte.github.repo';
}
onInit() {
this.registerLocalDb(require('../models/repo').default);
this.registerAction('ensure', this.ensure, {
params: {
repoName: 'string',
},
});
}
async ensure(ctx: TcContext<{ repoName: string }>): Promise<{
repoName: string;
groupId: string;
}> {
const { repoName } = ctx.params;
let doc = await this.adapter.model.findOne({
repoName,
});
if (!doc) {
// 不存在
const group = await this.systemCall<GroupStruct>(
ctx,
'group.createGroup',
{
name: repoName,
panels: defaultGroupPanel,
}
);
const groupId = String(group._id);
const activityPanel = group.panels.find(
(item) => item.name === ACTIVITY_PANEL_NAME
);
if (activityPanel) {
await this.systemCall(ctx, 'plugin:com.msgbyte.github.subscribe.add', {
groupId,
textPanelId: activityPanel.id,
repoName,
});
}
doc = await this.adapter.model.create({
repoName,
groupId,
});
}
const json = await this.transformDocuments(ctx, {}, doc);
return json;
}
}
export default GithubRepoService;

@ -0,0 +1,23 @@
import React from 'react';
import { useParams } from 'react-router';
interface GithubRepoName {
owner: string;
repo: string;
}
export const GithubRepoInfo: React.FC<GithubRepoName> = React.memo((props) => {
return <div>GithubRepoInfo {JSON.stringify(props)}</div>;
});
GithubRepoInfo.displayName = 'GithubRepoInfo';
export const GithubRepoInfoRoute: React.FC = React.memo(() => {
const params = useParams<GithubRepoName>();
return (
<div>
<GithubRepoInfo owner={params.owner} repo={params.repo} />
</div>
);
});
GithubRepoInfoRoute.displayName = 'GithubRepoInfoRoute';

@ -1,26 +1,40 @@
import {
regCustomPanel,
Loadable,
regInspectService,
regPluginPermission,
regPluginRootRoute,
isDevelopment,
} from '@capital/common';
import { Loadable } from '@capital/component';
import { Translate } from './translate';
const PLUGIN_ID = 'com.msgbyte.github';
regCustomPanel({
position: 'groupdetail',
name: 'com.msgbyte.github/groupSubscribe',
name: `${PLUGIN_ID}/groupSubscribe`,
label: Translate.groupSubscribe,
render: Loadable(() => import('./GroupSubscribePanel')),
});
regInspectService({
name: 'plugin:com.msgbyte.github.subscribe',
name: `plugin:${PLUGIN_ID}.subscribe`,
label: Translate.githubService,
});
regPluginPermission({
key: 'plugin.com.msgbyte.github.subscribe.manage',
key: `plugin.${PLUGIN_ID}.subscribe.manage`,
title: Translate.permissionTitle,
desc: Translate.permissionDesc,
default: false,
});
if (isDevelopment) {
regPluginRootRoute({
name: `plugin:${PLUGIN_ID}/route`,
path: '/github/:owner/:repo',
component: Loadable(() =>
import('./components/GithubRepoInfo').then((m) => m.GithubRepoInfoRoute)
),
});
}

@ -21,6 +21,7 @@ import {
GroupPanelType,
PanelFeature,
config,
SYSTEM_USERID,
} from 'tailchat-server-sdk';
import moment from 'moment';
@ -291,7 +292,10 @@ class GroupService extends TcService {
const userId = ctx.meta.userId;
const t = ctx.meta.t;
if (config.feature.disableCreateGroup === true) {
if (
config.feature.disableCreateGroup === true &&
userId !== SYSTEM_USERID
) {
// 环境变量禁止创建群组
throw new NoPermissionError(t('创建群组功能已被管理员禁用'));
}

Loading…
Cancel
Save