@@ -45,13 +45,31 @@ import Wire.API.Error.Galley
4545import Wire.API.Federation.Client (FederatorClient )
4646import Wire.API.Federation.Error
4747import Wire.API.Meeting
48- import Wire.API.Team.Feature (FeatureStatus (.. ), LockableFeature (.. ), PayingTeamConfig )
48+ import Wire.API.Team.Feature (FeatureStatus (.. ), LockableFeature (.. ), MeetingConfig , MeetingPremiumConfig )
4949import Wire.FederationAPIAccess ()
5050import Wire.MeetingsSubsystem qualified as Meetings
5151import Wire.NotificationSubsystem
5252import Wire.Sem.Now (Now )
5353import Wire.TeamStore qualified as TeamStore
5454
55+ -- | Check if meetings feature is enabled for the user (if they're in a team)
56+ checkMeetingsEnabled ::
57+ ( Member TeamStore r ,
58+ Member TeamFeatureStore r ,
59+ Member (ErrorS 'InvalidOperation) r ,
60+ Member (Input Opts ) r
61+ ) =>
62+ UserId ->
63+ Sem r ()
64+ checkMeetingsEnabled userId = do
65+ maybeTeamId <- TeamStore. getOneUserTeam userId
66+ case maybeTeamId of
67+ Nothing -> pure () -- Personal users can use meetings
68+ Just teamId -> do
69+ meetingFeature <- getFeatureForTeam @ MeetingConfig teamId
70+ unless (meetingFeature. status == FeatureStatusEnabled ) $
71+ throwS @ 'InvalidOperation
72+
5573createMeeting ::
5674 ( Member Meetings. MeetingsSubsystem r ,
5775 Member (ErrorS 'InvalidOperation) r ,
@@ -73,63 +91,80 @@ createMeeting ::
7391 NewMeeting ->
7492 Sem r Meeting
7593createMeeting lUser newMeeting = do
94+ -- Check if meetings feature is enabled
95+ checkMeetingsEnabled (tUnqualified lUser)
96+
7697 -- Validate that endDate > startDate
7798 when (newMeeting. endDate <= newMeeting. startDate) $
7899 throwS @ 'InvalidOperation
79100
80- -- Determine trial status based on team membership and paying team feature
81- trial <- do
82- maybeTeamId <- TeamStore. getOneUserTeam (tUnqualified lUser)
83- case maybeTeamId of
84- Nothing -> pure True -- Personal users are trial
85- Just teamId -> do
86- -- Verify user is a team member (not just a collaborator)
87- maybeMember <- TeamStore. getTeamMember teamId (tUnqualified lUser)
88- case maybeMember of
89- Nothing -> throwS @ 'NotATeamMember -- User not a member
90- Just _member -> do
91- -- Check paying team feature status
92- payingFeature <- getFeatureForTeam @ PayingTeamConfig teamId
93- pure $ case payingFeature of
94- LockableFeature {status = FeatureStatusEnabled } -> False -- paying team, not trial
95- _ -> True -- non-paying team or disabled, is trial
101+ -- Determine trial status based on team membership and premium feature
102+ maybeTeamId <- TeamStore. getOneUserTeam (tUnqualified lUser)
103+ trial <- case maybeTeamId of
104+ Nothing -> pure True -- Personal users create trial meetings
105+ Just teamId -> do
106+ -- Verify user is a team member (not just a collaborator)
107+ maybeMember <- TeamStore. getTeamMember teamId (tUnqualified lUser)
108+ case maybeMember of
109+ Nothing -> throwS @ 'NotATeamMember -- User not a member
110+ Just _member -> do
111+ -- Check meeting premium feature status to determine trial
112+ premiumFeature <- getFeatureForTeam @ MeetingPremiumConfig teamId
113+ pure $ case premiumFeature of
114+ LockableFeature {status = FeatureStatusEnabled } -> False -- premium team, not trial
115+ _ -> True -- non-premium team or disabled, is trial
96116 (meeting, conversation) <- Meetings. createMeeting lUser newMeeting trial
97117 notifyCreatedConversation lUser Nothing conversation InternalAdd
98118 pure meeting
99119
100120getMeeting ::
101121 ( Member Meetings. MeetingsSubsystem r ,
102- Member (ErrorS 'MeetingNotFound) r
122+ Member (ErrorS 'MeetingNotFound) r ,
123+ Member TeamStore r ,
124+ Member TeamFeatureStore r ,
125+ Member (ErrorS 'InvalidOperation) r ,
126+ Member (Input Opts ) r
103127 ) =>
104128 Local UserId ->
105129 Domain ->
106130 MeetingId ->
107131 Sem r Meeting
108132getMeeting zUser domain meetingId = do
133+ checkMeetingsEnabled (tUnqualified zUser)
109134 let qMeetingId = Qualified meetingId domain
110135 maybeMeeting <- Meetings. getMeeting zUser qMeetingId
111136 case maybeMeeting of
112137 Nothing -> throwS @ 'MeetingNotFound
113138 Just meeting -> pure meeting
114139
115140listMeetings ::
116- ( Member Meetings. MeetingsSubsystem r
141+ ( Member Meetings. MeetingsSubsystem r ,
142+ Member TeamStore r ,
143+ Member TeamFeatureStore r ,
144+ Member (ErrorS 'InvalidOperation) r ,
145+ Member (Input Opts ) r
117146 ) =>
118147 Local UserId ->
119148 Sem r [Meeting ]
120- listMeetings = Meetings. listMeetings
149+ listMeetings lUser = do
150+ checkMeetingsEnabled (tUnqualified lUser)
151+ Meetings. listMeetings lUser
121152
122153updateMeeting ::
123154 ( Member Meetings. MeetingsSubsystem r ,
124155 Member (ErrorS 'MeetingNotFound) r ,
125- Member (ErrorS 'InvalidOperation) r
156+ Member (ErrorS 'InvalidOperation) r ,
157+ Member TeamStore r ,
158+ Member TeamFeatureStore r ,
159+ Member (Input Opts ) r
126160 ) =>
127161 Local UserId ->
128162 Domain ->
129163 MeetingId ->
130164 UpdateMeeting ->
131165 Sem r Meeting
132166updateMeeting zUser domain meetingId update = do
167+ checkMeetingsEnabled (tUnqualified zUser)
133168 -- Validate that at least one field is being updated
134169 when (isNothing update. title && isNothing update. startDate && isNothing update. endDate && isNothing update. recurrence) $
135170 throwS @ 'InvalidOperation
@@ -145,41 +180,56 @@ updateMeeting zUser domain meetingId update = do
145180
146181deleteMeeting ::
147182 ( Member Meetings. MeetingsSubsystem r ,
148- Member (ErrorS 'MeetingNotFound) r
183+ Member (ErrorS 'MeetingNotFound) r ,
184+ Member (ErrorS 'InvalidOperation) r ,
185+ Member TeamStore r ,
186+ Member TeamFeatureStore r ,
187+ Member (Input Opts ) r
149188 ) =>
150189 Local UserId ->
151190 Domain ->
152191 MeetingId ->
153192 Sem r ()
154193deleteMeeting zUser domain meetingId = do
194+ checkMeetingsEnabled (tUnqualified zUser)
155195 let qMeetingId = Qualified meetingId domain
156196 success <- Meetings. deleteMeeting zUser qMeetingId
157197 unless success $ throwS @ 'MeetingNotFound
158198
159199addMeetingInvitation ::
160200 ( Member Meetings. MeetingsSubsystem r ,
161- Member (ErrorS 'MeetingNotFound) r
201+ Member (ErrorS 'MeetingNotFound) r ,
202+ Member (ErrorS 'InvalidOperation) r ,
203+ Member TeamStore r ,
204+ Member TeamFeatureStore r ,
205+ Member (Input Opts ) r
162206 ) =>
163207 Local UserId ->
164208 Domain ->
165209 MeetingId ->
166210 MeetingEmailsInvitation ->
167211 Sem r ()
168212addMeetingInvitation zUser domain meetingId (MeetingEmailsInvitation emails) = do
213+ checkMeetingsEnabled (tUnqualified zUser)
169214 let qMeetingId = Qualified meetingId domain
170215 success <- Meetings. addInvitedEmails zUser qMeetingId emails
171216 unless success $ throwS @ 'MeetingNotFound
172217
173218removeMeetingInvitation ::
174219 ( Member Meetings. MeetingsSubsystem r ,
175- Member (ErrorS 'MeetingNotFound) r
220+ Member (ErrorS 'MeetingNotFound) r ,
221+ Member (ErrorS 'InvalidOperation) r ,
222+ Member TeamStore r ,
223+ Member TeamFeatureStore r ,
224+ Member (Input Opts ) r
176225 ) =>
177226 Local UserId ->
178227 Domain ->
179228 MeetingId ->
180229 MeetingEmailsInvitation ->
181230 Sem r ()
182231removeMeetingInvitation zUser domain meetingId (MeetingEmailsInvitation emails) = do
232+ checkMeetingsEnabled (tUnqualified zUser)
183233 let qMeetingId = Qualified meetingId domain
184234 success <- Meetings. removeInvitedEmails zUser qMeetingId emails
185235 unless success $ throwS @ 'MeetingNotFound
0 commit comments