Skip to content

Commit 1359c20

Browse files
ostcarbastianjoeljsangmeister
authored
Add new restrictions for LoS extension (#807) (#810)
Co-authored-by: Bastian Rihm <[email protected]> Co-authored-by: Joshua Sangmeister <[email protected]>
1 parent 668f628 commit 1359c20

20 files changed

+1973
-1132
lines changed

internal/projector/slide/list_of_speakers.go

+275-26
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@ func losFromMap(in map[string]json.RawMessage) (*dbListOfSpeakers, error) {
3434
}
3535

3636
type dbSpeakerWork struct {
37-
MeetingUserID int `json:"meeting_user_id"`
38-
Weight int `json:"weight"`
39-
BeginTime int `json:"begin_time"`
40-
EndTime int `json:"end_time"`
37+
MeetingUserID int `json:"meeting_user_id"`
38+
Weight int `json:"weight"`
39+
BeginTime int `json:"begin_time"`
40+
EndTime int `json:"end_time"`
41+
StructureLevelListOfSpeakersID int `json:"structure_level_list_of_speakers_id"`
4142
}
4243
type dbSpeaker struct {
4344
User string `json:"user"`
@@ -63,9 +64,6 @@ func speakerFromMap(in map[string]json.RawMessage) (*dbSpeaker, error) {
6364
return nil, fmt.Errorf("decoding speaker work data: %w", err)
6465
}
6566

66-
if work.MeetingUserID == 0 {
67-
return nil, fmt.Errorf("meeting_user_id is 0")
68-
}
6967
return &speaker, nil
7068
}
7169

@@ -178,6 +176,201 @@ func CurrentSpeakerChyron(store *projector.SlideStore) {
178176
})
179177
}
180178

179+
type dbStructureLevel struct {
180+
Name string `json:"name"`
181+
Color string `json:"color"`
182+
}
183+
184+
func structureLevelFromMap(in map[string]json.RawMessage) (*dbStructureLevel, error) {
185+
bs, err := json.Marshal(in)
186+
if err != nil {
187+
return nil, fmt.Errorf("encoding motion data: %w", err)
188+
}
189+
190+
var m dbStructureLevel
191+
if err := json.Unmarshal(bs, &m); err != nil {
192+
return nil, fmt.Errorf("decoding motion: %w", err)
193+
}
194+
return &m, nil
195+
}
196+
197+
type dbStructureLevelListOfSpeakers struct {
198+
SpeakerIDs []int `json:"speaker_ids"`
199+
StructureLevelID int `json:"structure_level_id"`
200+
InitialTime int `json:"initial_time"`
201+
RemainingTime int `json:"remaining_time"`
202+
AdditionalTime int `json:"additional_time"`
203+
CurrentStartTime int `json:"current_start_time"`
204+
}
205+
206+
func structureLevelListOfSpeakersFromMap(in map[string]json.RawMessage) (*dbStructureLevelListOfSpeakers, error) {
207+
bs, err := json.Marshal(in)
208+
if err != nil {
209+
return nil, fmt.Errorf("encoding motion data: %w", err)
210+
}
211+
212+
var m dbStructureLevelListOfSpeakers
213+
if err := json.Unmarshal(bs, &m); err != nil {
214+
return nil, fmt.Errorf("decoding motion: %w", err)
215+
}
216+
return &m, nil
217+
}
218+
219+
type structureLevelRepr struct {
220+
ID int `json:"id"`
221+
Name string `json:"name"`
222+
Color string `json:"color"`
223+
RemainingTime int `json:"remaining_time"`
224+
CurrentStartTime int `json:"current_start_time"`
225+
}
226+
227+
// CurrentStructureLevelList renders the current_structure_level_list slide.
228+
func CurrentStructureLevelList(store *projector.SlideStore) {
229+
store.RegisterSliderFunc("current_structure_level_list", func(ctx context.Context, fetch *datastore.Fetcher, p7on *projector.Projection) (encoded []byte, err error) {
230+
losID, _, err := getLosID(ctx, p7on.ContentObjectID, fetch)
231+
if err != nil {
232+
return nil, fmt.Errorf("error in getLosID: %w", err)
233+
}
234+
235+
var losContentObject string
236+
fetch.Fetch(ctx, &losContentObject, "list_of_speakers/%d/content_object_id", losID)
237+
if err := fetch.Err(); err != nil {
238+
return nil, fmt.Errorf("getting content object for list of speakers %d: %w", losID, err)
239+
}
240+
241+
var title string
242+
fetch.Fetch(ctx, &title, "%s/%s", losContentObject, "title")
243+
if err := fetch.Err(); err != nil {
244+
return nil, fmt.Errorf("getting title for list of speakers content object %s: %w", losContentObject, err)
245+
}
246+
247+
var structureLevelListOfSpeakersIds []int
248+
fetch.Fetch(ctx, &structureLevelListOfSpeakersIds, "list_of_speakers/%d/structure_level_list_of_speakers_ids", losID)
249+
if err := fetch.Err(); err != nil {
250+
return nil, fmt.Errorf("getting structure_level_list_of_speakers_ids for list of speakers %d: %w", losID, err)
251+
}
252+
253+
structureLevels := []structureLevelRepr{}
254+
for _, slsID := range structureLevelListOfSpeakersIds {
255+
hasSpeaker, err := structureLevelHasSpeaker(ctx, fetch, slsID)
256+
if err != nil {
257+
return nil, fmt.Errorf("checking speakers structure level los %d for list of speakers %d: %w", slsID, losID, err)
258+
}
259+
260+
if !hasSpeaker {
261+
continue
262+
}
263+
264+
slsData := fetch.Object(ctx, fmt.Sprintf("structure_level_list_of_speakers/%d", slsID), "structure_level_id", "remaining_time", "current_start_time")
265+
sls, err := structureLevelListOfSpeakersFromMap(slsData)
266+
if err != nil {
267+
return nil, fmt.Errorf("parsing structure level los %d for list of speakers %d: %w", slsID, losID, err)
268+
}
269+
270+
slData := fetch.Object(ctx, fmt.Sprintf("structure_level/%d", sls.StructureLevelID), "name", "color")
271+
sl, err := structureLevelFromMap(slData)
272+
if err != nil {
273+
return nil, fmt.Errorf("parsing structure level %d for list of speakers %d: %w", sls.StructureLevelID, losID, err)
274+
}
275+
276+
structureLevel := structureLevelRepr{
277+
ID: sls.StructureLevelID,
278+
Name: sl.Name,
279+
Color: sl.Color,
280+
RemainingTime: sls.RemainingTime,
281+
CurrentStartTime: sls.CurrentStartTime,
282+
}
283+
structureLevels = append(structureLevels, structureLevel)
284+
}
285+
286+
out := struct {
287+
Title string `json:"title"`
288+
StructureLevels []structureLevelRepr `json:"structure_levels"`
289+
}{
290+
title,
291+
structureLevels,
292+
}
293+
294+
responseValue, err := json.Marshal(out)
295+
if err != nil {
296+
return nil, fmt.Errorf("encoding response slide current_speaker_chyron: %w", err)
297+
}
298+
return responseValue, nil
299+
})
300+
}
301+
302+
// CurrentSpeakingStructureLevel renders the current_speaking_structure_level slide.
303+
func CurrentSpeakingStructureLevel(store *projector.SlideStore) {
304+
store.RegisterSliderFunc("current_speaking_structure_level", func(ctx context.Context, fetch *datastore.Fetcher, p7on *projector.Projection) (encoded []byte, err error) {
305+
losID, _, err := getLosID(ctx, p7on.ContentObjectID, fetch)
306+
if err != nil {
307+
return nil, fmt.Errorf("error in getLosID: %w", err)
308+
}
309+
310+
slsID, err := getStructureLevelData(ctx, fetch, losID)
311+
if err != nil {
312+
return nil, fmt.Errorf("error in getStructureLevelData: %w", err)
313+
}
314+
315+
if slsID != 0 {
316+
slsData := fetch.Object(ctx, fmt.Sprintf("structure_level_list_of_speakers/%d", slsID), "structure_level_id", "remaining_time", "current_start_time")
317+
sls, err := structureLevelListOfSpeakersFromMap(slsData)
318+
if err != nil {
319+
return nil, fmt.Errorf("parsing structure level los %d for list of speakers %d: %w", slsID, losID, err)
320+
}
321+
322+
slData := fetch.Object(ctx, fmt.Sprintf("structure_level/%d", sls.StructureLevelID), "name", "color")
323+
sl, err := structureLevelFromMap(slData)
324+
if err != nil {
325+
return nil, fmt.Errorf("parsing structure level %d for list of speakers %d: %w", sls.StructureLevelID, losID, err)
326+
}
327+
328+
out := structureLevelRepr{
329+
ID: sls.StructureLevelID,
330+
Name: sl.Name,
331+
Color: sl.Color,
332+
RemainingTime: sls.RemainingTime,
333+
CurrentStartTime: sls.CurrentStartTime,
334+
}
335+
336+
responseValue, err := json.Marshal(out)
337+
if err != nil {
338+
return nil, fmt.Errorf("encoding response slide current_speaking_structure_level: %w", err)
339+
}
340+
return responseValue, nil
341+
}
342+
343+
return []byte("{}"), nil
344+
})
345+
}
346+
347+
func structureLevelHasSpeaker(ctx context.Context, fetch *datastore.Fetcher, structureLevelLosID int) (spoken bool, err error) {
348+
data := fetch.Object(ctx, fmt.Sprintf("structure_level_list_of_speakers/%d", structureLevelLosID), "speaker_ids", "initial_time", "additional_time", "remaining_time", "current_start_time")
349+
sllos, err := structureLevelListOfSpeakersFromMap(data)
350+
if err != nil {
351+
return false, fmt.Errorf("loading structure level list of speakers: %w", err)
352+
}
353+
354+
if sllos.InitialTime+sllos.AdditionalTime != sllos.RemainingTime || sllos.CurrentStartTime != 0 {
355+
return true, nil
356+
}
357+
358+
for _, id := range sllos.SpeakerIDs {
359+
speechState := datastore.String(ctx, fetch.FetchIfExist, "speaker/%d/speech_state", id)
360+
if err := fetch.Err(); err != nil {
361+
return false, fmt.Errorf("Error loading speach state %d %w", id, err)
362+
}
363+
364+
if speechState == "interposed_question" || speechState == "intervention" {
365+
continue
366+
}
367+
368+
return true, nil
369+
}
370+
371+
return false, nil
372+
}
373+
181374
// getLosID determines the losID and first current_projection of the reference_projector.
182375
func getLosID(ctx context.Context, ContentObjectID string, fetch *datastore.Fetcher) (losID int, referenceProjectorID int, err error) {
183376
parts := strings.Split(ContentObjectID, "/")
@@ -219,6 +412,36 @@ func getLosID(ctx context.Context, ContentObjectID string, fetch *datastore.Fetc
219412
return losID, referenceProjectorID, nil
220413
}
221414

415+
func getStructureLevelData(ctx context.Context, fetch *datastore.Fetcher, losID int) (id int, err error) {
416+
data := fetch.Object(ctx, fmt.Sprintf("list_of_speakers/%d", losID), "speaker_ids", "content_object_id", "closed")
417+
los, err := losFromMap(data)
418+
if err != nil {
419+
return 0, fmt.Errorf("loading list of speakers: %w", err)
420+
}
421+
422+
fields := []string{
423+
"begin_time",
424+
"end_time",
425+
"speech_state",
426+
"structure_level_list_of_speakers_id",
427+
}
428+
429+
for _, id := range los.SpeakerIDs {
430+
speaker, err := speakerFromMap(fetch.Object(ctx, fmt.Sprintf("speaker/%d", id), fields...))
431+
if err != nil {
432+
return 0, fmt.Errorf("loading speaker %d: %w", id, err)
433+
}
434+
435+
if speaker.SpeakerWork.BeginTime == 0 || (speaker.SpeakerWork.BeginTime != 0 && speaker.SpeakerWork.EndTime != 0) || speaker.SpeechState == "interposed_question" || speaker.SpeakerWork.StructureLevelListOfSpeakersID == 0 {
436+
continue
437+
}
438+
439+
return speaker.SpeakerWork.StructureLevelListOfSpeakersID, nil
440+
}
441+
442+
return 0, nil
443+
}
444+
222445
func getCurrentSpeakerData(ctx context.Context, fetch *datastore.Fetcher, losID int, meetingID int) (shortName string, structureLevel string, err error) {
223446
data := fetch.Object(ctx, fmt.Sprintf("list_of_speakers/%d", losID), "speaker_ids", "content_object_id", "closed")
224447
los, err := losFromMap(data)
@@ -242,17 +465,41 @@ func getCurrentSpeakerData(ctx context.Context, fetch *datastore.Fetcher, losID
242465
continue
243466
}
244467

245-
var userID int
246-
fetch.FetchIfExist(ctx, &userID, "meeting_user/%d/user_id", speaker.SpeakerWork.MeetingUserID)
247-
if err := fetch.Err(); err != nil {
248-
return "", "", fmt.Errorf("getting user for meeting user %d: %w", speaker.SpeakerWork.MeetingUserID, err)
249-
}
468+
if speaker.SpeakerWork.MeetingUserID != 0 {
469+
var userID int
470+
fetch.FetchIfExist(ctx, &userID, "meeting_user/%d/user_id", speaker.SpeakerWork.MeetingUserID)
471+
if err := fetch.Err(); err != nil {
472+
return "", "", fmt.Errorf("getting user for meeting user %d: %w", speaker.SpeakerWork.MeetingUserID, err)
473+
}
250474

251-
user, err := NewUser(ctx, fetch, userID, meetingID)
252-
if err != nil {
253-
return "", "", fmt.Errorf("getting newUser: %w", err)
475+
user, err := NewUser(ctx, fetch, userID, meetingID)
476+
if err != nil {
477+
return "", "", fmt.Errorf("getting newUser: %w", err)
478+
}
479+
480+
var structureLevelListOfSpeakersID int
481+
fetch.FetchIfExist(ctx, &structureLevelListOfSpeakersID, "speaker/%d/structure_level_list_of_speakers_id", id)
482+
if err := fetch.Err(); err != nil {
483+
return "", "", fmt.Errorf("getting structure level for speaker %d: %w", id, err)
484+
}
485+
486+
structureLevelName := ""
487+
if structureLevelListOfSpeakersID != 0 {
488+
var structureLevelID int
489+
fetch.FetchIfExist(ctx, &structureLevelID, "structure_level_list_of_speakers/%d/structure_level_id", structureLevelListOfSpeakersID)
490+
if err := fetch.Err(); err != nil {
491+
return "", "", fmt.Errorf("getting structure level for structure_level_list_of_speakers %d: %w", structureLevelListOfSpeakersID, err)
492+
}
493+
494+
fetch.Fetch(ctx, &structureLevelName, "structure_level/%d/name", structureLevelID)
495+
if err := fetch.Err(); err != nil {
496+
return "", "", fmt.Errorf("getting name for structure level name %d: %w", structureLevelID, err)
497+
}
498+
}
499+
500+
return user.UserShortName(), structureLevelName, nil
254501
}
255-
return user.UserShortName(), user.UserStructureLevel(meetingID), nil
502+
return "", "", nil
256503
}
257504

258505
return shortName, structureLevel, nil
@@ -340,18 +587,20 @@ func getSpeakerLists(ctx context.Context, los *dbListOfSpeakers, meetingID int,
340587
return nil, nil, fmt.Errorf("loading speaker: %w", err)
341588
}
342589

343-
var userID int
344-
fetch.FetchIfExist(ctx, &userID, "meeting_user/%d/user_id", speaker.SpeakerWork.MeetingUserID)
345-
if err := fetch.Err(); err != nil {
346-
return nil, nil, fmt.Errorf("getting user for meeting user %d: %w", speaker.SpeakerWork.MeetingUserID, err)
347-
}
590+
if speaker.SpeakerWork.MeetingUserID != 0 {
591+
var userID int
592+
fetch.FetchIfExist(ctx, &userID, "meeting_user/%d/user_id", speaker.SpeakerWork.MeetingUserID)
593+
if err := fetch.Err(); err != nil {
594+
return nil, nil, fmt.Errorf("getting user for meeting user %d: %w", speaker.SpeakerWork.MeetingUserID, err)
595+
}
348596

349-
user, err := NewUser(ctx, fetch, userID, meetingID)
350-
if err != nil {
351-
return nil, nil, fmt.Errorf("loading user: %w", err)
352-
}
597+
user, err := NewUser(ctx, fetch, userID, meetingID)
598+
if err != nil {
599+
return nil, nil, fmt.Errorf("loading user: %w", err)
600+
}
353601

354-
speaker.User = user.UserRepresentation(meetingID)
602+
speaker.User = user.UserRepresentation(meetingID)
603+
}
355604

356605
if speaker.SpeakerWork.BeginTime == 0 && speaker.SpeakerWork.EndTime == 0 {
357606
*speakersWaiting = append(*speakersWaiting, *speaker)

internal/projector/slide/list_of_speakers_test.go

+14-3
Original file line numberDiff line numberDiff line change
@@ -353,21 +353,32 @@ func TestCurrentSpeakerChyron(t *testing.T) {
353353
for k, v := range dsmock.YAMLData(`
354354
speaker/8/begin_time: 100
355355
speaker/8/end_time: 0
356+
speaker/8/structure_level_list_of_speakers_id: 7
356357
357358
user/10:
358359
title: Admiral
359360
first_name: Don
360361
last_name: Snyder
361-
default_structure_level: GB
362362
meeting_user_ids: [100]
363363
364364
meeting_user/100:
365365
meeting_id: 6
366-
structure_level: Dinner
366+
structure_level_ids: [4,8]
367367
368368
projector/60:
369369
chyron_background_color: green
370370
chyron_font_color: red
371+
372+
structure_level/4:
373+
name: "Level"
374+
375+
structure_level/8:
376+
name: "Foo"
377+
378+
structure_level_list_of_speakers/7:
379+
meeting_id: 6
380+
structure_level_id: 4
381+
speaker_ids: [8]
371382
`) {
372383
data[k] = v
373384
}
@@ -384,7 +395,7 @@ func TestCurrentSpeakerChyron(t *testing.T) {
384395
"background_color": "green",
385396
"font_color": "red",
386397
"current_speaker_name": "Admiral Don Snyder",
387-
"current_speaker_level": "Dinner"
398+
"current_speaker_level": "Level"
388399
}
389400
`,
390401
},

0 commit comments

Comments
 (0)