This commit is contained in:
sx1989827 2022-05-16 22:26:02 +08:00
parent 222b6bfc0b
commit 1cbacd5df8
78 changed files with 2162 additions and 287 deletions

View File

@ -5,7 +5,8 @@ export interface ICommon_Model_Field_Solution {
created_time :Date,
modified_time :Date ,
name :string,
description :string
description :string,
organization_id:string
}
export const Table_Field_Solution="field_solution"

View File

@ -8,6 +8,7 @@ export interface ICommon_Model_Issue_Type {
reserved:number,
created_time:Date,
modified_time:Date,
organization_id:string
}
export const Table_Issue_Type="issue_type"

View File

@ -7,6 +7,7 @@ export interface ICommon_Model_Issue_Type_Solution {
reserved :number,
created_time :Date,
modified_time :Date,
organization_id:string
}
export const Table_Issue_Type_Solution="issue_type_solution"

View File

@ -0,0 +1,20 @@
import { BaseModel } from "./base"
export interface ICommon_Model_Organization {
id:string,
name:string,
description:string,
photo:string,
created_time:Date,
modified_time:Date,
active:number,
user_id:string,
}
export const Table_Organization="organization"
class OrganizationModel extends BaseModel {
table=Table_Organization
model=<ICommon_Model_Organization>{}
}
export let organizationModel=new OrganizationModel

View File

@ -0,0 +1,28 @@
import { BaseModel } from "./base"
export enum ECommon_Organization_User_Role {
USER,
ADMIN
}
export interface ICommon_Model_Organization_User {
id :string,
organization_id :string,
user_id:string,
email :string,
phone :string,
created_time :Date,
modified_time :Date,
location :string,
title :string,
active:number,
role:ECommon_Organization_User_Role,
job:string,
nickname:string
}
export const Table_Organization_User="organization_user"
class OrganizationUserModel extends BaseModel {
table=Table_Organization_User
model=<ICommon_Model_Organization_User>{}
}
export let organizationUserModel=new OrganizationUserModel

View File

@ -9,6 +9,7 @@ export interface ICommon_Model_Project {
photo :string,
created_by :string ,
description :string,
organization_id:string
}
export const Table_Project="project"

View File

@ -7,6 +7,7 @@ export interface ICommon_Model_Team {
created_time :Date,
modified_time :Date,
created_by :string ,
organization_id:string
}
export const Table_Team="team"

View File

@ -1,19 +1,19 @@
import { BaseModel } from "./base"
import { BaseModel } from "./base"
export enum ECommon_User_Type {
USER,
ADMIN
}
export interface ICommon_Model_User {
id :string,
username :string,
photo:string,
email :string,
phone :string,
created_time :Date,
modified_time :Date,
password :string,
sign :string,
location :string,
title :string,
active:number,
is_admin:number
role:ECommon_User_Type
}
export const Table_User="user"

View File

@ -7,6 +7,7 @@ export interface ICommon_Model_Workflow {
reserved :number,
created_time :Date,
modified_time :Date,
organization_id:string
}
export const Table_Workflow="workflow"

View File

@ -6,7 +6,8 @@ export interface ICommon_Model_Workflow_Solution {
modified_time :Date,
reserved :number,
name :string,
description :string
description :string,
organization_id:string
}
export const Table_Workflow_Solution="workflow_solution"

View File

@ -261,4 +261,4 @@ const api={
}
}
export=api
export default api

View File

@ -24,4 +24,4 @@ const api={
}
}
export=api
export default api

View File

@ -1,5 +1,6 @@
import { ECommon_Services } from "../types"
import { ECommon_HttpApi_Method } from "./types"
import { ECommon_Services } from "../types";
import { ECommon_Application_Mode } from './../../server/common/app/app';
import { ECommon_HttpApi_Method } from "./types";
const api={
baseUrl:"/gateway",
@ -26,8 +27,17 @@ const api={
}>{},
res:{},
ignoreValidate:true
},
deployInfo:{
method:ECommon_HttpApi_Method.GET,
path:"/deploy",
req:{},
res:<{
type:ECommon_Application_Mode
}>{},
ignoreValidate:true
}
}
}
export=api
export default api

View File

@ -321,4 +321,4 @@ const api={
}
}
}
export=api
export default api

View File

@ -171,4 +171,4 @@ const api={
},
}
}
export=api
export default api

View File

@ -0,0 +1,120 @@
import { Permission_Types } from '../permission/permission';
import { ICommon_Model_Organization } from './../model/organization';
import { ECommon_Organization_User_Role, ICommon_Model_Organization_User } from './../model/organization_user';
import { ECommon_Services } from './../types';
import { ICommon_Route_Res_Organization_List, ICommon_Route_Res_Organization_User } from './response';
import { ECommon_HttpApi_Method } from "./types";
const api={
baseUrl:"/organization",
service:ECommon_Services.User,
routes:{
list:{
method:ECommon_HttpApi_Method.GET,
path:"/list",
req:<{
}>{},
res:<ICommon_Route_Res_Organization_List>{}
},
info:{
method:ECommon_HttpApi_Method.GET,
path:"/item",
req:<{
organizationId:string
}>{},
res:<ICommon_Model_Organization>{},
},
create:{
method:ECommon_HttpApi_Method.POST,
path:"/item",
req:<{
name:string,
description?:string,
photo?:string
}>{},
res:<ICommon_Model_Organization>{},
},
update:{
method:ECommon_HttpApi_Method.PUT,
path:"/item",
req:<{
organizationId:string
name?:string,
description?:string,
photo?:string,
active?:number
}>{},
res:<ICommon_Model_Organization>{},
permission:[Permission_Types.Admin.ADMIN]
},
remove:{
method:ECommon_HttpApi_Method.DELETE,
path:"/item",
req:<{
organizationId:string
}>{},
res:{},
permission:[Permission_Types.Admin.ADMIN]
},
listUser:{
method:ECommon_HttpApi_Method.GET,
path:"/user/list",
req:<{
organizationId:string,
page:number,
size:number,
keyword?:string
}>{},
res:<ICommon_Route_Res_Organization_User>{},
},
addUser:{
method:ECommon_HttpApi_Method.POST,
path:"/user",
req:<{
organizationId:string,
username:string,
role:ECommon_Organization_User_Role,
nickname:string,
active:number,
title?:string,
job?:string,
email?:string,
phone?:string,
location?:string
}>{},
res:<ICommon_Model_Organization_User>{},
permission:[Permission_Types.Admin.ADMIN]
},
updateUser:{
method:ECommon_HttpApi_Method.PUT,
path:"/user",
req:<{
organizationId:string,
userId:string,
role?:ECommon_Organization_User_Role,
nickname?:string,
active?:number,
title?:string,
job?:string,
email?:string,
phone?:string,
location?:string
}>{},
res:<ICommon_Model_Organization_User>{},
permission:[Permission_Types.Admin.ADMIN]
},
deleteUser:{
method:ECommon_HttpApi_Method.DELETE,
path:"/user",
req:<{
organizationId:string,
userId:string
}>{},
res:{},
permission:[Permission_Types.Admin.ADMIN]
},
}
}
export default api

View File

@ -245,4 +245,4 @@ const api={
}
}
}
export=api
export default api

View File

@ -106,4 +106,4 @@ const api={
},
}
}
export = api
export default api

View File

@ -2,11 +2,13 @@ import { ICommon_Model_Field_Solution_Workflow_Node_Field_Type } from "../model/
import { ICommon_Model_Field_Type } from "../model/field_type";
import { ICommon_Model_Field_Type_Config_Value } from "../model/field_type_config_value";
import { ICommon_Model_Issue_Type } from "../model/issue_type";
import { ICommon_Model_Organization } from "../model/organization";
import { ICommon_Model_Project } from "../model/project";
import { ICommon_Model_Team } from '../model/team';
import { ICommon_Model_User } from '../model/user';
import { ICommon_Model_Field_Solution } from './../model/field_solution';
import { ICommon_Model_Issue_Type_Solution } from './../model/issue_type_solution';
import { ICommon_Model_Organization_User } from './../model/organization_user';
import { ICommon_Model_Project_Issue } from './../model/project_issue';
import { ICommon_Model_Project_Issue_Field_Value } from './../model/project_issue_field_value';
import { ECommon_Model_Project_Member_Type } from './../model/project_member';
@ -208,4 +210,21 @@ export interface ICommon_Route_Res_Project_User_Item {
id:string,
photo:string,
username:string
}
export interface ICommon_Route_Res_Organization_User {
count:number,
totalPage:number,
data:(Omit<ICommon_Model_Organization_User,"user_id"> & {
user_id:{
id:string,
username:string,
photo:string
}
})[]
}
export interface ICommon_Route_Res_Organization_List {
create:ICommon_Model_Organization[],
join:ICommon_Model_Organization[]
}

View File

@ -134,4 +134,4 @@ const api={
}
}
}
export=api
export default api

View File

@ -65,7 +65,7 @@ const api={
req:<Partial<Omit<ICommon_Model_User,"id" | "created_time" | "modified_time">> & {
username:string,
password:string,
is_admin?:number
role?:number
}>{},
res:<Omit<ICommon_Model_User,"password">>{}
},
@ -158,4 +158,4 @@ const api={
}
}
export=api
export default api

View File

@ -269,4 +269,4 @@ const api={
},
}
}
export=api
export default api

View File

@ -59,6 +59,10 @@ export namespace Err {
requireParam:{
code:2001,
msg:"require param"
},
requireHeader:{
code:2002,
msg:"require header"
}
}
export let Project = {
@ -340,5 +344,32 @@ export namespace Err {
msg:"comment type not found"
}
}
export let Organization = {
ownerNotFound:{
code:8000,
msg:"owner not found"
},
organizationNotFound:{
code:8001,
msg:"organization not found"
},
userAlreadyExists:{
code:8002,
msg:"user already exists"
},
userNotFound:{
code:8003,
msg:"user not found"
},
ownerDeleteForbidden:{
code:8004,
msg:"owner delete forbidden"
},
nicknameEmpty:{
code:8005,
msg:"nickname empty"
}
}
}

View File

@ -27,6 +27,7 @@ export namespace REDIS_GATEWAY {
let labelCacheKey="permission:label:{0}"
let moduleCacheKey="permission:module:{0}"
let releaseCacheKey="permission:release:{0}"
let organizationRoleCacheKey="permission:organization:{0}:user:{1}"
export function projectIdFromProjectIssueComment(commentId:string) {
let obj=new RedisStringKey(StringUtil.format(commentCacheKey,commentId),cacheRedisType<string>().String,1000*10);
return obj;
@ -47,5 +48,9 @@ export namespace REDIS_GATEWAY {
let obj=new RedisStringKey(StringUtil.format(releaseCacheKey,releaseId),cacheRedisType<string>().String,1000*10);
return obj;
}
export function organizationRole(organizationId:string,userId:string) {
let obj=new RedisStringKey(StringUtil.format(organizationRoleCacheKey,organizationId,userId),cacheRedisType<string>().String,3600);
return obj;
}
}
}

View File

@ -1,8 +0,0 @@
import { Table_Issue_Type ,ICommon_Model_Issue_Type} from '../../../../common/model/issue_type';
import { getMysqlInstance } from "../mysql";
export async function getIssueTypeListMapper() {
var mysql=getMysqlInstance()
var ret=await mysql.execute<ICommon_Model_Issue_Type[]>(`select * from ${Table_Issue_Type}`)
return ret
}

View File

