Add data privacy request route and implementation

- Introduces new role for data-privacy-officer(Role allows user to manage data privacy requests)
- along with a new system resource for data privacy requests and its access control
- Routes as per access control to create data privacy request, list request and filter it based on their kind and status, update data privacy request status, and create/list comments on data privacy request
This commit is contained in:
Vivek Patel
2022-06-14 13:17:44 +05:30
parent de1f3a908e
commit 7cdf51adc4
44 changed files with 5544 additions and 115 deletions
+26 -21
View File
@@ -8,27 +8,29 @@ component: schema.#component & {
handle: "system"
resources: {
"attachment": attachment
"application": application
"apigw-route": apigw_route
"apigw-filter": apigw_filter
"auth-client": auth_client
"auth-confirmed-client": auth_confirmed_client
"auth-session": auth_session
"auth-oa2token": auth_oa2token
"credential": credential
"queue": queue
"queue_message": queue_message
"reminder": reminder
"report": report
"resource-translation": resource_translation
"role": role
"role_member": role_member
"settings": settings
"template": template
"user": user
"dal_connection": dal_connection
"dal_sensitivity_level": dal_sensitivity_level
"attachment": attachment
"application": application
"apigw-route": apigw_route
"apigw-filter": apigw_filter
"auth-client": auth_client
"auth-confirmed-client": auth_confirmed_client
"auth-session": auth_session
"auth-oa2token": auth_oa2token
"credential": credential
"data-privacy-request": data_privacy_request
"data-privacy-request_comment": data_privacy_request_comment
"queue": queue
"queue_message": queue_message
"reminder": reminder
"report": report
"resource-translation": resource_translation
"role": role
"role_member": role_member
"settings": settings
"template": template
"user": user
"dal_connection": dal_connection
"dal_sensitivity_level": dal_sensitivity_level
}
rbac: operations: {
@@ -70,5 +72,8 @@ component: schema.#component & {
"apigw-routes.search": description: "List search or filter API gateway routes"
"resource-translations.manage": description: "List, search, create, or update resource translations"
"data-privacy-request.create": description: "Create data privacy requests"
"data-privacy-requests.search": description: "List, search or filter data privacy requests"
}
}
+66
View File
@@ -0,0 +1,66 @@
package system
import (
"github.com/cortezaproject/corteza-server/codegen/schema"
)
data_privacy_request: schema.#Resource & {
features: {
labels: false
}
struct: {
id: schema.IdField
kind: { goType: "types.RequestKind", sortable: true }
status: { goType: "types.RequestStatus", sortable: true }
requested_at: schema.SortableTimestampField
requested_by: { goType: "uint64" }
completed_at: schema.SortableTimestampNilField
completed_by: { goType: "uint64" }
created_at: schema.SortableTimestampField
updated_at: schema.SortableTimestampNilField
deleted_at: schema.SortableTimestampNilField
created_by: { goType: "uint64" }
updated_by: { goType: "uint64" }
deleted_by: { goType: "uint64" }
}
filter: {
struct: {
request_id: {goType: "[]uint64", ident: "requestID", storeIdent: "id" }
requested_by: {goType: "[]uint64", ident: "requestedBy" }
kind: {goType: "[]types.RequestKind"}
status: {goType: "[]types.RequestStatus"}
}
query: ["kind", "status"]
byValue: ["kind", "status", "requested_by"]
}
rbac: {
operations: {
read:
description: "Read data privacy request"
approve:
description: "Approve/Reject data privacy request"
}
}
store: {
api: {
lookups: [
{
fields: ["id"]
description: """
searches for data privacy request by ID
It returns data privacy request even if deleted
"""
}
]
functions: []
}
}
}
+43
View File
@@ -0,0 +1,43 @@
package system
import (
"github.com/cortezaproject/corteza-server/codegen/schema"
)
data_privacy_request_comment: schema.#Resource & {
features: {
labels: false
}
struct: {
id: schema.IdField
request_id: { ident: "requestID", goType: "uint64", storeIdent: "rel_request" }
comment: { goType: "string" }
created_at: schema.SortableTimestampField
updated_at: schema.SortableTimestampNilField
deleted_at: schema.SortableTimestampNilField
created_by: { goType: "uint64" }
updated_by: { goType: "uint64" }
deleted_by: { goType: "uint64" }
}
filter: {
struct: {
request_id: {goType: "[]uint64", ident: "requestID", storeIdent: "rel_request" }
}
query: []
byValue: ["request_id"]
}
rbac: {
operations: {}
}
store: {
api: {
functions: []
}
}
}
+65
View File
@@ -2198,3 +2198,68 @@ endpoints:
path:
- { type: string, name: lang, required: true, title: Language }
- { type: string, name: application, required: true, title: Application name }
- title: Data Privacy Request
entrypoint: dataPrivacyRequest
path: "/data-privacy/requests"
apis:
- name: list
method: GET
title: List data privacy requests
path: "/"
parameters:
get:
- { name: requestedBy, type: "[]string", title: "Filter by user ID" }
- { name: query, type: "string", title: "Filter requests" }
- { name: kind, type: "[]string", title: "Filter by kind: correct, delete, export" }
- { name: status, type: "[]string", title: "Filter by status: pending, cancel, approve, reject" }
- { name: limit, type: "uint", title: "Limit" }
- { name: pageCursor, type: "string", title: "Page cursor" }
- { name: sort, type: "string", title: "Sort items" }
- name: create
method: POST
title: Create data privacy request
path: "/"
parameters:
post:
- { name: kind, type: "string", title: "Request Kind", required: true }
- name: update status
method: PATCH
title: Update data privacy request status
path: "/{requestID}/status/{status}"
parameters:
path:
- { name: requestID, type: "uint64", title: "ID", required: true }
- { name: status, type: "string", title: "Request Status", required: true }
- name: read
method: GET
title: Get details about specific request
path: "/{requestID}"
parameters:
path:
- { name: requestID, type: "uint64", title: "Request ID", required: true }
- title: Data Privacy Request Comment
entrypoint: dataPrivacyRequestComment
path: "/data-privacy/requests/{requestID}/comments"
parameters:
path:
- { name: requestID, type: "uint64", title: "Request ID", required: true }
apis:
- name: list
method: GET
title: List data privacy request comments
path: "/"
parameters:
get:
- { name: limit, type: "uint", title: "Limit" }
- { name: pageCursor, type: "string", title: "Page cursor" }
- { name: sort, type: "string", title: "Sort items" }
- name: create
method: POST
title: Create data privacy request comment
path: "/"
parameters:
post:
- { name: comment, type: "string", title: "Comment description", required: true }
+147
View File
@@ -0,0 +1,147 @@
package rest
import (
"context"
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/pkg/payload"
"github.com/cortezaproject/corteza-server/system/rest/request"
"github.com/cortezaproject/corteza-server/system/service"
"github.com/cortezaproject/corteza-server/system/types"
)
type (
DataPrivacyRequest struct {
dataPrivacy service.DataPrivacyService
ac dataPrivacyAccessController
}
dataPrivacyRequestSetPayload struct {
Filter types.DataPrivacyRequestFilter `json:"filter"`
Set types.DataPrivacyRequestSet `json:"set"`
}
dataPrivacyAccessController interface {
CanGrant(context.Context) bool
}
DataPrivacyRequestComment struct {
dataPrivacy service.DataPrivacyService
ac dataPrivacyAccessController
}
dataPrivacyRequestCommentSetPayload struct {
Filter types.DataPrivacyRequestCommentFilter `json:"filter"`
Set types.DataPrivacyRequestCommentSet `json:"set"`
}
)
func (DataPrivacyRequest) New() *DataPrivacyRequest {
return &DataPrivacyRequest{
dataPrivacy: service.DefaultDataPrivacy,
ac: service.DefaultAccessControl,
}
}
func (ctrl DataPrivacyRequest) List(ctx context.Context, r *request.DataPrivacyRequestList) (interface{}, error) {
var (
err error
f = types.DataPrivacyRequestFilter{
RequestedBy: payload.ParseUint64s(r.RequestedBy),
Query: r.Query,
Kind: r.Kind,
Status: r.Status,
}
)
if f.Paging, err = filter.NewPaging(r.Limit, r.PageCursor); err != nil {
return nil, err
}
if f.Sorting, err = filter.NewSorting(r.Sort); err != nil {
return nil, err
}
set, f, err := ctrl.dataPrivacy.FindRequests(ctx, f)
return ctrl.makeFilterPayload(ctx, set, f, err)
}
func (ctrl DataPrivacyRequest) makeFilterPayload(_ context.Context, rr types.DataPrivacyRequestSet, f types.DataPrivacyRequestFilter, err error) (*dataPrivacyRequestSetPayload, error) {
if err != nil {
return nil, err
}
if len(rr) == 0 {
rr = make([]*types.DataPrivacyRequest, 0)
}
return &dataPrivacyRequestSetPayload{Filter: f, Set: rr}, nil
}
func (ctrl DataPrivacyRequest) Create(ctx context.Context, r *request.DataPrivacyRequestCreate) (interface{}, error) {
req := &types.DataPrivacyRequest{
Kind: types.CastToRequestKind(r.Kind),
}
return ctrl.dataPrivacy.CreateRequest(ctx, req)
}
func (ctrl DataPrivacyRequest) UpdateStatus(ctx context.Context, r *request.DataPrivacyRequestUpdateStatus) (interface{}, error) {
req := &types.DataPrivacyRequest{
ID: r.RequestID,
Status: types.CastToRequestStatus(r.Status),
}
return ctrl.dataPrivacy.UpdateRequestStatus(ctx, req)
}
func (ctrl DataPrivacyRequest) Read(ctx context.Context, r *request.DataPrivacyRequestRead) (interface{}, error) {
return ctrl.dataPrivacy.FindRequestByID(ctx, r.RequestID)
}
func (DataPrivacyRequestComment) New() *DataPrivacyRequestComment {
return &DataPrivacyRequestComment{
dataPrivacy: service.DefaultDataPrivacy,
ac: service.DefaultAccessControl,
}
}
func (ctrl DataPrivacyRequestComment) List(ctx context.Context, r *request.DataPrivacyRequestCommentList) (interface{}, error) {
var (
err error
f = types.DataPrivacyRequestCommentFilter{
RequestID: []uint64{r.RequestID},
}
)
if f.Paging, err = filter.NewPaging(r.Limit, r.PageCursor); err != nil {
return nil, err
}
if f.Sorting, err = filter.NewSorting(r.Sort); err != nil {
return nil, err
}
set, f, err := ctrl.dataPrivacy.FindRequestComments(ctx, f)
return ctrl.makeFilterPayload(ctx, set, f, err)
}
func (ctrl DataPrivacyRequestComment) makeFilterPayload(_ context.Context, rr types.DataPrivacyRequestCommentSet, f types.DataPrivacyRequestCommentFilter, err error) (*dataPrivacyRequestCommentSetPayload, error) {
if err != nil {
return nil, err
}
if len(rr) == 0 {
rr = make([]*types.DataPrivacyRequestComment, 0)
}
return &dataPrivacyRequestCommentSetPayload{Filter: f, Set: rr}, nil
}
func (ctrl DataPrivacyRequestComment) Create(ctx context.Context, r *request.DataPrivacyRequestCommentCreate) (interface{}, error) {
req := &types.DataPrivacyRequestComment{
RequestID: r.RequestID,
Comment: r.Comment,
}
return ctrl.dataPrivacy.CreateRequestComment(ctx, req)
}
+114
View File
@@ -0,0 +1,114 @@
package handlers
// This file is auto-generated.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
// Definitions file that controls how this file is generated:
//
import (
"context"
"github.com/cortezaproject/corteza-server/pkg/api"
"github.com/cortezaproject/corteza-server/system/rest/request"
"github.com/go-chi/chi/v5"
"net/http"
)
type (
// Internal API interface
DataPrivacyRequestAPI interface {
List(context.Context, *request.DataPrivacyRequestList) (interface{}, error)
Create(context.Context, *request.DataPrivacyRequestCreate) (interface{}, error)
UpdateStatus(context.Context, *request.DataPrivacyRequestUpdateStatus) (interface{}, error)
Read(context.Context, *request.DataPrivacyRequestRead) (interface{}, error)
}
// HTTP API interface
DataPrivacyRequest struct {
List func(http.ResponseWriter, *http.Request)
Create func(http.ResponseWriter, *http.Request)
UpdateStatus func(http.ResponseWriter, *http.Request)
Read func(http.ResponseWriter, *http.Request)
}
)
func NewDataPrivacyRequest(h DataPrivacyRequestAPI) *DataPrivacyRequest {
return &DataPrivacyRequest{
List: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewDataPrivacyRequestList()
if err := params.Fill(r); err != nil {
api.Send(w, r, err)
return
}
value, err := h.List(r.Context(), params)
if err != nil {
api.Send(w, r, err)
return
}
api.Send(w, r, value)
},
Create: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewDataPrivacyRequestCreate()
if err := params.Fill(r); err != nil {
api.Send(w, r, err)
return
}
value, err := h.Create(r.Context(), params)
if err != nil {
api.Send(w, r, err)
return
}
api.Send(w, r, value)
},
UpdateStatus: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewDataPrivacyRequestUpdateStatus()
if err := params.Fill(r); err != nil {
api.Send(w, r, err)
return
}
value, err := h.UpdateStatus(r.Context(), params)
if err != nil {
api.Send(w, r, err)
return
}
api.Send(w, r, value)
},
Read: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewDataPrivacyRequestRead()
if err := params.Fill(r); err != nil {
api.Send(w, r, err)
return
}
value, err := h.Read(r.Context(), params)
if err != nil {
api.Send(w, r, err)
return
}
api.Send(w, r, value)
},
}
}
func (h DataPrivacyRequest) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) {
r.Group(func(r chi.Router) {
r.Use(middlewares...)
r.Get("/data-privacy/requests/", h.List)
r.Post("/data-privacy/requests/", h.Create)
r.Patch("/data-privacy/requests/{requestID}/status/{status}", h.UpdateStatus)
r.Get("/data-privacy/requests/{requestID}", h.Read)
})
}
@@ -0,0 +1,76 @@
package handlers
// This file is auto-generated.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
// Definitions file that controls how this file is generated:
//
import (
"context"
"github.com/cortezaproject/corteza-server/pkg/api"
"github.com/cortezaproject/corteza-server/system/rest/request"
"github.com/go-chi/chi/v5"
"net/http"
)
type (
// Internal API interface
DataPrivacyRequestCommentAPI interface {
List(context.Context, *request.DataPrivacyRequestCommentList) (interface{}, error)
Create(context.Context, *request.DataPrivacyRequestCommentCreate) (interface{}, error)
}
// HTTP API interface
DataPrivacyRequestComment struct {
List func(http.ResponseWriter, *http.Request)
Create func(http.ResponseWriter, *http.Request)
}
)
func NewDataPrivacyRequestComment(h DataPrivacyRequestCommentAPI) *DataPrivacyRequestComment {
return &DataPrivacyRequestComment{
List: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewDataPrivacyRequestCommentList()
if err := params.Fill(r); err != nil {
api.Send(w, r, err)
return
}
value, err := h.List(r.Context(), params)
if err != nil {
api.Send(w, r, err)
return
}
api.Send(w, r, value)
},
Create: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewDataPrivacyRequestCommentCreate()
if err := params.Fill(r); err != nil {
api.Send(w, r, err)
return
}
value, err := h.Create(r.Context(), params)
if err != nil {
api.Send(w, r, err)
return
}
api.Send(w, r, value)
},
}
}
func (h DataPrivacyRequestComment) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) {
r.Group(func(r chi.Router) {
r.Use(middlewares...)
r.Get("/data-privacy/requests/{requestID}/comments/", h.List)
r.Post("/data-privacy/requests/{requestID}/comments/", h.Create)
})
}
+367
View File
@@ -0,0 +1,367 @@
package request
// This file is auto-generated.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
// Definitions file that controls how this file is generated:
//
import (
"encoding/json"
"fmt"
"github.com/cortezaproject/corteza-server/pkg/payload"
"github.com/go-chi/chi/v5"
"io"
"mime/multipart"
"net/http"
"strings"
)
// dummy vars to prevent
// unused imports complain
var (
_ = chi.URLParam
_ = multipart.ErrMessageTooLarge
_ = payload.ParseUint64s
_ = strings.ToLower
_ = io.EOF
_ = fmt.Errorf
_ = json.NewEncoder
)
type (
// Internal API interface
DataPrivacyRequestList struct {
// RequestedBy GET parameter
//
// Filter by user ID
RequestedBy []string
// Query GET parameter
//
// Filter requests
Query string
// Kind GET parameter
//
// Filter by kind: correct, delete, export
Kind []string
// Status GET parameter
//
// Filter by status: pending, cancel, approve, reject
Status []string
// Limit GET parameter
//
// Limit
Limit uint
// PageCursor GET parameter
//
// Page cursor
PageCursor string
// Sort GET parameter
//
// Sort items
Sort string
}
DataPrivacyRequestCreate struct {
// Kind POST parameter
//
// Request Kind
Kind string
}
DataPrivacyRequestUpdateStatus struct {
// RequestID PATH parameter
//
// ID
RequestID uint64 `json:",string"`
// Status PATH parameter
//
// Request Status
Status string
}
DataPrivacyRequestRead struct {
// RequestID PATH parameter
//
// Request ID
RequestID uint64 `json:",string"`
}
)
// NewDataPrivacyRequestList request
func NewDataPrivacyRequestList() *DataPrivacyRequestList {
return &DataPrivacyRequestList{}
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestList) Auditable() map[string]interface{} {
return map[string]interface{}{
"requestedBy": r.RequestedBy,
"query": r.Query,
"kind": r.Kind,
"status": r.Status,
"limit": r.Limit,
"pageCursor": r.PageCursor,
"sort": r.Sort,
}
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestList) GetRequestedBy() []string {
return r.RequestedBy
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestList) GetQuery() string {
return r.Query
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestList) GetKind() []string {
return r.Kind
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestList) GetStatus() []string {
return r.Status
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestList) GetLimit() uint {
return r.Limit
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestList) GetPageCursor() string {
return r.PageCursor
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestList) GetSort() string {
return r.Sort
}
// Fill processes request and fills internal variables
func (r *DataPrivacyRequestList) Fill(req *http.Request) (err error) {
{
// GET params
tmp := req.URL.Query()
if val, ok := tmp["requestedBy[]"]; ok {
r.RequestedBy, err = val, nil
if err != nil {
return err
}
} else if val, ok := tmp["requestedBy"]; ok {
r.RequestedBy, err = val, nil
if err != nil {
return err
}
}
if val, ok := tmp["query"]; ok && len(val) > 0 {
r.Query, err = val[0], nil
if err != nil {
return err
}
}
if val, ok := tmp["kind[]"]; ok {
r.Kind, err = val, nil
if err != nil {
return err
}
} else if val, ok := tmp["kind"]; ok {
r.Kind, err = val, nil
if err != nil {
return err
}
}
if val, ok := tmp["status[]"]; ok {
r.Status, err = val, nil
if err != nil {
return err
}
} else if val, ok := tmp["status"]; ok {
r.Status, err = val, nil
if err != nil {
return err
}
}
if val, ok := tmp["limit"]; ok && len(val) > 0 {
r.Limit, err = payload.ParseUint(val[0]), nil
if err != nil {
return err
}
}
if val, ok := tmp["pageCursor"]; ok && len(val) > 0 {
r.PageCursor, err = val[0], nil
if err != nil {
return err
}
}
if val, ok := tmp["sort"]; ok && len(val) > 0 {
r.Sort, err = val[0], nil
if err != nil {
return err
}
}
}
return err
}
// NewDataPrivacyRequestCreate request
func NewDataPrivacyRequestCreate() *DataPrivacyRequestCreate {
return &DataPrivacyRequestCreate{}
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestCreate) Auditable() map[string]interface{} {
return map[string]interface{}{
"kind": r.Kind,
}
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestCreate) GetKind() string {
return r.Kind
}
// Fill processes request and fills internal variables
func (r *DataPrivacyRequestCreate) Fill(req *http.Request) (err error) {
if strings.HasPrefix(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 fmt.Errorf("error parsing http request body: %w", err)
}
}
{
// Caching 32MB to memory, the rest to disk
if err = req.ParseMultipartForm(32 << 20); err != nil && err != http.ErrNotMultipart {
return err
} else if err == nil {
// Multipart params
if val, ok := req.MultipartForm.Value["kind"]; ok && len(val) > 0 {
r.Kind, err = val[0], nil
if err != nil {
return err
}
}
}
}
{
if err = req.ParseForm(); err != nil {
return err
}
// POST params
if val, ok := req.Form["kind"]; ok && len(val) > 0 {
r.Kind, err = val[0], nil
if err != nil {
return err
}
}
}
return err
}
// NewDataPrivacyRequestUpdateStatus request
func NewDataPrivacyRequestUpdateStatus() *DataPrivacyRequestUpdateStatus {
return &DataPrivacyRequestUpdateStatus{}
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestUpdateStatus) Auditable() map[string]interface{} {
return map[string]interface{}{
"requestID": r.RequestID,
"status": r.Status,
}
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestUpdateStatus) GetRequestID() uint64 {
return r.RequestID
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestUpdateStatus) GetStatus() string {
return r.Status
}
// Fill processes request and fills internal variables
func (r *DataPrivacyRequestUpdateStatus) Fill(req *http.Request) (err error) {
{
var val string
// path params
val = chi.URLParam(req, "requestID")
r.RequestID, err = payload.ParseUint64(val), nil
if err != nil {
return err
}
val = chi.URLParam(req, "status")
r.Status, err = val, nil
if err != nil {
return err
}
}
return err
}
// NewDataPrivacyRequestRead request
func NewDataPrivacyRequestRead() *DataPrivacyRequestRead {
return &DataPrivacyRequestRead{}
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestRead) Auditable() map[string]interface{} {
return map[string]interface{}{
"requestID": r.RequestID,
}
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestRead) GetRequestID() uint64 {
return r.RequestID
}
// Fill processes request and fills internal variables
func (r *DataPrivacyRequestRead) Fill(req *http.Request) (err error) {
{
var val string
// path params
val = chi.URLParam(req, "requestID")
r.RequestID, err = payload.ParseUint64(val), nil
if err != nil {
return err
}
}
return err
}
@@ -0,0 +1,229 @@
package request
// This file is auto-generated.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
// Definitions file that controls how this file is generated:
//
import (
"encoding/json"
"fmt"
"github.com/cortezaproject/corteza-server/pkg/payload"
"github.com/go-chi/chi/v5"
"io"
"mime/multipart"
"net/http"
"strings"
)
// dummy vars to prevent
// unused imports complain
var (
_ = chi.URLParam
_ = multipart.ErrMessageTooLarge
_ = payload.ParseUint64s
_ = strings.ToLower
_ = io.EOF
_ = fmt.Errorf
_ = json.NewEncoder
)
type (
// Internal API interface
DataPrivacyRequestCommentList struct {
// RequestID PATH parameter
//
// Request ID
RequestID uint64 `json:",string"`
// Limit GET parameter
//
// Limit
Limit uint
// PageCursor GET parameter
//
// Page cursor
PageCursor string
// Sort GET parameter
//
// Sort items
Sort string
}
DataPrivacyRequestCommentCreate struct {
// RequestID PATH parameter
//
// Request ID
RequestID uint64 `json:",string"`
// Comment POST parameter
//
// Comment description
Comment string
}
)
// NewDataPrivacyRequestCommentList request
func NewDataPrivacyRequestCommentList() *DataPrivacyRequestCommentList {
return &DataPrivacyRequestCommentList{}
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestCommentList) Auditable() map[string]interface{} {
return map[string]interface{}{
"requestID": r.RequestID,
"limit": r.Limit,
"pageCursor": r.PageCursor,
"sort": r.Sort,
}
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestCommentList) GetRequestID() uint64 {
return r.RequestID
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestCommentList) GetLimit() uint {
return r.Limit
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestCommentList) GetPageCursor() string {
return r.PageCursor
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestCommentList) GetSort() string {
return r.Sort
}
// Fill processes request and fills internal variables
func (r *DataPrivacyRequestCommentList) Fill(req *http.Request) (err error) {
{
// GET params
tmp := req.URL.Query()
if val, ok := tmp["limit"]; ok && len(val) > 0 {
r.Limit, err = payload.ParseUint(val[0]), nil
if err != nil {
return err
}
}
if val, ok := tmp["pageCursor"]; ok && len(val) > 0 {
r.PageCursor, err = val[0], nil
if err != nil {
return err
}
}
if val, ok := tmp["sort"]; ok && len(val) > 0 {
r.Sort, err = val[0], nil
if err != nil {
return err
}
}
}
{
var val string
// path params
val = chi.URLParam(req, "requestID")
r.RequestID, err = payload.ParseUint64(val), nil
if err != nil {
return err
}
}
return err
}
// NewDataPrivacyRequestCommentCreate request
func NewDataPrivacyRequestCommentCreate() *DataPrivacyRequestCommentCreate {
return &DataPrivacyRequestCommentCreate{}
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestCommentCreate) Auditable() map[string]interface{} {
return map[string]interface{}{
"requestID": r.RequestID,
"comment": r.Comment,
}
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestCommentCreate) GetRequestID() uint64 {
return r.RequestID
}
// Auditable returns all auditable/loggable parameters
func (r DataPrivacyRequestCommentCreate) GetComment() string {
return r.Comment
}
// Fill processes request and fills internal variables
func (r *DataPrivacyRequestCommentCreate) Fill(req *http.Request) (err error) {
if strings.HasPrefix(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 fmt.Errorf("error parsing http request body: %w", err)
}
}
{
// Caching 32MB to memory, the rest to disk
if err = req.ParseMultipartForm(32 << 20); err != nil && err != http.ErrNotMultipart {
return err
} else if err == nil {
// Multipart params
if val, ok := req.MultipartForm.Value["comment"]; ok && len(val) > 0 {
r.Comment, err = val[0], nil
if err != nil {
return err
}
}
}
}
{
if err = req.ParseForm(); err != nil {
return err
}
// POST params
if val, ok := req.Form["comment"]; ok && len(val) > 0 {
r.Comment, err = val[0], nil
if err != nil {
return err
}
}
}
{
var val string
// path params
val = chi.URLParam(req, "requestID")
r.RequestID, err = payload.ParseUint64(val), nil
if err != nil {
return err
}
}
return err
}
+2
View File
@@ -47,6 +47,8 @@ func MountRoutes() func(r chi.Router) {
handlers.NewApigwRoute(ApigwRoute{}.New()).MountRoutes(r)
handlers.NewApigwFilter(ApigwFilter{}.New()).MountRoutes(r)
handlers.NewApigwProfiler(ApigwProfiler{}.New()).MountRoutes(r)
handlers.NewDataPrivacyRequest(DataPrivacyRequest{}.New()).MountRoutes(r)
handlers.NewDataPrivacyRequestComment(DataPrivacyRequestComment{}.New()).MountRoutes(r)
})
}
}
+151
View File
@@ -104,6 +104,16 @@ func (svc accessControl) List() (out []map[string]string) {
"any": types.AuthClientRbacResource(0),
"op": "authorize",
},
{
"type": types.DataPrivacyRequestResourceType,
"any": types.DataPrivacyRequestRbacResource(0),
"op": "read",
},
{
"type": types.DataPrivacyRequestResourceType,
"any": types.DataPrivacyRequestRbacResource(0),
"op": "approve",
},
{
"type": types.QueueResourceType,
"any": types.QueueRbacResource(0),
@@ -404,6 +414,16 @@ func (svc accessControl) List() (out []map[string]string) {
"any": types.ComponentRbacResource(),
"op": "resource-translations.manage",
},
{
"type": types.ComponentResourceType,
"any": types.ComponentRbacResource(),
"op": "data-privacy-request.create",
},
{
"type": types.ComponentResourceType,
"any": types.ComponentRbacResource(),
"op": "data-privacy-requests.search",
},
}
func(svc interface{}) {
@@ -547,6 +567,20 @@ func (svc accessControl) CanAuthorizeAuthClient(ctx context.Context, r *types.Au
return svc.can(ctx, "authorize", r)
}
// CanReadDataPrivacyRequest checks if current user can read data privacy request
//
// This function is auto-generated
func (svc accessControl) CanReadDataPrivacyRequest(ctx context.Context, r *types.DataPrivacyRequest) bool {
return svc.can(ctx, "read", r)
}
// CanApproveDataPrivacyRequest checks if current user can approve/reject data privacy request
//
// This function is auto-generated
func (svc accessControl) CanApproveDataPrivacyRequest(ctx context.Context, r *types.DataPrivacyRequest) bool {
return svc.can(ctx, "approve", r)
}
// CanReadQueue checks if current user can read queue
//
// This function is auto-generated
@@ -994,6 +1028,22 @@ func (svc accessControl) CanManageResourceTranslations(ctx context.Context) bool
return svc.can(ctx, "resource-translations.manage", r)
}
// CanCreateDataPrivacyRequest checks if current user can create data privacy requests
//
// This function is auto-generated
func (svc accessControl) CanCreateDataPrivacyRequest(ctx context.Context) bool {
r := &types.Component{}
return svc.can(ctx, "data-privacy-request.create", r)
}
// CanSearchDataPrivacyRequests checks if current user can list, search or filter data privacy requests
//
// This function is auto-generated
func (svc accessControl) CanSearchDataPrivacyRequests(ctx context.Context) bool {
r := &types.Component{}
return svc.can(ctx, "data-privacy-requests.search", r)
}
// rbacResourceValidator validates known component's resource by routing it to the appropriate validator
//
// This function is auto-generated
@@ -1005,6 +1055,10 @@ func rbacResourceValidator(r string, oo ...string) error {
return rbacApigwRouteResourceValidator(r, oo...)
case types.AuthClientResourceType:
return rbacAuthClientResourceValidator(r, oo...)
case types.DataPrivacyRequestResourceType:
return rbacDataPrivacyRequestResourceValidator(r, oo...)
case types.DataPrivacyRequestCommentResourceType:
return rbacDataPrivacyRequestCommentResourceValidator(r, oo...)
case types.QueueResourceType:
return rbacQueueResourceValidator(r, oo...)
case types.QueueMessageResourceType:
@@ -1052,6 +1106,13 @@ func rbacResourceOperations(r string) map[string]bool {
"delete": true,
"authorize": true,
}
case types.DataPrivacyRequestResourceType:
return map[string]bool{
"read": true,
"approve": true,
}
case types.DataPrivacyRequestCommentResourceType:
return map[string]bool{}
case types.QueueResourceType:
return map[string]bool{
"read": true,
@@ -1137,6 +1198,8 @@ func rbacResourceOperations(r string) map[string]bool {
"apigw-route.create": true,
"apigw-routes.search": true,
"resource-translations.manage": true,
"data-privacy-request.create": true,
"data-privacy-requests.search": true,
}
}
@@ -1275,6 +1338,94 @@ func rbacAuthClientResourceValidator(r string, oo ...string) error {
return nil
}
// rbacDataPrivacyRequestResourceValidator checks validity of RBAC resource and operations
//
// Can be called without operations to check for validity of resource string only
//
// This function is auto-generated
func rbacDataPrivacyRequestResourceValidator(r string, oo ...string) error {
if !strings.HasPrefix(r, types.DataPrivacyRequestResourceType) {
// expecting resource to always include path
return fmt.Errorf("invalid resource type")
}
defOps := rbacResourceOperations(r)
for _, o := range oo {
if !defOps[o] {
return fmt.Errorf("invalid operation '%s' for dataPrivacyRequest resource", o)
}
}
const sep = "/"
var (
pp = strings.Split(strings.Trim(r[len(types.DataPrivacyRequestResourceType):], sep), sep)
prc = []string{
"ID",
}
)
if len(pp) != len(prc) {
return fmt.Errorf("invalid resource path structure")
}
for i := 0; i < len(pp); i++ {
if pp[i] != "*" {
if i > 0 && pp[i-1] == "*" {
return fmt.Errorf("invalid path wildcard level (%d) for dataPrivacyRequest resource", i)
}
if _, err := cast.ToUint64E(pp[i]); err != nil {
return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i])
}
}
}
return nil
}
// rbacDataPrivacyRequestCommentResourceValidator checks validity of RBAC resource and operations
//
// Can be called without operations to check for validity of resource string only
//
// This function is auto-generated
func rbacDataPrivacyRequestCommentResourceValidator(r string, oo ...string) error {
if !strings.HasPrefix(r, types.DataPrivacyRequestCommentResourceType) {
// expecting resource to always include path
return fmt.Errorf("invalid resource type")
}
defOps := rbacResourceOperations(r)
for _, o := range oo {
if !defOps[o] {
return fmt.Errorf("invalid operation '%s' for dataPrivacyRequestComment resource", o)
}
}
const sep = "/"
var (
pp = strings.Split(strings.Trim(r[len(types.DataPrivacyRequestCommentResourceType):], sep), sep)
prc = []string{
"ID",
}
)
if len(pp) != len(prc) {
return fmt.Errorf("invalid resource path structure")
}
for i := 0; i < len(pp); i++ {
if pp[i] != "*" {
if i > 0 && pp[i-1] == "*" {
return fmt.Errorf("invalid path wildcard level (%d) for dataPrivacyRequestComment resource", i)
}
if _, err := cast.ToUint64E(pp[i]); err != nil {
return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i])
}
}
}
return nil
}
// rbacQueueResourceValidator checks validity of RBAC resource and operations
//
// Can be called without operations to check for validity of resource string only
+241
View File
@@ -0,0 +1,241 @@
package service
import (
"context"
"github.com/cortezaproject/corteza-server/pkg/actionlog"
a "github.com/cortezaproject/corteza-server/pkg/auth"
"github.com/cortezaproject/corteza-server/pkg/errors"
"github.com/cortezaproject/corteza-server/store"
"github.com/cortezaproject/corteza-server/system/service/event"
"github.com/cortezaproject/corteza-server/system/types"
)
type (
dataPrivacy struct {
actionlog actionlog.Recorder
ac dataPrivacyAccessController
eventbus eventDispatcher
store store.Storer
}
dataPrivacyAccessController interface {
CanSearchDataPrivacyRequests(context.Context) bool
CanCreateDataPrivacyRequest(context.Context) bool
CanReadDataPrivacyRequest(context.Context, *types.DataPrivacyRequest) bool
CanApproveDataPrivacyRequest(context.Context, *types.DataPrivacyRequest) bool
}
DataPrivacyService interface {
FindRequestByID(ctx context.Context, requestID uint64) (*types.DataPrivacyRequest, error)
FindRequests(context.Context, types.DataPrivacyRequestFilter) (types.DataPrivacyRequestSet, types.DataPrivacyRequestFilter, error)
CreateRequest(ctx context.Context, request *types.DataPrivacyRequest) (*types.DataPrivacyRequest, error)
UpdateRequestStatus(ctx context.Context, request *types.DataPrivacyRequest) (*types.DataPrivacyRequest, error)
FindRequestComments(ctx context.Context, filter types.DataPrivacyRequestCommentFilter) (rr types.DataPrivacyRequestCommentSet, f types.DataPrivacyRequestCommentFilter, err error)
CreateRequestComment(ctx context.Context, new *types.DataPrivacyRequestComment) (r *types.DataPrivacyRequestComment, err error)
}
)
func DataPrivacy(s store.Storer, ac dataPrivacyAccessController, al actionlog.Recorder, eb eventDispatcher) *dataPrivacy {
return &dataPrivacy{
actionlog: al,
ac: ac,
eventbus: eb,
store: s,
}
}
func (svc dataPrivacy) FindRequestByID(ctx context.Context, requestID uint64) (r *types.DataPrivacyRequest, err error) {
var (
raProps = &dataPrivacyActionProps{dataPrivacyRequest: &types.DataPrivacyRequest{ID: requestID}}
)
err = func() error {
if requestID == 0 {
return DataPrivacyErrInvalidID()
}
r, err = store.LookupDataPrivacyRequestByID(ctx, svc.store, requestID)
if r, err = svc.procRequest(ctx, r, err); err != nil {
return err
}
raProps.setDataPrivacyRequest(r)
if !svc.ac.CanReadDataPrivacyRequest(ctx, r) {
return DataPrivacyErrNotAllowedToRead()
}
return nil
}()
return r, svc.recordAction(ctx, raProps, DataPrivacyActionLookup, err)
}
func (svc dataPrivacy) procRequest(_ context.Context, r *types.DataPrivacyRequest, err error) (*types.DataPrivacyRequest, error) {
if err != nil {
if errors.IsNotFound(err) {
return nil, DataPrivacyErrNotFound()
}
return nil, err
}
return r, nil
}
func (svc dataPrivacy) FindRequests(ctx context.Context, filter types.DataPrivacyRequestFilter) (rr types.DataPrivacyRequestSet, f types.DataPrivacyRequestFilter, err error) {
var (
raProps = &dataPrivacyActionProps{filter: &filter}
)
// For each fetched item, store backend will check if it is valid or not
filter.Check = func(req *types.DataPrivacyRequest) (bool, error) {
if !svc.ac.CanReadDataPrivacyRequest(ctx, req) {
return false, nil
}
return true, nil
}
err = func() error {
if !svc.ac.CanSearchDataPrivacyRequests(ctx) {
return DataPrivacyErrNotAllowedToSearch()
}
if rr, f, err = store.SearchDataPrivacyRequests(ctx, svc.store, filter); err != nil {
return err
}
return nil
}()
return rr, f, svc.recordAction(ctx, raProps, DataPrivacyActionSearch, err)
}
func (svc dataPrivacy) CreateRequest(ctx context.Context, new *types.DataPrivacyRequest) (r *types.DataPrivacyRequest, err error) {
var (
raProps = &dataPrivacyActionProps{new: new}
)
err = func() (err error) {
if len(new.Kind.String()) == 0 {
return DataPrivacyErrInvalidKind()
}
if !svc.ac.CanCreateDataPrivacyRequest(ctx) {
return DataPrivacyErrNotAllowedToCreate()
}
if err = svc.eventbus.WaitFor(ctx, event.DataPrivacyRequestBeforeCreate(new, r)); err != nil {
return
}
new.ID = nextID()
new.Status = types.RequestStatusPending
new.RequestedAt = *now()
new.RequestedBy = a.GetIdentityFromContext(ctx).Identity()
new.CreatedAt = *now()
if err = store.CreateDataPrivacyRequest(ctx, svc.store, new); err != nil {
return
}
r = new
svc.eventbus.Dispatch(ctx, event.DataPrivacyRequestAfterCreate(new, r))
return
}()
return r, svc.recordAction(ctx, raProps, DataPrivacyActionCreate, err)
}
func (svc dataPrivacy) UpdateRequestStatus(ctx context.Context, upd *types.DataPrivacyRequest) (r *types.DataPrivacyRequest, err error) {
var (
raProps = &dataPrivacyActionProps{update: upd}
)
err = func() (err error) {
if upd.ID == 0 {
return DataPrivacyErrInvalidID()
}
if len(upd.Status.String()) == 0 {
return DataPrivacyErrInvalidStatus()
}
if upd.Status == types.RequestStatusPending {
return DataPrivacyErrInvalidStatus()
}
if upd.Status == types.RequestStatusApproved || upd.Status == types.RequestStatusRejected {
if !svc.ac.CanApproveDataPrivacyRequest(ctx, upd) {
return DataPrivacyErrNotAllowedToApprove()
}
}
if r, err = store.LookupDataPrivacyRequestByID(ctx, svc.store, upd.ID); err != nil {
return
}
raProps.setDataPrivacyRequest(r)
if err = svc.eventbus.WaitFor(ctx, event.DataPrivacyRequestBeforeUpdate(upd, r)); err != nil {
return
}
r.Status = upd.Status
r.CompletedAt = now()
r.CompletedBy = a.GetIdentityFromContext(ctx).Identity()
r.UpdatedAt = now()
// Assign changed values
if err = store.UpdateDataPrivacyRequest(ctx, svc.store, r); err != nil {
return err
}
svc.eventbus.Dispatch(ctx, event.DataPrivacyRequestAfterUpdate(upd, r))
return nil
}()
return r, svc.recordAction(ctx, raProps, DataPrivacyActionApprove, err)
}
func (svc dataPrivacy) FindRequestComments(ctx context.Context, filter types.DataPrivacyRequestCommentFilter) (rr types.DataPrivacyRequestCommentSet, f types.DataPrivacyRequestCommentFilter, err error) {
err = func() error {
if rr, f, err = store.SearchDataPrivacyRequestComments(ctx, svc.store, filter); err != nil {
return err
}
return nil
}()
return rr, f, err
}
func (svc dataPrivacy) CreateRequestComment(ctx context.Context, new *types.DataPrivacyRequestComment) (r *types.DataPrivacyRequestComment, err error) {
err = func() (err error) {
_, err = svc.FindRequestByID(ctx, new.RequestID)
if err != nil {
return
}
new.ID = nextID()
new.CreatedBy = a.GetIdentityFromContext(ctx).Identity()
new.CreatedAt = *now()
if err = store.CreateDataPrivacyRequestComment(ctx, svc.store, new); err != nil {
return
}
r = new
return
}()
return r, err
}
+706
View File
@@ -0,0 +1,706 @@
package service
// This file is auto-generated.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
// Definitions file that controls how this file is generated:
// system/service/data_privacy_request_actions.yaml
import (
"context"
"fmt"
"github.com/cortezaproject/corteza-server/pkg/actionlog"
"github.com/cortezaproject/corteza-server/pkg/errors"
"github.com/cortezaproject/corteza-server/pkg/locale"
"github.com/cortezaproject/corteza-server/system/types"
"strings"
"time"
)
type (
dataPrivacyActionProps struct {
dataPrivacyRequest *types.DataPrivacyRequest
new *types.DataPrivacyRequest
update *types.DataPrivacyRequest
filter *types.DataPrivacyRequestFilter
}
dataPrivacyAction struct {
timestamp time.Time
resource string
action string
log string
severity actionlog.Severity
// prefix for error when action fails
errorMessage string
props *dataPrivacyActionProps
}
dataPrivacyLogMetaKey struct{}
dataPrivacyPropsMetaKey struct{}
)
var (
// just a placeholder to cover template cases w/o fmt package use
_ = fmt.Println
)
// *********************************************************************************************************************
// *********************************************************************************************************************
// Props methods
// setDataPrivacyRequest updates dataPrivacyActionProps's dataPrivacyRequest
//
// Allows method chaining
//
// This function is auto-generated.
//
func (p *dataPrivacyActionProps) setDataPrivacyRequest(dataPrivacyRequest *types.DataPrivacyRequest) *dataPrivacyActionProps {
p.dataPrivacyRequest = dataPrivacyRequest
return p
}
// setNew updates dataPrivacyActionProps's new
//
// Allows method chaining
//
// This function is auto-generated.
//
func (p *dataPrivacyActionProps) setNew(new *types.DataPrivacyRequest) *dataPrivacyActionProps {
p.new = new
return p
}
// setUpdate updates dataPrivacyActionProps's update
//
// Allows method chaining
//
// This function is auto-generated.
//
func (p *dataPrivacyActionProps) setUpdate(update *types.DataPrivacyRequest) *dataPrivacyActionProps {
p.update = update
return p
}
// setFilter updates dataPrivacyActionProps's filter
//
// Allows method chaining
//
// This function is auto-generated.
//
func (p *dataPrivacyActionProps) setFilter(filter *types.DataPrivacyRequestFilter) *dataPrivacyActionProps {
p.filter = filter
return p
}
// Serialize converts dataPrivacyActionProps to actionlog.Meta
//
// This function is auto-generated.
//
func (p dataPrivacyActionProps) Serialize() actionlog.Meta {
var (
m = make(actionlog.Meta)
)
if p.dataPrivacyRequest != nil {
m.Set("dataPrivacyRequest.kind", p.dataPrivacyRequest.Kind, true)
m.Set("dataPrivacyRequest.ID", p.dataPrivacyRequest.ID, true)
}
if p.new != nil {
m.Set("new.kind", p.new.Kind, true)
m.Set("new.ID", p.new.ID, true)
}
if p.update != nil {
m.Set("update.kind", p.update.Kind, true)
m.Set("update.ID", p.update.ID, true)
}
if p.filter != nil {
m.Set("filter.kind", p.filter.Kind, true)
m.Set("filter.sort", p.filter.Sort, true)
}
return m
}
// tr translates string and replaces meta value placeholder with values
//
// This function is auto-generated.
//
func (p dataPrivacyActionProps) Format(in string, err error) string {
var (
pairs = []string{"{{err}}"}
// first non-empty string
fns = func(ii ...interface{}) string {
for _, i := range ii {
if s := fmt.Sprintf("%v", i); len(s) > 0 {
return s
}
}
return ""
}
)
if err != nil {
pairs = append(pairs, err.Error())
} else {
pairs = append(pairs, "nil")
}
if p.dataPrivacyRequest != nil {
// replacement for "{{dataPrivacyRequest}}" (in order how fields are defined)
pairs = append(
pairs,
"{{dataPrivacyRequest}}",
fns(
p.dataPrivacyRequest.Kind,
p.dataPrivacyRequest.ID,
),
)
pairs = append(pairs, "{{dataPrivacyRequest.kind}}", fns(p.dataPrivacyRequest.Kind))
pairs = append(pairs, "{{dataPrivacyRequest.ID}}", fns(p.dataPrivacyRequest.ID))
}
if p.new != nil {
// replacement for "{{new}}" (in order how fields are defined)
pairs = append(
pairs,
"{{new}}",
fns(
p.new.Kind,
p.new.ID,
),
)
pairs = append(pairs, "{{new.kind}}", fns(p.new.Kind))
pairs = append(pairs, "{{new.ID}}", fns(p.new.ID))
}
if p.update != nil {
// replacement for "{{update}}" (in order how fields are defined)
pairs = append(
pairs,
"{{update}}",
fns(
p.update.Kind,
p.update.ID,
),
)
pairs = append(pairs, "{{update.kind}}", fns(p.update.Kind))
pairs = append(pairs, "{{update.ID}}", fns(p.update.ID))
}
if p.filter != nil {
// replacement for "{{filter}}" (in order how fields are defined)
pairs = append(
pairs,
"{{filter}}",
fns(
p.filter.Kind,
p.filter.Sort,
),
)
pairs = append(pairs, "{{filter.kind}}", fns(p.filter.Kind))
pairs = append(pairs, "{{filter.sort}}", fns(p.filter.Sort))
}
return strings.NewReplacer(pairs...).Replace(in)
}
// *********************************************************************************************************************
// *********************************************************************************************************************
// Action methods
// String returns loggable description as string
//
// This function is auto-generated.
//
func (a *dataPrivacyAction) String() string {
var props = &dataPrivacyActionProps{}
if a.props != nil {
props = a.props
}
return props.Format(a.log, nil)
}
func (e *dataPrivacyAction) ToAction() *actionlog.Action {
return &actionlog.Action{
Resource: e.resource,
Action: e.action,
Severity: e.severity,
Description: e.String(),
Meta: e.props.Serialize(),
}
}
// *********************************************************************************************************************
// *********************************************************************************************************************
// Action constructors
// DataPrivacyActionSearch returns "system:data-privacy-request.search" action
//
// This function is auto-generated.
//
func DataPrivacyActionSearch(props ...*dataPrivacyActionProps) *dataPrivacyAction {
a := &dataPrivacyAction{
timestamp: time.Now(),
resource: "system:data-privacy-request",
action: "search",
log: "searched for data privacy requests",
severity: actionlog.Info,
}
if len(props) > 0 {
a.props = props[0]
}
return a
}
// DataPrivacyActionLookup returns "system:data-privacy-request.lookup" action
//
// This function is auto-generated.
//
func DataPrivacyActionLookup(props ...*dataPrivacyActionProps) *dataPrivacyAction {
a := &dataPrivacyAction{
timestamp: time.Now(),
resource: "system:data-privacy-request",
action: "lookup",
log: "looked-up for a {{dataPrivacyRequest}}",
severity: actionlog.Info,
}
if len(props) > 0 {
a.props = props[0]
}
return a
}
// DataPrivacyActionCreate returns "system:data-privacy-request.create" action
//
// This function is auto-generated.
//
func DataPrivacyActionCreate(props ...*dataPrivacyActionProps) *dataPrivacyAction {
a := &dataPrivacyAction{
timestamp: time.Now(),
resource: "system:data-privacy-request",
action: "create",
log: "created {{dataPrivacyRequest}}",
severity: actionlog.Notice,
}
if len(props) > 0 {
a.props = props[0]
}
return a
}
// DataPrivacyActionUpdate returns "system:data-privacy-request.update" action
//
// This function is auto-generated.
//
func DataPrivacyActionUpdate(props ...*dataPrivacyActionProps) *dataPrivacyAction {
a := &dataPrivacyAction{
timestamp: time.Now(),
resource: "system:data-privacy-request",
action: "update",
log: "updated {{dataPrivacyRequest}}",
severity: actionlog.Notice,
}
if len(props) > 0 {
a.props = props[0]
}
return a
}
// DataPrivacyActionApprove returns "system:data-privacy-request.approve" action
//
// This function is auto-generated.
//
func DataPrivacyActionApprove(props ...*dataPrivacyActionProps) *dataPrivacyAction {
a := &dataPrivacyAction{
timestamp: time.Now(),
resource: "system:data-privacy-request",
action: "approve",
log: "approved {{dataPrivacyRequest}}",
severity: actionlog.Notice,
}
if len(props) > 0 {
a.props = props[0]
}
return a
}
// *********************************************************************************************************************
// *********************************************************************************************************************
// Error constructors
// DataPrivacyErrGeneric returns "system:data-privacy-request.generic" as *errors.Error
//
//
// This function is auto-generated.
//
func DataPrivacyErrGeneric(mm ...*dataPrivacyActionProps) *errors.Error {
var p = &dataPrivacyActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("failed to complete request due to internal error", nil),
errors.Meta("type", "generic"),
errors.Meta("resource", "system:data-privacy-request"),
// action log entry; no formatting, it will be applied inside recordAction fn.
errors.Meta(dataPrivacyLogMetaKey{}, "{err}"),
errors.Meta(dataPrivacyPropsMetaKey{}, p),
// translation namespace & key
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
errors.Meta(locale.ErrorMetaKey{}, "dataPrivacy.errors.generic"),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// DataPrivacyErrNotFound returns "system:data-privacy-request.notFound" as *errors.Error
//
//
// This function is auto-generated.
//
func DataPrivacyErrNotFound(mm ...*dataPrivacyActionProps) *errors.Error {
var p = &dataPrivacyActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("data privacy request not found", nil),
errors.Meta("type", "notFound"),
errors.Meta("resource", "system:data-privacy-request"),
errors.Meta(dataPrivacyPropsMetaKey{}, p),
// translation namespace & key
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
errors.Meta(locale.ErrorMetaKey{}, "dataPrivacy.errors.notFound"),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// DataPrivacyErrInvalidID returns "system:data-privacy-request.invalidID" as *errors.Error
//
//
// This function is auto-generated.
//
func DataPrivacyErrInvalidID(mm ...*dataPrivacyActionProps) *errors.Error {
var p = &dataPrivacyActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("invalid ID", nil),
errors.Meta("type", "invalidID"),
errors.Meta("resource", "system:data-privacy-request"),
errors.Meta(dataPrivacyPropsMetaKey{}, p),
// translation namespace & key
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
errors.Meta(locale.ErrorMetaKey{}, "dataPrivacy.errors.invalidID"),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// DataPrivacyErrInvalidKind returns "system:data-privacy-request.invalidKind" as *errors.Error
//
//
// This function is auto-generated.
//
func DataPrivacyErrInvalidKind(mm ...*dataPrivacyActionProps) *errors.Error {
var p = &dataPrivacyActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("invalid Kind", nil),
errors.Meta("type", "invalidKind"),
errors.Meta("resource", "system:data-privacy-request"),
errors.Meta(dataPrivacyPropsMetaKey{}, p),
// translation namespace & key
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
errors.Meta(locale.ErrorMetaKey{}, "dataPrivacy.errors.invalidKind"),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// DataPrivacyErrInvalidStatus returns "system:data-privacy-request.invalidStatus" as *errors.Error
//
//
// This function is auto-generated.
//
func DataPrivacyErrInvalidStatus(mm ...*dataPrivacyActionProps) *errors.Error {
var p = &dataPrivacyActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("invalid Status", nil),
errors.Meta("type", "invalidStatus"),
errors.Meta("resource", "system:data-privacy-request"),
errors.Meta(dataPrivacyPropsMetaKey{}, p),
// translation namespace & key
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
errors.Meta(locale.ErrorMetaKey{}, "dataPrivacy.errors.invalidStatus"),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// DataPrivacyErrNotAllowedToRead returns "system:data-privacy-request.notAllowedToRead" as *errors.Error
//
//
// This function is auto-generated.
//
func DataPrivacyErrNotAllowedToRead(mm ...*dataPrivacyActionProps) *errors.Error {
var p = &dataPrivacyActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("not allowed to read this data privacy request", nil),
errors.Meta("type", "notAllowedToRead"),
errors.Meta("resource", "system:data-privacy-request"),
// action log entry; no formatting, it will be applied inside recordAction fn.
errors.Meta(dataPrivacyLogMetaKey{}, "failed to read data privacy request; insufficient permissions"),
errors.Meta(dataPrivacyPropsMetaKey{}, p),
// translation namespace & key
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
errors.Meta(locale.ErrorMetaKey{}, "dataPrivacy.errors.notAllowedToRead"),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// DataPrivacyErrNotAllowedToSearch returns "system:data-privacy-request.notAllowedToSearch" as *errors.Error
//
//
// This function is auto-generated.
//
func DataPrivacyErrNotAllowedToSearch(mm ...*dataPrivacyActionProps) *errors.Error {
var p = &dataPrivacyActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("not allowed to search or list data privacy request", nil),
errors.Meta("type", "notAllowedToSearch"),
errors.Meta("resource", "system:data-privacy-request"),
// action log entry; no formatting, it will be applied inside recordAction fn.
errors.Meta(dataPrivacyLogMetaKey{}, "failed to search or list data privacy requests; insufficient permissions"),
errors.Meta(dataPrivacyPropsMetaKey{}, p),
// translation namespace & key
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
errors.Meta(locale.ErrorMetaKey{}, "dataPrivacy.errors.notAllowedToSearch"),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// DataPrivacyErrNotAllowedToCreate returns "system:data-privacy-request.notAllowedToCreate" as *errors.Error
//
//
// This function is auto-generated.
//
func DataPrivacyErrNotAllowedToCreate(mm ...*dataPrivacyActionProps) *errors.Error {
var p = &dataPrivacyActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("not allowed to create data privacy request", nil),
errors.Meta("type", "notAllowedToCreate"),
errors.Meta("resource", "system:data-privacy-request"),
// action log entry; no formatting, it will be applied inside recordAction fn.
errors.Meta(dataPrivacyLogMetaKey{}, "failed to create data privacy request; insufficient permissions"),
errors.Meta(dataPrivacyPropsMetaKey{}, p),
// translation namespace & key
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
errors.Meta(locale.ErrorMetaKey{}, "dataPrivacy.errors.notAllowedToCreate"),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// DataPrivacyErrNotAllowedToApprove returns "system:data-privacy-request.notAllowedToApprove" as *errors.Error
//
//
// This function is auto-generated.
//
func DataPrivacyErrNotAllowedToApprove(mm ...*dataPrivacyActionProps) *errors.Error {
var p = &dataPrivacyActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("not allowed to approve/reject data privacy request", nil),
errors.Meta("type", "notAllowedToApprove"),
errors.Meta("resource", "system:data-privacy-request"),
// action log entry; no formatting, it will be applied inside recordAction fn.
errors.Meta(dataPrivacyLogMetaKey{}, "failed to approve/reject data privacy request; insufficient permissions"),
errors.Meta(dataPrivacyPropsMetaKey{}, p),
// translation namespace & key
errors.Meta(locale.ErrorMetaNamespace{}, "system"),
errors.Meta(locale.ErrorMetaKey{}, "dataPrivacy.errors.notAllowedToApprove"),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// *********************************************************************************************************************
// *********************************************************************************************************************
// recordAction is a service helper function wraps function that can return error
//
// It will wrap unrecognized/internal errors with generic errors.
//
// This function is auto-generated.
//
func (svc dataPrivacy) recordAction(ctx context.Context, props *dataPrivacyActionProps, actionFn func(...*dataPrivacyActionProps) *dataPrivacyAction, err error) error {
if svc.actionlog == nil || actionFn == nil {
// action log disabled or no action fn passed, return error as-is
return err
} else if err == nil {
// action completed w/o error, record it
svc.actionlog.Record(ctx, actionFn(props).ToAction())
return nil
}
a := actionFn(props).ToAction()
// Extracting error information and recording it as action
a.Error = err.Error()
switch c := err.(type) {
case *errors.Error:
m := c.Meta()
a.Error = err.Error()
a.Severity = actionlog.Severity(m.AsInt("severity"))
a.Description = props.Format(m.AsString(dataPrivacyLogMetaKey{}), err)
if p, has := m[dataPrivacyPropsMetaKey{}]; has {
a.Meta = p.(*dataPrivacyActionProps).Serialize()
}
svc.actionlog.Record(ctx, a)
default:
svc.actionlog.Record(ctx, a)
}
// Original error is passed on
return err
}
@@ -0,0 +1,79 @@
# List of loggable service actions
resource: system:data-privacy-request
service: dataPrivacy
# Default sensitivity for actions
defaultActionSeverity: notice
# default severity for errors
defaultErrorSeverity: alert
import:
- github.com/cortezaproject/corteza-server/system/types
props:
- name: dataPrivacyRequest
type: "*types.DataPrivacyRequest"
fields: [ kind, ID ]
- name: new
type: "*types.DataPrivacyRequest"
fields: [ kind, ID ]
- name: update
type: "*types.DataPrivacyRequest"
fields: [ kind, ID ]
- name: filter
type: "*types.DataPrivacyRequestFilter"
fields: [ kind, sort ]
actions:
- action: search
log: "searched for data privacy requests"
severity: info
- action: lookup
log: "looked-up for a {{dataPrivacyRequest}}"
severity: info
- action: create
log: "created {{dataPrivacyRequest}}"
- action: update
log: "updated {{dataPrivacyRequest}}"
- action: approve
log: "approved {{dataPrivacyRequest}}"
errors:
- error: notFound
message: "data privacy request not found"
severity: warning
- error: invalidID
message: "invalid ID"
severity: warning
- error: invalidKind
message: "invalid Kind"
severity: warning
- error: invalidStatus
message: "invalid Status"
severity: warning
- error: notAllowedToRead
message: "not allowed to read this data privacy request"
log: "failed to read data privacy request; insufficient permissions"
- error: notAllowedToSearch
message: "not allowed to search or list data privacy request"
log: "failed to search or list data privacy requests; insufficient permissions"
- error: notAllowedToCreate
message: "not allowed to create data privacy request"
log: "failed to create data privacy request; insufficient permissions"
- error: notAllowedToApprove
message: "not allowed to approve/reject data privacy request"
log: "failed to approve/reject data privacy request; insufficient permissions"
@@ -0,0 +1,19 @@
package event
import (
"github.com/cortezaproject/corteza-server/pkg/eventbus"
)
var _ = eventbus.ConstraintMaker
// Match returns false if given conditions do not match event & resource internals
func (res dataPrivacyRequestBase) Match(c eventbus.ConstraintMatcher) bool {
// By default we match no mather what kind of constraints we receive
//
// Function will be called multiple times - once for every trigger constraint
// All should match (return true):
// constraint#1 AND constraint#2 AND constraint#3 ...
//
// When there are multiple values, Match() can decide how to treat them (OR, AND...)
return true
}
+468
View File
@@ -206,6 +206,65 @@ type (
*authClientBase
}
// dataPrivacyRequestBase
//
// This type is auto-generated.
dataPrivacyRequestBase struct {
immutable bool
dataPrivacyRequest *types.DataPrivacyRequest
oldDataPrivacyRequest *types.DataPrivacyRequest
invoker auth.Identifiable
}
// dataPrivacyRequestOnManual
//
// This type is auto-generated.
dataPrivacyRequestOnManual struct {
*dataPrivacyRequestBase
}
// dataPrivacyRequestBeforeCreate
//
// This type is auto-generated.
dataPrivacyRequestBeforeCreate struct {
*dataPrivacyRequestBase
}
// dataPrivacyRequestBeforeUpdate
//
// This type is auto-generated.
dataPrivacyRequestBeforeUpdate struct {
*dataPrivacyRequestBase
}
// dataPrivacyRequestBeforeDelete
//
// This type is auto-generated.
dataPrivacyRequestBeforeDelete struct {
*dataPrivacyRequestBase
}
// dataPrivacyRequestAfterCreate
//
// This type is auto-generated.
dataPrivacyRequestAfterCreate struct {
*dataPrivacyRequestBase
}
// dataPrivacyRequestAfterUpdate
//
// This type is auto-generated.
dataPrivacyRequestAfterUpdate struct {
*dataPrivacyRequestBase
}
// dataPrivacyRequestAfterDelete
//
// This type is auto-generated.
dataPrivacyRequestAfterDelete struct {
*dataPrivacyRequestBase
}
// mailBase
//
// This type is auto-generated.
@@ -1733,6 +1792,415 @@ func (res *authClientBase) DecodeVars(vars *expr.Vars) (err error) {
return
}
// ResourceType returns "system:data-privacy-request"
//
// This function is auto-generated.
func (dataPrivacyRequestBase) ResourceType() string {
return "system:data-privacy-request"
}
// EventType on dataPrivacyRequestOnManual returns "onManual"
//
// This function is auto-generated.
func (dataPrivacyRequestOnManual) EventType() string {
return "onManual"
}
// EventType on dataPrivacyRequestBeforeCreate returns "beforeCreate"
//
// This function is auto-generated.
func (dataPrivacyRequestBeforeCreate) EventType() string {
return "beforeCreate"
}
// EventType on dataPrivacyRequestBeforeUpdate returns "beforeUpdate"
//
// This function is auto-generated.
func (dataPrivacyRequestBeforeUpdate) EventType() string {
return "beforeUpdate"
}
// EventType on dataPrivacyRequestBeforeDelete returns "beforeDelete"
//
// This function is auto-generated.
func (dataPrivacyRequestBeforeDelete) EventType() string {
return "beforeDelete"
}
// EventType on dataPrivacyRequestAfterCreate returns "afterCreate"
//
// This function is auto-generated.
func (dataPrivacyRequestAfterCreate) EventType() string {
return "afterCreate"
}
// EventType on dataPrivacyRequestAfterUpdate returns "afterUpdate"
//
// This function is auto-generated.
func (dataPrivacyRequestAfterUpdate) EventType() string {
return "afterUpdate"
}
// EventType on dataPrivacyRequestAfterDelete returns "afterDelete"
//
// This function is auto-generated.
func (dataPrivacyRequestAfterDelete) EventType() string {
return "afterDelete"
}
// DataPrivacyRequestOnManual creates onManual for system:data-privacy-request resource
//
// This function is auto-generated.
func DataPrivacyRequestOnManual(
argDataPrivacyRequest *types.DataPrivacyRequest,
argOldDataPrivacyRequest *types.DataPrivacyRequest,
) *dataPrivacyRequestOnManual {
return &dataPrivacyRequestOnManual{
dataPrivacyRequestBase: &dataPrivacyRequestBase{
immutable: false,
dataPrivacyRequest: argDataPrivacyRequest,
oldDataPrivacyRequest: argOldDataPrivacyRequest,
},
}
}
// DataPrivacyRequestOnManualImmutable creates onManual for system:data-privacy-request resource
//
// None of the arguments will be mutable!
//
// This function is auto-generated.
func DataPrivacyRequestOnManualImmutable(
argDataPrivacyRequest *types.DataPrivacyRequest,
argOldDataPrivacyRequest *types.DataPrivacyRequest,
) *dataPrivacyRequestOnManual {
return &dataPrivacyRequestOnManual{
dataPrivacyRequestBase: &dataPrivacyRequestBase{
immutable: true,
dataPrivacyRequest: argDataPrivacyRequest,
oldDataPrivacyRequest: argOldDataPrivacyRequest,
},
}
}
// DataPrivacyRequestBeforeCreate creates beforeCreate for system:data-privacy-request resource
//
// This function is auto-generated.
func DataPrivacyRequestBeforeCreate(
argDataPrivacyRequest *types.DataPrivacyRequest,
argOldDataPrivacyRequest *types.DataPrivacyRequest,
) *dataPrivacyRequestBeforeCreate {
return &dataPrivacyRequestBeforeCreate{
dataPrivacyRequestBase: &dataPrivacyRequestBase{
immutable: false,
dataPrivacyRequest: argDataPrivacyRequest,
oldDataPrivacyRequest: argOldDataPrivacyRequest,
},
}
}
// DataPrivacyRequestBeforeCreateImmutable creates beforeCreate for system:data-privacy-request resource
//
// None of the arguments will be mutable!
//
// This function is auto-generated.
func DataPrivacyRequestBeforeCreateImmutable(
argDataPrivacyRequest *types.DataPrivacyRequest,
argOldDataPrivacyRequest *types.DataPrivacyRequest,
) *dataPrivacyRequestBeforeCreate {
return &dataPrivacyRequestBeforeCreate{
dataPrivacyRequestBase: &dataPrivacyRequestBase{
immutable: true,
dataPrivacyRequest: argDataPrivacyRequest,
oldDataPrivacyRequest: argOldDataPrivacyRequest,
},
}
}
// DataPrivacyRequestBeforeUpdate creates beforeUpdate for system:data-privacy-request resource
//
// This function is auto-generated.
func DataPrivacyRequestBeforeUpdate(
argDataPrivacyRequest *types.DataPrivacyRequest,
argOldDataPrivacyRequest *types.DataPrivacyRequest,
) *dataPrivacyRequestBeforeUpdate {
return &dataPrivacyRequestBeforeUpdate{
dataPrivacyRequestBase: &dataPrivacyRequestBase{
immutable: false,
dataPrivacyRequest: argDataPrivacyRequest,
oldDataPrivacyRequest: argOldDataPrivacyRequest,
},
}
}
// DataPrivacyRequestBeforeUpdateImmutable creates beforeUpdate for system:data-privacy-request resource
//
// None of the arguments will be mutable!
//
// This function is auto-generated.
func DataPrivacyRequestBeforeUpdateImmutable(
argDataPrivacyRequest *types.DataPrivacyRequest,
argOldDataPrivacyRequest *types.DataPrivacyRequest,
) *dataPrivacyRequestBeforeUpdate {
return &dataPrivacyRequestBeforeUpdate{
dataPrivacyRequestBase: &dataPrivacyRequestBase{
immutable: true,
dataPrivacyRequest: argDataPrivacyRequest,
oldDataPrivacyRequest: argOldDataPrivacyRequest,
},
}
}
// DataPrivacyRequestBeforeDelete creates beforeDelete for system:data-privacy-request resource
//
// This function is auto-generated.
func DataPrivacyRequestBeforeDelete(
argDataPrivacyRequest *types.DataPrivacyRequest,
argOldDataPrivacyRequest *types.DataPrivacyRequest,
) *dataPrivacyRequestBeforeDelete {
return &dataPrivacyRequestBeforeDelete{
dataPrivacyRequestBase: &dataPrivacyRequestBase{
immutable: false,
dataPrivacyRequest: argDataPrivacyRequest,
oldDataPrivacyRequest: argOldDataPrivacyRequest,
},
}
}
// DataPrivacyRequestBeforeDeleteImmutable creates beforeDelete for system:data-privacy-request resource
//
// None of the arguments will be mutable!
//
// This function is auto-generated.
func DataPrivacyRequestBeforeDeleteImmutable(
argDataPrivacyRequest *types.DataPrivacyRequest,
argOldDataPrivacyRequest *types.DataPrivacyRequest,
) *dataPrivacyRequestBeforeDelete {
return &dataPrivacyRequestBeforeDelete{
dataPrivacyRequestBase: &dataPrivacyRequestBase{
immutable: true,
dataPrivacyRequest: argDataPrivacyRequest,
oldDataPrivacyRequest: argOldDataPrivacyRequest,
},
}
}
// DataPrivacyRequestAfterCreate creates afterCreate for system:data-privacy-request resource
//
// This function is auto-generated.
func DataPrivacyRequestAfterCreate(
argDataPrivacyRequest *types.DataPrivacyRequest,
argOldDataPrivacyRequest *types.DataPrivacyRequest,
) *dataPrivacyRequestAfterCreate {
return &dataPrivacyRequestAfterCreate{
dataPrivacyRequestBase: &dataPrivacyRequestBase{
immutable: false,
dataPrivacyRequest: argDataPrivacyRequest,
oldDataPrivacyRequest: argOldDataPrivacyRequest,
},
}
}
// DataPrivacyRequestAfterCreateImmutable creates afterCreate for system:data-privacy-request resource
//
// None of the arguments will be mutable!
//
// This function is auto-generated.
func DataPrivacyRequestAfterCreateImmutable(
argDataPrivacyRequest *types.DataPrivacyRequest,
argOldDataPrivacyRequest *types.DataPrivacyRequest,
) *dataPrivacyRequestAfterCreate {
return &dataPrivacyRequestAfterCreate{
dataPrivacyRequestBase: &dataPrivacyRequestBase{
immutable: true,
dataPrivacyRequest: argDataPrivacyRequest,
oldDataPrivacyRequest: argOldDataPrivacyRequest,
},
}
}
// DataPrivacyRequestAfterUpdate creates afterUpdate for system:data-privacy-request resource
//
// This function is auto-generated.
func DataPrivacyRequestAfterUpdate(
argDataPrivacyRequest *types.DataPrivacyRequest,
argOldDataPrivacyRequest *types.DataPrivacyRequest,
) *dataPrivacyRequestAfterUpdate {
return &dataPrivacyRequestAfterUpdate{
dataPrivacyRequestBase: &dataPrivacyRequestBase{
immutable: false,
dataPrivacyRequest: argDataPrivacyRequest,
oldDataPrivacyRequest: argOldDataPrivacyRequest,
},
}
}
// DataPrivacyRequestAfterUpdateImmutable creates afterUpdate for system:data-privacy-request resource
//
// None of the arguments will be mutable!
//
// This function is auto-generated.
func DataPrivacyRequestAfterUpdateImmutable(
argDataPrivacyRequest *types.DataPrivacyRequest,
argOldDataPrivacyRequest *types.DataPrivacyRequest,
) *dataPrivacyRequestAfterUpdate {
return &dataPrivacyRequestAfterUpdate{
dataPrivacyRequestBase: &dataPrivacyRequestBase{
immutable: true,
dataPrivacyRequest: argDataPrivacyRequest,
oldDataPrivacyRequest: argOldDataPrivacyRequest,
},
}
}
// DataPrivacyRequestAfterDelete creates afterDelete for system:data-privacy-request resource
//
// This function is auto-generated.
func DataPrivacyRequestAfterDelete(
argDataPrivacyRequest *types.DataPrivacyRequest,
argOldDataPrivacyRequest *types.DataPrivacyRequest,
) *dataPrivacyRequestAfterDelete {
return &dataPrivacyRequestAfterDelete{
dataPrivacyRequestBase: &dataPrivacyRequestBase{
immutable: false,
dataPrivacyRequest: argDataPrivacyRequest,
oldDataPrivacyRequest: argOldDataPrivacyRequest,
},
}
}
// DataPrivacyRequestAfterDeleteImmutable creates afterDelete for system:data-privacy-request resource
//
// None of the arguments will be mutable!
//
// This function is auto-generated.
func DataPrivacyRequestAfterDeleteImmutable(
argDataPrivacyRequest *types.DataPrivacyRequest,
argOldDataPrivacyRequest *types.DataPrivacyRequest,
) *dataPrivacyRequestAfterDelete {
return &dataPrivacyRequestAfterDelete{
dataPrivacyRequestBase: &dataPrivacyRequestBase{
immutable: true,
dataPrivacyRequest: argDataPrivacyRequest,
oldDataPrivacyRequest: argOldDataPrivacyRequest,
},
}
}
// SetDataPrivacyRequest sets new dataPrivacyRequest value
//
// This function is auto-generated.
func (res *dataPrivacyRequestBase) SetDataPrivacyRequest(argDataPrivacyRequest *types.DataPrivacyRequest) {
res.dataPrivacyRequest = argDataPrivacyRequest
}
// DataPrivacyRequest returns dataPrivacyRequest
//
// This function is auto-generated.
func (res dataPrivacyRequestBase) DataPrivacyRequest() *types.DataPrivacyRequest {
return res.dataPrivacyRequest
}
// OldDataPrivacyRequest returns oldDataPrivacyRequest
//
// This function is auto-generated.
func (res dataPrivacyRequestBase) OldDataPrivacyRequest() *types.DataPrivacyRequest {
return res.oldDataPrivacyRequest
}
// SetInvoker sets new invoker value
//
// This function is auto-generated.
func (res *dataPrivacyRequestBase) SetInvoker(argInvoker auth.Identifiable) {
res.invoker = argInvoker
}
// Invoker returns invoker
//
// This function is auto-generated.
func (res dataPrivacyRequestBase) Invoker() auth.Identifiable {
return res.invoker
}
// Encode internal data to be passed as event params & arguments to triggered Corredor script
func (res dataPrivacyRequestBase) Encode() (args map[string][]byte, err error) {
args = make(map[string][]byte)
if args["dataPrivacyRequest"], err = json.Marshal(res.dataPrivacyRequest); err != nil {
return nil, err
}
if args["oldDataPrivacyRequest"], err = json.Marshal(res.oldDataPrivacyRequest); err != nil {
return nil, err
}
if args["invoker"], err = json.Marshal(res.invoker); err != nil {
return nil, err
}
return
}
// Encode internal data to be passed as event params & arguments to workflow
func (res dataPrivacyRequestBase) EncodeVars() (out *expr.Vars, err error) {
out = &expr.Vars{}
var v expr.TypedValue
// Could not found expression-type counterpart for *types.DataPrivacyRequest
// Could not found expression-type counterpart for *types.DataPrivacyRequest
// Could not found expression-type counterpart for auth.Identifiable
_ = v
return
}
// Decode return values from Corredor script into struct props
func (res *dataPrivacyRequestBase) Decode(results map[string][]byte) (err error) {
if res.immutable {
// Respect immutability
return
}
if res.dataPrivacyRequest != nil {
if r, ok := results["result"]; ok && len(results) == 1 {
if err = json.Unmarshal(r, res.dataPrivacyRequest); err != nil {
return
}
}
}
if res.dataPrivacyRequest != nil {
if r, ok := results["dataPrivacyRequest"]; ok {
if err = json.Unmarshal(r, res.dataPrivacyRequest); err != nil {
return
}
}
}
// Do not decode oldDataPrivacyRequest; marked as immutable
if res.invoker != nil {
if r, ok := results["invoker"]; ok {
if err = json.Unmarshal(r, res.invoker); err != nil {
return
}
}
}
return
}
func (res *dataPrivacyRequestBase) DecodeVars(vars *expr.Vars) (err error) {
if res.immutable {
// Respect immutability
return
}
// Could not find expression-type counterpart for *types.DataPrivacyRequest
// oldDataPrivacyRequest marked as immutable
// Could not find expression-type counterpart for auth.Identifiable
return
}
// ResourceType returns "system:mail"
//
// This function is auto-generated.
+12
View File
@@ -118,3 +118,15 @@ system:queue:
type: '*types.QueueMessage'
constraints:
- name: payload.queue
system:data-privacy-request:
on: ['manual']
ba: ['create', 'update', 'delete']
props:
- name: 'dataPrivacyRequest'
type: '*types.DataPrivacyRequest'
- name: 'oldDataPrivacyRequest'
type: '*types.DataPrivacyRequest'
immutable: true
constraints:
- name: role.name
+2
View File
@@ -89,6 +89,7 @@ var (
DefaultApigwProfiler *apigwProfiler
DefaultReport *report
primaryConnectionConfig *types.DalConnection
DefaultDataPrivacy *dataPrivacy
DefaultStatistics *statistics
@@ -213,6 +214,7 @@ func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, primaryCon
DefaultApigwRoute = Route()
DefaultApigwProfiler = Profiler()
DefaultApigwFilter = Filter()
DefaultDataPrivacy = DataPrivacy(DefaultStore, DefaultAccessControl, DefaultActionlog, eventbus.Service())
if err = initRoles(ctx, log.Named("rbac.roles"), c.RBAC, eventbus.Service(), rbac.Global()); err != nil {
return err
+132
View File
@@ -0,0 +1,132 @@
package types
import (
"time"
"github.com/cortezaproject/corteza-server/pkg/filter"
)
type (
DataPrivacyRequest struct {
ID uint64 `json:"requestID,string"`
Kind RequestKind `json:"kind"`
Status RequestStatus `json:"status"`
RequestedAt time.Time `json:"requestedAt,omitempty"`
RequestedBy uint64 `json:"requestedBy,string"`
CompletedAt *time.Time `json:"completedAt,omitempty"`
CompletedBy uint64 `json:"completedBy,string,omitempty" `
CreatedAt time.Time `json:"createdAt,omitempty"`
CreatedBy uint64 `json:"createdBy,string" `
UpdatedAt *time.Time `json:"updatedAt,omitempty"`
UpdatedBy uint64 `json:"updatedBy,string,omitempty"`
DeletedAt *time.Time `json:"deletedAt,omitempty"`
DeletedBy uint64 `json:"deletedBy,string,omitempty"`
}
DataPrivacyRequestFilter struct {
RequestID []uint64 `json:"requestID"`
RequestedBy []uint64 `json:"requestedBy"`
Query string `json:"query"`
Kind []string `json:"kind"`
Status []string `json:"status"`
// Check fn is called by store backend for each resource found function can
// modify the resource and return false if store should not return it
//
// Store then loads additional resources to satisfy the paging parameters
Check func(request *DataPrivacyRequest) (bool, error) `json:"-"`
// Standard helpers for paging and sorting
filter.Sorting
filter.Paging
}
DataPrivacyRequestComment struct {
ID uint64 `json:"commentID,string"`
RequestID uint64 `json:"requestID,string"`
Comment string `json:"comment"`
CreatedAt time.Time `json:"createdAt,omitempty"`
CreatedBy uint64 `json:"createdBy,string" `
UpdatedAt *time.Time `json:"updatedAt,omitempty"`
UpdatedBy uint64 `json:"updatedBy,string,omitempty"`
DeletedAt *time.Time `json:"deletedAt,omitempty"`
DeletedBy uint64 `json:"deletedBy,string,omitempty"`
}
DataPrivacyRequestCommentFilter struct {
RequestID []uint64 `json:"requestID"`
// Check fn is called by store backend for each resource found function can
// modify the resource and return false if store should not return it
//
// Store then loads additional resources to satisfy the paging parameters
Check func(request *DataPrivacyRequestComment) (bool, error) `json:"-"`
// Standard helpers for paging and sorting
filter.Sorting
filter.Paging
}
RequestStatus string
RequestKind string
)
const (
// RequestKindCorrect to correct module fields
RequestKindCorrect RequestKind = "correct"
// RequestKindDelete to delete module fields
RequestKindDelete RequestKind = "delete"
// RequestKindExport to export module fields
RequestKindExport RequestKind = "export"
// RequestStatusPending initially request will be in pending status
RequestStatusPending RequestStatus = "pending"
// RequestStatusCanceled owner of request has cancelled the request
RequestStatusCanceled RequestStatus = "canceled"
// RequestStatusApproved data officer has of request has cancelled the request
RequestStatusApproved RequestStatus = "approved"
// RequestStatusRejected data officer has denied the request
RequestStatusRejected RequestStatus = "rejected"
)
func CastToRequestKind(s string) RequestKind {
switch s {
case "correct":
return RequestKindCorrect
case "delete":
return RequestKindCorrect
case "export":
return RequestKindCorrect
default:
return ""
}
}
func (k RequestKind) String() string {
return string(k)
}
func CastToRequestStatus(s string) RequestStatus {
switch s {
case "pending":
return RequestStatusPending
case "canceled":
return RequestStatusCanceled
case "approved":
return RequestStatusApproved
case "rejected":
return RequestStatusRejected
default:
return ""
}
}
func (s RequestStatus) String() string {
return string(s)
}
+74 -12
View File
@@ -24,18 +24,20 @@ var (
)
const (
ApplicationResourceType = "corteza::system:application"
ApigwRouteResourceType = "corteza::system:apigw-route"
AuthClientResourceType = "corteza::system:auth-client"
QueueResourceType = "corteza::system:queue"
QueueMessageResourceType = "corteza::system:queue_message"
ReportResourceType = "corteza::system:report"
RoleResourceType = "corteza::system:role"
TemplateResourceType = "corteza::system:template"
UserResourceType = "corteza::system:user"
DalConnectionResourceType = "corteza::system:dal_connection"
DalSensitivityLevelResourceType = "corteza::system:dal_sensitivity_level"
ComponentResourceType = "corteza::system"
ApplicationResourceType = "corteza::system:application"
ApigwRouteResourceType = "corteza::system:apigw-route"
AuthClientResourceType = "corteza::system:auth-client"
DataPrivacyRequestResourceType = "corteza::system:data-privacy-request"
DataPrivacyRequestCommentResourceType = "corteza::system:data-privacy-request_comment"
QueueResourceType = "corteza::system:queue"
QueueMessageResourceType = "corteza::system:queue_message"
ReportResourceType = "corteza::system:report"
RoleResourceType = "corteza::system:role"
TemplateResourceType = "corteza::system:template"
UserResourceType = "corteza::system:user"
DalConnectionResourceType = "corteza::system:dal_connection"
DalSensitivityLevelResourceType = "corteza::system:dal_sensitivity_level"
ComponentResourceType = "corteza::system"
)
// RbacResource returns string representation of RBAC resource for Application by calling ApplicationRbacResource fn
@@ -128,6 +130,66 @@ func AuthClientRbacResourceTpl() string {
return "%s/%s"
}
// RbacResource returns string representation of RBAC resource for DataPrivacyRequest by calling DataPrivacyRequestRbacResource fn
//
// RBAC resource is in the corteza::system:data-privacy-request/... format
//
// This function is auto-generated
func (r DataPrivacyRequest) RbacResource() string {
return DataPrivacyRequestRbacResource(r.ID)
}
// DataPrivacyRequestRbacResource returns string representation of RBAC resource for DataPrivacyRequest
//
// RBAC resource is in the corteza::system:data-privacy-request/... format
//
// This function is auto-generated
func DataPrivacyRequestRbacResource(id uint64) string {
cpts := []interface{}{DataPrivacyRequestResourceType}
if id != 0 {
cpts = append(cpts, strconv.FormatUint(id, 10))
} else {
cpts = append(cpts, "*")
}
return fmt.Sprintf(DataPrivacyRequestRbacResourceTpl(), cpts...)
}
func DataPrivacyRequestRbacResourceTpl() string {
return "%s/%s"
}
// RbacResource returns string representation of RBAC resource for DataPrivacyRequestComment by calling DataPrivacyRequestCommentRbacResource fn
//
// RBAC resource is in the corteza::system:data-privacy-request_comment/... format
//
// This function is auto-generated
func (r DataPrivacyRequestComment) RbacResource() string {
return DataPrivacyRequestCommentRbacResource(r.ID)
}
// DataPrivacyRequestCommentRbacResource returns string representation of RBAC resource for DataPrivacyRequestComment
//
// RBAC resource is in the corteza::system:data-privacy-request_comment/... format
//
// This function is auto-generated
func DataPrivacyRequestCommentRbacResource(id uint64) string {
cpts := []interface{}{DataPrivacyRequestCommentResourceType}
if id != 0 {
cpts = append(cpts, strconv.FormatUint(id, 10))
} else {
cpts = append(cpts, "*")
}
return fmt.Sprintf(DataPrivacyRequestCommentRbacResourceTpl(), cpts...)
}
func DataPrivacyRequestCommentRbacResourceTpl() string {
return "%s/%s"
}
// RbacResource returns string representation of RBAC resource for Queue by calling QueueRbacResource fn
//
// RBAC resource is in the corteza::system:queue/... format
+122
View File
@@ -75,6 +75,16 @@ type (
// This type is auto-generated.
DalSensitivityLevelSet []*DalSensitivityLevel
// DataPrivacyRequestSet slice of DataPrivacyRequest
//
// This type is auto-generated.
DataPrivacyRequestSet []*DataPrivacyRequest
// DataPrivacyRequestCommentSet slice of DataPrivacyRequestComment
//
// This type is auto-generated.
DataPrivacyRequestCommentSet []*DataPrivacyRequestComment
// QueueSet slice of Queue
//
// This type is auto-generated.
@@ -750,6 +760,118 @@ func (set DalSensitivityLevelSet) IDs() (IDs []uint64) {
return
}
// Walk iterates through every slice item and calls w(DataPrivacyRequest) err
//
// This function is auto-generated.
func (set DataPrivacyRequestSet) Walk(w func(*DataPrivacyRequest) error) (err error) {
for i := range set {
if err = w(set[i]); err != nil {
return
}
}
return
}
// Filter iterates through every slice item, calls f(DataPrivacyRequest) (bool, err) and return filtered slice
//
// This function is auto-generated.
func (set DataPrivacyRequestSet) Filter(f func(*DataPrivacyRequest) (bool, error)) (out DataPrivacyRequestSet, err error) {
var ok bool
out = DataPrivacyRequestSet{}
for i := range set {
if ok, err = f(set[i]); err != nil {
return
} else if ok {
out = append(out, set[i])
}
}
return
}
// FindByID finds items from slice by its ID property
//
// This function is auto-generated.
func (set DataPrivacyRequestSet) FindByID(ID uint64) *DataPrivacyRequest {
for i := range set {
if set[i].ID == ID {
return set[i]
}
}
return nil
}
// IDs returns a slice of uint64s from all items in the set
//
// This function is auto-generated.
func (set DataPrivacyRequestSet) IDs() (IDs []uint64) {
IDs = make([]uint64, len(set))
for i := range set {
IDs[i] = set[i].ID
}
return
}
// Walk iterates through every slice item and calls w(DataPrivacyRequestComment) err
//
// This function is auto-generated.
func (set DataPrivacyRequestCommentSet) Walk(w func(*DataPrivacyRequestComment) error) (err error) {
for i := range set {
if err = w(set[i]); err != nil {
return
}
}
return
}
// Filter iterates through every slice item, calls f(DataPrivacyRequestComment) (bool, err) and return filtered slice
//
// This function is auto-generated.
func (set DataPrivacyRequestCommentSet) Filter(f func(*DataPrivacyRequestComment) (bool, error)) (out DataPrivacyRequestCommentSet, err error) {
var ok bool
out = DataPrivacyRequestCommentSet{}
for i := range set {
if ok, err = f(set[i]); err != nil {
return
} else if ok {
out = append(out, set[i])
}
}
return
}
// FindByID finds items from slice by its ID property
//
// This function is auto-generated.
func (set DataPrivacyRequestCommentSet) FindByID(ID uint64) *DataPrivacyRequestComment {
for i := range set {
if set[i].ID == ID {
return set[i]
}
}
return nil
}
// IDs returns a slice of uint64s from all items in the set
//
// This function is auto-generated.
func (set DataPrivacyRequestCommentSet) IDs() (IDs []uint64) {
IDs = make([]uint64, len(set))
for i := range set {
IDs[i] = set[i].ID
}
return
}
// Walk iterates through every slice item and calls w(Queue) err
//
// This function is auto-generated.
+180
View File
@@ -1048,6 +1048,186 @@ func TestDalSensitivityLevelSetIDs(t *testing.T) {
}
}
func TestDataPrivacyRequestSetWalk(t *testing.T) {
var (
value = make(DataPrivacyRequestSet, 3)
req = require.New(t)
)
// check walk with no errors
{
err := value.Walk(func(*DataPrivacyRequest) error {
return nil
})
req.NoError(err)
}
// check walk with error
req.Error(value.Walk(func(*DataPrivacyRequest) error { return fmt.Errorf("walk error") }))
}
func TestDataPrivacyRequestSetFilter(t *testing.T) {
var (
value = make(DataPrivacyRequestSet, 3)
req = require.New(t)
)
// filter nothing
{
set, err := value.Filter(func(*DataPrivacyRequest) (bool, error) {
return true, nil
})
req.NoError(err)
req.Equal(len(set), len(value))
}
// filter one item
{
found := false
set, err := value.Filter(func(*DataPrivacyRequest) (bool, error) {
if !found {
found = true
return found, nil
}
return false, nil
})
req.NoError(err)
req.Len(set, 1)
}
// filter error
{
_, err := value.Filter(func(*DataPrivacyRequest) (bool, error) {
return false, fmt.Errorf("filter error")
})
req.Error(err)
}
}
func TestDataPrivacyRequestSetIDs(t *testing.T) {
var (
value = make(DataPrivacyRequestSet, 3)
req = require.New(t)
)
// construct objects
value[0] = new(DataPrivacyRequest)
value[1] = new(DataPrivacyRequest)
value[2] = new(DataPrivacyRequest)
// set ids
value[0].ID = 1
value[1].ID = 2
value[2].ID = 3
// Find existing
{
val := value.FindByID(2)
req.Equal(uint64(2), val.ID)
}
// Find non-existing
{
val := value.FindByID(4)
req.Nil(val)
}
// List IDs from set
{
val := value.IDs()
req.Equal(len(val), len(value))
}
}
func TestDataPrivacyRequestCommentSetWalk(t *testing.T) {
var (
value = make(DataPrivacyRequestCommentSet, 3)
req = require.New(t)
)
// check walk with no errors
{
err := value.Walk(func(*DataPrivacyRequestComment) error {
return nil
})
req.NoError(err)
}
// check walk with error
req.Error(value.Walk(func(*DataPrivacyRequestComment) error { return fmt.Errorf("walk error") }))
}
func TestDataPrivacyRequestCommentSetFilter(t *testing.T) {
var (
value = make(DataPrivacyRequestCommentSet, 3)
req = require.New(t)
)
// filter nothing
{
set, err := value.Filter(func(*DataPrivacyRequestComment) (bool, error) {
return true, nil
})
req.NoError(err)
req.Equal(len(set), len(value))
}
// filter one item
{
found := false
set, err := value.Filter(func(*DataPrivacyRequestComment) (bool, error) {
if !found {
found = true
return found, nil
}
return false, nil
})
req.NoError(err)
req.Len(set, 1)
}
// filter error
{
_, err := value.Filter(func(*DataPrivacyRequestComment) (bool, error) {
return false, fmt.Errorf("filter error")
})
req.Error(err)
}
}
func TestDataPrivacyRequestCommentSetIDs(t *testing.T) {
var (
value = make(DataPrivacyRequestCommentSet, 3)
req = require.New(t)
)
// construct objects
value[0] = new(DataPrivacyRequestComment)
value[1] = new(DataPrivacyRequestComment)
value[2] = new(DataPrivacyRequestComment)
// set ids
value[0].ID = 1
value[1].ID = 2
value[2].ID = 3
// Find existing
{
val := value.FindByID(2)
req.Equal(uint64(2), val.ID)
}
// Find non-existing
{
val := value.FindByID(4)
req.Nil(val)
}
// List IDs from set
{
val := value.IDs()
req.Equal(len(val), len(value))
}
}
func TestQueueSetWalk(t *testing.T) {
var (
value = make(QueueSet, 3)
+2
View File
@@ -35,3 +35,5 @@ types:
Queue: {}
QueueMessage:
noIdField: true
DataPrivacyRequest: {}
DataPrivacyRequestComment: {}