Skip to content
Open
Show file tree
Hide file tree
Changes from all 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 RSVP 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 RSVP 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)^(username|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