-
Notifications
You must be signed in to change notification settings - Fork 3
CE Refactor Part 1: create the Models package #338
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
6069931
PR 1 update models and create error codes
ginaxu1 d15f8d3
Redo changes but in v1 directory per Thanikan suggestion
ginaxu1 60b364b
Address Thanikan feedback
ginaxu1 263d947
Rename v1/models/types.go → v1/models/consent.go
ginaxu1 1ae0f0d
Clean up
ginaxu1 91b8da5
Update exchange/consent-engine/v1/models/dtos.go
ginaxu1 e5fec54
Update exchange/consent-engine/v1/models/consent.go
ginaxu1 93e74d4
Update exchange/consent-engine/v1/models/constants.go
ginaxu1 b475524
resolve merge conflicts and address other comment around v1/models
ginaxu1 0c99888
Clarify comments in ExpiresAt and GrantDuration
ginaxu1 a7d7ce4
Address Thanikan comments around errormessage enums and expiresAt
ginaxu1 98a3732
Clean up
ginaxu1 3405e0a
Address remaining comments
ginaxu1 3b028db
fix wrong type make sure that we are consistently using in
ginaxu1 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| package models | ||
|
|
||
| import ( | ||
| "time" | ||
|
|
||
| "github.com/google/uuid" | ||
| ) | ||
|
|
||
| // ConsentRecord represents a consent record in the system | ||
| type ConsentRecord struct { | ||
| // ConsentID is the unique identifier for the consent record | ||
| ConsentID uuid.UUID `gorm:"column:consent_id;type:uuid;primaryKey;default:gen_random_uuid()" json:"consent_id"` | ||
| // OwnerID is the unique identifier for the data owner | ||
| OwnerID string `gorm:"column:owner_id;type:varchar(255);not null;index:idx_consent_records_owner_id" json:"owner_id"` | ||
| // OwnerEmail is the email address of the data owner | ||
| OwnerEmail string `gorm:"column:owner_email;type:varchar(255);not null;index:idx_consent_records_owner_email" json:"owner_email"` | ||
| // AppID is the unique identifier for the consumer application | ||
| AppID string `gorm:"column:app_id;type:varchar(255);not null;index:idx_consent_records_app_id" json:"app_id"` | ||
| // Status is the status of the consent record: pending, approved, rejected, expired, revoked | ||
| Status string `gorm:"column:status;type:varchar(50);not null;index:idx_consent_records_status" json:"status"` | ||
| // Type is the type of consent mechanism "realtime" or "offline" | ||
| Type string `gorm:"column:type;type:varchar(50);not null" json:"type"` | ||
| // CreatedAt is the timestamp when the consent record was created | ||
| CreatedAt time.Time `gorm:"column:created_at;type:timestamp with time zone;not null;default:CURRENT_TIMESTAMP;index:idx_consent_records_created_at" json:"created_at"` | ||
| // UpdatedAt is the timestamp when the consent record was last updated | ||
| UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp with time zone;not null;default:CURRENT_TIMESTAMP" json:"updated_at"` | ||
| // PendingExpiresAt is the timestamp when a pending consent expires (timeout waiting for approval/denial) | ||
| // Set when status is pending, cleared when status changes to approved/rejected | ||
| PendingExpiresAt *time.Time `gorm:"column:pending_expires_at;type:timestamp with time zone;index:idx_consent_records_pending_expires_at" json:"pending_expires_at,omitempty"` | ||
| // GrantExpiresAt is the timestamp when an approved consent grant expires | ||
| // Calculated by adding GrantDuration to the current time when consent is approved | ||
| // Only set when status is approved | ||
| GrantExpiresAt *time.Time `gorm:"column:grant_expires_at;type:timestamp with time zone;index:idx_consent_records_grant_expires_at" json:"grant_expires_at,omitempty"` | ||
| // GrantDuration is the duration to add to current time when approving consent (e.g., "P30D", "1h") | ||
| // Used to calculate GrantExpiresAt: GrantExpiresAt = current_time + GrantDuration | ||
| GrantDuration string `gorm:"column:grant_duration;type:varchar(50);not null" json:"grant_duration"` | ||
| // Fields is the list of data fields that require consent (stored as array of field names) | ||
| Fields []ConsentField `gorm:"column:fields;type:jsonb;not null" json:"fields"` | ||
| // SessionID is the session identifier for tracking the consent flow | ||
| SessionID string `gorm:"column:session_id;type:varchar(255);not null" json:"session_id"` | ||
| // ConsentPortalURL is the URL to redirect to for consent portal | ||
| ConsentPortalURL string `gorm:"column:consent_portal_url;type:text" json:"consent_portal_url"` | ||
| // UpdatedBy identifies who last updated the consent (audit field) | ||
| UpdatedBy *string `gorm:"column:updated_by;type:varchar(255)" json:"updated_by,omitempty"` | ||
| } | ||
|
|
||
| // TableName specifies the table name for GORM | ||
| func (*ConsentRecord) TableName() string { | ||
| return "consent_records" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| package models | ||
|
|
||
| // ConsentStatus represents the status of a consent record | ||
| type ConsentStatus string | ||
|
|
||
| // ConsentStatus constants | ||
| const ( | ||
| StatusPending ConsentStatus = "pending" | ||
| StatusApproved ConsentStatus = "approved" | ||
| StatusRejected ConsentStatus = "rejected" | ||
| StatusExpired ConsentStatus = "expired" | ||
| StatusRevoked ConsentStatus = "revoked" | ||
| ) | ||
|
|
||
| // DefaultPendingTimeoutDuration is the default duration for pending consent expiry | ||
| // Pending consents will expire after this duration if not approved or rejected | ||
| // Format: ISO 8601 duration (e.g., "P1D" for 1 day, "PT24H" for 24 hours) | ||
| const DefaultPendingTimeoutDuration = "P1D" // 1 day default | ||
|
|
||
| // ConsentErrorMessage represents an error message | ||
| type ConsentErrorMessage string | ||
|
|
||
| // ConsentErrorMessage constants | ||
| const ( | ||
| ErrConsentNotFound ConsentErrorMessage = "consent record not found" | ||
| ErrConsentCreateFailed ConsentErrorMessage = "failed to create consent record" | ||
| ErrConsentUpdateFailed ConsentErrorMessage = "failed to update consent record" | ||
| ErrConsentRevokeFailed ConsentErrorMessage = "failed to revoke consent record" | ||
| ErrConsentGetFailed ConsentErrorMessage = "failed to get consent records" | ||
| ErrConsentExpiryFailed ConsentErrorMessage = "failed to check consent expiry" | ||
| ErrPortalRequestFailed ConsentErrorMessage = "failed to process consent portal request" | ||
| ) | ||
|
|
||
| // ConsentErrorCode represents an error code | ||
| type ConsentErrorCode string | ||
|
|
||
| // ConsentErrorCode constants | ||
| const ( | ||
| ErrorCodeConsentNotFound ConsentErrorCode = "CONSENT_NOT_FOUND" | ||
| ErrorCodeInternalError ConsentErrorCode = "INTERNAL_ERROR" | ||
| ErrorCodeBadRequest ConsentErrorCode = "BAD_REQUEST" | ||
| ErrorCodeUnauthorized ConsentErrorCode = "UNAUTHORIZED" | ||
| ErrorCodeForbidden ConsentErrorCode = "FORBIDDEN" | ||
| ) | ||
|
|
||
| // ConsentEngineOperation represents the operation | ||
| type ConsentEngineOperation string | ||
|
|
||
| // ConsentEngineOperation constants | ||
| const ( | ||
| OpCreateConsent ConsentEngineOperation = "create consent" | ||
| OpUpdateConsent ConsentEngineOperation = "update consent" | ||
| OpRevokeConsent ConsentEngineOperation = "revoke consent" | ||
| OpGetConsentStatus ConsentEngineOperation = "get consent status" | ||
| OpGetConsentsByOwner ConsentEngineOperation = "get consents by data owner" | ||
| OpGetConsentsByConsumer ConsentEngineOperation = "get consents by consumer" | ||
| OpCheckConsentExpiry ConsentEngineOperation = "check consent expiry" | ||
| OpProcessPortalRequest ConsentEngineOperation = "process consent portal" | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| package models | ||
|
|
||
| import ( | ||
| "strings" | ||
| "time" | ||
|
|
||
| "github.com/google/uuid" | ||
| "golang.org/x/text/cases" | ||
| "golang.org/x/text/language" | ||
| ) | ||
|
|
||
| // Owner represents the owner enum (matches PolicyDecisionPoint Owner type) | ||
| type Owner string | ||
|
|
||
| const ( | ||
| OwnerCitizen Owner = "citizen" | ||
| ) | ||
|
|
||
| // ConsentRequest defines the structure for creating a consent record | ||
| // GrantDuration is optional - nil means not provided and will use default value | ||
| type ConsentRequest struct { | ||
| AppID string `json:"app_id"` | ||
| ConsentRequirements []ConsentRequirement `json:"consent_requirements"` | ||
| GrantDuration *string `json:"grant_duration,omitempty"` | ||
| } | ||
ginaxu1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // ConsentRequirement represents a consent requirement for a specific owner | ||
| type ConsentRequirement struct { | ||
| Owner string `json:"owner"` | ||
| OwnerID string `json:"owner_id"` | ||
| Fields []ConsentField `json:"fields"` | ||
| } | ||
|
|
||
| // ConsentField represents a field that requires consent | ||
| // Matches PolicyDecisionResponseFieldRecord structure from PolicyDecisionPoint | ||
| type ConsentField struct { | ||
| FieldName string `json:"fieldName"` | ||
| SchemaID string `json:"schemaId"` | ||
| DisplayName *string `json:"displayName,omitempty"` | ||
| Description *string `json:"description,omitempty"` | ||
| Owner *Owner `json:"owner,omitempty"` | ||
| } | ||
ginaxu1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // UpdateConsentRequest defines the structure for updating a consent record | ||
| // Status is optional (omitempty) to support PATCH operations where status may not be provided | ||
| // Optional fields use pointers to distinguish between "not provided" (nil) and "provided as empty" (pointer to empty value) | ||
| type UpdateConsentRequest struct { | ||
| Status ConsentStatus `json:"status,omitempty"` // Required for PUT, optional for PATCH | ||
| UpdatedBy *string `json:"updated_by,omitempty"` // Optional - nil means not provided | ||
| GrantDuration *string `json:"grant_duration,omitempty"` // Optional - nil means not provided | ||
| Fields *[]ConsentField `json:"fields,omitempty"` // Optional - nil means not provided | ||
| Reason *string `json:"reason,omitempty"` // Optional - nil means not provided | ||
| } | ||
sthanikan2000 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // ConsentPortalRequest defines the structure for consent portal interactions | ||
| // Reason is optional - nil means not provided, pointer allows distinguishing from empty string | ||
| type ConsentPortalRequest struct { | ||
| ConsentID uuid.UUID `json:"consent_id"` | ||
| Action string `json:"action"` // "approve" or "reject" | ||
| DataOwner string `json:"data_owner"` | ||
| Reason *string `json:"reason,omitempty"` | ||
| } | ||
ginaxu1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // ConsentResponse represents the simplified response for consent operations | ||
| type ConsentResponse struct { | ||
| ConsentID uuid.UUID `json:"consent_id"` | ||
| Status string `json:"status"` | ||
| ConsentPortalURL *string `json:"consent_portal_url,omitempty"` // Only present when status is pending | ||
| } | ||
|
|
||
| // ConsentPortalView represents the user-facing consent object for the UI. | ||
| // Uses rich field information for better UX in the consent portal | ||
| type ConsentPortalView struct { | ||
| AppDisplayName string `json:"app_display_name"` | ||
| CreatedAt time.Time `json:"created_at"` | ||
| Fields []ConsentField `json:"fields"` // Rich field information with display names and descriptions | ||
| OwnerName string `json:"owner_name"` | ||
| OwnerEmail string `json:"owner_email"` | ||
| Status string `json:"status"` | ||
| Type string `json:"type"` | ||
| } | ||
|
|
||
| // Legacy structures for backwards compatibility (deprecated) | ||
| type DataField struct { | ||
| OwnerType string `json:"owner_type,omitempty"` | ||
| OwnerID string `json:"owner_id"` | ||
| OwnerEmail string `json:"owner_email"` | ||
| Fields []string `json:"fields"` | ||
| } | ||
|
|
||
| // ToConsentResponse converts a ConsentRecord to a simplified ConsentResponse | ||
| // Only includes consent_portal_url when status is pending and the URL is not empty | ||
| func (cr *ConsentRecord) ToConsentResponse() ConsentResponse { | ||
| response := ConsentResponse{ | ||
| ConsentID: cr.ConsentID, | ||
| Status: cr.Status, | ||
| } | ||
|
|
||
| // Only include consent_portal_url when status is pending and URL is not empty | ||
| if cr.Status == string(StatusPending) && cr.ConsentPortalURL != "" { | ||
| portalURL := cr.ConsentPortalURL | ||
| response.ConsentPortalURL = &portalURL | ||
| } | ||
|
|
||
| return response | ||
| } | ||
|
|
||
| // ToConsentPortalView converts an internal ConsentRecord to a user-facing view. | ||
| // Returns rich field information including display names and descriptions for better UX | ||
| func (cr *ConsentRecord) ToConsentPortalView() *ConsentPortalView { | ||
| // Simple mapping for app_id to a human-readable name. | ||
| appDisplayName := strings.ReplaceAll(cr.AppID, "-", " ") | ||
| appDisplayName = cases.Title(language.English).String(appDisplayName) | ||
|
|
||
| ownerName := strings.ReplaceAll(cr.OwnerID, "-", " ") | ||
| ownerName = cases.Title(language.English).String(ownerName) | ||
|
|
||
| return &ConsentPortalView{ | ||
| AppDisplayName: appDisplayName, | ||
| CreatedAt: cr.CreatedAt, | ||
| Fields: cr.Fields, // Now includes DisplayName, Description, and Owner for rich UI rendering | ||
| OwnerName: ownerName, | ||
| OwnerEmail: cr.OwnerEmail, | ||
| Status: cr.Status, | ||
| Type: cr.Type, | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.