add members

config file to enable/disable registration and other future admin settings
This commit is contained in:
cube
2026-03-16 13:11:56 +00:00
parent 2f499674ff
commit e3d6613bd4
10 changed files with 156 additions and 33 deletions

View File

@@ -7,4 +7,24 @@ flask app for plurals to publicly share member lists
- after cloning, run `py -3 -m venv .venv` in the root directory and then `.venv\Scripts\activate` - after cloning, run `py -3 -m venv .venv` in the root directory and then `.venv\Scripts\activate`
- then `pip install Flask` inside the virtual env - then `pip install Flask` inside the virtual env
- you might also need to init a database, so use `flask --app myriad init-db` - you might also need to init a database, so use `flask --app myriad init-db`
- to start the site use `flask --app myriad run --debug` - to start the site use `flask --app myriad run --debug`
# prod set up
- not ready yet
# config
- create `config.py` in the instance folder and customise the following settings to your needs
```
REGISTRATION: False # only set to True if in a development situation, or to create your first user
```
# usage
- the software here is free to use, and there's no requirement to link back
- edit the styles and functionality to suit your needs. i'm sure some of you out there are far better with CSS than I am
# dependencies
- Flask

View File

@@ -11,15 +11,11 @@ def create_app(test_config=None):
DATABASE=os.path.join(app.instance_path, 'database.sqlite'), DATABASE=os.path.join(app.instance_path, 'database.sqlite'),
) )
if test_config is None:
# load the instance config, if it exists, when not testing
app.config.from_pyfile('config.py', silent=True)
else:
# load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance folder exists # ensure the instance folder exists
os.makedirs(app.instance_path, exist_ok=True) os.makedirs(app.instance_path, exist_ok=True)
app.config.from_pyfile('config.py')
#print(app.config["REGISTRATION"])
from . import db from . import db
db.init_app(app) db.init_app(app)
@@ -31,4 +27,7 @@ def create_app(test_config=None):
app.register_blueprint(home.bp) app.register_blueprint(home.bp)
app.add_url_rule('/', endpoint='index') app.add_url_rule('/', endpoint='index')
from . import manage
app.register_blueprint(manage.bp)
return app return app

View File

@@ -1,7 +1,7 @@
import functools import functools
from flask import ( from flask import (
Blueprint, flash, g, redirect, render_template, request, session, url_for Blueprint, flash, g, redirect, render_template, request, session, url_for, current_app
) )
from werkzeug.security import check_password_hash, generate_password_hash from werkzeug.security import check_password_hash, generate_password_hash
@@ -9,8 +9,34 @@ from myriad.db import get_db
bp = Blueprint('auth', __name__, url_prefix='/auth') bp = Blueprint('auth', __name__, url_prefix='/auth')
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
@bp.before_app_request
def load_logged_in_user():
user_id = session.get('user_id')
if user_id is None:
g.user = None
else:
g.user = get_db().execute(
'SELECT * FROM user WHERE id = ?', (user_id,)
).fetchone()
@bp.route('/register', methods=('GET', 'POST')) @bp.route('/register', methods=('GET', 'POST'))
def register(): def register():
if current_app.config["REGISTRATION"] == False and g.user is None:
return redirect(url_for("index"))
if request.method == 'POST': if request.method == 'POST':
username = request.form['username'] username = request.form['username']
password = request.form['password'] password = request.form['password']
@@ -63,17 +89,6 @@ def login():
return render_template('auth/login.html') return render_template('auth/login.html')
@bp.before_app_request
def load_logged_in_user():
user_id = session.get('user_id')
if user_id is None:
g.user = None
else:
g.user = get_db().execute(
'SELECT * FROM user WHERE id = ?', (user_id,)
).fetchone()
@bp.route('/logout') @bp.route('/logout')
def logout(): def logout():
@@ -81,12 +96,3 @@ def logout():
return redirect(url_for('index')) return redirect(url_for('index'))
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

View File

