3
0

Basic system autuomation, mail processing

This commit is contained in:
Denis Arh
2019-09-03 09:09:44 +02:00
parent 78660c47ec
commit 6b5ef8aaae
19 changed files with 2807 additions and 122 deletions

View File

@@ -1103,7 +1103,8 @@
}
}
]
}, {
},
{
"title": "Permissions",
"parameters": {},
"entrypoint": "permissions",
@@ -1200,5 +1201,385 @@
}
}
]
},
{
"title": "Automation scripts",
"entrypoint": "automation_script",
"path": "/automation/script",
"authentication": [
"Client ID",
"Session ID"
],
"struct": [
{
"imports": [
"github.com/cortezaproject/corteza-server/pkg/automation"
]
}
],
"apis": [
{
"name": "list",
"method": "GET",
"title": "List/read automation script",
"path": "/",
"parameters": {
"get": [
{
"name": "query",
"required": false,
"title": "Search query to match against automation script",
"type": "string"
},
{
"name": "resource",
"required": false,
"title": "Limit by resource (via trigger)",
"type": "string"
},
{
"name": "incDeleted",
"required": false,
"title": "Include deleted scripts",
"type": "bool"
},
{
"name": "page",
"type": "uint",
"required": false,
"title": "Page number (0 based)"
},
{
"name": "perPage",
"type": "uint",
"required": false,
"title": "Returned items per page (default 50)"
}
]
}
},
{
"name": "create",
"method": "POST",
"title": "Add new automation script",
"path": "/",
"parameters": {
"post": [
{
"name": "name",
"title": "automation name",
"type": "string"
},
{
"name": "sourceRef",
"title": "Source URL",
"type": "string"
},
{
"name": "source",
"title": "Source code",
"type": "string"
},
{
"name": "runAs",
"title": "Run as specific user",
"type": "uint64"
},
{
"name": "timeout",
"title": "Script timeout (in milliseconds)",
"type": "uint"
},
{
"name": "critical",
"title": "Is it critical to run this script successfully",
"type": "bool"
},
{
"name": "async",
"title": "Will this script be ran asynchronously",
"type": "bool"
},
{
"name": "enabled",
"type": "bool"
},
{
"name": "triggers",
"type": "automation.TriggerSet"
}
]
}
},
{
"name": "read",
"method": "GET",
"title": "Read automation script by ID",
"path": "/{scriptID}",
"parameters": {
"path": [
{
"type": "uint64",
"name": "scriptID",
"required": true,
"title": "automation script ID"
}
]
}
},
{
"name": "update",
"method": "POST",
"title": "Update automation script",
"path": "/{scriptID}",
"parameters": {
"path": [
{
"type": "uint64",
"name": "scriptID",
"required": true,
"title": "Automation script ID"
}
],
"post": [
{
"name": "name",
"title": "Script name",
"type": "string"
},
{
"name": "sourceRef",
"title": "Source URL",
"type": "string"
},
{
"name": "source",
"title": "Source code",
"type": "string"
},
{
"name": "runAs",
"title": "Run script as specific user",
"type": "uint64"
},
{
"name": "timeout",
"title": "Run script in user-agent (browser)",
"type": "uint"
},
{
"name": "critical",
"title": "Is it critical to run this script successfully",
"type": "bool"
},
{
"name": "async",
"title": "Will this script be ran asynchronously",
"type": "bool"
},
{
"name": "enabled",
"type": "bool"
},
{
"name": "triggers",
"type": "automation.TriggerSet"
}
]
}
},
{
"name": "delete",
"method": "DELETE",
"title": "Delete script",
"path": "/{scriptID}",
"parameters": {
"path": [
{
"type": "uint64",
"name": "scriptID",
"required": true,
"title": "Script ID"
}
]
}
},
{
"name": "test",
"method": "POST",
"title": "Run source code in corredor. Used for testing",
"path": "/test",
"parameters": {
"post": [
{"name": "source", "type": "string", "title": "Script's source code"},
{"name": "payload", "type": "json.RawMessage", "title": "Payload to be used"}
]
}
}
]
},
{
"title": "Automation script triggers",
"entrypoint": "automation_trigger",
"path": "/automation/script/{scriptID}/trigger",
"authentication": [
"Client ID",
"Session ID"
],
"parameters": {
"path": [
{
"type": "uint64",
"name": "scriptID",
"required": true,
"title": "Script ID"
}
]
},
"apis": [
{
"name": "list",
"method": "GET",
"title": "List/read automation script triggers",
"path": "/",
"parameters": {
"get": [
{
"name": "resource",
"required": false,
"title": "Only triggers of a specific resource",
"type": "string"
},
{
"name": "event",
"required": false,
"title": "Only triggers of a specific event",
"type": "string"
},
{
"name": "incDeleted",
"required": false,
"title": "Include deleted scripts",
"type": "bool"
},
{
"name": "page",
"type": "uint",
"required": false,
"title": "Page number (0 based)"
},
{
"name": "perPage",
"type": "uint",
"required": false,
"title": "Returned items per page (default 50)"
}
]
}
},
{
"name": "create",
"method": "POST",
"title": "Add new automation script trigger",
"path": "/",
"parameters": {
"post": [
{
"name": "resource",
"title": "Resource",
"type": "string",
"required": true
},
{
"name": "event",
"title": "Event",
"type": "string",
"required": true
},
{
"name": "condition",
"title": "Event",
"type": "string"
},
{
"name": "enabled",
"type": "bool"
}
]
}
},
{
"name": "read",
"method": "GET",
"title": "Read automation script trigger by ID",
"path": "/{triggerID}",
"parameters": {
"path": [
{
"type": "uint64",
"name": "triggerID",
"required": true,
"title": "Automation script trigger ID"
}
]
}
},
{
"name": "update",
"method": "POST",
"title": "Update automation script trigger",
"path": "/{triggerID}",
"parameters": {
"path": [
{
"type": "uint64",
"name": "triggerID",
"required": true,
"title": "Automation script trigger ID"
}
],
"post": [
{
"name": "resource",
"title": "Resource",
"type": "string",
"required": true
},
{
"name": "event",
"title": "Event",
"type": "string",
"required": true
},
{
"name": "condition",
"title": "Event",
"type": "string"
},
{
"name": "enabled",
"type": "bool"
}
]
}
},
{
"name": "delete",
"method": "DELETE",
"title": "Delete script",
"path": "/{triggerID}",
"parameters": {
"path": [
{
"type": "uint64",
"name": "triggerID",
"required": true,
"title": "Automation script trigger ID"
}
]
}
}
]
}
]

View File

@@ -0,0 +1,226 @@
{
"Title": "Automation scripts",
"Interface": "Automation_script",
"Struct": [
{
"imports": [
"github.com/cortezaproject/corteza-server/pkg/automation"
]
}
],
"Parameters": null,
"Protocol": "",
"Authentication": [
"Client ID",
"Session ID"
],
"Path": "/automation/script",
"APIs": [
{
"Name": "list",
"Method": "GET",
"Title": "List/read automation script",
"Path": "/",
"Parameters": {
"get": [
{
"name": "query",
"required": false,
"title": "Search query to match against automation script",
"type": "string"
},
{
"name": "resource",
"required": false,
"title": "Limit by resource (via trigger)",
"type": "string"
},
{
"name": "incDeleted",
"required": false,
"title": "Include deleted scripts",
"type": "bool"
},
{
"name": "page",
"required": false,
"title": "Page number (0 based)",
"type": "uint"
},
{
"name": "perPage",
"required": false,
"title": "Returned items per page (default 50)",
"type": "uint"
}
]
}
},
{
"Name": "create",
"Method": "POST",
"Title": "Add new automation script",
"Path": "/",
"Parameters": {
"post": [
{
"name": "name",
"title": "automation name",
"type": "string"
},
{
"name": "sourceRef",
"title": "Source URL",
"type": "string"
},
{
"name": "source",
"title": "Source code",
"type": "string"
},
{
"name": "runAs",
"title": "Run as specific user",
"type": "uint64"
},
{
"name": "timeout",
"title": "Script timeout (in milliseconds)",
"type": "uint"
},
{
"name": "critical",
"title": "Is it critical to run this script successfully",
"type": "bool"
},
{
"name": "async",
"title": "Will this script be ran asynchronously",
"type": "bool"
},
{
"name": "enabled",
"type": "bool"
},
{
"name": "triggers",
"type": "automation.TriggerSet"
}
]
}
},
{
"Name": "read",
"Method": "GET",
"Title": "Read automation script by ID",
"Path": "/{scriptID}",
"Parameters": {
"path": [
{
"name": "scriptID",
"required": true,
"title": "automation script ID",
"type": "uint64"
}
]
}
},
{
"Name": "update",
"Method": "POST",
"Title": "Update automation script",
"Path": "/{scriptID}",
"Parameters": {
"path": [
{
"name": "scriptID",
"required": true,
"title": "Automation script ID",
"type": "uint64"
}
],
"post": [
{
"name": "name",
"title": "Script name",
"type": "string"
},
{
"name": "sourceRef",
"title": "Source URL",
"type": "string"
},
{
"name": "source",
"title": "Source code",
"type": "string"
},
{
"name": "runAs",
"title": "Run script as specific user",
"type": "uint64"
},
{
"name": "timeout",
"title": "Run script in user-agent (browser)",
"type": "uint"
},
{
"name": "critical",
"title": "Is it critical to run this script successfully",
"type": "bool"
},
{
"name": "async",
"title": "Will this script be ran asynchronously",
"type": "bool"
},
{
"name": "enabled",
"type": "bool"
},
{
"name": "triggers",
"type": "automation.TriggerSet"
}
]
}
},
{
"Name": "delete",
"Method": "DELETE",
"Title": "Delete script",
"Path": "/{scriptID}",
"Parameters": {
"path": [
{
"name": "scriptID",
"required": true,
"title": "Script ID",
"type": "uint64"
}
]
}
},
{
"Name": "test",
"Method": "POST",
"Title": "Run source code in corredor. Used for testing",
"Path": "/test",
"Parameters": {
"post": [
{
"name": "source",
"title": "Script's source code",
"type": "string"
},
{
"name": "payload",
"title": "Payload to be used",
"type": "json.RawMessage"
}
]
}
}
]
}

