Exemple #1
0
def search():
    query_string = flask.request.args.get('q')
    if not query_string:
        return render_template('search.tmpl', title="Search", query_string="")

    cnx = get_pg_connection()

    try:
        cursor = cnx.cursor()
        cursor.execute(
            "SELECT query.floor, query.post_id, query.thread_id, query.title, "
            "pgroonga_snippet_html(query.content, pgroonga_query_extract_keywords(%s)) FROM "
            "(SELECT post.post_id AS post_id, post.thread AS thread_id, post_content.content AS content, "
            "rank() OVER (PARTITION BY post.thread ORDER BY post.datetime) AS floor, thread.title AS title "
            "FROM post, post_content, thread WHERE post_content.post = post.post_id "
            "AND post.thread = thread.thread_id "
            "AND post.hidden = FALSE AND thread.hidden = FALSE "
            "AND thread.draft = FALSE "
            ") AS query WHERE query.content &@~ %s",
            (query_string, query_string))
        ret = render_template("search.tmpl",
                              title=query_string,
                              cursor=cursor,
                              query_string=query_string)
    finally:
        cnx.close()

    return ret
Exemple #2
0
def sudo():
    user = check_permission()

    redis = get_redis_connection()
    failed_attempts = redis.get('sudo_fail_{}'.format(user))
    failed_attempts = int(failed_attempts) if failed_attempts != None else 0
    if failed_attempts >= 5:
        write_log("dashboard_access", user, {
            "success": False,
            "reason": "too many attemps"
        })
        return render_template("dashboard/sudo.tmpl", error=True, chances=0)

    if flask.request.method == "GET":
        return render_template("dashboard/sudo.tmpl")

    password = flask.request.form.get("password")
    if password == None:
        flask.abort(400)

    cnx = get_pg_connection()
    try:
        cursor = cnx.cursor()
        cursor.execute("SELECT salt FROM users WHERE user_id = %s", (user, ))
        salt = cursor.fetchone()[0]

    finally:
        cnx.close()

    hashed_password = hashlib.sha256(
        (password + salt).encode()).hexdigest().upper()

    cnx = get_pg_connection()
    try:
        cursor = cnx.cursor()
        cursor.execute(
            "SELECT * FROM users WHERE user_id = %s AND password = %s",
            (user, hashed_password))
        result = cursor.fetchone()
    finally:
        cnx.close()

    if result == None:
        write_log("dashboard_access", user, {"success": False})
        redis = get_redis_connection()
        failed_attemps = int(redis.incr('sudo_fail_{}'.format(user)))
        redis.expire('sudo_fail_{}'.format(user), 300)
        ret = render_template("dashboard/sudo.tmpl",
                              error=True,
                              chances=max(5 - failed_attemps, 0))
        return ret
    else:
        ret = flask.make_response(flask.redirect("/dashboard/"))
        ret.set_cookie("sudo_mode", create_cookie(user))
        redis = get_redis_connection()
        redis.delete('sudo_fail_{}'.format(user))
        write_log("dashboard_access", user, {"success": True})
        return ret
Exemple #3
0
def registration():
    if flask.request.method == "GET":
        referrer = flask.request.referrer
        return render_template("login.tmpl",
                               title="注册",
                               referrer=referrer,
                               type="registration")

    try:
        username = flask.request.form["username"]
        password = flask.request.form["password"]
        email = flask.request.form["email"]
        referrer = flask.request.form["referrer"]
    except KeyError:
        flask.abort(400)

    cnx = get_pg_connection()
    try:
        cursor = cnx.cursor()
        cursor.execute("SELECT * FROM users WHERE name = %s", (username, ))
        if cursor.fetchone() != None:
            write_log(
                "registration", "", {
                    "success": False,
                    "username": username,
                    "reason": "user already exists"
                })
            return render_template("login.tmpl",
                                   title="注册",
                                   referrer=referrer,
                                   error="用户 {} 已经存在".format(username))

        user_id = str(uuid.uuid4()).replace('-', '').upper()
        salt = crypt.mksalt(crypt.METHOD_SHA256)
        hashed_password = hashlib.sha256(
            (password + salt).encode()).hexdigest().upper()
        cursor.execute(
            "INSERT INTO users VALUES ( "
            "%s, %s, %s, %s, %s, FALSE, FALSE, %s)",
            (user_id, username, email, hashed_password, username, salt))
        cnx.commit()
        write_log("registration", user_id, {"success": True})
    finally:
        cnx.close()

    cookie = create_cookie(user_id)
    response = flask.make_response(flask.redirect(referrer))
    response.set_cookie("session", cookie, expires=32503680000)
    return response
