Skip to content

Commit 700092e

Browse files
committed
remove BS challenges
1 parent 3125536 commit 700092e

9 files changed

Lines changed: 65 additions & 228 deletions

File tree

.env.example

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ DB_USERNAME = # Postgresql Username
77
DB_PASSWORD = # Postgresql Password
88
DB_HOST = # Database host IP
99
DB_NAME = # Database name
10-
BRAWLSTATS_TOKEN = # API Key of the Brawl Stars API
1110
NOREPLY_EMAIL = # Actual gmail email
1211
CUSTOM_EMAIL = # Custom domain email to use
1312
NOREPLY_APP_PASSWORD = # 2fa app password

core/config.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
from dotenv import load_dotenv, find_dotenv
2+
from sanic.config import Config
23
import os
34

45
load_dotenv(find_dotenv('.env'))
56

67

7-
class Config:
8+
class SiteConfig(Config):
89
ENV = os.getenv('ENV')
910
DEV = ENV == 'development'
1011
DISCORD_CLIENT_ID = os.getenv('DISCORD_CLIENT_ID')
1112
DISCORD_CLIENT_SECRET = os.getenv('DISCORD_CLIENT_SECRET')
12-
AUTH = os.getenv('AUTH')
13-
PORT = int(os.getenv('PORT'))
13+
PORT = int(os.getenv('PORT', 4000))
1414
DOMAIN = 'sharpbit.dev' if not DEV else f'127.0.0.1:{PORT}'
1515
DB_USERNAME = os.getenv('DB_USERNAME')
1616
DB_PASSWORD = os.getenv('DB_PASSWORD')
1717
DB_NAME = os.getenv('DB_NAME')
1818
DB_HOST = os.getenv('DB_HOST')
19-
BRAWLSTATS_TOKEN = os.getenv('BRAWLSTATS_TOKEN')
2019
NOREPLY_EMAIL = os.getenv('NOREPLY_EMAIL')
2120
CUSTOM_EMAIL = os.getenv('CUSTOM_EMAIL')
2221
EMAIL_APP_PASSWORD = os.getenv('NOREPLY_APP_PASSWORD')

core/routes.py

Lines changed: 56 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@
66
from email.message import EmailMessage
77
from email.mime.text import MIMEText
88

9-
import brawlstats
109
from sanic import Blueprint, response
11-
from sanic.exceptions import abort
10+
from sanic.exceptions import Forbidden, NotFound, ServerError
11+
from sanic.request import Request
1212

1313
from core.utils import (add_message, disable_xss, get_school_week,
1414
login_required, open_db_connection, render_template)
1515

1616
root = Blueprint('root')
1717

1818
@root.middleware('request')
19-
async def setup_session_dict(request):
19+
async def setup_session_dict(request: Request):
2020
"""Sets up session attributes if they do not exist already"""
2121
if request.ctx.session.get('logged_in', None) is None:
2222
request.ctx.session['logged_in'] = False
@@ -25,46 +25,44 @@ async def setup_session_dict(request):
2525
request.ctx.session['messages'] = []
2626

2727
@root.get('/')
28-
async def index(request):
29-
async with request.app.session.get('https://api.github.com/users/SharpBit/events/public') as resp:
28+
async def index(request: Request):
29+
async with request.app.ctx.aiohttp.get('https://api.github.com/users/SharpBit/events/public') as resp:
3030
info = await resp.json()
3131
recent_commits = filter(lambda x: x['repo']['name'] != 'SharpBit/modmail' and x['type'] == 'PushEvent', info)
3232
return await render_template('index', request, title="Home Page", description='Home Page', recent=recent_commits)
3333

34-
@root.get('/invite')
35-
async def invite(request):
36-
return response.redirect('https://discord.gg/C2tnmHa')
37-
3834
@root.get('/repo/<name>')
39-
async def repo(request, name):
35+
async def repo(request: Request, name: str):
4036
return response.redirect(f'https://github.com/SharpBit/{name}')
4137

42-
4338
@root.get('/login')
44-
async def login(request):
39+
async def login(request: Request):
4540
if request.ctx.session['logged_in']:
4641
return response.redirect('/')
47-
return response.redirect(request.app.oauth.discord_login_url)
42+
return response.redirect(request.app.ctx.oauth.discord_login_url)
4843

