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  }