Browse Source

implement login

feature_tests
Burathar 4 years ago
parent
commit
1de0ef561d
  1. 3
      app/__init__.py
  2. 22
      app/forms.py
  3. 28
      app/models.py
  4. 38
      app/routes.py
  5. 19
      app/templates/base.html
  6. 36
      app/templates/index.html
  7. 14
      app/templates/login.html
  8. 11
      app/templates/register.html
  9. 28
      migrations/versions/01c009738a1f_update_to_1_3.py

3
app/__init__.py

@ -3,11 +3,14 @@ from flask_bootstrap import Bootstrap
from config import Config from config import Config
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate from flask_migrate import Migrate
from flask_login import LoginManager
app = Flask(__name__) app = Flask(__name__)
app.config.from_object(Config) app.config.from_object(Config)
bootstrap = Bootstrap(app) bootstrap = Bootstrap(app)
db = SQLAlchemy(app) db = SQLAlchemy(app)
migrate = Migrate(app, db) migrate = Migrate(app, db)
login = LoginManager(app)
login.login_view = 'login'
from app import routes, models from app import routes, models

22
app/forms.py

@ -0,0 +1,22 @@
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField, TextAreaField
from wtforms.validators import DataRequired, EqualTo, ValidationError, Length
from app.models import Player
class LoginForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired()])
remember_me = BooleanField('Remember Me', default=True)
submit = SubmitField('Sign In')
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=0, max=64)])
password = PasswordField('Password', validators=[DataRequired(), Length(min=0, max=128)])
password2 = PasswordField(
'Repeat Password', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Register')
def validate_username(self, username):
player = Player.query.filter_by(name=username.data).first()
if player is not None:
raise ValidationError('Please use a different username.')

28
app/models.py

@ -1,5 +1,8 @@
from app import app, db from werkzeug.security import generate_password_hash, check_password_hash
from app import app, db, login
from sqlalchemy.sql import func from sqlalchemy.sql import func
from secrets import token_hex
from flask_login import UserMixin
game_player = db.Table('game_player', game_player = db.Table('game_player',
db.Column('game_id', db.Integer, db.ForeignKey('game.id'), nullable=False), db.Column('game_id', db.Integer, db.ForeignKey('game.id'), nullable=False),
@ -9,9 +12,9 @@ game_player = db.Table('game_player',
) )
player_found_objective = db.Table('player_found_objective', player_found_objective = db.Table('player_found_objective',
db.Column('game_id', db.Integer, db.ForeignKey('game.id'), nullable=False), db.Column('objective_id', db.Integer, db.ForeignKey('objective.id'), nullable=False, server_default='-1'),
db.Column('player_id', db.Integer, db.ForeignKey('player.id'), nullable=False), db.Column('player_id', db.Integer, db.ForeignKey('player.id'), nullable=False, server_default='-1'),
db.PrimaryKeyConstraint('game_id', 'player_id'), db.PrimaryKeyConstraint('objective_id', 'player_id'),
db.Column('timestamp', db.DateTime, server_default=func.now(), nullable=False) db.Column('timestamp', db.DateTime, server_default=func.now(), nullable=False)
) )
@ -49,11 +52,11 @@ class Game(db.Model):
lazy='select', lazy='select',
backref=db.backref('game', lazy='joined')) backref=db.backref('game', lazy='joined'))
class Player(db.Model): class Player(UserMixin, db.Model):
__tablename__ = 'player' __tablename__ = 'player'
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True, nullable=False) name = db.Column(db.String(64), unique=True, nullable=False)
auth_hash = db.Column(db.String(128), unique=True, nullable=True) auth_hash = db.Column(db.String(32), unique=True, nullable=True)
password_hash = db.Column(db.String(128)) password_hash = db.Column(db.String(128))
games = db.relationship( games = db.relationship(
'Game', 'Game',
@ -78,6 +81,19 @@ class Player(db.Model):
secondary=notification_player, secondary=notification_player,
back_populates='recipients') back_populates='recipients')
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def set_auth_hash(self):
self.auth_hash = token_hex(16)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
@login.user_loader
def load_user(id):
return Player.query.get(int(id))
class Objective(db.Model): class Objective(db.Model):
__tablename__ = 'objective' __tablename__ = 'objective'
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)

