@@ -179,6 +179,8 @@ pub(crate) struct Team {
179179 lists : Vec < TeamList > ,
180180 #[ serde( default ) ]
181181 zulip_groups : Vec < RawZulipGroup > ,
182+ #[ serde( default ) ]
183+ zulip_streams : Vec < RawZulipStream > ,
182184 discord_roles : Option < Vec < DiscordRole > > ,
183185}
184186
@@ -364,6 +366,51 @@ impl Team {
364366 Ok ( lists)
365367 }
366368
369+ /// `on_exclude_not_included` is a function that is returned when an excluded member
370+ /// wasn't included.
371+ fn expand_zulip_membership (
372+ & self ,
373+ data : & Data ,
374+ common : & RawZulipCommon ,
375+ on_exclude_not_included : impl Fn ( & str ) -> Error ,
376+ ) -> Result < Vec < ZulipMember > , Error > {
377+ let mut members = if common. include_team_members {
378+ self . members ( data) ?
379+ } else {
380+ HashSet :: new ( )
381+ } ;
382+ for person in & common. extra_people {
383+ members. insert ( person. as_str ( ) ) ;
384+ }
385+ for team in & common. extra_teams {
386+ let team = data
387+ . team ( team)
388+ . ok_or_else ( || format_err ! ( "team {} is missing" , team) ) ?;
389+ members. extend ( team. members ( data) ?) ;
390+ }
391+ for excluded in & common. excluded_people {
392+ if !members. remove ( excluded. as_str ( ) ) {
393+ return Err ( on_exclude_not_included ( excluded) ) ;
394+ }
395+ }
396+
397+ let mut final_members = Vec :: new ( ) ;
398+ for member in members. iter ( ) {
399+ let member = data
400+ . person ( member)
401+ . ok_or_else ( || format_err ! ( "{} does not have a person configuration" , member) ) ?;
402+ let member = match ( member. github . clone ( ) , member. zulip_id ) {
403+ ( github, Some ( zulip_id) ) => ZulipMember :: MemberWithId { github, zulip_id } ,
404+ ( github, _) => ZulipMember :: MemberWithoutId { github } ,
405+ } ;
406+ final_members. push ( member) ;
407+ }
408+ for & extra in & common. extra_zulip_ids {
409+ final_members. push ( ZulipMember :: JustId ( extra) ) ;
410+ }
411+ Ok ( final_members)
412+ }
413+
367414 pub ( crate ) fn raw_zulip_groups ( & self ) -> & [ RawZulipGroup ] {
368415 & self . zulip_groups
369416 }
@@ -373,48 +420,43 @@ impl Team {
373420 let zulip_groups = & self . zulip_groups ;
374421
375422 for raw_group in zulip_groups {
376- let mut group = ZulipGroup {
377- name : raw_group. name . clone ( ) ,
378- includes_team_members : raw_group. include_team_members ,
379- members : Vec :: new ( ) ,
380- } ;
423+ groups. push ( ZulipGroup ( ZulipCommon {
424+ name : raw_group. common . name . clone ( ) ,
425+ includes_team_members : raw_group. common . include_team_members ,
426+ members : self . expand_zulip_membership (
427+ data,
428+ & raw_group. common ,
429+ |excluded| {
430+ format_err ! ( "'{excluded}' was specifically excluded from the Zulip group '{}' but they were already not included" , raw_group. common. name)
431+ } ,
432+ ) ?,
433+ } ) ) ;
434+ }
435+ Ok ( groups)
436+ }
381437
382- let mut members = if raw_group. include_team_members {
383- self . members ( data) ?
384- } else {
385- HashSet :: new ( )
386- } ;
387- for person in & raw_group. extra_people {
388- members. insert ( person. as_str ( ) ) ;
389- }
390- for team in & raw_group. extra_teams {
391- let team = data
392- . team ( team)
393- . ok_or_else ( || format_err ! ( "team {} is missing" , team) ) ?;
394- members. extend ( team. members ( data) ?) ;
395- }
396- for excluded in & raw_group. excluded_people {
397- if !members. remove ( excluded. as_str ( ) ) {
398- bail ! ( "'{excluded}' was specifically excluded from the Zulip group '{}' but they were already not included" , raw_group. name) ;
399- }
400- }
438+ pub ( crate ) fn raw_zulip_streams ( & self ) -> & [ RawZulipStream ] {
439+ & self . zulip_streams
440+ }
401441
402- for member in members. iter ( ) {
403- let member = data. person ( member) . ok_or_else ( || {
404- format_err ! ( "{} does not have a person configuration" , member)
405- } ) ?;
406- let member = match ( member. github . clone ( ) , member. zulip_id ) {
407- ( github, Some ( zulip_id) ) => ZulipGroupMember :: MemberWithId { github, zulip_id } ,
408- ( github, _) => ZulipGroupMember :: MemberWithoutId { github } ,
409- } ;
410- group. members . push ( member) ;
411- }
412- for & extra in & raw_group. extra_zulip_ids {
413- group. members . push ( ZulipGroupMember :: JustId ( extra) ) ;
414- }
415- groups. push ( group) ;
442+ pub ( crate ) fn zulip_streams ( & self , data : & Data ) -> Result < Vec < ZulipStream > , Error > {
443+ let mut streams = Vec :: new ( ) ;
444+ let zulip_streams = self . raw_zulip_streams ( ) ;
445+
446+ for raw_stream in zulip_streams {
447+ streams. push ( ZulipStream ( ZulipCommon {
448+ name : raw_stream. common . name . clone ( ) ,
449+ includes_team_members : raw_stream. common . include_team_members ,
450+ members : self . expand_zulip_membership (
451+ data,
452+ & raw_stream. common ,
453+ |excluded| {
454+ format_err ! ( "'{excluded}' was specifically excluded from the Zulip stream '{}' but they were already not included" , raw_stream. common. name)
455+ } ,
456+ ) ?,
457+ } ) ) ;
416458 }
417- Ok ( groups )
459+ Ok ( streams )
418460 }
419461
420462 pub ( crate ) fn permissions ( & self ) -> & Permissions {
@@ -677,7 +719,7 @@ pub(crate) struct TeamList {
677719
678720#[ derive( serde_derive:: Deserialize , Debug ) ]
679721#[ serde( rename_all = "kebab-case" , deny_unknown_fields) ]
680- pub ( crate ) struct RawZulipGroup {
722+ pub ( crate ) struct RawZulipCommon {
681723 pub ( crate ) name : String ,
682724 #[ serde( default = "default_true" ) ]
683725 pub ( crate ) include_team_members : bool ,
@@ -691,6 +733,20 @@ pub(crate) struct RawZulipGroup {
691733 pub ( crate ) excluded_people : Vec < String > ,
692734}
693735
736+ #[ derive( serde_derive:: Deserialize , Debug ) ]
737+ #[ serde( rename_all = "kebab-case" , deny_unknown_fields) ]
738+ pub ( crate ) struct RawZulipGroup {
739+ #[ serde( flatten) ]
740+ pub ( crate ) common : RawZulipCommon ,
741+ }
742+
743+ #[ derive( serde_derive:: Deserialize , Debug ) ]
744+ #[ serde( rename_all = "kebab-case" , deny_unknown_fields) ]
745+ pub ( crate ) struct RawZulipStream {
746+ #[ serde( flatten) ]
747+ pub ( crate ) common : RawZulipCommon ,
748+ }
749+
694750#[ derive( Debug ) ]
695751pub ( crate ) struct List {
696752 address : String ,
@@ -708,29 +764,49 @@ impl List {
708764}
709765
710766#[ derive( Debug ) ]
711- pub ( crate ) struct ZulipGroup {
767+ pub ( crate ) struct ZulipCommon {
712768 name : String ,
713769 includes_team_members : bool ,
714- members : Vec < ZulipGroupMember > ,
770+ members : Vec < ZulipMember > ,
715771}
716772
717- impl ZulipGroup {
773+ impl ZulipCommon {
718774 pub ( crate ) fn name ( & self ) -> & str {
719775 & self . name
720776 }
721777
722- /// Whether the group includes the members of the team its associated
778+ /// Whether the group/stream includes the members of the associated team?
723779 pub ( crate ) fn includes_team_members ( & self ) -> bool {
724780 self . includes_team_members
725781 }
726782
727- pub ( crate ) fn members ( & self ) -> & [ ZulipGroupMember ] {
783+ pub ( crate ) fn members ( & self ) -> & [ ZulipMember ] {
728784 & self . members
729785 }
730786}
731787
788+ #[ derive( Debug ) ]
789+ pub ( crate ) struct ZulipGroup ( ZulipCommon ) ;
790+
791+ impl std:: ops:: Deref for ZulipGroup {
792+ type Target = ZulipCommon ;
793+ fn deref ( & self ) -> & Self :: Target {
794+ & self . 0
795+ }
796+ }
797+
798+ #[ derive( Debug ) ]
799+ pub ( crate ) struct ZulipStream ( ZulipCommon ) ;
800+
801+ impl std:: ops:: Deref for ZulipStream {
802+ type Target = ZulipCommon ;
803+ fn deref ( & self ) -> & Self :: Target {
804+ & self . 0
805+ }
806+ }
807+
732808#[ derive( Debug , Clone , Ord , PartialOrd , Eq , PartialEq , Hash ) ]
733- pub ( crate ) enum ZulipGroupMember {
809+ pub ( crate ) enum ZulipMember {
734810 MemberWithId { github : String , zulip_id : u64 } ,
735811 JustId ( u64 ) ,
736812 MemberWithoutId { github : String } ,
0 commit comments