WIP new WebAdmin: event rules

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino
2024-02-01 20:32:43 +01:00
parent c85601146d
commit ad80d4e475
11 changed files with 1264 additions and 1014 deletions

View File

@@ -117,19 +117,19 @@ func isEventTriggerValid(trigger int) bool {
func getTriggerTypeAsString(trigger int) string {
switch trigger {
case EventTriggerFsEvent:
return "Filesystem event"
return util.I18nTriggerFsEvent
case EventTriggerProviderEvent:
return "Provider event"
return util.I18nTriggerProviderEvent
case EventTriggerIPBlocked:
return "IP blocked"
return util.I18nTriggerIPBlockedEvent
case EventTriggerCertificate:
return "Certificate renewal"
return util.I18nTriggerCertificateRenewEvent
case EventTriggerOnDemand:
return "On demand"
return util.I18nTriggerOnDemandEvent
case EventTriggerIDPLogin:
return "Identity Provider login"
return util.I18nTriggerIDPLoginEvent
default:
return "Schedule"
return util.I18nTriggerScheduleEvent
}
}
@@ -1212,17 +1212,26 @@ func (a *EventAction) getACopy() EventAction {
func (a *EventAction) validateAssociation(trigger int, fsEvents []string) error {
if a.Options.IsFailureAction {
if a.Options.ExecuteSync {
return util.NewValidationError("sync execution is not supported for failure actions")
return util.NewI18nError(
util.NewValidationError("sync execution is not supported for failure actions"),
util.I18nErrorEvSyncFailureActions,
)
}
}
if a.Options.ExecuteSync {
if trigger != EventTriggerFsEvent && trigger != EventTriggerIDPLogin {
return util.NewValidationError("sync execution is only supported for some filesystem events and Identity Provider logins")
return util.NewI18nError(
util.NewValidationError("sync execution is only supported for some filesystem events and Identity Provider logins"),
util.I18nErrorEvSyncUnsupported,
)
}
if trigger == EventTriggerFsEvent {
for _, ev := range fsEvents {
if !util.Contains(allowedSyncFsEvents, ev) {
return util.NewValidationError("sync execution is only supported for upload and pre-* events")
return util.NewI18nError(
util.NewValidationError("sync execution is only supported for upload and pre-* events"),
util.I18nErrorEvSyncUnsupportedFs,
)
}
}
}
@@ -1379,11 +1388,14 @@ func (c *EventConditions) getACopy() EventConditions {
func (c *EventConditions) validateSchedules() error {
if len(c.Schedules) == 0 {
return util.NewValidationError("at least one schedule is required")
return util.NewI18nError(
util.NewValidationError("at least one schedule is required"),
util.I18nErrorRuleScheduleRequired,
)
}
for _, schedule := range c.Schedules {
if err := schedule.validate(); err != nil {
return err
return util.NewI18nError(err, util.I18nErrorRuleScheduleInvalid)
}
}
return nil
@@ -1397,7 +1409,10 @@ func (c *EventConditions) validate(trigger int) error {
c.Options.ProviderObjects = nil
c.IDPLoginEvent = 0
if len(c.FsEvents) == 0 {
return util.NewValidationError("at least one filesystem event is required")
return util.NewI18nError(
util.NewValidationError("at least one filesystem event is required"),
util.I18nErrorRuleFsEventRequired,
)
}
for _, ev := range c.FsEvents {
if !util.Contains(SupportedFsEvents, ev) {
@@ -1414,7 +1429,10 @@ func (c *EventConditions) validate(trigger int) error {
c.Options.MaxFileSize = 0
c.IDPLoginEvent = 0
if len(c.ProviderEvents) == 0 {
return util.NewValidationError("at least one provider event is required")
return util.NewI18nError(
util.NewValidationError("at least one provider event is required"),
util.I18nErrorRuleProviderEventRequired,
)
}
for _, ev := range c.ProviderEvents {
if !util.Contains(SupportedProviderEvents, ev) {
@@ -1558,7 +1576,7 @@ func (r *EventRule) isStatusValid() bool {
func (r *EventRule) validate() error {
if r.Name == "" {
return util.NewValidationError("name is mandatory")
return util.NewI18nError(util.NewValidationError("name is mandatory"), util.I18nErrorNameRequired)
}
if !r.isStatusValid() {
return util.NewValidationError(fmt.Sprintf("invalid event rule status: %d", r.Status))
@@ -1570,7 +1588,7 @@ func (r *EventRule) validate() error {
return err
}
if len(r.Actions) == 0 {
return util.NewValidationError("at least one action is required")
return util.NewI18nError(util.NewValidationError("at least one action is required"), util.I18nErrorRuleActionRequired)
}
actionNames := make(map[string]bool)
actionOrders := make(map[int]bool)
@@ -1581,7 +1599,10 @@ func (r *EventRule) validate() error {
return util.NewValidationError(fmt.Sprintf("invalid action at position %d, name not specified", idx))
}
if actionNames[r.Actions[idx].Name] {
return util.NewValidationError(fmt.Sprintf("duplicated action %q", r.Actions[idx].Name))
return util.NewI18nError(
util.NewValidationError(fmt.Sprintf("duplicated action %q", r.Actions[idx].Name)),
util.I18nErrorRuleDuplicateActions,
)
}
if actionOrders[r.Actions[idx].Order] {
return util.NewValidationError(fmt.Sprintf("duplicated order %d for action %q",
@@ -1600,7 +1621,10 @@ func (r *EventRule) validate() error {
actionOrders[r.Actions[idx].Order] = true
}
if len(r.Actions) == failureActions {
return util.NewValidationError("at least a non-failure action is required")
return util.NewI18nError(
util.NewValidationError("at least a non-failure action is required"),
util.I18nErrorRuleFailureActionsOnly,
)
}
if !hasSyncAction {
return r.validateMandatorySyncActions()
@@ -1614,7 +1638,13 @@ func (r *EventRule) validateMandatorySyncActions() error {
}
for _, ev := range r.Conditions.FsEvents {
if util.Contains(mandatorySyncFsEvents, ev) {
return util.NewValidationError(fmt.Sprintf("event %q requires at least a sync action", ev))
return util.NewI18nError(
util.NewValidationError(fmt.Sprintf("event %q requires at least a sync action", ev)),
util.I18nErrorRuleSyncActionRequired,
util.I18nErrorArgs(map[string]any{
"val": ev,
}),
)
}
}
return nil

View File

@@ -1775,6 +1775,8 @@ func (s *httpdServer) setupWebAdminRoutes() {
s.handleWebUpdateEventActionPost)
router.With(s.checkPerm(dataprovider.PermAdminManageEventRules), verifyCSRFHeader).
Delete(webAdminEventActionPath+"/{name}", deleteEventAction)
router.With(s.checkPerm(dataprovider.PermAdminManageEventRules), compressor.Handler, s.refreshCookie).
Get(webAdminEventRulesPath+jsonAPISuffix, getAllRules)
router.With(s.checkPerm(dataprovider.PermAdminManageEventRules), s.refreshCookie).
Get(webAdminEventRulesPath, s.handleWebGetEventRules)
router.With(s.checkPerm(dataprovider.PermAdminManageEventRules), s.refreshCookie).

View File

@@ -98,7 +98,6 @@ const (
templateMaintenance = "maintenance.html"
templateMFA = "mfa.html"
templateSetup = "adminsetup.html"
pageEventRulesTitle = "Event rules"
defaultQueryLimit = 1000
inversePatternType = "inverse"
)
@@ -153,11 +152,6 @@ type basePage struct {
Branding UIBranding
}
type eventRulesPage struct {
basePage
Rules []dataprovider.EventRule
}
type statusPage struct {
basePage
Status *ServicesStatus
@@ -312,7 +306,7 @@ type eventRulePage struct {
Protocols []string
ProviderEvents []string
ProviderObjects []string
Error string
Error *util.I18nError
Mode genericPageMode
IsShared bool
}
@@ -1105,19 +1099,19 @@ func (s *httpdServer) renderEventActionPage(w http.ResponseWriter, r *http.Reque
}
func (s *httpdServer) renderEventRulePage(w http.ResponseWriter, r *http.Request, rule dataprovider.EventRule,
mode genericPageMode, error string,
mode genericPageMode, err error,
) {
actions, err := s.getWebEventActions(w, r, defaultQueryLimit, true)
if err != nil {
actions, errActions := s.getWebEventActions(w, r, defaultQueryLimit, true)
if errActions != nil {
return
}
var title, currentURL string
switch mode {
case genericPageModeAdd:
title = "Add new event rules"
title = util.I18nAddRuleTitle
currentURL = webAdminEventRulePath
case genericPageModeUpdate:
title = "Update event rules"
title = util.I18nUpdateRuleTitle
currentURL = fmt.Sprintf("%v/%v", webAdminEventRulePath, url.PathEscape(rule.Name))
}
@@ -1130,7 +1124,7 @@ func (s *httpdServer) renderEventRulePage(w http.ResponseWriter, r *http.Request
Protocols: dataprovider.SupportedRuleConditionProtocols,
ProviderEvents: dataprovider.SupportedProviderEvents,
ProviderObjects: dataprovider.SupporteRuleConditionProviderObjects,
Error: error,
Error: getI18nError(err),
Mode: mode,
IsShared: s.isShared > 0,
}
@@ -2420,74 +2414,66 @@ func getIDPLoginEventFromPostField(r *http.Request) int {
func getEventRuleConditionsFromPostFields(r *http.Request) (dataprovider.EventConditions, error) {
var schedules []dataprovider.Schedule
var names, groupNames, roleNames, fsPaths []dataprovider.ConditionPattern
for k := range r.Form {
if strings.HasPrefix(k, "schedule_hour") {
hour := strings.TrimSpace(r.Form.Get(k))
if hour != "" {
idx := strings.TrimPrefix(k, "schedule_hour")
dayOfWeek := strings.TrimSpace(r.Form.Get(fmt.Sprintf("schedule_day_of_week%s", idx)))
dayOfMonth := strings.TrimSpace(r.Form.Get(fmt.Sprintf("schedule_day_of_month%s", idx)))
month := strings.TrimSpace(r.Form.Get(fmt.Sprintf("schedule_month%s", idx)))
schedules = append(schedules, dataprovider.Schedule{
Hours: hour,
DayOfWeek: dayOfWeek,
DayOfMonth: dayOfMonth,
Month: month,
})
}
}
if strings.HasPrefix(k, "name_pattern") {
pattern := strings.TrimSpace(r.Form.Get(k))
if pattern != "" {
idx := strings.TrimPrefix(k, "name_pattern")
patternType := r.Form.Get(fmt.Sprintf("type_name_pattern%s", idx))
names = append(names, dataprovider.ConditionPattern{
Pattern: pattern,
InverseMatch: patternType == inversePatternType,
})
}
}
if strings.HasPrefix(k, "group_name_pattern") {
pattern := strings.TrimSpace(r.Form.Get(k))
if pattern != "" {
idx := strings.TrimPrefix(k, "group_name_pattern")
patternType := r.Form.Get(fmt.Sprintf("type_group_name_pattern%s", idx))
groupNames = append(groupNames, dataprovider.ConditionPattern{
Pattern: pattern,
InverseMatch: patternType == inversePatternType,
})
}
}
if strings.HasPrefix(k, "role_name_pattern") {
pattern := strings.TrimSpace(r.Form.Get(k))
if pattern != "" {
idx := strings.TrimPrefix(k, "role_name_pattern")
patternType := r.Form.Get(fmt.Sprintf("type_role_name_pattern%s", idx))
roleNames = append(roleNames, dataprovider.ConditionPattern{
Pattern: pattern,
InverseMatch: patternType == inversePatternType,
})
}
}
if strings.HasPrefix(k, "fs_path_pattern") {
pattern := strings.TrimSpace(r.Form.Get(k))
if pattern != "" {
idx := strings.TrimPrefix(k, "fs_path_pattern")
patternType := r.Form.Get(fmt.Sprintf("type_fs_path_pattern%s", idx))
fsPaths = append(fsPaths, dataprovider.ConditionPattern{
Pattern: pattern,
InverseMatch: patternType == inversePatternType,
})
}
scheduleHours := r.Form["schedule_hour"]
scheduleDayOfWeeks := r.Form["schedule_day_of_week"]
scheduleDayOfMonths := r.Form["schedule_day_of_month"]
scheduleMonths := r.Form["schedule_month"]
for idx, hour := range scheduleHours {
if hour != "" {
schedules = append(schedules, dataprovider.Schedule{
Hours: hour,
DayOfWeek: scheduleDayOfWeeks[idx],
DayOfMonth: scheduleDayOfMonths[idx],
Month: scheduleMonths[idx],
})
}
}
for idx, name := range r.Form["name_pattern"] {
if name != "" {
names = append(names, dataprovider.ConditionPattern{
Pattern: name,
InverseMatch: r.Form["type_name_pattern"][idx] == inversePatternType,
})
}
}
for idx, name := range r.Form["group_name_pattern"] {
if name != "" {
groupNames = append(groupNames, dataprovider.ConditionPattern{
Pattern: name,
InverseMatch: r.Form["type_group_name_pattern"][idx] == inversePatternType,
})
}
}
for idx, name := range r.Form["role_name_pattern"] {
if name != "" {
roleNames = append(roleNames, dataprovider.ConditionPattern{
Pattern: name,
InverseMatch: r.Form["type_role_name_pattern"][idx] == inversePatternType,
})
}
}
for idx, name := range r.Form["fs_path_pattern"] {
if name != "" {
fsPaths = append(fsPaths, dataprovider.ConditionPattern{
Pattern: name,
InverseMatch: r.Form["type_fs_path_pattern"][idx] == inversePatternType,
})
}
}
minFileSize, err := util.ParseBytes(r.Form.Get("fs_min_size"))
if err != nil {
return dataprovider.EventConditions{}, fmt.Errorf("invalid min file size: %w", err)
return dataprovider.EventConditions{}, util.NewI18nError(fmt.Errorf("invalid min file size: %w", err), util.I18nErrorInvalidMinSize)
}
maxFileSize, err := util.ParseBytes(r.Form.Get("fs_max_size"))
if err != nil {
return dataprovider.EventConditions{}, fmt.Errorf("invalid max file size: %w", err)
return dataprovider.EventConditions{}, util.NewI18nError(fmt.Errorf("invalid max file size: %w", err), util.I18nErrorInvalidMaxSize)
}
conditions := dataprovider.EventConditions{
FsEvents: r.Form["fs_events"],
@@ -2511,38 +2497,86 @@ func getEventRuleConditionsFromPostFields(r *http.Request) (dataprovider.EventCo
func getEventRuleActionsFromPostFields(r *http.Request) ([]dataprovider.EventAction, error) {
var actions []dataprovider.EventAction
for k := range r.Form {
if strings.HasPrefix(k, "action_name") {
name := strings.TrimSpace(r.Form.Get(k))
if name != "" {
idx := strings.TrimPrefix(k, "action_name")
order, err := strconv.Atoi(r.Form.Get(fmt.Sprintf("action_order%s", idx)))
if err != nil {
return actions, fmt.Errorf("invalid order: %w", err)
}
options := r.Form[fmt.Sprintf("action_options%s", idx)]
actions = append(actions, dataprovider.EventAction{
BaseEventAction: dataprovider.BaseEventAction{
Name: name,
},
Order: order + 1,
Options: dataprovider.EventActionOptions{
IsFailureAction: util.Contains(options, "1"),
StopOnFailure: util.Contains(options, "2"),
ExecuteSync: util.Contains(options, "3"),
},
})
names := r.Form["action_name"]
orders := r.Form["action_order"]
for idx, name := range names {
if name != "" {
order, err := strconv.Atoi(orders[idx])
if err != nil {
return actions, fmt.Errorf("invalid order: %w", err)
}
options := r.Form["action_options"+strconv.Itoa(idx)]
actions = append(actions, dataprovider.EventAction{
BaseEventAction: dataprovider.BaseEventAction{
Name: name,
},
Order: order + 1,
Options: dataprovider.EventActionOptions{
IsFailureAction: util.Contains(options, "1"),
StopOnFailure: util.Contains(options, "2"),
ExecuteSync: util.Contains(options, "3"),
},
})
}
}
return actions, nil
}
func updateRepeaterFormRuleFields(r *http.Request) {
for k := range r.Form {
if hasPrefixAndSuffix(k, "schedules[", "][schedule_hour]") {
base, _ := strings.CutSuffix(k, "[schedule_hour]")
r.Form.Add("schedule_hour", strings.TrimSpace(r.Form.Get(k)))
r.Form.Add("schedule_day_of_week", strings.TrimSpace(r.Form.Get(base+"[schedule_day_of_week]")))
r.Form.Add("schedule_day_of_month", strings.TrimSpace(r.Form.Get(base+"[schedule_day_of_month]")))
r.Form.Add("schedule_month", strings.TrimSpace(r.Form.Get(base+"[schedule_month]")))
continue
}
if hasPrefixAndSuffix(k, "name_filters[", "][name_pattern]") {
base, _ := strings.CutSuffix(k, "[name_pattern]")
r.Form.Add("name_pattern", strings.TrimSpace(r.Form.Get(k)))
r.Form.Add("type_name_pattern", strings.TrimSpace(r.Form.Get(base+"[type_name_pattern]")))
continue
}
if hasPrefixAndSuffix(k, "group_name_filters[", "][group_name_pattern]") {
base, _ := strings.CutSuffix(k, "[group_name_pattern]")
r.Form.Add("group_name_pattern", strings.TrimSpace(r.Form.Get(k)))
r.Form.Add("type_group_name_pattern", strings.TrimSpace(r.Form.Get(base+"[type_group_name_pattern]")))
continue
}
if hasPrefixAndSuffix(k, "role_name_filters[", "][role_name_pattern]") {
base, _ := strings.CutSuffix(k, "[role_name_pattern]")
r.Form.Add("role_name_pattern", strings.TrimSpace(r.Form.Get(k)))
r.Form.Add("type_role_name_pattern", strings.TrimSpace(r.Form.Get(base+"[type_role_name_pattern]")))
continue
}
if hasPrefixAndSuffix(k, "path_filters[", "][fs_path_pattern]") {
base, _ := strings.CutSuffix(k, "[fs_path_pattern]")
r.Form.Add("fs_path_pattern", strings.TrimSpace(r.Form.Get(k)))
r.Form.Add("type_fs_path_pattern", strings.TrimSpace(r.Form.Get(base+"[type_fs_path_pattern]")))
continue
}
if hasPrefixAndSuffix(k, "actions[", "][action_name]") {
base, _ := strings.CutSuffix(k, "[action_name]")
order, _ := strings.CutPrefix(k, "actions[")
order, _ = strings.CutSuffix(order, "][action_name]")
r.Form.Add("action_name", strings.TrimSpace(r.Form.Get(k)))
r.Form["action_options"+strconv.Itoa(len(r.Form["action_name"])-1)] = r.Form[base+"[action_options][]"]
r.Form.Add("action_order", order)
continue
}
}
}
func getEventRuleFromPostFields(r *http.Request) (dataprovider.EventRule, error) {
err := r.ParseForm()
if err != nil {
return dataprovider.EventRule{}, util.NewI18nError(err, util.I18nErrorInvalidForm)
}
updateRepeaterFormRuleFields(r)
status, err := strconv.Atoi(r.Form.Get("status"))
if err != nil {
return dataprovider.EventRule{}, fmt.Errorf("invalid status: %w", err)
@@ -3789,31 +3823,27 @@ func (s *httpdServer) handleWebUpdateEventActionPost(w http.ResponseWriter, r *h
http.Redirect(w, r, webAdminEventActionsPath, http.StatusSeeOther)
}
func (s *httpdServer) handleWebGetEventRules(w http.ResponseWriter, r *http.Request) {
func getAllRules(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
limit := defaultQueryLimit
if _, ok := r.URL.Query()["qlimit"]; ok {
if lim, err := strconv.Atoi(r.URL.Query().Get("qlimit")); err == nil {
limit = lim
}
}
rules := make([]dataprovider.EventRule, 0, limit)
rules := make([]dataprovider.EventRule, 0, 10)
for {
res, err := dataprovider.GetEventRules(limit, len(rules), dataprovider.OrderASC)
res, err := dataprovider.GetEventRules(defaultQueryLimit, len(rules), dataprovider.OrderASC)
if err != nil {
s.renderInternalServerErrorPage(w, r, err)
sendAPIResponse(w, r, err, getI18NErrorString(err, util.I18nError500Message), http.StatusInternalServerError)
return
}
rules = append(rules, res...)
if len(res) < limit {
if len(res) < defaultQueryLimit {
break
}
}
render.JSON(w, r, rules)
}
data := eventRulesPage{
basePage: s.getBasePageData(pageEventRulesTitle, webAdminEventRulesPath, r),
Rules: rules,
}
func (s *httpdServer) handleWebGetEventRules(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
data := s.getBasePageData(util.I18nRulesTitle, webAdminEventRulesPath, r)
renderAdminTemplate(w, templateEventRules, data)
}
@@ -3823,7 +3853,7 @@ func (s *httpdServer) handleWebAddEventRuleGet(w http.ResponseWriter, r *http.Re
Status: 1,
Trigger: dataprovider.EventTriggerFsEvent,
}
s.renderEventRulePage(w, r, rule, genericPageModeAdd, "")
s.renderEventRulePage(w, r, rule, genericPageModeAdd, nil)
}
func (s *httpdServer) handleWebAddEventRulePost(w http.ResponseWriter, r *http.Request) {
@@ -3835,7 +3865,7 @@ func (s *httpdServer) handleWebAddEventRulePost(w http.ResponseWriter, r *http.R
}
rule, err := getEventRuleFromPostFields(r)
if err != nil {
s.renderEventRulePage(w, r, rule, genericPageModeAdd, err.Error())
s.renderEventRulePage(w, r, rule, genericPageModeAdd, err)
return
}
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
@@ -3845,7 +3875,7 @@ func (s *httpdServer) handleWebAddEventRulePost(w http.ResponseWriter, r *http.R
return
}
if err = dataprovider.AddEventRule(&rule, claims.Username, ipAddr, claims.Role); err != nil {
s.renderEventRulePage(w, r, rule, genericPageModeAdd, err.Error())
s.renderEventRulePage(w, r, rule, genericPageModeAdd, err)
return
}
http.Redirect(w, r, webAdminEventRulesPath, http.StatusSeeOther)
@@ -3856,7 +3886,7 @@ func (s *httpdServer) handleWebUpdateEventRuleGet(w http.ResponseWriter, r *http
name := getURLParam(r, "name")
rule, err := dataprovider.EventRuleExists(name)
if err == nil {
s.renderEventRulePage(w, r, rule, genericPageModeUpdate, "")
s.renderEventRulePage(w, r, rule, genericPageModeUpdate, nil)
} else if errors.Is(err, util.ErrNotFound) {
s.renderNotFoundPage(w, r, err)
} else {
@@ -3882,7 +3912,7 @@ func (s *httpdServer) handleWebUpdateEventRulePost(w http.ResponseWriter, r *htt
}
updatedRule, err := getEventRuleFromPostFields(r)
if err != nil {
s.renderEventRulePage(w, r, updatedRule, genericPageModeUpdate, err.Error())
s.renderEventRulePage(w, r, updatedRule, genericPageModeUpdate, err)
return
}
ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
@@ -3894,7 +3924,7 @@ func (s *httpdServer) handleWebUpdateEventRulePost(w http.ResponseWriter, r *htt
updatedRule.Name = rule.Name
err = dataprovider.UpdateEventRule(&updatedRule, claims.Username, ipAddr, claims.Role)
if err != nil {
s.renderEventRulePage(w, r, updatedRule, genericPageModeUpdate, err.Error())
s.renderEventRulePage(w, r, updatedRule, genericPageModeUpdate, err)
return
}
http.Redirect(w, r, webAdminEventRulesPath, http.StatusSeeOther)

View File

@@ -69,8 +69,11 @@ const (
I18nDefenderTitle = "title.defender"
I18nEventsTitle = "title.logs"
I18nActionsTitle = "title.event_actions"
I18nRulesTitle = "title.event_rules"
I18nAddActionTitle = "title.add_action"
I18nUpdateActionTitle = "title.update_action"
I18nAddRuleTitle = "title.add_rule"
I18nUpdateRuleTitle = "title.update_rule"
I18nStatusTitle = "status.desc"
I18nErrorSetupInstallCode = "setup.install_code_mismatch"
I18nInvalidAuth = "general.invalid_auth_request"
@@ -278,6 +281,26 @@ const (
I18nActionFsTypeCompress = "actions.fs_types.compress"
I18nActionFsTypeCopy = "actions.fs_types.copy"
I18nActionFsTypeCreateDirs = "actions.fs_types.create_dirs"
I18nTriggerFsEvent = "rules.triggers.fs_event"
I18nTriggerProviderEvent = "rules.triggers.provider_event"
I18nTriggerIPBlockedEvent = "rules.triggers.ip_blocked"
I18nTriggerCertificateRenewEvent = "rules.triggers.certificate_renewal"
I18nTriggerOnDemandEvent = "rules.triggers.on_demand"
I18nTriggerIDPLoginEvent = "rules.triggers.idp_login"
I18nTriggerScheduleEvent = "rules.triggers.schedule"
I18nErrorInvalidMinSize = "rules.invalid_fs_min_size"
I18nErrorInvalidMaxSize = "rules.invalid_fs_max_size"
I18nErrorRuleActionRequired = "rules.action_required"
I18nErrorRuleFsEventRequired = "rules.fs_event_required"
I18nErrorRuleProviderEventRequired = "rules.provider_event_required"
I18nErrorRuleScheduleRequired = "rules.schedule_required"
I18nErrorRuleScheduleInvalid = "rules.schedule_invalid"
I18nErrorRuleDuplicateActions = "rules.duplicate_actions"
I18nErrorEvSyncFailureActions = "rules.sync_failure_actions"
I18nErrorEvSyncUnsupported = "rules.sync_unsupported"
I18nErrorEvSyncUnsupportedFs = "rules.sync_unsupported_fs_event"
I18nErrorRuleFailureActionsOnly = "rules.only_failure_actions"
I18nErrorRuleSyncActionRequired = "rules.sync_action_required"
)
// NewI18nError returns a I18nError wrappring the provided error