View File

@@ -0,0 +1,165 @@
{
"Title": "Automation script triggers",
"Interface": "Automation_trigger",
"Struct": null,
"Parameters": {
"path": [
{
"name": "scriptID",
"required": true,
"title": "Script ID",
"type": "uint64"
}
]
},
"Protocol": "",
"Authentication": [
"Client ID",
"Session ID"
],
"Path": "/automation/script/{scriptID}/trigger",
"APIs": [
{
"Name": "list",
"Method": "GET",
"Title": "List/read automation script triggers",
"Path": "/",
"Parameters": {
"get": [
{
"name": "resource",
"required": false,
"title": "Only triggers of a specific resource",
"type": "string"
},
{
"name": "event",
"required": false,
"title": "Only triggers of a specific event",
"type": "string"
},
{
"name": "incDeleted",
"required": false,
"title": "Include deleted scripts",
"type": "bool"
},
{
"name": "page",
"required": false,
"title": "Page number (0 based)",
"type": "uint"
},
{
"name": "perPage",
"required": false,
"title": "Returned items per page (default 50)",
"type": "uint"
}
]
}
},
{
"Name": "create",
"Method": "POST",
"Title": "Add new automation script trigger",
"Path": "/",
"Parameters": {
"post": [
{
"name": "resource",
"required": true,
"title": "Resource",
"type": "string"
},
{
"name": "event",
"required": true,
"title": "Event",
"type": "string"
},
{
"name": "condition",
"title": "Event",
"type": "string"
},
{
"name": "enabled",
"type": "bool"
}
]
}
},
{
"Name": "read",
"Method": "GET",
"Title": "Read automation script trigger by ID",
"Path": "/{triggerID}",
"Parameters": {
"path": [
{
"name": "triggerID",
"required": true,
"title": "Automation script trigger ID",
"type": "uint64"
}
]
}
},
{
"Name": "update",
"Method": "POST",
"Title": "Update automation script trigger",
"Path": "/{triggerID}",
"Parameters": {
"path": [
{
"name": "triggerID",
"required": true,
"title": "Automation script trigger ID",
"type": "uint64"
}
],
"post": [
{
"name": "resource",
"required": true,
"title": "Resource",
"type": "string"
},
{
"name": "event",
"required": true,
"title": "Event",
"type": "string"
},
{
"name": "condition",
"title": "Event",
"type": "string"
},
{
"name": "enabled",
"type": "bool"
}
]
}
},
{
"Name": "delete",
"Method": "DELETE",
"Title": "Delete script",
"Path": "/{triggerID}",
"Parameters": {
"path": [
{
"name": "triggerID",
"required": true,
"title": "Automation script trigger ID",
"type": "uint64"
}
]
}
}
]
}

View File

