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

Fix mention user link #9346

Merged
merged 1 commit into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions h/presenters/mention_json.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
from typing import Any

from pyramid.request import Request

from h.models import Mention
from h.util.user import format_userid
from h.util.user import format_userid, get_user_url


class MentionJSONPresenter:
"""Present a mention in the JSON format returned by API requests."""

def __init__(self, mention: Mention):
def __init__(self, mention: Mention, request: Request):
self._mention = mention
self._request = request

def asdict(self) -> dict[str, Any]:
return {
Expand All @@ -18,5 +21,5 @@ def asdict(self) -> dict[str, Any]:
),
"username": self._mention.user.username,
"display_name": self._mention.user.display_name,
"link": self._mention.user.uri,
"link": get_user_url(self._mention.user, self._request),
}
9 changes: 8 additions & 1 deletion h/services/annotation_json.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from copy import deepcopy

from pyramid.request import Request

from h.models import Annotation, User
from h.presenters import DocumentJSONPresenter
from h.presenters.mention_json import MentionJSONPresenter
Expand Down Expand Up @@ -27,6 +29,7 @@ def __init__( # noqa: PLR0913
user_service: UserService,
mention_service: MentionService,
feature_service: FeatureService,
request: Request,
):
"""
Instantiate the service.
Expand All @@ -36,13 +39,16 @@ def __init__( # noqa: PLR0913
:param flag_service: FlagService instance
:param user_service: UserService instance
:param mention_service: MentionService instance
:param feature_service: FeatureService instance
:param request: The current request
"""
self._annotation_read_service = annotation_read_service
self._links_service = links_service
self._flag_service = flag_service
self._user_service = user_service
self._mention_service = mention_service
self._feature_service = feature_service
self._request = request

def present(self, annotation: Annotation):
"""
Expand Down Expand Up @@ -83,7 +89,7 @@ def present(self, annotation: Annotation):
)
if self._feature_service.enabled("at_mentions"): # pragma: no cover
model["mentions"] = [
MentionJSONPresenter(mention).asdict()
MentionJSONPresenter(mention, self._request).asdict()
for mention in annotation.mentions
]

Expand Down Expand Up @@ -201,4 +207,5 @@ def factory(_context, request):
user_service=request.find_service(name="user"),
mention_service=request.find_service(MentionService),
feature_service=request.find_service(name="feature"),
request=request,
)
5 changes: 3 additions & 2 deletions h/services/mention.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
class MentionService:
"""A service for managing user mentions."""

def __init__(self, session: Session, user_service: UserService):
def __init__(self, session: Session, user_service: UserService) -> None:
self._session = session
self._user_service = user_service

Expand Down Expand Up @@ -75,5 +75,6 @@ def _parse_userids(text: str) -> list[str]:
def factory(_context, request) -> MentionService:
"""Return a MentionService instance for the passed context and request."""
return MentionService(
session=request.db, user_service=request.find_service(name="user")
session=request.db,
user_service=request.find_service(name="user"),
)
9 changes: 9 additions & 0 deletions h/util/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import re

from pyramid.request import Request

from h.exceptions import InvalidUserId


Expand All @@ -23,3 +25,10 @@ def split_user(userid):

def format_userid(username, authority):
return f"acct:{username}@{authority}"


def get_user_url(user, request: Request) -> str | None:
if user.authority == request.default_authority:
return request.route_url("activity.user_search", username=user.username)

return None
14 changes: 9 additions & 5 deletions tests/unit/h/presenters/mention_json_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,24 @@


class TestMentionJSONPresenter:
def test_as_dict(self, user, annotation):
def test_as_dict(self, user, annotation, pyramid_request):
mention = Mention(annotation=annotation, user=user, username=user.username)

data = MentionJSONPresenter(mention).asdict()
data = MentionJSONPresenter(mention, pyramid_request).asdict()

assert data == {
"userid": user.userid,
"original_userid": user.userid,
"username": user.username,
"display_name": user.display_name,
"link": user.uri,
"link": f"http://example.com/users/{user.username}",
}

def test_as_dict_with_different_username(self, user, annotation):
def test_as_dict_with_different_username(self, user, annotation, pyramid_request):
new_username = "new_username"
mention = Mention(annotation=annotation, user=user, username=new_username)

data = MentionJSONPresenter(mention).asdict()
data = MentionJSONPresenter(mention, pyramid_request).asdict()

assert data["original_userid"] == format_userid(new_username, user.authority)

Expand All @@ -34,3 +34,7 @@ def user(self, factories):
@pytest.fixture
def annotation(self, factories):
return factories.Annotation.build()

@pytest.fixture(autouse=True)
def routes(self, pyramid_config):
pyramid_config.add_route("activity.user_search", "/users/{username}")
3 changes: 3 additions & 0 deletions tests/unit/h/services/annotation_json_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ def service(
user_service,
mention_service,
feature_service,
pyramid_request,
):
return AnnotationJSONService(
annotation_read_service=annotation_read_service,
Expand All @@ -222,6 +223,7 @@ def service(
user_service=user_service,
mention_service=mention_service,
feature_service=feature_service,
request=pyramid_request,
)

@pytest.fixture
Expand Down Expand Up @@ -272,6 +274,7 @@ def test_it(
user_service=user_service,
mention_service=mention_service,
feature_service=feature_service,
request=pyramid_request,
)
assert service == AnnotationJSONService.return_value

Expand Down
20 changes: 20 additions & 0 deletions tests/unit/h/util/user_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,23 @@ def test_split_user():
def test_split_user_no_match():
with pytest.raises(InvalidUserId):
user_util.split_user("donkeys")


class TestGetUserURL:
def test_it(self, pyramid_request, user):
assert (
user_util.get_user_url(user, pyramid_request)
== f"http://example.com/users/{user.username}"
)

def test_it_returns_none_if_authority_does_not_match(self, pyramid_request, user):
pyramid_request.default_authority = "foo.org"
assert user_util.get_user_url(user, pyramid_request) is None

@pytest.fixture
def user(self, factories):
return factories.User.build()

@pytest.fixture(autouse=True)
def routes(self, pyramid_config):
pyramid_config.add_route("activity.user_search", "/users/{username}")
Loading