diff options
| author | Daniel Schadt <kingdread@gmx.de> | 2025-12-28 16:26:07 +0100 |
|---|---|---|
| committer | Daniel Schadt <kingdread@gmx.de> | 2025-12-30 19:16:32 +0100 |
| commit | d1fa0c056a623779c0c111805fd1cc91961fe3d2 (patch) | |
| tree | 07bd434b51d83504bc13bdcc2fc91b00d6ab6bc7 | |
| parent | 1d23ffd3ad68a880a0d63a8e90902f5536915cd3 (diff) | |
| download | fietsboek-d1fa0c056a623779c0c111805fd1cc91961fe3d2.tar.gz fietsboek-d1fa0c056a623779c0c111805fd1cc91961fe3d2.tar.bz2 fietsboek-d1fa0c056a623779c0c111805fd1cc91961fe3d2.zip | |
respect journeys' visibility levels
| -rw-r--r-- | fietsboek/models/user.py | 34 | ||||
| -rw-r--r-- | fietsboek/templates/journey_form.jinja2 | 1 | ||||
| -rw-r--r-- | fietsboek/views/journey.py | 15 |
3 files changed, 46 insertions, 4 deletions
diff --git a/fietsboek/models/user.py b/fietsboek/models/user.py index 19d5e71..6d1a53e 100644 --- a/fietsboek/models/user.py +++ b/fietsboek/models/user.py @@ -6,7 +6,7 @@ import hashlib import secrets import uuid from functools import reduce -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Optional, Self from cryptography.exceptions import InvalidKey from cryptography.hazmat.primitives.kdf.scrypt import Scrypt @@ -34,6 +34,7 @@ from sqlalchemy.exc import NoResultFound from sqlalchemy.orm import Mapped, Session, mapped_column, relationship, with_parent from sqlalchemy.orm.attributes import flag_dirty from sqlalchemy.orm.session import object_session +from sqlalchemy.sql.expression import Selectable from .meta import Base @@ -398,6 +399,37 @@ class User(Base): return union(*queries) + @staticmethod + def visible_journeys_query(user: Self | None = None) -> Selectable: + # Late import to avoid cycles + # pylint: disable=import-outside-toplevel + from .journey import Journey, Visibility + + queries = [] + + # Step 1: Own journeys + if user: + queries.append(select(Journey).where(with_parent(user, User.journeys))) + + # Step 2: Public journeys + queries.append(select(Journey).filter_by(visibility=Visibility.PUBLIC)) + + # Step 3: Journeys for logged in users + if user: + queries.append(select(Journey).filter_by(visibility=Visibility.LOGGED_IN)) + + # Step 4: Friends' journeys + if user: + friend_query = user._friend_query().subquery() + friend_ids = select(friend_query.c.id) + queries.append( + select(Journey) + .filter_by(visibility=Visibility.FRIENDS) + .where(Journey.owner_id.in_(friend_ids)) + ) + + return union(*queries) + def _friend_query(self): qry1 = select(User).filter( friends_assoc.c.user_1_id == self.id, friends_assoc.c.user_2_id == User.id diff --git a/fietsboek/templates/journey_form.jinja2 b/fietsboek/templates/journey_form.jinja2 index c641648..6fdbfaa 100644 --- a/fietsboek/templates/journey_form.jinja2 +++ b/fietsboek/templates/journey_form.jinja2 @@ -53,7 +53,6 @@ {% set visibility = journey.visibility.name if journey else "" %} <option value="PRIVATE"{% if visibility== "PRIVATE" %} selected{% endif %}>{{ _("journeys.new.form.visibility.private") }}</option> <option value="FRIENDS"{% if visibility== "FRIENDS" %} selected{% endif %}>{{ _("journeys.new.form.visibility.friends") }}</option> - <option value="FRIENDS_TAGGED"{% if visibility== "FRIENDS_TAGGED" %} selected{% endif %}>{{ _("journeys.new.form.visibility.friends_tagged") }}</option> <option value="LOGGED_IN"{% if visibility== "LOGGED_IN" %} selected{% endif %}>{{ _("journeys.new.form.visibility.logged_in") }}</option> <option value="PUBLIC"{% if visibility== "PUBLIC" %} selected{% endif %}>{{ _("journeys.new.form.visibility.public") }}</option> </select> diff --git a/fietsboek/views/journey.py b/fietsboek/views/journey.py index b763317..3a64fd3 100644 --- a/fietsboek/views/journey.py +++ b/fietsboek/views/journey.py @@ -7,6 +7,7 @@ from pyramid.request import Request from pyramid.response import Response from pyramid.view import view_config from sqlalchemy import select +from sqlalchemy.orm import aliased from .. import trackmap, util from ..models.journey import Journey, Visibility @@ -22,7 +23,8 @@ LOGGER = logging.getLogger(__name__) renderer="fietsboek:templates/journey_list.jinja2", ) def journey_list(request: Request): - journeys = request.dbsession.execute(select(Journey)).scalars() + query = select(aliased(Journey, User.visible_journeys_query(request.identity).subquery())) + journeys = request.dbsession.execute(query).scalars() return { "journeys": journeys, "md_to_html": util.safe_markdown, @@ -95,7 +97,7 @@ def do_journey_new(request: Request): owner=request.identity, title=request.params.get("journeyTitle"), description=request.params.get("journeyDescription"), - visibility=Visibility.PUBLIC, + visibility=_extract_visibility(request), tracks=[], ) @@ -130,6 +132,7 @@ def do_journey_edit(request: Request): journey.title = request.params.get("journeyTitle") journey.description = request.params.get("journeyDescription") + journey.visibility = _extract_visibility(request) track_ids = _extract_valid_tracks(request) journey.set_track_ids(track_ids) @@ -139,6 +142,14 @@ def do_journey_edit(request: Request): return HTTPFound(request.route_url("journey-details", journey_id=journey.id)) +def _extract_visibility(request: Request) -> Visibility: + key = request.params.get("journeyVisibility") + try: + return Visibility[key] + except KeyError: + raise HTTPBadRequest("Invalid visibility") + + def _extract_valid_tracks(request: Request) -> list[int]: user: User = request.identity |