38
app/routes.py

@ -1,11 +1,45 @@
from flask import render_template, flash, redirect, url_for, request from flask import render_template, flash, redirect, url_for, request
from flask_login import login_user, logout_user, current_user, login_required
from app import app, db from app import app, db
#from app.forms import - from app.models import Player, Game
from app.forms import LoginForm, RegistrationForm
@app.route('/', methods=['GET']) @app.route('/', methods=['GET'])
@app.route('/index', methods=['GET']) @app.route('/index', methods=['GET'])
@login_required
def index(): def index():
message="Hello, World" message="Hello, World"
return render_template("index.html", title='Home', message=message) return render_template("index.html", title='Home', message=message)
#@app.route('/game/<game_name>/leader') @app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = LoginForm()
if form.validate_on_submit():
player = Player.query.filter_by(name=form.username.data).first()
if player is None or not player.check_password(form.password.data):
flash('Invalid username or password')
return redirect(url_for('login'))
login_user(player, remember=form.remember_me.data)
return redirect(url_for('index'))
return render_template('login.html', title='Sign In', form=form)
@app.route('/logout')
def logout():
logout_user()
return redirect(url_for('index'))
@app.route('/register', methods=['GET', 'POST'])
def register():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = RegistrationForm()
if form.validate_on_submit():
player = Player(name=form.username.data)
player.set_password(form.password.data)
db.session.add(player)
db.session.commit()
flash('Congratulations, you are now a registered user!')
return redirect(url_for('login'))
return render_template('register.html', title='Register', form=form)

19
app/templates/base.html

@ -1,7 +1,7 @@
{% extends 'bootstrap/base.html' %} {% extends 'bootstrap/base.html' %}
{% block title %} {% block title %}
{% if title %}{{ title }} - Microblog{% else %}Welcome to Microblog{% endif %} {% if title %}{{ title }} - The Hunt{% else %}Welcome to The Hunt{% endif %}
{% endblock %} {% endblock %}
{% block navbar %} {% block navbar %}
@ -14,14 +14,18 @@
<span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
</button> </button>
<a class="navbar-brand" href="{{ url_for('index') }}">Microblog</a> <a class="navbar-brand" href="{{ url_for('index') }}">The Hunt</a>
</div> </div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li><a href="{{ url_for('index') }}">Home</a></li> <li><a href="{{ url_for('index') }}">Home</a></li>
</ul> </ul>
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li><p>Logout</p></li> {% if current_user.is_anonymous %}
<li><a href="{{ url_for('login') }}">Login</a></li>
{% else %}
<li><a href="{{ url_for('logout') }}">Logout</a></li>
{% endif %}
</ul> </ul>
</div> </div>
</div> </div>
@ -30,6 +34,15 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<div class="alert alert-info" role="alert">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
{# application content needs to be provided in the app_content block #}
{% block app_content %}{% endblock %} {% block app_content %}{% endblock %}
</div> </div>
{% endblock %} {% endblock %}

36
app/templates/index.html

@ -1,8 +1,40 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block app_content %} {% block app_content %}
<h1>Hi, {{ current_user.name }}!</h1>
<h1>Welcome!</h1>
<h2>{{ message }}</h2> <h2>{{ message }}</h2>
<h2>My games:</h2>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">State</th>
<th scope="col">Start Time</th>
<th scope="col">End Time</th>
<th scope="col">My Role</th>
</tr>
</thead>
<tbody>
<tr>
<td>Gamename</td>
<td>Running</td>
<td>yesterday</td>
<td>tomorrow</td>
<td>bitch</td>
</tr>
{% for game in current_user.games %}
<tr>
<td>{{ game.name }}</td>
<td>{{ game.state }}</td>
<td>{{ game.start_time }}</td>
<td>{{ game.end_time }}</td>
<td>bitch</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %} {% endblock %}

14
app/templates/login.html

