Skip to content

Commit 2f8af6d

Browse files
authored
Merge pull request #19 from emsearcy/fix/v1-past-meeting-participant-username
Fix v1 past meeting participant username JSON tag mismatch
2 parents 159244a + 2546e3c commit 2f8af6d

File tree

3 files changed

+59
-58
lines changed

3 files changed

+59
-58
lines changed

charts/lfx-v2-fga-sync/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ apiVersion: v2
55
name: lfx-v2-fga-sync
66
description: LFX Platform V2 FGA Sync chart
77
type: application
8-
version: 0.2.7
8+
version: 0.2.8
99
appVersion: "latest"

handler_v1_meeting.go

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ import (
1515

1616
// v1MeetingStub represents the structure of v1 meeting data for FGA sync.
1717
type v1MeetingStub struct {
18-
MeetingID string `json:"meeting_id"` // This is still a v1 meeting ID.
19-
Visibility string `json:"visibility"` // v1 uses "visibility" instead of "public" boolean.
20-
ProjectUID string `json:"project_uid"` // This will already have been translated to a v2 project UID.
21-
Committee string `json:"committee"` // This will already have been translated to a v2 committee UID.
18+
UID string `json:"meeting_id"`
19+
Public bool `json:"public"`
20+
ProjectUID string `json:"project_uid"`
21+
Organizers []string `json:"organizers"`
22+
Committees []string `json:"committees"`
2223
}
2324

2425
// buildV1MeetingTuples builds all of the tuples for a v1 meeting object.
@@ -29,7 +30,7 @@ func (h *HandlerService) buildV1MeetingTuples(
2930
tuples := h.fgaService.NewTupleKeySlice(4)
3031

3132
// Convert the "public" attribute to a "user:*" relation.
32-
if meeting.Visibility == constants.VisibilityPublic {
33+
if meeting.Public {
3334
tuples = append(tuples, h.fgaService.TupleKey(constants.UserWildcard, constants.RelationViewer, object))
3435
}
3536

@@ -42,10 +43,10 @@ func (h *HandlerService) buildV1MeetingTuples(
4243
}
4344

4445
// Add the committee relation to associate this v1 meeting with its committee.
45-
if meeting.Committee != "" {
46+
for _, committee := range meeting.Committees {
4647
tuples = append(
4748
tuples,
48-
h.fgaService.TupleKey(constants.ObjectTypeCommittee+meeting.Committee, constants.RelationCommittee, object),
49+
h.fgaService.TupleKey(constants.ObjectTypeCommittee+committee, constants.RelationCommittee, object),
4950
)
5051
}
5152

@@ -67,7 +68,7 @@ func (h *HandlerService) v1MeetingUpdateAccessHandler(message INatsMsg) error {
6768
return err
6869
}
6970

70-
if meeting.MeetingID == "" {
71+
if meeting.UID == "" {
7172
logger.ErrorContext(ctx, "v1 meeting ID not found")
7273
return errors.New("v1 meeting ID not found")
7374
}
@@ -77,7 +78,7 @@ func (h *HandlerService) v1MeetingUpdateAccessHandler(message INatsMsg) error {
7778
return errors.New("v1 meeting project ID not found")
7879
}
7980

80-
object := constants.ObjectTypeV1Meeting + meeting.MeetingID
81+
object := constants.ObjectTypeV1Meeting + meeting.UID
8182

8283
// Build a list of tuples to sync.
8384
//
@@ -125,11 +126,11 @@ func (h *HandlerService) v1MeetingDeleteAllAccessHandler(message INatsMsg) error
125126

126127
// v1PastMeetingStub represents the structure of v1 past meeting data for FGA sync.
127128
type v1PastMeetingStub struct {
128-
MeetingAndOccurrenceID string `json:"meeting_and_occurrence_id"` // The composite ID is the best unique identifier.
129-
MeetingID string `json:"meeting_id"` // This is still a v1 meeting ID.
130-
Visibility string `json:"visibility"` // v1 uses "visibility" instead of "public" boolean.
131-
ProjectUID string `json:"project_uid"` // Translated to a v2 project UID.
132-
Committee string `json:"committee"` // Translated to a v2 committee UID.
129+
UID string `json:"uid"`
130+
MeetingUID string `json:"meeting_uid"`
131+
Public bool `json:"public"`
132+
ProjectUID string `json:"project_uid"`
133+
Committees []string `json:"committees"`
133134
}
134135

135136
// buildV1PastMeetingTuples builds all of the tuples for a v1 past meeting object.
@@ -140,15 +141,15 @@ func (h *HandlerService) buildV1PastMeetingTuples(
140141
tuples := h.fgaService.NewTupleKeySlice(4)
141142

142143
// Convert the "public" attribute to a "user:*" relation.
143-
if pastMeeting.Visibility == constants.VisibilityPublic {
144+
if pastMeeting.Public {
144145
tuples = append(tuples, h.fgaService.TupleKey(constants.UserWildcard, constants.RelationViewer, object))
145146
}
146147

147148
// Add the meeting relation to associate this v1 past meeting with its v1 meeting.
148-
if pastMeeting.MeetingID != "" {
149+
if pastMeeting.MeetingUID != "" {
149150
tuples = append(
150151
tuples,
151-
h.fgaService.TupleKey(constants.ObjectTypeV1Meeting+pastMeeting.MeetingID, constants.RelationMeeting, object),
152+
h.fgaService.TupleKey(constants.ObjectTypeV1Meeting+pastMeeting.MeetingUID, constants.RelationMeeting, object),
152153
)
153154
}
154155

@@ -161,10 +162,10 @@ func (h *HandlerService) buildV1PastMeetingTuples(
161162
}
162163

163164
// Add the committee relation to associate this v1 meeting with its committee.
164-
if pastMeeting.Committee != "" {
165+
for _, committee := range pastMeeting.Committees {
165166
tuples = append(
166167
tuples,
167-
h.fgaService.TupleKey(constants.ObjectTypeCommittee+pastMeeting.Committee, constants.RelationCommittee, object),
168+
h.fgaService.TupleKey(constants.ObjectTypeCommittee+committee, constants.RelationCommittee, object),
168169
)
169170
}
170171

@@ -186,7 +187,7 @@ func (h *HandlerService) v1PastMeetingUpdateAccessHandler(message INatsMsg) erro
186187
return err
187188
}
188189

189-
if pastMeeting.MeetingAndOccurrenceID == "" {
190+
if pastMeeting.UID == "" {
190191
logger.ErrorContext(ctx, "v1 past meeting ID not found")
191192
return errors.New("v1 past meeting ID not found")
192193
}
@@ -196,7 +197,7 @@ func (h *HandlerService) v1PastMeetingUpdateAccessHandler(message INatsMsg) erro
196197
return errors.New("v1 past meeting project ID not found")
197198
}
198199

199-
object := constants.ObjectTypeV1PastMeeting + pastMeeting.MeetingAndOccurrenceID
200+
object := constants.ObjectTypeV1PastMeeting + pastMeeting.UID
200201

201202
// Build a list of tuples to sync.
202203
//
@@ -244,7 +245,7 @@ func (h *HandlerService) v1PastMeetingDeleteAllAccessHandler(message INatsMsg) e
244245

245246
// V1PastMeetingParticipant represents a participant of a v1 past meeting.
246247
type V1PastMeetingParticipant struct {
247-
Username string `json:"lf_sso"`
248+
Username string `json:"username"`
248249
Host bool `json:"host"`
249250
IsInvited bool `json:"is_invited"`
250251
IsAttended bool `json:"is_attended"`
@@ -750,7 +751,7 @@ type v1PastMeetingParticipantStub struct {
750751
UID string `json:"id"`
751752
MeetingAndOccurrenceID string `json:"meeting_and_occurrence_id"`
752753
ArtifactVisibility string `json:"artifact_visibility"`
753-
Username string `json:"lf_sso"`
754+
Username string `json:"username"`
754755
Host bool `json:"host"`
755756
IsInvited bool `json:"is_invited"`
756757
IsAttended bool `json:"is_attended"`

handler_v1_meeting_test.go

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -32,28 +32,28 @@ func TestBuildV1MeetingTuples(t *testing.T) {
3232
{
3333
name: "minimal v1 meeting",
3434
meeting: &v1MeetingStub{
35-
MeetingID: "test-meeting-id",
35+
UID: "test-meeting-id",
3636
ProjectUID: "proj-123",
3737
},
3838
expected: 1, // project relation only
3939
},
4040
{
4141
name: "public v1 meeting with committee",
4242
meeting: &v1MeetingStub{
43-
MeetingID: "test-meeting-id",
44-
Visibility: "public",
43+
UID: "test-meeting-id",
44+
Public: true,
4545
ProjectUID: "proj-123",
46-
Committee: "committee-1",
46+
Committees: []string{"committee-1"},
4747
},
4848
expected: 3, // public + project + committee
4949
},
5050
{
5151
name: "private v1 meeting",
5252
meeting: &v1MeetingStub{
53-
MeetingID: "test-meeting-id",
54-
Visibility: "private",
53+
UID: "test-meeting-id",
54+
Public: false,
5555
ProjectUID: "proj-123",
56-
Committee: "committee-1",
56+
Committees: []string{"committee-1"},
5757
},
5858
expected: 2, // project + committee (no public access)
5959
},
@@ -68,7 +68,7 @@ func TestBuildV1MeetingTuples(t *testing.T) {
6868
},
6969
}
7070

71-
object := constants.ObjectTypeV1Meeting + tt.meeting.MeetingID
71+
object := constants.ObjectTypeV1Meeting + tt.meeting.UID
7272
tuples, err := handlerService.buildV1MeetingTuples(object, tt.meeting)
7373

7474
assert.NoError(t, err)
@@ -110,20 +110,20 @@ func TestBuildV1PastMeetingTuples(t *testing.T) {
110110
{
111111
name: "minimal v1 past meeting",
112112
pastMeeting: &v1PastMeetingStub{
113-
MeetingAndOccurrenceID: "past-meeting-occurrence-id",
114-
MeetingID: "meeting-123",
115-
ProjectUID: "proj-123",
113+
UID: "past-meeting-occurrence-id",
114+
MeetingUID: "meeting-123",
115+
ProjectUID: "proj-123",
116116
},
117117
expected: 2, // meeting relation + project relation
118118
},
119119
{
120120
name: "public v1 past meeting with committee",
121121
pastMeeting: &v1PastMeetingStub{
122-
MeetingAndOccurrenceID: "past-meeting-occurrence-id",
123-
MeetingID: "meeting-123",
124-
Visibility: "public",
125-
ProjectUID: "proj-123",
126-
Committee: "committee-1",
122+
UID: "past-meeting-occurrence-id",
123+
MeetingUID: "meeting-123",
124+
Public: true,
125+
ProjectUID: "proj-123",
126+
Committees: []string{"committee-1"},
127127
},
128128
expected: 4, // public + meeting + project + committee
129129
},
@@ -138,7 +138,7 @@ func TestBuildV1PastMeetingTuples(t *testing.T) {
138138
},
139139
}
140140

141-
object := constants.ObjectTypeV1PastMeeting + tt.pastMeeting.MeetingAndOccurrenceID
141+
object := constants.ObjectTypeV1PastMeeting + tt.pastMeeting.UID
142142
tuples, err := handlerService.buildV1PastMeetingTuples(object, tt.pastMeeting)
143143

144144
assert.NoError(t, err)
@@ -156,7 +156,7 @@ func TestBuildV1PastMeetingTuples(t *testing.T) {
156156
if tuple.User == constants.UserWildcard && tuple.Relation == constants.RelationViewer {
157157
foundPublic = true
158158
}
159-
if tuple.User == constants.ObjectTypeV1Meeting+"meeting-123" && tuple.Relation == constants.RelationMeeting {
159+
if tuple.Relation == constants.RelationMeeting {
160160
foundMeeting = true
161161
}
162162
if tuple.User == constants.ObjectTypeProject+"proj-123" && tuple.Relation == constants.RelationProject {
@@ -200,13 +200,13 @@ func TestBuildV1PastMeetingArtifactTuples(t *testing.T) {
200200
name: "meeting_hosts visibility",
201201
artifactVisibility: "meeting_hosts",
202202
participants: participants,
203-
expected: 2, // past_meeting relation + 1 host viewer
203+
expected: 2, // past_meeting relation + 1 host_view relation
204204
},
205205
{
206206
name: "meeting_participants visibility",
207207
artifactVisibility: "meeting_participants",
208208
participants: participants,
209-
expected: 4, // past_meeting relation + 3 participant viewers
209+
expected: 4, // past_meeting relation + 3 view relations (host_view, attendee_view, participant_view)
210210
},
211211
{
212212
name: "unknown visibility",
@@ -257,10 +257,10 @@ func TestV1MeetingUpdateAccessHandler(t *testing.T) {
257257
{
258258
name: "valid v1 meeting with all fields",
259259
messageData: mustMarshalJSON(v1MeetingStub{
260-
MeetingID: "meeting-123",
261-
Visibility: "public",
260+
UID: "meeting-123",
261+
Public: true,
262262
ProjectUID: "project-456",
263-
Committee: "committee1",
263+
Committees: []string{"committee1"},
264264
}),
265265
replySubject: "reply.subject",
266266
setupMocks: func(service *HandlerService, msg *MockNatsMsg) {
@@ -296,8 +296,8 @@ func TestV1MeetingUpdateAccessHandler(t *testing.T) {
296296
{
297297
name: "missing project UID",
298298
messageData: mustMarshalJSON(v1MeetingStub{
299-
MeetingID: "meeting-123",
300-
Visibility: "public",
299+
UID: "meeting-123",
300+
Public: true,
301301
}),
302302
setupMocks: func(service *HandlerService, msg *MockNatsMsg) {
303303
// No mocks needed for validation error
@@ -354,11 +354,11 @@ func TestV1PastMeetingUpdateAccessHandler(t *testing.T) {
354354
{
355355
name: "valid v1 past meeting",
356356
messageData: mustMarshalJSON(v1PastMeetingStub{
357-
MeetingAndOccurrenceID: "past-meeting-123",
358-
MeetingID: "meeting-456",
359-
Visibility: "private",
360-
ProjectUID: "project-789",
361-
Committee: "committee1",
357+
UID: "past-meeting-123",
358+
MeetingUID: "meeting-456",
359+
Public: false,
360+
ProjectUID: "project-789",
361+
Committees: []string{"committee1"},
362362
}),
363363
replySubject: "reply.subject",
364364
setupMocks: func(service *HandlerService, msg *MockNatsMsg) {
@@ -394,9 +394,9 @@ func TestV1PastMeetingUpdateAccessHandler(t *testing.T) {
394394
{
395395
name: "missing project UID",
396396
messageData: mustMarshalJSON(v1PastMeetingStub{
397-
MeetingAndOccurrenceID: "past-meeting-123",
398-
MeetingID: "meeting-456",
399-
Visibility: "public",
397+
UID: "past-meeting-123",
398+
MeetingUID: "meeting-456",
399+
Public: true,
400400
}),
401401
setupMocks: func(service *HandlerService, msg *MockNatsMsg) {
402402
// No mocks needed for validation error
@@ -457,7 +457,7 @@ func TestV1PastMeetingRecordingUpdateAccessHandler(t *testing.T) {
457457
"meeting_and_occurrence_id": "past-meeting-456",
458458
"recording_access": "public",
459459
"participants": [
460-
{"lf_sso": "user1", "host": true, "is_invited": true, "is_attended": true}
460+
{"username": "user1", "host": true, "is_invited": true, "is_attended": true}
461461
]
462462
}`),
463463
replySubject: "reply.subject",

0 commit comments

Comments
 (0)