github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/workflow/explode.go (about) 1 package workflow 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "time" 8 9 "database/sql" 10 11 dbconn "github.com/mdaxf/iac/databases" 12 "github.com/mdaxf/iac/documents" 13 "github.com/mdaxf/iac/logger" 14 "go.mongodb.org/mongo-driver/bson" 15 "go.mongodb.org/mongo-driver/bson/primitive" 16 17 wftype "github.com/mdaxf/iac/workflow/types" 18 19 "github.com/google/uuid" 20 // "github.com/mdaxf/iac/com" 21 "github.com/mdaxf/iac/notifications" 22 ) 23 24 type ExplodionEngine struct { 25 WorkflowName string 26 EntityName string 27 Type string 28 Log logger.Log 29 workflow wftype.WorkFlow 30 DocDBCon *documents.DocDB 31 DBTx *sql.Tx 32 Ctx context.Context 33 CtxCancel context.CancelFunc 34 UserName string 35 ClientID string 36 } 37 38 func NewExplosion(WorkFlowName string, EntityName string, Type string, UserName string, ClientID string) *ExplodionEngine { 39 log := logger.Log{} 40 log.ModuleName = logger.Framework 41 log.ControllerName = "workflow Explosion" 42 log.User = UserName 43 log.ClientID = ClientID 44 45 DBConn := documents.DocDBCon 46 fmt.Print(log) 47 return &ExplodionEngine{ 48 WorkflowName: WorkFlowName, 49 EntityName: EntityName, 50 Type: Type, 51 Log: log, 52 UserName: UserName, 53 ClientID: ClientID, 54 DocDBCon: DBConn, 55 } 56 57 } 58 59 func (e *ExplodionEngine) Explode(Description string, EntityData map[string]interface{}) (int64, error) { 60 /*if e.Log.ModuleName == "" { 61 e.Log = logger.Log{ModuleName: logger.Framework, User: e.UserName, ControllerName: "workflow"} 62 } */ 63 startTime := time.Now() 64 defer func() { 65 elapsed := time.Since(startTime) 66 e.Log.PerformanceWithDuration("engine.funcs.NewFuncs", elapsed) 67 }() 68 69 defer func() { 70 if r := recover(); r != nil { 71 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.Explode: %s", r)) 72 return 73 } 74 }() 75 76 e.Log.Debug(fmt.Sprintf("Start to explode workflow data %s's %s", e.WorkflowName, "Retrieven")) 77 78 workflowM, err := e.getWorkFlowbyName() 79 if err != nil { 80 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.Explode: %s", err)) 81 return 0, err 82 } 83 84 if workflowM == nil { 85 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.Explode: %s", "Workflow not found")) 86 return 0, err 87 } 88 89 jsonString, err := json.Marshal(workflowM) 90 if err != nil { 91 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.Explode: %s", err)) 92 return 0, err 93 } 94 95 var workflow wftype.WorkFlow 96 err = json.Unmarshal(jsonString, &workflow) 97 if err != nil { 98 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.Explode: %s", err)) 99 return 0, err 100 } 101 e.workflow = workflow 102 103 e.Log.Debug(fmt.Sprintf("Workflow %s data %v ", e.WorkflowName, workflow)) 104 105 Nodes := workflow.Nodes 106 Links := workflow.Links 107 108 startNode := wftype.Node{} 109 110 for _, node := range Nodes { 111 if node.Type == "start" { 112 e.Log.Debug(fmt.Sprintf("Workflow %s start node %s is %s ", e.WorkflowName, node.Name, e.Type)) 113 startNode = node 114 break 115 } 116 } 117 118 if startNode.ID == "" { 119 err = fmt.Errorf("start node not found") 120 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.Explode: %s", "start node not found")) 121 return 0, err 122 } 123 124 e.Log.Debug(fmt.Sprintf("Workflow %s start node %s is %s ", e.WorkflowName, startNode.ID, e.Type)) 125 126 firstNodes := []wftype.Node{} 127 128 for _, link := range Links { 129 if link.Source == startNode.ID { 130 e.Log.Debug(fmt.Sprintf("Workflow %s start node %s link %s ", e.WorkflowName, startNode.ID, link.Target)) 131 targetnode := e.getNodeByID(link.Target, Nodes) 132 if targetnode.Type != "end" { 133 firstNodes = append(firstNodes, targetnode) 134 } 135 } 136 } 137 138 if len(firstNodes) == 0 { 139 err = fmt.Errorf("the first node not found") 140 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.Explode: %s", "First node not found")) 141 return 0, err 142 } 143 144 if e.DBTx == nil { 145 e.DBTx, err = dbconn.DB.Begin() 146 if err != nil { 147 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.Explode: %s", err)) 148 return 0, err 149 } 150 defer e.DBTx.Rollback() 151 } 152 153 jsonEntityData, err := json.Marshal(EntityData) 154 if err != nil { 155 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.explodeNode - convert the Entityata: %s", err)) 156 return 0, err 157 } 158 159 e.Log.Debug(fmt.Sprintf("Workflow %s first node %v ", e.WorkflowName, firstNodes)) 160 161 dbop := dbconn.NewDBOperation(e.UserName, e.DBTx, "Workflow.Explosion") 162 163 columns := []string{"Type", "Entity", "Status", "Description", "Data", "WorkflowUUID", "Workflow", "createdby", "createdon", "updatedby", "updatedon"} 164 values := []string{e.Type, e.EntityName, "1", Description, string(jsonEntityData), workflow.UUID, string(jsonString), e.UserName, time.Now().UTC().Format("2006-01-02 15:04:05"), e.UserName, time.Now().UTC().Format("2006-01-02 15:04:05")} 165 166 wfentityid, err := dbop.TableInsert("workflow_entities", columns, values) 167 168 if err != nil { 169 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.Explode: %s", err)) 170 return 0, err 171 } 172 173 pretaskdata := make(map[string]interface{}) 174 175 for _, node := range firstNodes { 176 e.Log.Debug(fmt.Sprintf("Workflow %s first node %s explode ", e.WorkflowName, node.ID)) 177 e.explodeNode(node, wfentityid, e.DocDBCon, e.DBTx, pretaskdata) 178 } 179 180 err = e.DBTx.Commit() 181 if err != nil { 182 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.Explode: %s", err)) 183 return 0, err 184 } 185 return wfentityid, nil 186 187 } 188 189 func (e *ExplodionEngine) explodeNode(node wftype.Node, workflowentityid int64, DBConn *documents.DocDB, DBTx *sql.Tx, PreTaskData map[string]interface{}) { 190 startTime := time.Now() 191 defer func() { 192 elapsed := time.Since(startTime) 193 e.Log.PerformanceWithDuration("WorkFlow.Explosion.explodeNode", elapsed) 194 }() 195 196 defer func() { 197 if r := recover(); r != nil { 198 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.explodeNode: %s", r)) 199 return 200 } 201 }() 202 203 jsonData, err := json.Marshal(node.ProcessData) 204 if err != nil { 205 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.explodeNode - convert the node processdata: %s", err)) 206 return 207 } 208 209 PreTaskjsonData, err := json.Marshal(PreTaskData) 210 if err != nil { 211 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.explodeNode - convert the pretaskdata: %s", err)) 212 return 213 } 214 215 dbop := dbconn.NewDBOperation(e.UserName, DBTx, "Workflow.Explosion") 216 217 columns := []string{"WorkflowEntityID", "Type", "Status", "WorkflowNodeID", "PreTaskData", "ProcessData", "Page", "TranCode", "createdby", "createdon", "updatedby", "updatedon"} 218 values := []string{fmt.Sprintf("%d", workflowentityid), node.Type, "1", node.ID, string(PreTaskjsonData), string(jsonData), node.Page, node.TranCode, e.UserName, time.Now().UTC().Format("2006-01-02 15:04:05"), e.UserName, time.Now().UTC().Format("2006-01-02 15:04:05")} 219 220 taskid, err := dbop.TableInsert("workflow_tasks", columns, values) 221 222 if err != nil { 223 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.explodeNode - insert the data to database: %s", err)) 224 return 225 } 226 227 e.Log.Debug(fmt.Sprintf("Workflow %s node %s explode taskid %d ", e.WorkflowName, node.ID, taskid)) 228 roleids := []int64{} 229 230 notification := make(map[string]interface{}) 231 notroles := make(map[string]interface{}) 232 notusers := make(map[string]interface{}) 233 234 for _, role := range node.Roles { 235 236 if role != "" { 237 rows, err := dbop.Query_Json(fmt.Sprintf("select id from roles where Name = '%s'", role)) 238 239 if err != nil { 240 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.explodeNode to get the role assignment: %s", err)) 241 242 } else if len(rows) == 0 { 243 e.Log.Error(fmt.Sprintf("System does not find the role: %s", role)) 244 } else { 245 roleid := rows[0]["id"].(int64) 246 roleids = append(roleids, roleid) 247 columns = []string{"WorkflowTaskID", "RoleID", "createdby", "createdon", "updatedby", "updatedon"} 248 values = []string{fmt.Sprintf("%d", taskid), fmt.Sprintf("%d", roleid), e.UserName, time.Now().UTC().Format("2006-01-02 15:04:05"), e.UserName, time.Now().UTC().Format("2006-01-02 15:04:05")} 249 250 _, err = dbop.TableInsert("workflow_task_assignments", columns, values) 251 252 if err != nil { 253 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.explodeNode during adding assignment: %s", err)) 254 return 255 } 256 257 notroles[role] = 1 258 } 259 } 260 } 261 262 userids := []int64{} 263 264 for _, user := range node.Users { 265 if user != "" { 266 rows, err := dbop.Query_Json(fmt.Sprintf("select id, LoginName from users where LoginName = '%s' OR Name = '%s'", user, user)) 267 268 if err != nil { 269 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.explodeNode during gettign userid: %s", err)) 270 } else if len(rows) == 0 { 271 e.Log.Error(fmt.Sprintf("System does not find the user: %s", user)) 272 } else { 273 userid := rows[0]["id"].(int64) 274 loginname := rows[0]["LoginName"].(string) 275 userids = append(userids, userid) 276 columns = []string{"WorkflowTaskID", "UserID", "createdby", "createdon", "updatedby", "updatedon"} 277 values = []string{fmt.Sprintf("%d", taskid), fmt.Sprintf("%d", userid), e.UserName, time.Now().UTC().Format("2006-01-02 15:04:05"), e.UserName, time.Now().UTC().Format("2006-01-02 15:04:05")} 278 279 _, err = dbop.TableInsert("workflow_task_assignments", columns, values) 280 281 if err != nil { 282 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.explodeNode during adding assignment: %s", err)) 283 return 284 } 285 notusers[loginname] = 1 286 } 287 } 288 } 289 node.Roleids = roleids 290 node.Userids = userids 291 292 if (node.Type == "task" || node.Type == "gateway") && node.Page != "" { 293 294 e.Log.Debug(fmt.Sprintf("Workflow %s node %s explode page %s and send notification", e.WorkflowName, node.ID, node.Page)) 295 notification["type"] = "workflow" 296 notification["entity"] = e.EntityName 297 notification["workflow"] = e.WorkflowName 298 notification["workflownode"] = node.Name 299 notification["workflownodeid"] = node.ID 300 notification["workflowtaskid"] = taskid 301 notification["workflowentityid"] = workflowentityid 302 notification["status"] = "1" 303 notification["roles"] = notroles 304 notification["receipts"] = notusers 305 notification["sender"] = e.UserName 306 notification["topic"] = "workflow task created for " + e.EntityName 307 notification["message"] = "workflow task created for " + e.EntityName 308 notification["uuid"] = uuid.New().String() 309 310 err = notifications.CreateNewNotification(notification, e.UserName) 311 if err != nil { 312 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.explodeNode during creating notification: %s", err)) 313 } 314 315 columns = []string{"NotificationUUID"} 316 values = []string{notification["uuid"].(string)} 317 datatypes := []int{int(0)} 318 Where := fmt.Sprintf("id = %d", taskid) 319 _, err = dbop.TableUpdate("workflow_tasks", columns, values, datatypes, Where) 320 if err != nil { 321 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.explodeNode during updating notification: %s", err)) 322 } 323 324 } 325 326 columns = []string{"WorkflowEntityID", "WorkflowTaskID", "Type", "Status", "createdby", "createdon", "updatedby", "updatedon"} 327 values = []string{fmt.Sprintf("%d", workflowentityid), fmt.Sprintf("%d", taskid), "create task", "1", e.UserName, time.Now().UTC().Format("2006-01-02 15:04:05"), e.UserName, time.Now().UTC().Format("2006-01-02 15:04:05")} 328 329 _, err = dbop.TableInsert("workflow_task_histories", columns, values) 330 331 if err != nil { 332 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.explodeNode during adding history records: %s", err)) 333 return 334 } 335 336 ExecuteTask(taskid, node, DBTx, DBConn, e.UserName) 337 338 } 339 340 func (e *ExplodionEngine) getNodeByID(ID string, Nodes []wftype.Node) wftype.Node { 341 for _, node := range Nodes { 342 if node.ID == ID { 343 return node 344 } 345 } 346 return wftype.Node{} 347 } 348 349 func (e *ExplodionEngine) getWorkFlowbyName() (primitive.M, error) { 350 startTime := time.Now() 351 defer func() { 352 elapsed := time.Since(startTime) 353 e.Log.PerformanceWithDuration("WorkFlow.Explosion.getWorkFlowbyName", elapsed) 354 }() 355 356 defer func() { 357 if r := recover(); r != nil { 358 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.getWorkFlowbyName: %s", r)) 359 return 360 } 361 }() 362 363 if e.WorkflowName == "" { 364 return nil, fmt.Errorf("Workflow name is empty") 365 } 366 367 e.Log.Info(fmt.Sprintf("Start to get workflow data %s's %s", e.WorkflowName, "Retrieven")) 368 369 filter := bson.M{"name": e.WorkflowName, "isdefault": true} 370 371 workflowM, err := e.DocDBCon.QueryCollection("WorkFlow", filter, nil) 372 if err != nil { 373 e.Log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.getWorkFlowbyName: %s", err)) 374 return nil, err 375 } 376 e.Log.Debug(fmt.Sprintf("Workflow %s data %v ", e.WorkflowName, workflowM)) 377 e.Log.Info(fmt.Sprintf("End to get workflow data %s's %s", e.WorkflowName, "Retrieven")) 378 return workflowM[0], nil 379 380 } 381 382 func convertToMap(m primitive.M) map[string]interface{} { 383 result := make(map[string]interface{}) 384 385 for key, value := range m { 386 result[key] = value 387 } 388 389 return result 390 } 391 392 func convertWorkFlowNodeToJson(node wftype.Node) []byte { 393 /* result := make(map[string]interface{}) 394 result["name"] = node.Name 395 result["id"] = node.ID 396 result["description"] = node.Description 397 result["type"] = node.Type 398 result["page"] = node.Page 399 result["trancode"] = node.TranCode 400 result["roles"] = node.Roles 401 result["users"] = node.Users 402 result["roleids"] = node.Roleids 403 result["userids"] = node.Userids 404 result["precondition"] = node.PreCondition 405 result["postcondition"] = node.PostCondition 406 result["processdata"] = node.ProcessData 407 result["routingtables"] = node.RoutingTables */ 408 409 result, err := json.Marshal(node) 410 if err != nil { 411 return nil 412 } 413 /* 414 var resultMap map[string]interface{} 415 err = json.Unmarshal(result, &resultMap) 416 if err != nil { 417 return nil 418 } 419 */ 420 return result 421 } 422 423 func GetWorkFlowbyUUID(uuid string, UserName string, DocDBCon documents.DocDB) (wftype.WorkFlow, primitive.M, error) { 424 log := logger.Log{} 425 log.ModuleName = logger.Framework 426 log.ControllerName = "workflow" 427 log.User = UserName 428 429 startTime := time.Now() 430 defer func() { 431 elapsed := time.Since(startTime) 432 log.PerformanceWithDuration("engine.funcs.NewFuncs", elapsed) 433 }() 434 435 defer func() { 436 if r := recover(); r != nil { 437 log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.Explode: %s", r)) 438 return 439 } 440 }() 441 442 filter := bson.M{"uuid": uuid} 443 444 workflowM, err := DocDBCon.QueryCollection("WorkFlow", filter, nil) 445 if err != nil { 446 log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.getWorkFlowbyUUID: %s", err)) 447 return wftype.WorkFlow{}, nil, err 448 } 449 450 if workflowM == nil { 451 log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.Explode: %s", "Workflow not found")) 452 return wftype.WorkFlow{}, nil, err 453 } 454 455 jsonString, err := json.Marshal(workflowM[0]) 456 if err != nil { 457 log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.Explode: %s", err)) 458 return wftype.WorkFlow{}, nil, err 459 } 460 461 var workflow wftype.WorkFlow 462 err = json.Unmarshal(jsonString, &workflow) 463 if err != nil { 464 log.Error(fmt.Sprintf("Error in WorkFlow.Explosion.Explode: %s", err)) 465 return wftype.WorkFlow{}, nil, err 466 } 467 return workflow, workflowM[0], nil 468 }