re-add subscriptions
This commit is contained in:
		@@ -105,4 +105,11 @@ def create_app():
 | 
			
		||||
    def ts_datetime(ts, format):
 | 
			
		||||
        return datetime.utcfromtimestamp(ts or int(time.time())).strftime(format)
 | 
			
		||||
 | 
			
		||||
    @app.template_filter("pluralize")
 | 
			
		||||
    def pluralize(number, singular = "", plural = "s"):
 | 
			
		||||
        if number == 1:
 | 
			
		||||
            return singular
 | 
			
		||||
 | 
			
		||||
        return plural
 | 
			
		||||
 | 
			
		||||
    return app
 | 
			
		||||
 
 | 
			
		||||
@@ -56,6 +56,18 @@ class Users(Model):
 | 
			
		||||
            WHERE users.id = ?"""
 | 
			
		||||
        return db.fetch_one(q, self.id)
 | 
			
		||||
 | 
			
		||||
    def get_all_subscriptions(self):
 | 
			
		||||
        q = """
 | 
			
		||||
            SELECT threads.title AS thread_title, threads.slug AS thread_slug
 | 
			
		||||
            FROM
 | 
			
		||||
                threads
 | 
			
		||||
            JOIN
 | 
			
		||||
                subscriptions ON subscriptions.thread_id = threads.id
 | 
			
		||||
            WHERE
 | 
			
		||||
                subscriptions.user_id = ?"""
 | 
			
		||||
        return db.query(q, self.id)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Topics(Model):
 | 
			
		||||
    table = "topics"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ from flask import (
 | 
			
		||||
    )
 | 
			
		||||
from .users import login_required, mod_only, get_active_user, is_logged_in
 | 
			
		||||
from ..db import db
 | 
			
		||||
from ..models import Threads, Topics, Posts
 | 
			
		||||
from ..models import Threads, Topics, Posts, Subscriptions
 | 
			
		||||
from .posts import create_post
 | 
			
		||||
from slugify import slugify
 | 
			
		||||
import math
 | 
			
		||||
@@ -39,7 +39,17 @@ def thread(slug):
 | 
			
		||||
    topic = Topics.find({"id": thread.topic_id})
 | 
			
		||||
    other_topics = Topics.select()
 | 
			
		||||
 | 
			
		||||
    #TODO: subscription last seen
 | 
			
		||||
    is_subscribed = False
 | 
			
		||||
    if is_logged_in():
 | 
			
		||||
        subscription = Subscriptions.find({
 | 
			
		||||
            'thread_id': thread.id,
 | 
			
		||||
            'user_id': get_active_user().id,
 | 
			
		||||
        })
 | 
			
		||||
        if subscription:
 | 
			
		||||
            subscription.update({
 | 
			
		||||
                'last_seen': int(time.time())
 | 
			
		||||
            })
 | 
			
		||||
            is_subscribed = True
 | 
			
		||||
 | 
			
		||||
    return render_template(
 | 
			
		||||
        "threads/thread.html",
 | 
			
		||||
@@ -49,6 +59,7 @@ def thread(slug):
 | 
			
		||||
        posts = posts,
 | 
			
		||||
        topic = topic,
 | 
			
		||||
        topics = other_topics,
 | 
			
		||||
        is_subscribed = is_subscribed,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -122,3 +133,39 @@ def sticky(slug):
 | 
			
		||||
@mod_only(".thread", slug = lambda slug: slug)
 | 
			
		||||
def move(slug):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.post("/<slug>/subscribe")
 | 
			
		||||
@login_required
 | 
			
		||||
def subscribe(slug):
 | 
			
		||||
    user = get_active_user()
 | 
			
		||||
    thread = Threads.find({'slug': slug})
 | 
			
		||||
    if not thread:
 | 
			
		||||
        return 'no'
 | 
			
		||||
    subscription = Subscriptions.find({
 | 
			
		||||
        'user_id': user.id,
 | 
			
		||||
        'thread_id': thread.id,
 | 
			
		||||
    })
 | 
			
		||||
    if request.form['subscribe'] == 'subscribe':
 | 
			
		||||
        if subscription:
 | 
			
		||||
            subscription.delete()
 | 
			
		||||
        Subscriptions.create({
 | 
			
		||||
            'user_id': user.id,
 | 
			
		||||
            'thread_id': thread.id,
 | 
			
		||||
            'last_seen': int(time.time()),
 | 
			
		||||
        })
 | 
			
		||||
    elif request.form['subscribe'] == 'unsubscribe':
 | 
			
		||||
        if not subscription:
 | 
			
		||||
            return 'no'
 | 
			
		||||
        subscription.delete()
 | 
			
		||||
    elif request.form['subscribe'] == 'read':
 | 
			
		||||
        if not subscription:
 | 
			
		||||
            return 'no'
 | 
			
		||||
        subscription.update({
 | 
			
		||||
            'last_seen': int(time.time())
 | 
			
		||||
        })
 | 
			
		||||
    last_visible_post = request.form.get('last_visible_post', default=None)
 | 
			
		||||
    if last_visible_post is not None:
 | 
			
		||||
        return redirect(url_for('.thread', slug=thread.slug, after=last_visible_post))
 | 
			
		||||
    else:
 | 
			
		||||
        return redirect(url_for('users.inbox', username=user.username))
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,8 @@ from flask import (
 | 
			
		||||
    Blueprint, render_template, request, redirect, url_for, flash, session, current_app
 | 
			
		||||
    )
 | 
			
		||||
from functools import wraps
 | 
			
		||||
from ..models import Users, Sessions
 | 
			
		||||
from ..db import db
 | 
			
		||||
from ..models import Users, Sessions, Subscriptions
 | 
			
		||||
from ..constants import InfoboxKind, PermissionLevel
 | 
			
		||||
from ..auth import digest, verify
 | 
			
		||||
import secrets
 | 
			
		||||
@@ -202,12 +203,6 @@ def settings(username):
 | 
			
		||||
    return "stub"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.get("/<username>/inbox")
 | 
			
		||||
@login_required
 | 
			
		||||
def inbox(username):
 | 
			
		||||
    return "stub"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.post("/log_out")
 | 
			
		||||
@login_required
 | 
			
		||||
def log_out():
 | 
			
		||||
@@ -282,3 +277,86 @@ def guest_user(user_id):
 | 
			
		||||
        "permission": PermissionLevel.GUEST.value,
 | 
			
		||||
    })
 | 
			
		||||
    return redirect(url_for(".page", username=target_user.username))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.get("/<username>/inbox")
 | 
			
		||||
@login_required
 | 
			
		||||
def inbox(username):
 | 
			
		||||
    user = get_active_user()
 | 
			
		||||
    if username != user.username:
 | 
			
		||||
        return redirect(url_for(".inbox", username = user.username))
 | 
			
		||||
 | 
			
		||||
    new_posts = []
 | 
			
		||||
    subscription = Subscriptions.find({"user_id": user.id})
 | 
			
		||||
    all_subscriptions = None
 | 
			
		||||
    total_unreads_count = None
 | 
			
		||||
    if subscription:
 | 
			
		||||
        all_subscriptions = user.get_all_subscriptions()
 | 
			
		||||
        q = """
 | 
			
		||||
            WITH thread_metadata AS (
 | 
			
		||||
                SELECT
 | 
			
		||||
                    posts.thread_id, threads.slug AS thread_slug, threads.title AS thread_title, COUNT(*) AS unread_count, MAX(posts.created_at) AS newest_post_time
 | 
			
		||||
                FROM
 | 
			
		||||
                    posts
 | 
			
		||||
                LEFT JOIN
 | 
			
		||||
                    threads ON threads.id = posts.thread_id
 | 
			
		||||
                LEFT JOIN
 | 
			
		||||
                    subscriptions ON subscriptions.thread_id = posts.thread_id
 | 
			
		||||
                WHERE subscriptions.user_id = ? AND posts.created_at > subscriptions.last_seen
 | 
			
		||||
                GROUP BY posts.thread_id
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            SELECT
 | 
			
		||||
                tm.thread_id, tm.thread_slug, tm.thread_title, tm.unread_count, tm.newest_post_time,
 | 
			
		||||
 | 
			
		||||
                posts.id, posts.created_at, post_history.content, post_history.edited_at, users.username, users.status, avatars.file_path AS avatar_path, posts.thread_id, users.id AS user_id, post_history.original_markup, users.signature_rendered
 | 
			
		||||
            FROM
 | 
			
		||||
                thread_metadata tm
 | 
			
		||||
            JOIN
 | 
			
		||||
                posts ON posts.thread_id = tm.thread_id
 | 
			
		||||
            JOIN
 | 
			
		||||
                post_history ON posts.current_revision_id = post_history.id
 | 
			
		||||
            JOIN
 | 
			
		||||
                users ON posts.user_id = users.id
 | 
			
		||||
            LEFT JOIN
 | 
			
		||||
                threads ON threads.id = posts.thread_id
 | 
			
		||||
            LEFT JOIN
 | 
			
		||||
                avatars ON users.avatar_id = avatars.id
 | 
			
		||||
            LEFT JOIN
 | 
			
		||||
                subscriptions ON subscriptions.thread_id = posts.thread_id
 | 
			
		||||
            WHERE
 | 
			
		||||
                subscriptions.user_id = ? AND posts.created_at > subscriptions.last_seen
 | 
			
		||||
            ORDER BY
 | 
			
		||||
                tm.newest_post_time DESC, posts.created_at ASC"""
 | 
			
		||||
        new_posts_raw = db.query(q, user.id, user.id)
 | 
			
		||||
        current_thread_id = None
 | 
			
		||||
        current_thread_group = None
 | 
			
		||||
        total_unreads_count = 0
 | 
			
		||||
        for row in new_posts_raw:
 | 
			
		||||
            if row['thread_id'] != current_thread_id:
 | 
			
		||||
                current_thread_group = {
 | 
			
		||||
                    'thread_id': row['thread_id'],
 | 
			
		||||
                    'thread_title': row['thread_title'],
 | 
			
		||||
                    'unread_count': row['unread_count'],
 | 
			
		||||
                    'thread_slug': row['thread_slug'],
 | 
			
		||||
                    'newest_post_time': row['newest_post_time'],
 | 
			
		||||
                    'posts': [],
 | 
			
		||||
                }
 | 
			
		||||
                total_unreads_count += int(row['unread_count'])
 | 
			
		||||
                new_posts.append(current_thread_group)
 | 
			
		||||
                current_thread_id = row['thread_id']
 | 
			
		||||
            current_thread_group['posts'].append({
 | 
			
		||||
                'id': row['id'],
 | 
			
		||||
                'created_at': row['created_at'],
 | 
			
		||||
                'content': row['content'],
 | 
			
		||||
                'edited_at': row['edited_at'],
 | 
			
		||||
                'username': row['username'],
 | 
			
		||||
                'status': row['status'],
 | 
			
		||||
                'avatar_path': row['avatar_path'],
 | 
			
		||||
                'thread_id': row['thread_id'],
 | 
			
		||||
                'user_id': row['user_id'],
 | 
			
		||||
                'original_markup': row['original_markup'],
 | 
			
		||||
                'signature_rendered': row['signature_rendered']
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
    return render_template("users/inbox.html", new_posts = new_posts, total_unreads_count = total_unreads_count, all_subscriptions = all_subscriptions)
 | 
			
		||||
 
 | 
			
		||||
@@ -89,7 +89,7 @@
 | 
			
		||||
</form>
 | 
			
		||||
{% endmacro %}
 | 
			
		||||
 | 
			
		||||
{% macro full_post(post, render_sig = True, is_latest = False, editing = False, active_user = None) %}
 | 
			
		||||
{% macro full_post(post, render_sig = True, is_latest = False, editing = False, active_user = None, no_reply = false) %}
 | 
			
		||||
{% set postclass = "post" %}
 | 
			
		||||
{% if editing %}
 | 
			
		||||
  {% set postclass = postclass + " editing" %}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,11 @@
 | 
			
		||||
    </span>
 | 
			
		||||
    <div>
 | 
			
		||||
      {% if can_subscribe %}
 | 
			
		||||
        <form class="modform" action="{{ url_for('threads.subscribe', slug=thread.slug) }}" method="post">
 | 
			
		||||
          <input type='hidden' name='last_visible_post' value='{{posts[-1].id}}'>
 | 
			
		||||
          <input type='hidden' name='subscribe' value='{{ 'unsubscribe' if is_subscribed else 'subscribe' }}'>
 | 
			
		||||
          <input type='submit' value='{{ 'Unsubscribe' if is_subscribed else 'Subscribe' }}'>
 | 
			
		||||
        </form>
 | 
			
		||||
      {% endif %}
 | 
			
		||||
      {% if can_lock %}
 | 
			
		||||
        <form class="modform" action="{{ url_for("threads.lock", slug=thread.slug) }}" method="post">
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										51
									
								
								app/templates/users/inbox.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								app/templates/users/inbox.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
{% from "common/macros.html" import timestamp, full_post %}
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
{% block title %}inbox{% endblock %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
<div class="inbox-container">
 | 
			
		||||
  {% if all_subscriptions is none %}
 | 
			
		||||
    You have no subscriptions.<br>
 | 
			
		||||
  {% else %}
 | 
			
		||||
    Your subscriptions:
 | 
			
		||||
    <ul>
 | 
			
		||||
      {% for sub in all_subscriptions %}
 | 
			
		||||
        <li>
 | 
			
		||||
          <a href=" {{ url_for("threads.thread", slug=sub.thread_slug) }} ">{{ sub.thread_title }}</a>
 | 
			
		||||
          <form class="modform" method="post" action="{{ url_for("threads.subscribe", slug = sub.thread_slug) }}">
 | 
			
		||||
            <input type="hidden" name="subscribe" value="unsubscribe">
 | 
			
		||||
            <input class="warn" type="submit" value="Unsubscribe">
 | 
			
		||||
          </form>
 | 
			
		||||
        </li>
 | 
			
		||||
      {% endfor %}
 | 
			
		||||
    </ul>
 | 
			
		||||
  {% endif %}
 | 
			
		||||
  {% if not new_posts %}
 | 
			
		||||
    You have no unread posts.
 | 
			
		||||
  {% else %}
 | 
			
		||||
    You have {{ total_unreads_count }} unread post{{(total_unreads_count | int) | pluralize }}:
 | 
			
		||||
    {% for thread in new_posts %}
 | 
			
		||||
      <div class="accordion">
 | 
			
		||||
        <div class="accordion-header">
 | 
			
		||||
          <button type="button" class="accordion-toggle">▼</button>
 | 
			
		||||
          {% set latest_post_id = thread.posts[-1].id %}
 | 
			
		||||
          {% set unread_posts_text = " (" + (thread.unread_count | string) + (" unread post" | pluralize) %}
 | 
			
		||||
          <a class="accordion-title" href="{{ url_for("threads.thread", slug=latest_post_slug, after=latest_post_id, _anchor="post-" + (latest_post_id | string)) }}" title="Jump to latest post">{{thread.thread_title + unread_posts_text}}, latest at {{ timestamp(thread.newest_post_time) }})</a>
 | 
			
		||||
          <form class="modform" method="post" action="{{ url_for("threads.subscribe", slug = thread.thread_slug) }}">
 | 
			
		||||
            <input type="hidden" name="subscribe" value="read">
 | 
			
		||||
            <input type="submit" value="Mark thread as Read">
 | 
			
		||||
          </form>
 | 
			
		||||
          <form class="modform" method="post" action="{{ url_for("threads.subscribe", slug = thread.thread_slug) }}">
 | 
			
		||||
            <input type="hidden" name="subscribe" value="unsubscribe">
 | 
			
		||||
            <input class="warn" type="submit" value="Unsubscribe">
 | 
			
		||||
          </form>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="accordion-content">
 | 
			
		||||
          {% for post in thread.posts %}
 | 
			
		||||
            {{ full_post(post, no_reply = true) }}
 | 
			
		||||
          {% endfor %}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
  {% endif %}
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
		Reference in New Issue
	
	Block a user