@@ -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
@@ -421,6 +423,60 @@ impl Team {
421423 Ok ( groups)
422424 }
423425
426+ pub ( crate ) fn raw_zulip_streams ( & self ) -> & [ RawZulipStream ] {
427+ & self . zulip_streams
428+ }
429+
430+ pub ( crate ) fn zulip_streams ( & self , data : & Data ) -> Result < Vec < ZulipStream > , Error > {
431+ let mut streams = Vec :: new ( ) ;
432+ let zulip_streams = self . raw_zulip_streams ( ) ;
433+
434+ for raw_stream in zulip_streams {
435+ let mut stream = ZulipStream {
436+ name : raw_stream. name . clone ( ) ,
437+ members : Vec :: new ( ) ,
438+ } ;
439+
440+ let mut members = if raw_stream. include_team_members {
441+ self . members ( data) ?
442+ } else {
443+ HashSet :: new ( )
444+ } ;
445+ for person in & raw_stream. extra_people {
446+ members. insert ( person. as_str ( ) ) ;
447+ }
448+ for team in & raw_stream. extra_teams {
449+ let team = data
450+ . team ( team)
451+ . ok_or_else ( || format_err ! ( "team {} is missing" , team) ) ?;
452+ members. extend ( team. members ( data) ?) ;
453+ }
454+ for excluded in & raw_stream. excluded_people {
455+ if !members. remove ( excluded. as_str ( ) ) {
456+ bail ! ( "'{excluded}' was specifically excluded from the Zulip stream '{}' but they were already not included" , raw_stream. name) ;
457+ }
458+ }
459+
460+ for member in members. iter ( ) {
461+ let member = data. person ( member) . ok_or_else ( || {
462+ format_err ! ( "{} does not have a person configuration" , member)
463+ } ) ?;
464+ let member = match ( member. github . clone ( ) , member. zulip_id ) {
465+ ( github, Some ( zulip_id) ) => {
466+ ZulipStreamMember :: MemberWithId { github, zulip_id }
467+ }
468+ ( github, _) => ZulipStreamMember :: MemberWithoutId { github } ,
469+ } ;
470+ stream. members . push ( member) ;
471+ }
472+ for & extra in & raw_stream. extra_zulip_ids {
473+ stream. members . push ( ZulipStreamMember :: JustId ( extra) ) ;
474+ }
475+ streams. push ( stream) ;
476+ }
477+ Ok ( streams)
478+ }
479+
424480 pub ( crate ) fn permissions ( & self ) -> & Permissions {
425481 & self . permissions
426482 }
@@ -691,6 +747,22 @@ pub(crate) struct RawZulipGroup {
691747 pub ( crate ) excluded_people : Vec < String > ,
692748}
693749
750+ #[ derive( serde_derive:: Deserialize , Debug ) ]
751+ #[ serde( rename_all = "kebab-case" , deny_unknown_fields) ]
752+ pub ( crate ) struct RawZulipStream {
753+ pub ( crate ) name : String ,
754+ #[ serde( default = "default_true" ) ]
755+ pub ( crate ) include_team_members : bool ,
756+ #[ serde( default ) ]
757+ pub ( crate ) extra_people : Vec < String > ,
758+ #[ serde( default ) ]
759+ pub ( crate ) extra_zulip_ids : Vec < u64 > ,
760+ #[ serde( default ) ]
761+ pub ( crate ) extra_teams : Vec < String > ,
762+ #[ serde( default ) ]
763+ pub ( crate ) excluded_people : Vec < String > ,
764+ }
765+
694766#[ derive( Debug ) ]
695767pub ( crate ) struct List {
696768 address : String ,
@@ -736,6 +808,29 @@ pub(crate) enum ZulipGroupMember {
736808 MemberWithoutId { github : String } ,
737809}
738810
811+ #[ derive( Debug ) ]
812+ pub ( crate ) struct ZulipStream {
813+ name : String ,
814+ members : Vec < ZulipStreamMember > ,
815+ }
816+
817+ impl ZulipStream {
818+ pub ( crate ) fn name ( & self ) -> & str {
819+ & self . name
820+ }
821+
822+ pub ( crate ) fn members ( & self ) -> & [ ZulipStreamMember ] {
823+ & self . members
824+ }
825+ }
826+
827+ #[ derive( Debug , Clone , Ord , PartialOrd , Eq , PartialEq , Hash ) ]
828+ pub ( crate ) enum ZulipStreamMember {
829+ MemberWithId { github : String , zulip_id : u64 } ,
830+ JustId ( u64 ) ,
831+ MemberWithoutId { github : String } ,
832+ }
833+
739834fn default_true ( ) -> bool {
740835 true
741836}
0 commit comments