Skip to content

Commit 25c088a

Browse files
committed
model: Add hasPostingPermission helper method to PerAccountStore
1 parent 6b4c569 commit 25c088a

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

lib/model/store.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,30 @@ class PerAccountStore extends ChangeNotifier with EmojiStore, ChannelStore, Mess
474474

475475
final ChannelStoreImpl _channels;
476476

477+
bool hasPostingPermission({
478+
required ZulipStream inChannel,
479+
required User user,
480+
required DateTime byDate,
481+
}) {
482+
final role = user.role;
483+
// We let the users with [unknown] role to send the message, then the server
484+
// will decide to accept it or not based on its actual role.
485+
if (role == UserRole.unknown) return true;
486+
487+
switch (inChannel.channelPostPolicy) {
488+
case ChannelPostPolicy.any: return true;
489+
case ChannelPostPolicy.fullMembers: {
490+
if (!role.isAtLeast(UserRole.member)) return false;
491+
return role == UserRole.member
492+
? hasPassedWaitingPeriod(user, byDate: byDate)
493+
: true;
494+
}
495+
case ChannelPostPolicy.moderators: return role.isAtLeast(UserRole.moderator);
496+
case ChannelPostPolicy.administrators: return role.isAtLeast(UserRole.administrator);
497+
case ChannelPostPolicy.unknown: return true;
498+
}
499+
}
500+
477501
////////////////////////////////
478502
// Messages, and summaries of messages.
479503

test/model/store_test.dart

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,82 @@ void main() {
269269
}
270270
});
271271

272+
group('PerAccountStore.hasPostingPermission', () {
273+
final testCases = [
274+
(ChannelPostPolicy.unknown, UserRole.unknown, true),
275+
(ChannelPostPolicy.unknown, UserRole.guest, true),
276+
(ChannelPostPolicy.unknown, UserRole.member, true),
277+
(ChannelPostPolicy.unknown, UserRole.moderator, true),
278+
(ChannelPostPolicy.unknown, UserRole.administrator, true),
279+
(ChannelPostPolicy.unknown, UserRole.owner, true),
280+
(ChannelPostPolicy.any, UserRole.unknown, true),
281+
(ChannelPostPolicy.any, UserRole.guest, true),
282+
(ChannelPostPolicy.any, UserRole.member, true),
283+
(ChannelPostPolicy.any, UserRole.moderator, true),
284+
(ChannelPostPolicy.any, UserRole.administrator, true),
285+
(ChannelPostPolicy.any, UserRole.owner, true),
286+
(ChannelPostPolicy.fullMembers, UserRole.unknown, true),
287+
(ChannelPostPolicy.fullMembers, UserRole.guest, false),
288+
// The fullMembers/member case gets its own tests further below.
289+
// (ChannelPostPolicy.fullMembers, UserRole.member, /* complicated */),
290+
(ChannelPostPolicy.fullMembers, UserRole.moderator, true),
291+
(ChannelPostPolicy.fullMembers, UserRole.administrator, true),
292+
(ChannelPostPolicy.fullMembers, UserRole.owner, true),
293+
(ChannelPostPolicy.moderators, UserRole.unknown, true),
294+
(ChannelPostPolicy.moderators, UserRole.guest, false),
295+
(ChannelPostPolicy.moderators, UserRole.member, false),
296+
(ChannelPostPolicy.moderators, UserRole.moderator, true),
297+
(ChannelPostPolicy.moderators, UserRole.administrator, true),
298+
(ChannelPostPolicy.moderators, UserRole.owner, true),
299+
(ChannelPostPolicy.administrators, UserRole.unknown, true),
300+
(ChannelPostPolicy.administrators, UserRole.guest, false),
301+
(ChannelPostPolicy.administrators, UserRole.member, false),
302+
(ChannelPostPolicy.administrators, UserRole.moderator, false),
303+
(ChannelPostPolicy.administrators, UserRole.administrator, true),
304+
(ChannelPostPolicy.administrators, UserRole.owner, true),
305+
];
306+
307+
for (final (ChannelPostPolicy policy, UserRole role, bool canPost) in testCases) {
308+
test('"${role.name}" user ${canPost ? 'can' : "can't"} post in channel '
309+
'with "${policy.name}" policy', () {
310+
final store = eg.store();
311+
final actual = store.hasPostingPermission(
312+
inChannel: eg.stream(channelPostPolicy: policy), user: eg.user(role: role),
313+
// [byDate] is not actually relevant for these test cases; for the
314+
// ones which it is, they're practiced below.
315+
byDate: DateTime.now());
316+
check(actual).equals(canPost);
317+
});
318+
}
319+
320+
group('"member" user posting in a channel with "fullMembers" policy', () {
321+
PerAccountStore localStore({required int realmWaitingPeriodThreshold}) =>
322+
eg.store(initialSnapshot: eg.initialSnapshot(
323+
realmWaitingPeriodThreshold: realmWaitingPeriodThreshold));
324+
325+
User memberUser({required String dateJoined}) => eg.user(
326+
role: UserRole.member, dateJoined: dateJoined);
327+
328+
test('a "full" member -> can post in the channel', () {
329+
final store = localStore(realmWaitingPeriodThreshold: 3);
330+
final hasPermission = store.hasPostingPermission(
331+
inChannel: eg.stream(channelPostPolicy: ChannelPostPolicy.fullMembers),
332+
user: memberUser(dateJoined: '2024-11-25T10:00+00:00'),
333+
byDate: DateTime.utc(2024, 11, 28, 10, 00));
334+
check(hasPermission).isTrue();
335+
});
336+
337+
test('not a "full" member -> cannot post in the channel', () {
338+
final store = localStore(realmWaitingPeriodThreshold: 3);
339+
final actual = store.hasPostingPermission(
340+
inChannel: eg.stream(channelPostPolicy: ChannelPostPolicy.fullMembers),
341+
user: memberUser(dateJoined: '2024-11-25T10:00+00:00'),
342+
byDate: DateTime.utc(2024, 11, 28, 09, 59));
343+
check(actual).isFalse();
344+
});
345+
});
346+
});
347+
272348
group('PerAccountStore.handleEvent', () {
273349
// Mostly this method just dispatches to ChannelStore and MessageStore etc.,
274350
// and so most of the tests live in the test files for those

0 commit comments

Comments
 (0)