{ "kind": "open-flow-workflow", "version": 1, "name": "Zammad Ticket Summary to Zulip", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_8aca9e012fdbd0b0": { "name": "Run on demand", "kind": "start", "inputDefs": [] }, "n_c0c549cad5cc0acd": { "name": "Weekdays at 08:30 UTC", "kind": "cron", "cronTimes": [ { "type": "cron", "expression": "30 8 * * 1-5", "timezone": "UTC" } ] }, "n_cf3c9a6c9b1aedcc": { "inputs": { "previousState": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_cf3c9a6c9b1aedcc", "output": "state" } ] }, "newId": { "kind": "value", "value": 1 }, "openId": { "kind": "value", "value": 2 }, "reminderId": { "kind": "value", "value": 3 }, "closeId": { "kind": "value", "value": 7 }, "tickets": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_542a1a59700978ed", "output": "tickets" } ] } }, "name": "Count ticket states", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": true, "handle": "previousState" }, { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "integer", "exclusiveMinimum": 0, "description": "The numeric Zammad resource ID." }, "number": { "type": "string", "description": "The human-readable ticket number." }, "title": { "type": "string", "description": "The ticket title." }, "group_id": { "type": "integer", "description": "The assigned group ID." }, "customer_id": { "type": "integer", "description": "The customer user ID." }, "state_id": { "type": "integer", "description": "The ticket state ID." }, "priority_id": { "type": "integer", "description": "The ticket priority ID." } }, "additionalProperties": true, "description": "A Zammad ticket object." }, "description": "Tickets returned by Zammad." }, "nullable": true, "handle": "tickets" }, { "jsonSchema": { "type": "integer", "minimum": 1 }, "nullable": false, "handle": "newId" }, { "jsonSchema": { "type": "integer", "minimum": 1 }, "nullable": false, "handle": "openId" }, { "jsonSchema": { "type": "integer", "minimum": 1 }, "nullable": false, "handle": "reminderId" }, { "jsonSchema": { "type": "integer", "minimum": 1 }, "nullable": false, "handle": "closeId" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" }, { "jsonSchema": { "type": "integer", "minimum": 1 }, "nullable": false, "handle": "page" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "more" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "hasTickets" }, { "jsonSchema": { "type": "array", "items": { "type": "integer", "minimum": 0 }, "minItems": 4, "maxItems": 4 }, "nullable": false, "handle": "counts" } ], "name": "Count ticket states", "moduleId": "n_89610406e1110e0b", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_1816f0d5a74aa807": { "inputs": {}, "name": "More ticket pages", "kind": "condition", "matchMode": "first", "cases": [ { "output": "read", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_cf3c9a6c9b1aedcc", "output": "more" } }, "operator": "isTrue" } ] } ] } ] }, "n_542a1a59700978ed": { "inputs": { "page": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_cf3c9a6c9b1aedcc", "output": "page" } ] }, "perPage": { "kind": "value", "value": 20 } }, "name": "Read one Zammad ticket page", "kind": "task", "task": { "inputs": [ { "description": "The one-based result page number.", "jsonSchema": { "type": "integer", "exclusiveMinimum": 0, "description": "The one-based result page number." }, "nullable": true, "handle": "page", "value": null }, { "description": "The maximum number of records to return on this page.", "jsonSchema": { "type": "integer", "exclusiveMinimum": 0, "description": "The maximum number of records to return on this page." }, "nullable": true, "handle": "perPage", "value": null }, { "description": "Whether to expand named relations in the response.", "jsonSchema": { "type": "boolean", "description": "Whether to expand named relations in the response." }, "nullable": true, "handle": "expand", "value": null } ], "outputs": [ { "description": "Tickets returned by Zammad.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "integer", "exclusiveMinimum": 0, "description": "The numeric Zammad resource ID." }, "number": { "type": "string", "description": "The human-readable ticket number." }, "title": { "type": "string", "description": "The ticket title." }, "group_id": { "type": "integer", "description": "The assigned group ID." }, "customer_id": { "type": "integer", "description": "The customer user ID." }, "state_id": { "type": "integer", "description": "The ticket state ID." }, "priority_id": { "type": "integer", "description": "The ticket priority ID." } }, "additionalProperties": true, "description": "A Zammad ticket object." }, "description": "Tickets returned by Zammad." }, "nullable": false, "handle": "tickets" } ], "name": "Read one Zammad ticket page", "executor": { "kind": "connector", "action": "zammad.list_tickets" } } }, "n_f605ccddda35dd50": { "inputs": {}, "name": "Any tickets found", "kind": "condition", "matchMode": "first", "cases": [ { "output": "send", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_cf3c9a6c9b1aedcc", "output": "hasTickets" } }, "operator": "isTrue" } ] } ] } ] }, "n_2648e1dd757d1edc": { "inputs": { "counts": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_cf3c9a6c9b1aedcc", "output": "counts" } ] }, "stream": { "kind": "value", "value": "customer support" }, "topic": { "kind": "value", "value": "tickets" } }, "name": "Prepare the Zulip summary", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "integer", "minimum": 0 }, "minItems": 4, "maxItems": 4 }, "nullable": false, "handle": "counts" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "stream" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "topic" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": { "anyOf": [ { "type": [ "string", "number", "boolean" ] }, { "type": "array", "items": { "type": [ "string", "number", "boolean" ] } } ] } }, "nullable": false, "handle": "body" } ], "name": "Prepare the Zulip summary", "moduleId": "n_0658d606aeeee973", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_e317bab324970c11": { "inputs": { "url": { "kind": "value", "value": "https://zulip.example.invalid/api/v1/messages" }, "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_2648e1dd757d1edc", "output": "body" } ] }, "auth.username": { "kind": "unset" }, "auth.password": { "kind": "unset" } }, "name": "Send the Zulip summary", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "object", "additionalProperties": { "anyOf": [ { "type": [ "string", "number", "boolean" ] }, { "type": "array", "items": { "type": [ "string", "number", "boolean" ] } } ] } }, "nullable": false, "handle": "body" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "auth.username" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "auth.password" } ], "outputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Send the Zulip summary", "executor": { "method": "POST", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "form", "authentication": { "type": "basic" }, "responseFormat": "json", "statusPolicy": "success", "kind": "http-request" } } }, "n_79cf945aebf23b31": { "inputs": { "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_e317bab324970c11", "output": "body" } ] } }, "name": "Confirm the Zulip message", "kind": "task", "task": { "inputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" } ], "outputs": [ { "jsonSchema": { "type": "integer", "minimum": 1 }, "nullable": false, "handle": "messageId" } ], "name": "Confirm the Zulip message", "moduleId": "n_3dda71f76bf5d817", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } } }, "edges": [ { "source": "n_8aca9e012fdbd0b0", "target": "n_cf3c9a6c9b1aedcc" }, { "source": "n_c0c549cad5cc0acd", "target": "n_cf3c9a6c9b1aedcc" }, { "source": "n_cf3c9a6c9b1aedcc", "target": "n_1816f0d5a74aa807" }, { "source": "n_1816f0d5a74aa807", "target": "n_542a1a59700978ed", "sourceHandle": "read" }, { "source": "n_542a1a59700978ed", "target": "n_cf3c9a6c9b1aedcc" }, { "source": "n_1816f0d5a74aa807", "target": "n_f605ccddda35dd50", "sourceHandle": "otherwise" }, { "source": "n_f605ccddda35dd50", "target": "n_2648e1dd757d1edc", "sourceHandle": "send" }, { "source": "n_2648e1dd757d1edc", "target": "n_e317bab324970c11" }, { "source": "n_e317bab324970c11", "target": "n_79cf945aebf23b31" } ] } }, "modules": { "n_89610406e1110e0b": { "name": "Count ticket states", "imports": [], "source": "export default function collect({previousState,tickets,newId,openId,reminderId,closeId}) {\n const ids=[newId,openId,reminderId,closeId];if(ids.some(x=>!Number.isSafeInteger(x)||x<1)||new Set(ids).size!==4)throw Error('Configure four distinct positive Zammad state IDs');\n if(previousState===null){if(tickets!==null)throw Error('Unexpected initial ticket page');return{state:{page:1,seen:[],counts:[0,0,0,0]},page:1,more:true,hasTickets:false,counts:[0,0,0,0]};}\n if(!previousState||!Number.isSafeInteger(previousState.page)||!Array.isArray(previousState.seen)||!Array.isArray(previousState.counts)||!Array.isArray(tickets))throw Error('Invalid Zammad page state');\n const seen=new Set(previousState.seen),counts=[...previousState.counts];for(const t of tickets){if(!t||!Number.isSafeInteger(t.id)||t.id<1||!Number.isSafeInteger(t.state_id)||seen.has(t.id))throw Error('Invalid or duplicate Zammad ticket');seen.add(t.id);const index=ids.indexOf(t.state_id);if(index!==-1)counts[index]++;}\n const state={page:previousState.page+1,seen:[...seen],counts};return{state,page:state.page,more:tickets.length>0,hasTickets:state.seen.length>0,counts};\n}\n" }, "n_0658d606aeeee973": { "name": "Prepare the Zulip summary", "imports": [], "source": "export default function message({counts,stream,topic}) {\n if(!Array.isArray(counts)||counts.length!==4||counts.some(x=>!Number.isSafeInteger(x)||x<0)||typeof stream!=='string'||!stream.trim()||typeof topic!=='string'||!topic.trim())throw Error('Configure the Zulip stream and topic');\n const [n,o,r,c]=counts;return {body:{type:'stream',to:stream.trim(),topic:topic.trim(),content:`:ticket: Support Tickets Summary:\\n* Open: ${o}\\n* New: ${n}\\n* Pending Close ${c}\\n* Pending Reminder ${r}`}};\n}\n" }, "n_3dda71f76bf5d817": { "name": "Confirm the Zulip message", "imports": [], "source": "export default function confirm({body}) {if(!body||body.result!=='success'||!Number.isSafeInteger(body.id)||body.id<1)throw Error('Zulip did not confirm the message');return {messageId:body.id};}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }