Skip to content
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

Update email_address to be fetched from new API #1450

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

rsashank
Copy link
Member

What does this PR do, and why?

Added helper function to send request and get stream email_address, and called the helper function when user is viewing Stream Information.

External discussion & connections

How did you test this?

  • Manually - Behavioral changes
  • Manually - Visual changes
  • Adapting existing automated tests
  • Adding automated tests for new behavior (or missing tests)
  • Existing automated tests should already cover this (only a refactor of tested code)

Self-review checklist for each commit

  • It is a minimal coherent idea
  • It has a commit summary following the documented style (title & body)
  • It has a commit summary describing the motivation and reasoning for the change
  • It individually passes linting and tests
  • It contains test additions for any new behavior
  • It flows clearly from a previous branch commit, and/or prepares for the next commit

Visual changes

@zulipbot zulipbot added the size: S [Automatic label added by zulipbot] label Dec 14, 2023
@rsashank rsashank changed the title Zt emailapi Update email_address to be fetched from new API Dec 14, 2023
@rsashank rsashank force-pushed the zt_emailapi branch 7 times, most recently from 82035d7 to b5d4657 Compare December 16, 2023 02:04
Copy link
Collaborator

@neiljp neiljp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rsashank Thanks for the updates here 👍

I tested this and it appears to manually work against the community server, but as noted inline this will not work as expected for older servers, or likely where the incoming email is not configured on newer servers.

To isolate the API-specific logic, one option would be to have stream_email_address handle the logic across server versions. That could then be tested separately, and the existing UI tests could remain very similar.

zulipterminal/ui_tools/views.py Outdated Show resolved Hide resolved
zulipterminal/ui_tools/views.py Outdated Show resolved Hide resolved
@rsashank rsashank force-pushed the zt_emailapi branch 4 times, most recently from 4bf3497 to e2856b6 Compare December 21, 2023 10:39
@rsashank
Copy link
Member Author

@zulipbot add "PR needs review"

@zulipbot zulipbot added the PR needs review PR requires feedback to proceed label Dec 25, 2023
Copy link
Collaborator

@neiljp neiljp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rsashank This looks to have a good flow, but I think we should take the opportunity to move the logic that varies with server version in the model.

It would also be good to see independent tests for the model methods.

When you update the suggested additional model method to call the _fetch, that would be a good time to include what is currently in the first commit - and using NotRequired would be a good change at that point too.

Comment on lines 871 to 899
def stream_email_address(self, stream_id: int) -> str:
"""
Return a string containing the email address of a stream.
"""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's name this more explicitly with a _fetch prefix, to indicate this makes an API call to the server. The leading underscore will mean that we don't expect it to be called/used outside of the model.

My suggestion would be to add a separate model function which wraps the logic for determining if the data is present in the stream/subscription, and fetches it otherwise using the wrapped .call_endpoint method. You might consider the movement of the existing code in the popup into this new method to be a preliminary refactor; then once you have added the _fetch commit, you can update this other method to call it.

The docstring doesn't add much, compared to the method name and signature (ie. parameter & return value)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review! I've updated the PR accordingly.

I'm still unsure about the docstrings though.

zulipterminal/ui_tools/views.py Outdated Show resolved Hide resolved
@neiljp neiljp added PR awaiting update PR has been reviewed & is awaiting update or response to reviewer feedback and removed PR needs review PR requires feedback to proceed labels Feb 13, 2024
@zulipbot zulipbot added size: M [Automatic label added by zulipbot] and removed size: S [Automatic label added by zulipbot] labels Feb 14, 2024
@rsashank rsashank force-pushed the zt_emailapi branch 5 times, most recently from e5ccdce to 1c5106c Compare February 15, 2024 10:39
@zulipbot zulipbot added size: L [Automatic label added by zulipbot] and removed size: M [Automatic label added by zulipbot] labels Feb 15, 2024
@rsashank
Copy link
Member Author

@zulipbot remove "PR awaiting update"
@zulipbot add "PR needs review"

@zulipbot zulipbot added PR needs review PR requires feedback to proceed and removed PR awaiting update PR has been reviewed & is awaiting update or response to reviewer feedback labels Feb 15, 2024
Copy link
Collaborator

@neiljp neiljp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rsashank This looks close to ready - most of my feedback should be clear to address, but let me know if not :)

if response.get("result") == "success":
email_address = response.get("email", "")
return str(email_address)
return "invalid"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this arbitrary string isn't likely to be mistaken for an email address, it would be clearer to have this return something like None instead.

This likely simplifies the rest of the code here too.

Comment on lines +918 to +920
if stream_email == "invalid" or stream_email is None:
stream_email = ""
return stream_email
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly here, the empty string is a special marker string being returned, to indicate that we couldn't get the email address, but we can just use None again.

Comment on lines +1390 to +1392
# This field was removed from the subscription data in Zulip 7.5 / ZFL226
# Using the new /streams/{stream_id}/email_address endpoint
# if field isn't present in subscription data
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good to see this updated comment, but note that this detail is now described in the model, so we don't need it here :)

At this position in the code, all we care about is 'what is the stream email address for this stream', and rely upon the model to do the right thing, as best it can.

@@ -1398,9 +1398,11 @@ def test_stream_info_content__email_copy_text(
general_stream: Dict[str, Any],
stream_email_present: bool,
expected_copy_text: str,
mocker: MockerFixture,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no additional use of mocker here, so this is unnecessary?

return str(email_address)
return "invalid"

def stream_copy_text(self, stream_id: int) -> str:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is certainly about a stream, but it's specifically returning an email address for the stream, so I'd be confused reading this (or where it's used) why it was named with a copy_text suffix.

So, let's use a more descriptive name for this method :)

Attempts to retrieve stream email from stream_dict, fetching
from method if unavailable. (Retains handling across server versions).
"""
stream = self.stream_dict[stream_id]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a PR open to support fixing this problem more broadly, but in general we should check that a stream_id is in the dict until we have a clearer solution. See similar functions where we use a RuntimeError for now.

assert result == return_value

@pytest.mark.parametrize(
"stream, fetched, response, return_value",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests generally look good, but it's useful to use expected_ before parameters that are only used in asserts (and place them at the end).

Similarly, while the parameters are somewhat descriptive, more detail is generally better, eg.

  • is it all the stream data? part of it?
  • what is the response from?

Comment on lines 1403 to 1408
if not stream_email_present:
del general_stream["email_address"]
self.controller.model.stream_copy_text.return_value = ""

model = self.controller.model
stream_id = general_stream["stream_id"]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be simplified further? The code doesn't access as much of the model data directly now.

@neiljp
Copy link
Collaborator

neiljp commented May 11, 2024

When you update the suggested additional model method to call the _fetch, that would be a good time to include what is currently in the first commit - and using NotRequired would be a good change at that point too.

Did you understand what I meant here? I missed following up on this.

Reading this again, I think my original idea was to add the model methods in two stages: firstly to wrap the direct data access (pure refactor) and secondly update that method and add the new one (so only in the model) to try and fetch the data instead - combined with the NotRequired change.

This isn't critical, so focus on the other points first, but consider how the code changes would read differently in two commits as above.

@neiljp neiljp added PR awaiting update PR has been reviewed & is awaiting update or response to reviewer feedback api migrations version parity: 8 and removed PR needs review PR requires feedback to proceed labels May 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api migrations PR awaiting update PR has been reviewed & is awaiting update or response to reviewer feedback size: L [Automatic label added by zulipbot] version parity: 8
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants