Skip to content

Commit 5b0afdf

Browse files
committed
add flash messages to replace error pages
1 parent ae9072e commit 5b0afdf

12 files changed

Lines changed: 240 additions & 192 deletions

core/routes.py

Lines changed: 58 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,22 @@
55

66
import brawlstats
77
from sanic import Blueprint, response
8+
from sanic.exceptions import abort
89

9-
from core.utils import disable_xss, login_required, open_db_connection, render_template
10+
from core.utils import add_message, disable_xss, login_required, open_db_connection, render_template
1011
from core.utils import daterange, thisweek
1112

1213
root = Blueprint('root')
1314

15+
@root.middleware('request')
16+
async def setup_session_dict(request):
17+
"""Sets up session attributes if they do not exist already"""
18+
if request.ctx.session.get('logged_in', None) is None:
19+
request.ctx.session['logged_in'] = False
20+
21+
if request.ctx.session.get('messages', None) is None:
22+
request.ctx.session['messages'] = []
23+
1424
@root.get('/')
1525
async def index(request):
1626
async with request.app.session.get('https://api.github.com/users/SharpBit/events/public') as resp:
@@ -29,7 +39,7 @@ async def repo(request, name):
2939

3040
@root.get('/login')
3141
async def login(request):
32-
if request.ctx.session.get('logged_in'):
42+
if request.ctx.session['logged_in']:
3343
return response.redirect('/')
3444
return response.redirect(request.app.oauth.discord_login_url)
3545

@@ -89,24 +99,32 @@ async def url_shortener_home(request):
8999
async def create_url(request):
90100
chars = string.ascii_letters + string.digits
91101
code = ''.join(random.choice(chars) for i in range(8))
92-
url = request.form['url'][0]
102+
try:
103+
url = request.form['url'][0]
104+
except KeyError:
105+
return add_message(request, 'error', 'Enter a URL to redirect to.', '/urlshortener')
93106
account = request.ctx.session.get('id', 'no_account')
94107

95108
async with open_db_connection(request.app) as conn:
96109
if request.form.get('code'):
97110
code = request.form['code'][0]
98111
existing = await conn.fetchrow('SELECT * FROM urls WHERE code = $1', code)
99112
if existing:
100-
return response.text('Error: Code already exists')
113+
return add_message(request, 'error', 'That code is already taken. Try another one.', '/urlshortener')
101114
await conn.execute('INSERT INTO urls(user_id, code, url) VALUES ($1, $2, $3)', account, code, url)
102-
return response.text(f'Here is your shortened URL: https://{request.app.config.DOMAIN}/{code}')
115+
return add_message(
116+
request,
117+
'success',
118+
f'Shortened URL created at <a href="https://{request.app.config.DOMAIN}/{code}">https://{request.app.config.DOMAIN}/{code}</a>',
119+
'/urlshortener'
120+
)
103121

104122
@root.get('/<code>')
105123
async def existing_code(request, code):
106124
async with open_db_connection(request.app) as conn:
107125
res = await conn.fetchrow('SELECT * FROM urls WHERE code = $1', code)
108126
if not res:
109-
return response.text(f'No such URL shortener code "{code}" found.')
127+
abort(404, message=f'Requested URL {request.path} not found')
110128
return response.redirect(res['url'])
111129

112130
@root.get('/pastebin')
@@ -118,7 +136,10 @@ async def pastebin_home(request):
118136
async def create_pastebin(request):
119137
chars = string.ascii_letters + string.digits
120138
code = ''.join(random.choice(chars) for i in range(8))
121-
text = request.form['text'][0]
139+
try:
140+
text = request.form['text'][0]
141+
except KeyError:
142+
return add_message(request, 'error', 'Paste some code in to save.', '/pastebin')
122143
account = request.ctx.session.get('id', 'no_account')
123144
async with open_db_connection(request.app) as conn:
124145
await conn.execute('INSERT INTO pastebin(user_id, code, text) VALUES ($1, $2, $3)', account, code, text)
@@ -129,7 +150,7 @@ async def existing_pastebin(request, code):
129150
async with open_db_connection(request.app) as conn:
130151
res = await conn.fetchrow('SELECT * FROM pastebin WHERE code = $1', code)
131152
if not res:
132-
return response.text(f'No such pastebin code "{code}" found.')
153+
abort(404, message=f'Requested URL {request.path} not found')
133154
text = disable_xss(res['text'])
134155
return await render_template('saved_pastebin', request, title="Pastebin - Saved", description="Saved Pastebin", code=text)
135156

@@ -145,17 +166,16 @@ async def challenge_home(request):
145166
@root.post('/challenges/post')
146167
async def challenge_post(request):
147168
try:
148-
tag = brawlstats.utils.bstag(request.form['tag'][0])
169+
form_tag = request.form['tag'][0]
170+
except KeyError:
171+
return add_message(request, 'error', 'Enter a player tag.', '/challenges')
172+
173+
try:
174+
tag = brawlstats.utils.bstag(form_tag)
149175
except brawlstats.NotFoundError as e:
150-
invalid_chars = e.error.split('\n')
151-
invalid_chars = invalid_chars[len(invalid_chars) - 1]
152-
return await render_template(
153-
template='challenge_home',
154-
request=request,
155-
invalid_chars=invalid_chars,
156-
title='Brawl Stars Challenges',
157-
description='Search up your tag to view the logs of your Brawl Stars challenge games.'
158-
)
176+
invalid_chars = e.message.split('\n')
177+
invalid_chars = invalid_chars[-1]
178+
return add_message(request, 'error', invalid_chars, '/challenges')
159179
return response.redirect(f'/challenges/{tag}')
160180

161181
@root.get('/challenges/<tag>')
@@ -164,14 +184,7 @@ async def challenge_stats(request, tag):
164184
try:
165185
logs = await client.get_battle_logs(tag)
166186
except brawlstats.NotFoundError:
167-
return await render_template(
168-
'challenge_stats',
169-
request,
170-
tag_found=False,
171-
entered_tag=disable_xss(tag.upper()),
172-
title='Brawl Stars Challenges',
173-
description='View the logs of your Brawl Stars challenge games.'
174-
)
187+
return add_message(request, 'error', f'Tag {disable_xss(tag.upper())} was not found.', '/challenges')
175188

176189
event_map = {
177190
'gemGrab': 'Gem Grab',
@@ -200,15 +213,7 @@ def filter_challenge_games(battle):
200213
games = list(filter(filter_challenge_games, logs))[::-1]
201214

202215
if len(games) == 0:
203-
return await render_template(
204-
template='challenge_stats',
205-
request=request,
206-
tag_found=True,
207-
games=[],
208-
len=len,
209-
title='Brawl Stars Challenges',
210-
description='View the logs of your Brawl Stars challenge games.'
211-
)
216+
return add_message(request, 'error', 'No recent challenge games were found.', '/challenges')
212217

213218
battlelog = []
214219
for battle in games:
@@ -229,10 +234,8 @@ def filter_challenge_games(battle):
229234
return await render_template(
230235
template='challenge_stats',
231236
request=request,
232-
tag_found=True,
233237
games=battlelog,
234238
brawler_key={'EL PRIMO': 'El-Primo', 'MR. P': 'Mr.P'},
235-
len=len, # allow len() to be called in the template
236239
title='Brawl Stars Challenges',
237240
description='View the logs of your Brawl Stars challenge games.'
238241
)
@@ -247,8 +250,6 @@ async def brawlstats_tests_proxy(request, endpoint):
247250
'Authorization': f'Bearer {request.token}',
248251
'Accept-Encoding': 'gzip'
249252
}
250-
print(headers)
251-
print(f'https://api.brawlstars.com/v1/{endpoint}')
252253
try:
253254
async with app.session.get(f'https://api.brawlstars.com/v1/{endpoint}', timeout=30, headers=headers) as resp:
254255
return response.json(await resp.json(), status=resp.status)
@@ -339,7 +340,24 @@ async def schoolweek(request, requested_date_str):
339340
template='schoolweek',
340341
request=request,
341342
week=week_fmt,
342-
title='School Week',
343343
requested_date=requested_date,
344+
title='School Week',
344345
description='This week\'s maroon and gray A and B days.'
345346
)
347+
348+
349+
@root.post('/schoolweek/subscribe')
350+
# @authorized()
351+
async def email_subscribe(request):
352+
try:
353+
email = request.form['email'][0]
354+
except KeyError:
355+
return add_message(request, 'error', 'Enter an email in the field.', '/schoolweek')
356+
357+
async with open_db_connection(request.app) as conn:
358+
existing = await conn.fetchrow('SELECT * FROM mailing_list WHERE email = $1', email)
359+
if existing:
360+
return add_message(request, 'error', 'Email already subscribed.', '/schoolweek')
361+
await conn.execute('INSERT INTO mailing_list(email) VALUES ($1)', email)
362+
363+
return add_message(request, 'success', 'Your email has been added to the mailing list.', '/schoolweek')

