diff --git a/docker/addons/bootstrap/ssl/placeholder b/docker/addons/bootstrap/ssl/placeholder index f5f101481..f4ebb3239 100644 --- a/docker/addons/bootstrap/ssl/placeholder +++ b/docker/addons/bootstrap/ssl/placeholder @@ -1 +1,4 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + optional bind-mount placeholder diff --git a/docker/addons/postgres-reader/ssl/placeholder b/docker/addons/postgres-reader/ssl/placeholder index f5f101481..f4ebb3239 100644 --- a/docker/addons/postgres-reader/ssl/placeholder +++ b/docker/addons/postgres-reader/ssl/placeholder @@ -1 +1,4 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + optional bind-mount placeholder diff --git a/docker/addons/ssl/placeholder b/docker/addons/ssl/placeholder index f5f101481..f4ebb3239 100644 --- a/docker/addons/ssl/placeholder +++ b/docker/addons/ssl/placeholder @@ -1 +1,4 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + optional bind-mount placeholder diff --git a/docker/ssl/placeholder b/docker/ssl/placeholder index f5f101481..f4ebb3239 100644 --- a/docker/ssl/placeholder +++ b/docker/ssl/placeholder @@ -1 +1,4 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + optional bind-mount placeholder diff --git a/pkg/sdk/reports.go b/pkg/sdk/reports.go index 5b52dbdb4..4f7b262a3 100644 --- a/pkg/sdk/reports.go +++ b/pkg/sdk/reports.go @@ -12,6 +12,7 @@ import ( "time" "github.com/absmach/magistrala/pkg/errors" + "github.com/absmach/magistrala/pkg/roles" ) const ( @@ -21,20 +22,21 @@ const ( // ReportConfig represents a report configuration. type ReportConfig struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Description string `json:"description,omitempty"` - DomainID string `json:"domain_id,omitempty"` - Schedule any `json:"schedule,omitempty"` - Config any `json:"config,omitempty"` - Email any `json:"email,omitempty"` - Metrics any `json:"metrics,omitempty"` - ReportTemplate ReportTemplate `json:"report_template,omitempty"` - Status string `json:"status,omitempty"` - CreatedAt time.Time `json:"created_at,omitempty"` - CreatedBy string `json:"created_by,omitempty"` - UpdatedAt time.Time `json:"updated_at,omitempty"` - UpdatedBy string `json:"updated_by,omitempty"` + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + DomainID string `json:"domain_id,omitempty"` + Schedule any `json:"schedule,omitempty"` + Config any `json:"config,omitempty"` + Email any `json:"email,omitempty"` + Metrics any `json:"metrics,omitempty"` + ReportTemplate ReportTemplate `json:"report_template,omitempty"` + Status string `json:"status,omitempty"` + CreatedAt time.Time `json:"created_at,omitempty"` + CreatedBy string `json:"created_by,omitempty"` + UpdatedAt time.Time `json:"updated_at,omitempty"` + UpdatedBy string `json:"updated_by,omitempty"` + Roles []roles.MemberRoleActions `json:"roles,omitempty"` } type ReportTemplate any diff --git a/pkg/sdk/rules.go b/pkg/sdk/rules.go index 89630b500..288f15368 100644 --- a/pkg/sdk/rules.go +++ b/pkg/sdk/rules.go @@ -10,27 +10,29 @@ import ( "net/http" "github.com/absmach/magistrala/pkg/errors" + "github.com/absmach/magistrala/pkg/roles" ) const rulesEndpoint = "rules" // Rule represents a rule configuration. type Rule struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - DomainID string `json:"domain,omitempty"` - Metadata Metadata `json:"metadata,omitempty"` - Tags []string `json:"tags,omitempty"` - InputChannel string `json:"input_channel,omitempty"` - InputTopic string `json:"input_topic,omitempty"` - Logic any `json:"logic,omitempty"` - Outputs any `json:"outputs,omitempty"` - Schedule any `json:"schedule,omitempty"` - Status string `json:"status,omitempty"` - CreatedAt string `json:"created_at,omitempty"` - CreatedBy string `json:"created_by,omitempty"` - UpdatedAt string `json:"updated_at,omitempty"` - UpdatedBy string `json:"updated_by,omitempty"` + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + DomainID string `json:"domain,omitempty"` + Metadata Metadata `json:"metadata,omitempty"` + Tags []string `json:"tags,omitempty"` + InputChannel string `json:"input_channel,omitempty"` + InputTopic string `json:"input_topic,omitempty"` + Logic any `json:"logic,omitempty"` + Outputs any `json:"outputs,omitempty"` + Schedule any `json:"schedule,omitempty"` + Status string `json:"status,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + CreatedBy string `json:"created_by,omitempty"` + UpdatedAt string `json:"updated_at,omitempty"` + UpdatedBy string `json:"updated_by,omitempty"` + Roles []roles.MemberRoleActions `json:"roles,omitempty"` } type Page struct { diff --git a/re/postgres/repository.go b/re/postgres/repository.go index dccbac43b..35545ab9b 100644 --- a/re/postgres/repository.go +++ b/re/postgres/repository.go @@ -404,37 +404,64 @@ func (repo *PostgresRepository) ListAllRules(ctx context.Context, pm re.PageMeta func (repo *PostgresRepository) ListUserRules(ctx context.Context, userID string, pm re.PageMeta) (re.Page, error) { pm.UserID = userID - clauses := []string{ - `( - EXISTS ( - SELECT 1 - FROM rules_roles rr - JOIN rules_role_members rrm ON rrm.role_id = rr.id - WHERE rr.entity_id = r.id AND rrm.member_id = :user_id - ) - OR EXISTS ( - SELECT 1 - FROM domains_roles dr - JOIN domains_role_members drm ON drm.role_id = dr.id - JOIN domains_role_actions dra ON dra.role_id = dr.id - WHERE dr.entity_id = r.domain_id - AND drm.member_id = :user_id - AND dra.action LIKE 'rule%' - ) - )`, + + additionalConditions := pageRulesQueryConditions(pm) + additionalWhereClause := "" + if len(additionalConditions) > 0 { + additionalWhereClause = "AND " + strings.Join(additionalConditions, " AND ") } - clauses = append(clauses, pageRulesQueryConditions(pm)...) + orderClause := rulesOrderClause(pm) pgData := rulesPageData(pm) - whereClause := fmt.Sprintf("WHERE %s", strings.Join(clauses, " AND ")) - innerQ := fmt.Sprintf(` - SELECT DISTINCT r.id, r.name, r.domain_id, r.tags, r.input_channel, r.input_topic, r.logic_type, r.logic_value, r.outputs, - r.start_datetime, r.time, r.recurring, r.recurring_period, r.created_at, r.created_by, r.updated_at, r.updated_by, r.status - FROM rules r - %s - `, whereClause) + WITH direct_rules AS ( + SELECT r.id, r.name, r.domain_id, r.tags, r.metadata, r.input_channel, r.input_topic, + r.logic_type, r.logic_value, r.outputs, r.start_datetime, r.time, + r.recurring, r.recurring_period, r.created_at, r.created_by, r.updated_at, r.updated_by, r.status, + rr.id AS role_id, + rr."name" AS role_name, + array_remove(array_agg(DISTINCT rra."action"), NULL) AS actions, + 'direct' AS access_type, + '' AS access_provider_id, + '' AS access_provider_role_id, + '' AS access_provider_role_name, + CAST(array[] AS text[]) AS access_provider_role_actions + FROM rules_role_members rrm + JOIN rules_roles rr ON rr.id = rrm.role_id + JOIN rules r ON r.id = rr.entity_id + LEFT JOIN rules_role_actions rra ON rra.role_id = rrm.role_id + WHERE rrm.member_id = :user_id + %s + GROUP BY r.id, rr.id, rr."name" + ), + domain_rules AS ( + SELECT r.id, r.name, r.domain_id, r.tags, r.metadata, r.input_channel, r.input_topic, + r.logic_type, r.logic_value, r.outputs, r.start_datetime, r.time, + r.recurring, r.recurring_period, r.created_at, r.created_by, r.updated_at, r.updated_by, r.status, + '' AS role_id, + '' AS role_name, + CAST(array[] AS text[]) AS actions, + 'domain' AS access_type, + d.id AS access_provider_id, + dr.id AS access_provider_role_id, + dr."name" AS access_provider_role_name, + array_agg(DISTINCT dra."action") AS access_provider_role_actions + FROM domains_role_members drm + JOIN domains_role_actions dra ON dra.role_id = drm.role_id + JOIN domains_roles dr ON dr.id = drm.role_id + JOIN domains d ON d.id = dr.entity_id + JOIN rules r ON r.domain_id = d.id + WHERE drm.member_id = :user_id + AND dra.action LIKE 'rule%%' + AND NOT EXISTS (SELECT 1 FROM direct_rules tmp WHERE tmp.id = r.id) + %s + GROUP BY r.id, d.id, dr.id, dr."name" + ) + SELECT * FROM direct_rules + UNION ALL + SELECT * FROM domain_rules + `, additionalWhereClause, additionalWhereClause) q := fmt.Sprintf(` SELECT * FROM (%s) AS sub %s %s; diff --git a/re/postgres/rule.go b/re/postgres/rule.go index 44422fb76..7b67ff650 100644 --- a/re/postgres/rule.go +++ b/re/postgres/rule.go @@ -13,31 +13,40 @@ import ( "github.com/absmach/magistrala/pkg/schedule" "github.com/absmach/magistrala/re" "github.com/jackc/pgtype" + "github.com/lib/pq" ) // dbRule represents the database structure for a Rule. type dbRule struct { - ID string `db:"id"` - Name string `db:"name"` - DomainID string `db:"domain_id"` - Tags pgtype.TextArray `db:"tags,omitempty"` - Metadata []byte `db:"metadata,omitempty"` - InputChannel string `db:"input_channel"` - InputTopic sql.NullString `db:"input_topic"` - LogicType re.ScriptType `db:"logic_type"` - LogicValue string `db:"logic_value"` - Outputs []byte `db:"outputs"` - StartDateTime sql.NullTime `db:"start_datetime"` - Time sql.NullTime `db:"time"` - Recurring schedule.Recurring `db:"recurring"` - RecurringPeriod uint `db:"recurring_period"` - Status re.Status `db:"status"` - CreatedAt time.Time `db:"created_at"` - CreatedBy string `db:"created_by"` - UpdatedAt time.Time `db:"updated_at"` - UpdatedBy string `db:"updated_by"` - MemberID string `db:"member_id,omitempty"` - Roles json.RawMessage `db:"roles,omitempty"` + ID string `db:"id"` + Name string `db:"name"` + DomainID string `db:"domain_id"` + Tags pgtype.TextArray `db:"tags,omitempty"` + Metadata []byte `db:"metadata,omitempty"` + InputChannel string `db:"input_channel"` + InputTopic sql.NullString `db:"input_topic"` + LogicType re.ScriptType `db:"logic_type"` + LogicValue string `db:"logic_value"` + Outputs []byte `db:"outputs"` + StartDateTime sql.NullTime `db:"start_datetime"` + Time sql.NullTime `db:"time"` + Recurring schedule.Recurring `db:"recurring"` + RecurringPeriod uint `db:"recurring_period"` + Status re.Status `db:"status"` + CreatedAt time.Time `db:"created_at"` + CreatedBy string `db:"created_by"` + UpdatedAt time.Time `db:"updated_at"` + UpdatedBy string `db:"updated_by"` + MemberID string `db:"member_id,omitempty"` + RoleID string `db:"role_id,omitempty"` + RoleName string `db:"role_name,omitempty"` + Actions pq.StringArray `db:"actions,omitempty"` + AccessType string `db:"access_type,omitempty"` + AccessProviderId string `db:"access_provider_id,omitempty"` + AccessProviderRoleId string `db:"access_provider_role_id,omitempty"` + AccessProviderRoleName string `db:"access_provider_role_name,omitempty"` + AccessProviderRoleActions pq.StringArray `db:"access_provider_role_actions,omitempty"` + Roles json.RawMessage `db:"roles,omitempty"` } func ruleToDb(r re.Rule) (dbRule, error) { @@ -137,12 +146,20 @@ func dbToRule(dto dbRule) (re.Rule, error) { Recurring: dto.Recurring, RecurringPeriod: dto.RecurringPeriod, }, - Status: dto.Status, - CreatedAt: dto.CreatedAt, - CreatedBy: dto.CreatedBy, - UpdatedAt: dto.UpdatedAt, - UpdatedBy: dto.UpdatedBy, - Roles: roles, + Status: dto.Status, + CreatedAt: dto.CreatedAt, + CreatedBy: dto.CreatedBy, + UpdatedAt: dto.UpdatedAt, + UpdatedBy: dto.UpdatedBy, + RoleID: dto.RoleID, + RoleName: dto.RoleName, + Actions: []string(dto.Actions), + AccessType: dto.AccessType, + AccessProviderId: dto.AccessProviderId, + AccessProviderRoleId: dto.AccessProviderRoleId, + AccessProviderRoleName: dto.AccessProviderRoleName, + AccessProviderRoleActions: []string(dto.AccessProviderRoleActions), + Roles: roles, }, nil } diff --git a/re/rule.go b/re/rule.go index a5f0441f9..bf1e49735 100644 --- a/re/rule.go +++ b/re/rule.go @@ -45,22 +45,31 @@ var outputRegistry = map[outputs.OutputType]func() Runnable{ } type Rule struct { - ID string `json:"id"` - Name string `json:"name"` - DomainID string `json:"domain"` - Metadata Metadata `json:"metadata,omitempty"` - Tags []string `json:"tags,omitempty"` - InputChannel string `json:"input_channel"` - InputTopic string `json:"input_topic"` - Logic Script `json:"logic"` - Outputs Outputs `json:"outputs,omitempty"` - Schedule schedule.Schedule `json:"schedule,omitempty"` - Status Status `json:"status"` - CreatedAt time.Time `json:"created_at"` - CreatedBy string `json:"created_by"` - UpdatedAt time.Time `json:"updated_at"` - UpdatedBy string `json:"updated_by"` - Roles []roles.MemberRoleActions `json:"roles,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + DomainID string `json:"domain"` + Metadata Metadata `json:"metadata,omitempty"` + Tags []string `json:"tags,omitempty"` + InputChannel string `json:"input_channel"` + InputTopic string `json:"input_topic"` + Logic Script `json:"logic"` + Outputs Outputs `json:"outputs,omitempty"` + Schedule schedule.Schedule `json:"schedule,omitempty"` + Status Status `json:"status"` + CreatedAt time.Time `json:"created_at"` + CreatedBy string `json:"created_by"` + UpdatedAt time.Time `json:"updated_at"` + UpdatedBy string `json:"updated_by"` + // Extended + RoleID string `json:"role_id,omitempty"` + RoleName string `json:"role_name,omitempty"` + Actions []string `json:"actions,omitempty"` + AccessType string `json:"access_type,omitempty"` + AccessProviderId string `json:"access_provider_id,omitempty"` + AccessProviderRoleId string `json:"access_provider_role_id,omitempty"` + AccessProviderRoleName string `json:"access_provider_role_name,omitempty"` + AccessProviderRoleActions []string `json:"access_provider_role_actions,omitempty"` + Roles []roles.MemberRoleActions `json:"roles,omitempty"` } // EventEncode converts a Rule struct to map[string]any at event producer. diff --git a/reports/postgres/reports.go b/reports/postgres/reports.go index e32317f0b..32ac857bb 100644 --- a/reports/postgres/reports.go +++ b/reports/postgres/reports.go @@ -12,29 +12,38 @@ import ( "github.com/absmach/magistrala/pkg/roles" "github.com/absmach/magistrala/pkg/schedule" "github.com/absmach/magistrala/reports" + "github.com/lib/pq" ) // dbReport represents the database structure for a Report. type dbReport struct { - ID string `db:"id"` - Name string `db:"name"` - Description string `db:"description"` - DomainID string `db:"domain_id"` - StartDateTime sql.NullTime `db:"start_datetime"` - Due sql.NullTime `db:"due"` - Recurring schedule.Recurring `db:"recurring"` - RecurringPeriod uint `db:"recurring_period"` - Status reports.Status `db:"status"` - CreatedAt time.Time `db:"created_at"` - CreatedBy string `db:"created_by"` - UpdatedAt time.Time `db:"updated_at"` - UpdatedBy string `db:"updated_by"` - Config []byte `db:"config,omitempty"` - Metrics []byte `db:"metrics"` - Email []byte `db:"email"` - ReportTemplate reports.ReportTemplate `db:"report_template"` - MemberID string `db:"member_id,omitempty"` - Roles json.RawMessage `db:"roles,omitempty"` + ID string `db:"id"` + Name string `db:"name"` + Description string `db:"description"` + DomainID string `db:"domain_id"` + StartDateTime sql.NullTime `db:"start_datetime"` + Due sql.NullTime `db:"due"` + Recurring schedule.Recurring `db:"recurring"` + RecurringPeriod uint `db:"recurring_period"` + Status reports.Status `db:"status"` + CreatedAt time.Time `db:"created_at"` + CreatedBy string `db:"created_by"` + UpdatedAt time.Time `db:"updated_at"` + UpdatedBy string `db:"updated_by"` + Config []byte `db:"config,omitempty"` + Metrics []byte `db:"metrics"` + Email []byte `db:"email"` + ReportTemplate reports.ReportTemplate `db:"report_template"` + MemberID string `db:"member_id,omitempty"` + RoleID string `db:"role_id,omitempty"` + RoleName string `db:"role_name,omitempty"` + Actions pq.StringArray `db:"actions,omitempty"` + AccessType string `db:"access_type,omitempty"` + AccessProviderId string `db:"access_provider_id,omitempty"` + AccessProviderRoleId string `db:"access_provider_role_id,omitempty"` + AccessProviderRoleName string `db:"access_provider_role_name,omitempty"` + AccessProviderRoleActions pq.StringArray `db:"access_provider_role_actions,omitempty"` + Roles json.RawMessage `db:"roles,omitempty"` } func reportToDb(r reports.ReportConfig) (dbReport, error) { @@ -136,14 +145,22 @@ func dbToReport(dto dbReport) (reports.ReportConfig, error) { Recurring: dto.Recurring, RecurringPeriod: dto.RecurringPeriod, }, - Email: &email, - Status: dto.Status, - CreatedAt: dto.CreatedAt, - CreatedBy: dto.CreatedBy, - UpdatedAt: dto.UpdatedAt, - UpdatedBy: dto.UpdatedBy, - ReportTemplate: dto.ReportTemplate, - Roles: roles, + Email: &email, + Status: dto.Status, + CreatedAt: dto.CreatedAt, + CreatedBy: dto.CreatedBy, + UpdatedAt: dto.UpdatedAt, + UpdatedBy: dto.UpdatedBy, + ReportTemplate: dto.ReportTemplate, + RoleID: dto.RoleID, + RoleName: dto.RoleName, + Actions: []string(dto.Actions), + AccessType: dto.AccessType, + AccessProviderId: dto.AccessProviderId, + AccessProviderRoleId: dto.AccessProviderRoleId, + AccessProviderRoleName: dto.AccessProviderRoleName, + AccessProviderRoleActions: []string(dto.AccessProviderRoleActions), + Roles: roles, } return rpt, nil diff --git a/reports/postgres/repository.go b/reports/postgres/repository.go index 507cf75cb..09a5d8c95 100644 --- a/reports/postgres/repository.go +++ b/reports/postgres/repository.go @@ -452,38 +452,65 @@ func (repo *PostgresRepository) ListAllReportsConfig(ctx context.Context, pm rep } func (repo *PostgresRepository) ListUserReportsConfig(ctx context.Context, userID string, pm reports.PageMeta) (reports.ReportConfigPage, error) { - clauses := []string{ - `( - EXISTS ( - SELECT 1 - FROM reports_roles rr - JOIN reports_role_members rrm ON rrm.role_id = rr.id - WHERE rr.entity_id = rc.id AND rrm.member_id = :user_id - ) - OR EXISTS ( - SELECT 1 - FROM domains_roles dr - JOIN domains_role_members drm ON drm.role_id = dr.id - JOIN domains_role_actions dra ON dra.role_id = dr.id - WHERE dr.entity_id = rc.domain_id - AND drm.member_id = :user_id - AND dra.action LIKE 'report%' - ) - )`, + pm.UserID = userID + + additionalConditions := pageReportQueryConditions(pm) + additionalWhereClause := "" + if len(additionalConditions) > 0 { + additionalWhereClause = "AND " + strings.Join(additionalConditions, " AND ") } - clauses = append(clauses, pageReportQueryConditions(pm)...) + orderClause := reportsOrderClause(pm) pgData := reportsPageData(pm) - pm.UserID = userID - whereClause := fmt.Sprintf("WHERE %s", strings.Join(clauses, " AND ")) - innerQ := fmt.Sprintf(` - SELECT DISTINCT rc.id, rc.name, rc.description, rc.domain_id, rc.metrics, rc.email, rc.config, - rc.start_datetime, rc.due, rc.recurring, rc.recurring_period, rc.created_at, rc.created_by, rc.updated_at, rc.updated_by, rc.status - FROM report_config rc - %s - `, whereClause) + WITH direct_reports AS ( + SELECT rc.id, rc.name, rc.description, rc.domain_id, rc.metrics, rc.email, rc.config, + rc.start_datetime, rc.due, rc.recurring, rc.recurring_period, + rc.created_at, rc.created_by, rc.updated_at, rc.updated_by, rc.status, + rr.id AS role_id, + rr."name" AS role_name, + array_remove(array_agg(DISTINCT rra."action"), NULL) AS actions, + 'direct' AS access_type, + '' AS access_provider_id, + '' AS access_provider_role_id, + '' AS access_provider_role_name, + CAST(array[] AS text[]) AS access_provider_role_actions + FROM reports_role_members rrm + JOIN reports_roles rr ON rr.id = rrm.role_id + JOIN report_config rc ON rc.id = rr.entity_id + LEFT JOIN reports_role_actions rra ON rra.role_id = rrm.role_id + WHERE rrm.member_id = :user_id + %s + GROUP BY rc.id, rr.id, rr."name" + ), + domain_reports AS ( + SELECT rc.id, rc.name, rc.description, rc.domain_id, rc.metrics, rc.email, rc.config, + rc.start_datetime, rc.due, rc.recurring, rc.recurring_period, + rc.created_at, rc.created_by, rc.updated_at, rc.updated_by, rc.status, + '' AS role_id, + '' AS role_name, + CAST(array[] AS text[]) AS actions, + 'domain' AS access_type, + d.id AS access_provider_id, + dr.id AS access_provider_role_id, + dr."name" AS access_provider_role_name, + array_agg(DISTINCT dra."action") AS access_provider_role_actions + FROM domains_role_members drm + JOIN domains_role_actions dra ON dra.role_id = drm.role_id + JOIN domains_roles dr ON dr.id = drm.role_id + JOIN domains d ON d.id = dr.entity_id + JOIN report_config rc ON rc.domain_id = d.id + WHERE drm.member_id = :user_id + AND dra.action LIKE 'report%%' + AND NOT EXISTS (SELECT 1 FROM direct_reports tmp WHERE tmp.id = rc.id) + %s + GROUP BY rc.id, d.id, dr.id, dr."name" + ) + SELECT * FROM direct_reports + UNION ALL + SELECT * FROM domain_reports + `, additionalWhereClause, additionalWhereClause) q := fmt.Sprintf(` SELECT * FROM (%s) AS sub %s %s; diff --git a/reports/reports.go b/reports/reports.go index dc4aa0b49..3e4dca2b8 100644 --- a/reports/reports.go +++ b/reports/reports.go @@ -153,21 +153,30 @@ func (rm ReqMetric) Validate() error { } type ReportConfig struct { - ID string `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - DomainID string `json:"domain_id"` - Schedule schedule.Schedule `json:"schedule,omitempty"` - Config *MetricConfig `json:"config,omitempty"` - Email *EmailSetting `json:"email,omitempty"` - Metrics []ReqMetric `json:"metrics,omitempty"` - ReportTemplate ReportTemplate `json:"report_template,omitempty"` - Status Status `json:"status"` - CreatedAt time.Time `json:"created_at"` - CreatedBy string `json:"created_by,omitempty"` - UpdatedAt time.Time `json:"updated_at"` - UpdatedBy string `json:"updated_by,omitempty"` - Roles []roles.MemberRoleActions `json:"roles,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + DomainID string `json:"domain_id"` + Schedule schedule.Schedule `json:"schedule,omitempty"` + Config *MetricConfig `json:"config,omitempty"` + Email *EmailSetting `json:"email,omitempty"` + Metrics []ReqMetric `json:"metrics,omitempty"` + ReportTemplate ReportTemplate `json:"report_template,omitempty"` + Status Status `json:"status"` + CreatedAt time.Time `json:"created_at"` + CreatedBy string `json:"created_by,omitempty"` + UpdatedAt time.Time `json:"updated_at"` + UpdatedBy string `json:"updated_by,omitempty"` + // Extended + RoleID string `json:"role_id,omitempty"` + RoleName string `json:"role_name,omitempty"` + Actions []string `json:"actions,omitempty"` + AccessType string `json:"access_type,omitempty"` + AccessProviderId string `json:"access_provider_id,omitempty"` + AccessProviderRoleId string `json:"access_provider_role_id,omitempty"` + AccessProviderRoleName string `json:"access_provider_role_name,omitempty"` + AccessProviderRoleActions []string `json:"access_provider_role_actions,omitempty"` + Roles []roles.MemberRoleActions `json:"roles,omitempty"` } type ReportConfigPage struct {