Exemple #4
0
def userinfo(userid):
    user = check_permission()
    sudo = check_sudo(user)
    if not sudo:
        return flask.redirect("/dashboard/sudo")

    cnx = get_pg_connection()
    try:
        cursor = cnx.cursor()
        cursor.execute(
            "SELECT name, nick, email, admin FROM users WHERE user_id = %s",
            (userid, ))
        userinfo = cursor.fetchone()
    finally:
        cnx.close()

    if user == None:
        flask.abort(404)

    username, nick, email, admin = userinfo

    user_avatar = hashlib.md5(
        email.lower().strip().encode()).hexdigest().lower()

    return render_template("dashboard/userinfo.tmpl",
                           username=username,
                           nick=nick,
                           email=email,
                           user_avatar=user_avatar,
                           user_is_admin=admin,
                           userid=userid)
Exemple #5
0
def posts_view():
    user = check_permission()
    sudo = check_sudo(user)
    if not sudo:
        return flask.redirect("/dashboard/sudo")

    return render_template("posts_view.tmpl")
Exemple #6
0
def index():
    user = check_permission()

    sudo = check_sudo(user)

    if not sudo:
        return flask.redirect("/dashboard/sudo")

    cnx = get_pg_connection()
    try:
        cursor = cnx.cursor()
        cursor.execute(
            "SELECT log.type, users.name, log.data FROM log, users "
            "WHERE users.user_id = log.operator ORDER BY log.datetime DESC LIMIT 10"
        )
        recent_events = list(cursor)

        cursor.execute(
            "SELECT log.datetime, log.data FROM log, users "
            "WHERE users.user_id = log.operator AND log.operator = %s "
            "AND log.type = 'dashboard_access' ORDER by log.datetime DESC LIMIT 10",
            (user, ))
        recent_access = list(cursor)
    finally:
        cnx.close()

    return render_template("dashboard/index.tmpl",
                           recent_events=recent_events,
                           recent_access=recent_access,
                           log_type_to_string=log_type_to_string,
                           log_data_simple=log_data_simple)
Exemple #7
0
def new():
    cnx = get_pg_connection()
    try:
        cursor = cnx.cursor()

    finally:
        cnx.close()

    return render_template("edit.tmpl", title="New Thread", type="new_thread")
Exemple #8
0
def threads():
    user = check_permission()
    sudo = check_sudo(user)
    if not sudo:
        return flask.redirect("/dashboard/sudo")

    query_string = flask.request.args.get("s")
    if query_string == None:
        return render_template("dashboard/threads.tmpl")

    cnx = get_pg_connection()
    try:
        cursor = cnx.cursor()
        cursor.execute(
            "SELECT title, hidden, thread_id FROM thread WHERE title &@~ %s",
            (query_string, ))
        threads = cursor.fetchall()
    finally:
        cnx.close()

    return render_template("dashboard/threads.tmpl", threads=threads)
Exemple #9
0
def users():
    user = check_permission()

    sudo = check_sudo(user)
    if not sudo:
        return flask.redirect("/dashboard/sudo")

    query_string = flask.request.args.get("s")

    if query_string == None:
        return render_template("dashboard/user.tmpl")

    cnx = get_pg_connection()
    try:
        cursor = cnx.cursor()
        cursor.execute(
            "SELECT user_id, name, nick FROM users WHERE nick LIKE %s",
            ("%{}%".format(query_string), ))
        users = cursor.fetchall()
    finally:
        cnx.close()

    return render_template("dashboard/user.tmpl", users=users)
Exemple #10
0
def categories():
    user = check_permission()

    sudo = check_sudo(user)
    if not sudo:
        return flask.redirect("/dashboard/sudo")

    cnx = get_pg_connection()
    try:
        cursor = cnx.cursor()
        cursor.execute('SELECT category_id, name FROM category')
        categories = cursor.fetchall()
    finally:
        cnx.close()

    return render_template("dashboard/category.tmpl", categories=categories)
Exemple #11
0
def log():
    user = check_permission()
    sudo = check_sudo(user)
    if not sudo:
        return flask.redirect("/dashboard/sudo")

    cnx = get_pg_connection()
    try:
        cursor = cnx.cursor()
        cursor.execute(
            "SELECT log.*, users.name FROM log, users WHERE users.user_id = log.operator ORDER BY log.datetime DESC"
        )
        logs = cursor.fetchall()
    finally:
        cnx.close()

    return render_template("/dashboard/logs.tmpl",
                           logs=logs,
                           log_type_to_string=log_type_to_string,
                           log_data_simple=log_data_simple)
