~melmon/at-channel

842a6f23be2231dc133401b08493395b720f2852 — Melmon 3 years ago 58f0344 master
improved tripcodes, added archiving threads and sticky threads
A atch/admin.py => atch/admin.py +40 -0
@@ 0,0 1,40 @@
import functools
from flask import Blueprint, flash, g, redirect, render_template, request, session, url_for, abort, jsonify
from atch.db import get_db
from werkzeug.security import check_password_hash, generate_password_hash

bp = Blueprint('admin', __name__, url_prefix="/admin")


@bp.route('/login', methods=('GET', 'POST'))
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        db = get_db()
        error = None
        user = db.execute(
            'SELECT * FROM admins WHERE username = ?', (username,)
        ).fetchone()

        if (user is None) or (not check_password_hash(user['password'], password)):
            error = 'Incorrect username or password'

        if error is None:
            session.clear()
            session['user_id'] = user['id']
            return redirect(url_for('dashboard'))

        flash(error)

    return render_template('login.html')


def login_required(view):
    @functools.wraps(view)
    def wrapped_view(**kwargs):
        if g.user is None:
            return redirect(url_for('auth.login'))

        return view(**kwargs)
    return wrapped_view

M atch/board.py => atch/board.py +11 -10
@@ 12,10 12,10 @@ def browse_board(uri):
    if board_name is None:
        abort(404)
    threads = db.execute(
        'SELECT threads.thread_id, threads.board, threads.bump_timestamp, threads.title, '
        'posts.created, posts.name, posts.email, posts.body  '
        'SELECT threads.thread_id, threads.board, threads.bump_timestamp, threads.title, threads.archived, '
        'threads.sticky, posts.created, posts.name, posts.email, posts.body, posts.tripcode '
        'FROM threads JOIN posts ON posts.thread=threads.thread_id WHERE threads.board=? and posts.reply_id=0 '
        'ORDER BY bump_timestamp DESC',
        'ORDER BY sticky DESC, bump_timestamp DESC',
        (uri,)
    ).fetchall()



@@ 25,9 25,7 @@ def browse_board(uri):
@bp.route('/<string:uri>/new_thread', methods=['POST'])
def new_thread(uri):
    if request.method == 'POST':
        if '◆' in request.form['name']:
            return render_template('post_error.html', why="The diamond symbol (◆) is not allowed in usernames.")
        name = process_name(request.form['name'])
        name, tripcode = process_name(request.form['name'])
        email = request.form['email']
        title = request.form['title']
        if request.form['body']:


@@ 42,8 40,8 @@ def new_thread(uri):
            (thread_number, uri, title)
        )
        db.execute(
            'INSERT INTO posts (thread, reply_id, name, email, body, board) VALUES (?, 0, ?, ?, ?, ?)',
            (thread_number, name, email, body, uri)
            'INSERT INTO posts (thread, reply_id, name, email, body, board, tripcode) VALUES (?, 0, ?, ?, ?, ?, ?)',
            (thread_number, name, email, body, uri, tripcode)
        )
        db.commit()
        return redirect(url_for("thread.view_thread", uri=uri, thread=thread_number))  # view specific post


@@ 64,5 62,8 @@ def process_name(name):
            go = name.index('#')
            trip = sha1(name[go:].encode('utf-8'))
            name = name[:go]
            return name + "◆" + trip.hexdigest()[:10]
    return "Anonymous"
            return name, trip.hexdigest()[:10]
        else:
            return name, None
    else:
        return "Anonymous", None

M atch/schema.sql => atch/schema.sql +16 -0
@@ 9,6 9,8 @@ CREATE TABLE IF NOT EXISTS threads (
    board VARCHAR(7) NOT NULL,
    bump_timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    title VARCHAR(50),
    archived INTEGER DEFAULT 0,
    sticky INTEGER DEFAULT 0,

    PRIMARY KEY (thread_id, board),
    FOREIGN KEY (board) REFERENCES boards(uri)


@@ 20,9 22,23 @@ CREATE TABLE IF NOT EXISTS posts (
    reply_id INTEGER NOT NULL,
    created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    name VARCHAR(50) NOT NULL,
    tripcode VARCHAR(10),
    email VARCHAR(50),
    body TEXT NOT NULL,
    banned INTEGER DEFAULT 0,
    deleted INTEGER DEFAULT 0,

    PRIMARY KEY (thread, board, reply_id),
    FOREIGN KEY (thread, board) REFERENCES threads(thread_id, board)
);

CREATE TABLE IF NOT EXISTS admins (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    username VARCHAR(15) NOT NULL,
    password_hash TEXT NOT NULL
);

CREATE TABLE IF NOT EXISTS users (
    ip_address TEXT PRIMARY KEY NOT NULL,
    banned INTEGER DEFAULT 0
);
\ No newline at end of file

M atch/static/css/style.css => atch/static/css/style.css +29 -0
@@ 10,6 10,11 @@ html {

.user {
    color: darkgreen;
    font-weight: bold;
}

.tripcode {
    color: darkgreen;
}

.arrows {


@@ 39,4 44,28 @@ html {
    padding-left: 15px;
    padding-top: 10px;
    padding-bottom: 10px;
}

.tag {
    font-size: 7pt;
    padding: 3px;
    display: inline;
    font-weight: bolder;
    vertical-align: middle;
    color: white;
    text-transform: uppercase;
    text-align: center;
    border: 1px solid black;
}

.tag.archived {
    background-color: royalblue;
}

.tag.banned {
    background-color: darkred;
}

.tag.sticky {
    background-color: rebeccapurple;
}
\ No newline at end of file

M atch/static/js/threadMain.js => atch/static/js/threadMain.js +3 -4
@@ 8,10 8,9 @@ function parsePostBodies() {


function addReplyTag(tag) {
    let text = $('textarea#body')
    text.append(">>" + tag)
    text.focus()
    console.log("eeee")
    let text = $('textarea#body');
    text.append(">>" + tag + "\n");
    text.focus();
}



M atch/templates/board.html => atch/templates/board.html +9 -0
@@ 33,6 33,12 @@
    {% for thread in threads %}
        <div class="post_container" id="t{{ thread["threads.thread_id"] }}">
            <div class="post header">
                {% if thread["sticky"] == 1 %}
                    <div class="tag sticky">STICKY</div>
                {% endif %}
                {% if thread["archived"] == 1 %}
                    <div class="tag archived">ARCH</div>
                {% endif %}
                <span class="thread_no">Thread No: {{ thread["thread_id"] }} ||</span>
                <span class="title">{{ thread["title"] }}</span>
                <span class="user">


@@ 42,6 48,9 @@
                        <a href="mailto:{{ thread["email"] }}">{{ thread["name"] }}</a>
                    {% endif %}
                </span>
                {% if thread["tripcode"] is not none %}
                    <span class="tripcode"> ◆ {{ thread["tripcode"] }}</span>
                {% endif %}
                <span class="date">{{ thread["created"] }}</span>
                <span>
                    [<a href="{{ url_for("thread.view_thread", uri=uri, thread=thread["thread_id"]) }}">View</a>]

M atch/templates/thread.html => atch/templates/thread.html +16 -0
@@ 15,6 15,7 @@
{% endblock %}

{% block content %}
    {% if thread_data["archived"] == 0 %}
    Reply to this thread:
    <form action="{{ url_for('thread.new_reply', uri=uri, thread=thread_data["thread_id"]) }}" name="new_post" method="post" enctype="multipart/form-data">
        <table id="new_post">


@@ 35,6 36,9 @@
            </tr>
        </table>
    </form>
    {% else %}
        <h1 style="color: navy;">This thread is archived; you may no longer reply.</h1>
    {% endif %}

    <br>



@@ 50,6 54,15 @@
        </div>
        <div class="post_container">
                <div class="post header" id="{{ reply["reply_id"] }}">
                    {% if thread_data["sticky"] == 1 %}
                        <div class="tag sticky">STICKY</div>
                    {% endif %}
                    {% if thread_data["archived"] == 1 %}
                        <div class="tag archived">ARCH</div>
                    {% endif %}
                    {% if reply["banned"] == 1 %}
                        <div class="tag banned">BAN</div>
                    {% endif %}
                    <span class="user">
                        {% if reply["email"] == "" %}
                            {{ reply["name"] }}


@@ 57,6 70,9 @@
                            <a href="mailto:{{ reply["email"] }}">{{ reply["name"] }}</a>
                        {% endif %}
                    </span>
                    {% if reply["tripcode"] is not none %}
                        <span class="tripcode"> ◆ {{ reply["tripcode"] }}</span>
                    {% endif %}
                    <span class="date">{{ reply["created"] }}</span>
                    <span class="reply_bt"><a href="#" onclick="return addReplyTag({{ reply["reply_id"] }})">Reply</a></span>
                </div>

M atch/thread.py => atch/thread.py +11 -8
@@ 8,7 8,9 @@ bp = Blueprint('thread', __name__)
@bp.route('/<string:uri>/<int:thread>')
def view_thread(uri, thread):
    db = get_db()
    thread_data = db.execute('SELECT * FROM threads WHERE board=? and thread_id=?', (uri, thread)).fetchone()
    thread_data = db.execute('SELECT * FROM threads WHERE board=? AND thread_id=?', (uri, thread)).fetchone()
    if thread_data is None:
        abort(404)
    replies = db.execute('SELECT * FROM posts WHERE thread=? ORDER BY created', (thread,)).fetchall()

    return render_template('thread.html', thread_data=thread_data, replies=replies, uri=uri,


@@ 18,19 20,20 @@ def view_thread(uri, thread):
@bp.route('/<string:uri>/<int:thread>/new_post', methods=['POST'])
def new_reply(uri, thread):
    if request.method == 'POST':
        if '◆' in request.form['name']:
            return render_template('post_error.html', why="The diamond symbol (◆) is not allowed in usernames.")
        name = process_name(request.form['name'])
        name, tripcode = process_name(request.form['name'])
        email = request.form['email']
        body = request.form['body']
        db = get_db()
        reply_no = len(db.execute("SELECT * FROM posts WHERE thread=?", (thread,)).fetchall())
        reply_no = len(db.execute("SELECT * FROM posts WHERE thread=? AND board=?", (thread, uri)).fetchall())
        if reply_no == 1000:
            db.execute('UPDATE threads SET archived = 1 WHERE board=? AND thread_id=?',
                       (uri, thread))
        db.execute(
            'INSERT INTO posts (thread, reply_id, name, email, body, board) VALUES (?, ?, ?, ?, ?, ?)',
            (thread, reply_no, name, email, body, uri)
            'INSERT INTO posts (thread, reply_id, name, email, body, board, tripcode) VALUES (?, ?, ?, ?, ?, ?, ?)',
            (thread, reply_no, name, email, body, uri, tripcode)
        )
        if request.form["email"] != "sage":
            db.execute('UPDATE threads SET bump_timestamp = CURRENT_TIMESTAMP WHERE board=? and thread_id=?',
            db.execute('UPDATE threads SET bump_timestamp = CURRENT_TIMESTAMP WHERE board=? AND thread_id=?',
                       (uri, thread))
        db.commit()
        return redirect(url_for('thread.view_thread', uri=uri, thread=thread))  # view specific post