Skip to content

Commit

Permalink
Improve front-end (#6)
Browse files Browse the repository at this point in the history
* Initial front-end

* Remove unnecessary form.submit()

* Little Fixes

* Overhaul wind, clouds displaying

* Fix url for airport page in favorite airports

* Move redundant code outside of a function

* Revert "Move redundant code outside of a function"

This reverts commit d0dcee1.

* Add airport name search

* Add airport name filter

* Add edge cases handling for lists in index.html

* Add 404 and 500 .html

* Add custom error handlers

* Add correct descriptions

* Add error 476

* Add metar error handling

* Move favicon to external server

* Move error image to external site

* Add image handlers

* Close #5

* Add reset_password sites layouts and some global fixes

* Move error pages to their own directory

* Add "forgot the password" button in login.html

* Last fixes

* Add new favicon

* Button bugfixes

Co-authored-by: DayWD <[email protected]>
Co-authored-by: Artur Michałek <[email protected]>
  • Loading branch information
3 people authored May 27, 2021
1 parent bc84646 commit f77eecf
Show file tree
Hide file tree
Showing 39 changed files with 967 additions and 230 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
venv/
__pycache__/

.idea
htmlcov
.coverage

Expand Down
6 changes: 6 additions & 0 deletions avw/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
from flask_caching import Cache
from config import Config
from elasticsearch import Elasticsearch
from flask_bootstrap import Bootstrap


db = SQLAlchemy()
login_manager = LoginManager()
mail = Mail()
cache = Cache(config={'CACHE_TYPE': 'SimpleCache'})
bootstrap = Bootstrap()


def create_app(config=Config):
Expand All @@ -24,6 +26,7 @@ def create_app(config=Config):
login_manager.init_app(app)
mail.init_app(app)
cache.init_app(app)
bootstrap.init_app(app)

es_url = app.config.get('ELASTICSEARCH_URL')
if es_url is not None:
Expand All @@ -37,6 +40,9 @@ def create_app(config=Config):

from avw.airport import bp as airport_bp
app.register_blueprint(airport_bp)

from avw.errors import bp as error_bp
app.register_blueprint(error_bp)

return app

Expand Down
3 changes: 2 additions & 1 deletion avw/airport/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

bp = Blueprint('airport', __name__)

from avw.airport import routes
from avw.airport import filters
from avw.airport import routes
15 changes: 15 additions & 0 deletions avw/airport/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from avw.airport import bp


@bp.app_template_filter()
def decode_clouds(code):
d = {
'FEW': 'Few',
'SCT': 'Scattered',
'BKN': 'Broken',
'OVC': 'Overcast',
'CLR': 'Clear',
'CAVOK': 'Clear'
}
print(code)
return d.get(code, code)
2 changes: 1 addition & 1 deletion avw/airport/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def airport(code):
preferences = {}

if metar['errors'] is not None:
abort(500)
return redirect(url_for('errors.no_metar_for_this_airport_error'))
if current_user.is_authenticated:
in_favorites = True if code in current_user.get_favorite_airports() \
else False
Expand Down
2 changes: 1 addition & 1 deletion avw/auth/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def login():
user = User.query.filter_by(username=form.username.data).first()
if user is not None and user.validate_password(form.password.data):
login_user(user)
flash(f'Succesfully logged in user {user}')
# flash(f'Succesfully logged in user {current_user.username}')
next = request.args.get('next', 'main.index')
return redirect(url_for(next))
flash('Invalid login or password')
Expand Down
11 changes: 9 additions & 2 deletions avw/email.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from avw.models import User
from flask import current_app, render_template
from flask_mailman import EmailMessage
from threading import Thread


def send_reset_password_email(email: str) -> None:
user = User.query.filter_by(email=email).first()
Expand All @@ -13,5 +15,10 @@ def send_reset_password_email(email: str) -> None:
from_email='[email protected]',
body=render_template('mail/reset_password.html', token=token)
)
with current_app.app_context():
msg.send()
Thread(target=send_email, args=[
current_app._get_current_object(), msg]).start()


def send_email(app_object, email: EmailMessage):
with app_object.app_context():
email.send()
5 changes: 5 additions & 0 deletions avw/errors/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from flask import Blueprint

bp = Blueprint('errors', __name__)

from avw.errors import routes
21 changes: 21 additions & 0 deletions avw/errors/routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from avw.errors import bp
from flask import render_template, current_app
from os import environ


@bp.app_errorhandler(404)
def not_found_error(error):
img = environ.get('ERROR_IMG')
return render_template('errors/404.html', img=img), 404


@bp.app_errorhandler(500)
def internal_server_error(error):
img = environ.get('ERROR_IMG')
return render_template('errors/500.html', img=img), 500