Exemple #12
0
def deleted_post(post_id):
    user = flask.request.cookies.get("session")
    if user != None and read_cookie(user) != None:
        user = read_cookie(user)

    cnx = get_pg_connection()
    try:
        if user:
            cursor = cnx.cursor()
            cursor.execute("SELECT admin FROM users WHERE user_id = %s",
                           (user, ))
            admin, = cursor.fetchone()
        else:
            admin = False

        if not admin:
            flask.abort(404)

        cursor = cnx.cursor()
        cursor.execute(
            "select post.post_id, users.nick, post.author, "
            "LOWER(MD5(TRIM(LOWER(users.email)))), "
            "post_content.content, post_content.datetime, post_content.renderer FROM post, users, post_content "
            "WHERE post.author = users.user_id "
            "AND post.content = post_content.content_id "
            "AND post.post_id = %s", (post_id, ))
        posts = cursor.fetchall()
    finally:
        cnx.close()
        return render_template("post.tmpl",
                               posts=posts,
                               page=1,
                               post_per_page=1,
                               total_pages=1,
                               render_content=render_content,
                               title="被删除的回复")
Exemple #13
0
def log_detail(id):
    user = check_permission()
    sudo = check_sudo(user)
    if not sudo:
        return flask.redirect("/dashboard/sudo")

    try:
        id = int(id)
    except:
        flask.abort(400)

    cnx = get_pg_connection()
    try:
        cursor = cnx.cursor()
        cursor.execute(
            "SELECT log.*, users.name FROM log, users WHERE users.user_id = log.operator AND log.log_id = %s",
            (id, ))
        details = cursor.fetchone()
    finally:
        cnx.close()

    return render_template("/dashboard/log_details.tmpl",
                           details=details,
                           log_type_to_string=log_type_to_string)
Exemple #14
0
def login():
    if flask.request.method == "GET":
        referrer = flask.request.referrer
    else:
        referrer = flask.request.form["referrer"]

    try:
        referrer.index("/login")
    except ValueError:
        pass
    else:
        referrer = "/"

    if flask.request.method == "GET":
        return render_template("login.tmpl",
                               title="登录",
                               referrer=flask.request.referrer,
                               error=None,
                               type="login")
    else:
        username = flask.request.form["username"]
        password = flask.request.form["password"]

        cnx = get_pg_connection()
        try:
            cursor = cnx.cursor()
            cursor.execute("SELECT salt FROM users WHERE name = %s",
                           (username, ))
            salt = cursor.fetchone()
            if salt:
                salt = salt[0]
            else:
                error = "用户名或密码错误"
                write_log(
                    "login", "", {
                        "success": False,
                        "username": username,
                        "reason": "user does not exist"
                    })
                return render_template("login.tmpl",
                                       referrer=referrer,
                                       error=error,
                                       title="Login",
                                       type="login")
            hashed_password = hashlib.sha256(
                (password + salt).encode()).hexdigest().upper()
            cursor.execute(
                "SELECT user_id AS uid FROM users WHERE name = %s AND password = %s",
                (username, hashed_password))

            ret = cursor.fetchone()
            if not ret:
                cnx.close()
                error = "用户名或密码错误"
                write_log(
                    "login", "", {
                        "success": False,
                        "username": username,
                        "reason": "wrong password"
                    })
                return render_template("login.tmpl",
                                       referrer=referrer,
                                       error=error,
                                       title="Login",
                                       type="login")
        finally:
            cnx.close()

        userid = ret[0]
        cookie = create_cookie(userid)
        response = flask.make_response(flask.redirect(referrer))
        response.set_cookie("session", cookie, expires=32503680000)
        write_log("login", userid, {"success": True, "username": username})
        return response
