Coder Social home page Coder Social logo

flow's People

Contributors

js-ojus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flow's Issues

Tx is nil bug!!

@js-ojus

Hi, I have found that the following code is a bug:

	var tx *sql.Tx
	if otx == nil {
		tx, err := db.Begin()
		if err != nil {
			return 0, err
		}
		defer tx.Rollback()
	} else {
		tx = otx
	}

here tx, err := db.Begin() will make a temporary variable tx, so out of the if statement, tx also will be a nil value. Thus, when you call the interface which need parameter *sql.Tx and you give a nil to it, it will cause a panic. For example:

        gid, err := flow.Groups.New(nil, "nike", "G")

I give nil to Groups.New because I have called RegisterDB to make db is not null.

We can use this code to fix it:

    var tx *sql.Tx
    if otx == nil {
        var err error
        tx, err = db.Begin()
        if err != nil {
            return 0, err
        }
        defer tx.Rollback()
    } else {
        tx = otx
    }

Do you have plans to provide a version that supports sqlite databases?

Do you have plans to provide a version that supports sqlite databases? I tried to change your code to support sqlite. The original SQL language is a bit different for mysql and sqlite. If you are considering using a golang orm library like xorm, the flow may have extensive database support.

Check group id is singleton when create a new event?

Hi, I have read your code and has a little confused. When creating a new event without check the group id is singleton, that may be will cause we do not know who create this event if the group is type of 'G' and has more than one user. Yeah, the workflow also do not check the group type, so the event can be applied. Is there a problem?

Hi,can you help me a example?

I am trying like these:

dtID1, err := flow.DocTypes.New(tx, "图纸设计") //dtID1
	if err != nil {
		fmt.Println(err)
	}
	// dtID2, err := flow.DocTypes.New(tx, "图纸校核") //dtID1
	// if err != nil {
	// 	fmt.Println(err)
	// }
	_, err = flow.DocTypes.New(tx, "变更立项") //dtID2
	if err != nil {
		fmt.Println(err)
	}
	dsID1, err := flow.DocStates.New(tx, "设计中...") //初始化
	if err != nil {
		fmt.Println(err)
	}
	dsID2, err := flow.DocStates.New(tx, "校核中...") //委托创建
	if err != nil {
		fmt.Println(err)
	}
	_, err = flow.DocStates.New(tx, "审查中...")
	if err != nil {
		fmt.Println(err)
	}
	flow.DocStates.New(tx, "批注中...")
	flow.DocStates.New(tx, "申报中...")
	flow.DocStates.New(tx, "评估中...")
	flow.DocStates.New(tx, "审批中...")
	// flow.DocStates.New(tx, "DataApproved")
	// flow.DocStates.New(tx, "ReportGen")
	// flow.DocStates.New(tx, "ReportApproved")

	daID1, err := flow.DocActions.New(tx, "提交设计", false) //改变状态设计中...为校核中...
	if err != nil {
		fmt.Println(err)
	}
	daID2, err := flow.DocActions.New(tx, "校核", false)
	if err != nil {
		fmt.Println(err)
	}
	daID3, err := flow.DocActions.New(tx, "审查", false)
	if err != nil {
		fmt.Println(err)
	}
	daID4, err := flow.DocActions.New(tx, "核定", true)
	if err != nil {
		fmt.Println(err)
	}
	daID5, err := flow.DocActions.New(tx, "评估", true)
	if err != nil {
		fmt.Println(err)
	}
	daID6, err := flow.DocActions.New(tx, "审批", false)
	if err != nil {
		fmt.Println(err)
	}
	daID7, err := flow.DocActions.New(tx, "立项", false)
	if err != nil {
		fmt.Println(err)
	}

	workflowID1, err := flow.Workflows.New(tx, "图纸设计流程", dtID1, dsID1) //初始状态是“设计中...”
	if err != nil {
		fmt.Println(err)
	}
	// workflowID2, err := flow.Workflows.New(tx, "图纸校核流程", dtID2, dsID2) //初始状态是“设计中...”
	// if err != nil {
	// 	fmt.Println(err)
	// }

	accessContextID1, err := flow.AccessContexts.New(tx, "Context")
	if err != nil {
		beego.Error(err)
	}
	// AddNode maps the given document state to the specified node.  This
	// map is consulted by the workflow when performing a state transition
	// of the system.nodeID1
	// _, err = flow.Workflows.AddNode(tx, dtID1, dsID1, accessContextID1, workflowID1, "图纸三角校审流程-设计", flow.NodeTypeLinear)
	// if err != nil {
	// 	fmt.Println(err)
	// }
	_, err = flow.Workflows.AddNode(tx, dtID1, dsID2, accessContextID1, workflowID1, "图纸三角校审流程-校核", flow.NodeTypeEnd)
	if err != nil {
		fmt.Println(err)
	}

	res, err := tx.Exec(`INSERT INTO users_master(first_name, last_name, email, active)
			VALUES('秦', '晓川-1', '[email protected]', 1)`)
	if err != nil {
		log.Fatalf("%v\n", err)
	}
	uid, _ := res.LastInsertId()
	uID1 := flow.UserID(uid)
	_, err = flow.Groups.NewSingleton(tx, uID1)

	res, err = tx.Exec(`INSERT INTO users_master(first_name, last_name, email, active)
			VALUES('秦', '晓川-2', '[email protected]', 1)`)
	if err != nil {
		log.Fatalf("%v\n", err)
	}
	uid, _ = res.LastInsertId()
	uID2 := flow.UserID(uid)
	_, err = flow.Groups.NewSingleton(tx, uID2)

	res, err = tx.Exec(`INSERT INTO users_master(first_name, last_name, email, active)
			VALUES('秦', '晓川-3', '[email protected]', 1)`)
	if err != nil {
		log.Fatalf("%v\n", err)
	}
	uid, _ = res.LastInsertId()
	uID3 := flow.UserID(uid)
	_, err = flow.Groups.NewSingleton(tx, uID3)

	res, err = tx.Exec(`INSERT INTO users_master(first_name, last_name, email, active)
			VALUES('秦', '晓川-4', '[email protected]', 1)`)
	if err != nil {
		log.Fatalf("%v\n", err)
	}
	uid, _ = res.LastInsertId()
	uID4 := flow.UserID(uid)
	_, err = flow.Groups.NewSingleton(tx, uID4)

	gID1 := fatal1(flow.Groups.New(tx, "设计人员组", "G")).(flow.GroupID)
	gID2 := fatal1(flow.Groups.New(tx, "校核人员组", "G")).(flow.GroupID)
	fatal0(flow.Groups.AddUser(tx, gID1, uID1))
	fatal0(flow.Groups.AddUser(tx, gID1, uID2))
	fatal0(flow.Groups.AddUser(tx, gID1, uID3))

	fatal0(flow.Groups.AddUser(tx, gID2, uID2))
	fatal0(flow.Groups.AddUser(tx, gID2, uID3))
	fatal0(flow.Groups.AddUser(tx, gID2, uID4))
	roleID1 := fatal1(flow.Roles.New(tx, "设计人员角色")).(flow.RoleID)
	roleID2 := fatal1(flow.Roles.New(tx, "校核人员角色")).(flow.RoleID)
	//给角色赋予action权限
	fatal0(flow.Roles.AddPermissions(tx, roleID1, dtID1, []flow.DocActionID{daID1, daID2, daID3, daID4}))
	fatal0(flow.Roles.AddPermissions(tx, roleID2, dtID1, []flow.DocActionID{daID1, daID2, daID3, daID4, daID5, daID6, daID7}))
	//给用户组赋予角色
	err = flow.AccessContexts.AddGroupRole(tx, accessContextID1, gID1, roleID1)
	if err != nil {
		beego.Error(err)
	}
	err = flow.AccessContexts.AddGroupRole(tx, accessContextID1, gID2, roleID2)
	if err != nil {
		beego.Error(err) 
	}

	tx.Commit()

and then:

dtID1, err := flow.DocTypes.GetByName("图纸设计")
	if err != nil {
		beego.Error(err)
	}
	beego.Info(dtID1)
	//查询context
	accessContextID1, err := flow.AccessContexts.List("Context", 0, 0)
	if err != nil {
		beego.Error(err)
	}
	beego.Info(accessContextID1[0].ID)
	beego.Info(flow.GroupID(1))
	docNewInput := flow.DocumentsNewInput{
		DocTypeID:       dtID1.ID,
		AccessContextID: accessContextID1[0].ID,
		GroupID:         5, //groupId,
		Title:           "厂房布置图",
		Data:            "设计、制图: 秦晓川1, 校核: 秦晓川2",
	}
	// flow.Documents.New(tx, &docNewInput)
	DocumentID1, err := flow.Documents.New(tx, &docNewInput)
	if err != nil {
		beego.Error(err)
	}
	// tx.Commit() 
	beego.Info(DocumentID1)
	dsID2, err := flow.DocStates.GetByName("校核中...")
	if err != nil {
		fmt.Println(err)
	}
	beego.Info(dsID2)
	daID2, err := flow.DocActions.GetByName("提交设计")
	if err != nil {
		fmt.Println(err)
	}
	beego.Info(daID2)
	beego.Info(flow.GroupID(2))
	docEventInput := flow.DocEventsNewInput{
		DocTypeID:   dtID1.ID, //flow.DocTypeID(1),
		DocumentID:  DocumentID1,
		DocStateID:  dsID2.ID,
		DocActionID: daID2.ID, //flow.DocActionID(2),
		GroupID:     6,
		Text:        "校核",
	}

	docEventID1, err := flow.DocEvents.New(tx, &docEventInput)
	if err != nil {
		beego.Error(err)
	}
	tx.Commit() 
	beego.Info(docEventID1)
	myDocEvent, err := flow.DocEvents.Get(docEventID1)
	if err != nil {
		beego.Error(err)
	}
	beego.Info(myDocEvent)
	// myWorkflow, err := flow.Workflows.Get(workflowId.ID)
	// if err != nil {
	// 	beego.Error(err)
	// }
	myWorkflow, err := flow.Workflows.GetByName("图纸设计流程")
	if err != nil {
		beego.Error(err)
	}
	beego.Info(myWorkflow)
	//给出接受的组groupids
	groupIds := []flow.GroupID{flow.GroupID(6)}
	beego.Info(groupIds)
	newDocStateId, err := myWorkflow.ApplyEvent(tx, myDocEvent, groupIds)
	if err != nil {
		beego.Error(err)
	}
	tx.Commit() 
	fmt.Println("newDocStateId=", newDocStateId, err)

I don't know how to use the flow. Can you give me some advice?

Can't delete groups which received messages

If a group received messages and a mailbox created for it, then an error would be raised if you try to delete it.

update or delete on table "wf_groups_master" violates foreign key constraint "wf_mailboxes_group_id_fkey" on table "wf_mailboxes"

Maybe Groups.Delete should also delete the Group mailbox, or Mailboxes should provide a Delete method?

good job~

This workflow is what I need, and I'm going to make it in beego.Thanks.

The node which belongs to NodeTypeEnd should refuse the requests to apply event.

Hi, I think the node should refuse the request to apply event if it is in NodeTypeEnd. How do you think so?

the code:

func (n *Node) applyEvent(otx *sql.Tx, event *DocEvent, recipients []GroupID) (DocStateID, error) {
    ...
    switch tnode.NodeType {
    ...
    case NodeTypeBegin, NodeTypeEnd, NodeTypeLinear, NodeTypeBranch:
        ....
    }
}

Can you make a easy turtorial?

Hi the information of flow is too little。can you make a turtorial that a blog or a website? i think is very useful for some people who is new beginner of flow.

Why is unique(doctype_id, docstate_id), but not unique(doctype_id, docstate_id, ac_id)?

Hi, I have some question about workflow node after reading wf_workflow_nodes.sql. If I want to create two workflows for the same doctype, for example, A -> B -> C and E -> B -> F. Now, since the constraints of table wf_workflow_nodes.sql, the two flows on the node B will has the same ac_id and will have the same access context which means the same permission. So, why not change to unique(doctype_id, docstate_id, ac_id), so we can give the different permission to node B in the two or more wrokflows?

flow-ui online

flow-ui online #113
In order to facilitate everyone to understand and use flow, I wrote a demo with vue.js+element+vue-element-extends+beego and put it on tencent cloud. It is just a preliminary one,at present it has the function of adding, but cant delete and modify.
Snap3
Snap5

Can you perfect the example again?

Thank you very much for the previous example.
Can you perfect the example again?

For example, when I create a new documents, do I create their events at the same time? Or create a new event and apply it to workflow when I clicks the action button?

In the list of documents presented to the user, for each document, is it right to list all possible actions and next states according to transition? When the user clicks on the action button, do I just create a new event and then apply it to workflow?

When I create a new event, it returns DocEventID, but what workflow applyevent needs is an DocEvent. Feel that I do is not correct.

Stalled

Is this project stalled.
Are you going to put any examples in the repo.

I ask because it's quite useful code base for BPM

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.