diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/db_engine.py b/app/db_engine.py new file mode 100644 index 0000000..e07ad27 --- /dev/null +++ b/app/db_engine.py @@ -0,0 +1,765 @@ +import math +from datetime import datetime +import logging +import os + +from peewee import * +from playhouse.shortcuts import model_to_dict + +db = SqliteDatabase( + 'storage/pd_master.db', + pragmas={ + 'journal_mode': 'wal', + 'cache_size': -1 * 64000, + 'synchronous': 0 + } +) + +date = f'{datetime.now().year}-{datetime.now().month}-{datetime.now().day}' +log_level = logging.INFO if os.environ.get('LOG_LEVEL') == 'INFO' else 'WARN' +logging.basicConfig( + filename=f'logs/database/{date}.log', + format='%(asctime)s - database - %(levelname)s - %(message)s', + level=log_level +) + + +class BaseModel(Model): + class Meta: + database = db + + +class Current(BaseModel): + season = IntegerField() + week = IntegerField(default=0) + gsheet_template = CharField() + gsheet_version = CharField() + live_scoreboard = IntegerField() + + @staticmethod + def latest(): + latest_current = Current.select().order_by(-Current.id).get() + return latest_current + + +db.create_tables([Current]) + + +class Rarity(BaseModel): + value = IntegerField() + name = CharField(unique=True) + color = CharField() + + def __str__(self): + return self.name + + +db.create_tables([Rarity]) + + +class Event(BaseModel): + name = CharField() + short_desc = CharField(null=True) + url = CharField(null=True) + long_desc = CharField(null=True) + thumbnail = CharField(null=True) + active = BooleanField(default=False) + + +db.create_tables([Event]) + + +class Cardset(BaseModel): + name = CharField() + description = CharField() + event = ForeignKeyField(Event, null=True) + for_purchase = BooleanField(default=True) # for_purchase + total_cards = IntegerField() + in_packs = BooleanField(default=True) + ranked_legal = BooleanField(default=True) + + def __str__(self): + return self.name + + +db.create_tables([Cardset]) + + +class Player(BaseModel): + player_id = IntegerField(primary_key=True) + p_name = CharField() + cost = IntegerField(default=0) + image = CharField() + image2 = CharField(null=True) + mlbclub = CharField() + franchise = CharField() + cardset = ForeignKeyField(Cardset) + set_num = IntegerField() + rarity = ForeignKeyField(Rarity) + pos_1 = CharField() + pos_2 = CharField(null=True) + pos_3 = CharField(null=True) + pos_4 = CharField(null=True) + pos_5 = CharField(null=True) + pos_6 = CharField(null=True) + pos_7 = CharField(null=True) + pos_8 = CharField(null=True) + headshot = CharField(null=True) + vanity_card = CharField(null=True) + strat_code = CharField(null=True) + bbref_id = CharField(null=True) + fangr_id = CharField(null=True) + description = CharField() + quantity = IntegerField(default=999) + + def __str__(self): + return f'{self.cardset} {self.p_name} ({self.rarity.name})' + + # def __eq__(self, other): + # if self.cardset.id == other.cardset.id and self.name == other.name: + # return True + # else: + # return False + + def __lt__(self, other): + if self.wara < other.wara: + return True + elif self.wara > other.wara: + return False + elif self.name < other.name: + return True + else: + return False + + def get_all_pos(self): + all_pos = [] + + if self.pos_1 and self.pos_1 != 'CP': + all_pos.append(self.pos_1) + if self.pos_2 and self.pos_2 != 'CP': + all_pos.append(self.pos_2) + if self.pos_3 and self.pos_3 != 'CP': + all_pos.append(self.pos_3) + if self.pos_4 and self.pos_4 != 'CP': + all_pos.append(self.pos_4) + if self.pos_5 and self.pos_5 != 'CP': + all_pos.append(self.pos_5) + if self.pos_6 and self.pos_6 != 'CP': + all_pos.append(self.pos_6) + if self.pos_7 and self.pos_7 != 'CP': + all_pos.append(self.pos_7) + if self.pos_8 and self.pos_8 != 'CP': + all_pos.append(self.pos_8) + + return all_pos + + def change_on_sell(self): + # caps = { + # 'replacement': 15, + # 'reserve': 50, + # 'starter': 200, + # 'all-star': 750, + # 'mvp': 2500, + # 'hof': 999999999 + # } + logging.info(f'{self.p_name} cost changing from: {self.cost}') + self.cost = max(math.floor(self.cost * .95), 1) + # if self.quantity != 999: + # self.quantity += 1 + logging.info(f'{self.p_name} cost now: {self.cost}') + self.save() + + def change_on_buy(self): + logging.info(f'{self.p_name} cost changing from: {self.cost}') + self.cost = math.ceil(self.cost * 1.1) + # if self.quantity != 999: + # self.quantity -= 1 + logging.info(f'{self.p_name} cost now: {self.cost}') + self.save() + + +db.create_tables([Player]) + + +class Team(BaseModel): + abbrev = CharField() + sname = CharField() + lname = CharField() + gmid = IntegerField() + gmname = CharField() + gsheet = CharField() + wallet = IntegerField() + team_value = IntegerField() + collection_value = IntegerField() + logo = CharField(null=True) + color = CharField(null=True) + season = IntegerField() + event = ForeignKeyField(Event, null=True) + career = IntegerField(default=0) + ranking = IntegerField(default=1000) + has_guide = BooleanField(default=False) + is_ai = IntegerField(null=True) + + def __str__(self): + return f'S{self.season} {self.lname}' + + @staticmethod + def get_by_owner(gmid, season=None): + if not season: + season = Current.get().season + team = Team.get_or_none((Team.gmid == gmid) & (Team.season == season)) + + if not team: + return None + + return team + + @staticmethod + def select_season(season=None): + if not season: + season = Current.get().season + return Team.select().where(Team.season == season) + + @staticmethod + def get_season(abbrev, season=None): + if not season: + season = Current.get().season + return Team.get_or_none(Team.season == season, Team.abbrev == abbrev.upper()) + + def team_hash(self): + hash_string = f'{self.sname[-1]}{self.gmid / 6950123:.0f}{self.sname[-2]}{self.gmid / 42069123:.0f}' + logging.info(f'string: {hash_string}') + return hash_string + + +db.create_tables([Team]) + + +class PackType(BaseModel): + name = CharField() + card_count = IntegerField() + description = CharField() + cost = IntegerField() + available = BooleanField(default=True) + + +db.create_tables([PackType]) + + +class Pack(BaseModel): + team = ForeignKeyField(Team) + pack_type = ForeignKeyField(PackType) + pack_team = ForeignKeyField(Team, null=True) + pack_cardset = ForeignKeyField(Cardset, null=True) + open_time = DateTimeField(null=True) + + +db.create_tables([Pack]) + + +class Card(BaseModel): + player = ForeignKeyField(Player, null=True) + team = ForeignKeyField(Team, null=True) + pack = ForeignKeyField(Pack, null=True) + value = IntegerField(default=0) + + def __str__(self): + if self.player: + return f'{self.player} - {self.team.sname}' + else: + return f'Blank - {self.team.sname}' + + @staticmethod + def select_season(season): + return Card.select().join(Team).where(Card.team.season == season) + + +db.create_tables([Card]) + + +class Roster(BaseModel): + team = ForeignKeyField(Team) + name = CharField() + roster_num = IntegerField() + card_1 = ForeignKeyField(Card) + card_2 = ForeignKeyField(Card) + card_3 = ForeignKeyField(Card) + card_4 = ForeignKeyField(Card) + card_5 = ForeignKeyField(Card) + card_6 = ForeignKeyField(Card) + card_7 = ForeignKeyField(Card) + card_8 = ForeignKeyField(Card) + card_9 = ForeignKeyField(Card) + card_10 = ForeignKeyField(Card) + card_11 = ForeignKeyField(Card) + card_12 = ForeignKeyField(Card) + card_13 = ForeignKeyField(Card) + card_14 = ForeignKeyField(Card) + card_15 = ForeignKeyField(Card) + card_16 = ForeignKeyField(Card) + card_17 = ForeignKeyField(Card) + card_18 = ForeignKeyField(Card) + card_19 = ForeignKeyField(Card) + card_20 = ForeignKeyField(Card) + card_21 = ForeignKeyField(Card) + card_22 = ForeignKeyField(Card) + card_23 = ForeignKeyField(Card) + card_24 = ForeignKeyField(Card) + card_25 = ForeignKeyField(Card) + card_26 = ForeignKeyField(Card) + + def __str__(self): + return f'{self.team} Roster' + + # def get_cards(self, team): + # all_cards = Card.select().where(Card.roster == self) + # this_roster = [] + # return [this_roster.card1, this_roster.card2, this_roster.card3, this_roster.card4, this_roster.card5, + # this_roster.card6, this_roster.card7, this_roster.card8, this_roster.card9, this_roster.card10, + # this_roster.card11, this_roster.card12, this_roster.card13, this_roster.card14, this_roster.card15, + # this_roster.card16, this_roster.card17, this_roster.card18, this_roster.card19, this_roster.card20, + # this_roster.card21, this_roster.card22, this_roster.card23, this_roster.card24, this_roster.card25, + # this_roster.card26] + + +class BattingStat(BaseModel): + card = ForeignKeyField(Card) + team = ForeignKeyField(Team) + roster_num = IntegerField() + vs_team = ForeignKeyField(Team) + pos = CharField() + pa = IntegerField() + ab = IntegerField() + run = IntegerField() + hit = IntegerField() + rbi = IntegerField() + double = IntegerField() + triple = IntegerField() + hr = IntegerField() + bb = IntegerField() + so = IntegerField() + hbp = IntegerField() + sac = IntegerField() + ibb = IntegerField() + gidp = IntegerField() + sb = IntegerField() + cs = IntegerField() + bphr = IntegerField() + bpfo = IntegerField() + bp1b = IntegerField() + bplo = IntegerField() + xch = IntegerField() + xhit = IntegerField() + error = IntegerField() + pb = IntegerField() + sbc = IntegerField() + csc = IntegerField() + week = IntegerField() + season = IntegerField() + created = DateTimeField() + game_id = IntegerField() + + +class PitchingStat(BaseModel): + card = ForeignKeyField(Card) + team = ForeignKeyField(Team) + roster_num = IntegerField() + vs_team = ForeignKeyField(Team) + ip = FloatField() + hit = IntegerField() + run = IntegerField() + erun = IntegerField() + so = IntegerField() + bb = IntegerField() + hbp = IntegerField() + wp = IntegerField() + balk = IntegerField() + hr = IntegerField() + ir = IntegerField() + irs = IntegerField() + gs = IntegerField() + win = IntegerField() + loss = IntegerField() + hold = IntegerField() + sv = IntegerField() + bsv = IntegerField() + week = IntegerField() + season = IntegerField() + created = DateTimeField() + game_id = IntegerField() + + +class Result(BaseModel): + away_team = ForeignKeyField(Team) + home_team = ForeignKeyField(Team) + away_score = IntegerField() + home_score = IntegerField() + away_team_value = IntegerField(null=True) + home_team_value = IntegerField(null=True) + away_team_ranking = IntegerField(null=True) + home_team_ranking = IntegerField(null=True) + scorecard = CharField() + week = IntegerField() + season = IntegerField() + ranked = BooleanField() + short_game = BooleanField() + game_type = CharField(null=True) + + @staticmethod + def select_season(season=None): + if not season: + season = Current.get().season + return Result.select().where(Result.season == season) + + +class Award(BaseModel): + name = CharField() + season = IntegerField() + timing = CharField(default="In-Season") + card = ForeignKeyField(Card, null=True) + team = ForeignKeyField(Team, null=True) + image = CharField(null=True) + + +class Paperdex(BaseModel): + team = ForeignKeyField(Team) + player = ForeignKeyField(Player) + created = DateTimeField(default=int(datetime.timestamp(datetime.now())*1000)) + + # def add_to_paperdex(self, team, cards: list): + # for x in players: + # if not isinstance(x, Card): + # raise TypeError(f'The Pokedex can only take a list of Player or Card objects') + # + # Paperdex.get_or_create(team=team, player=player) + + +class Reward(BaseModel): + name = CharField(null=True) + season = IntegerField() + week = IntegerField() + team = ForeignKeyField(Team) + created = DateTimeField() + + +class GameRewards(BaseModel): + name = CharField() + pack_type = ForeignKeyField(PackType, null=True) + player = ForeignKeyField(Player, null=True) + money = IntegerField(null=True) + + +class Notification(BaseModel): + created = DateTimeField() + title = CharField() + desc = CharField(null=True) + field_name = CharField() + message = CharField() + about = CharField() # f'{Topic}-{Object ID}' + ack = BooleanField(default=False) + + +class GauntletReward(BaseModel): + name = CharField() + gauntlet = ForeignKeyField(Event) + reward = ForeignKeyField(GameRewards) + win_num = IntegerField() + loss_max = IntegerField(default=1) + + +class GauntletRun(BaseModel): + team = ForeignKeyField(Team) + gauntlet = ForeignKeyField(Event) + wins = IntegerField(default=0) + losses = IntegerField(default=0) + gsheet = CharField(null=True) + created = DateTimeField(default=int(datetime.timestamp(datetime.now())*1000)) + ended = DateTimeField(default=0) + + +db.create_tables([ + Roster, BattingStat, PitchingStat, Result, Award, Paperdex, Reward, GameRewards, Notification, GauntletReward, + GauntletRun +]) + + +class BattingCard(BaseModel): + player = ForeignKeyField(Player) + steal_low = IntegerField() + steal_high = IntegerField() + steal_auto = BooleanField() + steal_jump = FloatField() + bunting = CharField() + hit_and_run = CharField() + running = IntegerField() + offense_col = IntegerField() + hand = CharField(default='R') + + +class BattingCardRatings(BaseModel): + battingcard = ForeignKeyField(BattingCard) + vs_hand = FloatField() + homerun = FloatField() + bp_homerun = FloatField() + triple = FloatField() + double_three = FloatField() + double_two = FloatField() + double_pull = FloatField() + single_two = FloatField() + single_one = FloatField() + single_center = FloatField() + bp_single = FloatField() + hbp = FloatField() + walk = FloatField() + strikeout = FloatField() + lineout = FloatField() + popout = FloatField() + flyout_a = FloatField() + flyout_bq = FloatField() + flyout_lf_b = FloatField() + flyout_rf_b = FloatField() + groundout_a = FloatField() + groundout_b = FloatField() + groundout_c = FloatField() + avg = FloatField(null=True) + obp = FloatField(null=True) + slg = FloatField(null=True) + + +class PitchingCard(BaseModel): + player = ForeignKeyField(Player) + balk = IntegerField() + wild_pitch = IntegerField(null=True) + hold = CharField() + starter_rating = IntegerField() + relief_rating = IntegerField() + closer_rating = IntegerField(null=True) + batting = CharField(null=True) + + +class PitchingCardRatings(BaseModel): + pitchingcard = ForeignKeyField(PitchingCard) + vs_hand = CharField() + homerun = FloatField() + bp_homerun = FloatField() + triple = FloatField() + double_three = FloatField() + double_two = FloatField() + double_cf = FloatField() + single_two = FloatField() + single_one = FloatField() + single_center = FloatField() + bp_single = FloatField() + hbp = FloatField() + walk = FloatField() + strikeout = FloatField() + fo_slap = FloatField() + fo_center = FloatField() + groundout_a = FloatField() + groundout_b = FloatField() + xcheck_p = FloatField() + xcheck_c = FloatField() + xcheck_1b = FloatField() + xcheck_2b = FloatField() + xcheck_3b = FloatField() + xcheck_ss = FloatField() + xcheck_lf = FloatField() + xcheck_cf = FloatField() + xcheck_rf = FloatField() + avg = FloatField(null=True) + obp = FloatField(null=True) + slg = FloatField(null=True) + + +class CardPosition(BaseModel): + player = ForeignKeyField(Player) + batting = ForeignKeyField(BattingCard, null=True) + pitching = ForeignKeyField(PitchingCard, null=True) + position = CharField() + innings = IntegerField() + range = IntegerField() + error = IntegerField() + arm = IntegerField(null=True) + pb = IntegerField(null=True) + overthrow = IntegerField(null=True) + + +db.create_tables([BattingCard, BattingCardRatings, PitchingCard, PitchingCardRatings, CardPosition]) + + +db.close() + +# scout_db = SqliteDatabase( +# 'storage/card_creation.db', +# pragmas={ +# 'journal_mode': 'wal', +# 'cache_size': -1 * 64000, +# 'synchronous': 0 +# } +# ) +# +# +# class BaseModelScout(Model): +# class Meta: +# database = scout_db +# +# +# class ScoutCardset(BaseModelScout): +# set_title = CharField() +# set_subtitle = CharField(null=True) +# +# +# class ScoutPlayer(BaseModelScout): +# sba_id = IntegerField(primary_key=True) +# name = CharField() +# fg_id = IntegerField() +# br_id = CharField() +# offense_col = IntegerField() +# hand = CharField(default='R') +# +# +# scout_db.create_tables([ScoutCardset, ScoutPlayer]) +# +# +# class BatterRatings(BaseModelScout): +# id = CharField(unique=True, primary_key=True) +# player = ForeignKeyField(ScoutPlayer) +# cardset = ForeignKeyField(ScoutCardset) +# vs_hand = FloatField() +# is_prep = BooleanField() +# homerun = FloatField() +# bp_homerun = FloatField() +# triple = FloatField() +# double_three = FloatField() +# double_two = FloatField() +# double_pull = FloatField() +# single_two = FloatField() +# single_one = FloatField() +# single_center = FloatField() +# bp_single = FloatField() +# hbp = FloatField() +# walk = FloatField() +# strikeout = FloatField() +# lineout = FloatField() +# popout = FloatField() +# flyout_a = FloatField() +# flyout_bq = FloatField() +# flyout_lf_b = FloatField() +# flyout_rf_b = FloatField() +# groundout_a = FloatField() +# groundout_b = FloatField() +# groundout_c = FloatField() +# avg = FloatField(null=True) +# obp = FloatField(null=True) +# slg = FloatField(null=True) +# +# +# class PitcherRatings(BaseModelScout): +# id = CharField(unique=True, primary_key=True) +# player = ForeignKeyField(ScoutPlayer) +# cardset = ForeignKeyField(ScoutCardset) +# vs_hand = CharField() +# is_prep = BooleanField() +# homerun = FloatField() +# bp_homerun = FloatField() +# triple = FloatField() +# double_three = FloatField() +# double_two = FloatField() +# double_cf = FloatField() +# single_two = FloatField() +# single_one = FloatField() +# single_center = FloatField() +# bp_single = FloatField() +# hbp = FloatField() +# walk = FloatField() +# strikeout = FloatField() +# fo_slap = FloatField() +# fo_center = FloatField() +# groundout_a = FloatField() +# groundout_b = FloatField() +# xcheck_p = FloatField() +# xcheck_c = FloatField() +# xcheck_1b = FloatField() +# xcheck_2b = FloatField() +# xcheck_3b = FloatField() +# xcheck_ss = FloatField() +# xcheck_lf = FloatField() +# xcheck_cf = FloatField() +# xcheck_rf = FloatField() +# avg = FloatField(null=True) +# obp = FloatField(null=True) +# slg = FloatField(null=True) +# +# +# # scout_db.create_tables([BatterRatings, PitcherRatings]) +# +# +# class CardColumns(BaseModelScout): +# id = CharField(unique=True, primary_key=True) +# player = ForeignKeyField(ScoutPlayer) +# hand = CharField() +# b_ratings = ForeignKeyField(BatterRatings, null=True) +# p_ratings = ForeignKeyField(PitcherRatings, null=True) +# one_dice = CharField() +# one_results = CharField() +# one_splits = CharField() +# two_dice = CharField() +# two_results = CharField() +# two_splits = CharField() +# three_dice = CharField() +# three_results = CharField() +# three_splits = CharField() +# +# +# class Position(BaseModelScout): +# player = ForeignKeyField(ScoutPlayer) +# cardset = ForeignKeyField(ScoutCardset) +# position = CharField() +# innings = IntegerField() +# range = IntegerField() +# error = IntegerField() +# arm = CharField(null=True) +# pb = IntegerField(null=True) +# overthrow = IntegerField(null=True) +# +# +# class BatterData(BaseModelScout): +# player = ForeignKeyField(ScoutPlayer) +# cardset = ForeignKeyField(ScoutCardset) +# stealing = CharField() +# st_low = IntegerField() +# st_high = IntegerField() +# st_auto = BooleanField() +# st_jump = FloatField() +# bunting = CharField(null=True) +# hit_and_run = CharField(null=True) +# running = CharField() +# +# +# class PitcherData(BaseModelScout): +# player = ForeignKeyField(ScoutPlayer) +# cardset = ForeignKeyField(ScoutCardset) +# balk = IntegerField(null=True) +# wild_pitch = IntegerField(null=True) +# hold = CharField() +# starter_rating = IntegerField() +# relief_rating = IntegerField() +# closer_rating = IntegerField(null=True) +# batting = CharField(null=True) +# +# +# scout_db.create_tables([CardColumns, Position, BatterData, PitcherData]) +# +# +# class CardOutput(BaseModelScout): +# name = CharField() +# hand = CharField() +# positions = CharField() +# stealing = CharField() +# bunting = CharField() +# hitandrun = CharField() +# running = CharField() +# +# +# scout_db.close() + diff --git a/app/dependencies.py b/app/dependencies.py new file mode 100644 index 0000000..8386e66 --- /dev/null +++ b/app/dependencies.py @@ -0,0 +1,26 @@ +import datetime +import logging +import os + +from fastapi.security import OAuth2PasswordBearer + +date = f'{datetime.datetime.now().year}-{datetime.datetime.now().month}-{datetime.datetime.now().day}' +LOG_DATA = { + 'filename': f'logs/database/{date}.log', + 'format': '%(asctime)s - database - %(levelname)s - %(message)s', + 'log_level': logging.INFO if os.environ.get('LOG_LEVEL') == 'INFO' else 'WARN' +} + + +logging.basicConfig( + filename=LOG_DATA['filename'], + format=LOG_DATA['format'], + level=LOG_DATA['log_level'] +) + + +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") + + +def valid_token(token): + return token == os.environ.get('API_TOKEN') diff --git a/app/main.py b/app/main.py new file mode 100644 index 0000000..fc7999a --- /dev/null +++ b/app/main.py @@ -0,0 +1,13 @@ +import datetime +import logging +import os + +from fastapi import FastAPI + +from.routers_v2 import current + +app = FastAPI( + responses={404: {'description': 'Not found'}} +) + +app.include_router(current.router) diff --git a/app/routers_v2/__init__.py b/app/routers_v2/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/routers_v2/current.py b/app/routers_v2/current.py new file mode 100644 index 0000000..f3d1dbf --- /dev/null +++ b/app/routers_v2/current.py @@ -0,0 +1,165 @@ +from fastapi import APIRouter, Depends, HTTPException +from typing import Optional +import logging +import pydantic + +from ..db_engine import db, Current, model_to_dict +from ..dependencies import oauth2_scheme, valid_token, LOG_DATA + +logging.basicConfig( + filename=LOG_DATA['filename'], + format=LOG_DATA['format'], + level=LOG_DATA['log_level'] +) + +router = APIRouter( + prefix='/api/v2/current', + tags=['current'] +) + + +class CurrentModel(pydantic.BaseModel): + season: int + week: int + gsheet_template: str + gsheet_version: str + + +@router.get('') +async def get_current(season: Optional[int] = None, csv: Optional[bool] = False): + if season: + current = Current.get_or_none(season=season) + else: + current = Current.latest() + + if csv: + current_list = [ + ['id', 'season', 'week'], + [current.id, current.season, current.week] + ] + return_val = DataFrame(current_list).to_csv(header=False, index=False) + + db.close() + return Response(content=return_val, media_type='text/csv') + else: + return_val = model_to_dict(current) + db.close() + return return_val + + +@router.get('/{current_id}') +async def get_one_current(current_id, csv: Optional[bool] = False): + try: + current = Current.get_by_id(current_id) + except Exception: + db.close() + raise HTTPException(status_code=404, detail=f'No current found with id {current_id}') + + if csv: + current_list = [ + ['id', 'season', 'week'], + [current.id, current.season, current.week] + ] + return_val = DataFrame(current_list).to_csv(header=False, index=False) + + db.close() + return Response(content=return_val, media_type='text/csv') + else: + return_val = model_to_dict(current) + db.close() + return return_val + + +@router.post('') +async def post_current(current: CurrentModel, token: str = Depends(oauth2_scheme)): + if not valid_token(token): + logging.warning(f'Bad Token: {token}') + db.close() + raise HTTPException( + status_code=401, + detail='You are not authorized to post current. This event has been logged.' + ) + + dupe_curr = Current.get_or_none(Current.season == current.season) + if dupe_curr: + db.close() + raise HTTPException(status_code=400, detail=f'There is already a current for season {current.season}') + + this_curr = Current( + season=current.season, + week=current.week, + gsheet_template=current.gsheet_template, + gsheet_version=current.gsheet_version + ) + + saved = this_curr.save() + if saved == 1: + return_val = model_to_dict(this_curr) + db.close() + return return_val + else: + raise HTTPException(status_code=418, detail='Well slap my ass and call me a teapot; I could not save that team') + + +@router.patch('/{current_id}') +async def patch_current( + current_id: int, season: Optional[int] = None, week: Optional[int] = None, + gsheet_template: Optional[str] = None, gsheet_version: Optional[str] = None, + live_scoreboard: Optional[int] = None, token: str = Depends(oauth2_scheme)): + if not valid_token(token): + logging.warning(f'Bad Token: {token}') + db.close() + raise HTTPException( + status_code=401, + detail='You are not authorized to patch current. This event has been logged.' + ) + try: + current = Current.get_by_id(current_id) + except Exception: + db.close() + raise HTTPException(status_code=404, detail=f'No current found with id {current_id}') + + if season is not None: + current.season = season + if week is not None: + current.week = week + if gsheet_template is not None: + current.gsheet_template = gsheet_template + if gsheet_version is not None: + current.gsheet_version = gsheet_version + if live_scoreboard is not None: + current.live_scoreboard = live_scoreboard + + if current.save() == 1: + return_val = model_to_dict(current) + db.close() + return return_val + else: + raise HTTPException( + status_code=418, + detail='Well slap my ass and call me a teapot; I could not save that current' + ) + + +@router.delete('/{current_id}') +async def delete_current(current_id, token: str = Depends(oauth2_scheme)): + if not valid_token(token): + logging.warning(f'Bad Token: {token}') + db.close() + raise HTTPException( + status_code=401, + detail='You are not authorized to delete current. This event has been logged.' + ) + try: + this_curr = Current.get_by_id(current_id) + except Exception: + db.close() + raise HTTPException(status_code=404, detail=f'No current found with id {current_id}') + + count = this_curr.delete_instance() + db.close() + + if count == 1: + raise HTTPException(status_code=200, detail=f'Current {current_id} has been deleted') + else: + raise HTTPException(status_code=500, detail=f'Current {current_id} was not deleted') diff --git a/requirements.txt b/requirements.txt index ecccb5d..4ac1ae5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ peewee python-multipart pandas pygsheets +pybaseball diff --git a/venv/share/man/man1/ttx.1 b/venv/share/man/man1/ttx.1 new file mode 100644 index 0000000..bba23b5 --- /dev/null +++ b/venv/share/man/man1/ttx.1 @@ -0,0 +1,225 @@ +.Dd May 18, 2004 +.\" ttx is not specific to any OS, but contrary to what groff_mdoc(7) +.\" seems to imply, entirely omitting the .Os macro causes 'BSD' to +.\" be used, so I give a zero-width space as its argument. +.Os \& +.\" The "FontTools Manual" argument apparently has no effect in +.\" groff 1.18.1. I think it is a bug in the -mdoc groff package. +.Dt TTX 1 "FontTools Manual" +.Sh NAME +.Nm ttx +.Nd tool for manipulating TrueType and OpenType fonts +.Sh SYNOPSIS +.Nm +.Bk +.Op Ar option ... +.Ek +.Bk +.Ar file ... +.Ek +.Sh DESCRIPTION +.Nm +is a tool for manipulating TrueType and OpenType fonts. It can convert +TrueType and OpenType fonts to and from an +.Tn XML Ns -based format called +.Tn TTX . +.Tn TTX +files have a +.Ql .ttx +extension. +.Pp +For each +.Ar file +argument it is given, +.Nm +detects whether it is a +.Ql .ttf , +.Ql .otf +or +.Ql .ttx +file and acts accordingly: if it is a +.Ql .ttf +or +.Ql .otf +file, it generates a +.Ql .ttx +file; if it is a +.Ql .ttx +file, it generates a +.Ql .ttf +or +.Ql .otf +file. +.Pp +By default, every output file is created in the same directory as the +corresponding input file and with the same name except for the +extension, which is substituted appropriately. +.Nm +never overwrites existing files; if necessary, it appends a suffix to +the output file name before the extension, as in +.Pa Arial#1.ttf . +.Ss "General options" +.Bl -tag -width ".Fl t Ar table" +.It Fl h +Display usage information. +.It Fl d Ar dir +Write the output files to directory +.Ar dir +instead of writing every output file to the same directory as the +corresponding input file. +.It Fl o Ar file +Write the output to +.Ar file +instead of writing it to the same directory as the +corresponding input file. +.It Fl v +Be verbose. Write more messages to the standard output describing what +is being done. +.It Fl a +Allow virtual glyphs ID's on compile or decompile. +.El +.Ss "Dump options" +The following options control the process of dumping font files +(TrueType or OpenType) to +.Tn TTX +files. +.Bl -tag -width ".Fl t Ar table" +.It Fl l +List table information. Instead of dumping the font to a +.Tn TTX +file, display minimal information about each table. +.It Fl t Ar table +Dump table +.Ar table . +This option may be given multiple times to dump several tables at +once. When not specified, all tables are dumped. +.It Fl x Ar table +Exclude table +.Ar table +from the list of tables to dump. This option may be given multiple +times to exclude several tables from the dump. The +.Fl t +and +.Fl x +options are mutually exclusive. +.It Fl s +Split tables. Dump each table to a separate +.Tn TTX +file and write (under the name that would have been used for the output +file if the +.Fl s +option had not been given) one small +.Tn TTX +file containing references to the individual table dump files. This +file can be used as input to +.Nm +as long as the referenced files can be found in the same directory. +.It Fl i +.\" XXX: I suppose OpenType programs (exist and) are also affected. +Don't disassemble TrueType instructions. When this option is specified, +all TrueType programs (glyph programs, the font program and the +pre-program) are written to the +.Tn TTX +file as hexadecimal data instead of +assembly. This saves some time and results in smaller +.Tn TTX +files. +.It Fl y Ar n +When decompiling a TrueType Collection (TTC) file, +decompile font number +.Ar n , +starting from 0. +.El +.Ss "Compilation options" +The following options control the process of compiling +.Tn TTX +files into font files (TrueType or OpenType): +.Bl -tag -width ".Fl t Ar table" +.It Fl m Ar fontfile +Merge the input +.Tn TTX +file +.Ar file +with +.Ar fontfile . +No more than one +.Ar file +argument can be specified when this option is used. +.It Fl b +Don't recalculate glyph bounding boxes. Use the values in the +.Tn TTX +file as is. +.El +.Sh "THE TTX FILE FORMAT" +You can find some information about the +.Tn TTX +file format in +.Pa documentation.html . +In particular, you will find in that file the list of tables understood by +.Nm +and the relations between TrueType GlyphIDs and the glyph names used in +.Tn TTX +files. +.Sh EXAMPLES +In the following examples, all files are read from and written to the +current directory. Additionally, the name given for the output file +assumes in every case that it did not exist before +.Nm +was invoked. +.Pp +Dump the TrueType font contained in +.Pa FreeSans.ttf +to +.Pa FreeSans.ttx : +.Pp +.Dl ttx FreeSans.ttf +.Pp +Compile +.Pa MyFont.ttx +into a TrueType or OpenType font file: +.Pp +.Dl ttx MyFont.ttx +.Pp +List the tables in +.Pa FreeSans.ttf +along with some information: +.Pp +.Dl ttx -l FreeSans.ttf +.Pp +Dump the +.Sq cmap +table from +.Pa FreeSans.ttf +to +.Pa FreeSans.ttx : +.Pp +.Dl ttx -t cmap FreeSans.ttf +.Sh NOTES +On MS\-Windows and MacOS, +.Nm +is available as a graphical application to which files can be dropped. +.Sh SEE ALSO +.Pa documentation.html +.Pp +.Xr fontforge 1 , +.Xr ftinfo 1 , +.Xr gfontview 1 , +.Xr xmbdfed 1 , +.Xr Font::TTF 3pm +.Sh AUTHORS +.Nm +was written by +.An -nosplit +.An "Just van Rossum" Aq just@letterror.com . +.Pp +This manual page was written by +.An "Florent Rougon" Aq f.rougon@free.fr +for the Debian GNU/Linux system based on the existing FontTools +documentation. It may be freely used, modified and distributed without +restrictions. +.\" For Emacs: +.\" Local Variables: +.\" fill-column: 72 +.\" sentence-end: "[.?!][]\"')}]*\\($\\| $\\| \\| \\)[ \n]*" +.\" sentence-end-double-space: t +.\" End: \ No newline at end of file