-
-
Notifications
You must be signed in to change notification settings - Fork 7.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add API support to set can_mention_group
setting to anonymous user group.
#29937
Conversation
zerver/lib/user_groups.py
Outdated
direct_subgroups: List[int], | ||
current_setting_value: Optional[UserGroup], | ||
) -> UserGroup: # nocoverage | ||
if current_setting_value is not None and not hasattr(current_setting_value, "named_user_group"): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can probably avoid one query here by updating the UserGroup query to have select_related(can_mention_group__named_user_group)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That might be worth doing -- but seems reasonable to leave for a follow-up.
zerver/openapi/zulip.yaml
Outdated
The list of user group IDs that are direct subgroups of the user group. | ||
type: array | ||
items: | ||
type: integer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be taking another pass at the API documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think we want to define it as a type at the bottom of the file, so the markup here can just be an include, plus I guess the Changes
entry.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I have kept description separate here for now since the description is not exactly same at all places like we use "permission to mention the new group" in a couple of places like the endpoint to create groups.
zerver/lib/user_groups.py
Outdated
"can_mention_group", "can_mention_group__named_user_group" | ||
) | ||
.prefetch_related( | ||
"can_mention_group__direct_members", "can_mention_group__direct_subgroups" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This adds two queries - one to fetch direct_members
and one for direct_subgroups
. And this count will keep increasing for each setting that we add.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
37d6b40#r1589802705 might help the prefetching work properly? Not sure.
A single bump of two queries is OK, but we'll need to figure out a way to make it just do two queries period -- one to fetch realm_groups
and the second to fetch all of the groups they point to, and Python can glue it together.
It should be possible to make that happen, but it's likely very messy, so I think we should just leave a TODO
comment here and fix it in a follow-up before adding 4 more group-valued settings here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we can do that. Will do it as a follow-up.
zerver/views/user_groups.py
Outdated
parsed_current_setting_value = get_parsed_group_setting_value(current_value) | ||
|
||
return not is_api_value_same_as_current_setting_value( | ||
parsed_current_setting_value, new_setting_value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure of the function and variable name here, just added them in a way so that we can avoid duplicate logic and also need not have queries like user_group.direct_members.all()
twice. Any suggestions would be helpful here.
zerver/lib/exceptions.py
Outdated
@staticmethod | ||
@override | ||
def msg_format() -> str: | ||
return _("Someone else modified this setting at the same time.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what should be the message and the class name here. Used one of the error code suggested in CZO for now, but we can change after more discussion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah post in "api design" asking for suggests text, I think we can do better but seems not a blocker.
zerver/views/user_groups.py
Outdated
@@ -138,12 +138,20 @@ def is_api_value_same_as_current_setting_value( | |||
) == set(current_value["direct_subgroups"]) | |||
|
|||
|
|||
def check_setting_value_changed( | |||
def can_edit_group_setting( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here again, this can be named better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe validate_group_setting_value_change
zerver/views/user_groups.py
Outdated
current_value: Union[int, AnonymousSettingGroupDict], | ||
api_value: Union[int, AnonymousSettingGroupDict], | ||
) -> bool: | ||
if isinstance(current_value, int): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not confident of this function here, since it seems somewhat hard to read. Would try to think of something so that we can get a better readable function but we also duplicate a lot of code and queries. Maybe we can add some comments for explaination.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think probably the right approach involves having a bit of code that rewrites the {direct_members: [], direct_subgroups: [group_id]}
format into the integer format at the API boundary, before we try to look up any objects; possibly even in a typed_endpoint
parsing function layer, or as basically the first thing we do in the views code -- and then we don't need to consider that type of possibility here, since the only way to have equality is if they're both a pure integer or identical dicts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure how to do it in typed_endpoint
but added the code to use a function to parse this in the views at top itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, seems fine to do that as a follow-up refactor later.
can_mention_group
setting to anonymous user group.can_mention_group
setting to anonymous user group.
zerver/lib/user_groups.py
Outdated
return named_user_group.usergroup_ptr | ||
|
||
assert "direct_members" in setting_user_group | ||
assert "direct_subgroups" in setting_user_group |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could probably be removed by making AnonymousSettingGroupDict
better defined, but we might also want to change it to a dataclass
anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had added these statements when I was not using TypedDict
. Anyways changed it to a dataclass
.
zerver/lib/user_groups.py
Outdated
check_setting_configuration_for_system_groups( | ||
named_user_group, setting_name, permission_configuration | ||
) | ||
return named_user_group.usergroup_ptr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to deduplicate this with the block at the top of the file; I think it might feel easier to do that after resolving 7df7a3e#r1589801457 though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The link would not point to any comment, but this was on the code which checked the case of len(direct_members) == 0 and len(direct_subgroups) == 1)
, which is now removed and we convert such cases to an integer in views code itself.
zerver/lib/user_groups.py
Outdated
"direct_members": [member.id for member in setting_value_group.direct_members.all()], | ||
"direct_subgroups": [ | ||
subgroup.id for subgroup in setting_value_group.direct_subgroups.all() | ||
], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These queries are inefficient, use .values_list(flat=True)
to only ask the database for the list of IDs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we use values_list(flat=True)
, then there would be no advantage of using prefetch_related
and there would be a new query for each group, since prefetch_related
caches the result for group.direct_members.all()
call only.
Instead updated the prefetch_related
call to set the queryset with .only("id")
.
zerver/actions/user_groups.py
Outdated
@@ -175,7 +176,7 @@ def do_send_create_user_group_event( | |||
id=user_group.id, | |||
is_system_group=user_group.is_system_group, | |||
direct_subgroup_ids=[direct_subgroup.id for direct_subgroup in direct_subgroups], | |||
can_mention_group=user_group.can_mention_group_id, | |||
can_mention_group=get_group_setting_value_for_api(user_group.can_mention_group), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This hunk might belong in the previous commit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before this commit, one could only set the setting to named user groups while creating groups, so passing ID would have been fine then. But this commit adds support to set the setting to anonymous groups as well, and thus added this change here.
zerver/lib/event_schema.py
Outdated
int, | ||
DictType( | ||
required_keys=[("direct_members", ListType(int)), ("direct_subgroups", ListType(int))] | ||
), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would probably line-wrap this so each field gets its own line; you can tell ruff-format
that's what you want by adding trailing commas.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
zerver/views/user_groups.py
Outdated
), | ||
), | ||
] | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess next time you're looking at writing a validator function like this, it's probably worth just converting the file to the typed_endpoint
/ Pydantic system first, since it'll save a migration later.
zerver/openapi/zulip.yaml
Outdated
anonymous user group. | ||
|
||
The request will be rejected if this value does not match | ||
the actual setting value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should explain the purpose of this parameter a bit more clearly -- the fact that it's optional, but also that the purpose is to prevent races by having the client send what value it expects the server to already have.
I guess that does present a question of whether we want to call this _expected_current
instead of _previous
; probably worth discussing that detail a bit.
): | ||
# We do not allow changing the setting if the value sent in | ||
# "_previous" field is not same as the current setting value. | ||
raise PreviousSettingValueMismatchedError |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like with the API documentation, this is a good place for a comment, but the should hint concisely what's going on -- e.g., that this check is here to help prevent races, by refusing to change a setting where the client (and thus UI it was presenting to the user) showed a different existing state.
Awesome, this is looking great! I think the slowest part of finishing it might be finalizing some of the naming questions in the "api design" stream; I gave this a full read and the above are my only implementation notes. |
zerver/actions/user_groups.py
Outdated
RealmAuditLog.OLD_VALUE: get_group_setting_value_for_audit_log_data( | ||
old_setting_api_value | ||
), | ||
RealmAuditLog.NEW_VALUE: get_group_setting_value_for_audit_log_data( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is because the extra_data
field needs a JSON serializable object and thus we cannot set these to a dataclass. This worked previously because we used TypedDict.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense! Probably worth having get_group_setting_value_for_audit_log_data
include a comment explaining that detail.
zerver/views/user_groups.py
Outdated
@@ -121,6 +122,34 @@ def get_user_group(request: HttpRequest, user_profile: UserProfile) -> HttpRespo | |||
return json_success(request, data={"user_groups": user_groups}) | |||
|
|||
|
|||
def are_both_setting_values_equal( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is a better name for this function. We can also move this function to zerver.lib.user_groups
probably or some file like zerver.lib.utils
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zerver.lib.user_groups
seems probably a better home.
Added a commit to migrate the endpoints to use So, instead added the commit at the end when we no longer require |
Have not made any changes to the commit for adding the |
0a2235e
to
0cf142d
Compare
0cf142d
to
b3cca0a
Compare
zerver/openapi/zulip.yaml
Outdated
to mention the group. | ||
- $ref: "#/components/schemas/CanMentionGroup" | ||
required: | ||
- new |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated the PR -
Have not updated the error code and message yet when the previous value is not correct. Also, finding it hard to explain the allowed value in API docs, so would be good to get some help on that. |
b3cca0a
to
b79510d
Compare
5b4e87b
to
aeb4ea5
Compare
api_docs/updating-group-settings.md
Outdated
@@ -0,0 +1,32 @@ | |||
# Updating group settings | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably add an introductory line here like "Client should pass a group setting update object", but am not sure how to phrase it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I'll do an introduction revision pass on this before merging, looks like a great start though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ended up doing quite a bit of reworking to make this nice:
diff --git a/api_docs/changelog.md b/api_docs/changelog.md
index 6c7401c8b0..a54dd829cf 100644
--- a/api_docs/changelog.md
+++ b/api_docs/changelog.md
@@ -23,8 +23,8 @@ format used by the Zulip server that they are interacting with.
**Feature level 260**:
* [`PATCH /user_groups/{user_group_id}`](/api/update-user-group):
- `can_mention_group` parameter now also accepts object value
- containing `old` and `new` fields.
+ Updating `can_mention_group` now uses a race-resistant format where
+ the client sends the expected `old` value and desired `new` value.
**Feature level 259**:
diff --git a/api_docs/group-setting-values.md b/api_docs/group-setting-values.md
new file mode 100644
index 0000000000..aceaf4f7c2
--- /dev/null
+++ b/api_docs/group-setting-values.md
@@ -0,0 +1,83 @@
+# Group-setting values
+
+Settings defining permissions in Zulip are increasingly represented
+using [user groups](/help/user-groups), which offer much more flexible
+configuration than the older [roles](/api/roles-and-permissions) system.
+
+In the API, these settings are represented using a **group-setting
+value**, which can take two forms:
+
+- An integer user group ID, which can be either a named user group
+ visible in the UI or a [role-based system group](#system-groups).
+- An object with fields `direct_member_ids` containing a list of
+ integer user IDs and `direct_subgroup_ids` containing a list of
+ integer group IDs. The setting's value is the union of the
+ identified collection of users and groups.
+
+Group-setting values in the object form function very much like a
+formal user group object, without requiring the naming and UI clutter
+overhead involved with creating a visible user group just to store the
+value of a single setting.
+
+The server will canonicalize an object with empty `direct_member_ids`
+and with `direct_subgroup_ids` containing just the given group ID to
+the integer format.
+
+## System groups
+
+The Zulip server maintains a collection of system groups that
+correspond to the users with a given role; this makes it convenient to
+store concepts like "all administrators" in a group-setting
+value. These use a special naming convention and can be recognized by
+the `is_system_group` property on their group object.
+
+The following system groups are maintained by the Zulip server:
+
+- `role:internet`: Everyone on the Internet has this permission; this
+ is used to configure the [public access
+ option](/help/public-access-option).
+- `role:everyone`: All users, including guests.
+- `role:members`: All users, excluding guests.
+- `role:fullmembers`: All [full
+ members](https://zulip.com/api/roles-and-permissions#determining-if-a-user-is-a-full-member)
+ of the organization.
+- `role:moderators`: All users with at least the moderator role.
+- `role:administrators`: All users with at least the administrator
+ role.
+- `role:owners`: All users with the owner role.
+- `role:nobody`: The formal empty group. Used in the API to represent
+ disabling a feature.
+
+Client UI for setting a permission is encouraged to display system
+groups using their description, rather than using their names, which
+are chosen to be unique and clear in the API.
+
+System groups should generally not be displayed in UI for
+administering an organization's user groups, since they are not
+directly mutable.
+
+## Updating group-setting values
+
+The Zulip API uses a special format for modifying an existing setting
+using a group-setting value.
+
+A **group-setting update** is an object with a `new` field and an
+optional `old` field, each containing a group-setting value. The
+setting's value will be set to the membership expressed by the `new`
+field.
+
+The `old` field expresses the client's understanding of the current
+value of the setting. If the `old` field is present and does not match
+the actual current value of the setting, then the request will fail
+with error code `EXPECTATION_MISMATCH` and no changes will be applied.
+
+When a user edits the setting in a UI, the resulting API request
+should generally always include the `old` field, giving the value
+the list had when the user started editing. This accurately expresses
+the user's intent, and if two users edit the same list around the
+same time, it prevents a situation where the second change
+accidentally reverts the first one without either user noticing.
+
+Omitting `old` is appropriate where the intent really is a new complete
+list rather than an edit, for example in an integration that syncs the
+list from an external source of truth.
diff --git a/api_docs/roles-and-permissions.md b/api_docs/roles-and-permissions.md
index 662ae6513d..db3c4acba9 100644
--- a/api_docs/roles-and-permissions.md
+++ b/api_docs/roles-and-permissions.md
@@ -102,6 +102,11 @@ and owners.
Note that specific settings and policies in the Zulip API that use these
permission levels will likely support a subset of those listed above.
+## Group-based permissions
+
+Some settings have been migrated to a more flexible system based on
+[user groups](/api/group-setting-values).
+
## Determining if a user is a full member
When a Zulip organization has set up a [waiting period before new members
diff --git a/api_docs/sidebar_index.md b/api_docs/sidebar_index.md
index 099164b9c5..10540e7946 100644
--- a/api_docs/sidebar_index.md
+++ b/api_docs/sidebar_index.md
@@ -21,7 +21,7 @@
* [HTTP headers](/api/http-headers)
* [Error handling](/api/rest-error-handling)
* [Roles and permissions](/api/roles-and-permissions)
-* [Updating group settings](/api/updating-group-settings)
+* [Group-setting values](/api/group-setting-values)
* [Message formatting](/api/message-formatting)
* [Client libraries](/api/client-libraries)
* [API changelog](/api/changelog)
diff --git a/api_docs/updating-group-settings.md b/api_docs/updating-group-settings.md
deleted file mode 100644
index c819756650..0000000000
--- a/api_docs/updating-group-settings.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# Updating group settings
-
-A **group-setting update** is an object with a `new` field and
-an optional `old` field, each containing a group-setting value
-(as defined below). The setting's value will be set to the
-membership expressed by the `new` field.
-
-The `old` field expresses the expected current value of the setting.
-If the `old` field is present and does not match the actual current
-value of the setting, then the request will fail with error code
-`EXPECTATION_MISMATCH` and no changes will be applied.
-
-When a user edits the setting in a UI, the resulting API request
-should generally always include the `old` field, giving the value
-the list had when the user started editing. This accurately expresses
-the user's intent, and if two users edit the same list around the
-same time, it prevents a situation where the second change
-accidentally reverts the first one without either user noticing.
-
-Omitting `old` is appropriate where the intent really is a new complete
-list rather than an edit, for example in an integration that syncs the
-list from an external source of truth.
-
-A **group-setting value** can take two forms: either an integer group ID,
-or an object with fields `direct_member_ids` containing a list of integer
-user IDs and `direct_subgroup_ids` containing a list of integer group IDs.
-
-In the object form, the setting's value consists of the identified users
-and groups.
-
-The integer form is equivalent to an object with empty `direct_member_ids`
-and with `direct_subgroup_ids` containing just the given group ID.
diff --git a/zerver/openapi/zulip.yaml b/zerver/openapi/zulip.yaml
index cb0fe8e75c..c82c797451 100644
--- a/zerver/openapi/zulip.yaml
+++ b/zerver/openapi/zulip.yaml
@@ -3167,7 +3167,7 @@ paths:
changed.
can_mention_group:
allOf:
- - $ref: "#/components/schemas/CanMentionGroup"
+ - $ref: "#/components/schemas/GroupSettingValue"
- description: |
Either the ID of a named user group that has permission
to mention the group, or an object describing the set of
@@ -18589,9 +18589,8 @@ paths:
can_mention_group:
allOf:
- description: |
- Either the ID of a named user group that has permission to
- mention the group, or an object describing the set of users
- and groups who have permission mention the new group.
+ A [group-setting value](/api/group-setting-values) defining the set
+ of users who have permission to mention the new group.
This setting cannot be set to `"role:internet"` and
`"role:owners"` system groups.
@@ -18604,7 +18603,7 @@ paths:
New in Zulip 8.0 (feature level 191). Previously, groups
could be mentioned if and only if they were not system groups.
- - $ref: "#/components/schemas/CanMentionGroup"
+ - $ref: "#/components/schemas/GroupSettingValue"
example: 11
required:
- name
@@ -18743,10 +18742,9 @@ paths:
example: The marketing team.
can_mention_group:
description: |
- The set of users who have permission to mention this group.
-
- This parameter is expressed as a [group-setting update](/api/updating-group-settings).
- See [details](/api/updating-group-settings) on that format.
+ The set of users who have permission to mention
+ this group, expressed as an [update to a
+ group-setting value](/api/group-valued-settings#updating-group-setting-values).
This setting cannot be set to `"role:internet"` and `"role:owners"`
system groups.
@@ -18768,15 +18766,15 @@ paths:
new:
allOf:
- description: |
- The new value for who would have the permission to
- mention the group.
- - $ref: "#/components/schemas/CanMentionGroup"
+ The new [group-setting value](/api/group-setting-values) for who would
+ have the permission to mention the group.
+ - $ref: "#/components/schemas/GroupSettingValue"
old:
allOf:
- description: |
- The expected current value for who has the permission
- to mention the group.
- - $ref: "#/components/schemas/CanMentionGroup"
+ The expected current [group-setting value](/api/group-setting-values)
+ for who has the permission to mention the group.
+ - $ref: "#/components/schemas/GroupSettingValue"
required:
- new
example:
@@ -18904,11 +18902,10 @@ paths:
**Changes**: New in Zulip 5.0 (feature level 93).
can_mention_group:
allOf:
- - $ref: "#/components/schemas/CanMentionGroup"
+ - $ref: "#/components/schemas/GroupSettingValue"
- description: |
- Either the ID of a named user group that has permission to
- mention the group, or an object describing the set of users
- and groups who have permission to mention the group.
+ A [group-setting value](/api/group-setting-values) defining the set
+ of users who have permission to mention the new group.
**Changes**: Before Zulip 9.0 (feature level 258), the
`can_mention_group` field was always an integer.
@@ -20088,11 +20085,10 @@ components:
**Changes**: New in Zulip 5.0 (feature level 93).
can_mention_group:
allOf:
- - $ref: "#/components/schemas/CanMentionGroup"
+ - $ref: "#/components/schemas/GroupSettingValue"
- description: |
- Either the ID of a named user group that has permission to
- mention the group, or an object describing the set of users
- and groups who have permission mention the group.
+ A [group-setting value](/api/group-setting-values) defining the set
+ of users who have permission to mention the new group.
**Changes**: Before Zulip 9.0 (feature level 258), the
`can_mention_group` field was always an integer.
@@ -20102,26 +20098,26 @@ components:
New in Zulip 8.0 (feature level 191). Previously, groups
could be mentioned if and only if they were not system groups.
- CanMentionGroup:
+ GroupSettingValue:
oneOf:
- type: object
additionalProperties: false
properties:
direct_members:
description: |
- The list of user IDs that have permission to
- mention the group.
+ The list of IDs of individual users in the collection of users with this permission.
type: array
items:
type: integer
direct_subgroups:
description: |
- The list of user group IDs that have permission
- to mention the group.
+ The list of IDs of the groups in the collection of users with this permission.
type: array
items:
type: integer
- type: integer
+ description: |
+ The ID of the [user group](/help/user-groups) with this permission.
Invite:
type: object
description: |
- description: | | ||
The expected current value for who has the permission | ||
to mention the group. | ||
- $ref: "#/components/schemas/CanMentionGroup" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great!
@staticmethod | ||
@override | ||
def msg_format() -> str: | ||
return _("'old' value does not match the expected value.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this error fine for here considering we were discussing about showing different message in the client as we pass a unique error code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have not changed the error message to be different in client.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this seems fine; I think it should be more like "Submitted old value does not match current value of this setting."...
if check_setting_value_changed(current_value, new_setting_value): | ||
if validate_group_setting_value_change( | ||
current_value, new_setting_value, previous_setting_value | ||
): | ||
setting_value_group = access_user_group_for_setting( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Applied this change for better readability.
diff --git a/zerver/views/user_groups.py b/zerver/views/user_groups.py
index 7eeaec5ca3..90abb9c526 100644
--- a/zerver/views/user_groups.py
+++ b/zerver/views/user_groups.py
@@ -129,12 +129,12 @@ def are_both_setting_values_equal(
def validate_group_setting_value_change(
current_value: UserGroup,
new_setting_value: Union[int, AnonymousSettingGroupDict],
- previous_setting_value: Optional[Union[int, AnonymousSettingGroupDict]],
+ expected_current_setting_value: Optional[Union[int, AnonymousSettingGroupDict]],
) -> bool:
current_setting_api_value = get_group_setting_value_for_api(current_value)
- if previous_setting_value is not None and not are_both_setting_values_equal(
- current_setting_api_value, previous_setting_value
+ if expected_current_setting_value is not None and not are_both_setting_values_equal(
+ expected_current_setting_value, current_setting_api_value,
):
# This check is here to help prevent races, by refusing to
# change a setting where the client (and thus the UI presented
@@ -185,13 +185,13 @@ def edit_user_group(
setting_value = request_settings_dict[setting_name]
new_setting_value = parse_group_setting_value(setting_value.new)
- previous_setting_value = None
+ expected_current_setting_value = None
if setting_value.old is not None:
- previous_setting_value = parse_group_setting_value(setting_value.old)
+ expected_current_setting_value = parse_group_setting_value(setting_value.old)
current_value = getattr(user_group, setting_name)
if validate_group_setting_value_change(
- current_value, new_setting_value, previous_setting_value
+ current_value, new_setting_value, expected_current_setting_value
):
setting_value_group = access_user_group_for_setting(
new_setting_value,
aeb4ea5
to
f761c5a
Compare
This is great! I did a bunch of reworking to define a reusable There is one thing that's broken, which is that if you look at, say http://localhost:9991/api/create-user-group, the full content of the API documentation doesn't actually display: This is probably something that I messed up in my changes; I think probably the right plan is to let this merge as a content update, as the API docs are usable in this state, but fix that as a priority follow-up. @Vector73 would you be up for debugging why the extra details aren't being displayed? I think there's some version on it on every page using |
This commit adds support to pass object containing both old and new values of the can_mention_group setting, as well as detailed API documentation for this part of the API system. Co-authored-by: Tim Abbott <tabbott@zulip.com> Co-authored-by: Greg PRice <greg@zulip.com>
This commit updates the webapp code to use new format to update the can_mention_group setting.
f761c5a
to
5edabbe
Compare
Fixes:
Screenshots and screen captures:
Self-review checklist
(variable names, code reuse, readability, etc.).
Communicate decisions, questions, and potential concerns.
Individual commits are ready for review (see commit discipline).
Completed manual review and testing of the following: