add thread view
This commit is contained in:
		@@ -1,10 +1,12 @@
 | 
			
		||||
from flask import (
 | 
			
		||||
    Blueprint, render_template, request, redirect, url_for
 | 
			
		||||
    )
 | 
			
		||||
from .users import login_required, get_active_user
 | 
			
		||||
from ..models import Threads, Topics
 | 
			
		||||
from .users import login_required, mod_only, get_active_user, is_logged_in
 | 
			
		||||
from ..db import db
 | 
			
		||||
from ..models import Threads, Topics, Posts
 | 
			
		||||
from .posts import create_post
 | 
			
		||||
from slugify import slugify
 | 
			
		||||
import math
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
bp = Blueprint("threads", __name__, url_prefix = "/threads/")
 | 
			
		||||
@@ -12,7 +14,43 @@ bp = Blueprint("threads", __name__, url_prefix = "/threads/")
 | 
			
		||||
 | 
			
		||||
@bp.get("/<slug>")
 | 
			
		||||
def thread(slug):
 | 
			
		||||
    return slug
 | 
			
		||||
    POSTS_PER_PAGE = 10
 | 
			
		||||
    thread = Threads.find({"slug": slug})
 | 
			
		||||
    if not thread:
 | 
			
		||||
        return "no"
 | 
			
		||||
 | 
			
		||||
    post_count = Posts.count({"thread_id": thread.id})
 | 
			
		||||
    page_count = max(math.ceil(post_count / POSTS_PER_PAGE), 1)
 | 
			
		||||
 | 
			
		||||
    page = 1
 | 
			
		||||
    after = request.args.get("after", default=None)
 | 
			
		||||
    if after is not None:
 | 
			
		||||
        after_id = int(after)
 | 
			
		||||
        post_position = Posts.count([
 | 
			
		||||
            ("thread_id", "=", thread.id),
 | 
			
		||||
            ("id", "<=", after_id),
 | 
			
		||||
        ])
 | 
			
		||||
        print(post_position)
 | 
			
		||||
        page = math.floor((post_position + 1) / POSTS_PER_PAGE) + 1
 | 
			
		||||
    else:
 | 
			
		||||
        page = max(1, min(page_count, int(request.args.get("page", default = 1))))
 | 
			
		||||
 | 
			
		||||
    posts = thread.get_posts(POSTS_PER_PAGE, (page - 1) * POSTS_PER_PAGE)
 | 
			
		||||
    print(posts)
 | 
			
		||||
    topic = Topics.find({"id": thread.topic_id})
 | 
			
		||||
    other_topics = Topics.select()
 | 
			
		||||
 | 
			
		||||
    #TODO: subscription last seen
 | 
			
		||||
 | 
			
		||||
    return render_template(
 | 
			
		||||
        "threads/thread.html",
 | 
			
		||||
        thread = thread,
 | 
			
		||||
        current_page = page,
 | 
			
		||||
        page_count = page_count,
 | 
			
		||||
        posts = posts,
 | 
			
		||||
        topic = topic,
 | 
			
		||||
        topics = other_topics,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.get("/create")
 | 
			
		||||
@@ -47,3 +85,23 @@ def create_form():
 | 
			
		||||
    })
 | 
			
		||||
    post = create_post(thread.id, user.id, post_content)
 | 
			
		||||
    return redirect(url_for(".thread", slug = thread.slug))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.post("/<slug>/lock")
 | 
			
		||||
@login_required
 | 
			
		||||
def lock(slug):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.post("/<slug>/sticky")
 | 
			
		||||
@login_required
 | 
			
		||||
@mod_only(".thread", slug = lambda slug: slug)
 | 
			
		||||
def sticky(slug):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@bp.post("/<slug>/move")
 | 
			
		||||
@login_required
 | 
			
		||||
@mod_only(".thread", slug = lambda slug: slug)
 | 
			
		||||
def move(slug):
 | 
			
		||||
    pass
 | 
			
		||||
 
 | 
			
		||||
@@ -88,3 +88,86 @@
 | 
			
		||||
  </span>
 | 
			
		||||
</form>
 | 
			
		||||
{% endmacro %}
 | 
			
		||||
 | 
			
		||||
{% macro full_post(post, render_sig = True, is_latest = False, editing = False, active_user = None) %}
 | 
			
		||||
{% set postclass = "post" %}
 | 
			
		||||
{% if editing %}
 | 
			
		||||
  {% set postclass = postclass + " editing" %}
 | 
			
		||||
{% endif %}
 | 
			
		||||
