-
-
Notifications
You must be signed in to change notification settings - Fork 263
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
Feature: Add user info view #848
Conversation
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.
@Ezio-Sarthak This looks like a good start 👍
I like that you've got the separate commits, though we may want to squash some together to represent the changes that should only be visible at the same time.
I do like u
on a message to some extent, I'm just wary of using keys for actions and users getting used to them, only for us to run out of keys to use later :) I think a u
from message info, or i
from the user list might be good triggers for the popup, until we can agree about u
from the message list.
I often find myself wondering whether someone may be awake, so I look forward to the next iteration :)
zulipterminal/config/keys.py
Outdated
('USER_INFO', { | ||
'keys': ['u'], | ||
'help_text': 'View user description', | ||
'key_category': 'msg_actions', |
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 we could try u
as a key for this, though previously from messages we've aimed to have keys from the message-info popup rather than directly - this keeps simple keys free for later use. Any change to keys.py should be in the same commit as one to the keys list in README.md.
I think it would definitely be helpful to hook the same popup functionality into the user list, probably via i
in that case - in parallel to the same key being applied to message and streams.
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 totally feel you :) Just like the edit history view in the message info, I'll add the key for the user info view (i
) so that we're clear with the keys.
Yeah, I'll hook the README and keys commit together :)
zulipterminal/ui_tools/views.py
Outdated
user_details = [] | ||
for key, value in display_data.items(): | ||
if(key == 'Name'): | ||
continue | ||
user_details.append((key,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 looks like it could be a lot simpler as a comprehension.
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, absolutely. I'll make it cleaner and simpler :)
zulipterminal/core.py
Outdated
display_data['Local time'] = datetime.now(pytz.timezone(str(res_data['timezone']))).strftime("%H:%M") | ||
except: | ||
display_data['Local time'] = "Unknown timezone" | ||
presence = self.client.get_user_presence(str(res_data['email'])) |
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 have this information already? Do we need to fetch it? What does the webapp do?
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 so (not completely sure though).
By the GET request client.get_user_by_id(user_id)
, I got the following dict:
{
'result': 'success',
'msg': '',
'user':
{
'email': '[email protected]', 'user_id': 16790, 'avatar_version': 2,
'is_admin': False, 'is_owner': False, 'is_guest': False, 'is_bot': False,
'full_name': 'Matt Hall', 'timezone': 'America/Los_Angeles',
'is_active': True, 'date_joined': '2020-07-24T21:53:55.770840+00:00',
'avatar_url': '/user_avatars/2/848f00cf86435f7a12c7f6dafb476e47a7ee5665.png?x=x&version=2'
}
}
Seems like we have to fetch the timezone of a user in any case. Please drop any suggestions if you have :)
UPDATE: The logged-in user's time zone is stored in page_params js global variable in webapp.
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.
Right, well the user data should be available in the model from what I can tell. It would benefit from refactoring, but the initial data is in Model.initial_data['realm_users']
.
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.
Thanks @neiljp for reminding me of the users realm, I've updated the PR accordingly :)
@neiljp Thanks for the review! |
PR updated :) |
0f6733a
to
bf698ef
Compare
bf698ef
to
aa8a559
Compare
2b5d88a
to
cab7b28
Compare
df964b1
to
af34576
Compare
@Ezio-Sarthak This is one of many in the queue to review, but you could check over your commit titles. |
cb1a099
to
3e1741e
Compare
Commit titles improved :) |
e0ee338
to
c39a7b2
Compare
c39a7b2
to
21319e8
Compare
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.
@Ezio-Sarthak This looks tidier than I remember 👍
We're essentially making new data available here, rather than just plumbing through to existing prepared data, so don't be too concerned this is taking a bit longer than other PRs. In particular the project has ended up with a lot of duplicate test data in the past which became quite challenging to update, so I'm keen to keep this as clean as we can, within reason :)
zulipterminal/model.py
Outdated
tz = pytz.timezone(user_info['timezone']) | ||
time = datetime.datetime.now(tz).replace(tzinfo=None).timestamp() |
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.
Reading the pytz docs, it seems that passing a timezone when constructing a datetime is not advised, and I suspect that's what is happening with now(tz)
?
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.
Right. I'll consider this and your other comment mentioning now()
declaration in UI.
zulipterminal/ui_tools/views.py
Outdated
if data['timezone']: | ||
display_data['Timezone'] = data['timezone'] | ||
if data['local_time']: | ||
display_data['Local time'] = data['local_time'][11:] |
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.
My timezone output from this has an underscore instead of a space; I'm not sure if there's a built-in conversion for this?
I do see that this is also the case in the webapp too though!
A possible point to consider (or in the future in a next iteration) is that while the "local time" is going to be very similar between the model+UI, now
changes rather continuously, so it might be more meaningful to have the user info timezone be something to use, and the local time generated 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.
Agreed. I understand the timezone strings might be unaltered due to internal calculations, and the server would expect to let the client-side handle it. This should be straightforward with replace
in our case. Could you elaborate (either here or in stream) exactly what similarity you observed regarding the buggy underscore behavior with webapp ?:sweat_smile:
zulipterminal/model.py
Outdated
@@ -774,6 +778,7 @@ def get_all_users(self) -> List[Dict[str, Any]]: | |||
'user_id': bot['user_id'], | |||
'status': 'inactive', | |||
} | |||
self.cross_realm_bots_by_id[user['user_id']] = user |
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.
Would it be simpler to also add an entry to all_users_by_id
for cross-realm-bots here too?
zulipterminal/model.py
Outdated
self.all_users_by_id: Dict[int, Dict[str, Any]] = {} | ||
self.cross_realm_bots_by_id: Dict[int, Dict[str, Any]] = {} |
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 are intended to be internal, so let's indicate that with a leading underscore.
At risk of expanding this PR further, you could clarify the Any
by adding new types to api_types
- you may be able to use a style similar to the Event
Union to simplify between regular users and bots?
I'd expect a blank line before these lines.
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.
Re the 2nd point, I like this idea. Though, I think the API responses for realm_users
and cross_realm_bots
are mostly the same, as seen in the register API response.
That said, I wonder if we could keep it a single TypedDict for now?
zulipterminal/model.py
Outdated
data = self.all_users_by_id.get(user_id, None) | ||
if not data: | ||
# If the user is a cross realm bot (e.g., Welcome Bot) | ||
data = self.cross_realm_bots_by_id.get(user_id, None) |
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 would be simplified by combining the regular and cross-realm bots - unless there's a reason we need the latter separate?
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. I think I could remove this commit now that I could access all users via a single get
command. What do you think?
zulipterminal/ui_tools/views.py
Outdated
display_data['Local time'] = data['local_time'][11:] | ||
|
||
if data['is_bot']: | ||
display_data['Role'] = BOT_TYPE_BY_ID[data['bot_type']] |
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.
To be forward-compatible, we likely want to make this into a .get
with some kind of 'unknown' text?
Possibly the same for USER_ROLE in terms of the default value, as eg. 'moderator' would not be identified right now - which I've tested since I now am one :)
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, that makes sense. For USER_ROLE, I wish to propose that as I'm returning a custom-made role
param from get_tidied_user_info
, I could forcefully pass is_moderator
(with False
as default, or specified value) to it, and then handle it easily. I suppose it would make sense with regards to backward compatibility?
Noting in my above proposal, if is_moderator
is false, it wouldn't affect the default Member
value as well, due to the internal ordering in role
:)
tests/ui_tools/test_popups.py
Outdated
mocker.patch.object(self.controller, 'maximum_popup_dimensions', | ||
return_value=(64, 64)) | ||
mocker.patch(VIEWS + '.urwid.SimpleFocusListWalker', return_value=[]) | ||
self.user_data = dict( |
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 essentially a fixture for the output of get_tidied_user_info
?
I understand for getting this going that a dict internal to the test is easier, but it would be good if we could unify a "sample output" from that method, ie. relate it to our current standard test users in some way. If we change the output from the model method then we need to change the internals of this test otherwise - or eg. handling adding is_moderator.
21319e8
to
a9dc63f
Compare
a9dc63f
to
b43fc1e
Compare
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.
@Ezio-Sarthak I'm keen to merge this, so after having merged (split) the first commit with a slight adjustment as we discussed, I've left a few comments and I'd like to get this in ASAP.
After reviewing the data we get from the server today, I think we're not quite handling the role correctly, and there's also an older-style bot_owner field to consider.
I think we need to integrate the user-id code better, but it's in now for use in other PRs.
6da0b68
to
6dab928
Compare
6dab928
to
5a039dd
Compare
This commit adds two constant dicts (BOT_TYPE_BY_ID, ROLE_BY_ID) to translate bot/role ids into descriptive text, as well as connect old (`is_*`) and new role specifications.
This commit adds a model method to tidy and return required user information given user id. The returned information is in the form of a new TypedDict 'TidiedUserInfo'. Tests added for individual properties and sample human user. Fixture `tidied_user_info_response` added in `conftest.py`.
This commit handles the API response for older servers. The endpoints are prioritized according to the `RealmUser` TypedDict in `api_types.py`. API response changes (old -> new): (Server versions noted in api_types.py) * bot_owner (email: str) -> bot_owner_id (user_id: int) * is_* (e.g., is_admin: bool) -> role (role: int) Tests added.
As a v0, user info would be seen by pressing `i` in the users' list. This would allow the unification of the keypress event for `i` in all three views. It could be integrated to also trigger from message info view as a follow up, potentially with a different hotkey. docs/hotkeys.md regenerated.
This commit adds the class responsible to show user information. * It inherits the generalized PopUpView class. * Fetches tidied data to be displayed from model through static method `_fetch_user_data()`. Tests added (UserInfoView).
* Member function show_user_info() to trigger the popup. * New theme area added: `area:user`. This could generally be used in the future for user-related areas.
This commit wraps up the user-info feature by defining keypress events to toggle user info view. Tests added. Fixes zulip#511.
5a039dd
to
92dbb8c
Compare
@Ezio-Sarthak Thanks for the fixture work; I squashed those fixup commits from yesterday and also added a tiny test to use that new fixture early on, making a few tiny commit text changes, resulting in what's on the PR now - which I'm merging now! 🎉 We should really test those new model attributes we added, though I was ~ok with merging that commit early, there's nothing validating them right now. |
What does this PR do?!
i
in the users list to see user info.Commit flow
i
to trigger the popup.Fixes #511
Screenshots/GIF
![Screenshot from 2021-04-27 19-58-50](https://user-images.githubusercontent.com/55916430/116259136-2a801400-a793-11eb-9613-568e7e569f04.png)