Skip to content

Commit ace4782

Browse files
authored
Merge pull request #30 from linuxfoundation/andrest50/v1-meeting-rsvp
[LFXV2-887] Add V1 meeting RSVP enricher for indexing RSVP data
2 parents 7a9a806 + 293b095 commit ace4782

4 files changed

Lines changed: 137 additions & 1 deletion

File tree

charts/lfx-v2-indexer-service/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ apiVersion: v2
66
name: lfx-v2-indexer-service
77
description: LFX Platform V2 Indexer Service chart
88
type: application
9-
version: 0.4.10
9+
version: 0.4.11
1010
appVersion: "latest"

internal/domain/services/indexer_service.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ func NewIndexerService(
9898
enrichers.NewV1MeetingEnricher(),
9999
enrichers.NewV1PastMeetingEnricher(),
100100
enrichers.NewV1MeetingRegistrantEnricher(),
101+
enrichers.NewV1MeetingRSVPEnricher(),
101102
enrichers.NewV1PastMeetingParticipantEnricher(),
102103
enrichers.NewV1PastMeetingRecordingEnricher(),
103104
enrichers.NewV1PastMeetingTranscriptEnricher(),
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Copyright The Linux Foundation and each contributor to LFX.
2+
// SPDX-License-Identifier: MIT
3+
4+
// Package enrichers provides data enrichment functionality for different object types.
5+
package enrichers
6+
7+
import (
8+
"fmt"
9+
"regexp"
10+
"strings"
11+
12+
"github.com/linuxfoundation/lfx-v2-indexer-service/internal/domain/contracts"
13+
"github.com/linuxfoundation/lfx-v2-indexer-service/pkg/constants"
14+
)
15+
16+
// V1MeetingRSVPEnricher handles V1 meeting-RSVP-specific enrichment logic
17+
type V1MeetingRSVPEnricher struct {
18+
defaultEnricher Enricher
19+
}
20+
21+
// ObjectType returns the object type this enricher handles.
22+
func (e *V1MeetingRSVPEnricher) ObjectType() string {
23+
return e.defaultEnricher.ObjectType()
24+
}
25+
26+
// EnrichData enriches V1 meeting-RSVP-specific data
27+
func (e *V1MeetingRSVPEnricher) EnrichData(body *contracts.TransactionBody, transaction *contracts.LFXTransaction) error {
28+
return e.defaultEnricher.EnrichData(body, transaction)
29+
}
30+
31+
// setAccessControl provides V1 meeting-RSVP-specific access control logic
32+
func (e *V1MeetingRSVPEnricher) setAccessControl(body *contracts.TransactionBody, data map[string]any, objectType, objectID string) {
33+
meetingLevelPermission := func(data map[string]any) string {
34+
if value, ok := data["meeting_id"]; ok {
35+
if meetingUID, ok := value.(string); ok {
36+
return fmt.Sprintf("%s:%s", constants.ObjectTypeV1Meeting, meetingUID)
37+
}
38+
}
39+
return fmt.Sprintf("%s:%s", objectType, objectID)
40+
}
41+
42+
// Build access control values
43+
var accessObject, accessRelation string
44+
var historyObject, historyRelation string
45+
46+
// Set access control with V1 meeting-RSVP-specific logic
47+
// Only apply defaults when fields are completely missing from data
48+
if accessCheckObject, ok := data["accessCheckObject"].(string); ok {
49+
// Field exists in data (even if empty) - use data value
50+
accessObject = accessCheckObject
51+
} else if _, exists := data["accessCheckObject"]; !exists {
52+
// Field doesn't exist in data - use computed default with objectType prefix
53+
accessObject = meetingLevelPermission(data)
54+
}
55+
// If field exists but is not a string, leave empty (no override)
56+
57+
if accessCheckRelation, ok := data["accessCheckRelation"].(string); ok {
58+
accessRelation = accessCheckRelation
59+
} else if _, exists := data["accessCheckRelation"]; !exists {
60+
accessRelation = "auditor"
61+
}
62+
63+
if historyCheckObject, ok := data["historyCheckObject"].(string); ok {
64+
historyObject = historyCheckObject
65+
} else if _, exists := data["historyCheckObject"]; !exists {
66+
historyObject = meetingLevelPermission(data)
67+
}
68+
69+
if historyCheckRelation, ok := data["historyCheckRelation"].(string); ok {
70+
historyRelation = historyCheckRelation
71+
} else if _, exists := data["historyCheckRelation"]; !exists {
72+
historyRelation = "writer"
73+
}
74+
75+
// Assign to body fields (deprecated fields)
76+
body.AccessCheckObject = accessObject
77+
body.AccessCheckRelation = accessRelation
78+
body.HistoryCheckObject = historyObject
79+
body.HistoryCheckRelation = historyRelation
80+
81+
// Build and assign the query strings
82+
if accessObject != "" && accessRelation != "" {
83+
body.AccessCheckQuery = contracts.JoinFgaQuery(accessObject, accessRelation)
84+
}
85+
if historyObject != "" && historyRelation != "" {
86+
body.HistoryCheckQuery = contracts.JoinFgaQuery(historyObject, historyRelation)
87+
}
88+
}
89+
90+
// extractSortName extracts the sort name from the V1 meeting RSVP data
91+
func (e *V1MeetingRSVPEnricher) extractSortName(data map[string]any) string {
92+
if value, ok := data["email"]; ok {
93+
if strValue, isString := value.(string); isString && strValue != "" {
94+
return strings.TrimSpace(strValue)
95+
}
96+
}
97+
return ""
98+
}
99+
100+
// extractNameAndAliases extracts the name and aliases from the V1 meeting RSVP data
101+
func (e *V1MeetingRSVPEnricher) extractNameAndAliases(data map[string]any) []string {
102+
var nameAndAliases []string
103+
seen := make(map[string]bool) // Deduplicate names
104+
105+
// Compile regex pattern for name-like fields
106+
aliasRegex := regexp.MustCompile(`(?i)^(username|email)$`)
107+
108+
// Collect all name-like fields using regex pattern
109+
for key, value := range data {
110+
if aliasRegex.MatchString(key) {
111+
if strValue, ok := value.(string); ok && strValue != "" {
112+
trimmed := strings.TrimSpace(strValue)
113+
if trimmed != "" && !seen[trimmed] {
114+
nameAndAliases = append(nameAndAliases, trimmed)
115+
seen[trimmed] = true
116+
}
117+
}
118+
}
119+
}
120+
121+
return nameAndAliases
122+
}
123+
124+
// NewV1MeetingRSVPEnricher creates a new V1 meeting RSVP enricher
125+
func NewV1MeetingRSVPEnricher() Enricher {
126+
enricher := &V1MeetingRSVPEnricher{}
127+
enricher.defaultEnricher = newDefaultEnricher(
128+
constants.ObjectTypeV1MeetingRSVP,
129+
WithAccessControl(enricher.setAccessControl),
130+
WithNameAndAliases(enricher.extractNameAndAliases),
131+
WithSortName(enricher.extractSortName),
132+
)
133+
return enricher
134+
}

pkg/constants/messaging.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ const (
6666
ObjectTypeV1Meeting = "v1_meeting"
6767
ObjectTypeV1PastMeeting = "v1_past_meeting"
6868
ObjectTypeV1MeetingRegistrant = "v1_meeting_registrant"
69+
ObjectTypeV1MeetingRSVP = "v1_meeting_rsvp"
6970
ObjectTypeV1PastMeetingParticipant = "v1_past_meeting_participant"
7071
ObjectTypeV1PastMeetingRecording = "v1_past_meeting_recording"
7172
ObjectTypeV1PastMeetingTranscript = "v1_past_meeting_transcript"

0 commit comments

Comments
 (0)