summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--app.py92
-rw-r--r--forms.py16
-rw-r--r--models.py39
-rw-r--r--requirements.txt2
-rw-r--r--templates/login.html24
-rw-r--r--templates/post.html24
7 files changed, 175 insertions, 25 deletions
diff --git a/.gitignore b/.gitignore
index c2014f5..1d2d98a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -115,4 +115,5 @@ cython_debug/
# Local configuration files
config.py
-*.db \ No newline at end of file
+*.db
+AI_HOLDING/* \ No newline at end of file
diff --git a/app.py b/app.py
index 219b160..137a6ca 100644
--- a/app.py
+++ b/app.py
@@ -1,46 +1,108 @@
-from flask import Flask, render_template, request, redirect, url_for
+from urllib.parse import urlparse as url_parse
+
+
+from flask import Flask, render_template, request, redirect, url_for, flash
from markdown import markdown, Markdown
from config import config
-from models import Post, db
-from forms import PostForm
+from models import Post, db, get_replies, Faccet
+from models import User as NewUser
+from forms import PostForm, LoginForm
+from flask_login import (
+ login_user,
+ logout_user,
+ login_required,
+ current_user,
+ LoginManager,
+)
import os
+
app = Flask(__name__)
-app.config.from_object('config')
+app.config.from_object("config")
SECRET_KEY = os.urandom(32)
-app.config['SECRET_KEY'] = SECRET_KEY
+app.config["SECRET_KEY"] = SECRET_KEY
app.jinja_options = app.jinja_options.copy()
app.jinja_env.add_extension(Markdown)
app.jinja_env.filters["markdown"] = markdown
+login = LoginManager(app)
+login.login_view = "login"
+
+
+@login.user_loader
+def load_user(uid):
+ return NewUser.get(NewUser.id == uid)
+
+
+@app.route("/login", methods=["GET", "POST"])
+def login():
+ form = LoginForm()
+ if form.validate_on_submit(): # noqa
+ user = NewUser.get(NewUser.username == form.username.data)
+ if user is None or not user.check_password(form.password.data):
+ flash("Invalid username or password")
+ return redirect(url_for("login"))
+ login_user(user, remember=form.remember_me.data)
+ next_page = request.args.get("next")
+ if not next_page or url_parse(next_page).netloc != "":
+ next_page = url_for("index")
+ return redirect(next_page)
+
+ return render_template("login.html", form=form)
+
@app.before_request
def before_request():
db.connect()
+
@app.after_request
def after_request(response):
db.close()
return response
-@app.route('/')
+
+@app.route("/")
+@login_required
def index():
- posts = Post.select().order_by(Post.created_at.desc())
- return render_template('index.html', posts=posts)
+ posts = Post.select().where(Post.parent == 0).order_by(Post.created_at.desc())
+ return render_template("index.html", posts=posts)
+
-@app.route('/post/<int:post_id>')
+@app.route("/logout")
+@login_required
+def logout():
+ flash("Goodbye!")
+ logout_user()
+ return redirect(url_for("login"))
+
+
+@app.route("/post/<int:post_id>")
+@login_required
def post(post_id):
post = Post.get(Post.id == post_id)
- return render_template('post.html', post=post)
+ replies = get_replies(post_id)
+ return render_template("post.html", post=post, replies=replies)
-@app.route('/create', methods=['GET', 'POST'])
+
+@app.route("/create", methods=["GET", "POST"])
+@login_required
def create():
form = PostForm()
+ replyto = request.args.get("reply", 0)
+ userctx = NewUser.get(NewUser.username == current_user.username)
+ asfaccet = Faccet.get(Faccet.name == userctx.default_faccet)
if form.validate_on_submit():
- Post.create(title=form.title.data, content=form.content.data)
- return redirect(url_for('index'))
- return render_template('create.html', form=form)
+ Post.create(
+ title=form.title.data,
+ content=form.content.data,
+ authour=asfaccet,
+ parent=replyto,
+ )
+ return redirect(url_for("index"))
+ return render_template("create.html", form=form)
+
-if __name__ == '__main__':
+if __name__ == "__main__":
app.run(debug=True, port=5052)
diff --git a/forms.py b/forms.py
index d8aa8c0..be0171a 100644
--- a/forms.py
+++ b/forms.py
@@ -1,8 +1,18 @@
from flask_wtf import FlaskForm
-from wtforms import StringField, TextAreaField, SubmitField
+from wtforms import StringField, TextAreaField, SubmitField, PasswordField, BooleanField
from wtforms.validators import DataRequired
+
class PostForm(FlaskForm):
- title = StringField('Title', validators=[DataRequired()])
- content = TextAreaField('Content', validators=[DataRequired()])
+ title = StringField("Title", validators=[DataRequired()])
+ content = TextAreaField("Content", validators=[DataRequired()])
submit = SubmitField("Toot!")
+
+
+class LoginForm(FlaskForm):
+ """Login Form"""
+
+ username = StringField("Username", validators=[DataRequired()])
+ password = PasswordField("Password", validators=[DataRequired()])
+ remember_me = BooleanField("Remember Me")
+ submit = SubmitField("Sign In")
diff --git a/models.py b/models.py
index 75af58b..26934d9 100644
--- a/models.py
+++ b/models.py
@@ -1,15 +1,50 @@
-from peewee import Model, CharField, TextField, DateTimeField, SqliteDatabase
+from peewee import Model, CharField, TextField, DateTimeField, SqliteDatabase, BlobField
+from peewee import IntegerField, ForeignKeyField
+from flask_login import UserMixin
+from werkzeug.security import check_password_hash, generate_password_hash
from datetime import datetime
from config import dbloc
+
# from app import db
db = SqliteDatabase(dbloc)
+
+
class BaseModel(Model):
class Meta:
database = db
+
+class User(UserMixin, BaseModel):
+ id = IntegerField(primary_key=True)
+ username = CharField(max_length=64, index=True, unique=True)
+ default_faccet = TextField(null=False)
+ password_hash = CharField(max_length=128)
+
+ def set_password(self, password):
+ self.password_hash = generate_password_hash(password)
+
+ def check_password(self, password):
+ return check_password_hash(self.password_hash, password)
+
+
+class Faccet(BaseModel):
+ user_belongs = ForeignKeyField(User, backref="parts")
+ name = TextField(unique=True)
+ picture = BlobField()
+ bio = TextField()
+
+
class Post(BaseModel):
+ id = IntegerField(primary_key=True)
+ authour = ForeignKeyField(Faccet, backref="creator")
+ parent = IntegerField(default=0)
title = CharField()
content = TextField()
created_at = DateTimeField(default=datetime.now)
-db.create_tables([Post])
+
+def get_replies(post_id):
+ return Post.select().where(Post.parent == post_id).order_by(Post.created_at.desc())
+
+
+db.create_tables([User, Post, Faccet])
diff --git a/requirements.txt b/requirements.txt
index 125950d..70cfdae 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,10 +1,12 @@
blinker==1.9.0
click==8.1.8
Flask==3.1.0
+Flask-Login==0.6.3
Flask-WTF==1.2.2
itsdangerous==2.2.0
Jinja2==3.1.6
MarkupSafe==3.0.2
+mistletoe==1.4.0
peewee==3.17.9
Werkzeug==3.1.3
WTForms==3.2.1
diff --git a/templates/login.html b/templates/login.html
new file mode 100644
index 0000000..3a46511
--- /dev/null
+++ b/templates/login.html
@@ -0,0 +1,24 @@
+{% extends "base.html" %}
+
+{% block content %}
+<h1>Welcome to VibeEngine</h1>
+<form action="" method="post" novalidate>
+ {{ form.hidden_tag() }}
+ <p>
+ {{ form.username.label }}<br>
+ {{ form.username(size=32) }}<br>
+ {% for error in form.username.errors %}
+ <span style="color: peru;">[{{ error }}]</span>
+ {% endfor %}
+ </p>
+ <p>
+ {{ form.password.label }}<br>
+ {{ form.password(size=32) }}<br>
+ {% for error in form.password.errors %}
+ <span style="color: peru;">[{{ error }}]</span>
+ {% endfor %}
+ </p>
+ <p>{{ form.remember_me() }} {{ form.remember_me.label }}</p>
+ <p>{{ form.submit() }}</p>
+</form>
+{% endblock %} \ No newline at end of file
diff --git a/templates/post.html b/templates/post.html
index 8272d37..d759da4 100644
--- a/templates/post.html
+++ b/templates/post.html
@@ -1,8 +1,24 @@
{% extends 'base.html' %}
{% block content %}
- <h2>{{ post.title }}</h2>
- <p>{{ post.created_at.strftime('%Y-%m-%d %H:%M') }}</p>
- <div>{{ post.content|markdown|safe }}</div>
+{% if post.parent != 0 %}
+<a href="{{url_for('post', post_id=post.parent)}}"> Previous</a>
+<hr>
+{% endif %}
+<h2>{{ post.title }}</h2>
+<p>{{ post.created_at.strftime('%Y-%m-%d %H:%M') }}</p>
+<p> Authour: {{post.authour.name}}</p>
+<div>{{ post.content|markdown|safe }}</div>
+<div class="post-actions">
+ <a href="{{ url_for('create', reply=post.id)}}"> Reply</a> ~
<a href="{{ url_for('index') }}">Back to posts</a>
-{% endblock %}
+</div>
+<hr>
+<h3> Replies to this</h3>
+<div class="post-replies">
+ <ul>
+ <li> {% for reply in replies %} <a href="{{ url_for('post', post_id=reply.id) }}">{{ reply.title }}</a> - {{
+ reply.created_at.strftime('%Y-%m-%d') }}</li> {% endfor %}
+ </ul>
+</div>
+{% endblock %} \ No newline at end of file