4944
@root.get('/callback')
50-
async def callback(request):
45+
async def callback(request: Request):
5146
app = request.app
5247
code = request.args.get('code')
53-
access_token = await app.oauth.get_access_token(code)
54-
user = await app.oauth.get_user_json(access_token)
48+
access_token = await app.ctx.oauth.get_access_token(code)
49+
user = await app.ctx.oauth.get_user_json(access_token)
5550
if user.get('message'):
5651
return await render_template('unauthorized', request, description='Discord Oauth Unauthorized.')
5752

5853
if user.get('avatar'):
59-
avatar = 'https://cdn.discordapp.com/avatars/{}/{}.png'.format(user['id'], user['avatar'])
60-
else: # in case of default avatar users
61-
avatar = 'https://cdn.discordapp.com/embed/avatars/{}.png'.format(user['discriminator'] % 5)
54+
avatar = f"https://cdn.discordapp.com/avatars/{user['id']}/{user['avatar']}.png"
55+
else: # in case of default avatar users
56+
avatar = f"https://cdn.discordapp.com/embed/avatars/{user['discriminator'] % 5}.png"
6257

6358
async with open_db_connection(request.app) as conn:
6459
await conn.executemany(
6560
'''INSERT INTO users(id, name, discrim, avatar) VALUES ($1, $2, $3, $4)
6661
ON CONFLICT (id) DO UPDATE SET id=$1, name=$2, discrim=$3, avatar=$4''',
67-
[(user['id'], user['username'], user['discriminator'], avatar), (user['id'], user['username'], user['discriminator'], avatar)]
62+
[
63+
(user['id'], user['username'], user['discriminator'], avatar),
64+
(user['id'], user['username'], user['discriminator'], avatar)
65+
]
6866
)
6967

7068
request.ctx.session['logged_in'] = True
@@ -73,14 +71,14 @@ async def callback(request):
7371
return response.redirect('/dashboard')
7472

7573
@root.get('/logout')
76-
async def logout(request):
74+
async def logout(request: Request):
7775
del request.ctx.session['logged_in']
7876
del request.ctx.session['id']
7977
return response.redirect('/')
8078

8179
@root.get('/dashboard')
8280
@login_required()
83-
async def dashboard_home(request):
81+
async def dashboard_home(request: Request):
8482
async with open_db_connection(request.app) as conn:
8583
urls = await conn.fetch('SELECT * FROM urls WHERE user_id = $1', request.ctx.session['id'])
8684
pastes = await conn.fetch('SELECT * FROM pastebin WHERE user_id = $1', request.ctx.session['id'])
@@ -94,12 +92,12 @@ async def dashboard_home(request):
9492
)
9593

9694
@root.get('/urlshortener')
97-
async def url_shortener_home(request):
95+
async def url_shortener_home(request: Request):
9896
return await render_template('url_shortener', request, title='URL Shortener', description='Shorten a URL!')
9997

10098
@root.post('/url/create')
10199
# @authorized()
102-
async def create_url(request):
100+
async def create_url(request: Request):
103101
chars = string.ascii_letters + string.digits
104102
code = ''.join(random.choice(chars) for i in range(8))
105103
try:
@@ -115,29 +113,31 @@ async def create_url(request):
115113
if existing:
116114
return add_message(request, 'error', 'That code is already taken. Try another one.', '/urlshortener')
117115
await conn.execute('INSERT INTO urls(user_id, code, url) VALUES ($1, $2, $3)', account, code, url)
116+
secure = 's' if not request.app.config.DEV else ''
118117
return add_message(
119118
request,
120119
'success',
121-
f"Shortened URL created at <a href=\"http{'s' if not request.app.config.DEV else ''}://{request.app.config.DOMAIN}/{code}\">"
120+
f"Shortened URL created at <a href=\"http{secure}://{request.app.config.DOMAIN}/{code}\">"
122121
f"http{'s' if not request.app.config.DEV else ''}://{request.app.config.DOMAIN}/{code}</a>",
123122
'/urlshortener'
124123
)
125124