@@ -16,4 +16,10 @@ def index():
# ' FROM post p JOIN user u ON p.author_id = u.id' # ' FROM post p JOIN user u ON p.author_id = u.id'
# ' ORDER BY created DESC' # ' ORDER BY created DESC'
# ).fetchall() # ).fetchall()
return render_template('index.html') return render_template('index.html')
@bp.route('/full')
def full_list():
db = get_db()
members = db.execute('SELECT * FROM member ORDER BY member_name').fetchall()
return render_template('full.html', memberlist=members)

36
myriad/manage.py Normal file
View File

@@ -0,0 +1,36 @@
from flask import (
Blueprint, flash, g, redirect, render_template, request, session, url_for
)
from myriad.auth import login_required
from myriad.db import get_db
bp = Blueprint('manage', __name__, url_prefix='/manage')
@bp.route('/new', methods=('GET', 'POST'))
@login_required
def new():
if request.method == 'POST':
name = request.form['name']
bio = request.form['bio']
#icon = request.form['icon']
user_id = g.user[0]
db = get_db()
error = None
if not name:
error = 'Name is required.'
if error is None:
db.execute(
"INSERT INTO member (user_id, member_name, bio) VALUES (?, ?, ?)",
(user_id, name, bio),
)
db.commit()
flash(error)
return redirect(url_for('home.full_list'))
return render_template('manage/new.html')

BIN
myriad/static/icons/any.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -29,6 +29,11 @@ form{
label,input{ label,input{
margin:10px; margin:10px;
} }
form textarea{
height:100px;
width:300px;
vertical-align: top;
}

View File

@@ -7,14 +7,25 @@
<div id="main"> <div id="main">
<div class="container" id="nav"> <div class="container" id="nav">
<div class="heading">myriad</div> <div class="heading">Myriad</div>
<div class="navitem">> <a href="{{ url_for('index') }}">Home</a></div> <div class="navitem">> <a href="{{ url_for('home.index') }}">Home</a></div>
<div class="navitem">> <a href="{{ url_for('home.full_list') }}">Full List</a></div>
{% if g.user %}
<div class="heading">Manage</div>
<div class="navitem">> <a href="{{ url_for('manage.new') }}">Add New</a></div>
{% endif %}
<div class="heading">Administration</div>
{% if g.user %} {% if g.user %}
<div class="navitem">> <a href="{{ url_for('auth.logout') }}">Log out</a></div> <div class="navitem">> <a href="{{ url_for('auth.logout') }}">Log out</a></div>
{% else %} {% else %}
<div class="navitem">> <a href="{{ url_for('auth.register') }}">Register</a></div> {% if config["REGISTRATION"] == True %}
<div class="navitem">> <a href="{{ url_for('auth.register') }}">Register</a></div>
{% endif %}
<div class="navitem">> <a href="{{ url_for('auth.login') }}">Log in</a></div> <div class="navitem">> <a href="{{ url_for('auth.login') }}">Log in</a></div>
{% endif %} {% endif %}
</div> </div>
<div class="container"> <div class="container">

View File

@@ -0,0 +1,25 @@
{% extends 'base.html' %}
{% block header %}
<div class="title">{% block title %}Full List{% endblock %}</div>
{% endblock %}
{% block content %}
{% for member in memberlist %}
<div class="profile">
<div class="heading"><b>{{ member[3] }}</b> {{ member[4] }}</div>
<img src="{{ url_for('static', filename='/icons/any.jpg') }}" class="icon">
<div class="bio">
{{ member[5] }}
</div>
<br class="clear" />
<!--<div class="heading links"><a href="/geo">my page</a> &#9734 tumblr &#9734</div>
<img src="/geo/dsgame.webp" class="dsgame">
<br class="clear" /> -->
</div>
{% endfor %}
{% endblock %}

View File

@@ -0,0 +1,15 @@
{% extends 'base.html' %}
{% block header %}
<div class="title">{% block title %}New{% endblock %}</div>
{% endblock %}
{% block content %}
<form method="post">
<label for="name">Name</label>
<input name="name" id="name" required><br>
<label for="bio">Description</label>
<textarea name="bio" id="bio"></textarea><br>
<input type="submit" value="Submit">
</form>
{% endblock %}