Add the ability to create and view articles
This commit is contained in:
parent
549e15add0
commit
55514664f0
|
@ -1,9 +1,9 @@
|
|||
from flask import Flask, render_template, g
|
||||
|
||||
from .models import *
|
||||
from .markdown import *
|
||||
from .models import db, migrate
|
||||
from .blueprints.session_simple import session_provider
|
||||
from .blueprints.user_default import user_provider
|
||||
from .blueprints.article_default import article_provider
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config["SECRET_KEY"] = "changeme"
|
||||
|
@ -14,18 +14,11 @@ db.init_app(app)
|
|||
migrate.init_app(app, db)
|
||||
|
||||
app.register_blueprint(session_provider, url_prefix="/session")
|
||||
app.register_blueprint(user_provider, url_prefix="/users")
|
||||
app.register_blueprint(user_provider, url_prefix="/user")
|
||||
app.register_blueprint(article_provider, url_prefix="/article")
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def main_page():
|
||||
print(g.wl_user)
|
||||
return render_template('index.html')
|
||||
|
||||
|
||||
@app.route("/test")
|
||||
def test_article():
|
||||
return render_template(
|
||||
'article.html', article_title="Sample Text",
|
||||
article_content=md_render("# sample\n\nmeme and also\n\n\n---\nmeme $2+2$"))
|
||||
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
from flask import Blueprint, render_template, g, session, redirect, request, url_for, flash
|
||||
import secrets
|
||||
from datetime import datetime
|
||||
import re
|
||||
|
||||
from ..models import *
|
||||
from ..markdown import *
|
||||
|
||||
article_provider = Blueprint("article", __name__, template_folder='templates')
|
||||
|
||||
blacklisted_titles = ["new", "by-id"]
|
||||
allowed_titles = re.compile(r"^[a-zA-Z0-9 \(\)\.\,:;]+$")
|
||||
|
||||
def urlify(title):
|
||||
return title[0].upper() + title[1:].replace(" ", "_")
|
||||
|
||||
|
||||
def unurlify(title):
|
||||
return title.replace("_", " ").lower()
|
||||
|
||||
|
||||
@article_provider.route("/<title>")
|
||||
def show(title):
|
||||
real_title = unurlify(title)
|
||||
print(real_title)
|
||||
article = Article.query.filter_by(title=real_title).first_or_404()
|
||||
revision = ArticleRevision.query.filter_by(article_id=article.id).order_by(
|
||||
ArticleRevision.date.desc()).first()
|
||||
toc, content = md_render(revision.content)
|
||||
return render_template(
|
||||
'article.html', article_title=article.title,
|
||||
article_content=content, article_toc=toc)
|
||||
|
||||
|
||||
@article_provider.route("/new", methods=["GET", "POST"])
|
||||
def new():
|
||||
if g.wl_user is None:
|
||||
return redirect(url_for("session.login"), code=302)
|
||||
|
||||
old_csrf = session.get("csrf", None)
|
||||
csrf = secrets.token_urlsafe(16)
|
||||
session["csrf"] = csrf
|
||||
|
||||
if request.method == "GET":
|
||||
return render_template("article_new.html", csrf=csrf, article_title="", article_content="")
|
||||
else:
|
||||
article_title = request.form["article_title"].strip().lower()
|
||||
article_content = request.form["article_content"]
|
||||
|
||||
if request.form["csrf"] != old_csrf:
|
||||
flash("Error creating article", "error");
|
||||
return render_template("article_new.html",
|
||||
csrf=csrf, article_title=article_title,
|
||||
article_content=article_content)
|
||||
if (len(article_title) == 0
|
||||
or article_title in blacklisted_titles
|
||||
or not allowed_titles.match(article_title)):
|
||||
flash("Invalid title", "error")
|
||||
return render_template("article_new.html",
|
||||
csrf=csrf, article_title=article_title,
|
||||
article_content=article_content)
|
||||
if Article.query.filter_by(title=article_title).first() is not None:
|
||||
flash("Article already exists", "error")
|
||||
return render_template("article_new.html",
|
||||
csrf=csrf, article_title=article_title,
|
||||
article_content=article_content)
|
||||
|
||||
article = Article(title=article_title)
|
||||
article.revisions.append(ArticleRevision(
|
||||
date=datetime.now(),
|
||||
user=g.wl_user,
|
||||
changelog="Created article " + article_title,
|
||||
content=article_content))
|
||||
db.session.add(article)
|
||||
db.session.commit()
|
||||
session.pop("csrf", None)
|
||||
return redirect(url_for(".show", title=urlify(article_title)), code=302)
|
|
@ -17,12 +17,16 @@ def get_session_user():
|
|||
|
||||
@session_provider.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
old_csrf = session.get("_csrf", None)
|
||||
old_csrf = session.get("csrf", None)
|
||||
csrf = secrets.token_urlsafe(32)
|
||||
session["_csrf"] = csrf
|
||||
session["csrf"] = csrf
|
||||
redir = request.args.get("redirect", session.get("redirect", "/"))
|
||||
|
||||
if g.wl_user is not None:
|
||||
return redirect("/", code=302)
|
||||
session.pop("redirect", None)
|
||||
return redirect(redir, code=302)
|
||||
|
||||
session["redirect"] = redir
|
||||
|
||||
if request.method == 'GET':
|
||||
return render_template("login_form.html", csrf=csrf)
|
||||
|
@ -30,20 +34,22 @@ def login():
|
|||
if not request.form["username"]:
|
||||
flash("Must provide username", "error")
|
||||
return render_template("login_form.html", csrf=csrf)
|
||||
if old_csrf != request.form["_csrf"]:
|
||||
if old_csrf != request.form["csrf"]:
|
||||
flash("Invalid request", "error")
|
||||
return render_template("login_form.html", csrf=csrf)
|
||||
user = User.query.filter_by(username=request.form["username"]).first()
|
||||
if not user:
|
||||
db.session.add(User(username=request.form["username"], email=secrets.token_hex(8) + "@example.com"))
|
||||
db.session.add(User(username=request.form["username"],
|
||||
email=secrets.token_hex(8) + "@example.com"))
|
||||
db.session.commit()
|
||||
session["username"] = request.form["username"]
|
||||
session.pop("_csrf", None)
|
||||
return redirect("/", code=302)
|
||||
session.pop("csrf", None)
|
||||
session.pop("redirect", None)
|
||||
return redirect(redir, code=302)
|
||||
|
||||
|
||||
@session_provider.route("/logout", methods=["POST"])
|
||||
def logout():
|
||||
session.pop("username", None)
|
||||
session.pop("_csrf", None)
|
||||
return redirect("/", code=302)
|
||||
session.pop("csrf", None)
|
||||
return redirect(request.form.get("redirect", "/"), code=302)
|
||||
|
|
|
@ -6,5 +6,6 @@
|
|||
|
||||
{% block content %}
|
||||
<h1>{{ article_title }}</h1>
|
||||
{{ article_toc }}
|
||||
{{ article_content }}
|
||||
{% endblock %}
|
|
@ -0,0 +1,15 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}
|
||||
New Article
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>New Article</h1>
|
||||
<form action="{{ url_for('article.new') }}" method="POST">
|
||||
<input type="hidden" style="display:none" name="csrf" value="{{ csrf }}" />
|
||||
<input type="text" name="article_title" placeholder="Title" value="{{ article_title }}" />
|
||||
<textarea name="article_content" placeholder="Content">{{article_content}}</textarea>
|
||||
<button type="submit">Create</button>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -7,8 +7,9 @@ Log In
|
|||
{% block content %}
|
||||
<h2>Log In</h2>
|
||||
<form action="{{ url_for(".login") }}" method="POST">
|
||||
<input type="hidden" style="display:none" name="_csrf" value="{{ csrf }}" />
|
||||
<input type="text" name="username" placeholder="Username" />
|
||||
<input type="submit" />
|
||||
<input type="hidden" style="display:none" name="csrf" value="{{ csrf }}" />
|
||||
<input type="text" name="username" placeholder="Username" autocomplete="off" />
|
||||
<input type="password" name="password" placeholder="Password" />
|
||||
<button type="submit">Log In</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
|
|
@ -32,5 +32,5 @@ __all__ = ["md_render"]
|
|||
def md_render(*args, **kwargs):
|
||||
renderer.reset_toc()
|
||||
results = markdown(*args, **kwargs)
|
||||
print(renderer.toc_tree)
|
||||
return Markup(renderer.render_toc(level=3) + results)
|
||||
toc = renderer.render_toc(level=3) if len(renderer.toc_tree) > 0 else ""
|
||||
return Markup(toc), Markup(results)
|
||||
|
|
|
@ -29,7 +29,7 @@ class Article(db.Model):
|
|||
__tablename__ = "articles"
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
title = db.Column(db.String, unique=True, nullable=False)
|
||||
section_id = db.Column(db.Integer, db.ForeignKey("sections.id"), nullable=False)
|
||||
section_id = db.Column(db.Integer, db.ForeignKey("sections.id"), nullable=True)
|
||||
revisions = db.relationship("ArticleRevision", backref="article", lazy=True)
|
||||
|
||||
def __repr__(self):
|
||||
|
|
|
@ -11,16 +11,23 @@
|
|||
<h1><a href="/">WikiLain</a></h1>
|
||||
<ul>
|
||||
<li>
|
||||
<form action="/search" action="POST">
|
||||
<form action="/search" method="POST">
|
||||
<button type="submit"></button>
|
||||
<input type="text" name="q" placeholder="Search" />
|
||||
</form>
|
||||
</li>
|
||||
<li><a href="/sections">Sections</a></li>
|
||||
{% if not g.wl_user %}
|
||||
<li><a href="{{ url_for("session.login") }}">Log In</a></li>
|
||||
<li>
|
||||
<a href="{{ url_for("session.login") }}?redirect={{ request.path }}">
|
||||
Log In
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li>
|
||||
<form action="{{ url_for("session.logout") }}" method="POST">
|
||||
<input type="hidden" style="display:none" name="redirect"
|
||||
value="{{ request.path }}" />
|
||||
<button type="submit">Log Out</button>
|
||||
</form>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue