Skip to content

Commit c6206a8

Browse files
committed
realm: Add selfHasPermissionForGroupSetting
1 parent 1550173 commit c6206a8

File tree

2 files changed

+93
-1
lines changed

2 files changed

+93
-1
lines changed

lib/model/realm.dart

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,14 @@ mixin RealmStore on PerAccountStoreBase, UserGroupStore {
121121
}
122122
return topic;
123123
}
124+
125+
/// Whether the self-user has the given (group-based) permission.
126+
bool selfHasPermissionForGroupSetting(GroupSettingValue value,
127+
GroupSettingType type, String name);
124128
}
125129

130+
enum GroupSettingType { realm, stream, group }
131+
126132
mixin ProxyRealmStore on RealmStore {
127133
@protected
128134
RealmStore get realmStore;
@@ -159,6 +165,9 @@ mixin ProxyRealmStore on RealmStore {
159165
Map<String, RealmDefaultExternalAccount> get realmDefaultExternalAccounts => realmStore.realmDefaultExternalAccounts;
160166
@override
161167
List<CustomProfileField> get customProfileFields => realmStore.customProfileFields;
168+
@override
169+
bool selfHasPermissionForGroupSetting(GroupSettingValue value, GroupSettingType type, String name) =>
170+
realmStore.selfHasPermissionForGroupSetting(value, type, name);
162171
}
163172

164173
/// A base class for [PerAccountStore] substores that need access to [RealmStore]
@@ -197,12 +206,45 @@ class RealmStoreImpl extends HasUserGroupStore with RealmStore {
197206
realmDefaultExternalAccounts = initialSnapshot.realmDefaultExternalAccounts,
198207
customProfileFields = _sortCustomProfileFields(initialSnapshot.customProfileFields);
199208

209+
@override
210+
bool selfHasPermissionForGroupSetting(GroupSettingValue value,
211+
GroupSettingType type, String name) {
212+
// Compare web's settings_data.user_has_permission_for_group_setting.
213+
//
214+
// In the whole web app, there's just one caller for that function with
215+
// a user other than the self user: stream_data.can_post_messages_in_stream,
216+
// and only for get_current_user_and_their_bots_with_post_messages_permission,
217+
// with only the self-user's own bots as the arguments.
218+
// That exists for deciding whether to offer the "Generate email address"
219+
// button, and if so then which users to offer in the dropdown;
220+
// it's predicting whether /api/get-stream-email-address would succeed.
221+
if (_selfUserRole == UserRole.guest) {
222+
final config = _groupSettingConfig(type, name);
223+
if (!config.allowEveryoneGroup) return false;
224+
}
225+
return selfInGroupSetting(value);
226+
}
227+
228+
/// The metadata for how to interpret the given group-based permission setting.
229+
PermissionSettingsItem _groupSettingConfig(GroupSettingType type, String name) {
230+
final supportedSettings = SupportedPermissionSettings.fixture;
231+
232+
// Compare web's group_permission_settings.get_group_permission_setting_config.
233+
final configGroup = switch (type) {
234+
GroupSettingType.realm => supportedSettings.realm,
235+
GroupSettingType.stream => supportedSettings.stream,
236+
GroupSettingType.group => supportedSettings.group,
237+
};
238+
final config = configGroup[name];
239+
return config!; // TODO(log)
240+
}
241+
200242
/// The [User.role] of the self-user.
201243
///
202244
/// The main home of this information is [UserStore]: `store.selfUser.role`.
203245
/// We need it here for interpreting some permission settings;
204246
/// so we denormalize it here to avoid a cycle between substores.
205-
UserRole _selfUserRole; // ignore: unused_field // TODO(#814)
247+
UserRole _selfUserRole;
206248

207249
@override
208250
final int serverPresencePingIntervalSeconds;

test/model/realm_test.dart

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'package:checks/checks.dart';
22
import 'package:test/scaffolding.dart';
33
import 'package:zulip/api/model/events.dart';
44
import 'package:zulip/api/model/model.dart';
5+
import 'package:zulip/model/realm.dart';
56

67
import '../example_data.dart' as eg;
78

@@ -34,6 +35,55 @@ void main() {
3435
doCheck(eg.t('(no topic)'), eg.t(''), 370);
3536
});
3637

38+
group('selfHasPermissionForGroupSetting', () {
39+
// Most of the implementation of this is in [UserGroupStore.selfInGroupSetting],
40+
// and is tested in more detail in user_group_test.dart .
41+
42+
bool hasPermission(User selfUser, UserGroup group, String permissionName) {
43+
final store = eg.store(selfUser: selfUser,
44+
initialSnapshot: eg.initialSnapshot(
45+
realmUsers: [selfUser], realmUserGroups: [group]));
46+
return store.selfHasPermissionForGroupSetting(
47+
GroupSettingValueNamed(group.id),
48+
GroupSettingType.stream, permissionName);
49+
}
50+
51+
test('not in group -> no permission', () {
52+
final selfUser = eg.user();
53+
final group = eg.userGroup(members: []);
54+
check(hasPermission(selfUser, group, 'can_subscribe_group'))
55+
.isFalse();
56+
});
57+
58+
test('in group -> has permission', () {
59+
final selfUser = eg.user();
60+
final group = eg.userGroup(members: [selfUser.userId]);
61+
check(hasPermission(selfUser, group, 'can_subscribe_group'))
62+
.isTrue();
63+
});
64+
65+
test('guest -> no permission, despite group', () {
66+
final selfUser = eg.user(role: UserRole.guest);
67+
final group = eg.userGroup(members: [selfUser.userId]);
68+
check(hasPermission(selfUser, group, 'can_subscribe_group'))
69+
.isFalse();
70+
});
71+
72+
test('guest -> still has permission, if allowEveryoneGroup', () {
73+
final selfUser = eg.user(role: UserRole.guest);
74+
final group = eg.userGroup(members: [selfUser.userId]);
75+
check(hasPermission(selfUser, group, 'can_send_message_group'))
76+
.isTrue();
77+
});
78+
79+
test('guest not in group -> no permission, even if allowEveryoneGroup', () {
80+
final selfUser = eg.user(role: UserRole.guest);
81+
final group = eg.userGroup(members: []);
82+
check(hasPermission(selfUser, group, 'can_send_message_group'))
83+
.isFalse();
84+
});
85+
});
86+
3787
group('customProfileFields', () {
3888
test('update clobbers old list', () async {
3989
final store = eg.store(initialSnapshot: eg.initialSnapshot(

0 commit comments

Comments
 (0)