Exemple #15
0
def userinfo():
    try:
        user = read_cookie(flask.request.cookies["session"])
    except KeyError:
        return flask.redirect("/")

    if not user:
        flask.redirect("/")

    cnx = get_pg_connection()
    try:
        cursor = cnx.cursor()
        cursor.execute(
            'SELECT name, email, nick, salt FROM users WHERE user_id = %s',
            (user, ))
        name, email, nick, salt = cursor.fetchone()
    finally:
        cnx.close()

    if flask.request.method == "GET":
        return render_template("userinfo.tmpl",
                               error=False,
                               name=name,
                               email=email,
                               nick=nick,
                               title="User Info")
    else:
        try:
            new_email = flask.request.form["email"]
            new_nick = flask.request.form["nick"]
            old_password = flask.request.form["old_password"]
            new_password = flask.request.form["new_password"]
        except:
            return flask.abort(400)

        if new_password != "":
            cnx = get_pg_connection()
            cursor = cnx.cursor()
            try:
                hashed_old_password = hashlib.sha256(
                    (old_password + salt).encode()).hexdigest().upper()
                cursor.execute(
                    "SELECT user_id FROM users WHERE user_id = %s AND password = %s",
                    (user, hashed_old_password))
                if not cursor.fetchone():
                    cnx.close()
                    write_log("update_userinfo", user, {
                        "success": False,
                        "reason": "wrong password"
                    })
                    return render_template("userinfo.tmpl",
                                           error=True,
                                           name=name,
                                           email=email,
                                           nick=nick,
                                           title="User Info")
            except:
                cnx.close()
                raise

            salt = crypt.mksalt(crypt.METHOD_SHA256)
            hashed_password = hashlib.sha256(
                (new_password + salt).encode()).hexdigest().upper()
        else:
            hashed_password = None

        cnx = get_pg_connection()
        try:
            cursor = cnx.cursor()
            if hashed_password:
                cursor.execute(
                    "UPDATE users SET email = %s, nick = %s, password = %s, salt = %s WHERE user_id = %s",
                    (new_email, new_nick, hashed_password, salt, user))
            else:
                cursor.execute(
                    "UPDATE users SET email = %s, nick = %s WHERE user_id = %s",
                    (new_email, new_nick, user))
            cnx.commit()
        finally:
            cnx.close()

        log_data = {
            "success": True,
            "nick": [nick, new_nick],
            "email": [email, new_email],
            "password_changed": new_password != ""
        }
        write_log("update_userinfo", user, log_data)
        return flask.redirect("/userinfo")
Exemple #16
0
def edit(edit_type, target_id):
    try:
        user = read_cookie(flask.request.cookies["session"])
    except:
        user = None

    if user == None:
        flask.abort(401)

    cnx = get_pg_connection()
    try:
        cursor = cnx.cursor()

        if edit_type == 'thread':
            cursor.execute(
                "SELECT thread.title, thread.category, thread.draft, users.admin FROM thread, users "
                "WHERE thread.thread_id = %s AND users.user_id = %s AND (thread.author = users.user_id OR users.admin = TRUE)",
                (target_id, user))
            title, category, is_draft, _ = cursor.fetchone()

            cursor.execute(
                "SELECT post.post_id, users.admin FROM post, users "
                "WHERE post.thread = %s AND users.user_id = %s AND (post.author = users.user_id OR users.admin = TRUE) "
                "ORDER BY datetime LIMIT 1 OFFSET 0", (target_id, user))
            post_id = cursor.fetchone()
            if not post_id:
                flask.abort(404)
            post_id = post_id[0]
        else:
            post_id = target_id
    except:
        cnx.close()
        raise

    try:
        cursor = cnx.cursor()
        cursor.execute(
            "SELECT content, renderer FROM post_content WHERE post = %s ORDER BY datetime DESC LIMIT 1 OFFSET 0",
            (post_id, ))
        content, renderer = cursor.fetchone()
    finally:
        cnx.close()

    kwargs = {
        "renderer": renderer,
        "referrer": flask.request.referrer,
        "content": content,
        "post_id": post_id
    }

    if edit_type == "thread":
        print(title)
        kwargs["type"] = "edit_thread"
        kwargs["title"] = "编辑主题:" + title
        kwargs["current_category_id"] = category
        kwargs["draft"] = is_draft
        kwargs["thread_id"] = target_id
    else:
        kwargs["type"] = "edit_post"
        kwargs["title"] = "编辑回复"

    return render_template("edit.tmpl", **kwargs)
