From 9d6e5933ef00c2b48ceebe097d0dc683827f137e Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Wed, 29 Jun 2022 23:16:28 +0200 Subject: implement different track visibilities --- fietsboek/models/track.py | 23 +++++++++++++++- fietsboek/models/user.py | 47 ++++++++++++++++++++++++++++++++ fietsboek/templates/edit.jinja2 | 2 +- fietsboek/templates/edit_form.jinja2 | 13 ++++++++- fietsboek/templates/finish_upload.jinja2 | 2 +- fietsboek/views/detail.py | 5 ++++ fietsboek/views/edit.py | 2 ++ fietsboek/views/upload.py | 3 ++ 8 files changed, 93 insertions(+), 4 deletions(-) diff --git a/fietsboek/models/track.py b/fietsboek/models/track.py index d264e15..6f500b9 100644 --- a/fietsboek/models/track.py +++ b/fietsboek/models/track.py @@ -41,7 +41,7 @@ class TagBag(TypeDecorator): class Visibility(enum.Enum): PRIVATE = enum.auto() - LINK_ONLY = enum.auto() + FRIENDS = enum.auto() PUBLIC = enum.auto() @@ -71,6 +71,7 @@ class Track(Base): gpx = Column(LargeBinary) visibility = Column(Enum(Visibility)) tags = Column(TagBag) + link_secret = Column(Text) owner = relationship('User', back_populates='tracks') cache = relationship('TrackCache', back_populates='track', uselist=False) @@ -91,6 +92,26 @@ class Track(Base): def gpx_data(self, value): self.gpx = gzip.compress(value) + def is_visible_to(self, user): + """Checks whether the track is visible to the given user. + + :param request: The user. + :type request: fietsboek.models.User + :return: Whether the track is visible to the current user. + :rtype: bool + """ + # Public tracks are always visible + if self.visibility == Visibility.PUBLIC: + return True + # Tracks are always visible to the owner and the tagged people + if user == self.owner or user in self.tagged_people: + return True + # Alternatively, if the track is set to friends visibility and the + # logged in user is a friend. + if self.visibility == Visibility.FRIENDS: + return request.identity in self.owner.get_friends() + return False + def ensure_cache(self): if self.cache is not None: return diff --git a/fietsboek/models/user.py b/fietsboek/models/user.py index 9bfcdc4..c9ec5b6 100644 --- a/fietsboek/models/user.py +++ b/fietsboek/models/user.py @@ -5,8 +5,12 @@ from sqlalchemy import ( Text, LargeBinary, Boolean, + Table, + ForeignKey, ) from sqlalchemy.orm import relationship +from sqlalchemy.orm.session import object_session +from sqlalchemy import select, union, delete from .meta import Base @@ -35,6 +39,14 @@ SCRYPT_PARAMETERS = { } +friends_assoc = Table( + "friends_assoc", + Base.metadata, + Column("user_1_id", ForeignKey("users.id"), primary_key=True), + Column("user_2_id", ForeignKey("users.id"), primary_key=True), +) + + class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) @@ -82,6 +94,41 @@ class User(Base): yield from self.tracks yield from self.tagged_tracks + def get_friends(self): + """Returns all friends of the user. + + This is not a simple SQLAlchemy property because the friendship + relation is complex. + + :return: All friends of this user. + :rtype: list[User] + """ + q1 = select(User).filter(friends_assoc.c.user_1_id == self.id, friends_assoc.c.user_2_id == User.id) + q2 = select(User).filter(friends_assoc.c.user_2_id == self.id, friends_assoc.c.user_1_id == User.id) + query = select(User).from_statement(union(q1, q2)) + yield from object_session(self).execute(query).scalars() + + def remove_friend(self, friend): + """Remove the friend relationship between two users. + + :param friend: The befriended user. + :type friend: User + """ + session = object_session(self) + session.execute(delete(friends_assoc).filter_by(user_1_id=self.id, user_2_id=friend.id)) + session.execute(delete(friends_assoc).filter_by(user_1_id=friend.id, user_2_id=self.id)) + + def add_friend(self, friend): + """Add the given user as a new friend. + + :param friend: The user to befriend. + :type friend: User + """ + if self.id > friend.id: + return friend.add_friend(self) + stmt = friends_assoc.insert().values(user_1_id=self.id, user_2_id=friend.id) + object_session(self).execute(stmt) + Index('idx_users_name', User.name, unique=True) Index('idx_users_email', User.email, unique=True) diff --git a/fietsboek/templates/edit.jinja2 b/fietsboek/templates/edit.jinja2 index a1985e6..9d5e484 100644 --- a/fietsboek/templates/edit.jinja2 +++ b/fietsboek/templates/edit.jinja2 @@ -9,7 +9,7 @@