core/static/style.css

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
src: url('/static/fonts/LilitaOne-Regular.ttf');
44
}
55

6-
h1, h2, h3, h4, h5, h6 {
6+
h1, h2, h3, h4, h5, h6, p, tr, td, input, a, button, .label{
77
font-family: 'Lato';
88
}
99

@@ -48,12 +48,35 @@ h1, h2, h3, h4, h5, h6 {
4848
padding-right: 20px;
4949
padding-bottom: 0px;
5050
padding-left: 20px;
51-
border: 2px solid #28a745;
51+
border-width: 1px;
52+
border-style: solid;
53+
border-color: #28a745;
5254
border-radius: 3px;
5355
margin-bottom: 20px;
5456
max-width: 640px;
5557
}
5658

59+
.flash {
60+
padding-top: 10px;
61+
padding-bottom: 10px;
62+
}
63+
64+
.flash p {
65+
margin-bottom: 0px; /*Override the margin-bottom of 20px in content-section*/
66+
}
67+
68+
.flash-success {
69+
border: 1px solid #a3c293;
70+
color: #6b8c5c;
71+
background-color: #fcfff5;
72+
}
73+
74+
.flash-error {
75+
border: 1px solid #e0b4b4;
76+
color: #b7638a;
77+
background-color: #fff6f6;
78+
}
79+
5780
.battle-victory {
5881
color: #28a745;
5982
padding-top: 10px;

core/templates/challenge_home.html

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
11
{% extends "layout.html" %}
22
{% block content %}
3-
<div class="container">
4-
<div class="info" style="padding-top:20px;padding-bottom:10px">
5-
<h1 style="font-family: 'LilitaOne'">Brawl Stars Challenges</h1>
6-
<h5 style="font-family: 'LilitaOne'">This includes the Championship Challenge, the PSG challenge, and any other future challenges.</h5>
7-
<h5 style="font-family: 'LilitaOne'">Your challenge games must be in your battlelog (last 25 games) for this to work.</h5>
8-
</div>
9-
<div class="form-items" style="max-width: 700px;">
10-
<form class="form" method="POST" action="/challenges/post">
11-
<div class="form-group">
12-
<label class="label" for="tag" style="font-family: 'LilitaOne'">Tag</label>
13-
{% if invalid_chars %}
14-
<br />
15-
<h7 style="font-family: 'LilitaOne';color: #C73930"">{{ invalid_chars }}</h7>
16-
{% endif %}
17-
<input name="tag" type="tag" class="form-control" id="tag" placeholder="Enter tag here"></input>
18-
</div>
19-
<button type="submit" class="btn btn-success">Submit</button>
20-
</form>
21-
</div>
3+
<div class="info" style="padding-top:20px;padding-bottom:10px">
4+
<h1 style="font-family: 'LilitaOne'">Brawl Stars Challenges</h1>
5+
<h5 style="font-family: 'LilitaOne'">This includes the Championship Challenge, the PSG challenge, and any other future challenges.</h5>
6+
<h5 style="font-family: 'LilitaOne'">Your challenge games must be in your battlelog (last 25 games) for this to work.</h5>
7+
</div>
8+
<div class="form-items" style="max-width: 700px;">
9+
<form class="form" method="POST" action="/challenges/post">
10+
<div class="form-group">
11+
<label class="label" for="tag" style="font-family: 'LilitaOne'">Tag</label>
12+
<input name="tag" type="tag" class="form-control" id="tag" placeholder="Enter tag here"></input>
13+
</div>
14+
<button type="submit" class="btn btn-success">Submit</button>
15+
</form>
2216
</div>
2317
{% endblock content %}
Lines changed: 20 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,24 @@
11
{% extends "layout.html" %}
22
{% block content %}
3-
<div class="container">
4-
<div class="info" style="padding-top:20px;padding-bottom:10px">
5-
<h1 style="font-family: 'LilitaOne'">BS Challenges</h1>
6-
<h5 style="font-family: 'LilitaOne'">Your challenge games must be in your battlelog (last 25 games) for this to work.</h5>
7-
</div>
8-
<div class="battlelog">
9-
<h4 style="font-family: 'LilitaOne'">Challenge games</h4>
10-
{% if not tag_found %}
11-
<h7 style="font-family: 'LilitaOne';color: #C73930">Tag #{{ entered_tag }} was not found.</h7>
12-
{% else %}
13-
{% if len(games) == 0 %}
14-
<h7 style="font-family: 'LilitaOne';color: #C73930">No recent challenge games were found.</h7>
15-
{% else %}
16-
{% for battle in games %}
17-
<div class="battle-{{ battle.result.lower() }}">
18-
<img src="https://starlist.pro/assets/gamemode/{{ battle.event.replace(' ', '-') }}.png?v=1" height="25" width="25"></img>
19-
<h7>{{ battle.event }} - {{ battle.map }} ({{ battle.result }})</h7><br />
20-
{% for team in battle.teams %}
21-
<div class="team" style="padding: 5px">
22-
{% for player in team %}
23-
<h7 class="player-{{ player.star_player }}">{{ player.name }}</h7>
24-
<img src="https://starlist.pro/assets/brawler-bs/{{ brawler_key.get(player.brawler.name, player.brawler.name.title()) }}.png?v=2" height="20" width="20"></img>
25-
{% endfor %}
26-
</div>
27-
{% endfor %}
28-
</div>
29-
{% endfor %}
30-
{% endif %}
31-
{% endif %}
32-
</div>
3+
<div class="info" style="padding-top:20px;padding-bottom:10px">
4+
<h1 style="font-family: 'LilitaOne'">BS Challenges</h1>
5+
<h5 style="font-family: 'LilitaOne'">Your challenge games must be in your battlelog (last 25 games) for this to work.</h5>
6+
</div>
7+
<div class="battlelog">
8+
<h4 style="font-family: 'LilitaOne'">Challenge games</h4>
9+
{% for battle in games %}
10+
<div class="battle-{{ battle.result.lower() }}">
11+
<img src="https://starlist.pro/assets/gamemode/{{ battle.event.replace(' ', '-') }}.png?v=1" height="25" width="25"></img>
12+
<p>{{ battle.event }} - {{ battle.map }} ({{ battle.result }})</p><br />
13+
{% for team in battle.teams %}
14+
<div class="team" style="padding: 5px">
15+
{% for player in team %}
16+
<p class="player-{{ player.star_player }}">{{ player.name }}</p>
17+
<img src="https://starlist.pro/assets/brawler-bs/{{ brawler_key.get(player.brawler.name, player.brawler.name.title()) }}.png?v=2" height="20" width="20"></img>
18+
{% endfor %}
19+
</div>
20+
{% endfor %}
21+
</div>
22+
{% endfor %}
3323
</div>
3424
{% endblock content %}

core/templates/dashboard.html

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
{% extends "layout.html" %}
22
{% block content %}
3-
<div class="container">
4-
<h1 style="padding-top:20px">Dashboard</h1>
5-
<div class="content-section" style="border:1px solid #28a745;padding-bottom:20px">
6-
<h3>Shortened URLs</h3>
7-
{% for url in urls %}
8-
<a href="{{ url.url }}">https://sharpbit.dev/{{ url.code }}</a><br />
9-
{% endfor %}
10-
</div>
11-
<div class="content-section" style="border:1px solid #28a745;padding-bottom:20px">
12-
<h3>Pastebins</h3>
13-
{% for p in pastes %}
14-
<a href="https://sharpbit.dev/pastebin/{{ p.code }}">https://sharpbit.dev/pastebin/{{ p.code }}</a><br />
15-
{% endfor %}
16-
</div>
3+
<h1 style="padding-top:20px">Dashboard</h1>
4+
<div class="content-section" style="padding-bottom:20px">
5+
<h3>Shortened URLs</h3>
6+
{% for url in urls %}
7+
<a href="{{ url.url }}">https://sharpbit.dev/{{ url.code }}</a><br />
8+
{% endfor %}
9+
</div>
10+
<div class="content-section" style="padding-bottom:20px">
11+
<h3>Pastebins</h3>
12+
{% for p in pastes %}
13+
<a href="https://sharpbit.dev/pastebin/{{ p.code }}">https://sharpbit.dev/pastebin/{{ p.code }}</a><br />
14+
{% endfor %}
1715
</div>
1816
{% endblock content %}

0 commit comments

Comments
 (0)