Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion charts/lfx-v2-indexer-service/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ apiVersion: v2
name: lfx-v2-indexer-service
description: LFX Platform V2 Indexer Service chart
type: application
version: 0.4.10
version: 0.4.11
appVersion: "latest"
1 change: 1 addition & 0 deletions internal/domain/services/indexer_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func NewIndexerService(
enrichers.NewV1MeetingEnricher(),
enrichers.NewV1PastMeetingEnricher(),
enrichers.NewV1MeetingRegistrantEnricher(),
enrichers.NewV1MeetingRSVPEnricher(),
enrichers.NewV1PastMeetingParticipantEnricher(),
enrichers.NewV1PastMeetingRecordingEnricher(),
enrichers.NewV1PastMeetingTranscriptEnricher(),
Expand Down
134 changes: 134 additions & 0 deletions internal/enrichers/v1_meeting_rsvp_enricher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Copyright The Linux Foundation and each contributor to LFX.
// SPDX-License-Identifier: MIT

// Package enrichers provides data enrichment functionality for different object types.
package enrichers

import (
"fmt"
"regexp"
"strings"

"github.com/linuxfoundation/lfx-v2-indexer-service/internal/domain/contracts"
"github.com/linuxfoundation/lfx-v2-indexer-service/pkg/constants"
)

// V1MeetingRSVPEnricher handles V1 meeting-RSVP-specific enrichment logic
type V1MeetingRSVPEnricher struct {
defaultEnricher Enricher
}

// ObjectType returns the object type this enricher handles.
func (e *V1MeetingRSVPEnricher) ObjectType() string {
return e.defaultEnricher.ObjectType()
}

// EnrichData enriches V1 meeting-RSVP-specific data
func (e *V1MeetingRSVPEnricher) EnrichData(body *contracts.TransactionBody, transaction *contracts.LFXTransaction) error {
return e.defaultEnricher.EnrichData(body, transaction)
}

// setAccessControl provides V1 meeting-RSVP-specific access control logic
func (e *V1MeetingRSVPEnricher) setAccessControl(body *contracts.TransactionBody, data map[string]any, objectType, objectID string) {
meetingLevelPermission := func(data map[string]any) string {
if value, ok := data["meeting_id"]; ok {
if meetingUID, ok := value.(string); ok {
return fmt.Sprintf("%s:%s", constants.ObjectTypeV1Meeting, meetingUID)
}
}
return fmt.Sprintf("%s:%s", objectType, objectID)
}

// Build access control values
var accessObject, accessRelation string
var historyObject, historyRelation string

// Set access control with V1 meeting-RSVP-specific logic
// Only apply defaults when fields are completely missing from data
if accessCheckObject, ok := data["accessCheckObject"].(string); ok {
// Field exists in data (even if empty) - use data value
accessObject = accessCheckObject
} else if _, exists := data["accessCheckObject"]; !exists {
// Field doesn't exist in data - use computed default with objectType prefix
accessObject = meetingLevelPermission(data)
}
// If field exists but is not a string, leave empty (no override)

if accessCheckRelation, ok := data["accessCheckRelation"].(string); ok {
accessRelation = accessCheckRelation
} else if _, exists := data["accessCheckRelation"]; !exists {
accessRelation = "auditor"
}

if historyCheckObject, ok := data["historyCheckObject"].(string); ok {
historyObject = historyCheckObject
} else if _, exists := data["historyCheckObject"]; !exists {
historyObject = meetingLevelPermission(data)
}

if historyCheckRelation, ok := data["historyCheckRelation"].(string); ok {
historyRelation = historyCheckRelation
} else if _, exists := data["historyCheckRelation"]; !exists {
historyRelation = "writer"
}

// Assign to body fields (deprecated fields)
body.AccessCheckObject = accessObject
body.AccessCheckRelation = accessRelation
body.HistoryCheckObject = historyObject
body.HistoryCheckRelation = historyRelation

// Build and assign the query strings
if accessObject != "" && accessRelation != "" {
body.AccessCheckQuery = contracts.JoinFgaQuery(accessObject, accessRelation)
}
if historyObject != "" && historyRelation != "" {
body.HistoryCheckQuery = contracts.JoinFgaQuery(historyObject, historyRelation)
}
}

// extractSortName extracts the sort name from the V1 meeting message data
func (e *V1MeetingRSVPEnricher) extractSortName(data map[string]any) string {
if value, ok := data["email"]; ok {
if strValue, isString := value.(string); isString && strValue != "" {
return strings.TrimSpace(strValue)
}
}
return ""
}

// extractNameAndAliases extracts the name and aliases from the V1 meeting message data
func (e *V1MeetingRSVPEnricher) extractNameAndAliases(data map[string]any) []string {
var nameAndAliases []string
seen := make(map[string]bool) // Deduplicate names

// Compile regex pattern for name-like fields
aliasRegex := regexp.MustCompile(`(?i)^(email)$`)

// Collect all name-like fields using regex pattern
for key, value := range data {
if aliasRegex.MatchString(key) {
if strValue, ok := value.(string); ok && strValue != "" {
trimmed := strings.TrimSpace(strValue)
if trimmed != "" && !seen[trimmed] {
nameAndAliases = append(nameAndAliases, trimmed)
seen[trimmed] = true
}
}
}
}

return nameAndAliases
}

// NewV1MeetingRSVPEnricher creates a new V1 meeting RSVP enricher
func NewV1MeetingRSVPEnricher() Enricher {
enricher := &V1MeetingRSVPEnricher{}
enricher.defaultEnricher = newDefaultEnricher(
constants.ObjectTypeV1MeetingRSVP,
WithAccessControl(enricher.setAccessControl),
WithNameAndAliases(enricher.extractNameAndAliases),
WithSortName(enricher.extractSortName),
)
return enricher
}
1 change: 1 addition & 0 deletions pkg/constants/messaging.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ const (
ObjectTypeV1Meeting = "v1_meeting"
ObjectTypeV1PastMeeting = "v1_past_meeting"
ObjectTypeV1MeetingRegistrant = "v1_meeting_registrant"
ObjectTypeV1MeetingRSVP = "v1_meeting_rsvp"
ObjectTypeV1PastMeetingParticipant = "v1_past_meeting_participant"
ObjectTypeV1PastMeetingRecording = "v1_past_meeting_recording"
ObjectTypeV1PastMeetingTranscript = "v1_past_meeting_transcript"
Expand Down