Initial Commit

- Basic accounts system
This commit is contained in:
Socks 2018-01-12 12:45:52 +00:00
commit 16bf449dff
10 changed files with 401 additions and 0 deletions

41
Tweeder.py Normal file
View 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
View 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
View file

@ -0,0 +1,3 @@
{
"database": "mongodb://localhost:27017/"
}

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

File diff suppressed because one or more lines are too long

99
static/index.css Normal file
View 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
View 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

File diff suppressed because one or more lines are too long

91
templates/index.html Normal file
View 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
View 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>