diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4119916 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +data +data.db diff --git a/Dockerfile b/Dockerfile index 3f2c87f..befc2f4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,6 +6,8 @@ COPY src /blog WORKDIR /blog +VOLUME /blog/data + RUN pip3 install -r requirements.txt VOLUME /blog/templates/entry diff --git a/README.md b/README.md index 482789c..b41a5a3 100644 --- a/README.md +++ b/README.md @@ -6,21 +6,21 @@ The blog is intended to be used to review and critique things. ## Features/To-Dos -- [ ] Accounts +- [x] Accounts - [x] Login - [x] Logout - - [ ] Register + - [x] Register - [ ] Review blog entries - - [ ] Writing entries + - [x] Writing entries - [ ] Editing entries - [ ] Deleting entries - [ ] Infinite-scroll blog page -- [ ] Archive page - - [ ] Months as headings - - [ ] Links to scrolling blog page - - [ ] Links to standalone article -- [ ] Standalone article page - - [ ] Links to scrolling blog page +- [x] Archive page + - [x] Months as headings + - [x] Links to scrolling blog page + - [x] Links to standalone article +- [x] Standalone article page + - [x] Links to scrolling blog page - [ ] RSS feed - [ ] Eye candy - [ ] Star rating @@ -58,9 +58,9 @@ Set the following volumes with the -v tag. | Volume-Name | Container mount | Description | | ------------- | ---------------------- | ---------------------------------- | -| `config-file` | `/blog/src/config.py` | Config file | -| `css` | `/blog/src/static/css` | (optional) Directory for css files | -| `html` | `/blog/src/templates` | (optional) Directory for templates | +| `config-file` | `/blog/config.py` | Config file | +| `data` | `/blog/data` | Directory for data | +| `css` | `/blog/static/css` | (optional) Directory for css files | #### Ports diff --git a/rebuild.sh b/rebuild.sh index 816ac62..24c20a1 100755 --- a/rebuild.sh +++ b/rebuild.sh @@ -6,4 +6,5 @@ docker run --name container-critique \ --restart unless-stopped \ -p "5000:5000" \ -e FLASK_ENV=development \ + -v data:/blog/data -d tiyn/container-critique diff --git a/src/app.py b/src/app.py index ab3ad17..2c3bf94 100644 --- a/src/app.py +++ b/src/app.py @@ -1,14 +1,21 @@ -from flask import Flask, flash, make_response, render_template, request, redirect, abort, url_for -from flask_login import current_user, login_user, LoginManager, logout_user +from flask import Flask, flash, make_response, render_template, redirect, \ + abort, url_for +from flask_login import current_user, login_user, LoginManager, logout_user, \ + login_required from flask_wtf import CSRFProtect +import os -import content as con_gen import config +import content as con_gen +from database import Database, User +from forms import LoginForm, RegisterForm, WriteForm app = Flask(__name__) csrf = CSRFProtect() -app.secret_key = "123534" +db = Database() + +app.secret_key = os.urandom(32) csrf.init_app(app) login = LoginManager(app) @@ -18,6 +25,8 @@ TITLE = config.TITLE STYLE = config.STYLE DESCRIPTION = config.DESCRIPTION WEBSITE = config.WEBSITE +REGISTER = config.REGISTER + @app.errorhandler(404) def page_not_found(e): @@ -38,9 +47,9 @@ def archive(): return render_template("archive.html", title=TITLE, content_string=content, style=STYLE) -@app.route("/entry/") -def entry(path): - content = con_gen.gen_stand_string(path) +@app.route("/entry/") +def entry(ident): + content = con_gen.gen_stand_string(ident) if content != "": return render_template("standalone.html", title=TITLE, content_string=content, style=STYLE) abort(404) @@ -56,18 +65,14 @@ def feed(): response.headers["Content-Type"] = "application/rss+xml" return response + @login.user_loader def load_user(ident): - ## TODO: load user from db by id - db_user = db.get_by_id(ident) + db_user = db.get_user_by_id(ident) if db_user is not None: return db.db_to_user(*db_user) return None -from login import LoginForm, User -from database import Database - -db = Database() @app.route("/login", methods=["GET", "POST"]) @app.route("/login.html", methods=["GET", "POST"]) @@ -76,22 +81,59 @@ def login(): return redirect(url_for("index")) form = LoginForm() if form.validate_on_submit(): - db_user = db.get_by_name(form.username.data) - if db_user is None: - flash("Invalid username or password") - return redirect(url_for("login")) - user = db.db_to_user(*db_user) - if 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) - return redirect(url_for("index")) + db_user = db.get_user_by_name(form.username.data) + if db_user is not None: + user = db.db_to_user(*db_user) + if user.check_password(form.password.data): + login_user(user) + return redirect(url_for("index")) + flash("Invalid username or password.") + return redirect(url_for("login")) return render_template("login.html", title=TITLE, form=form, style=STYLE) + @app.route('/logout') +@app.route('/logout.html') def logout(): logout_user() return redirect(url_for('index')) + +@app.route("/register", methods=["GET", "POST"]) +@app.route("/register.html", methods=["GET", "POST"]) +def register(): + if current_user.is_authenticated or not REGISTER: + return redirect(url_for("index")) + form = RegisterForm() + if form.validate_on_submit(): + if not REGISTER: + return redirect(url_for("index")) + db_user = db.get_user_by_name(form.username.data) + if db_user is None: + user = User(form.username.data) + user.set_password(form.password.data) + ident = db.insert_user(user) + if ident is not None: + user.set_id(ident) + login_user(user) + return redirect(url_for("index")) + flash("An error occured during registration.") + return redirect(url_for("register")) + return render_template("register.html", title=TITLE, form=form, style=STYLE) + + +@app.route("/write", methods=["GET", "POST"]) +@app.route("/write.html", methods=["GET", "POST"]) +@login_required +def write(): + if not current_user.is_authenticated: + return redirect(url_for("index")) + form = WriteForm() + if form.validate_on_submit(): + db.insert_entry(form.name.data, form.date.data, form.text.data, form.rating.data, current_user.id) + return redirect(url_for("index")) + return render_template("write.html", title=TITLE, form=form, style=STYLE) + + if __name__ == "__main__": app.run(host="0.0.0.0") diff --git a/src/config.py b/src/config.py index b21bbab..3821a0c 100644 --- a/src/config.py +++ b/src/config.py @@ -9,3 +9,6 @@ WEBSITE = "localhost:5000" # Theme for the blog: dark, light STYLE = "dark" + +# Allow new registrations +REGISTER = True diff --git a/src/content.py b/src/content.py index 458c6d2..4842c5a 100644 --- a/src/content.py +++ b/src/content.py @@ -1,3 +1,8 @@ +from database import Database + +db = Database() + + def gen_arch_string(): """ Creates and returns a archive string of every file in ENTRY_DIR. @@ -5,32 +10,100 @@ def gen_arch_string(): Returns: string: html-formatted archive-string """ - return "" + content_string = "" + last_year = "" + entries = db.get_entries() + if entries is None: + return "" + entries.sort(key=lambda y: y[2]) + for entry in entries: + ident = entry[0] + title = entry[1] + year = entry[2] + rating = entry[4] + if year != last_year: + if last_year != "": + content_string += "\n" + content_string += "

" + year + "

\n" + content_string += "