@bp.route('/476', methods=('GET',))
def no_metar_for_this_airport_error():
img = environ.get('476_IMG')
return render_template('errors/476.html', img=img), 476
3 changes: 2 additions & 1 deletion avw/main/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

bp = Blueprint('main', __name__)

from avw.main import routes
from avw.main import filters
from avw.main import routes
7 changes: 7 additions & 0 deletions avw/main/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from avw.main import bp
from avw.search import get_airport_name


@bp.app_template_filter('airport_name')
def airport_name(code):
return get_airport_name(code) or code
5 changes: 5 additions & 0 deletions avw/main/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,8 @@ def search(code):
title=f'Search results for {code}',
results=results)
return redirect(url_for('main.index'))

# @bp.route('/favicon.ico')
# def favicon():
# return send_from_directory(os.path.join(current_app.root_path, 'static'),
# 'favicon.ico', mimetype='image/vnd.microsoft.icon')
28 changes: 26 additions & 2 deletions avw/search.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from flask import current_app
from collections import OrderedDict
from elasticsearch import TransportError


Expand Down Expand Up @@ -30,9 +29,34 @@ def search_airport(name) -> list:
}
}
)
except TransportError as e:
except TransportError:
return None
if q['timed_out'] is False and q['hits']['total']['value'] > 0:
return sorted(q['hits']['hits'], key=lambda k: k['_score'], reverse=True)
else:
return None


def get_airport_name(code: str) -> str:
if getattr(current_app, 'elasticsearch', None) is None:
return None
try:
q: dict = current_app.elasticsearch.search(
index=current_app.config['SEARCH_INDEX_NAME'],
body={
'query': {
'term': {
'ident': {
'value': code,
'case_insensitive': True
}
}
}
}
)
except TransportError:
return None
if q['timed_out'] is False and q['hits']['total']['value'] > 0:
return q['hits']['hits'][0]['_source']['name']
else:
return None
3 changes: 3 additions & 0 deletions avw/static/airport_template.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
tbody#airport td {
vertical-align: middle;
}
Binary file added avw/static/change_pass_icon.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added avw/static/favicon.ico
Binary file not shown.
62 changes: 62 additions & 0 deletions avw/static/favorite_button.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
.button {
background: rgb(117, 242, 231);
background: linear-gradient(180deg, rgba(117, 242, 231, 1) 0%, rgba(58, 143, 225, 1) 80%);
border-radius: 20px;
border: none;
color: white;
padding: 10px 18px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 15px;
margin: 2px 1px;
cursor: pointer;
transition: all 0.3s;
}

.login_button {
background: rgb(58, 143, 225);
background: linear-gradient(180deg, rgba(58, 143, 225, 1) 1%, rgba(117, 242, 231, 1) 100%);
border-radius: 20px;
border: none;
color: white;
padding: 10px 18px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 15px;
margin: 2px 1px;
cursor: pointer;
transition: all 0.3s;
}

.list_fav {
background: rgb(117, 242, 231);
background: linear-gradient(180deg, rgba(117, 242, 231, 1) 0%, rgba(58, 143, 225, 1) 84%);
border: black;
}

.button span {
cursor: pointer;
display: inline-block;
position: relative;
transition: 0.5s;
}

.button span:after {
content: '\00bb';
position: absolute;
opacity: 0;
top: 0;
right: -20px;
transition: 0.5s;
}

.button:hover span {
padding-right: 25px;
}

.button:hover span:after {
opacity: 1;
right: 0;
}
51 changes: 51 additions & 0 deletions avw/static/login_template.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.pass {
width: 22%;
padding: 8px 20px;
border-radius: 20px;
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
display: inline-block;
border: 1px solid #ccc;
box-sizing: border-box;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='50px' width='200px'><text x='20' y='22' fill='gray' font-size='16'>Password</text></svg>");
background-repeat: no-repeat;
outline: none;
}

.login {
width: 22%;
padding: 8px 20px;
border-radius: 20px;
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
display: inline-block;
border: 1px solid #ccc;
box-sizing: border-box;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='50px' width='200px'><text x='20' y='22' fill='gray' font-size='16'>Login</text></svg>");
background-repeat: no-repeat;
outline: none;
}

input:valid {
background-image: none;
}

input:focus {
background-image: none;
}

::-webkit-input-placeholder { /* Chrome/Opera/Safari */
color: transparent;
}

::-moz-placeholder { /* Firefox 19+ */
color: transparent;
}

:-ms-input-placeholder { /* IE 10+ */
color: transparent;
}

:-moz-placeholder { /* Firefox 18- */
color: transparent;
}
Binary file added avw/static/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added avw/static/logo_sun.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added avw/static/register.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit f77eecf

Please sign in to comment.