initial commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.pyc
|
||||
106
app.py
Normal file
106
app.py
Normal file
@@ -0,0 +1,106 @@
|
||||
from flask import Flask, session, url_for, redirect, render_template, request, abort, flash
|
||||
from database import list_users, verify, delete_user_from_db, add_user
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_object('config')
|
||||
|
||||
|
||||
|
||||
@app.errorhandler(401)
|
||||
def FUN_401(error):
|
||||
return render_template("page_401.html"), 401
|
||||
|
||||
@app.errorhandler(404)
|
||||
def FUN_404(error):
|
||||
return render_template("page_404.html"), 404
|
||||
|
||||
@app.errorhandler(405)
|
||||
def FUN_405(error):
|
||||
return render_template("page_405.html"), 405
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def FUN_root():
|
||||
return render_template("index.html")
|
||||
|
||||
@app.route("/public/")
|
||||
def FUN_public():
|
||||
return render_template("public_page.html")
|
||||
|
||||
@app.route("/private/")
|
||||
def FUN_private():
|
||||
if "current_user" in session.keys():
|
||||
return render_template("private_page.html")
|
||||
else:
|
||||
return abort(401)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@app.route("/admin/")
|
||||
def FUN_admin():
|
||||
if session.get("current_user", None) == "ADMIN":
|
||||
user_list = list_users()
|
||||
user_table = zip(range(1, len(user_list)+1),\
|
||||
user_list,\
|
||||
[x + y for x,y in zip(["/delete_user/"] * len(user_list), user_list)])
|
||||
return render_template("admin.html", users = user_table)
|
||||
else:
|
||||
return abort(401)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@app.route("/login", methods = ["POST"])
|
||||
def FUN_login():
|
||||
id_submitted = request.form.get("id").upper()
|
||||
if (id_submitted in list_users()) and verify(id_submitted, request.form.get("pw")):
|
||||
session['current_user'] = id_submitted
|
||||
|
||||
return(redirect(url_for("FUN_root")))
|
||||
|
||||
@app.route("/logout/")
|
||||
def FUN_logout():
|
||||
session.pop("current_user", None)
|
||||
return(redirect(url_for("FUN_root")))
|
||||
|
||||
@app.route("/delete_user/<id>/", methods = ['GET'])
|
||||
def FUN_delete_user(id):
|
||||
if session.get("current_user", None) == "ADMIN":
|
||||
if id == "ADMIN": # ADMIN account can't be deleted.
|
||||
return abort(403)
|
||||
delete_user_from_db(id)
|
||||
return(redirect(url_for("FUN_admin")))
|
||||
else:
|
||||
return abort(401)
|
||||
|
||||
@app.route("/add_user", methods = ["POST"])
|
||||
def FUN_add_user():
|
||||
if session.get("current_user", None) == "ADMIN":
|
||||
|
||||
# before we add the user, we need to ensure this is doesn't exsit in database.
|
||||
if request.form.get('id').upper() in list_users():
|
||||
user_list = list_users()
|
||||
user_table = zip(range(1, len(user_list)+1),\
|
||||
user_list,\
|
||||
[x + y for x,y in zip(["/delete_user/"] * len(user_list), user_list)])
|
||||
return(render_template("admin.html", id_is_duplicated = True, users = user_table))
|
||||
else:
|
||||
add_user(request.form.get('id'), request.form.get('pw'))
|
||||
return(redirect(url_for("FUN_admin")))
|
||||
else:
|
||||
return abort(401)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(debug=True, port = 9000, host="0.0.0.0")
|
||||
51
database.py
Normal file
51
database.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import sqlite3
|
||||
import hashlib
|
||||
|
||||
db_file_location = "database_file/users.db"
|
||||
|
||||
def list_users():
|
||||
_conn = sqlite3.connect(db_file_location)
|
||||
_c = _conn.cursor()
|
||||
|
||||
_c.execute("select id from users;")
|
||||
result = [x[0] for x in _c.fetchall()]
|
||||
|
||||
_conn.close()
|
||||
|
||||
return result
|
||||
|
||||
def verify(id, pw):
|
||||
_conn = sqlite3.connect(db_file_location)
|
||||
_c = _conn.cursor()
|
||||
|
||||
_c.execute("select pw from users where id = '" + id + "';")
|
||||
result = _c.fetchone()[0] == hashlib.sha256(pw).hexdigest()
|
||||
|
||||
_conn.close()
|
||||
|
||||
return result
|
||||
|
||||
def delete_user_from_db(id):
|
||||
_conn = sqlite3.connect(db_file_location)
|
||||
_c = _conn.cursor()
|
||||
|
||||
_c.execute("delete from users where id = '" + id + "';")
|
||||
|
||||
_conn.commit()
|
||||
_conn.close()
|
||||
|
||||
def add_user(id, pw):
|
||||
_conn = sqlite3.connect(db_file_location)
|
||||
_c = _conn.cursor()
|
||||
|
||||
command = "insert into users values('" + id.upper() + "', '" + hashlib.sha256(pw).hexdigest() + "');"
|
||||
_c.execute(command)
|
||||
|
||||
_conn.commit()
|
||||
_conn.close()
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print list_users()
|
||||
BIN
database_file/users.db
Normal file
BIN
database_file/users.db
Normal file
Binary file not shown.
6
static/css/bootstrap.min.css
vendored
Executable file
6
static/css/bootstrap.min.css
vendored
Executable file
File diff suppressed because one or more lines are too long
BIN
static/img/flask-powered.png
Executable file
BIN
static/img/flask-powered.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
64
templates/admin.html
Normal file
64
templates/admin.html
Normal file
@@ -0,0 +1,64 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block page_title %}Admin Dashboard{% endblock %}
|
||||
{% block body %}
|
||||
{{ super() }}
|
||||
|
||||
{% if id_is_duplicated %}
|
||||
<div class="text-danger">
|
||||
<strong>Warning!</strong> The account name already exists.
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class = "container">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-lg-6">
|
||||
<h3>Add Account</h3>
|
||||
|
||||
<form class="form-inline" action="/add_user" method='post'>
|
||||
<div class="form-group">
|
||||
<label for="id">ID</label>
|
||||
<input type="text" class="form-control" name="id">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="pw">Password</label>
|
||||
<input type="password" class="form-control" name="pw">
|
||||
</div>
|
||||
<br><br>
|
||||
<button type="submit" class="btn">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
<h3>Manage Existing Accounts</h3>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>ID</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for number, id, act in users %}
|
||||
<tr>
|
||||
<th> {{ number }} </th>
|
||||
<td> {{ id }} </td>
|
||||
<td><a href={{act}}>Delete</a></td>
|
||||
</tr>
|
||||
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
8
templates/index.html
Normal file
8
templates/index.html
Normal file
@@ -0,0 +1,8 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block page_title %}Welcome to Flask Example{% endblock %}
|
||||
{% block body %}
|
||||
{{ super() }}
|
||||
|
||||
<p>In this example, we cover concepts including: </p>
|
||||
<p>template (inheritance), URL building, redirecting, error handeling, session management (authentication), etc.</p>
|
||||
{% endblock %}
|
||||
63
templates/layout.html
Normal file
63
templates/layout.html
Normal file
@@ -0,0 +1,63 @@
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}">
|
||||
<title>Flask Example</title>
|
||||
<nav class="navbar navbar-inverse">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="/">Flask Example</a>
|
||||
</div>
|
||||
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/public/">Public</a></li>
|
||||
<li><a href="/private/">Private</a></li>
|
||||
<li><a href="/admin">Admin Dashboard</a></li>
|
||||
</ul>
|
||||
|
||||
{% if session.get("current_user", None) == None %}
|
||||
<div id="navbar" class="navbar-collapse collapse">
|
||||
<form action="/login" method="post" class="navbar-form navbar-right">
|
||||
<div class="form-group">
|
||||
<input type="text" name="id" placeholder="User Name" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" name="pw" placeholder="Password" class="form-control">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success">Log In</button>
|
||||
</form>
|
||||
</div>
|
||||
{% else %}
|
||||
<a href="/logout" class="navbar-form navbar-right"> Logout </a>
|
||||
<a class="navbar-form navbar-right">{{ session.get("current_user") }}</a>
|
||||
|
||||
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
||||
<div class="container">
|
||||
|
||||
<h1>{% block page_title %}{% endblock %}</h1>
|
||||
|
||||
<p>{% block body %}{% endblock %}</p>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class='container'>
|
||||
<hr>
|
||||
<a href="http://flask.pocoo.org/"><img
|
||||
src="{{ url_for('static', filename='img/flask-powered.png') }}"
|
||||
border="0"
|
||||
alt="Flask powered"
|
||||
title="Flask powered"></a>
|
||||
|
||||
Developed by <a href='https://github.com/XD-DENG'>XD-DENG</a>
|
||||
</div>
|
||||
|
||||
|
||||
</html>
|
||||
6
templates/page_401.html
Normal file
6
templates/page_401.html
Normal file
@@ -0,0 +1,6 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block page_title %}Unauthorized(401){% endblock %}
|
||||
{% block body %}
|
||||
{{ super() }}
|
||||
You're not allowed to access.
|
||||
{% endblock %}
|
||||
6
templates/page_404.html
Normal file
6
templates/page_404.html
Normal file
@@ -0,0 +1,6 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block page_title %}Not Found (404){% endblock %}
|
||||
{% block body %}
|
||||
{{ super() }}
|
||||
The resource can not be found.
|
||||
{% endblock %}
|
||||
6
templates/page_405.html
Normal file
6
templates/page_405.html
Normal file
@@ -0,0 +1,6 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block page_title %}Method not allowd (405){% endblock %}
|
||||
{% block body %}
|
||||
{{ super() }}
|
||||
The method of your request is not allowed.
|
||||
{% endblock %}
|
||||
6
templates/private_page.html
Normal file
6
templates/private_page.html
Normal file
@@ -0,0 +1,6 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block page_title %}Private Page{% endblock %}
|
||||
{% block body %}
|
||||
{{ super() }}
|
||||
Only logged-in users, like you, can access this page.
|
||||
{% endblock %}
|
||||
6
templates/public_page.html
Normal file
6
templates/public_page.html
Normal file
@@ -0,0 +1,6 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block page_title %}Public Page{% endblock %}
|
||||
{% block body %}
|
||||
{{ super() }}
|
||||
You can access this no matter whether you have logged in.
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user