Exemple #17
0
def post(thread, page):
    user = flask.request.cookies.get("session")
    if user != None and read_cookie(user) != None:
        user = read_cookie(user)

    cnx = get_pg_connection()
    try:
        if user:
            cursor = cnx.cursor()
            cursor.execute("SELECT admin FROM users WHERE user_id = %s",
                           (user, ))
            admin, = cursor.fetchone()
        else:
            admin = False

        cursor = cnx.cursor()
        cursor.execute("SELECT title FROM thread WHERE thread_id = %s",
                       (thread, ))
        title = cursor.fetchone()[0]

        cursor = cnx.cursor()
        cursor.execute("SELECT COUNT(*) FROM post WHERE thread = %s",
                       (thread, ))
        post_count = cursor.fetchone()[0]

        cursor = cnx.cursor()
        cursor.execute("SELECT hidden FROM thread WHERE thread_id = %s",
                       (thread, ))
        hidden, = cursor.fetchone()

        if hidden and not admin:
            flask.abort(404)

        query = (
            "SELECT post.post_id, users.nick, post.author, "
            "LOWER(MD5(TRIM(LOWER(users.email)))), "
            "post_content.content, post_content.datetime, post_content.renderer FROM post, users, thread, post_content "
            "WHERE post.thread = %s AND post.hidden = FALSE "
            "AND post.thread = thread.thread_id "
            "AND post.author = users.user_id "
            "AND post.content = post_content.content_id "
            "ORDER BY post.datetime LIMIT {} OFFSET %s".format(
                config["paginator"]["post_per_page"]))
        cursor = cnx.cursor()
        cursor.execute(
            query,
            (thread, int(
                (int(page) - 1) * config["paginator"]["post_per_page"])))
        posts = list(cursor)

        cursor = cnx.cursor()
        cursor.execute("SELECT thread.author FROM thread WHERE thread_id = %s",
                       (thread, ))
        thread_author_id = cursor.fetchone()[0]

    finally:
        cnx.close()

    total_pages = int((post_count - 1) / config["paginator"]["post_per_page"] +
                      1)
    return render_template("post.tmpl",
                           posts=posts,
                           thread_hidden=hidden,
                           page=int(page),
                           total_pages=total_pages,
                           thread_author_id=thread_author_id,
                           baseurl="/thread/view/{}".format(thread),
                           post_per_page=config["paginator"]["post_per_page"],
                           render_content=render_content,
                           title=title,
                           thread_id=thread)
Exemple #18
0
def list_threads(order, page, category=None, author=None, draft=False):
    order_sql = {
        'publish': 'publish_datetime',
        'reply': 'reply_count',
        'last_modified': 'last_modified',
        'random': 'RAND()'
    }

    category_sql = "AND thread.category = %s" if category else ''
    author_sql = "AND thread.author = %s" if author else ''

    try:
        sudo_mode = read_cookie(flask.request.cookies["sudo_mode"])
    except KeyError:
        sudo_mode = None

    hidden = bool(sudo_mode)

    query = (
        "SELECT thread.thread_id, thread.title, thread.datetime AS publish_datetime, "
        "users.nick, MAX(post.last_modified) AS last_modified, "
        "(SELECT COUNT(*) FROM post WHERE post.thread = thread.thread_id) AS reply_count FROM thread, post, users "
        "WHERE thread.hidden = FALSE "
        "AND post.thread = thread.thread_id "
        "AND users.user_id = thread.author "
        "AND thread.draft = %s {} {} "
        "GROUP BY thread.thread_id, users.nick "
        "ORDER BY {} DESC "
        "LIMIT {} "
        "OFFSET %s ").format(category_sql, author_sql, order_sql[order],
                             config["paginator"]["thread_per_page"])
    page_query = "SELECT COUNT(*) FROM thread WHERE hidden = FALSE AND draft = %s {} {}".format(
        category_sql, author_sql)
    category_query = "SELECT name FROM category WHERE category_id = %s"

    cnx = get_pg_connection()
    try:
        cursor = cnx.cursor()
        page_cursor = cnx.cursor()

        if category:
            category_cursor = cnx.cursor()

            if author:
                cursor.execute(
                    query,
                    (draft, category, author,
                     (page - 1) * config["paginator"]["thread_per_page"]))
            else:
                cursor.execute(
                    query,
                    (draft, category,
                     (page - 1) * config["paginator"]["thread_per_page"]))

            if author:
                page_cursor.execute(page_query, (draft, category, author))
            else:
                page_cursor.execute(page_query, (
                    draft,
                    category,
                ))

            category_cursor.execute(category_query, (category, ))

            category_name, = category_cursor.fetchone()

            title = "分类: " + category_name

        else:
            if author:
                cursor.execute(
                    query,
                    (draft, author,
                     (page - 1) * config["paginator"]["thread_per_page"]))
            else:
                cursor.execute(
                    query,
                    (draft,
                     (page - 1) * config["paginator"]["thread_per_page"]))

            if author:
                page_cursor.execute(page_query, (draft, author))
            else:
                page_cursor.execute(page_query, (draft, ))

            title = "主页"

        total_pages, = page_cursor.fetchone()
        total_pages = int((total_pages - 1) /
                          config["paginator"]["thread_per_page"] + 1)

        if draft:
            baseurl = "/drafts"
        elif category:
            baseurl = "/category/{}/{}".format(category, order)
        else:
            baseurl = "/index/" + order

        ret = render_template('list.tmpl',
                              cursor=cursor,
                              title=title,
                              page=page,
                              total_pages=total_pages,
                              order=order,
                              baseurl=baseurl)
    finally:
        cnx.close()

    return ret