diff --git a/app/models.py b/app/models.py index 43fe8378..7b954dc3 100644 --- a/app/models.py +++ b/app/models.py @@ -613,6 +613,12 @@ user_role = db.Table('user_role', db.PrimaryKeyConstraint('user_id', 'role_id') ) +# table to hold users' 'read' post ids +read_posts = db.Table('read_posts', + db.Column('user_id', db.Integer, db.ForeignKey('user.id'), index=True), + db.Column('read_post_id', db.Integer, db.ForeignKey('post.id'), index=True), + # db.PrimaryKeyConstraint('user_id', 'read_post_id') + ) class User(UserMixin, db.Model): query_class = FullTextSearchQuery @@ -692,6 +698,12 @@ class User(UserMixin, db.Model): roles = db.relationship('Role', secondary=user_role, lazy='dynamic', cascade="all, delete") + read_post = db.relationship( + 'Post', secondary=read_posts, + primaryjoin=(read_posts.c.user_id == id), + secondaryjoin=(read_posts.c.read_post_id == id), + backref=db.backref('read_by', lazy='dynamic'), lazy='dynamic') + def __repr__(self): return ''.format(self.user_name, self.id) @@ -1017,6 +1029,18 @@ class User(UserMixin, db.Model): except Exception as e: return str(e) + # mark a post as 'read' for this user + def mark_post_as_read(self, post_id): + # check if its already marked as read, if not, mark it as read + if not self.has_read_post(post_id): + self.read_post.append(post_id) + + # check if post has been read by this user + # returns true if the post has been read, false if not + def has_read_post(self, post_id): + return self.read_post.filter(read_posts.c.read_post_id == post_id).count() > 0 + + class ActivityLog(db.Model): id = db.Column(db.Integer, primary_key=True) @@ -1560,6 +1584,7 @@ class PostReply(db.Model): return undo + class Domain(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(255), index=True) diff --git a/app/post/util.py b/app/post/util.py index 150d9977..bcf8e943 100644 --- a/app/post/util.py +++ b/app/post/util.py @@ -113,3 +113,7 @@ def url_needs_archive(url) -> bool: def generate_archive_link(url) -> bool: return 'https://archive.ph/' + url + +# marks the post as read for a provided user +def mark_post_as_read(post_id: int, user_id: int): + pass \ No newline at end of file diff --git a/migrations/versions/27b71f6cb21e_adding_read_posts_table.py b/migrations/versions/27b71f6cb21e_adding_read_posts_table.py new file mode 100644 index 00000000..1865dfb8 --- /dev/null +++ b/migrations/versions/27b71f6cb21e_adding_read_posts_table.py @@ -0,0 +1,41 @@ +"""adding read_posts table + +Revision ID: 27b71f6cb21e +Revises: fdaeb0b2c078 +Create Date: 2024-09-27 10:17:54.020762 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '27b71f6cb21e' +down_revision = 'fdaeb0b2c078' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('read_posts', + sa.Column('user_id', sa.Integer(), nullable=True), + sa.Column('read_post_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['read_post_id'], ['post.id'], ), + sa.ForeignKeyConstraint(['user_id'], ['user.id'], ) + ) + with op.batch_alter_table('read_posts', schema=None) as batch_op: + batch_op.create_index(batch_op.f('ix_read_posts_read_post_id'), ['read_post_id'], unique=False) + batch_op.create_index(batch_op.f('ix_read_posts_user_id'), ['user_id'], unique=False) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('read_posts', schema=None) as batch_op: + batch_op.drop_index(batch_op.f('ix_read_posts_user_id')) + batch_op.drop_index(batch_op.f('ix_read_posts_read_post_id')) + + op.drop_table('read_posts') + # ### end Alembic commands ###