126125
@root.get('/<code>')
127-
async def existing_code(request, code):
126+
async def existing_code(request: Request, code: str):
128127
async with open_db_connection(request.app) as conn:
129128
res = await conn.fetchrow('SELECT * FROM urls WHERE code = $1', code)
130129
if not res:
131-
abort(404, message=f'Requested URL {request.path} not found')
130+
raise NotFound(message=f'Requested URL {request.path} not found')
132131
return response.redirect(res['url'])
133132

134133
@root.get('/pastebin')
135-
async def pastebin_home(request):
136-
return await render_template('pastebin', request, title="Pastebin", description='Paste in code for easy access later!')
134+
async def pastebin_home(request: Request):
135+
return await render_template('pastebin', request, title="Pastebin",
136+
description='Paste some code for easy access later!')
137137

138138
@root.post('/pastebin/create')
139139
# @authorized()
140-
async def create_pastebin(request):
140+
async def create_pastebin(request: Request):
141141
chars = string.ascii_letters + string.digits
142142
code = ''.join(random.choice(chars) for i in range(8))
143143
try:
@@ -150,126 +150,49 @@ async def create_pastebin(request):
150150
return response.redirect(f'/pastebin/{code}')
151151

152152
@root.get('/pastebin/<code>')
153-
async def existing_pastebin(request, code):
153+
async def existing_pastebin(request: Request, code: str):
154154
async with open_db_connection(request.app) as conn:
155155
res = await conn.fetchrow('SELECT * FROM pastebin WHERE code = $1', code)
156156
if not res:
157-
abort(404, message=f'Requested URL {request.path} not found')
157+
raise NotFound(message=f'Requested URL {request.path} not found')
158158
text = disable_xss(res['text'])
159-
return await render_template('saved_pastebin', request, title="Pastebin - Saved", description="Saved Pastebin", code=text)
160-
161-
@root.get('/challenges')
162-
async def challenge_home(request):
163-
return await render_template(
164-
template='challenge_home',
165-
request=request,
166-
title='Brawl Stars Challenges',
167-
description='Search up your tag to view the logs of your Brawl Stars challenge games.'
168-
)
169-
170-
@root.post('/challenges/post')
171-
async def challenge_post(request):
172-
try:
173-
form_tag = request.form['tag'][0]
174-
except KeyError:
175-
return add_message(request, 'error', 'Enter a player tag.', '/challenges')
176-
177-
try:
178-
tag = brawlstats.utils.bstag(form_tag)
179-
except brawlstats.NotFoundError as e:
180-
invalid_chars = e.message.split('\n')
181-
invalid_chars = invalid_chars[-1]
182-
return add_message(request, 'error', invalid_chars, '/challenges')
183-
return response.redirect(f'/challenges/{tag}')
184-
185-
@root.get('/challenges/<tag>')
186-
async def challenge_stats(request, tag):
187-
client = request.app.brawl_client
188-
try:
189-
logs = await client.get_battle_logs(tag)
190-
except brawlstats.NotFoundError:
191-
return add_message(request, 'error', f'Tag {disable_xss(tag.upper())} was not found.', '/challenges')
192-
193-
event_map = {
194-
'gemGrab': 'Gem Grab',
195-
'brawlBall': 'Brawl Ball',
196-
'bounty': 'Bounty',
197-
'heist': 'Heist',
198-
'siege': 'Siege'
199-
}
200-
201-
def filter_challenge_games(battle):
202-
try:
203-
if battle.battle.trophy_change == 1 and 'Showdown' not in battle.event.mode:
204-
return True
205-
except:
206-
valid_modes = ['gemGrab', 'brawlBall', 'bounty', 'heist', 'siege']
207-
if battle.event.mode in valid_modes:
208-
# Hacky way to filter out ranked matches
209-
# still possible for a ranked match to be in the result but very unlikely
210-
for team in battle.battle.teams:
211-
for player in team:
212-
if player.brawler.trophies % 100 > 3 or player.brawler.power < 10:
213-
return False
214-
return True
215-
return False
216-
217-
games = list(filter(filter_challenge_games, logs))[::-1]
218-
219-
if len(games) == 0:
220-
return add_message(request, 'error', 'No recent challenge games were found.', '/challenges')
221-
222-
battlelog = []
223-
for battle in games:
224-
battle_info = {
225-
'event': event_map[battle.event.mode],
226-
'map': battle.event.map,
227-
'result': battle.battle.result.title(),
228-
'teams': battle.battle.teams.to_list()
229-
}
230-
for i, team in enumerate(battle_info['teams']):
231-
for j, player in enumerate(team):
232-
if player['tag'] == battle.battle.star_player.tag:
233-
battle_info['teams'][i][j]['star_player'] = 'star'
234-
else:
235-
battle_info['teams'][i][j]['star_player'] = 'normal'
236-
237-
battlelog.append(battle_info)
238159
return await render_template(
239-
template='challenge_stats',
160+
template='saved_pastebin',
240161
request=request,
241-
games=battlelog,
242-
brawler_key={'EL PRIMO': 'El-Primo', 'MR. P': 'Mr.P'},
243-
title='Brawl Stars Challenges',
244-
description='View the logs of your Brawl Stars challenge games.'
162+
title="Pastebin - Saved",
163+
description="Saved Pastebin",
164+
code=text
245165
)
246166

