diasporadiaries

a platform for writing stories with personal accounts and messages
git clone git://parazyd.org/diasporadiaries.git
Log | Files | Refs | Submodules | README | LICENSE

commit 9be8a1f54657852b316ae536a75bfd0a8c808aa2
parent 6fb63b1614bea44befce80b6d6ca72c1b0f859f2
Author: parazyd <parazyd@dyne.org>
Date:   Sun, 20 Jan 2019 18:45:59 +0100

Add support for user list and profiles.

Diffstat:
Mdb.py | 36+++++++++++++-----------------------
Mdiaspora.py | 46+++++++++++++++++++++++++++++++++++++++-------
Mstatic/css/diaspora.css | 2--
Mtemplates/edit.html | 2+-
Mtemplates/nav.html | 6++++++
Atemplates/users.html | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mutils.py | 22++++++++++++++++++----
7 files changed, 134 insertions(+), 37 deletions(-)

diff --git a/db.py b/db.py @@ -37,8 +37,7 @@ def initdb(dbpath): password text NOT NULL, cap integer NOT NULL, first_seen integer NOT NULL, - is_active integer NOT NULL, - is_authed integer NOT NULL + is_active integer NOT NULL ); ''' @@ -71,7 +70,9 @@ def sql_select_col_where(col0, col1, val, table='stories'): """ Queries col0 where col1 = val. """ - db.execute("SELECT %s FROM %s WHERE %s = '%s';" % (col0, table, col1, val)) + db.execute(""" + SELECT %s FROM %s WHERE %s = '%s'; + """ % (col0, table, col1, val)) return db.fetchall() @@ -101,23 +102,12 @@ def sql_update_row_where(vals, col, val, table='stories'): vals is a list of tuples. """ - length = len(vals) - 1 - valstring = '' - for i, j in enumerate(vals): - if not isinstance(j[1], int): - valstring += "%s = '%s'" % (j[0], j[1].replace("'", "''")) - else: - valstring += "%s = '%s'" % (j[0], j[1]) - if i < length: - valstring += ', ' - - print(valstring) - - db.execute(""" - UPDATE %s - SET %s - WHERE %s = '%s'; - """ % (table, valstring, col, val)) + for i in vals: + db.execute(""" + UPDATE %s + SET %s = ? + WHERE %s = ?; + """ % (table, i[0], col), (i[1], val)) dbctx.commit() @@ -135,13 +125,13 @@ def sql_insert(args): ); """, (args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10])) - elif len(args) == 8: + elif len(args) == 7: # User db.execute(""" INSERT INTO users VALUES ( - ?, ?, ?, ?, ?, ?, ?, ? + ?, ?, ?, ?, ?, ?, ? ); """, (args[0], args[1], args[2], args[3], args[4], args[5], - args[6], args[7])) + args[6])) dbctx.commit() diff --git a/diaspora.py b/diaspora.py @@ -22,6 +22,7 @@ from argparse import ArgumentParser from random import choice from time import time +from bcrypt import hashpw, gensalt from flask import Markup, Flask, render_template, request, url_for, redirect from flask_login import (LoginManager, UserMixin, login_required, login_user, logout_user, current_user) @@ -31,7 +32,7 @@ from db import (sql_delete_row_where, sql_update_row_where, sql_insert, from utils import (get_story, makenav, randomstring, getcountryname, get_multiple_stories, get_multiple_stories_filtered, make_profile, find_user_by_id, find_user_by_email, - validate_user) + validate_user, get_multiple_users) app = Flask(__name__) @@ -50,7 +51,7 @@ class LoginUser(UserMixin): # TODO: Find out if it's possible to do less SQL queries. def __init__(self, uid): """ Init """ - self.uid = uid + self.id = uid @property def username(self): @@ -74,7 +75,7 @@ class LoginUser(UserMixin): def get_user(self): """ Get user struct """ - return find_user_by_id(self.uid) + return find_user_by_id(self.id) @login_manager.user_loader @@ -265,9 +266,11 @@ def profile(): email = sql_select_col_where('email', 'id', uid, table='users') if email: email = email[0][0] - stories = get_multiple_stories('email', email) - name = stories[0]['name'] - return render_template('profile.html', stories=stories, name=name) + stories = get_multiple_stories_filtered('email', email, + ('visible', 1)) + if stories: + name = stories[0]['name'] + return render_template('profile.html', stories=stories, name=name) return render_template('fail_profile.html') @@ -283,7 +286,6 @@ def dashboard(): fparam = {'pending': 0, 'posted': 1} - add_id = request.args.get('approveid') if add_id: sql_update_row_where([('visible', 1)], 'id', add_id) @@ -300,6 +302,36 @@ def dashboard(): return render_template('dashboard.html', stories=stories) +@app.route('/users', methods=['GET', 'POST']) +#@login_required +def users(): + """ + Route for users view. + """ + #if not current_user.is_admin: + # return render_template('fail_permissions.html') + + if request.method == 'POST': + vals = [] + if request.form['password']: + vals.append(('password', + hashpw(request.form['password'].encode(), + gensalt()))) + if request.form['cap']: + vals.append(('cap', request.form['cap'])) + + if vals: + sql_update_row_where(vals, 'id', request.form['id'], table='users') + + print(vals) + + if request.args.get('delid'): + sql_delete_row_where('id', request.args.get('delid'), table='users') + + users = get_multiple_users('is_active', 1) + return render_template('users.html', users=users) + + @app.route('/') def main(): """ diff --git a/static/css/diaspora.css b/static/css/diaspora.css @@ -126,5 +126,3 @@ nav { .countrylist-bottom a { text-decoration: none; } - - diff --git a/templates/edit.html b/templates/edit.html @@ -21,7 +21,7 @@ <main role="main" class="container"> <p> - <a href="/delete?key={{ story['deletekey'] }}" class="btn btn-danger">Delete this story</a> + <a href="/delete?key={{ story['deletekey'] }}" class="btn btn-outline-danger">Delete this story</a> </p> <form action="/edit" method="POST" id="storyform"> diff --git a/templates/nav.html b/templates/nav.html @@ -49,10 +49,16 @@ <a class="dropdown-item" href="/dashboard?list=posted"> <span class="fa fa-envelope-open"></span> Posted stories </a> + <a class="dropdown-item" href="/users"> + <span class="fa fa-user-circle"></span> Users + </a> </div> </li> {% endif %} <li class="nav-item"> + <a class="nav-link" href="/profile?id={{ current_user.id }}">Profile</a> + </li> + <li class="nav-item"> <a class="nav-link" href="/logout">Logout</a> </li> {% else %} diff --git a/templates/users.html b/templates/users.html @@ -0,0 +1,57 @@ +{% include 'header.html' %} + + <title>Users | Diaspora Diaries</title> + +{% include 'nav.html' %} + + <main role="main" class="container-fluid"> + + <h1 class="cover-heading">Users</h1> + + <table class="table"> + <thead> + <tr> + <th scope="col">#</th> + <th scope="col">Name</th> + <th scope="col">Email</th> + <th scope="col">Password</th> + <th scope="col">Cap</th> + <th scope="col">First seen</th> + <th scope="col">Apply</th> + <th scope="col">Delete</th> + </tr> + </thead> + <tbody> + {% for i in users %} + <tr> + <th scope="row"> + <form action="/users" method="POST" id="form_{{ i['id'] }}"> + <input type="hidden" name="id" value="{{ i['id'] }}"> + </form> + {{ i['id'] }} + </th> + <td> + <a href="/profile?id={{ i['id'] }}">{{ i['name'] }}</a> + </td> + <td>{{ i['email'] }}</td> + <td><input form="form_{{ i['id'] }}" type="text" name="password" placeholder="New password"></td> + <td><input form="form_{{ i['id'] }}" type="text" name="cap" placeholder="{{ i['cap'] }} (0=writer, 2=admin)"></td> + <td>{{ i['first_seen'] }}</td> + <td> + <button type="submit" form="form_{{ i['id'] }}" class="btn btn-outline-success"> + <span class="fa fa-check"></span> + </button> + </td> + <td> + <a href="/users?delid={{ i['id'] }}" class="btn btn-outline-danger"> + <span class="fa fa-times"></span> + </a> + </td> + </tr> + {% endfor %} + </tbody> + </table> + + </main> + +{% include 'footer.html' %} diff --git a/utils.py b/utils.py @@ -120,6 +120,22 @@ def get_multiple_stories_filtered(col, val, param, reverse=True): return filtered_stories +def get_multiple_users(col, val, reverse=False): + """ + Returns a list of users where col=val. + """ + rows = sql_select_col_where('*', col, val, table='users') + + users = [] + for i in rows: + j = fill_user_dict(i) + users.append(j) + + if reverse: + return users[::-1] + return users + + def makenav(randomize=False): """ Queries the disembark column for filling up the by-country dropdown @@ -146,9 +162,8 @@ def fill_user_dict(row): 'name': row[2], 'password': row[3], 'cap': row[4], - 'first_seen': row[5], + 'first_seen': strftime('%d.%m.%Y. %H:%M UTC', gmtime(row[5])), 'is_active': row[6], - 'is_authed': row[7], } @@ -201,10 +216,9 @@ def make_profile(name, email): email, name, password, - 0, + 2, int(time()), 1, - 0, ] sql_insert(userargs)