@ -72,7 +72,7 @@ export default class Mysql {
let table=key.substring(1,key.indexOf("__"))
if(table in aggregation) {
if(aggregation[table]) {
if(!(aggregation[table] in ret)){
if(!(aggregation[table] in ret) || typeof(ret[aggregation[table]])!="object"){
ret[aggregation[table]]={}
}
ret[aggregation[table]][key.substr(table.length+3)]=item[key]
@ -119,7 +119,7 @@ export default class Mysql {
let table=key.substring(1,key.indexOf("__"))
if(table in aggregation) {
if(aggregation[table]) {
if(!(aggregation[table] in ret)){
if(!(aggregation[table] in ret) || typeof(ret[aggregation[table]])!="object"){
ret[aggregation[table]]={}
}
ret[aggregation[table]][key.substr(table.length+3)]=item[key]

View File

@ -118,4 +118,22 @@ export abstract class Entity<T extends BaseModel,M extends Mapper<T>> {
return null;
}
}
}
static async getItemByExp<Type>(this:{new():Type},exp:{
[param in keyof GET<Type>["model"]]?:GET<Type>["model"][param]
}):Promise<Type>{
if(!exp) {
return null
}
let user = new this() as any;
let obj = await user.mapper.getByExp(exp);
if(obj) {
user.setItem(obj);
return user;
} else {
return null;
}
}
}
type GET<T>=T extends Entity<infer T1,Mapper<infer T1>>?T1:never

View File

@ -27,6 +27,16 @@ export abstract class Mapper<T extends BaseModel> {
let ret=await mysql.executeOne(generateQuerySql(this.model,[],{id}))
return ret
}
async getByExp(exp:{
[param in keyof T["model"]]:T["model"][param]
}):Promise<T["model"]> {
if(!exp) {
throw Err.Common.itemNotFound
}
var mysql=getMysqlInstance();
let ret=await mysql.executeOne(generateQuerySql(this.model,[],exp))
return ret
}
async updateConfig(info:T["model"]){}
async update(data:T["model"]):Promise<void> {
let info:T["model"]={}

View File

@ -147,6 +147,43 @@ export function DHttpContext(target: Object, propertyKey: string, parameterIndex
g_objParam[key].unshift(obj)
}
export function DHttpHeaderRequired(name:string){
return function(target: Object, propertyKey: string, parameterIndex: number){
let types=Reflect.getMetadata("design:paramtypes",target,propertyKey);
let type=types[parameterIndex].name
let key=target.constructor.name+"::"+propertyKey
let obj:IServer_Common_Http_Structure_HandleParam={
name:name,
index:parameterIndex,
type:type,
category:EServer_Common_Http_Structure_HandleParam_Category.Header,
required:true
}
if(!g_objParam[key]){
g_objParam[key]=[]
}
g_objParam[key].unshift(obj)
}
}
export function DHttpHeader(name:string){
return function(target: Object, propertyKey: string, parameterIndex: number){
let types=Reflect.getMetadata("design:paramtypes",target,propertyKey);
let type=types[parameterIndex].name
let key=target.constructor.name+"::"+propertyKey
let obj:IServer_Common_Http_Structure_HandleParam={
name:name,
index:parameterIndex,
type:type,
category:EServer_Common_Http_Structure_HandleParam_Category.Header
}
if(!g_objParam[key]){
g_objParam[key]=[]
}
g_objParam[key].unshift(obj)
}
}
export function DHttpContent(target: Object, propertyKey: string, parameterIndex: number){
let types=Reflect.getMetadata("design:paramtypes",target,propertyKey);
let type=types[parameterIndex].name
@ -225,6 +262,16 @@ export async function handleHttpCall(obj:IServer_Common_Http_Structure,ctx:IServ
let objFile:IServer_Common_Http_Req_File=ctx.data[name]
arr.push(objFile)
}
else if(obj.category==EServer_Common_Http_Structure_HandleParam_Category.Header)
{
let header=ctx.headers[name]
if(header===null || header===undefined) {
if(obj.required) {
throw Err.Http.requireHeader
}
}
arr.push(header)
}
else if(obj.category==EServer_Common_Http_Structure_HandleParam_Category.Content)
{
let obj={};

View File

@ -0,0 +1,27 @@
import { organizationUserModel } from '../../../common/model/organization_user';
import { REDIS_GATEWAY } from '../cache/keys/gateway';
import { getMysqlInstance } from '../db/mysql';
import { generateQuerySql } from '../util/sql';
import { ECommon_Organization_User_Role } from './../../../common/model/organization_user';
export async function getOrganizationPermission(organizationId:string,userId:string):Promise<ECommon_Organization_User_Role> {
if(!organizationId) {
return null;
}
let objRedis=REDIS_GATEWAY.Permission.organizationRole(organizationId,userId)
let exist = objRedis.exists()
if(exist) {
let value=await objRedis.get()
return parseInt(value);
} else {
let mysql=getMysqlInstance()
let obj=await mysql.executeOne(generateQuerySql(organizationUserModel,["role"],{
organization_id:organizationId,
user_id:userId
}))
if(obj) {
return obj.role
} else {
return null;
}
}
}

View File

@ -0,0 +1,9 @@
export default interface IServer_Common_RPC_Cooperation {
clearProject?(organizationId:string)
clearField?(organizationId:string)
clearWorkflow?(organizationId:string)
clearIssueType?(organizationId:string)
initIssueTypeWorkflowAndSolution?(organizationId:string,projectId?:string)
initProject?(userId:string,projectRoleUserId:string,organizationId:string):Promise<string>
initField?()
}

View File

@ -1,16 +1,20 @@
import { EServer_Common_User_Type } from "../../types/user";
import { ECommon_User_Type } from "../../../../common/model/user";
export interface IServer_Common_RPC_User_CheckSession {
userId:string,
type:EServer_Common_User_Type
type:ECommon_User_Type
}
export default interface IServer_Common_RPC_User {
checkSession?(token:string):Promise<IServer_Common_RPC_User_CheckSession>
getUsersInfo?(userIds:string[]):Promise<{
getUsersInfo?(userIds:string[],organizationId:string):Promise<{
id:string,
username:string,
photo?:string
photo?:string,
nickname?:string
}[]>
initAdmin?():Promise<string[]>
initUser?():Promise<string[]>
initOrganization?(adminIds:string[],userIds:string[]):Promise<string>
}
export type IUserSession=IServer_Common_RPC_User_CheckSession

View File

@ -1,4 +0,0 @@
export enum EServer_Common_User_Type {
USER,
ADMIN
}

View File

@ -16,6 +16,25 @@ type EXPRVALUE=string|number|boolean|string|Date|EXPRVALUEEXP|{
values:EXPRVALUEEXP[]
}
type QUERYJOINEXPSIMPLE = {
value:EXPRVALUE,
model:{
table:string
}
}
type QUERYJOINMULTI = {
[param :string]:{
value:EXPRVALUE,
model:{
table:string
}
}
}
type QUERYJOINEXP=QUERYJOINEXPSIMPLE|QUERYJOINMULTI
export async function generateSnowId() {
let id = intFormat(uid.next(),"dec") as string
return id
@ -95,32 +114,53 @@ function generateExp(objExpr?:EXPR,exprMode?:"and"|"or"):string{
return expr;
}
function isQueryJoinSimple(obj:QUERYJOINEXP):obj is QUERYJOINEXPSIMPLE {
return (obj as QUERYJOINEXPSIMPLE).model!==undefined && (obj as QUERYJOINEXPSIMPLE).model.table!==undefined
}
function generateLeftJoinExp(objExpr?:{
[param :string]:{
value:EXPRVALUE,
model:{
table:string
}
}
[param :string]:QUERYJOINEXP
},exprMode?:"and"|"or"):string{
let expr="",arrExpr=[]
if(objExpr) {
for(let key in objExpr) {
let value=objExpr[key]
if(typeof(value.value)!="object") {
let val=typeof(value.value)=="number"?value.value:typeof(value.value)=="boolean"?(value.value?1:0):("'"+value.value+"'")
arrExpr.push(`${value.model.table}.${key}=${val}`)
} else if (typeof(value.value)=="object" && (value.value instanceof Date)){
arrExpr.push(`${value.model.table}.${key}=${value.value.getTime()}`)
} else if (isEXPRVALUEEXP(value.value)) {
handleExp(key,value.value,arrExpr,value.model.table)
}else {
let arr=[];
for(let obj of value.value.values) {
handleExp(key,obj,arr,value.model.table)
if(isQueryJoinSimple(value)) {
if(typeof(value.value)!="object") {
let val=typeof(value.value)=="number"?value.value:typeof(value.value)=="boolean"?(value.value?1:0):("'"+value.value+"'")
arrExpr.push(`${value.model.table}.${key}=${val}`)
} else if (typeof(value.value)=="object" && (value.value instanceof Date)){
arrExpr.push(`${value.model.table}.${key}=${value.value.getTime()}`)
} else if (isEXPRVALUEEXP(value.value)) {
handleExp(key,value.value,arrExpr,value.model.table)
}else {
let arr=[];
for(let obj of value.value.values) {
handleExp(key,obj,arr,value.model.table)
}
arrExpr.push(`(${arr.join(` ${value.value.type?value.value.type:"and"} `)})`)
}
arrExpr.push(`(${arr.join(` ${value.value.type?value.value.type:"and"} `)})`)
}
} else {
let arr=[]
for(let k in value){
let v=value[k];
if(typeof(v.value)!="object") {
let val=typeof(v.value)=="number"?v.value:typeof(v.value)=="boolean"?(v.value?1:0):("'"+v.value+"'")
arr.push(`${v.model.table}.${k}=${val}`)
} else if (typeof(v.value)=="object" && (v.value instanceof Date)){
arr.push(`${v.model.table}.${k}=${v.value.getTime()}`)
} else if (isEXPRVALUEEXP(v.value)) {
handleExp(k,v.value,arr,v.model.table)
}else {
let arr1=[];
for(let obj of v.value.values) {
handleExp(k,obj,arr1,v.model.table)
}
arr.push(`(${arr1.join(` ${v.value.type?v.value.type:"and"} `)})`)
}
}
arrExpr.push(`(${arr.join(` ${key.startsWith("$and")?"and":"or"} `)})`)
}
}
expr=arrExpr.join(` ${exprMode?exprMode:"and"} `)
}
@ -282,9 +322,14 @@ export function generateLeftJoinSql<T1 extends BaseModel,T2 extends BaseModel,K1
}
}
},objExpr?:{
[param in keyof (T1 & T2)["model"]]?:{
[param in ((keyof (T1 & T2)["model"])|`${"$and"|"$or"}${number}`)]?:{
value:EXPRVALUE,
model:T1|T2
}|{
[param in keyof (T1 & T2)["model"]]?:{
value:EXPRVALUE,
model:T1|T2
}
}
},exprMode?:"and"|"or",order?:{
field:keyof (T1["model"] & T2["model"]),
@ -387,6 +432,11 @@ export function generateLeftJoin2Sql<T1 extends BaseModel,T2 extends BaseModel,T
[param in keyof (T1 & T2 & T3)["model"]]?:{
value:EXPRVALUE,
model:T1|T2|T3
}|{
[param in keyof (T1 & T2 & T3)["model"]]?:{
value:EXPRVALUE,
model:T1|T2|T3
}
}
},exprMode?:"and"|"or",order?:{
field:keyof(T1["model"] & T2["model"] & T3["model"]),
@ -519,6 +569,11 @@ export function generateLeftJoin3Sql<T1 extends BaseModel,T2 extends BaseModel,T
[param in keyof (T1 & T2 & T3 & T4)["model"]]?:{
value:EXPRVALUE,
model:T1|T2|T3|T4
}|{
[param in keyof (T1 & T2 & T3 & T4)["model"]]?:{
value:EXPRVALUE,
model:T1|T2|T3|T4
}
}
},exprMode?:"and"|"or",order?:{
field:keyof(T1["model"] & T2["model"] & T3["model"] & T4["model"]),

View File

@ -8,6 +8,7 @@ import "../http/project";
import "../http/release";
import "../http/tag";
import "../http/workflow";
import "../rpc/cooperation";
export default class Cooperation extends Application {
override async config(app: import("koa")<DefaultState, DefaultContext>) {

View File

@ -1,7 +1,7 @@
import * as fieldApi from "../../../common/routes/field";
import fieldApi from "../../../common/routes/field";
import { Err } from "../../../common/status/error";
import { DComponent } from "../../common/decorate/component";
import { DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired } from "../../common/http/http";
import { DHttpApi, DHttpController, DHttpHeaderRequired, DHttpReqParam, DHttpReqParamRequired } from "../../common/http/http";
import FieldTypeService from "../service/field";
import { FieldSolutionService } from './../service/field';
@DComponent
@ -23,8 +23,8 @@ class FieldController {
}
@DHttpApi(fieldApi.routes.solutionList)
async solutionList(): Promise<typeof fieldApi.routes.solutionList.res> {
let ret = await FieldSolutionService.list()
async solutionList(@DHttpHeaderRequired("organizationid") organizationId:string): Promise<typeof fieldApi.routes.solutionList.res> {
let ret = await FieldSolutionService.list(organizationId)
return ret;
}
@ -39,11 +39,12 @@ class FieldController {
}
@DHttpApi(fieldApi.routes.solutionCreate)
async solutionCreate(@DHttpReqParamRequired("name") name:string,@DHttpReqParam("description") description:string): Promise<typeof fieldApi.routes.solutionCreate.res> {
async solutionCreate(@DHttpReqParamRequired("name") name:string,@DHttpReqParam("description") description:string,@DHttpHeaderRequired("organizationid") organizationId:string): Promise<typeof fieldApi.routes.solutionCreate.res> {
let service=new FieldSolutionService
service.assignItem({
name,
description
description,
organization_id:organizationId
})
let ret=await service.create()
return ret;

View File

@ -1,5 +1,5 @@
import { ECommon_Model_Comment_Type } from "../../../common/model/comment";
import * as projectIssueApi from "../../../common/routes/issue";
import projectIssueApi from "../../../common/routes/issue";
import { ICommon_Route_Req_ProjectIssue_Field } from "../../../common/routes/response";
import { Err } from "../../../common/status/error";
import { DComponent } from "../../common/decorate/component";

View File

@ -1,14 +1,14 @@
import * as issueTypeApi from "../../../common/routes/issueType";
import issueTypeApi from "../../../common/routes/issueType";
import { Err } from "../../../common/status/error";
import { DComponent } from "../../common/decorate/component";
import { DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired } from "../../common/http/http";
import { DHttpApi, DHttpController, DHttpHeaderRequired, DHttpReqParam, DHttpReqParamRequired } from "../../common/http/http";
import IssueTypeService, { IssueTypeSolutionService } from "../service/issueType";
@DComponent
@DHttpController(issueTypeApi)
class IssueTypeController {
@DHttpApi(issueTypeApi.routes.list)
async list():Promise<typeof issueTypeApi.routes.list.res> {
let ret=await IssueTypeService.list()
async list(@DHttpHeaderRequired("organizationid") organizationId:string):Promise<typeof issueTypeApi.routes.list.res> {
let ret=await IssueTypeService.list(organizationId)
return ret;
}
@DHttpApi(issueTypeApi.routes.info)
@ -21,12 +21,13 @@ class IssueTypeController {
}
@DHttpApi(issueTypeApi.routes.create)
async create(@DHttpReqParamRequired("name") name:string,@DHttpReqParam("icon") icon:string,@DHttpReqParam("description") description:string):Promise<typeof issueTypeApi.routes.create.res> {
async create(@DHttpReqParamRequired("name") name:string,@DHttpReqParam("icon") icon:string,@DHttpReqParam("description") description:string,@DHttpHeaderRequired("organizationid") organizationId:string):Promise<typeof issueTypeApi.routes.create.res> {
let obj=new IssueTypeService()
obj.assignItem({
name,
icon,
description
description,
organization_id:organizationId
})
let ret=await obj.create()
return ret;
@ -65,8 +66,8 @@ class IssueTypeController {
}
@DHttpApi(issueTypeApi.routes.solutionList)
async solutionList():Promise<typeof issueTypeApi.routes.solutionList.res> {
let ret=await IssueTypeSolutionService.list()
async solutionList(@DHttpHeaderRequired("organizationid") organizationId:string):Promise<typeof issueTypeApi.routes.solutionList.res> {
let ret=await IssueTypeSolutionService.list(organizationId)
return ret;
}
@DHttpApi(issueTypeApi.routes.solutionInfo)
@ -76,11 +77,12 @@ class IssueTypeController {
}
@DHttpApi(issueTypeApi.routes.solutionCreate)
async solutionCreate(@DHttpReqParamRequired("name") name:string,@DHttpReqParam("description") description:string):Promise<typeof issueTypeApi.routes.solutionCreate.res> {
async solutionCreate(@DHttpReqParamRequired("name") name:string,@DHttpReqParam("description") description:string,@DHttpHeaderRequired("organizationid") organizationId:string):Promise<typeof issueTypeApi.routes.solutionCreate.res> {
let obj=new IssueTypeSolutionService()
obj.assignItem({
name,
description
description,
organization_id:organizationId
})
let ret=await obj.create()
return ret;

View File

@ -1,4 +1,4 @@
import * as projectApi from "../../../common/routes/project";
import projectApi from "../../../common/routes/project";
import { DComponent } from "../../common/decorate/component";
import { DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired } from "../../common/http/http";
import ModuleService from "../service/module";

View File

@ -1,9 +1,9 @@
import { ECommon_Model_Project_Member_Type } from "../../../common/model/project_member";
import * as projectApi from "../../../common/routes/project";
import { ECommon_User_Type } from "../../../common/model/user";
import projectApi from "../../../common/routes/project";
import { Err } from "../../../common/status/error";
import { DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired, DHttpUser } from "../../common/http/http";
import { DHttpApi, DHttpController, DHttpHeaderRequired, DHttpReqParam, DHttpReqParamRequired, DHttpUser } from "../../common/http/http";
import { IUserSession } from "../../common/rpc/api/user";
import { EServer_Common_User_Type } from "../../common/types/user";
import ProjectService from "../service/project";
@DHttpController(projectApi)
@ -18,14 +18,15 @@ class ProjectController {
}
@DHttpApi(projectApi.routes.create)
async createProject(@DHttpReqParamRequired("name") name:string,@DHttpReqParamRequired("keyword") keyword:string,@DHttpReqParam("photo") photo:string,@DHttpReqParam("description") description:string,@DHttpUser user:IUserSession):Promise<typeof projectApi.routes.create.res>{
async createProject(@DHttpReqParamRequired("name") name:string,@DHttpReqParamRequired("keyword") keyword:string,@DHttpReqParam("photo") photo:string,@DHttpReqParam("description") description:string,@DHttpUser user:IUserSession,@DHttpHeaderRequired("organizationid") organizationId:string):Promise<typeof projectApi.routes.create.res>{
let obj=new ProjectService()
obj.assignItem({
keyword:keyword,
name:name,
created_by:user.userId,
description:description,
photo:photo
photo:photo,
organization_id:organizationId
})
let ret=await obj.create()
return ret
@ -97,14 +98,14 @@ class ProjectController {
}
@DHttpApi(projectApi.routes.list)
async list(@DHttpReqParam("keyword") keyword:string,@DHttpReqParamRequired("page") page:number,@DHttpReqParamRequired("size") size:number,@DHttpReqParam("userId") userId:string,@DHttpUser userInfo:IUserSession) :Promise<typeof projectApi.routes.list.res>{
async list(@DHttpReqParam("keyword") keyword:string,@DHttpReqParamRequired("page") page:number,@DHttpReqParamRequired("size") size:number,@DHttpReqParam("userId") userId:string,@DHttpUser userInfo:IUserSession,@DHttpHeaderRequired("organizationid") organizationId:string) :Promise<typeof projectApi.routes.list.res>{
let user=""
if(userInfo.type==EServer_Common_User_Type.ADMIN && userId) {
if(userInfo.type==ECommon_User_Type.ADMIN && userId) {
user=userId
} else if(userInfo.type==EServer_Common_User_Type.USER) {
} else if(userInfo.type==ECommon_User_Type.USER) {
user=userInfo.userId
}
let list=await ProjectService.list(page,size,keyword,user)
let list=await ProjectService.list(organizationId,page,size,keyword,user)
return list
}

View File

@ -1,5 +1,5 @@
import { ECommon_Model_Project_Release_Status } from "../../../common/model/project_release";
import * as releaseApi from "../../../common/routes/release";
import releaseApi from "../../../common/routes/release";
import { Err } from "../../../common/status/error";
import { DComponent } from "../../common/decorate/component";
import { DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired, DHttpUser } from "../../common/http/http";

View File

@ -1,4 +1,4 @@
import * as projectApi from "../../../common/routes/project";
import projectApi from "../../../common/routes/project";
import { DComponent } from "../../common/decorate/component";
import { DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired } from "../../common/http/http";
import TagService from "../service/tag";

View File

@ -1,16 +1,16 @@
import { ECommon_Model_Workflow_Node_Status } from "../../../common/model/workflow_node";
import * as workflowApi from "../../../common/routes/workflow";
import workflowApi from "../../../common/routes/workflow";
import { Err } from "../../../common/status/error";
import { DComponent } from "../../common/decorate/component";
import { DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired } from "../../common/http/http";
import { DHttpApi, DHttpController, DHttpHeaderRequired, DHttpReqParam, DHttpReqParamRequired } from "../../common/http/http";
import WorkflowService, { WorkflowActionService } from "../service/workflow";
import { WorkflowNodeService, WorkflowSolutionService } from './../service/workflow';
@DComponent
@DHttpController(workflowApi)
class WorkflowController {
@DHttpApi(workflowApi.routes.list)
async list(): Promise<typeof workflowApi.routes.list.res> {
let ret = await WorkflowService.list()
async list(@DHttpHeaderRequired("organizationid") organizationId:string): Promise<typeof workflowApi.routes.list.res> {
let ret = await WorkflowService.list(organizationId)
return ret;
}
@DHttpApi(workflowApi.routes.info)
@ -24,11 +24,12 @@ class WorkflowController {
}
@DHttpApi(workflowApi.routes.create)
async create(@DHttpReqParamRequired("name") name: string, @DHttpReqParam("description") description: string): Promise<typeof workflowApi.routes.create.res> {
async create(@DHttpReqParamRequired("name") name: string, @DHttpReqParam("description") description: string,@DHttpHeaderRequired("organizationid") organizationId:string): Promise<typeof workflowApi.routes.create.res> {
let obj = new WorkflowService()
obj.assignItem({
name,
description
description,
organization_id:organizationId
})
let ret = await obj.create()
return ret;
@ -164,8 +165,8 @@ class WorkflowController {
}
@DHttpApi(workflowApi.routes.solutionList)
async solutionList():Promise<typeof workflowApi.routes.solutionList.res> {
let ret=await WorkflowSolutionService.list()
async solutionList(@DHttpHeaderRequired("organizationid") organizationId:string):Promise<typeof workflowApi.routes.solutionList.res> {
let ret=await WorkflowSolutionService.list(organizationId)
return ret;
}
@DHttpApi(workflowApi.routes.solutionInfo)
@ -187,11 +188,12 @@ class WorkflowController {
return
}
@DHttpApi(workflowApi.routes.solutionCreate)
async solutionCreate(@DHttpReqParamRequired("name") name:string,@DHttpReqParam("description") description:string):Promise<typeof workflowApi.routes.solutionCreate.res> {
async solutionCreate(@DHttpReqParamRequired("name") name:string,@DHttpReqParam("description") description:string,@DHttpHeaderRequired("organizationid") organizationId:string):Promise<typeof workflowApi.routes.solutionCreate.res> {
let obj=new WorkflowSolutionService()
obj.assignItem({
name:name,
description:description
description:description,
organization_id:organizationId
})
let ret=await obj.create();
return ret;

View File

@ -1,7 +1,7 @@
import { Err } from "../../../common/status/error";
import { getMysqlInstance } from "../../common/db/mysql";
import { Mapper } from "../../common/entity/mapper";
import { generateQuerySql } from "../../common/util/sql";
import { generateDeleteSql, generateQuerySql } from "../../common/util/sql";
import { commentModel } from './../../../common/model/comment';
class CommentMapper extends Mapper<typeof commentModel> {
@ -23,6 +23,29 @@ class CommentMapper extends Mapper<typeof commentModel> {
return ret;
}
async clear(projectIssueId:string) {
if(!projectIssueId) {
throw Err.Project.Issue.issueTypeNotFound
}
let mysql=getMysqlInstance()
await mysql.execute(generateDeleteSql(commentModel,{
type_id:projectIssueId
}))
}
async clearByProjectIssueIds(projectIssueIds:string[]) {
if(!projectIssueIds || projectIssueIds.length==0) {
return;
}
let mysql=getMysqlInstance()
await mysql.execute(generateDeleteSql(commentModel,{
type_id:{
exp:"in",
value:projectIssueIds
}
}))
}
}
export let commentMapper=new CommentMapper

View File

@ -10,7 +10,7 @@ import { generateBatchCreateSql, generateCreateSql, generateDeleteSql, generateL
import { ICommon_Model_Field_Solution } from './../../../common/model/field_solution';
import { ECommon_Model_Field_Solution_Workflow_Node_Field_Type_Label_Type } from './../../../common/model/field_solution_workflow_node_field_type';
import { fieldSolutionWorkflowSolutionModel } from './../../../common/model/field_solution_workflow_solution';
import { fieldTypeModel, ICommon_Model_Field_Type } from './../../../common/model/field_type';
import { ECommon_Model_Field_Type, fieldTypeModel, ICommon_Model_Field_Type } from './../../../common/model/field_type';
import { fieldTypeConfigValueModel } from './../../../common/model/field_type_config_value';
class FieldTypeMapper extends Mapper<typeof fieldTypeModel> {
@ -26,6 +26,63 @@ class FieldTypeMapper extends Mapper<typeof fieldTypeModel> {
}))
return ret;
}
async init() {
let mysql = getMysqlInstance()
let fieldTypeLabelId = await generateSnowId()
let fieldTypeMultiLabelId = await generateSnowId()
let fieldTypeTextId = await generateSnowId()
let fieldTypeMultiTextId = await generateSnowId()
let fieldTypeSelectId = await generateSnowId()
let fieldTypeMultiSelectId = await generateSnowId()
let fieldTypeSwitchId = await generateSnowId()
let fieldTypeTimeId = await generateSnowId()
let fieldTypeDateId = await generateSnowId()
let fieldTypeDateTimeId = await generateSnowId()
await mysql.execute(generateBatchCreateSql(fieldTypeModel, [{
id: fieldTypeLabelId,
name: "label",
type: ECommon_Model_Field_Type.LABEL
}, {
id: fieldTypeMultiLabelId,
name: "multi label",
multi: 1,
type: ECommon_Model_Field_Type.MULTILABEL
}, {
id: fieldTypeTextId,
name: "text",
type: ECommon_Model_Field_Type.TEXT
}, {
id: fieldTypeMultiTextId,
name: "multi text",
type: ECommon_Model_Field_Type.MULTITEXT
}, {
id: fieldTypeSelectId,
name: "select",
type: ECommon_Model_Field_Type.SELECT
}, {
id: fieldTypeMultiSelectId,
name: "multi select",
multi: 1,
type: ECommon_Model_Field_Type.MULTISELECT
}, {
id: fieldTypeSwitchId,
name: "switch",
type: ECommon_Model_Field_Type.SWITCH
}, {
id: fieldTypeTimeId,
name: "timepicker",
type: ECommon_Model_Field_Type.TIME
}, {
id: fieldTypeDateId,
name: "datepicker",
type: ECommon_Model_Field_Type.DATE
}, {
id: fieldTypeDateTimeId,
name: "datetimepicker",
type: ECommon_Model_Field_Type.DATETIME
}]))
}
}
export let fieldTypeMapper=new FieldTypeMapper
@ -34,10 +91,15 @@ class FieldSolutionMapper extends Mapper<typeof fieldSolutionModel> {
constructor() {
super(fieldSolutionModel)
}
async list():Promise<ICommon_Model_Field_Solution[]>
async list(organizationId:string):Promise<ICommon_Model_Field_Solution[]>
{
if(!organizationId) {
throw Err.Organization.organizationNotFound
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(fieldSolutionModel,[],null,null,{
let ret=await mysql.execute(generateQuerySql(fieldSolutionModel,[],{
organization_id:organizationId
},null,{
field:"name",
type:"asc"
}))
@ -216,6 +278,49 @@ class FieldSolutionMapper extends Mapper<typeof fieldSolutionModel> {
}
}
async clearFieldSolutionByOrganizationId(organizationId:string) {
if(!organizationId) {
throw Err.Organization.organizationNotFound
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(fieldSolutionModel,["id"],{
organization_id:organizationId
}))
let fieldSolutionIds=ret.map(item=>item.id)
if(fieldSolutionIds.length>0) {
await mysql.execute(generateDeleteSql(fieldSolutionModel,{
organization_id:organizationId
}))
await mysql.execute(generateDeleteSql(fieldSolutionWorkflowSolutionModel,{
field_solution_id:{
exp:"in",
value:fieldSolutionIds
}
}))
let arrField=await mysql.execute(generateQuerySql(fieldSolutionWorkflowNodeFieldTypeModel,["id"],{
field_solution_id:{
exp:"in",
value:fieldSolutionIds
}
}))
await mysql.execute(generateDeleteSql(fieldSolutionWorkflowNodeFieldTypeModel,{
field_solution_id:{
exp:"in",
value:fieldSolutionIds
}
}))
if(arrField.length>0) {
await mysql.execute(generateDeleteSql(fieldTypeConfigValueModel,{
field_solution_workflow_node_field_type_id:{
exp:"in",
value:arrField.map(item=>item.id)
}
}))
}
}
}
async clearItemsByWorkflowId(workflowId:string) {
if(!workflowId) {
throw Err.Project.Workflow.workflowNotFound

View File

@ -187,6 +187,7 @@ class ProjectIssueMapper extends Mapper<typeof projectIssueModel> {
project_issue_1_id:projectIssueId,
project_issue_2_id:projectIssueId
},"or"))
}
async getBasicInfo(projectIssueId:string) {
@ -704,6 +705,72 @@ class ProjectIssueMapper extends Mapper<typeof projectIssueModel> {
let ret=await mysql.execute(sql)
return ret;
}
async clearMany(projectIssueIds:string[]) {
if(!projectIssueIds) {
throw Err.Project.ProjectIssue.projectIssueNotFound
}
let mysql=getMysqlInstance()
await mysql.execute(generateDeleteSql(projectIssueModel,{
id:{
exp:"in",
value:projectIssueIds
}
}))
await mysql.execute(generateDeleteSql(projectIssueDescriptionModel,{
project_issue_id:{
exp:"in",
value:projectIssueIds
}
}))
await mysql.execute(generateDeleteSql(projectIssueFieldValueModel,{
project_issue_id:{
exp:"in",
value:projectIssueIds
}
}))
await mysql.execute(generateDeleteSql(projectIssueParentModel,{
parent_id:{
exp:"in",
value:projectIssueIds
},
child_id:{
exp:"in",
value:projectIssueIds
}
},"or"))
await mysql.execute(generateDeleteSql(projectIssueProcessModel,{
project_issue_id:{
exp:"in",
value:projectIssueIds
}
}))
await mysql.execute(generateDeleteSql(projectIssueRelatedModel,{
project_issue_1_id:{
exp:"in",
value:projectIssueIds
},
project_issue_2_id:{
exp:"in",
value:projectIssueIds
}
},"or"))
}
async getIdsByProjectIds(projectIds:string[]){
if(!projectIds || projectIds.length==0) {
return []
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(projectIssueModel,["id"],{
project_id:{
exp:"in",
value:projectIds
}
}))
return ret.map(item=>item.id);
}
}
export let projectIssueMapper=new ProjectIssueMapper

View File

@ -1,4 +1,5 @@
import { ICommon_Model_Project, projectModel } from "../../../common/model/project";
import { workflowSolutionIssueTypeSolutionModel } from "../../../common/model/workflow_solution_issue_type_solution";
import { workflowSolutionWorkflowIssueTypeModel } from "../../../common/model/workflow_solution_workflow_issue_type";
import { Err } from "../../../common/status/error";
import { keys } from "../../../common/transform";
@ -13,10 +14,15 @@ class IssueTypeMapper extends Mapper<typeof issueTypeModel> {
constructor() {
super(issueTypeModel)
}
async list():Promise<ICommon_Model_Issue_Type[]>
async list(organizationId:string):Promise<ICommon_Model_Issue_Type[]>
{
if(!organizationId) {
throw Err.Organization.organizationNotFound
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(issueTypeModel,[],null,null,{
let ret=await mysql.execute(generateQuerySql(issueTypeModel,[],{
organization_id:organizationId
},null,{
field:"name",
type:"asc"
}))
@ -35,10 +41,15 @@ class IssueTypeSolutionMapper extends Mapper<typeof issueTypeSolutionModel> {
constructor() {
super(issueTypeSolutionModel)
}
async list():Promise<ICommon_Model_Issue_Type_Solution[]>
async list(organizationId:string):Promise<ICommon_Model_Issue_Type_Solution[]>
{
if(!organizationId) {
throw Err.Organization.organizationNotFound
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(issueTypeSolutionModel,[],null,null,{
let ret=await mysql.execute(generateQuerySql(issueTypeSolutionModel,[],{
organization_id:organizationId
},null,{
field:"name",
type:"asc"
}))
@ -106,10 +117,11 @@ class IssueTypeSolutionMapper extends Mapper<typeof issueTypeSolutionModel> {
}))
}
async getReservedItem() {
async getReservedItem(organizationId:string) {
let mysql=getMysqlInstance()
let ret=await mysql.executeOne(generateQuerySql(issueTypeSolutionModel,[],{
reserved:1
reserved:1,
organization_id:organizationId
}))
return ret;
}
@ -142,14 +154,14 @@ class IssueTypeSolutionMapper extends Mapper<typeof issueTypeSolutionModel> {
}))
}
async unbindProject(issueTypeSolutionId:string,projectId:string) {
async unbindProject(issueTypeSolutionId:string,projectId:string,organizationId:string) {
if(!issueTypeSolutionId) {
throw Err.Project.Issue.issueTypeSolutionNotFound
} else if(!projectId) {
throw Err.Project.projectNotFound
}
let mysql=getMysqlInstance()
let item=await this.getReservedItem();
let item=await this.getReservedItem(organizationId);
await mysql.execute(generateUpdateSql(projectIssueTypeSolutionModel,{
issue_type_solution_id:item.id
},{
@ -157,12 +169,25 @@ class IssueTypeSolutionMapper extends Mapper<typeof issueTypeSolutionModel> {
}))
}
async resetProjects(issueTypeSolutionId:string) {
async clearProjects(projectIds:string[]) {
if(!projectIds || projectIds.length==0) {
return;
}
let mysql=getMysqlInstance()
await mysql.execute(generateDeleteSql(projectIssueTypeSolutionModel,{
project_id:{
exp:"in",
value:projectIds
}
}))
}
async resetProjects(issueTypeSolutionId:string,organizationId:string) {
if(!issueTypeSolutionId) {
throw Err.Project.Issue.issueTypeSolutionNotFound
}
let mysql=getMysqlInstance()
let item=await this.getReservedItem();
let item=await this.getReservedItem(organizationId);
await mysql.execute(generateUpdateSql(projectIssueTypeSolutionModel,{
issue_type_solution_id:item.id
},{
@ -221,5 +246,60 @@ class IssueTypeSolutionMapper extends Mapper<typeof issueTypeSolutionModel> {
let ret=await mysql.executeOne(sql)
return ret;
}
async clearByOrganizationId(organizationId:string) {
if(!organizationId){
throw Err.Organization.organizationNotFound
}
let mysql=getMysqlInstance()
let issueTypeSolutionList=await mysql.execute(generateQuerySql(issueTypeSolutionModel,["id"],{
organization_id:organizationId
}))
if(issueTypeSolutionList.length>0) {
let ids=issueTypeSolutionList.map(item=>item.id);
await mysql.execute(generateDeleteSql(issueTypeSolutionModel,{
organization_id:organizationId
}))
await mysql.execute(generateDeleteSql(issueTypeSolutionIssueTypeModel,{
issue_type_solution_id:{
exp:"in",
value:ids
}
}))
await mysql.execute(generateDeleteSql(projectIssueTypeSolutionModel,{
issue_type_solution_id:{
exp:"in",
value:ids
}
}))
await mysql.execute(generateDeleteSql(workflowSolutionIssueTypeSolutionModel,{
issue_type_solution_id:{
exp:"in",
value:ids
}
}))
}
let issueTypeList=await mysql.execute(generateQuerySql(issueTypeModel,["id"],{
organization_id:organizationId
}))
if(issueTypeList.length>0) {
let ids=issueTypeList.map(item=>item.id);
await mysql.execute(generateDeleteSql(issueTypeModel,{
organization_id:organizationId
}))
await mysql.execute(generateDeleteSql(issueTypeSolutionIssueTypeModel,{
issue_type_id:{
exp:"in",
value:ids
}
}))
await mysql.execute(generateDeleteSql(workflowSolutionWorkflowIssueTypeModel,{
issue_type_id:{
exp:"in",
value:ids
}
}))
}
}
}
export let issueTypeSolutionMapper=new IssueTypeSolutionMapper

View File

@ -80,5 +80,21 @@ class ModuleMapper extends Mapper<typeof projectModuleModel> {
project_id:projectId
}))
}
async deleteByProjectIds(projectIds:string[]) {
if(!projectIds) {
throw Err.Project.Module.moduleNotFound
}
if(projectIds.length==0) {
return;
}
let mysql=getMysqlInstance()
await mysql.execute(generateDeleteSql(projectModuleModel,{
project_id:{
exp:"in",
value:projectIds
}
}))
}
}
export let moduleMapper=new ModuleMapper

View File

@ -8,6 +8,7 @@ import { generateCreateSql, generateDeleteSql, generateGroupLeftJoin2Sql, genera
import { projectIssueModel } from './../../../common/model/project_issue';
import { ECommon_Model_Project_Member_Type, projectMemberModel, Table_Project_Member } from './../../../common/model/project_member';
import { ICommon_Model_Project_Role, projectRoleModel } from './../../../common/model/project_role';
import { rolelPermissionModel } from './../../../common/model/role_permission';
import { teamModel } from './../../../common/model/team';
import { teamUserModel } from './../../../common/model/team_user';
import { userModel } from './../../../common/model/user';
@ -204,7 +205,23 @@ class ProjectMapper extends Mapper<typeof projectModel>{
}))
}
async list(page:number,size:number,keyword?:string,userId?:string):Promise<{
async clearMemberByProjectIds(projectIds:string[]) {
if(!projectIds) {
throw Err.Project.projectNotFound
}
if(projectIds.length==0) {
return;
}
let mysql=getMysqlInstance()
await mysql.execute(generateDeleteSql(projectMemberModel,{
project_id:{
exp:"in",
value:projectIds
}
}))
}
async list(organizationId:string,page:number,size:number,keyword?:string,userId?:string):Promise<{
count:number,
totalPage:number,
data:ICommon_Model_Project[]
@ -212,8 +229,11 @@ class ProjectMapper extends Mapper<typeof projectModel>{
if(page===undefined || page<0 || size===undefined || size<=0) {
throw Err.Common.paramError
}
if(!organizationId) {
throw Err.Organization.organizationNotFound
}
var mysql=getMysqlInstance();
let str=`select count(1) from ${Table_Project}`,keywrodStr="",userIdStr=""
let str=`select count(1) from ${Table_Project} where organization_id=${organizationId}`,keywrodStr="",userIdStr=""
if(keyword) {
keywrodStr=`name like '%${keyword}%'`
}
@ -230,6 +250,7 @@ class ProjectMapper extends Mapper<typeof projectModel>{
let count=Object.values(await mysql.executeOne<number>(str))[0]
let totalPage=CommonUtil.pageTotal(count,size)
let ret=await mysql.execute(generateQuerySql(projectModel,[],{
organization_id:organizationId,
...(keyword && {
name:{
exp:"%like%",
@ -473,5 +494,82 @@ class ProjectMapper extends Mapper<typeof projectModel>{
})
return arr;
}
async clearRole(projectId:string) {
if(!projectId) {
throw Err.Project.projectNotFound
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(projectRoleModel,["id"],{
project_id:projectId
}))
if(ret.length>0) {
await mysql.execute(generateDeleteSql(projectRoleModel,{
project_id:projectId
}))
await mysql.execute(generateDeleteSql(rolelPermissionModel,{
role_id:{
exp:"in",
value:ret.map(item=>item.id)
}
}))
}
}
async clearRoleByProjectIds(projectIds:string[]) {
if(!projectIds) {
throw Err.Project.projectNotFound
}
if(projectIds.length==0) {
return;
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(projectRoleModel,["id"],{
project_id:{
exp:"in",
value:projectIds
}
}))
if(ret.length>0) {
await mysql.execute(generateDeleteSql(projectRoleModel,{
project_id:{
exp:"in",
value:projectIds
}
}))
await mysql.execute(generateDeleteSql(rolelPermissionModel,{
role_id:{
exp:"in",
value:ret.map(item=>item.id)
}
}))
}
}
async getProjectListByOrganizationId(organizationId:string) {
if(!organizationId) {
throw Err.Organization.organizationNotFound
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(projectModel,[],{
organization_id:organizationId
},"and",{
field:"name",
type:"asc"
}))
return ret;
}
async clearProjects(projectIds:string[]){
if(!projectIds || projectIds.length==0) {
return;
}
let mysql=getMysqlInstance()
await mysql.execute(generateDeleteSql(projectModel,{
id:{
exp:"in",
value:projectIds
}
}))
}
}
export let projectMapper=new ProjectMapper

View File

@ -334,6 +334,54 @@ class ReleaseMapper extends Mapper<typeof projectReleaseModel> {
let issueList=await mysql.execute(sql)
return issueList
}
async clear(projectId:string) {
if(!projectId) {
throw Err.Project.projectNotFound
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(projectReleaseModel,["id"],{
project_id:projectId
}))
if(ret.length>0) {
await mysql.execute(generateDeleteSql(projectReleaseModel,{
project_id:projectId
}))
await mysql.execute(generateDeleteSql(projectReleaseIssueModel,{
project_release_id:{
exp:"in",
value:ret.map(item=>item.id)
}
}))
}
}
async clearByProjectIds(projectIds:string[]) {
if(!projectIds || projectIds.length==0) {
return
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(projectReleaseModel,["id"],{
project_id:{
exp:"in",
value:projectIds
}
}))
if(ret.length>0) {
await mysql.execute(generateDeleteSql(projectReleaseModel,{
project_id:{
exp:"in",
value:projectIds
}
}))
await mysql.execute(generateDeleteSql(projectReleaseIssueModel,{
project_release_id:{
exp:"in",
value:ret.map(item=>item.id)
}
}))
}
}
}
export let releaseMapper=new ReleaseMapper

View File

@ -46,5 +46,21 @@ class TagMapper extends Mapper<typeof projectLabelModel> {
project_id:projectId
}))
}
async deleteByProjectIds(projectIds:string[]) {
if(!projectIds) {
throw Err.Project.Module.moduleNotFound
}
if(projectIds.length==0) {
return;
}
let mysql=getMysqlInstance()
await mysql.execute(generateDeleteSql(projectLabelModel,{
project_id:{
exp:"in",
value:projectIds
}
}))
}
}
export let tagMapper=new TagMapper

View File

@ -8,6 +8,8 @@ import { keys } from "../../../common/transform";
import { getMysqlInstance } from "../../common/db/mysql";
import { Mapper } from "../../common/entity/mapper";
import { generateBatchCreateSql, generateCreateSql, generateDeleteSql, generateLeftJoin2Sql, generateLeftJoinSql, generateQuerySql, generateSnowId, generateUpdateSql } from "../../common/util/sql";
import { fieldSolutionWorkflowNodeFieldTypeModel } from './../../../common/model/field_solution_workflow_node_field_type';
import { fieldSolutionWorkflowSolutionModel } from './../../../common/model/field_solution_workflow_solution';
import { issueTypeModel } from './../../../common/model/issue_type';
import { ICommon_Model_Issue_Type_Solution, issueTypeSolutionModel } from './../../../common/model/issue_type_solution';
import { issueTypeSolutionIssueTypeModel } from './../../../common/model/issue_type_solution_issue_type';
@ -19,17 +21,23 @@ class WorkflowMapper extends Mapper<typeof workflowModel> {
constructor() {
super(workflowModel)
}
async getReservedItem() {
async getReservedItem(organizationId:string) {
let mysql=getMysqlInstance()
let ret=await mysql.executeOne(generateQuerySql(workflowModel,[],{
reserved:1
reserved:1,
organization_id:organizationId
}))
return ret;
}
async list():Promise<ICommon_Model_Workflow[]>
async list(organizationId:string):Promise<ICommon_Model_Workflow[]>
{
if(!organizationId) {
throw Err.Organization.organizationNotFound
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(workflowModel,[],null,null,{
let ret=await mysql.execute(generateQuerySql(workflowModel,[],{
organization_id:organizationId
},null,{
field:"name",
type:"asc"
}))
@ -56,12 +64,12 @@ class WorkflowMapper extends Mapper<typeof workflowModel> {
return ret;
}
async revoke(workflowId:string) {
async revoke(workflowId:string,organizationId:string) {
if(!workflowId) {
throw Err.Project.Workflow.workflowNotFound
}
let mysql=getMysqlInstance()
let objWorkflow=await workflowMapper.getReservedItem()
let objWorkflow=await workflowMapper.getReservedItem(organizationId)
await mysql.execute(generateUpdateSql(workflowSolutionWorkflowIssueTypeModel,{
workflow_id:objWorkflow.id
},{
@ -124,6 +132,106 @@ class WorkflowMapper extends Mapper<typeof workflowModel> {
return ret!=null
}
async init(organizationId: string) {
if (!organizationId) {
throw Err.Organization.organizationNotFound
}
let mysql = getMysqlInstance()
let workflowId = await generateSnowId()
await mysql.execute(generateCreateSql(workflowModel, {
id: workflowId,
name: "default",
description: "",
reserved: 1,
organization_id: organizationId
}))
let workflowNodeOpenId = await generateSnowId()
let workflowNodeProgressId = await generateSnowId()
let workflowNodeClosedId = await generateSnowId()
let workflowNodeResolvedId = await generateSnowId()
await mysql.execute(generateCreateSql(workflowNodeModel, {
id: workflowNodeOpenId,
name: "open",
status: ECommon_Model_Workflow_Node_Status.NOTSTART,
workflow_id: workflowId,
x: 50,
y: 45
}))
await mysql.execute(generateCreateSql(workflowNodeModel, {
id: workflowNodeProgressId,
name: "in progress",
status: ECommon_Model_Workflow_Node_Status.INPROGRESS,
workflow_id: workflowId,
x: 281,
y: 177
}))
await mysql.execute(generateCreateSql(workflowNodeModel, {
id: workflowNodeClosedId,
name: "closed",
status: ECommon_Model_Workflow_Node_Status.DONE,
workflow_id: workflowId,
x: 59,
y: 502
}))
await mysql.execute(generateCreateSql(workflowNodeModel, {
id: workflowNodeResolvedId,
name: "resolved",
status: ECommon_Model_Workflow_Node_Status.DONE,
workflow_id: workflowId,
x: 507,
y: 503
}))
let actionOpenToProgressId = await generateSnowId()
let actionProgressToOpenId = await generateSnowId()
let actionOpenToClosedId = await generateSnowId()
let actionClosedToOpenId = await generateSnowId()
let actionProgressToResolvedId = await generateSnowId()
let actionResolvedToProgressId = await generateSnowId()
await mysql.execute(generateCreateSql(workflowActionModel, {
id: actionOpenToProgressId,
name: "open to progress",
workflow_id: workflowId,
source_node_id: workflowNodeOpenId,
dest_node_id: workflowNodeProgressId
}))
await mysql.execute(generateCreateSql(workflowActionModel, {
id: actionProgressToOpenId,
name: "progress to open",
workflow_id: workflowId,
source_node_id: workflowNodeProgressId,
dest_node_id: workflowNodeOpenId
}))
await mysql.execute(generateCreateSql(workflowActionModel, {
id: actionOpenToClosedId,
name: "open to close",
workflow_id: workflowId,
source_node_id: workflowNodeOpenId,
dest_node_id: workflowNodeClosedId
}))
await mysql.execute(generateCreateSql(workflowActionModel, {
id: actionClosedToOpenId,
name: "closed to open",
workflow_id: workflowId,
source_node_id: workflowNodeClosedId,
dest_node_id: workflowNodeOpenId
}))
await mysql.execute(generateCreateSql(workflowActionModel, {
id: actionProgressToResolvedId,
name: "progress to resolved",
workflow_id: workflowId,
source_node_id: workflowNodeProgressId,
dest_node_id: workflowNodeResolvedId
}))
await mysql.execute(generateCreateSql(workflowActionModel, {
id: actionResolvedToProgressId,
name: "resolved to progress",
workflow_id: workflowId,
source_node_id: workflowNodeResolvedId,
dest_node_id: workflowNodeProgressId
}))
return workflowId;
}
}
export let workflowMapper=new WorkflowMapper
@ -131,17 +239,23 @@ class WorkflowSolutionMapper extends Mapper<typeof workflowSolutionModel> {
constructor() {
super(workflowSolutionModel)
}
async getReservedItem() {
async getReservedItem(organizationId:string) {
let mysql=getMysqlInstance()
let ret=await mysql.executeOne(generateQuerySql(workflowSolutionModel,[],{
reserved:1
reserved:1,
organization_id:organizationId
}))
return ret;
}
async list():Promise<ICommon_Model_Workflow_Solution[]>
async list(organizationId:string):Promise<ICommon_Model_Workflow_Solution[]>
{
if(!organizationId) {
throw Err.Organization.organizationNotFound
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(workflowSolutionModel,[],null,null,{
let ret=await mysql.execute(generateQuerySql(workflowSolutionModel,[],{
organization_id:organizationId
},null,{
field:"name",
type:"asc"
}))
@ -164,14 +278,14 @@ class WorkflowSolutionMapper extends Mapper<typeof workflowSolutionModel> {
return obj;
}
async bindIssueTypeSolutionList(workflowSolutionId:string,issueTypeSolutionIds:string[]) {
async bindIssueTypeSolutionList(workflowSolutionId:string,issueTypeSolutionIds:string[],organizationId:string) {
if(!issueTypeSolutionIds || issueTypeSolutionIds.length==0) {
throw Err.Project.Issue.issueTypeSolutionNotFound
} else if(!workflowSolutionId) {
throw Err.Project.Workflow.workflowSolutionNotFound
}
let mysql=getMysqlInstance()
let workflowId=(await workflowMapper.getReservedItem()).id;
let workflowId=(await workflowMapper.getReservedItem(organizationId)).id;
for(let issueTypeSolutionId of issueTypeSolutionIds) {
await mysql.execute(generateCreateSql(workflowSolutionIssueTypeSolutionModel,{
id:await generateSnowId(),
@ -532,6 +646,115 @@ class WorkflowSolutionMapper extends Mapper<typeof workflowSolutionModel> {
let ret=await mysql.execute(sql)
return ret;
}
async clearByOrganizationId(organizationId:string) {
if(!organizationId) {
throw Err.Organization.organizationNotFound
}
let mysql=getMysqlInstance()
let workflowSolutionList =await mysql.execute(generateQuerySql(workflowSolutionModel,["id"],{
organization_id:organizationId
}))
if(workflowSolutionList.length>0){
let ids=workflowSolutionList.map(item=>item.id);
await mysql.execute(generateDeleteSql(workflowSolutionModel,{
organization_id:organizationId
}))
await mysql.execute(generateDeleteSql(workflowSolutionIssueTypeSolutionModel,{
workflow_solution_id:{
exp:"in",
value:ids
}
}))
await mysql.execute(generateDeleteSql(workflowSolutionWorkflowModel,{
workflow_solution_id:{
exp:"in",
value:ids
}
}))
await mysql.execute(generateDeleteSql(workflowSolutionWorkflowIssueTypeModel,{
workflow_solution_id:{
exp:"in",
value:ids
}
}))
await mysql.execute(generateDeleteSql(fieldSolutionWorkflowSolutionModel,{
workflow_solution_id:{
exp:"in",
value:ids
}
}))
await mysql.execute(generateDeleteSql(fieldSolutionWorkflowNodeFieldTypeModel,{
workflow_solution_id:{
exp:"in",
value:ids
}
}))
}
let workflowList =await mysql.execute(generateQuerySql(workflowModel,["id"],{
organization_id:organizationId
}))
if(workflowList.length>0) {
let ids=workflowSolutionList.map(item=>item.id);
await mysql.execute(generateDeleteSql(workflowModel,{
organization_id:organizationId
}))
await mysql.execute(generateDeleteSql(workflowNodeModel,{
workflow_id:{
exp:"in",
value:ids
}
}))
await mysql.execute(generateDeleteSql(workflowActionModel,{
workflow_id:{
exp:"in",
value:ids
}
}))
}
}
async init(issueTypeSolutionId: string, issueTypeSolutionName: string, issueTypeTaskId: string, issueTypeBugId: string, issueTypeTicketId: string, workflowId: string, organizationId: string) {
let mysql=getMysqlInstance()
let workflowSolutionId = await generateSnowId()
await mysql.execute(generateCreateSql(workflowSolutionModel, {
id: workflowSolutionId,
reserved: 1,
name: issueTypeSolutionName,
organization_id: organizationId
}))
await mysql.execute(generateCreateSql(workflowSolutionWorkflowModel, {
id: await generateSnowId(),
workflow_solution_id: workflowSolutionId,
workflow_id: workflowId
}))
await mysql.execute(generateCreateSql(workflowSolutionIssueTypeSolutionModel, {
id: await generateSnowId(),
workflow_solution_id: workflowSolutionId,
issue_type_solution_id: issueTypeSolutionId
}))
await mysql.execute(generateCreateSql(workflowSolutionWorkflowIssueTypeModel, {
id: await generateSnowId(),
workflow_solution_id: workflowSolutionId,
workflow_id: workflowId,
issue_type_id: issueTypeTaskId,
issue_type_solution_id: issueTypeSolutionId
}))
await mysql.execute(generateCreateSql(workflowSolutionWorkflowIssueTypeModel, {
id: await generateSnowId(),
workflow_solution_id: workflowSolutionId,
workflow_id: workflowId,
issue_type_id: issueTypeBugId,
issue_type_solution_id: issueTypeSolutionId
}))
await mysql.execute(generateCreateSql(workflowSolutionWorkflowIssueTypeModel, {
id: await generateSnowId(),
workflow_solution_id: workflowSolutionId,
workflow_id: workflowId,
issue_type_id: issueTypeTicketId,
issue_type_solution_id: issueTypeSolutionId
}))
}
}
export let workflowSolutionMapper=new WorkflowSolutionMapper

View File

@ -0,0 +1,68 @@
import { ECommon_Model_Project_Member_Type } from "../../../common/model/project_member";
import { Err } from "../../../common/status/error";
import IServer_Common_RPC_Cooperation from "../../common/rpc/api/cooperation";
import { DRPCRecieve } from "../../common/rpc/rpc";
import { FieldSolutionService } from "../service/field";
import ProjectService from "../service/project";
import FieldTypeService from './../service/field';
import IssueTypeService, { IssueTypeSolutionService } from './../service/issueType';
import WorkflowService, { WorkflowSolutionService } from './../service/workflow';
class RpcCooperationApi implements IServer_Common_RPC_Cooperation {
@DRPCRecieve
async clearProject(organizationId:string) {
if(!organizationId) {
throw Err.Organization.organizationNotFound;
}
let ret=await ProjectService.getProjectListByOrganizationId(organizationId)
await ProjectService.clearProjects(ret.map(item=>item.id));
}
@DRPCRecieve
async clearField(organizationId:string){
if(!organizationId) {
throw Err.Organization.organizationNotFound;
}
await FieldSolutionService.clearFieldByOrganizationId(organizationId);
}
@DRPCRecieve
async clearWorkflow(organizationId:string) {
if(!organizationId) {
throw Err.Organization.organizationNotFound;
}
await WorkflowSolutionService.clearByOrganizationId(organizationId);
}
@DRPCRecieve
async clearIssueType(organizationId:string) {
if(!organizationId) {
throw Err.Organization.organizationNotFound;
}
await IssueTypeSolutionService.clearByOrganizationId(organizationId);
}
@DRPCRecieve
async initIssueTypeWorkflowAndSolution(organizationId: string,projectId?:string) {
let objIssueType=await IssueTypeService.init(organizationId);
let objIssueTypeSolution=await IssueTypeSolutionService.init(organizationId,objIssueType)
let workflowId = await WorkflowService.init(organizationId)
await WorkflowSolutionService.init(objIssueTypeSolution.solutionId,objIssueTypeSolution.solutionName,objIssueType.taskId,objIssueType.bugId,objIssueType.ticketId,workflowId,organizationId);
}
@DRPCRecieve
async initProject(userId: string, projectRoleUserId: string, organizationId: string):Promise<string> {
let objProject=new ProjectService
objProject.assignItem({
name:"test",
keyword:"test",
organization_id:organizationId,
created_by:userId
})
await objProject.create()
objProject.addMember(userId,ECommon_Model_Project_Member_Type.USER,projectRoleUserId)
return objProject.getId();
}
@DRPCRecieve
async initField() {
await FieldTypeService.init()
}
}
export default new RpcCooperationApi;

View File

@ -18,14 +18,17 @@ export default class FieldType extends Entity<typeof fieldTypeModel,typeof field
return ret;
}
static async init() {
await fieldTypeMapper.init();
}
}
export class FieldSolutionService extends Entity<typeof fieldSolutionModel,typeof fieldSolutionMapper> {
constructor(){
super(fieldSolutionMapper)
}
static async list(){
let ret=await fieldSolutionMapper.list()
static async list(organizationId:string){
let ret=await fieldSolutionMapper.list(organizationId)
return ret;
}
@ -351,4 +354,8 @@ export class FieldSolutionService extends Entity<typeof fieldSolutionModel,typeo
let arr=await fieldSolutionMapper.getFieldTypesByFieldIds(fieldIds)
return arr;
}
static async clearFieldByOrganizationId(organizationId:string) {
await fieldSolutionMapper.clearFieldSolutionByOrganizationId(organizationId);
}
}

View File

@ -9,6 +9,7 @@ import { generateSnowId } from '../../common/util/sql';
import ProjectService from "../service/project";
import { ICommon_Model_Project_Issue, projectIssueModel } from './../../../common/model/project_issue';
import { ICommon_Model_Project_Issue_Field_Value } from './../../../common/model/project_issue_field_value';
import { commentMapper } from './../mapper/comment';
import { projectIssueMapper } from './../mapper/issue';
import { FieldSolutionService } from './field';
import ProjectModuleService from './module';
@ -242,6 +243,7 @@ export default class ProjectIssue extends Entity<typeof projectIssueModel,typeof
override async delete(eventPulish?: EServer_Common_Event_Types.Types): Promise<void> {
await super.delete()
await projectIssueMapper.clear(this.getId())
await commentMapper.clear(this.getId());
}
async getBasicInfo() {
@ -386,5 +388,14 @@ export default class ProjectIssue extends Entity<typeof projectIssueModel,typeof
let ret=await projectIssueMapper.filter(projectId ,page ,size ,createdBy ,issueTypeId,name,priority,assignerId,reporterId,status,moduleId,tagId)
return ret;
}
static async clearByProjectIds(projectIds:string[]) {
let ret=await projectIssueMapper.getIdsByProjectIds(projectIds);
if(ret.length>0) {
await projectIssueMapper.clearMany(ret);
await commentMapper.clearByProjectIssueIds(ret)
}
}
}

View File

@ -10,8 +10,8 @@ export default class IssueType extends Entity<typeof issueTypeModel,typeof issue
constructor(){
super(issueTypeMapper)
}
static async list(){
let ret=await issueTypeMapper.list()
static async list(organizationId:string){
let ret=await issueTypeMapper.list(organizationId)
return ret;
}
override async delete() {
@ -19,6 +19,42 @@ export default class IssueType extends Entity<typeof issueTypeModel,typeof issue
await issueTypeMapper.deleteFromSolution(this.getId());
await WorkflowSolutionService.clearIssueType(this.getId())
}
static async init(organizationId:string):Promise<{
taskId:string,
bugId:string,
ticketId:string
}> {
if(!organizationId) {
throw Err.Organization.organizationNotFound
}
let objTask=new IssueType;
objTask.assignItem({
name:"Task",
reserved:1,
organization_id:organizationId
})
await objTask.create();
let objBug=new IssueType;
objBug.assignItem({
name:"Bug",
reserved:1,
organization_id:organizationId
})
await objBug.create();
let objTicket=new IssueType;
objTicket.assignItem({
name:"Ticket",
reserved:1,
organization_id:organizationId
})
await objTicket.create();
return {
taskId:objTask.getId(),
bugId:objBug.getId(),
ticketId:objTicket.getId()
};
}
}
export class IssueTypeSolutionService extends Entity<typeof issueTypeSolutionModel,typeof issueTypeSolutionMapper> {
@ -39,7 +75,7 @@ export class IssueTypeSolutionService extends Entity<typeof issueTypeSolutionMod
}
override async create():Promise<ICommon_Model_Issue_Type_Solution> {
let ret=await super.create();
let objWorkflowReserved=await WorkflowSolutionService.getReservedItem()
let objWorkflowReserved=await WorkflowSolutionService.getReservedItem(ret.organization_id)
objWorkflowReserved.bindIssueTypeSolutions([this.getId()])
return ret;
}
@ -55,11 +91,11 @@ export class IssueTypeSolutionService extends Entity<typeof issueTypeSolutionMod
if(objWorkflowSolution) {
await objWorkflowSolution.unbindIssueTypeSolutions([this.getId()]);
}
await issueTypeSolutionMapper.resetProjects(this.getId());
await issueTypeSolutionMapper.resetProjects(this.getId(),this.getItem().organization_id);
}
static async list(){
let ret=await issueTypeSolutionMapper.list()
static async list(organizationId:string){
let ret=await issueTypeSolutionMapper.list(organizationId)
let arr:ICommon_Route_Res_IssueTypeSolution_List_Item[]=[]
for(let obj of ret) {
arr.push({
@ -97,7 +133,7 @@ export class IssueTypeSolutionService extends Entity<typeof issueTypeSolutionMod
await issueTypeSolutionMapper.addIssueType(issueTypeId,this.getId())
let objWorkflowSolution=await WorkflowSolutionService.getItemByIssueTypeSolutionId(this.getId())
if(objWorkflowSolution) {
let reserved=await WorkflowService.getReservedItem()
let reserved=await WorkflowService.getReservedItem(this.getItem().organization_id)
await objWorkflowSolution.assign(issueTypeId,reserved.getId(),this.getId())
}
}
@ -110,8 +146,8 @@ export class IssueTypeSolutionService extends Entity<typeof issueTypeSolutionMod
}
}
static async getReservedItem() {
let obj=await issueTypeSolutionMapper.getReservedItem()
static async getReservedItem(organizationId:string) {
let obj=await issueTypeSolutionMapper.getReservedItem(organizationId)
let ret=new IssueTypeSolutionService
ret.setItem(obj)
return ret;
@ -136,7 +172,7 @@ export class IssueTypeSolutionService extends Entity<typeof issueTypeSolutionMod
if(!objProject) {
throw Err.Project.projectNotFound
}
await issueTypeSolutionMapper.unbindProject(this.getId(),projectId)
await issueTypeSolutionMapper.unbindProject(this.getId(),projectId,this.getItem().organization_id)
}
async projectList():Promise<{
@ -171,4 +207,39 @@ export class IssueTypeSolutionService extends Entity<typeof issueTypeSolutionMod
}
}
static async clearByOrganizationId(organizationId:string) {
await issueTypeSolutionMapper.clearByOrganizationId(organizationId)
}
static async init(organizationId:string,issueTypeIds:{
taskId:string,
bugId:string,
ticketId:string
},projectId?:string):Promise<{
solutionId:string,
solutionName:string
}> {
if(!organizationId) {
throw Err.Organization.organizationNotFound
}
let objSolution=new IssueTypeSolutionService;
objSolution.assignItem({
name:"Default",
description:"Default",
reserved:1,
organization_id:organizationId
})
await objSolution.create()
await issueTypeSolutionMapper.addIssueType(issueTypeIds.taskId,objSolution.getId());
await issueTypeSolutionMapper.addIssueType(issueTypeIds.bugId,objSolution.getId());
await issueTypeSolutionMapper.addIssueType(issueTypeIds.ticketId,objSolution.getId());
if(projectId) {
issueTypeSolutionMapper.bindProject(objSolution.getId(),projectId);
}
return {
solutionId:objSolution.getId(),
solutionName:objSolution.getItem().name
}
}
}

View File

@ -5,8 +5,11 @@ import { Entity } from "../../common/entity/entity";
import { EServer_Common_Event_Types } from "../../common/event/types";
import { moduleMapper } from "../mapper/module";
import { projectMapper } from '../mapper/project';
import ProjectIssueService from "../service/issue";
import { ICommon_Model_Project, projectModel } from './../../../common/model/project';
import { ECommon_Model_Project_Member_Type } from './../../../common/model/project_member';
import { issueTypeSolutionMapper } from './../mapper/issueType';
import { releaseMapper } from './../mapper/release';
import { tagMapper } from './../mapper/tag';
import { FieldSolutionService } from './field';
import { IssueTypeSolutionService } from './issueType';
@ -20,6 +23,10 @@ export default class Project extends Entity<typeof projectModel,typeof projectMa
await moduleMapper.deleteByProjectId(this.item.id)
await tagMapper.deleteByProjectId(this.item.id)
await projectMapper.clearMember(this.item.id);
await projectMapper.clearRole(this.item.id);
await ProjectIssueService.clearByProjectIds([this.item.id]);
await releaseMapper.clear(this.item.id);
await issueTypeSolutionMapper.clearProjects([this.item.id]);
}
override async create(): Promise<ICommon_Model_Project> {
@ -28,7 +35,7 @@ export default class Project extends Entity<typeof projectModel,typeof projectMa
if(role) {
await projectMapper.addMember(this.getId(),this.getItem().created_by,ECommon_Model_Project_Member_Type.USER,role.id)
}
let issueTypeSolution=await IssueTypeSolutionService.getReservedItem()
let issueTypeSolution=await IssueTypeSolutionService.getReservedItem(ret.organization_id)
await issueTypeSolution.bindProject(this.getId())
return ret;
}
@ -50,8 +57,8 @@ export default class Project extends Entity<typeof projectModel,typeof projectMa
await projectMapper.changeRole(this.item.id,memberId,roleId)
}
static async list(page:number,size:number,keyword?:string,userId?:string):Promise<ICommon_Route_Res_Project_List>{
let ret=await projectMapper.list(page,size,keyword,userId)
static async list(organizationId:string,page:number,size:number,keyword?:string,userId?:string):Promise<ICommon_Route_Res_Project_List>{
let ret=await projectMapper.list(organizationId,page,size,keyword,userId)
return {
count:ret.count,
totalPage:ret.totalPage,
@ -151,4 +158,20 @@ export default class Project extends Entity<typeof projectModel,typeof projectMa
let arr=await projectMapper.listUser(this.getId(),keyword)
return arr;
}
static async getProjectListByOrganizationId(organizationId:string) {
let ret=await projectMapper.getProjectListByOrganizationId(organizationId);
return ret;
}
static async clearProjects(projectIds:string[]) {
await projectMapper.clearProjects(projectIds);
await moduleMapper.deleteByProjectIds(projectIds)
await tagMapper.deleteByProjectIds(projectIds)
await projectMapper.clearMemberByProjectIds(projectIds);
await projectMapper.clearRoleByProjectIds(projectIds);
await ProjectIssueService.clearByProjectIds(projectIds);
await releaseMapper.clearByProjectIds(projectIds);
await issueTypeSolutionMapper.clearProjects(projectIds);
}
}

View File

@ -16,12 +16,12 @@ export default class Workflow extends Entity<typeof workflowModel,typeof workflo
constructor(){
super(workflowMapper)
}
static async list(){
let ret=await workflowMapper.list()
static async list(organizationId:string){
let ret=await workflowMapper.list(organizationId)
return ret;
}
static async getReservedItem () {
let ret=await workflowMapper.getReservedItem()
static async getReservedItem (organizationId:string) {
let ret=await workflowMapper.getReservedItem(organizationId)
let workflow=new Workflow
workflow.setItem(ret);
return workflow;
@ -117,7 +117,7 @@ export default class Workflow extends Entity<typeof workflowModel,typeof workflo
override async delete(eventPulish?: EServer_Common_Event_Types.Types): Promise<void> {
await super.delete()
await workflowMapper.revoke(this.getId())
await workflowMapper.revoke(this.getId(),this.getItem().organization_id)
await FieldSolutionService.clearItemsByWorkflowId(this.getId())
}
@ -142,14 +142,18 @@ export default class Workflow extends Entity<typeof workflowModel,typeof workflo
return ret;
}
static async init(organizationId:string) {
let workflowId=await workflowMapper.init(organizationId);
return workflowId;
}
}
export class WorkflowSolutionService extends Entity<typeof workflowSolutionModel,typeof workflowSolutionMapper> {
constructor(){
super(workflowSolutionMapper)
}
static async list(){
let ret=await workflowSolutionMapper.list()
static async list(organizationId:string){
let ret=await workflowSolutionMapper.list(organizationId)
return ret;
}
static async getItemByIssueTypeSolutionId(issueSolutionId:string) {
@ -169,8 +173,8 @@ export class WorkflowSolutionService extends Entity<typeof workflowSolutionModel
return ret;
}
static async getReservedItem () {
let ret=await workflowSolutionMapper.getReservedItem()
static async getReservedItem (organizationId:string) {
let ret=await workflowSolutionMapper.getReservedItem(organizationId)
let obj=new WorkflowSolutionService()
obj.setItem(ret)
return obj;
@ -187,7 +191,7 @@ export class WorkflowSolutionService extends Entity<typeof workflowSolutionModel
if(existIssueTypeSolutionIds.length>0) {
await WorkflowSolutionService.clearIssueTypeSolutions(existIssueTypeSolutionIds)
}
await workflowSolutionMapper.bindIssueTypeSolutionList(this.getId(),issueTypeSolutionIds)
await workflowSolutionMapper.bindIssueTypeSolutionList(this.getId(),issueTypeSolutionIds,this.getItem().organization_id)
}
async unbindIssueTypeSolutions(issueTypeSolutionIds:string[]=null) {
await workflowSolutionMapper.unbindIssueTypeSolution(this.getId(),issueTypeSolutionIds)
@ -202,7 +206,7 @@ export class WorkflowSolutionService extends Entity<typeof workflowSolutionModel
throw Err.Project.Workflow.unbindReservedWorkflowSolutionForbidden
}
await workflowSolutionMapper.unbindIssueTypeSolution(this.getId(),issueTypeSolutionIds)
let objWorkflowReserved=await WorkflowSolutionService.getReservedItem()
let objWorkflowReserved=await WorkflowSolutionService.getReservedItem(this.getItem().organization_id)
objWorkflowReserved.bindIssueTypeSolutions(issueTypeSolutionIds)
}
@ -250,7 +254,7 @@ export class WorkflowSolutionService extends Entity<typeof workflowSolutionModel
override async create(): Promise<ICommon_Model_Workflow_Solution> {
let ret=await super.create()
let obj=await workflowMapper.getReservedItem()
let obj=await workflowMapper.getReservedItem(ret.organization_id)
await workflowSolutionMapper.addWorkflow(this.getId(),obj.id)
return ret
}
@ -325,6 +329,14 @@ export class WorkflowSolutionService extends Entity<typeof workflowSolutionModel
}
return true
}
static async clearByOrganizationId(organizationId:string){
await workflowSolutionMapper.clearByOrganizationId(organizationId)
}
static async init(issueTypeSolutionId:string,issueTypeSolutionName:string,issueTypeTaskId:string,issueTypeBugId:string,issueTypeTicketId:string,workflowId:string,organizationId:string) {
await workflowSolutionMapper.init(issueTypeSolutionId,issueTypeSolutionName,issueTypeTaskId,issueTypeBugId,issueTypeTicketId,workflowId,organizationId)
}
}
export class WorkflowNodeService extends Entity<typeof workflowNodeModel,typeof workflowNodeMapper> {

View File

@ -1,5 +1,5 @@
import { ECommon_Model_File_Type } from '../../../common/model/file';
import * as fileApi from "../../../common/routes/file";
import fileApi from "../../../common/routes/file";
import { Err } from '../../../common/status/error';
import { DComponent } from "../../common/decorate/component";
import { DHttpApi, DHttpController, DHttpReqParamRequired, DHttpUser } from "../../common/http/http";

View File

@ -1,32 +1,35 @@
import * as Koa from "koa";
import * as koaStaticServer from "koa-static-server";
import * as path from "path";
import { ECommon_User_Type } from "../../../common/model/user";
import { Permission_Base } from '../../../common/permission/permission';
import * as fieldApi from "../../../common/routes/field";
import * as fileApi from "../../../common/routes/file";
import * as gatewayApi from "../../../common/routes/gateway";
import * as issueApi from "../../../common/routes/issue";
import * as issueTypeApi from "../../../common/routes/issueType";
import * as projectApi from "../../../common/routes/project";
import * as releaseApi from "../../../common/routes/release";
import * as teamApi from "../../../common/routes/team";
import fieldApi from "../../../common/routes/field";
import fileApi from "../../../common/routes/file";
import gatewayApi from "../../../common/routes/gateway";
import issueApi from "../../../common/routes/issue";
import issueTypeApi from "../../../common/routes/issueType";
import organizationApi from "../../../common/routes/organization";
import projectApi from "../../../common/routes/project";
import releaseApi from "../../../common/routes/release";
import teamApi from "../../../common/routes/team";
import { ICommon_HttpApi } from "../../../common/routes/types";
import * as userApi from "../../../common/routes/user";
import * as workflowApi from "../../../common/routes/workflow";
import userApi from "../../../common/routes/user";
import workflowApi from "../../../common/routes/workflow";
import { Err } from "../../../common/status/error";
import { ECommon_Services } from "../../../common/types";
import Application, { ECommon_Application_Mode } from "../../common/app/app";
import { deletePermission, processPermission } from '../../common/permission/base';
import { getOrganizationPermission } from "../../common/permission/organization";
import { proxyRequest } from "../../common/rpc/rpc";
import { EServer_Common_Http_Body_Type, IServer_Common_Http_Proxy } from "../../common/types/http";
import { EServer_Common_User_Type } from '../../common/types/user';
import { generateHttpOkResponse } from "../../common/util/http";
import "../http/gateway";
import userRpcApi from '../rpc/user';
import { checkIfNeedInit, handleImageFields } from "../util/util";
import { ECommon_Organization_User_Role } from './../../../common/model/organization_user';
import { CacheService } from './../cache/service';
var apis:ICommon_HttpApi[]=[userApi,projectApi,teamApi,fileApi,issueTypeApi,workflowApi,fieldApi,issueApi,releaseApi,gatewayApi];
var apis:ICommon_HttpApi[]=[userApi,projectApi,teamApi,fileApi,issueTypeApi,workflowApi,fieldApi,issueApi,releaseApi,gatewayApi,organizationApi];
export default class GateWay extends Application {
override async config(app: Koa<Koa.DefaultState, Koa.DefaultContext>) {
let cacheService=new CacheService()
@ -101,11 +104,15 @@ export default class GateWay extends Application {
let permissionDelete:object;
if(permission && ((Array.isArray(permission) && permission.length>0) || (typeof(permission)=="object" && !Array.isArray(permission) && Array.isArray(permission.data) && permission.data.length>0))) {
if(ctx.state.user) {
if(ctx.state.user.type==EServer_Common_User_Type.USER) {
if(ctx.state.user.type==ECommon_User_Type.USER) {
let organizationRole:ECommon_Organization_User_Role=null;
if(ctx.get("organizationid")) {
organizationRole=await getOrganizationPermission(ctx.get("organizationid"),ctx.state.user.userId);
}
let per=Array.isArray(permission)?permission:permission.data;
let [isCheck,map] =await processPermission(per,Object.assign({},obj.data,{
userId:ctx.state.user?ctx.state.user.userId:undefined,
isAdmin:ctx.state.user.type===EServer_Common_User_Type.ADMIN
isAdmin:ctx.state.user.type===ECommon_User_Type.ADMIN || organizationRole===ECommon_Organization_User_Role.ADMIN
}))
if(isCheck && typeof(permission)=="object" && !Array.isArray(permission) && Array.isArray(permission.data)) {
permissionDelete=map;
@ -133,7 +140,7 @@ export default class GateWay extends Application {
if(ret.data===undefined || typeof(ret.data)=="string" || typeof(ret.data)=="number" || typeof(ret.data)=="boolean" || typeof(ret.data)=="object")
{
if(typeof(ret.data)=="object") {
await handleImageFields(ret.data);
await handleImageFields(ret.data,ctx.get("organizationid"));
}
ctx.body = generateHttpOkResponse(ret.data);
} else {

View File

@ -1,4 +1,5 @@
import * as gateApi from "../../../common/routes/gateway";
import gateApi from "../../../common/routes/gateway";
import Application from "../../common/app/app";
import { DComponent } from "../../common/decorate/component";
import { DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired } from "../../common/http/http";
import { GateWayService } from './../service/http';
@ -15,4 +16,11 @@ class GatewayController {
async editConfig(@DHttpReqParamRequired("dbUrl") dbUrl:string,@DHttpReqParam("dbPort") dbPort:number,@DHttpReqParam("dbDatabase") dbDatabase:string,@DHttpReqParam("dbUsername") dbUsername:string,@DHttpReqParam("dbPassword") dbPassword:string) {
await GateWayService.editConfig(dbUrl,dbPort,dbDatabase,dbUsername,dbPassword);
}
@DHttpApi(gateApi.routes.deployInfo)
async deployInfo():Promise<typeof gateApi.routes.deployInfo.res> {
return {
type:Application.mode
}
}
}

View File

@ -7,7 +7,7 @@ class RpcUserApi implements IServer_Common_RPC_User {
return null
}
@DRPCSend(ECommon_Services.User)
async getUsersInfo(userIds: string[]): Promise<{ id: string; username: string; photo?: string; }[]> {
async getUsersInfo(userIds: string[],organizationId:string): Promise<{ id: string; username: string; photo?: string;nickname?:string }[]> {
return null;
}
}

View File

@ -1,4 +1,3 @@
import * as fs from "fs-extra";
import * as Importer from "mysql2-import";
import * as path from "path";
@ -26,6 +25,8 @@ import { Table_Field_Type_Config_Value } from './../../../common/model/field_typ
import { Table_Issue_Type } from './../../../common/model/issue_type';
import { Table_Issue_Type_Solution } from './../../../common/model/issue_type_solution';
import { Table_Issue_Type_Solution_Issue_Type } from './../../../common/model/issue_type_solution_issue_type';
import { organizationModel, Table_Organization } from './../../../common/model/organization';
import { ECommon_Organization_User_Role, organizationUserModel, Table_Organization_User } from './../../../common/model/organization_user';
import { Table_Permission } from './../../../common/model/permission';
import { Table_Project_Issue_Description } from './../../../common/model/project_issue_description';
import { Table_Project_Issue_Field_Value } from './../../../common/model/project_issue_field_value';
@ -53,7 +54,8 @@ import { Table_Workflow_Solution_Workflow, workflowSolutionWorkflowModel } from
import { OBTPConfig } from './obtp';
export async function handleImageFields(data:object){
export async function handleImageFields(data:object,organizationId:string){
let arrImage=<{
object:object,
key:string|number
@ -101,7 +103,7 @@ export async function handleImageFields(data:object){
let ids=arrUser.map(item=>{
return item.object[item.key];
})
let paths=await rpcUserApi.getUsersInfo(ids)
let paths=await rpcUserApi.getUsersInfo(ids,organizationId)
for(let i=0;i<arrUser.length;i++)
{
arrUser[i].object[arrUser[i].key]=paths[i]
@ -150,6 +152,8 @@ async function resetSystem(){
await mysql.execute(`delete from ${Table_Project_Issue_Solution}`)
await mysql.execute(`delete from ${Table_Project_Module_Issue}`)
await mysql.execute(`delete from ${Table_Project_Label_Issue}`)
await mysql.execute(`delete from ${Table_Organization}`)
await mysql.execute(`delete from ${Table_Organization_User}`)
} catch (err) {
console.log("db reset error:",err);
}
@ -260,49 +264,80 @@ export async function initSystem() {
let mysql=getMysqlInstance()
let ret=await mysql.execute<any[]>(`select * from ${Table_Version}`)
if(ret===null || ret.length==0){
let adminId=await initAdmin()
let userId=await initUser()
let adminIds=await initAdmin()
let userIds=await initUser()
let organizationId=await initOrganization(adminIds,userIds);
await initVersion()
let objPermission=await initPermission()
let {projectRoleUserId,groupRoleUserId}=await initRole(objPermission);
await initTeam(userId,groupRoleUserId);
let projectId=await initProject(userId,projectRoleUserId)
let {issueTypeBugId,issueTypeSolutionId,issueTypeSolutionName,issueTypeTaskId,issueTypeTicketId}=await initIssueType(projectId)
await initWorkflow(issueTypeSolutionId,issueTypeSolutionName,issueTypeTaskId,issueTypeBugId,issueTypeTicketId)
await initTeam(userIds[0],groupRoleUserId,organizationId);
let projectId=await initProject(userIds[0],projectRoleUserId,organizationId)
let {issueTypeBugId,issueTypeSolutionId,issueTypeSolutionName,issueTypeTaskId,issueTypeTicketId}=await initIssueType(projectId,organizationId)
await initWorkflow(issueTypeSolutionId,issueTypeSolutionName,issueTypeTaskId,issueTypeBugId,issueTypeTicketId,organizationId)
await initField()
}
console.log("init finish")
}
async function initUser():Promise<string> {
async function initOrganization(adminIds:string[],userIds:string[]):Promise<string> {
let mysql=getMysqlInstance()
let userId=await generateSnowId()
await mysql.execute(`insert into ${Table_User} (id,username,password) values ('${userId}','sx','sx')`)
await mysql.execute(`insert into ${Table_User} (id,username,password) values ('${await generateSnowId()}','wgq','wgq')`)
await mysql.execute(`insert into ${Table_User} (id,username,password) values ('${await generateSnowId()}','hxx','hxx')`)
return userId
let id=await generateSnowId()
await mysql.executeOne(generateCreateSql(organizationModel,{
id,
name:"default",
user_id:adminIds[0]
}))
let i=0;
for(let adminId of adminIds) {
await mysql.execute(generateCreateSql(organizationUserModel,{
id:await generateSnowId(),
nickname:"test"+(i++),
organization_id:id,
role:ECommon_Organization_User_Role.ADMIN,
user_id:adminId
}))
}
for(let userId of userIds) {
await mysql.execute(generateCreateSql(organizationUserModel,{
id:await generateSnowId(),
nickname:"test"+(i++),
organization_id:id,
role:ECommon_Organization_User_Role.USER,
user_id:userId
}))
}
return id;
}
async function initAdmin():Promise<string> {
async function initUser():Promise<string[]> {
let mysql=getMysqlInstance()
let adminId=await generateSnowId()
await mysql.execute(`insert into ${Table_User} (id,username,password,is_admin) values ('${adminId}','teamlinker','teamlinker',1)`)
await mysql.execute(`insert into ${Table_User} (id,username,password,is_admin) values ('${await generateSnowId()}','wgq_admin','123456',1)`)
await mysql.execute(`insert into ${Table_User} (id,username,password,is_admin) values ('${await generateSnowId()}','hxx_admin','123456',1)`)
return adminId
let userIds=[await generateSnowId(),await generateSnowId(),await generateSnowId()]
await mysql.execute(`insert into ${Table_User} (id,username,password) values ('${userIds[0]}','sx','sx')`)
await mysql.execute(`insert into ${Table_User} (id,username,password) values ('${userIds[1]}','wgq','wgq')`)
await mysql.execute(`insert into ${Table_User} (id,username,password) values ('${userIds[2]}','hxx','hxx')`)
return userIds
}
async function initTeam(userId:string,groupRoleUserId:string) {
async function initAdmin():Promise<string[]> {
let mysql=getMysqlInstance()
let adminIds=[await generateSnowId(),await generateSnowId(),await generateSnowId()]
await mysql.execute(`insert into ${Table_User} (id,username,password,role) values ('${adminIds[0]}','teamlinker','teamlinker',1)`)
await mysql.execute(`insert into ${Table_User} (id,username,password,role) values ('${adminIds[1]}','wgq_admin','123456',1)`)
await mysql.execute(`insert into ${Table_User} (id,username,password,role) values ('${adminIds[2]}','hxx_admin','123456',1)`)
return adminIds
}
async function initTeam(userId:string,groupRoleUserId:string,organizationId:string) {
let mysql=getMysqlInstance()
let groupId=await generateSnowId()
await mysql.execute(`insert into ${Table_Team} (id,name,created_by) values ('${groupId}','test_group','${userId}')`)
await mysql.execute(`insert into ${Table_Team} (id,name,created_by,organization_id) values ('${groupId}','test_group','${userId}','${organizationId}')`)
await mysql.execute(`insert into ${Table_Team_User} (id,role_id,team_id,user_id) values ('${await generateSnowId()}','${groupRoleUserId}','${groupId}','${userId}')`)
}
async function initProject(userId:string,projectRoleUserId:string):Promise<string> {
async function initProject(userId:string,projectRoleUserId:string,organizationId:string):Promise<string> {
let mysql=getMysqlInstance()
let projectId=await generateSnowId()
await mysql.execute(`insert into ${Table_Project} (id,name,keyword,created_by) values ('${projectId}','test','test','${userId}')`)
await mysql.execute(`insert into ${Table_Project} (id,name,keyword,created_by,organization_id) values ('${projectId}','test','test','${userId}','${organizationId}')`)
await mysql.execute(`insert into ${Table_Project_Member} (id,role_id,project_id,member_id,type) values ('${await generateSnowId()}','${projectRoleUserId}','${projectId}','${userId}',0)`)
return projectId
}
@ -380,16 +415,16 @@ async function initRole(objPermission:{
}
}
async function initIssueType(projectId:string) {
async function initIssueType(projectId:string,organizationId:string) {
let mysql = getMysqlInstance()
let taskId=await generateSnowId()
let bugId=await generateSnowId()
let ticketId=await generateSnowId()
let solutionId=await generateSnowId()
await mysql.execute(`insert into ${Table_Issue_Type} (id,name,reserved) values ('${taskId}','Task',1)`)
await mysql.execute(`insert into ${Table_Issue_Type} (id,name,reserved) values ('${bugId}','Bug',1)`)
await mysql.execute(`insert into ${Table_Issue_Type} (id,name,reserved) values ('${ticketId}','Ticket',1)`)
await mysql.execute(`insert into ${Table_Issue_Type_Solution} (id,name,description,reserved) values ('${solutionId}','Default','Default',1)`)
await mysql.execute(`insert into ${Table_Issue_Type} (id,name,reserved,organization_id) values ('${taskId}','Task',1,'${organizationId}')`)
await mysql.execute(`insert into ${Table_Issue_Type} (id,name,reserved,organization_id) values ('${bugId}','Bug',1,'${organizationId}')`)
await mysql.execute(`insert into ${Table_Issue_Type} (id,name,reserved,organization_id) values ('${ticketId}','Ticket',1,'${organizationId}')`)
await mysql.execute(`insert into ${Table_Issue_Type_Solution} (id,name,description,reserved,organization_id) values ('${solutionId}','Default','Default',1,'${organizationId}')`)
await mysql.execute(`insert into ${Table_Issue_Type_Solution_Issue_Type} (id,issue_type_id,issue_type_solution_id) values ('${await generateSnowId()}','${taskId}','${solutionId}')`)
await mysql.execute(`insert into ${Table_Issue_Type_Solution_Issue_Type} (id,issue_type_id,issue_type_solution_id) values ('${await generateSnowId()}','${bugId}','${solutionId}')`)
await mysql.execute(`insert into ${Table_Issue_Type_Solution_Issue_Type} (id,issue_type_id,issue_type_solution_id) values ('${await generateSnowId()}','${ticketId}','${solutionId}')`)
@ -407,14 +442,15 @@ async function initIssueType(projectId:string) {
}
}
async function initWorkflow(issueTypeSolutionId:string,issueTypeSolutionName:string,issueTypeTaskId:string,issueTypeBugId:string,issueTypeTicketId:string) {
async function initWorkflow(issueTypeSolutionId:string,issueTypeSolutionName:string,issueTypeTaskId:string,issueTypeBugId:string,issueTypeTicketId:string,organizationId:string) {
let mysql = getMysqlInstance()
let workflowId=await generateSnowId()
await mysql.execute(generateCreateSql(workflowModel,{
id:workflowId,
name:"default",
description:"",
reserved:1
reserved:1,
organization_id:organizationId
}))
let workflowNodeOpenId=await generateSnowId()
let workflowNodeProgressId=await generateSnowId()
@ -505,6 +541,7 @@ async function initWorkflow(issueTypeSolutionId:string,issueTypeSolutionName:str
id:workflowSolutionId,
reserved:1,
name:issueTypeSolutionName,
organization_id:organizationId
}))
await mysql.execute(generateCreateSql(workflowSolutionWorkflowModel,{
id:await generateSnowId(),

View File

@ -1,10 +1,10 @@
import { DefaultContext, DefaultState } from "koa";
import Application from "../../common/app/app";
import "../http/admin";
import "../http/organization";
import "../http/team";
import "../http/user";
import "../rpc/user";
export default class User extends Application {
override async config(app: import("koa")<DefaultState, DefaultContext>) {

View File

@ -1,4 +1,4 @@
import * as userApi from "../../../common/routes/user";
import userApi from "../../../common/routes/user";
import { Err } from "../../../common/status/error";
import { DComponent } from "../../common/decorate/component";
import HttpContext from "../../common/http/context";

View File

@ -0,0 +1,183 @@
import { ECommon_Organization_User_Role } from "../../../common/model/organization_user";
import organizationApi from "../../../common/routes/organization";
import { Err } from "../../../common/status/error";
import { REDIS_GATEWAY } from "../../common/cache/keys/gateway";
import { DComponent } from "../../common/decorate/component";
import { DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired, DHttpUser } from "../../common/http/http";
import { IUserSession } from "../../common/rpc/api/user";
import UserService from "../service/user";
import { OrganizationService, OrganizationUserService } from './../service/organization';
@DComponent
@DHttpController(organizationApi)
class OrganizationController {
@DHttpApi(organizationApi.routes.list)
async list(@DHttpUser user:IUserSession) :Promise<typeof organizationApi.routes.list.res>{
let ret=await OrganizationService.list(user.userId)
return ret;
}
@DHttpApi(organizationApi.routes.info)
async info(@DHttpReqParamRequired("organizationid") organizationId:string) :Promise<typeof organizationApi.routes.info.res>{
let obj=await OrganizationService.getItemById(organizationId)
if(!obj) {
throw Err.Organization.organizationNotFound
}
return obj.getItem();
}
@DHttpApi(organizationApi.routes.create)
async create(@DHttpReqParamRequired("name") name:string,@DHttpReqParam("description") description:string,@DHttpReqParam("photo") photo:string,@DHttpUser user:IUserSession) :Promise<typeof organizationApi.routes.create.res>{
let service=new OrganizationService()
service.assignItem({
name,
description,
photo,
user_id:user.userId
})
let obj=await service.create()
return obj;
}
@DHttpApi(organizationApi.routes.update)
async update(@DHttpReqParamRequired("organizationid") organizationId:string,
@DHttpReqParam("name") name:string,
@DHttpReqParam("description") description:string,
@DHttpReqParam("photo") photo:string,
@DHttpReqParam("active") active:number) :Promise<typeof organizationApi.routes.update.res>{
let obj=await OrganizationService.getItemById(organizationId)
if(!obj) {
throw Err.Organization.organizationNotFound
}
obj.assignItem({
name,
description,
photo,
active
})
let ret=await obj.update()
return ret;
}
@DHttpApi(organizationApi.routes.remove)
async remove(@DHttpReqParamRequired("organizationid") organizationId:string) :Promise<typeof organizationApi.routes.remove.res>{
let obj=await OrganizationService.getItemById(organizationId)
if(!obj) {
throw Err.Organization.organizationNotFound
}
await obj.delete()
return
}
@DHttpApi(organizationApi.routes.listUser)
async listUser(@DHttpReqParamRequired("organizationid") organizationId:string,
@DHttpReqParamRequired("page") page:number,
@DHttpReqParamRequired("size") size:number,
@DHttpReqParam("keyword") keyword:string) :Promise<typeof organizationApi.routes.listUser.res>{
let obj=await OrganizationService.getItemById(organizationId)
if(!obj) {
throw Err.Organization.organizationNotFound
}
let ret=await OrganizationUserService.listUser(organizationId,page,size,keyword)
return ret;
}
@DHttpApi(organizationApi.routes.addUser)
async addUser(@DHttpReqParamRequired("organizationid") organizationId:string,
@DHttpReqParamRequired("username") username:string,
@DHttpReqParamRequired("role") role:ECommon_Organization_User_Role,
@DHttpReqParamRequired("nickname") nickname:string,
@DHttpReqParamRequired("active") active:number,
@DHttpReqParam("title") title:string,
@DHttpReqParam("job") job:string,
@DHttpReqParam("email") email:string,
@DHttpReqParam("phone") phone:string,
@DHttpReqParam("location") location:string) :Promise<typeof organizationApi.routes.addUser.res>{
let user=await UserService.getItemByName(username);
if(!user) {
throw Err.User.userNotFound;
}
let obj=await OrganizationUserService.getItemByExp({
organization_id:organizationId,
user_id:user.getId()
})
if(obj) {
throw Err.Organization.userAlreadyExists
}
let newUser=new OrganizationUserService;
newUser.assignItem({
organization_id:organizationId,
user_id:user.getId(),
role,
nickname,
active,
title,
job,
email,
phone,
location
})
let ret=await newUser.create()
return ret;
}
@DHttpApi(organizationApi.routes.updateUser)
async updateUser(@DHttpReqParamRequired("organizationid") organizationId:string,
@DHttpReqParamRequired("userId") userId:string,
@DHttpReqParam("role") role:ECommon_Organization_User_Role,
@DHttpReqParam("nickname") nickname:string,
@DHttpReqParam("active") active:number,
@DHttpReqParam("title") title:string,
@DHttpReqParam("job") job:string,
@DHttpReqParam("email") email:string,
@DHttpReqParam("phone") phone:string,
@DHttpReqParam("location") location:string) :Promise<typeof organizationApi.routes.updateUser.res>{
if(nickname === "") {
throw Err.Organization.nicknameEmpty
}
let obj=await OrganizationUserService.getItemByExp({
organization_id:organizationId,
user_id:userId
})
if(!obj) {
throw Err.Organization.userNotFound
}
obj.assignItem({
role,
nickname,
active,
title,
job,
email,
phone,
location
})
let ret=await obj.update()
let objRedis=REDIS_GATEWAY.Permission.organizationRole(organizationId,userId)
await objRedis.del();
return ret;
}
@DHttpApi(organizationApi.routes.deleteUser)
async deleteUser(@DHttpReqParamRequired("organizationid") organizationId:string,
@DHttpReqParamRequired("userId") userId:string) :Promise<typeof organizationApi.routes.deleteUser.res>{
let obj=await OrganizationService.getItemById(organizationId)
if(!obj) {
throw Err.Organization.organizationNotFound
} else if(obj.getItem().user_id==userId) {
throw Err.Organization.ownerDeleteForbidden
}
let objUser=await OrganizationUserService.getItemByExp({
organization_id:organizationId,
user_id:userId
})
if(!objUser) {
throw Err.Organization.userNotFound
}
await objUser.delete()
let objRedis=REDIS_GATEWAY.Permission.organizationRole(organizationId,userId)
await objRedis.del();
return;
}
}

View File

@ -1,20 +1,26 @@
import * as teamApi from "../../../common/routes/team";
import { ECommon_User_Type } from "../../../common/model/user";
import teamApi from "../../../common/routes/team";
import { Err } from '../../../common/status/error';
import { DComponent } from "../../common/decorate/component";
import { EServer_Common_Event_Types } from "../../common/event/types";
import { DHttpApi, DHttpController, DHttpReqParam, DHttpReqParamRequired, DHttpUser } from "../../common/http/http";
import { DHttpApi, DHttpController, DHttpHeaderRequired, DHttpReqParam, DHttpReqParamRequired, DHttpUser } from "../../common/http/http";
import { IUserSession } from '../../common/rpc/api/user';
import { EServer_Common_User_Type } from '../../common/types/user';
import TeamService from "../service/team";
import { OrganizationService } from './../service/organization';
@DComponent
@DHttpController(teamApi)
class TeamController {
@DHttpApi(teamApi.routes.create)
async create(@DHttpReqParamRequired("name") name:string,@DHttpUser user:IUserSession):Promise<typeof teamApi.routes.create.res>{
async create(@DHttpReqParamRequired("name") name:string,@DHttpUser user:IUserSession,@DHttpHeaderRequired("organizationid") organizationId:string):Promise<typeof teamApi.routes.create.res>{
let organization = OrganizationService.getItemById(organizationId)
if(!organization) {
throw Err.Organization.organizationNotFound
}
let team=new TeamService
team.assignItem({
name,
created_by:user.type==EServer_Common_User_Type.USER?user.userId:null
created_by:user.type==ECommon_User_Type.USER?user.userId:null,
organization_id:organizationId
});
let obj=await team.create()
return obj
@ -102,14 +108,22 @@ class TeamController {
}
@DHttpApi(teamApi.routes.list)
async list(@DHttpReqParam("keyword") keyword:string,@DHttpReqParamRequired("page") page:number,@DHttpReqParamRequired("size") size:number) :Promise<typeof teamApi.routes.list.res>{
let list=await TeamService.list(page,size,keyword)
async list(@DHttpReqParam("keyword") keyword:string,@DHttpReqParamRequired("page") page:number,@DHttpReqParamRequired("size") size:number,@DHttpHeaderRequired("organizationid") organizationId:string) :Promise<typeof teamApi.routes.list.res>{
let organization = OrganizationService.getItemById(organizationId)
if(!organization) {
throw Err.Organization.organizationNotFound
}
let list=await TeamService.list(organizationId ,page,size,keyword)
return list
}
@DHttpApi(teamApi.routes.filterTeam)
async filterTeam(@DHttpReqParamRequired("name") name:string) :Promise<typeof teamApi.routes.filterTeam.res>{
let ret=await TeamService.filter(name,10);
async filterTeam(@DHttpReqParamRequired("name") name:string,@DHttpHeaderRequired("organizationid") organizationId:string) :Promise<typeof teamApi.routes.filterTeam.res>{
let organization = OrganizationService.getItemById(organizationId)
if(!organization) {
throw Err.Organization.organizationNotFound
}
let ret=await TeamService.filter(organizationId,name,10);
return ret;
}

View File

@ -1,10 +1,10 @@
import * as userApi from "../../../common/routes/user";
import { ECommon_User_Type } from "../../../common/model/user";
import userApi from "../../../common/routes/user";
import { Err } from "../../../common/status/error";
import { DComponent } from '../../common/decorate/component';
import { EServer_Common_Event_Types } from '../../common/event/types';
import HttpContext from "../../common/http/context";
import { DHttpApi, DHttpContent, DHttpContext, DHttpController, DHttpReqParam, DHttpReqParamRequired, DHttpUser } from "../../common/http/http";
import { EServer_Common_User_Type } from "../../common/types/user";
import { DHttpApi, DHttpContent, DHttpContext, DHttpController, DHttpHeader, DHttpReqParam, DHttpReqParamRequired, DHttpUser } from "../../common/http/http";
import UserService from "../service/user";
import { IUserSession } from './../../common/rpc/api/user';
@DComponent
@ -67,7 +67,7 @@ class UserController {
@DHttpApi(userApi.routes.update)
async update(@DHttpUser userInfo:IUserSession,@DHttpContent content:typeof userApi.routes.update.req):Promise<typeof userApi.routes.update.res> {
let user=await UserService.getItemById(userInfo.type==EServer_Common_User_Type.USER?userInfo.userId:content.userId)
let user=await UserService.getItemById(userInfo.type==ECommon_User_Type.USER?userInfo.userId:content.userId)
if(!user) {
throw Err.User.userNotFound
}
@ -105,7 +105,7 @@ class UserController {
@DHttpApi(userApi.routes.resetPassword)
async resetPassword(@DHttpReqParam("userId") userId:string,@DHttpReqParamRequired("password") password:string,@DHttpUser userInfo:IUserSession) :Promise<typeof userApi.routes.resetPassword.res>{
let user=await UserService.getItemById(userInfo.type==EServer_Common_User_Type.USER?userInfo.userId:userId)
let user=await UserService.getItemById(userInfo.type==ECommon_User_Type.USER?userInfo.userId:userId)
if(!user) {
throw Err.User.userNotFound
}
@ -117,8 +117,8 @@ class UserController {
}
@DHttpApi(userApi.routes.teamList)
async teamList(@DHttpReqParam("keyword") keyword:string,@DHttpReqParamRequired("page") page:number,@DHttpReqParamRequired("size") size:number,@DHttpReqParam("userId") userId:string,@DHttpUser userInfo:IUserSession) :Promise<typeof userApi.routes.teamList.res>{
let user=await UserService.getItemById(userInfo.type==EServer_Common_User_Type.USER?userInfo.userId:userId)
async teamList(@DHttpReqParam("keyword") keyword:string,@DHttpReqParamRequired("page") page:number,@DHttpReqParamRequired("size") size:number,@DHttpReqParam("userId") userId:string,@DHttpUser userInfo:IUserSession,@DHttpHeader("organizationid") organizationId:string) :Promise<typeof userApi.routes.teamList.res>{
let user=await UserService.getItemById(userInfo.type==ECommon_User_Type.USER?userInfo.userId:userId)
if(!user) {
throw Err.User.userNotFound
}
@ -127,8 +127,8 @@ class UserController {
}
@DHttpApi(userApi.routes.projectList)
async projectList(@DHttpReqParam("keyword") keyword:string,@DHttpReqParamRequired("page") page:number,@DHttpReqParamRequired("size") size:number,@DHttpReqParam("userId") userId:string,@DHttpUser userInfo:IUserSession) :Promise<typeof userApi.routes.projectList.res>{
let user=await UserService.getItemById(userInfo.type==EServer_Common_User_Type.USER?userInfo.userId:userId)
async projectList(@DHttpReqParam("keyword") keyword:string,@DHttpReqParamRequired("page") page:number,@DHttpReqParamRequired("size") size:number,@DHttpReqParam("userId") userId:string,@DHttpUser userInfo:IUserSession,@DHttpHeader("organizationid") organizationId:string) :Promise<typeof userApi.routes.projectList.res>{
let user=await UserService.getItemById(userInfo.type==ECommon_User_Type.USER?userInfo.userId:userId)
if(!user) {
throw Err.User.userNotFound
}
@ -137,18 +137,18 @@ class UserController {
}
@DHttpApi(userApi.routes.profile)
async profile(@DHttpReqParam("userId") userId:string,@DHttpUser userInfo:IUserSession) :Promise<typeof userApi.routes.profile.res>{
async profile(@DHttpReqParam("userId") userId:string,@DHttpUser userInfo:IUserSession,@DHttpHeader("organizationid") organizationId:string) :Promise<typeof userApi.routes.profile.res>{
let user=await UserService.getItemById(userId??userInfo.userId)
if(!user) {
throw Err.User.userNotFound
}
let ret=await user.profile()
let ret=await user.profile(organizationId)
return ret;
}
@DHttpApi(userApi.routes.infos)
async infos(@DHttpReqParam("userIds") userIds:string) :Promise<typeof userApi.routes.infos.res>{
let ret=await UserService.userInfos(userIds)
async infos(@DHttpReqParam("userIds") userIds:string,@DHttpHeader("organizationid") organizationId:string) :Promise<typeof userApi.routes.infos.res>{
let ret=await UserService.userInfos(userIds,true,organizationId)
return ret;
}

View File

@ -2,23 +2,23 @@ import { Err } from "../../../common/status/error";
import { getMysqlInstance } from "../../common/db/mysql";
import { Mapper } from "../../common/entity/mapper";
import { generateQuerySql } from "../../common/util/sql";
import { ICommon_Model_User, userModel } from './../../../common/model/user';
import { ECommon_User_Type, ICommon_Model_User, userModel } from './../../../common/model/user';
class AdminMapper extends Mapper<typeof userModel> {
constructor(){
super(userModel)
}
override async createConfig(info:ICommon_Model_User) {
info.is_admin=1
info.role=ECommon_User_Type.ADMIN
}
override async updateConfig(info:ICommon_Model_User) {
info.is_admin=1
info.role=ECommon_User_Type.ADMIN
}
async getUserByName(name:string):Promise<ICommon_Model_User> {
if(!name) {
throw Err.User.userNameNotExists
}
var mysql=getMysqlInstance();
let ret=await mysql.executeOne(generateQuerySql(userModel,[],{username:name,is_admin:1}))
let ret=await mysql.executeOne(generateQuerySql(userModel,[],{username:name,role:ECommon_User_Type.ADMIN}))
return ret
}
}

View File

@ -0,0 +1,169 @@
import { Err } from '../../../common/status/error';
import { keys } from '../../../common/transform';
import { getMysqlInstance } from '../../common/db/mysql';
import { Mapper } from '../../common/entity/mapper';
import CommonUtil from '../../common/util/common';
import { generateCreateSql, generateDeleteSql, generateLeftJoinSql, generateQuerySql, generateSnowId } from '../../common/util/sql';
import { ICommon_Model_Organization, organizationModel } from './../../../common/model/organization';
import { ECommon_Organization_User_Role, ICommon_Model_Organization_User, organizationUserModel, Table_Organization_User } from './../../../common/model/organization_user';
import { Table_User, userModel } from './../../../common/model/user';
class OrganizationMapper extends Mapper<typeof organizationModel> {
constructor(){
super(organizationModel)
}
async list(userId:string) {
if(!userId) {
throw Err.Organization.ownerNotFound
}
let mysql=getMysqlInstance()
let arrOrganizationOwner=await mysql.execute(generateQuerySql(organizationModel,[],{
user_id:userId
},"and",{
field:"name",
type:"asc"
}))
let sql=generateLeftJoinSql({
model:organizationUserModel
},{
model:organizationModel,
columns:keys<ICommon_Model_Organization>().map(item=>item.name),
expression:{
id:{
model:organizationUserModel,
field:"organization_id"
}
}
},{
user_id:{
model:organizationUserModel,
value:userId
}
})
let arrOrganizationOwnerId=arrOrganizationOwner.map(item=>item.id);
let arrOrganization=await mysql.execute(sql);
return {
create:arrOrganizationOwner,
join:arrOrganization.filter(item=>{
return !arrOrganizationOwnerId.includes(item.id)
})
};
}
async clearUser(organizationId:string){
if(!organizationId) {
throw Err.Organization.organizationNotFound
}
let mysql=getMysqlInstance()
await mysql.execute(generateDeleteSql(organizationUserModel,{
organization_id:organizationId
}))
}
async init(adminIds: string[], userIds: string[]) {
let mysql=getMysqlInstance()
let id=await generateSnowId()
await mysql.executeOne(generateCreateSql(organizationModel,{
id,
name:"default",
user_id:adminIds[0]
}))
let i=0;
for(let adminId of adminIds) {
await mysql.execute(generateCreateSql(organizationUserModel,{
id:await generateSnowId(),
nickname:"test"+(i++),
organization_id:id,
role:ECommon_Organization_User_Role.ADMIN,
user_id:adminId
}))
}
for(let userId of userIds) {
await mysql.execute(generateCreateSql(organizationUserModel,{
id:await generateSnowId(),
nickname:"test"+(i++),
organization_id:id,
role:ECommon_Organization_User_Role.USER,
user_id:userId
}))
}
return id;
}
}
export let organizationMapper=new OrganizationMapper()
class OrganizationUserMapper extends Mapper<typeof organizationUserModel> {
constructor(){
super(organizationUserModel)
}
async clearUser(organizationId:string) {
if(!organizationId) {
throw Err.Organization.organizationNotFound
}
let mysql=getMysqlInstance()
await mysql.execute(generateDeleteSql(organizationUserModel,{
organization_id:organizationId
}))
}
async listUser(organizationId:string,page:number,size:number,keyword?:string) {
if(page===undefined || page<0 || size===undefined || size<=0 || !organizationId) {
throw Err.Common.paramError
}
var mysql=getMysqlInstance();
let count=Object.values(await mysql.executeOne<number>(`select count(1) from ${Table_Organization_User} ou left join ${Table_User} u on u.id=ou.user_id where ou.organization_id=${organizationId}${keyword?` and (u.username like '%${keyword}%' or ou.nickname like '%${keyword}%')`:""}`))[0]
let totalPage=CommonUtil.pageTotal(count,size)
let sql=generateLeftJoinSql({
model:organizationUserModel,
columns:keys<Omit<ICommon_Model_Organization_User,"user_id">>().map(item=>item.name)
},{
model:userModel,
columns:["id","username","photo"],
expression:{
id:{
model:organizationUserModel,
field:"user_id"
}
},
aggregation:"user_id"
},{
organization_id:{
model:organizationUserModel,
value:organizationId
},
...(keyword && {
"$or0":{
"username":{
model:userModel,
value:{
exp:"%like%",
value:keyword
}
},
"nickname":{
model:organizationUserModel,
value:{
exp:"%like%",
value:keyword
}
}
}
})
},"and",{
field:"nickname",
model:organizationUserModel,
type:"asc"
},size*page,size)
let ret=await mysql.execute(sql)
return {
count:count,
totalPage:totalPage,
data:ret
};
}
}
export let organizationUserMapper=new OrganizationUserMapper()

View File

@ -168,23 +168,26 @@ class TeamMapper extends Mapper<typeof teamModel> {
}))
}
async list(page:number,size:number,keyword?:string):Promise<{
async list(organizationId:string,page:number,size:number,keyword?:string):Promise<{
count:number,
totalPage:number,
data:ICommon_Model_Team[]
}> {
if(page===undefined || page<0 || size===undefined || size<=0) {
if(page===undefined || page<0 || size===undefined || size<=0 || !organizationId) {
throw Err.Common.paramError
}
var mysql=getMysqlInstance();
let count=Object.values(await mysql.executeOne<number>(`select count(1) from ${Table_Team}${keyword?` where name like '%${keyword}%'`:""}`))[0]
let count=Object.values(await mysql.executeOne<number>(`select count(1) from ${Table_Team}${keyword?` where organization_id='${organizationId}' name like '%${keyword}%'`:""}`))[0]
let totalPage=CommonUtil.pageTotal(count,size)
let ret=await mysql.execute(generateQuerySql(teamModel,[],keyword?{
name:{
exp:"%like%",
value:keyword
}
}:null,"and",{
let ret=await mysql.execute(generateQuerySql(teamModel,[],{
organization_id:organizationId,
...(keyword && {
name:{
exp:"%like%",
value:keyword
}
})
},"and",{
field:"name",
type:"asc"
},page*size,size))
@ -195,20 +198,22 @@ class TeamMapper extends Mapper<typeof teamModel> {
};
}
async filter(name:string,size:number)
async filter(organizationId:string,name:string,size:number)
{
if(!name) {
throw Err.User.userNameNotExists
}
if(!size) {
} else if(!size) {
throw Err.Common.paramError
} else if(!organizationId) {
throw Err.Organization.organizationNotFound
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(teamModel,["id","name","photo"],{
name:{
exp:"%like%",
value:name
}
},
organization_id:organizationId
},"and",{
field:"name",
type:"asc"

View File

@ -5,10 +5,11 @@ import { getMysqlInstance } from "../../common/db/mysql";
import { Mapper } from "../../common/entity/mapper";
import CommonUtil from "../../common/util/common";
import { exculdeColumns, generateLeftJoinSql, generateQuerySql, generateUpdateSql } from "../../common/util/sql";
import { organizationUserModel } from './../../../common/model/organization_user';
import { ICommon_Model_Project, projectModel, Table_Project } from './../../../common/model/project';
import { projectMemberModel, Table_Project_Member } from './../../../common/model/project_member';
import { Table_Team_User, teamUserModel } from './../../../common/model/team_user';
import { ICommon_Model_User, Table_User, userModel } from './../../../common/model/user';
import { ECommon_User_Type, ICommon_Model_User, Table_User, userModel } from './../../../common/model/user';
class UserMapper extends Mapper<typeof userModel> {
constructor(){
super(userModel)
@ -29,7 +30,7 @@ class UserMapper extends Mapper<typeof userModel> {
throw Err.User.userNameNotExists
}
var mysql=getMysqlInstance();
let ret=await mysql.executeOne(generateQuerySql(userModel,[],{username:name,is_admin:0}))
let ret=await mysql.executeOne(generateQuerySql(userModel,[],{username:name,role:ECommon_User_Type.USER}))
return ret
}
@ -51,7 +52,7 @@ class UserMapper extends Mapper<typeof userModel> {
throw Err.Common.paramError
}
var mysql=getMysqlInstance();
let count=Object.values(await mysql.executeOne<number>(`select count(1) from ${Table_User} where is_admin=0${keyword?` and username like '%${keyword}%'`:""}`))[0]
let count=Object.values(await mysql.executeOne<number>(`select count(1) from ${Table_User} where role=0${keyword?` and username like '%${keyword}%'`:""}`))[0]
let totalPage=CommonUtil.pageTotal(count,size)
let colums=keys<ICommon_Model_User>().map(item=>item.name);
let ret=await mysql.execute(generateQuerySql(userModel,exculdeColumns(colums,[]),{
@ -70,7 +71,7 @@ class UserMapper extends Mapper<typeof userModel> {
};
}
async teamList(page:number,size:number,userId:string,keyword?:string):Promise<{
async teamList(page:number,size:number,userId:string,organizationId?:string,keyword?:string):Promise<{
count:number,
totalPage:number,
data:ICommon_Model_Team[]
@ -79,7 +80,7 @@ class UserMapper extends Mapper<typeof userModel> {
throw Err.Common.paramError
}
var mysql=getMysqlInstance();
let count=Object.values(await mysql.executeOne<number>(`select count(1) from ${Table_Team_User} tu left join ${Table_Team} t on t.id=tu.team_id where tu.user_id='${userId}'${keyword?` and t.name like '%${keyword}%'`:""}`))[0]
let count=Object.values(await mysql.executeOne<number>(`select count(1) from ${Table_Team_User} tu left join ${Table_Team} t on t.id=tu.team_id where ${organizationId?`t.organization_id='${organizationId}' and `:""} tu.user_id='${userId}'${keyword?` and t.name like '%${keyword}%'`:""}`))[0]
let totalPage=CommonUtil.pageTotal(count,size)
let sql=generateLeftJoinSql({
model:teamUserModel,
@ -98,6 +99,12 @@ class UserMapper extends Mapper<typeof userModel> {
model:teamUserModel,
value:userId
},
...(organizationId && {
organization_id:{
model:teamModel,
value:organizationId
}
}),
...(keyword && {
name:{
model:teamModel,
@ -120,7 +127,7 @@ class UserMapper extends Mapper<typeof userModel> {
};
}
async projectList(page:number,size:number,userId:string,keyword?:string):Promise<{
async projectList(page:number,size:number,userId:string,organizationId?:string,keyword?:string):Promise<{
count:number,
totalPage:number,
data:ICommon_Model_Project[]
@ -129,7 +136,7 @@ class UserMapper extends Mapper<typeof userModel> {
throw Err.Common.paramError
}
var mysql=getMysqlInstance();
let count=Object.values(await mysql.executeOne<number>(`select count(1) from ${Table_Project_Member} pm left join ${Table_Project} p on p.id=pm.project_id where pm.member_id='${userId}'${keyword?` and p.name like '%${keyword}%'`:""}`))[0]
let count=Object.values(await mysql.executeOne<number>(`select count(1) from ${Table_Project_Member} pm left join ${Table_Project} p on p.id=pm.project_id where ${organizationId?`p.organization_id='${organizationId}' and `:""} pm.member_id='${userId}'${keyword?` and p.name like '%${keyword}%'`:""}`))[0]
let totalPage=CommonUtil.pageTotal(count,size)
let sql=generateLeftJoinSql({
model:projectMemberModel,
@ -148,6 +155,12 @@ class UserMapper extends Mapper<typeof userModel> {
model:projectMemberModel,
value:userId
},
...(organizationId && {
organization_id:{
model:projectModel,
value:organizationId
}
}),
...(keyword && {
name:{
model:projectModel,
@ -169,31 +182,61 @@ class UserMapper extends Mapper<typeof userModel> {
data:ret.map(item=>item.project)
};
}
async users(userIds:string[]){
async users(userIds:string[],organizationId?:string){
if(!userIds){
throw Err.User.userIdNotExists
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(userModel,[],{
id:{
exp:"in",
value:userIds
}
}))
return ret;
let ret:(ICommon_Model_User & {
nickname?:string
})[]
if(!organizationId) {
ret=await mysql.execute(generateQuerySql(userModel,[],{
id:{
exp:"in",
value:userIds
}
}))
return ret;
} else {
let sql=generateLeftJoinSql({
model:organizationUserModel,
columns:["nickname"]
},{
model:userModel,
columns:keys<ICommon_Model_User>().map(item=>item.name),
expression:{
id:{
model:organizationUserModel,
field:"user_id"
},
}
},{
user_id:{
model:organizationUserModel,
value:{
exp:"in",
value:userIds
}
}
})
ret=await mysql.execute(sql)
return ret
}
}
async filter(name:string,size:number)
{
if(!name) {
throw Err.User.userNameNotExists
}
if(!size) {
} else if(!size) {
throw Err.Common.paramError
}
let mysql=getMysqlInstance()
let ret=await mysql.execute(generateQuerySql(userModel,["id","username","photo"],{
is_admin:0,
active:1,
username:{
exp:"%like%",

View File

@ -0,0 +1,27 @@
import { ECommon_Services } from "../../../common/types";
import IServer_Common_RPC_Cooperation from "../../common/rpc/api/cooperation";
import { DRPCSend } from "../../common/rpc/rpc";
class RpcCooperationApi implements IServer_Common_RPC_Cooperation {
@DRPCSend(ECommon_Services.Cooperation)
async clearProject(organizationId:string) {
return null;
}
@DRPCSend(ECommon_Services.Cooperation)
async clearField(organizationId:string){
return null;
}
@DRPCSend(ECommon_Services.Cooperation)
async clearWorkflow(organizationId:string) {
return null;
}
@DRPCSend(ECommon_Services.Cooperation)
async clearIssueType(organizationId:string) {
return null;
}
@DRPCSend(ECommon_Services.Cooperation)
async initIssueTypeWorkflowAndSolution(organizationId: string,projectId?:string) {
return null;
}
}
export default new RpcCooperationApi;

View File

@ -3,7 +3,9 @@ import { REDIS_USER } from "../../common/cache/keys/user";
import { getConfigInstance } from '../../common/config/config';
import IServer_Common_RPC_User, { IServer_Common_RPC_User_CheckSession } from "../../common/rpc/api/user";
import { DRPCRecieve } from "../../common/rpc/rpc";
import AdminService from "../service/admin";
import UserService from "../service/user";
import { OrganizationService } from './../service/organization';
import rpcFileApi from "./file";
class RpcUserApi implements IServer_Common_RPC_User {
@ -35,13 +37,14 @@ class RpcUserApi implements IServer_Common_RPC_User {
})
}
@DRPCRecieve
async getUsersInfo?(userIds:string[]):Promise<{
async getUsersInfo?(userIds:string[],organizationId:string):Promise<{
id:string,
username:string,
photo?:string
photo?:string,
nickname?:string
}[]> {
let arrUser:any[]=[...userIds];
let arr=await UserService.userInfos(userIds.join(","),false);
let arr=await UserService.userInfos(userIds.join(","),false,organizationId);
let ret=arr.map(item=>{
return {
id:item.id,
@ -66,5 +69,57 @@ class RpcUserApi implements IServer_Common_RPC_User {
})
return arrUser;
}
@DRPCRecieve
async initAdmin():Promise<string[]> {
let obj1=new AdminService
obj1.assignItem({
username:"teamlinker",
password:"teamlinker"
})
await obj1.create()
let obj2=new AdminService
obj2.assignItem({
username:"wgq_admin",
password:"123456"
})
await obj2.create()
let obj3=new AdminService
obj3.assignItem({
username:"hxx_admin",
password:"123456"
})
await obj3.create()
return [obj1.getId(),obj2.getId(),obj3.getId()]
}
@DRPCRecieve
async initUser():Promise<string[]> {
let obj1=new UserService
obj1.assignItem({
username:"sx",
password:"sx"
})
await obj1.create()
let obj2=new UserService
obj2.assignItem({
username:"wgq",
password:"wgq"
})
await obj2.create()
let obj3=new UserService
obj3.assignItem({
username:"hxx",
password:"hxx"
})
await obj3.create()
return [obj1.getId(),obj2.getId(),obj3.getId()]
}
@DRPCRecieve
async initOrganization(adminIds: string[], userIds: string[]): Promise<string> {
let ret=await OrganizationService.init(adminIds,userIds)
return ret;
}
}
export default new RpcUserApi;

View File

@ -3,8 +3,7 @@ import { Err } from '../../../common/status/error';
import { REDIS_USER } from "../../common/cache/keys/user";
import { getConfigInstance } from '../../common/config/config';
import { Entity } from "../../common/entity/entity";
import { userModel } from './../../../common/model/user';
import { EServer_Common_User_Type } from './../../common/types/user';
import { ECommon_User_Type, userModel } from './../../../common/model/user';
import { adminMapper } from './../mapper/admin';
export default class Admin extends Entity<typeof userModel,typeof adminMapper> {
constructor(){
@ -29,7 +28,7 @@ export default class Admin extends Entity<typeof userModel,typeof adminMapper> {
return new Promise(async (resolve,reject)=>{
jwt.sign({
userId:this.item.id,
type:EServer_Common_User_Type.ADMIN
type:ECommon_User_Type.ADMIN
},secret,async (err,token)=>{
if(err) {
reject(err)

View File

@ -0,0 +1,56 @@
import { ECommon_Organization_User_Role, organizationUserModel } from "../../../common/model/organization_user";
import { Entity } from "../../common/entity/entity";
import { EServer_Common_Event_Types } from "../../common/event/types";
import rpcCooperationApi from "../rpc/cooperation";
import { ICommon_Model_Organization, organizationModel } from './../../../common/model/organization';
import { organizationMapper, organizationUserMapper } from './../mapper/organization';
export class OrganizationService extends Entity<typeof organizationModel,typeof organizationMapper> {
constructor(){
super(organizationMapper)
}
static async list(userId:string) {
let ret=await organizationMapper.list(userId)
return ret;
}
override async create(): Promise<ICommon_Model_Organization> {
let ret=await super.create()
let service=new OrganizationUserService;
service.assignItem({
organization_id:ret.id,
user_id:ret.user_id,
role:ECommon_Organization_User_Role.ADMIN,
nickname:"Admin"
})
await service.create()
await rpcCooperationApi.initIssueTypeWorkflowAndSolution(ret.id);
return ret;
}
override async delete(eventPulish?: EServer_Common_Event_Types.Types): Promise<void> {
await super.delete()
await organizationUserMapper.clearUser(this.getId());
await rpcCooperationApi.clearProject(this.getId())
await rpcCooperationApi.clearIssueType(this.getId())
await rpcCooperationApi.clearWorkflow(this.getId())
await rpcCooperationApi.clearField(this.getId())
}
static async init(adminIds:string[],userIds:string[]) {
let ret=await organizationMapper.init(adminIds,userIds);
return ret;
}
}
export class OrganizationUserService extends Entity<typeof organizationUserModel,typeof organizationUserMapper> {
constructor(){
super(organizationUserMapper)
}
static async listUser(organizationId:string,page:number,size:number,keyword?:string) {
let ret=await organizationUserMapper.listUser(organizationId,page,size,keyword)
return ret;
}
}

View File

@ -52,8 +52,8 @@ export default class Team extends Entity<typeof teamModel,typeof teamMapper> {
await teamMapper.changeRole(this.item.id,userId,roleId)
}
static async list(page:number,size:number,keyword?:string):Promise<ICommon_Route_Res_Team_List>{
let ret=await teamMapper.list(page,size,keyword)
static async list(organizationId:string,page:number,size:number,keyword?:string):Promise<ICommon_Route_Res_Team_List>{
let ret=await teamMapper.list(organizationId,page,size,keyword)
return {
count:ret.count,
totalPage:ret.totalPage,
@ -62,7 +62,7 @@ export default class Team extends Entity<typeof teamModel,typeof teamMapper> {
}
}
static async filter(name:string,size:number):Promise<{
static async filter(organizationId:string,name:string,size:number):Promise<{
name:string,
id:string,
photo:string
@ -73,7 +73,7 @@ export default class Team extends Entity<typeof teamModel,typeof teamMapper> {
if(!size) {
throw Err.Common.paramError
}
let ret=await teamMapper.filter(name,size);
let ret=await teamMapper.filter(organizationId,name,size);
let arr=<{
name:string,
id:string,

View File

@ -6,8 +6,7 @@ import { getConfigInstance } from '../../common/config/config';
import { Entity } from "../../common/entity/entity";
import { userMapper } from '../mapper/user';
import rpcFileApi from "../rpc/file";
import { ICommon_Model_User, userModel } from './../../../common/model/user';
import { EServer_Common_User_Type } from './../../common/types/user';
import { ECommon_User_Type, ICommon_Model_User, userModel } from './../../../common/model/user';
export default class User extends Entity<typeof userModel,typeof userMapper> {
constructor(){
super(userMapper)
@ -32,7 +31,7 @@ export default class User extends Entity<typeof userModel,typeof userMapper> {
return new Promise(async (resolve,reject)=>{
jwt.sign({
userId:this.item.id,
type:EServer_Common_User_Type.USER
type:ECommon_User_Type.USER
},secret,async (err,token)=>{
if(err) {
reject(err)
@ -82,37 +81,37 @@ export default class User extends Entity<typeof userModel,typeof userMapper> {
}
}
async projectList(page:number,size:number,keyword?:string){
let ret= await userMapper.projectList(page,size,this.item.id,keyword)
async projectList(page:number,size:number,keyword?:string,organizationId?:string){
let ret= await userMapper.projectList(page,size,this.item.id,organizationId,keyword)
return {
...ret,
page:page
};
}
async teamList(page:number,size:number,keyword?:string){
let ret= await userMapper.teamList(page,size,this.item.id,keyword)
async teamList(page:number,size:number,keyword?:string,organizationId?:string){
let ret= await userMapper.teamList(page,size,this.item.id,organizationId,keyword)
return {
...ret,
page:page
};
}
async profile(){
async profile(organizationId?:string){
let ret={
info:this.getItem(),
project:(await this.projectList(0,10)).data,
team:(await this.teamList(0,10)).data
info:User.userInfos(this.getId(),true,organizationId)[0],
project:(await this.projectList(0,10,undefined,organizationId)).data,
team:(await this.teamList(0,10,undefined,organizationId)).data
}
delete ret.info.password
return ret;
}
static async userInfos(userIds:string,isGetPhoto:boolean=true):Promise<Omit<ICommon_Model_User,"password"|"created_time"|"modified_time">[]>{
static async userInfos(userIds:string,isGetPhoto:boolean=true,organizationId?:string):Promise<Omit<ICommon_Model_User,"password"|"created_time"|"modified_time">[]>{
if(!userIds) {
throw Err.User.userIdNotExists
}
let ret=await userMapper.users(userIds.split(","))
let ret=await userMapper.users(userIds.split(","),organizationId)
for(let obj of ret) {
delete obj.password;
delete obj.created_time;