247167
@root.get('/brawlstats/<endpoint:path>')
248-
async def brawlstats_tests_proxy(request, endpoint):
249-
app = request.app
168+
async def brawlstats_tests_proxy(request: Request, endpoint: str):
250169
endpoint = '/'.join(request.url.split('/')[4:])
251170
if not request.token:
252-
return response.text('Invalid authorization', status=403)
171+
raise Forbidden('Invalid authorization')
253172
headers = {
254173
'Authorization': f'Bearer {request.token}',
255174
'Accept-Encoding': 'gzip'
256175
}
257176
try:
258-
async with app.session.get(f'https://api.brawlstars.com/v1/{endpoint}', timeout=30, headers=headers) as resp:
177+
async with request.app.ctx.aiohttp.get(
178+
f'https://api.brawlstars.com/v1/{endpoint}',
179+
timeout=30,
180+
headers=headers
181+
) as resp:
259182
return response.json(await resp.json(), status=resp.status)
260183
except asyncio.TimeoutError:
261-
return response.text('Request failed', status=503)
184+
raise ServerError('Request failed', status_code=503)
262185

263186
@root.get('/schoolweek')
264-
async def schoolweektoday(request):
187+
async def schoolweektoday(request: Request):
265188
return response.redirect(f'/schoolweek/{date.today()}')
266189

267190
@root.get('/schoolweek/<requested_date_str>')
268-
async def schoolweek(request, requested_date_str):
191+
async def schoolweek(request: Request, requested_date_str: str):
269192
requested_date = date(*map(int, requested_date_str.split('-')))
270193
first_day = date(2020, 9, 8)
271194
if not first_day <= requested_date <= date(2021, 3, 11):
272-
abort(404, message=f'Requested URL {request.path} not found')
195+
raise NotFound(f'Requested URL {request.path} not found. Maybe try a date between 9/8/2020 and 3/11/2021?')
273196

274197
week_fmt = await get_school_week(requested_date, first_day, week=True)
275198

@@ -300,8 +223,9 @@ async def email_subscribe(request):
300223
msg['Subject'] = 'Thank you for subscribing to GCHS Daily Updates!'
301224
msg['From'] = request.app.config.CUSTOM_EMAIL
302225
msg['To'] = email
226+
secure = 's' if not request.app.config.DEV else ''
303227
body = MIMEText(
304-
f"If this wasn't you, click <a href=\"http{'s' if not request.app.config.DEV else ''}://{request.app.config.DOMAIN}"
228+
f"If this wasn't you, click <a href=\"http{secure}://{request.app.config.DOMAIN}"
305229
f"/schoolweek/unsubscribe/{email}\">here</a> to unsubscribe.", 'html')
306230
msg.set_content(body)
307231

@@ -320,3 +244,10 @@ async def email_unsubscribe(request, email):
320244
async with open_db_connection(request.app) as conn:
321245
await conn.execute('DELETE FROM mailing_list WHERE email = $1', email)
322246
return add_message(request, 'success', 'Your email has been removed from mailing list.', '/schoolweek')
247+
248+
@root.get('/japanese-conjugation-practice')
249+
async def jap_conj(request):
250+
return await render_template(
251+
template='jap-conj',
252+
request=request
253+
)
-27.4 KB
Binary file not shown.

0 commit comments

Comments
 (0)