Initial Commit
- Basic accounts system
This commit is contained in:
commit
16bf449dff
10 changed files with 401 additions and 0 deletions
41
Tweeder.py
Normal file
41
Tweeder.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
from flask import Flask, render_template, request
|
||||
from backend import accounts
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def hello_world():
|
||||
return render_template("index.html")
|
||||
|
||||
|
||||
@app.route('/login', methods=['POST'])
|
||||
def login():
|
||||
|
||||
username = request.form['username']
|
||||
password = request.form['password']
|
||||
|
||||
login_attempt = accounts.login(username, password)
|
||||
return render_template('status.html',
|
||||
title_status=login_attempt['status'].title(),
|
||||
status=login_attempt['status'],
|
||||
message=login_attempt['message'])
|
||||
|
||||
|
||||
@app.route('/register', methods=['POST'])
|
||||
def register():
|
||||
|
||||
username = request.form['username']
|
||||
email = request.form['email']
|
||||
password = request.form['password']
|
||||
confirm_password = request.form['confirm-password']
|
||||
|
||||
if password == confirm_password:
|
||||
register_attempt = accounts.create_account(email, username, password)
|
||||
return register_attempt['message']
|
||||
else:
|
||||
return "Passwords do not match!"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
111
backend/accounts.py
Normal file
111
backend/accounts.py
Normal file
|
@ -0,0 +1,111 @@
|
|||
from pymongo import MongoClient
|
||||
# import json
|
||||
import bcrypt
|
||||
|
||||
# try:
|
||||
# with open('config.json') as f:
|
||||
# config = json.loads(f.read())
|
||||
# except FileNotFounddanger:
|
||||
# print("Config file does not exist!",
|
||||
# "Please copy and configure config.local.json to config.json in the root directory.")
|
||||
# exit()
|
||||
# client = MongoClient(config['database'])
|
||||
|
||||
|
||||
client = MongoClient()
|
||||
accounts_db = client.tweeder.accounts
|
||||
|
||||
|
||||
def create_account(email, username, password):
|
||||
|
||||
displayname = username
|
||||
username = username.lower()
|
||||
|
||||
if accounts_db.find_one({'username': username}):
|
||||
|
||||
return {
|
||||
'status': 'danger',
|
||||
'code': 1,
|
||||
'message': 'Username already exists!'
|
||||
}
|
||||
|
||||
elif accounts_db.find_one({'email': email}):
|
||||
|
||||
return {
|
||||
'status': 'danger',
|
||||
'code': 2,
|
||||
'message': 'Email address already in use!'
|
||||
}
|
||||
|
||||
elif email == "":
|
||||
return {
|
||||
'status': 'danger',
|
||||
'code': 3,
|
||||
'message': 'Email address cannot be blank!'
|
||||
}
|
||||
|
||||
elif username == "":
|
||||
return {
|
||||
'status': 'danger',
|
||||
'code': 4,
|
||||
'message': "Username cannot be blank!"
|
||||
}
|
||||
|
||||
elif password == "":
|
||||
return {
|
||||
'status': 'danger',
|
||||
'code': 5,
|
||||
'message': 'Password cannot be blank!'
|
||||
}
|
||||
|
||||
else:
|
||||
hashed_password = bcrypt.hashpw(str.encode(password), bcrypt.gensalt(14))
|
||||
accounts_db.insert_one({
|
||||
'username': username,
|
||||
'displayname': displayname,
|
||||
'email': email,
|
||||
'password': hashed_password
|
||||
})
|
||||
|
||||
return {
|
||||
'status': 'success',
|
||||
'code': 0,
|
||||
'message': 'Account created!'
|
||||
}
|
||||
|
||||
|
||||
def login(username, password):
|
||||
|
||||
username = username.lower()
|
||||
|
||||
# Check that account exists, either with username or email based login
|
||||
if accounts_db.find_one({'username': username}):
|
||||
account_document = accounts_db.find_one({'username': username})
|
||||
elif accounts_db.find_one({'email': username}):
|
||||
account_document = accounts_db.find_one({'email': username})
|
||||
else:
|
||||
|
||||
return {
|
||||
'status': 'danger',
|
||||
'code': 1,
|
||||
'message': 'Account does not exist!'
|
||||
}
|
||||
|
||||
# Do login stuff
|
||||
hashed_password = account_document['password']
|
||||
if hashed_password == bcrypt.hashpw(str.encode(password), hashed_password):
|
||||
|
||||
return {
|
||||
'status': 'success',
|
||||
'code': 0,
|
||||
'message': 'Logged in!'
|
||||
}
|
||||
|
||||
else:
|
||||
|
||||
return {
|
||||
'status': 'danger',
|
||||
'code': 2,
|
||||
'message': 'Incorrect password'
|
||||
}
|
||||
|
3
config.json
Normal file
3
config.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"database": "mongodb://localhost:27017/"
|
||||
}
|
6
static/bootstrap.min.css
vendored
Normal file
6
static/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
7
static/bootstrap.min.js
vendored
Normal file
7
static/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
99
static/index.css
Normal file
99
static/index.css
Normal file
|
@ -0,0 +1,99 @@
|
|||
body {
|
||||
padding-top: 90px;
|
||||
}
|
||||
.panel-login {
|
||||
border-color: #ccc;
|
||||
-webkit-box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.2);
|
||||
-moz-box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.2);
|
||||
box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.2);
|
||||
}
|
||||
.panel-login>.panel-heading {
|
||||
color: #00415d;
|
||||
background-color: #fff;
|
||||
border-color: #fff;
|
||||
text-align:center;
|
||||
}
|
||||
.panel-login>.panel-heading a{
|
||||
text-decoration: none;
|
||||
color: #666;
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
-webkit-transition: all 0.1s linear;
|
||||
-moz-transition: all 0.1s linear;
|
||||
transition: all 0.1s linear;
|
||||
}
|
||||
.panel-login>.panel-heading a.active{
|
||||
color: #029f5b;
|
||||
font-size: 18px;
|
||||
}
|
||||
.panel-login>.panel-heading hr{
|
||||
margin-top: 10px;
|
||||
margin-bottom: 0px;
|
||||
clear: both;
|
||||
border: 0;
|
||||
height: 1px;
|
||||
background-image: -webkit-linear-gradient(left,rgba(0, 0, 0, 0),rgba(0, 0, 0, 0.15),rgba(0, 0, 0, 0));
|
||||
background-image: -moz-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0));
|
||||
background-image: -ms-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0));
|
||||
background-image: -o-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0));
|
||||
}
|
||||
.panel-login input[type="text"],.panel-login input[type="email"],.panel-login input[type="password"] {
|
||||
height: 45px;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 16px;
|
||||
-webkit-transition: all 0.1s linear;
|
||||
-moz-transition: all 0.1s linear;
|
||||
transition: all 0.1s linear;
|
||||
}
|
||||
.panel-login input:hover,
|
||||
.panel-login input:focus {
|
||||
outline:none;
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
border-color: #ccc;
|
||||
}
|
||||
.btn-login {
|
||||
background-color: #59B2E0;
|
||||
outline: none;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
height: auto;
|
||||
font-weight: normal;
|
||||
padding: 14px 0;
|
||||
text-transform: uppercase;
|
||||
border-color: #59B2E6;
|
||||
}
|
||||
.btn-login:hover,
|
||||
.btn-login:focus {
|
||||
color: #fff;
|
||||
background-color: #53A3CD;
|
||||
border-color: #53A3CD;
|
||||
}
|
||||
.forgot-password {
|
||||
text-decoration: underline;
|
||||
color: #888;
|
||||
}
|
||||
.forgot-password:hover,
|
||||
.forgot-password:focus {
|
||||
text-decoration: underline;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.btn-register {
|
||||
background-color: #1CB94E;
|
||||
outline: none;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
height: auto;
|
||||
font-weight: normal;
|
||||
padding: 14px 0;
|
||||
text-transform: uppercase;
|
||||
border-color: #1CB94A;
|
||||
}
|
||||
.btn-register:hover,
|
||||
.btn-register:focus {
|
||||
color: #fff;
|
||||
background-color: #1CA347;
|
||||
border-color: #1CA347;
|
||||
}
|
26
static/index.js
Normal file
26
static/index.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
$(function() {
|
||||
|
||||
$('#login-form-link').click(function(e) {
|
||||
$("#login-form").delay(100).fadeIn(100);
|
||||
$("#register-form").fadeOut(100);
|
||||
$('#register-form-link').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
e.preventDefault();
|
||||
});
|
||||
$('#register-form-link').click(function(e) {
|
||||
$("#register-form").delay(100).fadeIn(100);
|
||||
$("#login-form").fadeOut(100);
|
||||
$('#login-form-link').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function check(input) {
|
||||
if (input.value != document.getElementById('password').value) {
|
||||
input.setCustomValidity('Password Must be Matching.');
|
||||
} else {
|
||||
// input is valid -- reset the error message
|
||||
input.setCustomValidity('');
|
||||
}}
|
4
static/jquery-3.2.1.min.js
vendored
Normal file
4
static/jquery-3.2.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
91
templates/index.html
Normal file
91
templates/index.html
Normal file
|
@ -0,0 +1,91 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename = 'bootstrap.min.css') }}" />
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename = 'index.css') }}" />
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<title>Welcome to Tweeder!</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
<div class="panel panel-login">
|
||||
<div class="panel-heading">
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<a href="#" id="login-form-link">Login</a>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<a href="#" class="active" id="register-form-link">Register</a>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<form id="login-form" action="login" method="POST" role="form" style="display: none;">
|
||||
<div class="form-group">
|
||||
<input type="text" name="username" id="username" tabindex="1" class="form-control" placeholder="Username or email address" value="">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" name="password" id="password" tabindex="2" class="form-control" placeholder="Password">
|
||||
</div>
|
||||
<div class="form-group text-center">
|
||||
<input type="checkbox" tabindex="3" class="" name="remember" id="remember">
|
||||
<label for="remember"> Remember Me</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-sm-offset-3">
|
||||
<input type="submit" name="login-submit" id="login-submit" tabindex="4" class="form-control btn btn-login" value="Log In">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="text-center">
|
||||
<a href="/recover" tabindex="5" class="forgot-password">Forgot Password?</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<form id="register-form" action="/register" method="POST" role="form" style="display: block;">
|
||||
<div class="form-group">
|
||||
<input type="text" name="username" id="username" tabindex="1" class="form-control" placeholder="Username" value="">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="email" name="email" id="email" tabindex="1" class="form-control" placeholder="Email Address" value="">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" name="password" id="password" tabindex="2" class="form-control" placeholder="Password">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" name="confirm-password" id="confirm-password" tabindex="2" class="form-control" placeholder="Confirm Password" oninput="check(this)">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-sm-offset-3">
|
||||
<input type="submit" name="register-submit" id="register-submit" tabindex="4" class="form-control btn btn-register" value="Register Now">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="{{ url_for('static', filename = 'jquery-3.2.1.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename = 'bootstrap.min.js') }}" ></script>
|
||||
<script src="{{ url_for('static', filename = 'index.js') }}" ></script>
|
||||
</body>
|
||||
</html>
|
13
templates/status.html
Normal file
13
templates/status.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename = 'bootstrap.min.css') }}" />
|
||||
<meta charset="UTF-8">
|
||||
<title>{{ title_status }}! - Tweeder</title>
|
||||
</head>
|
||||
<body style="padding-top: 90px;">
|
||||
<div class="container">
|
||||
<div class="alert alert-{{ status }}" role="alert">{{ message }}</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Reference in a new issue