@ -0,0 +1,14 @@
{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block app_content %}
<h1>Sign In</h1>
<div class="row">
<div class="col-md-4">
{{ wtf.quick_form(form) }}
</div>
</div>
<br>
<p>New User? <a href="{{ url_for('register') }}">Click to Register!</a></p>
{% endblock %}

11
app/templates/register.html

@ -0,0 +1,11 @@
{% extends "base.html" %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block app_content %}
<h1>Register</h1>
<div class="row">
<div class="col-md-4">
{{ wtf.quick_form(form) }}
</div>
</div>
{% endblock %}

28
migrations/versions/b98d6f905471_update_up_to_1_3.py → migrations/versions/01c009738a1f_update_to_1_3.py

@ -1,8 +1,8 @@
"""update up to 1.3 """update to 1.3
Revision ID: b98d6f905471 Revision ID: 01c009738a1f
Revises: Revises:
Create Date: 2020-07-03 11:23:06.765509 Create Date: 2020-07-03 13:12:00.463246
""" """
from alembic import op from alembic import op
@ -10,7 +10,7 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'b98d6f905471' revision = '01c009738a1f'
down_revision = None down_revision = None
branch_labels = None branch_labels = None
depends_on = None depends_on = None
@ -30,7 +30,7 @@ def upgrade():
op.create_table('player', op.create_table('player',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=64), nullable=False), sa.Column('name', sa.String(length=64), nullable=False),
sa.Column('auth_hash', sa.String(length=128), nullable=True), sa.Column('auth_hash', sa.String(length=32), nullable=True),
sa.Column('password_hash', sa.String(length=128), nullable=True), sa.Column('password_hash', sa.String(length=128), nullable=True),
sa.PrimaryKeyConstraint('id'), sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('auth_hash'), sa.UniqueConstraint('auth_hash'),
@ -82,14 +82,6 @@ def upgrade():
sa.ForeignKeyConstraint(['caught_player_id'], ['player.id'], ), sa.ForeignKeyConstraint(['caught_player_id'], ['player.id'], ),
sa.UniqueConstraint('photo_reference') sa.UniqueConstraint('photo_reference')
) )
op.create_table('player_found_objective',
sa.Column('game_id', sa.Integer(), nullable=False),
sa.Column('player_id', sa.Integer(), nullable=False),
sa.Column('timestamp', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=False),
sa.ForeignKeyConstraint(['game_id'], ['game.id'], ),
sa.ForeignKeyConstraint(['player_id'], ['player.id'], ),
sa.PrimaryKeyConstraint('game_id', 'player_id')
)
op.create_table('notification_player', op.create_table('notification_player',
sa.Column('notification_id', sa.Integer(), nullable=False), sa.Column('notification_id', sa.Integer(), nullable=False),
sa.Column('player_id', sa.Integer(), nullable=False), sa.Column('player_id', sa.Integer(), nullable=False),
@ -98,13 +90,21 @@ def upgrade():
sa.ForeignKeyConstraint(['player_id'], ['player.id'], ), sa.ForeignKeyConstraint(['player_id'], ['player.id'], ),
sa.PrimaryKeyConstraint('notification_id', 'player_id') sa.PrimaryKeyConstraint('notification_id', 'player_id')
) )
op.create_table('player_found_objective',
sa.Column('objective_id', sa.Integer(), server_default='-1', nullable=False),
sa.Column('player_id', sa.Integer(), server_default='-1', nullable=False),
sa.Column('timestamp', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=False),
sa.ForeignKeyConstraint(['objective_id'], ['objective.id'], ),
sa.ForeignKeyConstraint(['player_id'], ['player.id'], ),
sa.PrimaryKeyConstraint('objective_id', 'player_id')
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_table('notification_player')
op.drop_table('player_found_objective') op.drop_table('player_found_objective')
op.drop_table('notification_player')
op.drop_table('player_caught_player') op.drop_table('player_caught_player')
op.drop_table('objective') op.drop_table('objective')
op.drop_table('notification') op.drop_table('notification')
Loading…
Cancel
Save