<div class=" {{ postclass }}" id="post-{{ post['id'] }}">
 | 
			
		||||
  <div class="usercard">
 | 
			
		||||
    <div class="usercard-inner">
 | 
			
		||||
      <a href="{{ url_for("users.page", username=post['username']) }}" style="display: contents;">
 | 
			
		||||
      <img src="{{ post['avatar_path'] }}" class="avatar">
 | 
			
		||||
      </a>
 | 
			
		||||
      <a href="{{ url_for("users.page", username=post['username']) }}" class="username-link">{{ post['username'] }}</a>
 | 
			
		||||
      {% if post['status'] %}
 | 
			
		||||
        <em class="user-status">{{ post['status'] }}</em>
 | 
			
		||||
      {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div class="post-content-container" {{ "id=latest-post" if is_latest else "" }}>
 | 
			
		||||
    <div class="post-info">
 | 
			
		||||
      {% set post_permalink = url_for("threads.thread", slug = post['thread_slug'], after = post['id'], _anchor = ("post-" + (post['id'] | string))) %}
 | 
			
		||||
      <a href="{{ post_permalink }}" title="Permalink"><i>
 | 
			
		||||
        {% if (post['edited_at'] | int) > (post['created_at'] | int) %}
 | 
			
		||||
          Edited on {{ timestamp(post['edited_at']) }}
 | 
			
		||||
        {% else %}
 | 
			
		||||
          Posted on {{ timestamp(post['edited_at']) }}
 | 
			
		||||
        {% endif %}
 | 
			
		||||
      </i></a>
 | 
			
		||||
      <span>
 | 
			
		||||
        {% set show_edit = false %}
 | 
			
		||||
        {% if active_user %}
 | 
			
		||||
          {% set show_edit = (active_user.id | string) == (post['user_id'] | string) and (not post['thread_is_locked'] or active_user.is_mod()) and not no_reply %}
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        {% if show_edit %}
 | 
			
		||||
          <a class="linkbutton" href="#TODO">Edit</a>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
 | 
			
		||||
        {% set show_reply = true %}
 | 
			
		||||
 | 
			
		||||
        {% if active_user and post['thread_is_locked'] and not active_user.is_mod() %}
 | 
			
		||||
          {% set show_reply = false %}
 | 
			
		||||
        {% elif active_user and active_user.is_guest() %}
 | 
			
		||||
          {% set show_reply = false %}
 | 
			
		||||
        {% elif editing %}
 | 
			
		||||
          {% set show_reply = false %}
 | 
			
		||||
        {% elif no_reply %}
 | 
			
		||||
          {% set show_reply = false %}
 | 
			
		||||
        {% endif %}
 | 
			
		||||
 | 
			
		||||
        {% if show_reply %}
 | 
			
		||||
          {% set qtext = "[url=%s]%s said:[/url]" | format(post_permalink, post['username']) %}
 | 
			
		||||
          {% set reply_text = "%s\n[quote]%s[/quote]\n" | format(qtext, post['original_markup']) %}
 | 
			
		||||
          <button value="{{ reply_text }}" class="reply-button">Quote</button>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
 | 
			
		||||
        {% set show_delete = false %}
 | 
			
		||||
 | 
			
		||||
        {% if active_user %}
 | 
			
		||||
          {% set show_delete = (((post['user_id'] | string) == (active_user.id | string) and not post['thread_is_locked']) or active_user.is_mod()) and not no_reply %}
 | 
			
		||||
        {% endif %}
 | 
			
		||||
 | 
			
		||||
        {% if show_delete %}
 | 
			
		||||
          <button class="critical post-delete-button" value="{{ post['id'] }}">Delete</button>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
      </span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="post-content">
 | 
			
		||||
      {% if not editing %}
 | 
			
		||||
        <div class="post-inner">{{ post['content'] | safe }}</div>
 | 
			
		||||
        {% if render_sig and post['signature_rendered'] %}
 | 
			
		||||
          <div class="signature-container">
 | 
			
		||||
            <hr>
 | 
			
		||||
            {{ post['signature_rendered'] | safe }}
 | 
			
		||||
          </div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
      {% else %}
 | 
			
		||||
        {{ babycode_editor_form(cancel_url = post_permalink, prefill = post['original_markup'], ta_name = "new_content") }}
 | 
			
		||||
      {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endmacro %}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										71
									
								
								app/templates/threads/thread.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								app/templates/threads/thread.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
{% from 'common/macros.html' import pager, babycode_editor_form, full_post %}
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
{% block title %}{{ thread.title }}{% endblock %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
{% set can_post = false %}
 | 
			
		||||
{% set can_lock = false %}
 | 
			
		||||
{% set can_subscribe = false %}
 | 
			
		||||
{% if active_user %}
 | 
			
		||||
  {% set can_subscribe = true %}
 | 
			
		||||
  {% set can_post = (not thread.is_locked and not active_user.is_guest()) or active_user.is_mod() %}
 | 
			
		||||
  {% set can_lock = ((active_user.id | int) == (thread.user_id | int)) or active_user.is_mod() %}
 | 
			
		||||
{% endif %}
 | 
			
		||||
<main>
 | 
			
		||||
  <nav class="darkbg">
 | 
			
		||||
    <h1 class="thread-title">{{ thread.title }}</h1>
 | 
			
		||||
    <span>Posted in <a href="{{ url_for("topics.topic", slug=topic.slug) }}">{{ topic.name }}</a>
 | 
			
		||||
    {% if thread.is_stickied %}
 | 
			
		||||
      • <i>stickied, so it's probably important</i>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
    </span>
 | 
			
		||||
    <div>
 | 
			
		||||
      {% if can_subscribe %}
 | 
			
		||||
      {% endif %}
 | 
			
		||||
      {% if can_lock %}
 | 
			
		||||
        <form class="modform" action="{{ url_for("threads.lock", slug=thread.slug) }}" method="post">
 | 
			
		||||
          <input type=hidden value="{{ (not thread.is_locked) | int }}">
 | 
			
		||||
          <input class="warn" type="submit" value="{{"Unlock thread" if thread.is_locked else "Lock thread"}}">
 | 
			
		||||
        </form>
 | 
			
		||||
      {% endif %}
 | 
			
		||||
      {% if active_user.is_mod() %}
 | 
			
		||||
        <form class="modform" action="{{ url_for("threads.sticky", slug=thread.slug) }}" method="post">
 | 
			
		||||
          <input type=hidden value="{{ (not thread.is_stickied) | int }}">
 | 
			
		||||
          <input class="warn" type="submit" value="{{"Unsticky thread" if thread.is_stickied else "Sticky thread"}}">
 | 
			
		||||
        </form>
 | 
			
		||||
        <form class="modform" action="{{ url_for("threads.move", slug=thread.slug) }}" method="post">
 | 
			
		||||
          <label for="new_topic_id">Move to topic:</label>
 | 
			
		||||
          <select style="width:200px;" id="new_topic_id" name="new_topic_id" autocomplete="off">
 | 
			
		||||
            {% for topic in topics %}
 | 
			
		||||
              <option value="{{ topic['id'] }}" {{ "selected disabled" if (thread.topic_id | string) == (topic['id'] | string) else "" }}>{{ topic['name'] }}</option>
 | 
			
		||||
            {% endfor %}
 | 
			
		||||
          </select>
 | 
			
		||||
          <input class="warn" type="submit" value="Move thread">
 | 
			
		||||
        </form>
 | 
			
		||||
      {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
  </nav>
 | 
			
		||||
  {% for post in posts %}
 | 
			
		||||
    {{ full_post(post = post, active_user = active_user, is_latest = loop.index0 == (posts | length)) }}
 | 
			
		||||
  {% endfor %}
 | 
			
		||||
</main>
 | 
			
		||||
 | 
			
		||||
<nav id="bottomnav">
 | 
			
		||||
  {{ pager(current_page = current_page, page_count = page_count) }}
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
{% if can_post %}
 | 
			
		||||
  <h1>Respond to "{{ thread.title }}"</h1>
 | 
			
		||||
  {{ babycode_editor_form(ta_name = post_content)}}
 | 
			
		||||
{% endif %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
<dialog id="delete-dialog">
 | 
			
		||||
  <div class=delete-dialog-inner>
 | 
			
		||||
    Are you sure you want to delete the highlighted post?
 | 
			
		||||
    <span>
 | 
			
		||||
      <button id=post-delete-dialog-close>Cancel</button>
 | 
			
		||||
      <button class="critical" form=post-delete-form>Delete</button>
 | 
			
		||||
      <form id="post-delete-form" method="post"></form>
 | 
			
		||||
    </span>
 | 
			
		||||
  </div>
 | 
			
		||||
</dialog>
 | 
			
		||||
<script src="/static/js/thread.js?v=1"></script>
 | 
			
		||||
		Reference in New Issue
	
	Block a user