@@ -278,6 +278,229 @@
# Automation scripts
| Method | Endpoint | Purpose |
| ------ | -------- | ------- |
| `GET` | `/automation/script/` | List/read automation script |
| `POST` | `/automation/script/` | Add new automation script |
| `GET` | `/automation/script/{scriptID}` | Read automation script by ID |
| `POST` | `/automation/script/{scriptID}` | Update automation script |
| `DELETE` | `/automation/script/{scriptID}` | Delete script |
| `POST` | `/automation/script/test` | Run source code in corredor. Used for testing |
## List/read automation script
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/automation/script/` | HTTP/S | GET | Client ID, Session ID |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| query | string | GET | Search query to match against automation script | N/A | NO |
| resource | string | GET | Limit by resource (via trigger) | N/A | NO |
| incDeleted | bool | GET | Include deleted scripts | N/A | NO |
| page | uint | GET | Page number (0 based) | N/A | NO |
| perPage | uint | GET | Returned items per page (default 50) | N/A | NO |
## Add new automation script
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/automation/script/` | HTTP/S | POST | Client ID, Session ID |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| name | string | POST | automation name | N/A | NO |
| sourceRef | string | POST | Source URL | N/A | NO |
| source | string | POST | Source code | N/A | NO |
| runAs | uint64 | POST | Run as specific user | N/A | NO |
| timeout | uint | POST | Script timeout (in milliseconds) | N/A | NO |
| critical | bool | POST | Is it critical to run this script successfully | N/A | NO |
| async | bool | POST | Will this script be ran asynchronously | N/A | NO |
| enabled | bool | POST | | N/A | NO |
| triggers | automation.TriggerSet | POST | | N/A | NO |
## Read automation script by ID
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/automation/script/{scriptID}` | HTTP/S | GET | Client ID, Session ID |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| scriptID | uint64 | PATH | automation script ID | N/A | YES |
## Update automation script
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/automation/script/{scriptID}` | HTTP/S | POST | Client ID, Session ID |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| scriptID | uint64 | PATH | Automation script ID | N/A | YES |
| name | string | POST | Script name | N/A | NO |
| sourceRef | string | POST | Source URL | N/A | NO |
| source | string | POST | Source code | N/A | NO |
| runAs | uint64 | POST | Run script as specific user | N/A | NO |
| timeout | uint | POST | Run script in user-agent (browser) | N/A | NO |
| critical | bool | POST | Is it critical to run this script successfully | N/A | NO |
| async | bool | POST | Will this script be ran asynchronously | N/A | NO |
| enabled | bool | POST | | N/A | NO |
| triggers | automation.TriggerSet | POST | | N/A | NO |
## Delete script
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/automation/script/{scriptID}` | HTTP/S | DELETE | Client ID, Session ID |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| scriptID | uint64 | PATH | Script ID | N/A | YES |
## Run source code in corredor. Used for testing
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/automation/script/test` | HTTP/S | POST | Client ID, Session ID |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| source | string | POST | Script's source code | N/A | NO |
| payload | json.RawMessage | POST | Payload to be used | N/A | NO |
---
# Automation script triggers
| Method | Endpoint | Purpose |
| ------ | -------- | ------- |
| `GET` | `/automation/script/{scriptID}/trigger/` | List/read automation script triggers |
| `POST` | `/automation/script/{scriptID}/trigger/` | Add new automation script trigger |
| `GET` | `/automation/script/{scriptID}/trigger/{triggerID}` | Read automation script trigger by ID |
| `POST` | `/automation/script/{scriptID}/trigger/{triggerID}` | Update automation script trigger |
| `DELETE` | `/automation/script/{scriptID}/trigger/{triggerID}` | Delete script |
## List/read automation script triggers
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/automation/script/{scriptID}/trigger/` | HTTP/S | GET | Client ID, Session ID |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| resource | string | GET | Only triggers of a specific resource | N/A | NO |
| event | string | GET | Only triggers of a specific event | N/A | NO |
| incDeleted | bool | GET | Include deleted scripts | N/A | NO |
| page | uint | GET | Page number (0 based) | N/A | NO |
| perPage | uint | GET | Returned items per page (default 50) | N/A | NO |
| scriptID | uint64 | PATH | Script ID | N/A | YES |
## Add new automation script trigger
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/automation/script/{scriptID}/trigger/` | HTTP/S | POST | Client ID, Session ID |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| resource | string | POST | Resource | N/A | YES |
| event | string | POST | Event | N/A | YES |
| condition | string | POST | Event | N/A | NO |
| enabled | bool | POST | | N/A | NO |
| scriptID | uint64 | PATH | Script ID | N/A | YES |
## Read automation script trigger by ID
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/automation/script/{scriptID}/trigger/{triggerID}` | HTTP/S | GET | Client ID, Session ID |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| triggerID | uint64 | PATH | Automation script trigger ID | N/A | YES |
| scriptID | uint64 | PATH | Script ID | N/A | YES |
## Update automation script trigger
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/automation/script/{scriptID}/trigger/{triggerID}` | HTTP/S | POST | Client ID, Session ID |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| triggerID | uint64 | PATH | Automation script trigger ID | N/A | YES |
| scriptID | uint64 | PATH | Script ID | N/A | YES |
| resource | string | POST | Resource | N/A | YES |
| event | string | POST | Event | N/A | YES |
| condition | string | POST | Event | N/A | NO |
| enabled | bool | POST | | N/A | NO |
## Delete script
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/automation/script/{scriptID}/trigger/{triggerID}` | HTTP/S | DELETE | Client ID, Session ID |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| triggerID | uint64 | PATH | Automation script trigger ID | N/A | YES |
| scriptID | uint64 | PATH | Script ID | N/A | YES |
---
# Organisations
Organisations represent a top-level grouping entity. There may be many organisations defined in a single deployment.

View File

@@ -0,0 +1,198 @@
package mail
import (
"encoding/json"
"errors"
"net/mail"
"regexp"
"strings"
"github.com/cortezaproject/corteza-server/pkg/automation"
"github.com/cortezaproject/corteza-server/system/types"
)
// Trigger condition:
// Matcher for mail headers
type (
Condition struct {
MatchAll bool `json:"matchAll"`
Headers []HeaderMatcher `json:"headers"`
}
HeaderMatcher struct {
Name HMName `json:"name"`
Op HMOp `json:"op"`
Match string `json:"match"`
// Compiled regexp
re *regexp.Regexp
}
HMName string
HMOp string
userExistanceVerifier func(string) bool
)
const (
HeaderMatchNameFrom HMName = "from"
HeaderMatchNameTo = "to"
HeaderMatchNameCC = "cc"
HeaderMatchNameBCC = "bcc"
HeaderMatchNameReplyTo = "reply-to"
HeaderMatchNameSubject = "subject"
HMOpEqualCi HMOp = ""
HMOpSuffixCi = "suffix-ci"
HMOpPrefixCi = "prefix-ci"
HMOpRegex = "regex"
HMOpUser = "user"
)
var (
ErrUnknownHeaderMatcherName = errors.New("unknown header matcher field")
ErrUnknownHeaderMatcherOperator = errors.New("unknown header matcher operator")
ErrInvalidHeaderMatcherValue = errors.New("invalid header matcher value")
)
func (c *Condition) Prepare() (err error) {
for i := range c.Headers {
err = c.Headers[i].prepare()
if err != nil {
return
}
}
return
}
// IsValid verifies if header matcher is valid
func (m *HeaderMatcher) prepare() (err error) {
switch m.Name {
case HeaderMatchNameFrom,
HeaderMatchNameTo,
HeaderMatchNameCC,
HeaderMatchNameBCC,
HeaderMatchNameReplyTo,
HeaderMatchNameSubject:
// ok fields
default:
return ErrUnknownHeaderMatcherName
}
switch m.Op {
case HMOpRegex:
// Try to compile given regex
m.re, err = regexp.Compile(m.Match)
if err != nil {
return ErrInvalidHeaderMatcherValue
}
case HMOpUser:
// When matching against existing user,
// there should be no value set
if m.Match != "" {
return ErrInvalidHeaderMatcherValue
}
case HMOpEqualCi, HMOpSuffixCi, HMOpPrefixCi:
// no special validation here
m.Match = strings.ToLower(m.Match)
default:
return ErrUnknownHeaderMatcherOperator
}
return
}
func (n HMName) match(name string) bool {
return string(n) == strings.ToLower(name)
}
// IsMatch checks if header matcher matches against given headers
func (m *HeaderMatcher) isMatch(header mail.Header, exists userExistanceVerifier, matchAll bool) (match bool) {
var lcHeader string
for name, vv := range header {
if !m.Name.match(name) {
continue
}
for _, v := range vv {
lcHeader = strings.ToLower(v)
switch m.Op {
case HMOpEqualCi:
match = m.Match == lcHeader
// spew.Dump("doing simple string match", match, m, v)
case HMOpSuffixCi:
match = strings.HasSuffix(lcHeader, m.Match)
case HMOpPrefixCi:
match = strings.HasPrefix(lcHeader, m.Match)
case HMOpRegex:
match = m.re.MatchString(v)
case HMOpUser:
match = exists(v)
default:
return false
}
if !match && matchAll {
// fail in first non-match
return false
} else if match && !matchAll {
// match in first
return true
}
}
}
return match
}
func (c *Condition) CheckHeader(header mail.Header, uev userExistanceVerifier) (match bool) {
_ = c.Prepare()
// Pre-process & simplify header values: parse all addresses,
// extract emails and toss away names, we do not need them
for name := range header {
for i, v := range header[name] {
switch name {
case "from",
"to",
"cc",
"bcc",
"reply-to":
addr, _ := mail.ParseAddress(v)
header[name][i] = addr.Address
}
}
}
for _, h := range c.Headers {
match = h.isMatch(header, uev, c.MatchAll)
if !match && c.MatchAll {
// fail in first non-match
return false
} else if match && !c.MatchAll {
// match in first
return true
}
}
return match
}
func MakeChecker(headers types.MailMessageHeader, uev userExistanceVerifier) automation.TriggerConditionChecker {
return func(c string) bool {
var (
tc = Condition{}
)
if err := json.Unmarshal([]byte(c), &tc); err == nil {
return tc.CheckHeader(headers.Raw, uev)
}
return false
}
}

View File

@@ -1,4 +1,4 @@
package service
package mail
import (
"encoding/json"
@@ -11,45 +11,45 @@ func Test_makeMailHeaderChecker(t *testing.T) {
tests := []struct {
name string
mh types.MailMessageHeader
tc TriggerCondition
tc Condition
expecting bool
}{
{
name: "empty should not match",
mh: types.MailMessageHeader{},
tc: TriggerCondition{},
tc: Condition{},
},
{
name: "simple check",
mh: types.MailMessageHeader{Raw: map[string][]string{"Subject": []string{"SIMPLE"}}},
tc: TriggerCondition{Headers: []TriggerConditionHeaderMatcher{{Name: "Subject", Match: "SIMPLE"}}},
tc: Condition{Headers: []HeaderMatcher{{Name: HeaderMatchNameSubject, Match: "SIMPLE"}}},
expecting: true,
},
{
name: "simple check - no match",
mh: types.MailMessageHeader{Raw: map[string][]string{"Subject": []string{"SIMPLE"}}},
tc: TriggerCondition{Headers: []TriggerConditionHeaderMatcher{{Name: "Subject", Match: "complex"}}},
tc: Condition{Headers: []HeaderMatcher{{Name: HeaderMatchNameSubject, Match: "complex"}}},
expecting: false,
},
{
name: "simple check - no match",
mh: types.MailMessageHeader{Raw: map[string][]string{"Subject": []string{"SIMPLE"}}},
tc: TriggerCondition{Headers: []TriggerConditionHeaderMatcher{{Name: "From", Match: "SIMPLE"}}},
tc: Condition{Headers: []HeaderMatcher{{Name: HeaderMatchNameFrom, Match: "SIMPLE"}}},
expecting: false,
},
{
name: "simple check - name-case",
mh: types.MailMessageHeader{Raw: map[string][]string{"SUBJECT": []string{"SIMPLE"}}},
tc: TriggerCondition{Headers: []TriggerConditionHeaderMatcher{{Name: "subject", Match: "SIMPLE"}}},
tc: Condition{Headers: []HeaderMatcher{{Name: HeaderMatchNameSubject, Match: "SIMPLE"}}},
expecting: true,
},
{
name: "two matchers, one matches",
mh: types.MailMessageHeader{Raw: map[string][]string{"Subject": []string{"SIMPLE"}}},
tc: TriggerCondition{
Headers: []TriggerConditionHeaderMatcher{
{Name: "Subject", Match: "SIMPLE"},
{Name: "Subject", Match: "complex"},
tc: Condition{
Headers: []HeaderMatcher{
{Name: HeaderMatchNameSubject, Match: "SIMPLE"},
{Name: HeaderMatchNameSubject, Match: "complex"},
},
},
expecting: true,
@@ -57,11 +57,11 @@ func Test_makeMailHeaderChecker(t *testing.T) {
{
name: "two matchers, one matches, match-all=true",
mh: types.MailMessageHeader{Raw: map[string][]string{"Subject": []string{"SIMPLE"}}},
tc: TriggerCondition{
tc: Condition{
MatchAll: true,
Headers: []TriggerConditionHeaderMatcher{
{Name: "Subject", Match: "SIMPLE"},
{Name: "Subject", Match: "complex"},
Headers: []HeaderMatcher{
{Name: HeaderMatchNameSubject, Match: "SIMPLE"},
{Name: HeaderMatchNameSubject, Match: "complex"},
},
},
expecting: false,
@@ -69,19 +69,23 @@ func Test_makeMailHeaderChecker(t *testing.T) {
{
name: "regex check",
mh: types.MailMessageHeader{Raw: map[string][]string{"Subject": []string{"SIMPLE"}}},
tc: TriggerCondition{Headers: []TriggerConditionHeaderMatcher{{Name: "Subject", Match: "^S.+$", Op: "regex"}}},
tc: Condition{Headers: []HeaderMatcher{{Name: HeaderMatchNameSubject, Match: "^S.+$", Op: HMOpRegex}}},
expecting: true,
},
{
name: "case-insensitive check",
mh: types.MailMessageHeader{Raw: map[string][]string{"Subject": []string{"SIMPLE"}}},
tc: TriggerCondition{Headers: []TriggerConditionHeaderMatcher{{Name: "Subject", Match: "simple", Op: "ci"}}},
tc: Condition{Headers: []HeaderMatcher{{Name: HeaderMatchNameSubject, Match: "simple", Op: HMOpEqualCi}}},
expecting: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
checker := (automationRunner{}).makeMailHeaderChecker(tt.mh)
if err := tt.tc.Prepare(); err != nil {
t.Errorf("unable to prepare header matcher: %v", err)
}
checker := MakeChecker(tt.mh, nil)
j, _ := json.Marshal(tt.tc)
if checker(string(j)) != tt.expecting {

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,48 @@
CREATE TABLE IF NOT EXISTS sys_automation_script (
`id` BIGINT(20) UNSIGNED NOT NULL,
`rel_namespace` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'For compatibility only, not used',
`name` VARCHAR(64) NOT NULL DEFAULT 'unnamed' COMMENT 'The name of the script',
`source` TEXT NOT NULL COMMENT 'Source code for the script',
`source_ref` VARCHAR(200) NOT NULL COMMENT 'Where is the script located (if remote)',
`async` BOOLEAN NOT NULL DEFAULT FALSE COMMENT 'Do we run this script asynchronously?',
`rel_runner` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Who is running the script? 0 for invoker',
`run_in_ua` BOOLEAN NOT NULL DEFAULT FALSE COMMENT 'Run this script inside user-agent environment',
`timeout` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Any explicit timeout set for this script (milliseconds)?',
`critical` BOOLEAN NOT NULL DEFAULT TRUE COMMENT 'Is it critical that this script is executed successfully',
`enabled` BOOLEAN NOT NULL DEFAULT TRUE COMMENT 'Is this script enabled?',
`created_by` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_by` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
`updated_at` DATETIME NULL DEFAULT NULL,
`deleted_by` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
`deleted_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS sys_automation_trigger (
`id` BIGINT(20) UNSIGNED NOT NULL,
`rel_script` BIGINT(20) UNSIGNED NOT NULL COMMENT 'Script that is triggered',
`resource` VARCHAR(128) NOT NULL COMMENT 'Resource triggering the event',
`event` VARCHAR(128) NOT NULL COMMENT 'Event triggered',
`event_condition`
TEXT NOT NULL COMMENT 'Trigger condition',
`enabled` BOOLEAN NOT NULL DEFAULT TRUE COMMENT 'Trigger enabled?',
`weight` INT NOT NULL DEFAULT 0,
`created_by` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_by` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
`updated_at` DATETIME NULL DEFAULT NULL,
`deleted_by` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
`deleted_at` DATETIME NULL DEFAULT NULL,
CONSTRAINT `fk_sys_automation_script` FOREIGN KEY (`rel_script`) REFERENCES `sys_automation_script` (`id`),
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@@ -2,10 +2,6 @@ package service
import (
"context"
"encoding/json"
"net/mail"
"regexp"
"strings"
"time"
"github.com/pkg/errors"
@@ -17,7 +13,9 @@ import (
intAuth "github.com/cortezaproject/corteza-server/internal/auth"
"github.com/cortezaproject/corteza-server/pkg/automation"
"github.com/cortezaproject/corteza-server/pkg/automation/corredor"
mailTrigger "github.com/cortezaproject/corteza-server/pkg/automation/mail"
"github.com/cortezaproject/corteza-server/pkg/sentry"
"github.com/cortezaproject/corteza-server/system/internal/repository"
"github.com/cortezaproject/corteza-server/system/proto"
"github.com/cortezaproject/corteza-server/system/types"
)
@@ -27,10 +25,15 @@ type (
opt AutomationRunnerOpt
logger *zap.Logger
runner corredor.ScriptRunnerClient
userFinder automationRunnerUserFinder
scriptFinder automationScriptsFinder
jwtEncoder intAuth.TokenEncoder
}
automationRunnerUserFinder interface {
FindByEmail(string) (*types.User, error)
}
automationScriptsFinder interface {
Watch(ctx context.Context)
FindRunnableScripts(resource, event string, cc ...automation.TriggerConditionChecker) automation.ScriptSet
@@ -41,27 +44,13 @@ type (
ApiBaseURLMessaging string
ApiBaseURLCompose string
}
TriggerCondition struct {
MatchAll bool `json:"matchAll"`
Headers []TriggerConditionHeaderMatcher `json:"headers"`
}
TriggerConditionHeaderMatcher struct {
Name string `json:"name"`
Match string `json:"match"`
Op string `json:"op"`
}
)
const (
AutomationResourceRecord = "compose:record"
)
func AutomationRunner(opt AutomationRunnerOpt, f automationScriptsFinder, r corredor.ScriptRunnerClient) automationRunner {
var svc = automationRunner{
opt: opt,
userFinder: DefaultUser,
scriptFinder: f,
runner: r,
@@ -76,7 +65,7 @@ func (svc automationRunner) Watch(ctx context.Context) {
svc.scriptFinder.Watch(ctx)
}
func (svc automationRunner) OnReceivedMailMessage(ctx context.Context, mail *types.MailMessage) error {
func (svc automationRunner) OnReceiveMailMessage(ctx context.Context, mail *types.MailMessage) error {
return svc.findMailScripts(mail.Header).Walk(
svc.makeMailScriptRunner(ctx, mail),
)
@@ -84,7 +73,12 @@ func (svc automationRunner) OnReceivedMailMessage(ctx context.Context, mail *typ
// Finds all scripts that can process email
func (svc automationRunner) findMailScripts(headers types.MailMessageHeader) automation.ScriptSet {
ss, _ := svc.scriptFinder.FindRunnableScripts("system:mail", "onReceived", svc.makeMailHeaderChecker(headers)).
uev := func(email string) bool {
u, err := svc.userFinder.FindByEmail(email)
return u != nil && err == nil
}
ss, _ := svc.scriptFinder.FindRunnableScripts("system:mail", "onReceive", mailTrigger.MakeChecker(headers, uev)).
Filter(func(script *automation.Script) (bool, error) {
// Filter out user-agent scripts
return !script.RunInUA, nil
@@ -93,22 +87,24 @@ func (svc automationRunner) findMailScripts(headers types.MailMessageHeader) aut
return ss
}
func (svc automationRunner) RecordScriptTester(ctx context.Context, source string, mail *types.MailMessage) (err error) {
// Make record script runner and
runner := svc.makeMailScriptRunner(ctx, mail)
return runner(&automation.Script{
ID: 0,
Name: "test",
SourceRef: "test",
Source: source,
Async: false,
RunAs: 0,
RunInUA: false,
Timeout: 0,
Critical: true,
Enabled: false,
})
func (svc automationRunner) RecordScriptTester(ctx context.Context, source string, payload interface{}) (err error) {
// Make record script runner
// @todo figure out how to convert payload to *types.MailMessage
// runner := svc.makeMailScriptRunner(ctx, payload)
//
// return runner(&automation.Script{
// ID: 0,
// Name: "test",
// SourceRef: "test",
// Source: source,
// Async: false,
// RunAs: 0,
// RunInUA: false,
// Timeout: 0,
// Critical: true,
// Enabled: false,
// })
return repository.ErrNotImplemented
}
// Runs record script
@@ -194,64 +190,3 @@ func (svc automationRunner) getJWT(ctx context.Context, script *automation.Scrip
return svc.jwtEncoder.Encode(intAuth.GetIdentityFromContext(ctx))
}
func (svc automationRunner) makeMailHeaderChecker(headers types.MailMessageHeader) automation.TriggerConditionChecker {
return func(c string) bool {
var (
err error
tc = TriggerCondition{}
re *regexp.Regexp
match bool
)
if err := json.Unmarshal([]byte(c), &tc); err != nil {
panic(err) // @todo replace with log
return false
}
for _, m := range tc.Headers {
if m.Op == "regex" {
if re, err = regexp.Compile(m.Match); err != nil {
// Invalid re
continue
}
}
for name, vv := range headers.Raw {
name = strings.ToLower(name)
if strings.ToLower(m.Name) != name {
continue
}
for _, v := range vv {
switch name {
case "from",
"to",
"cc",
"bcc",
"reply-to":
a, _ := mail.ParseAddress(v)
v = a.Address
}
switch m.Op {
case "regex":
match = re.MatchString(v)
case "ci":
match = strings.ToLower(v) == strings.ToLower(m.Match)
default:
match = v == m.Match
}
if tc.MatchAll && !match {
return false
} else if !tc.MatchAll && match {
return true
}
}
}
}
return match
}
}

View File

@@ -50,7 +50,7 @@ func AutomationScript(sm automationScriptManager) automationScript {
return svc
}
func (svc automationScript) FindByID(ctx context.Context, namespaceID, scriptID uint64) (*automation.Script, error) {
func (svc automationScript) FindByID(ctx context.Context, scriptID uint64) (*automation.Script, error) {
if s, err := svc.loadCombo(ctx, scriptID); err != nil {
return nil, err
} else {
@@ -133,7 +133,7 @@ func (svc automationScript) Update(ctx context.Context, mod *automation.Script)
return svc.scriptManager.UpdateScript(ctx, s)
}
func (svc automationScript) Delete(ctx context.Context, namespaceID, scriptID uint64) (err error) {
func (svc automationScript) Delete(ctx context.Context, scriptID uint64) (err error) {
if s, err := svc.loadCombo(ctx, scriptID); err != nil {
return err
} else if !svc.ac.CanDeleteAutomationScript(ctx, s) {

View File

@@ -105,7 +105,7 @@ func (svc automationTrigger) isValid(ctx context.Context, s *automation.Script,
}
switch t.Event {
case "onReceived":
case "onReceive":
// @todo validate
default:

View File

@@ -92,7 +92,7 @@ func Init(ctx context.Context, log *zap.Logger, c Config) (err error) {
// handles script & trigger management & keeping runnables cripts in internal cache
ias := automation.Service(automation.AutomationServiceConfig{
Logger: DefaultLogger,
DbTablePrefix: "system",
DbTablePrefix: "sys",
DB: repository.DB(ctx),
TokenMaker: func(ctx context.Context, userID uint64) (jwt string, err error) {
var u *types.User

View File

@@ -0,0 +1,180 @@
package rest
import (
"context"
"github.com/pkg/errors"
"github.com/titpetric/factory/resputil"
"github.com/cortezaproject/corteza-server/pkg/automation"
"github.com/cortezaproject/corteza-server/pkg/rh"
"github.com/cortezaproject/corteza-server/system/internal/service"
"github.com/cortezaproject/corteza-server/system/rest/request"
)
var _ = errors.Wrap
type (
automationScriptPayload struct {
*automation.Script
CanGrant bool `json:"canGrant"`
CanUpdate bool `json:"canUpdate"`
CanDelete bool `json:"canDelete"`
CanSetRunner bool `json:"canSetRunner"`
CanSetAsAsync bool `json:"canSetAsAsync"`
CanSetAsCritical bool `json:"canAsCritical"`
}
automationScriptSetPayload struct {
Filter automation.ScriptFilter `json:"filter"`
Set []*automationScriptPayload `json:"set"`
}
automationScriptRunnablePayload struct {
Set []*automationScriptRunnable `json:"set"`
}
automationScriptRunnable struct {
ScriptID uint64 `json:"scriptID,string"`
Name string `json:"name"`
Events map[string][]string `json:"events"`
Source string `json:"source,omitempty"`
Async bool `json:"async"`
}
AutomationScript struct {
scripts automationScriptService
runner automationScriptRunner
ac automationScriptAccessController
}
automationScriptService interface {
FindByID(context.Context, uint64) (*automation.Script, error)
Find(context.Context, automation.ScriptFilter) (automation.ScriptSet, automation.ScriptFilter, error)
Create(context.Context, *automation.Script) error
Update(context.Context, *automation.Script) error
Delete(context.Context, uint64) error
}
automationScriptRunner interface {
RecordScriptTester(context.Context, string, interface{}) error
}
automationScriptAccessController interface {
CanGrant(context.Context) bool
CanUpdateAutomationScript(context.Context, *automation.Script) bool
CanDeleteAutomationScript(context.Context, *automation.Script) bool
}
)
func (AutomationScript) New() *AutomationScript {
return &AutomationScript{
scripts: service.DefaultAutomationScriptManager,
runner: service.DefaultAutomationRunner,
ac: service.DefaultAccessControl,
}
}
func (ctrl AutomationScript) List(ctx context.Context, r *request.AutomationScriptList) (interface{}, error) {
set, filter, err := ctrl.scripts.Find(ctx, automation.ScriptFilter{
Query: r.Query,
Resource: r.Resource,
IncDeleted: false,
PageFilter: rh.Paging(r.Page, r.PerPage),
})
return ctrl.makeFilterPayload(ctx, set, filter, err)
}
func (ctrl AutomationScript) Create(ctx context.Context, r *request.AutomationScriptCreate) (interface{}, error) {
var (
script = &automation.Script{
Name: r.Name,
SourceRef: r.SourceRef,
Source: r.Source,
Async: r.Async,
RunAs: r.RunAs,
Timeout: r.Timeout,
Critical: r.Critical,
Enabled: r.Enabled,
}
)
script.AddTrigger(automation.STMS_FRESH, r.Triggers...)
return ctrl.makePayload(ctx, script, ctrl.scripts.Create(ctx, script))
}
func (ctrl AutomationScript) Read(ctx context.Context, r *request.AutomationScriptRead) (interface{}, error) {
script, err := ctrl.scripts.FindByID(ctx, r.ScriptID)
return ctrl.makePayload(ctx, script, err)
}
func (ctrl AutomationScript) Update(ctx context.Context, r *request.AutomationScriptUpdate) (interface{}, error) {
mod := &automation.Script{
ID: r.ScriptID,
Name: r.Name,
SourceRef: r.SourceRef,
Source: r.Source,
Async: r.Async,
RunAs: r.RunAs,
Timeout: r.Timeout,
Critical: r.Critical,
Enabled: r.Enabled,
}
mod.AddTrigger(automation.STMS_UPDATE, r.Triggers...)
return ctrl.makePayload(ctx, mod, ctrl.scripts.Update(ctx, mod))
}
func (ctrl AutomationScript) Delete(ctx context.Context, r *request.AutomationScriptDelete) (interface{}, error) {
return resputil.OK(), ctrl.scripts.Delete(ctx, r.ScriptID)
}
func (ctrl AutomationScript) Test(ctx context.Context, r *request.AutomationScriptTest) (interface{}, error) {
var (
err error
)
if err = ctrl.runner.RecordScriptTester(ctx, r.Source, r.Payload); err != nil {
return nil, err
}
return r.Payload, err
}
func (ctrl AutomationScript) makePayload(ctx context.Context, s *automation.Script, err error) (*automationScriptPayload, error) {
if err != nil || s == nil {
return nil, err
}
return &automationScriptPayload{
Script: s,
CanGrant: ctrl.ac.CanGrant(ctx),
CanUpdate: ctrl.ac.CanUpdateAutomationScript(ctx, s),
CanDelete: ctrl.ac.CanDeleteAutomationScript(ctx, s),
CanSetRunner: ctrl.ac.CanGrant(ctx),
CanSetAsCritical: true,
CanSetAsAsync: true,
}, nil
}
func (ctrl AutomationScript) makeFilterPayload(ctx context.Context, nn automation.ScriptSet, f automation.ScriptFilter, err error) (*automationScriptSetPayload, error) {
if err != nil {
return nil, err
}
modp := &automationScriptSetPayload{Filter: f, Set: make([]*automationScriptPayload, len(nn))}
for i := range nn {
modp.Set[i], _ = ctrl.makePayload(ctx, nn[i], nil)
}
return modp, nil
}

View File

@@ -0,0 +1,166 @@
package rest
import (
"context"
"github.com/pkg/errors"
"github.com/titpetric/factory/resputil"
"github.com/cortezaproject/corteza-server/pkg/automation"
"github.com/cortezaproject/corteza-server/pkg/rh"
"github.com/cortezaproject/corteza-server/system/internal/service"
"github.com/cortezaproject/corteza-server/system/rest/request"
)
var _ = errors.Wrap
type (
automationTriggerPayload struct {
*automation.Trigger
CanRun bool `json:"canRun"`
}
automationTriggerSetPayload struct {
Filter automation.TriggerFilter `json:"filter"`
Set []*automationTriggerPayload `json:"set"`
}
AutomationTrigger struct {
triggers automationTriggerService
scripts automationScriptFinderService
ac automationTriggerAccessController
}
automationTriggerService interface {
FindByID(context.Context, uint64) (*automation.Trigger, error)
Find(context.Context, automation.TriggerFilter) (automation.TriggerSet, automation.TriggerFilter, error)
Create(context.Context, *automation.Script, *automation.Trigger) error
Update(context.Context, *automation.Script, *automation.Trigger) error
Delete(context.Context, *automation.Script, *automation.Trigger) error
}
automationScriptFinderService interface {
FindByID(context.Context, uint64) (*automation.Script, error)
}
automationTriggerAccessController interface {
CanGrant(context.Context) bool
CanRunAutomationTrigger(context.Context, *automation.Trigger) bool
}
)
func (AutomationTrigger) New() *AutomationTrigger {
return &AutomationTrigger{
scripts: service.DefaultAutomationScriptManager,
triggers: service.DefaultAutomationTriggerManager,
ac: service.DefaultAccessControl,
}
}
func (ctrl AutomationTrigger) List(ctx context.Context, r *request.AutomationTriggerList) (interface{}, error) {
set, filter, err := ctrl.triggers.Find(ctx, automation.TriggerFilter{
Resource: r.Resource,
Event: r.Event,
ScriptID: r.ScriptID,
IncDeleted: false,
PageFilter: rh.Paging(r.Page, r.PerPage),
})
return ctrl.makeFilterPayload(ctx, set, filter, err)
}
func (ctrl AutomationTrigger) Create(ctx context.Context, r *request.AutomationTriggerCreate) (interface{}, error) {
s, _, err := ctrl.loadCombo(ctx, r.ScriptID, 0)
if err != nil {
return nil, errors.Wrap(err, "can not create trigger")
}
var (
t = &automation.Trigger{
Event: r.Event,
Resource: r.Resource,
Condition: r.Condition,
ScriptID: s.ID,
Enabled: r.Enabled,
}
)
return ctrl.makePayload(ctx, t, ctrl.triggers.Create(ctx, s, t))
}
func (ctrl AutomationTrigger) Read(ctx context.Context, r *request.AutomationTriggerRead) (interface{}, error) {
_, t, err := ctrl.loadCombo(ctx, r.ScriptID, 0)
if err != nil {
return nil, errors.Wrap(err, "can not read trigger")
}
return ctrl.makePayload(ctx, t, err)
}
func (ctrl AutomationTrigger) Update(ctx context.Context, r *request.AutomationTriggerUpdate) (interface{}, error) {
s, t, err := ctrl.loadCombo(ctx, r.ScriptID, r.TriggerID)
if err != nil {
return nil, errors.Wrap(err, "can not update trigger")
}
t.Event = r.Event
t.Resource = r.Resource
t.Condition = r.Condition
t.ScriptID = r.ScriptID
t.Enabled = r.Enabled
return ctrl.makePayload(ctx, t, ctrl.triggers.Update(ctx, s, t))
}
func (ctrl AutomationTrigger) Delete(ctx context.Context, r *request.AutomationTriggerDelete) (interface{}, error) {
s, t, err := ctrl.loadCombo(ctx, r.ScriptID, r.TriggerID)
if err != nil {
return nil, errors.Wrap(err, "can not update trigger")
}
return resputil.OK(), ctrl.triggers.Delete(ctx, s, t)
}
func (ctrl AutomationTrigger) loadCombo(ctx context.Context, scriptID, triggerID uint64) (s *automation.Script, t *automation.Trigger, err error) {
if triggerID > 0 {
t, err = ctrl.triggers.FindByID(ctx, triggerID)
return
}
if scriptID > 0 {
s, err = ctrl.scripts.FindByID(ctx, scriptID)
return
}
return
}
func (ctrl AutomationTrigger) makePayload(ctx context.Context, t *automation.Trigger, err error) (*automationTriggerPayload, error) {
if err != nil || t == nil {
return nil, err
}
return &automationTriggerPayload{
Trigger: t,
CanRun: ctrl.ac.CanRunAutomationTrigger(ctx, t),
}, nil
}
func (ctrl AutomationTrigger) makeFilterPayload(ctx context.Context, nn automation.TriggerSet, f automation.TriggerFilter, err error) (*automationTriggerSetPayload, error) {
if err != nil {
return nil, err
}
modp := &automationTriggerSetPayload{Filter: f, Set: make([]*automationTriggerPayload, len(nn))}
for i := range nn {
modp.Set[i], _ = ctrl.makePayload(ctx, nn[i], nil)
}
return modp, nil
}

View File

@@ -0,0 +1,185 @@
package handlers
/*
Hello! This file is auto-generated from `docs/src/spec.json`.
For development:
In order to update the generated files, edit this file under the location,
add your struct fields, imports, API definitions and whatever you want, and:
1. run [spec](https://github.com/titpetric/spec) in the same folder,
2. run `./_gen.php` in this folder.
You may edit `automation_script.go`, `automation_script.util.go` or `automation_script_test.go` to
implement your API calls, helper functions and tests. The file `automation_script.go`
is only generated the first time, and will not be overwritten if it exists.
*/
import (
"context"
"net/http"
"github.com/go-chi/chi"
"github.com/titpetric/factory/resputil"
"github.com/cortezaproject/corteza-server/pkg/logger"
"github.com/cortezaproject/corteza-server/system/rest/request"
)
// Internal API interface
type AutomationScriptAPI interface {
List(context.Context, *request.AutomationScriptList) (interface{}, error)
Create(context.Context, *request.AutomationScriptCreate) (interface{}, error)
Read(context.Context, *request.AutomationScriptRead) (interface{}, error)
Update(context.Context, *request.AutomationScriptUpdate) (interface{}, error)
Delete(context.Context, *request.AutomationScriptDelete) (interface{}, error)
Test(context.Context, *request.AutomationScriptTest) (interface{}, error)
}
// HTTP API interface
type AutomationScript struct {
List func(http.ResponseWriter, *http.Request)
Create func(http.ResponseWriter, *http.Request)
Read func(http.ResponseWriter, *http.Request)
Update func(http.ResponseWriter, *http.Request)
Delete func(http.ResponseWriter, *http.Request)
Test func(http.ResponseWriter, *http.Request)
}
func NewAutomationScript(h AutomationScriptAPI) *AutomationScript {
return &AutomationScript{
List: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewAutomationScriptList()
if err := params.Fill(r); err != nil {
logger.LogParamError("AutomationScript.List", r, err)
resputil.JSON(w, err)
return
}
value, err := h.List(r.Context(), params)
if err != nil {
logger.LogControllerError("AutomationScript.List", r, err, params.Auditable())
resputil.JSON(w, err)
return
}
logger.LogControllerCall("AutomationScript.List", r, params.Auditable())
if !serveHTTP(value, w, r) {
resputil.JSON(w, value)
}
},
Create: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewAutomationScriptCreate()
if err := params.Fill(r); err != nil {
logger.LogParamError("AutomationScript.Create", r, err)
resputil.JSON(w, err)
return
}
value, err := h.Create(r.Context(), params)
if err != nil {
logger.LogControllerError("AutomationScript.Create", r, err, params.Auditable())
resputil.JSON(w, err)
return
}
logger.LogControllerCall("AutomationScript.Create", r, params.Auditable())
if !serveHTTP(value, w, r) {
resputil.JSON(w, value)
}
},
Read: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewAutomationScriptRead()
if err := params.Fill(r); err != nil {
logger.LogParamError("AutomationScript.Read", r, err)
resputil.JSON(w, err)
return
}
value, err := h.Read(r.Context(), params)
if err != nil {
logger.LogControllerError("AutomationScript.Read", r, err, params.Auditable())
resputil.JSON(w, err)
return
}
logger.LogControllerCall("AutomationScript.Read", r, params.Auditable())
if !serveHTTP(value, w, r) {
resputil.JSON(w, value)
}
},
Update: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewAutomationScriptUpdate()
if err := params.Fill(r); err != nil {
logger.LogParamError("AutomationScript.Update", r, err)
resputil.JSON(w, err)
return
}
value, err := h.Update(r.Context(), params)
if err != nil {
logger.LogControllerError("AutomationScript.Update", r, err, params.Auditable())
resputil.JSON(w, err)
return
}
logger.LogControllerCall("AutomationScript.Update", r, params.Auditable())
if !serveHTTP(value, w, r) {
resputil.JSON(w, value)
}
},
Delete: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewAutomationScriptDelete()
if err := params.Fill(r); err != nil {
logger.LogParamError("AutomationScript.Delete", r, err)
resputil.JSON(w, err)
return
}
value, err := h.Delete(r.Context(), params)
if err != nil {
logger.LogControllerError("AutomationScript.Delete", r, err, params.Auditable())
resputil.JSON(w, err)
return
}
logger.LogControllerCall("AutomationScript.Delete", r, params.Auditable())
if !serveHTTP(value, w, r) {
resputil.JSON(w, value)
}
},
Test: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewAutomationScriptTest()
if err := params.Fill(r); err != nil {
logger.LogParamError("AutomationScript.Test", r, err)
resputil.JSON(w, err)
return
}
value, err := h.Test(r.Context(), params)
if err != nil {
logger.LogControllerError("AutomationScript.Test", r, err, params.Auditable())
resputil.JSON(w, err)
return
}
logger.LogControllerCall("AutomationScript.Test", r, params.Auditable())
if !serveHTTP(value, w, r) {
resputil.JSON(w, value)
}
},
}
}
func (h AutomationScript) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) {
r.Group(func(r chi.Router) {
r.Use(middlewares...)
r.Get("/automation/script/", h.List)
r.Post("/automation/script/", h.Create)
r.Get("/automation/script/{scriptID}", h.Read)
r.Post("/automation/script/{scriptID}", h.Update)
r.Delete("/automation/script/{scriptID}", h.Delete)
r.Post("/automation/script/test", h.Test)
})
}

View File

@@ -0,0 +1,162 @@
package handlers
/*
Hello! This file is auto-generated from `docs/src/spec.json`.
For development:
In order to update the generated files, edit this file under the location,
add your struct fields, imports, API definitions and whatever you want, and:
1. run [spec](https://github.com/titpetric/spec) in the same folder,
2. run `./_gen.php` in this folder.
You may edit `automation_trigger.go`, `automation_trigger.util.go` or `automation_trigger_test.go` to
implement your API calls, helper functions and tests. The file `automation_trigger.go`
is only generated the first time, and will not be overwritten if it exists.
*/
import (
"context"
"net/http"
"github.com/go-chi/chi"
"github.com/titpetric/factory/resputil"
"github.com/cortezaproject/corteza-server/pkg/logger"
"github.com/cortezaproject/corteza-server/system/rest/request"
)
// Internal API interface
type AutomationTriggerAPI interface {
List(context.Context, *request.AutomationTriggerList) (interface{}, error)
Create(context.Context, *request.AutomationTriggerCreate) (interface{}, error)
Read(context.Context, *request.AutomationTriggerRead) (interface{}, error)
Update(context.Context, *request.AutomationTriggerUpdate) (interface{}, error)
Delete(context.Context, *request.AutomationTriggerDelete) (interface{}, error)
}
// HTTP API interface
type AutomationTrigger struct {
List func(http.ResponseWriter, *http.Request)
Create func(http.ResponseWriter, *http.Request)
Read func(http.ResponseWriter, *http.Request)
Update func(http.ResponseWriter, *http.Request)
Delete func(http.ResponseWriter, *http.Request)
}
func NewAutomationTrigger(h AutomationTriggerAPI) *AutomationTrigger {
return &AutomationTrigger{
List: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewAutomationTriggerList()
if err := params.Fill(r); err != nil {
logger.LogParamError("AutomationTrigger.List", r, err)
resputil.JSON(w, err)
return
}
value, err := h.List(r.Context(), params)
if err != nil {
logger.LogControllerError("AutomationTrigger.List", r, err, params.Auditable())
resputil.JSON(w, err)
return
}
logger.LogControllerCall("AutomationTrigger.List", r, params.Auditable())
if !serveHTTP(value, w, r) {
resputil.JSON(w, value)
}
},
Create: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewAutomationTriggerCreate()
if err := params.Fill(r); err != nil {
logger.LogParamError("AutomationTrigger.Create", r, err)
resputil.JSON(w, err)
return
}
value, err := h.Create(r.Context(), params)
if err != nil {
logger.LogControllerError("AutomationTrigger.Create", r, err, params.Auditable())
resputil.JSON(w, err)
return
}
logger.LogControllerCall("AutomationTrigger.Create", r, params.Auditable())
if !serveHTTP(value, w, r) {
resputil.JSON(w, value)
}
},
Read: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewAutomationTriggerRead()
if err := params.Fill(r); err != nil {
logger.LogParamError("AutomationTrigger.Read", r, err)
resputil.JSON(w, err)
return
}
value, err := h.Read(r.Context(), params)
if err != nil {
logger.LogControllerError("AutomationTrigger.Read", r, err, params.Auditable())
resputil.JSON(w, err)
return
}
logger.LogControllerCall("AutomationTrigger.Read", r, params.Auditable())
if !serveHTTP(value, w, r) {
resputil.JSON(w, value)
}
},
Update: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewAutomationTriggerUpdate()
if err := params.Fill(r); err != nil {
logger.LogParamError("AutomationTrigger.Update", r, err)
resputil.JSON(w, err)
return
}
value, err := h.Update(r.Context(), params)
if err != nil {
logger.LogControllerError("AutomationTrigger.Update", r, err, params.Auditable())
resputil.JSON(w, err)
return
}
logger.LogControllerCall("AutomationTrigger.Update", r, params.Auditable())
if !serveHTTP(value, w, r) {
resputil.JSON(w, value)
}
},
Delete: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewAutomationTriggerDelete()
if err := params.Fill(r); err != nil {
logger.LogParamError("AutomationTrigger.Delete", r, err)
resputil.JSON(w, err)
return
}
value, err := h.Delete(r.Context(), params)
if err != nil {
logger.LogControllerError("AutomationTrigger.Delete", r, err, params.Auditable())
resputil.JSON(w, err)
return
}
logger.LogControllerCall("AutomationTrigger.Delete", r, params.Auditable())
if !serveHTTP(value, w, r) {
resputil.JSON(w, value)
}
},
}
}
func (h AutomationTrigger) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) {
r.Group(func(r chi.Router) {
r.Use(middlewares...)
r.Get("/automation/script/{scriptID}/trigger/", h.List)
r.Post("/automation/script/{scriptID}/trigger/", h.Create)
r.Get("/automation/script/{scriptID}/trigger/{triggerID}", h.Read)
r.Post("/automation/script/{scriptID}/trigger/{triggerID}", h.Update)
r.Delete("/automation/script/{scriptID}/trigger/{triggerID}", h.Delete)
})
}

View File

@@ -0,0 +1,449 @@
package request
/*
Hello! This file is auto-generated from `docs/src/spec.json`.
For development:
In order to update the generated files, edit this file under the location,
add your struct fields, imports, API definitions and whatever you want, and:
1. run [spec](https://github.com/titpetric/spec) in the same folder,
2. run `./_gen.php` in this folder.
You may edit `automation_script.go`, `automation_script.util.go` or `automation_script_test.go` to
implement your API calls, helper functions and tests. The file `automation_script.go`
is only generated the first time, and will not be overwritten if it exists.
*/
import (
"io"
"strings"
"encoding/json"
"mime/multipart"
"net/http"
"github.com/go-chi/chi"
"github.com/pkg/errors"
"github.com/cortezaproject/corteza-server/pkg/automation"
)
var _ = chi.URLParam
var _ = multipart.FileHeader{}
// AutomationScript list request parameters
type AutomationScriptList struct {
Query string
Resource string
IncDeleted bool
Page uint
PerPage uint
}
func NewAutomationScriptList() *AutomationScriptList {
return &AutomationScriptList{}
}
func (r AutomationScriptList) Auditable() map[string]interface{} {
var out = map[string]interface{}{}
out["query"] = r.Query
out["resource"] = r.Resource
out["incDeleted"] = r.IncDeleted
out["page"] = r.Page
out["perPage"] = r.PerPage
return out
}
func (r *AutomationScriptList) Fill(req *http.Request) (err error) {
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(req.Body).Decode(r)
switch {
case err == io.EOF:
err = nil
case err != nil:
return errors.Wrap(err, "error parsing http request body")
}
}
if err = req.ParseForm(); err != nil {
return err
}
get := map[string]string{}
post := map[string]string{}
urlQuery := req.URL.Query()
for name, param := range urlQuery {
get[name] = string(param[0])
}
postVars := req.Form
for name, param := range postVars {
post[name] = string(param[0])
}
if val, ok := get["query"]; ok {
r.Query = val
}
if val, ok := get["resource"]; ok {
r.Resource = val
}
if val, ok := get["incDeleted"]; ok {
r.IncDeleted = parseBool(val)
}
if val, ok := get["page"]; ok {
r.Page = parseUint(val)
}
if val, ok := get["perPage"]; ok {
r.PerPage = parseUint(val)
}
return err
}
var _ RequestFiller = NewAutomationScriptList()
// AutomationScript create request parameters
type AutomationScriptCreate struct {
Name string
SourceRef string
Source string
RunAs uint64 `json:",string"`
Timeout uint
Critical bool
Async bool
Enabled bool
Triggers automation.TriggerSet
}
func NewAutomationScriptCreate() *AutomationScriptCreate {
return &AutomationScriptCreate{}
}
func (r AutomationScriptCreate) Auditable() map[string]interface{} {
var out = map[string]interface{}{}
out["name"] = r.Name
out["sourceRef"] = r.SourceRef
out["source"] = r.Source
out["runAs"] = r.RunAs
out["timeout"] = r.Timeout
out["critical"] = r.Critical
out["async"] = r.Async
out["enabled"] = r.Enabled
out["triggers"] = r.Triggers
return out
}
func (r *AutomationScriptCreate) Fill(req *http.Request) (err error) {
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(req.Body).Decode(r)
switch {
case err == io.EOF:
err = nil
case err != nil:
return errors.Wrap(err, "error parsing http request body")
}
}
if err = req.ParseForm(); err != nil {
return err
}
get := map[string]string{}
post := map[string]string{}
urlQuery := req.URL.Query()
for name, param := range urlQuery {
get[name] = string(param[0])
}
postVars := req.Form
for name, param := range postVars {
post[name] = string(param[0])
}
if val, ok := post["name"]; ok {
r.Name = val
}
if val, ok := post["sourceRef"]; ok {
r.SourceRef = val
}
if val, ok := post["source"]; ok {
r.Source = val
}
if val, ok := post["runAs"]; ok {
r.RunAs = parseUInt64(val)
}
if val, ok := post["timeout"]; ok {
r.Timeout = parseUint(val)
}
if val, ok := post["critical"]; ok {
r.Critical = parseBool(val)
}
if val, ok := post["async"]; ok {
r.Async = parseBool(val)
}
if val, ok := post["enabled"]; ok {
r.Enabled = parseBool(val)
}
return err
}
var _ RequestFiller = NewAutomationScriptCreate()
// AutomationScript read request parameters
type AutomationScriptRead struct {
ScriptID uint64 `json:",string"`
}
func NewAutomationScriptRead() *AutomationScriptRead {
return &AutomationScriptRead{}
}
func (r AutomationScriptRead) Auditable() map[string]interface{} {
var out = map[string]interface{}{}
out["scriptID"] = r.ScriptID
return out
}
func (r *AutomationScriptRead) Fill(req *http.Request) (err error) {
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(req.Body).Decode(r)
switch {
case err == io.EOF:
err = nil
case err != nil:
return errors.Wrap(err, "error parsing http request body")
}
}
if err = req.ParseForm(); err != nil {
return err
}
get := map[string]string{}
post := map[string]string{}
urlQuery := req.URL.Query()
for name, param := range urlQuery {
get[name] = string(param[0])
}
postVars := req.Form
for name, param := range postVars {
post[name] = string(param[0])
}
r.ScriptID = parseUInt64(chi.URLParam(req, "scriptID"))
return err
}
var _ RequestFiller = NewAutomationScriptRead()
// AutomationScript update request parameters
type AutomationScriptUpdate struct {
ScriptID uint64 `json:",string"`
Name string
SourceRef string
Source string
RunAs uint64 `json:",string"`
Timeout uint
Critical bool
Async bool
Enabled bool
Triggers automation.TriggerSet
}
func NewAutomationScriptUpdate() *AutomationScriptUpdate {
return &AutomationScriptUpdate{}
}
func (r AutomationScriptUpdate) Auditable() map[string]interface{} {
var out = map[string]interface{}{}
out["scriptID"] = r.ScriptID
out["name"] = r.Name
out["sourceRef"] = r.SourceRef
out["source"] = r.Source
out["runAs"] = r.RunAs
out["timeout"] = r.Timeout
out["critical"] = r.Critical
out["async"] = r.Async
out["enabled"] = r.Enabled
out["triggers"] = r.Triggers
return out
}
func (r *AutomationScriptUpdate) Fill(req *http.Request) (err error) {
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(req.Body).Decode(r)
switch {
case err == io.EOF:
err = nil
case err != nil:
return errors.Wrap(err, "error parsing http request body")
}
}
if err = req.ParseForm(); err != nil {
return err
}
get := map[string]string{}
post := map[string]string{}
urlQuery := req.URL.Query()
for name, param := range urlQuery {
get[name] = string(param[0])
}
postVars := req.Form
for name, param := range postVars {
post[name] = string(param[0])
}
r.ScriptID = parseUInt64(chi.URLParam(req, "scriptID"))
if val, ok := post["name"]; ok {
r.Name = val
}
if val, ok := post["sourceRef"]; ok {
r.SourceRef = val
}
if val, ok := post["source"]; ok {
r.Source = val
}
if val, ok := post["runAs"]; ok {
r.RunAs = parseUInt64(val)
}
if val, ok := post["timeout"]; ok {
r.Timeout = parseUint(val)
}
if val, ok := post["critical"]; ok {
r.Critical = parseBool(val)
}
if val, ok := post["async"]; ok {
r.Async = parseBool(val)
}
if val, ok := post["enabled"]; ok {
r.Enabled = parseBool(val)
}
return err
}
var _ RequestFiller = NewAutomationScriptUpdate()
// AutomationScript delete request parameters
type AutomationScriptDelete struct {
ScriptID uint64 `json:",string"`
}
func NewAutomationScriptDelete() *AutomationScriptDelete {
return &AutomationScriptDelete{}
}
func (r AutomationScriptDelete) Auditable() map[string]interface{} {
var out = map[string]interface{}{}
out["scriptID"] = r.ScriptID
return out
}
func (r *AutomationScriptDelete) Fill(req *http.Request) (err error) {
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(req.Body).Decode(r)
switch {
case err == io.EOF:
err = nil
case err != nil:
return errors.Wrap(err, "error parsing http request body")
}
}
if err = req.ParseForm(); err != nil {
return err
}
get := map[string]string{}
post := map[string]string{}
urlQuery := req.URL.Query()
for name, param := range urlQuery {
get[name] = string(param[0])
}
postVars := req.Form
for name, param := range postVars {
post[name] = string(param[0])
}
r.ScriptID = parseUInt64(chi.URLParam(req, "scriptID"))
return err
}
var _ RequestFiller = NewAutomationScriptDelete()
// AutomationScript test request parameters
type AutomationScriptTest struct {
Source string
Payload json.RawMessage
}
func NewAutomationScriptTest() *AutomationScriptTest {
return &AutomationScriptTest{}
}
func (r AutomationScriptTest) Auditable() map[string]interface{} {
var out = map[string]interface{}{}
out["source"] = r.Source
out["payload"] = r.Payload
return out
}
func (r *AutomationScriptTest) Fill(req *http.Request) (err error) {
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(req.Body).Decode(r)
switch {
case err == io.EOF:
err = nil
case err != nil:
return errors.Wrap(err, "error parsing http request body")
}
}
if err = req.ParseForm(); err != nil {
return err
}
get := map[string]string{}
post := map[string]string{}
urlQuery := req.URL.Query()
for name, param := range urlQuery {
get[name] = string(param[0])
}
postVars := req.Form
for name, param := range postVars {
post[name] = string(param[0])
}
if val, ok := post["source"]; ok {
r.Source = val
}
if val, ok := post["payload"]; ok {
r.Payload = json.RawMessage(val)
}
return err
}
var _ RequestFiller = NewAutomationScriptTest()

View File

@@ -0,0 +1,360 @@
package request
/*
Hello! This file is auto-generated from `docs/src/spec.json`.
For development:
In order to update the generated files, edit this file under the location,
add your struct fields, imports, API definitions and whatever you want, and:
1. run [spec](https://github.com/titpetric/spec) in the same folder,
2. run `./_gen.php` in this folder.
You may edit `automation_trigger.go`, `automation_trigger.util.go` or `automation_trigger_test.go` to
implement your API calls, helper functions and tests. The file `automation_trigger.go`
is only generated the first time, and will not be overwritten if it exists.
*/
import (
"io"
"strings"
"encoding/json"
"mime/multipart"
"net/http"
"github.com/go-chi/chi"
"github.com/pkg/errors"
)
var _ = chi.URLParam
var _ = multipart.FileHeader{}
// AutomationTrigger list request parameters
type AutomationTriggerList struct {
Resource string
Event string
IncDeleted bool
Page uint
PerPage uint
ScriptID uint64 `json:",string"`
}
func NewAutomationTriggerList() *AutomationTriggerList {
return &AutomationTriggerList{}
}
func (r AutomationTriggerList) Auditable() map[string]interface{} {
var out = map[string]interface{}{}
out["resource"] = r.Resource
out["event"] = r.Event
out["incDeleted"] = r.IncDeleted
out["page"] = r.Page
out["perPage"] = r.PerPage
out["scriptID"] = r.ScriptID
return out
}
func (r *AutomationTriggerList) Fill(req *http.Request) (err error) {
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(req.Body).Decode(r)
switch {
case err == io.EOF:
err = nil
case err != nil:
return errors.Wrap(err, "error parsing http request body")
}
}
if err = req.ParseForm(); err != nil {
return err
}
get := map[string]string{}
post := map[string]string{}
urlQuery := req.URL.Query()
for name, param := range urlQuery {
get[name] = string(param[0])
}
postVars := req.Form
for name, param := range postVars {
post[name] = string(param[0])
}
if val, ok := get["resource"]; ok {
r.Resource = val
}
if val, ok := get["event"]; ok {
r.Event = val
}
if val, ok := get["incDeleted"]; ok {
r.IncDeleted = parseBool(val)
}
if val, ok := get["page"]; ok {
r.Page = parseUint(val)
}
if val, ok := get["perPage"]; ok {
r.PerPage = parseUint(val)
}
r.ScriptID = parseUInt64(chi.URLParam(req, "scriptID"))
return err
}
var _ RequestFiller = NewAutomationTriggerList()
// AutomationTrigger create request parameters
type AutomationTriggerCreate struct {
Resource string
Event string
Condition string
Enabled bool
ScriptID uint64 `json:",string"`
}
func NewAutomationTriggerCreate() *AutomationTriggerCreate {
return &AutomationTriggerCreate{}
}
func (r AutomationTriggerCreate) Auditable() map[string]interface{} {
var out = map[string]interface{}{}
out["resource"] = r.Resource
out["event"] = r.Event
out["condition"] = r.Condition
out["enabled"] = r.Enabled
out["scriptID"] = r.ScriptID
return out
}
func (r *AutomationTriggerCreate) Fill(req *http.Request) (err error) {
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(req.Body).Decode(r)
switch {
case err == io.EOF:
err = nil
case err != nil:
return errors.Wrap(err, "error parsing http request body")
}
}
if err = req.ParseForm(); err != nil {
return err
}
get := map[string]string{}
post := map[string]string{}
urlQuery := req.URL.Query()
for name, param := range urlQuery {
get[name] = string(param[0])
}
postVars := req.Form
for name, param := range postVars {
post[name] = string(param[0])
}
if val, ok := post["resource"]; ok {
r.Resource = val
}
if val, ok := post["event"]; ok {
r.Event = val
}
if val, ok := post["condition"]; ok {
r.Condition = val
}
if val, ok := post["enabled"]; ok {
r.Enabled = parseBool(val)
}
r.ScriptID = parseUInt64(chi.URLParam(req, "scriptID"))
return err
}
var _ RequestFiller = NewAutomationTriggerCreate()
// AutomationTrigger read request parameters
type AutomationTriggerRead struct {
TriggerID uint64 `json:",string"`
ScriptID uint64 `json:",string"`
}
func NewAutomationTriggerRead() *AutomationTriggerRead {
return &AutomationTriggerRead{}
}
func (r AutomationTriggerRead) Auditable() map[string]interface{} {
var out = map[string]interface{}{}
out["triggerID"] = r.TriggerID
out["scriptID"] = r.ScriptID
return out
}
func (r *AutomationTriggerRead) Fill(req *http.Request) (err error) {
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(req.Body).Decode(r)
switch {
case err == io.EOF:
err = nil
case err != nil:
return errors.Wrap(err, "error parsing http request body")
}
}
if err = req.ParseForm(); err != nil {
return err
}
get := map[string]string{}
post := map[string]string{}
urlQuery := req.URL.Query()
for name, param := range urlQuery {
get[name] = string(param[0])
}
postVars := req.Form
for name, param := range postVars {
post[name] = string(param[0])
}
r.TriggerID = parseUInt64(chi.URLParam(req, "triggerID"))
r.ScriptID = parseUInt64(chi.URLParam(req, "scriptID"))
return err
}
var _ RequestFiller = NewAutomationTriggerRead()
// AutomationTrigger update request parameters
type AutomationTriggerUpdate struct {
TriggerID uint64 `json:",string"`
ScriptID uint64 `json:",string"`
Resource string
Event string
Condition string
Enabled bool
}
func NewAutomationTriggerUpdate() *AutomationTriggerUpdate {
return &AutomationTriggerUpdate{}
}
func (r AutomationTriggerUpdate) Auditable() map[string]interface{} {
var out = map[string]interface{}{}
out["triggerID"] = r.TriggerID
out["scriptID"] = r.ScriptID
out["resource"] = r.Resource
out["event"] = r.Event
out["condition"] = r.Condition
out["enabled"] = r.Enabled
return out
}
func (r *AutomationTriggerUpdate) Fill(req *http.Request) (err error) {
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(req.Body).Decode(r)
switch {
case err == io.EOF:
err = nil
case err != nil:
return errors.Wrap(err, "error parsing http request body")
}
}
if err = req.ParseForm(); err != nil {
return err
}
get := map[string]string{}
post := map[string]string{}
urlQuery := req.URL.Query()
for name, param := range urlQuery {
get[name] = string(param[0])
}
postVars := req.Form
for name, param := range postVars {
post[name] = string(param[0])
}
r.TriggerID = parseUInt64(chi.URLParam(req, "triggerID"))
r.ScriptID = parseUInt64(chi.URLParam(req, "scriptID"))
if val, ok := post["resource"]; ok {
r.Resource = val
}
if val, ok := post["event"]; ok {
r.Event = val
}
if val, ok := post["condition"]; ok {
r.Condition = val
}
if val, ok := post["enabled"]; ok {
r.Enabled = parseBool(val)
}
return err
}
var _ RequestFiller = NewAutomationTriggerUpdate()
// AutomationTrigger delete request parameters
type AutomationTriggerDelete struct {
TriggerID uint64 `json:",string"`
ScriptID uint64 `json:",string"`
}
func NewAutomationTriggerDelete() *AutomationTriggerDelete {
return &AutomationTriggerDelete{}
}
func (r AutomationTriggerDelete) Auditable() map[string]interface{} {
var out = map[string]interface{}{}
out["triggerID"] = r.TriggerID
out["scriptID"] = r.ScriptID
return out
}
func (r *AutomationTriggerDelete) Fill(req *http.Request) (err error) {
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(req.Body).Decode(r)
switch {
case err == io.EOF:
err = nil
case err != nil:
return errors.Wrap(err, "error parsing http request body")
}
}
if err = req.ParseForm(); err != nil {
return err
}
get := map[string]string{}
post := map[string]string{}
urlQuery := req.URL.Query()
for name, param := range urlQuery {
get[name] = string(param[0])
}
postVars := req.Form
for name, param := range postVars {
post[name] = string(param[0])
}
r.TriggerID = parseUInt64(chi.URLParam(req, "triggerID"))
r.ScriptID = parseUInt64(chi.URLParam(req, "scriptID"))
return err
}
var _ RequestFiller = NewAutomationTriggerDelete()

View File

@@ -25,5 +25,8 @@ func MountRoutes(r chi.Router) {
handlers.NewPermissions(Permissions{}.New()).MountRoutes(r)
handlers.NewApplication(Application{}.New()).MountRoutes(r)
handlers.NewSettings(Settings{}.New()).MountRoutes(r)
handlers.NewAutomationScript(AutomationScript{}.New()).MountRoutes(r)
handlers.NewAutomationTrigger(AutomationTrigger{}.New()).MountRoutes(r)
})
}