Пример #1
0
            ('date', pymongo.DESCENDING)
        ],
        unique=True
    )


# Hook up resources to operations

service.post('/users', response_model=User)(add_user)
service.post('/sessions')(authenticate)
service.get('/sessions/current', response_model=User)(get_current_user)

service.post('/institutions', response_model=Institution)(add_institution)
service.get('/institutions', response_model=List[Institution])(get_institutions)
service.put('/institutions/{code}', response_model=Institution)(modify_institution)
service.delete('/institutions/{code}')(delete_institution)

service.post('/instruments', response_model=Union[Security, Instrument])(add_instrument)
service.get('/instruments', response_model=List[Union[Security, Instrument]])(get_instruments)
service.put('/instruments/{code}', response_model=Union[Security, Instrument])(modify_instrument)
service.delete('/instruments/{code}')(delete_instrument)
service.put('/instruments/{code}/values/{date}', response_model=Value)(set_value)
service.get('/instruments/{code}/values/{date}', response_model=Value)(get_value)

service.post('/accounts', response_model=Union[FinancialAccount, CashAccount])(add_account)
service.get('/accounts', response_model=List[Union[FinancialAccount, CashAccount]])(get_accounts)
service.put('/accounts/{code}', response_model=Union[FinancialAccount, CashAccount])(modify_account)
service.delete('/accounts/{code}')(delete_account)

service.post('/transactions', response_model=Transaction)(add_transaction)
service.get('/transactions', response_model=List[Transaction])(get_transactions)
Пример #2
0
#------------------------------------------------------------------
#UPDATE
# Example update endpoint
class updateBookPayload(BaseModel):
    name: str
    page: int
#------------------------------------------------------------------
# Example update endpoint
@app.patch("/books/{book_id}")
def update_book_by_id(req_body: updateBookPayload,book_id: str):
    req_body_dict = req_body.dict()

    name = req_body_dict["name"]
    page = req_body_dict["page"]

    print(f"name: {name}, page: {page}")

    update_message = f"update book id{book_id} is complete !!!"
    response = {"status": "ok","data":update_message}
    return JSONResponse(content=response,status_code=200)
#-----------------------------------------------------------------
#DELETE
@app.delete("/books/{book_id}")
def delete_book_by_id(book_id: int):
    delete_message = f"Delete book id {biik_id} is complete !!"
    response = {"status": "ok", "data": delete_message}
    return JSONResponse(content=response, status_code=200)

#--------------------------------------------------------------------

Пример #3
0
class Api:
    __slots__ = ("database", "app", "_snowflake_lock", "tba_client")

    async def generate_snowflake(self, entry: ScoutEntry) -> int:
        """For identifying scout entries"""

        if not self._snowflake_lock:
            self._snowflake_lock = asyncio.Lock()

        async with self._snowflake_lock:
            n = bin(int(datetime.datetime.utcnow().timestamp() * 100))
            h = bin(abs(hash(frozenset(entry))))[2:]
            return int(f"{n}{h[:10] if len(h) >= 10 else h.zfill(10)}", 2)

    def __init__(self,
                 database: ScoutEntriesDatabase,
                 parent_app: Starlette,
                 prefix="/api"):
        self.database = database
        try:
            self.tba_client = TBAClient(token=os.environ["X-TBA-Auth-Key"])
        except KeyError:
            self.tba_client = TBAClient()
            log.warning(
                "TBA Authorization Key not provided. Some endpoints will be unavailable"
            )

        self._snowflake_lock = asyncio.Lock()
        self.app = FastAPI(
            title="CabbageScout API",
            version=cabbagescout.__version__,
            openapi_prefix=prefix,
        )

        self.app.get("/csv",
                     response_model=str,
                     response_class=PlainTextResponse)(self.to_csv)
        self.app.post("/entry",
                      response_model=int,
                      response_description="The unique entry ID")(
                          self.add_entry)
        self.app.get("/entry/{entry_id}",
                     response_model=ScoutEntryID)(self.get_entry)
        self.app.put("/entry/{entry_id")(self.edit_entry)
        self.app.delete("/entry/{entry_id}")(self.delete_entry)
        self.app.get("/list", response_model=EntryPage)(self.get_entries)
        self.app.get("/teams", response_model=List[int])(self.get_teams)
        self.app.get("/teams/{team}",
                     response_model=TeamData)(self.get_team_data)

        parent_app.mount(prefix, self.app)

    async def get_team_data(
        self, team: int = Path(..., title="The team to fetch data on")
    ) -> TeamData:
        """
        This method is long and disgusting.
        Any attempts to clean it up or increase speed ar encouraged.
        """

        entries: List[ScoutEntryID] = await self.database.get_entries(team=team
                                                                      )
        num_entries = len(entries)

        if num_entries == 0:
            raise HTTPException(status_code=404,
                                detail=f"No entries found on team {team}")

        scores = defaultdict(int)
        climb_times: List[float] = []
        defense_time: float = 0

        for entry in entries:
            scores["auto_upper_scored"] += entry.auto_uppergoal_scored
            scores["auto_upper_missed"] += entry.auto_uppergoal_missed
            scores["auto_lower_scored"] += entry.auto_lowergoal_scored
            scores["teleop_upper_scored"] += entry.teleop_uppergoal_scored
            scores["teleop_upper_missed"] += entry.teleop_uppergoal_missed
            scores["teleop_lower_scored"] += entry.teleop_lowergoal_scored
            scores["auto_crossed_line"] += 1 if entry.auto_crossed_line else 0
            scores["climb_attempts"] += 1 if entry.hang_attempted else 0
            scores["climb_successes"] += 1 if entry.hang_succeeded else 0
            scores["downs"] += 1 if entry.down_time > 0 else 0
            scores["fouls"] += 1 if entry.received_foul else 0
            defense_time += entry.defending_time

            if entry.hang_time:
                climb_times.append(entry.hang_time)

        try:
            # try to fetch OPR

            opr = Event_OPRS(**(await self.tba_client.get_event_oprs(
                event_key=EventKey(os.environ["event_key"])))).oprs.get(
                    TeamKey.from_team_number(team))
        except (cabbagescout.errors.HTTPException, ValidationError):
            opr = None

        aum = scores.get("auto_upper_missed")
        tum = scores.get("teleop_upper_missed")

        auto_upper = scores.get("auto_upper_scored")
        teleop_upper = scores.get("teleop_upper_scored")

        ca = scores.get("climb_attempts")
        ct = len(climb_times)

        data = TeamData(
            auto_line_rate=scores.get("auto_crossed_line") / num_entries,
            climb_success_rate=(scores.get("climb_successes") /
                                ca) if ca else 0,
            climb_speed=sum(climb_times) / ct if ct else -1,
            auto=TeamData.Scoring(
                uppergoal_scored=auto_upper / num_entries,
                uppergoal_rate=(auto_upper / aum) if aum else 1,
                lowergoal_scored=scores.get("auto_lower_scored") / num_entries,
            ),
            teleop=TeamData.Scoring(
                uppergoal_scored=teleop_upper / num_entries,
                uppergoal_rate=(teleop_upper / tum) if tum else 1,
                lowergoal_scored=scores.get("teleop_lower_scored") /
                num_entries,
            ),
            down_rate=scores.get("downs") / num_entries,
            foul_rate=scores.get("fouls") / num_entries,
            defense_rate=defense_time / (num_entries * 165.0),
        )

        if opr:
            data.opr = opr

        return data

    async def get_entry(
        self,
        entry_id: int = Path(...,
                             alias="entry_id",
                             title="The ID of the entry to query"),
    ) -> ScoutEntryID:
        return await self.database.get_entry(entry_id)

    async def edit_entry(
        self,
        entry: ScoutEntry,
        _id: int = Path(...,
                        alias="entry_id",
                        title="The ID of the entry to edit"),
    ) -> None:
        await self.assert_timestamp_valid(entry.timestamp)
        await self.database.edit_entry(_id, entry)

    async def delete_entry(
        self,
        _id: int = Path(...,
                        alias="entry_id",
                        title="The ID of the entry to delete"),
    ) -> None:
        await self.database.delete_entry(_id)

    async def get_entries(
        self,
        *,
        match: int = Query(
            None,
            ge=1,
            title="The match number of a single event of qualifiers"),
        team: int = Query(None,
                          ge=1,
                          le=9999,
                          title="The team number of the scouted team"),
        page: int = Query(1, ge=1, title="The page number to query"),
        size: int = Query(20, ge=1, title="The size of each page"),
    ) -> EntryPage:
        # number of rows matching query
        rows = await self.database.count_rows(match=match, team=team)
        # number of pages in the query
        pages = ceil(rows / size)

        if page > pages:
            raise HTTPException(status_code=400,
                                detail="Page index out of range")

        entries = await self.database.get_entries(match=match,
                                                  team=team,
                                                  offset=(page - 1) * size,
                                                  limit=size)

        return EntryPage(pages=pages, entries=entries, lastPage=page == pages)

    async def get_teams(self) -> List[int]:
        return await self.database.get_teams()

    async def add_entry(self, entry: ScoutEntry) -> int:
        await self.assert_timestamp_valid(entry.timestamp)

        snowflake = await self.generate_snowflake(entry)
        _entry = ScoutEntryID(**entry.json(), entry_id=snowflake)
        await self.database.add_entry(_entry)
        return snowflake

    async def to_csv(self):
        return await self.database.to_csv()

    async def assert_timestamp_valid(self, ts: float):
        now = datetime.datetime.utcnow()
        week_past = (now - datetime.timedelta(weeks=1)).timestamp()
        minute_future = (now + datetime.timedelta(minutes=1)).timestamp()

        print(f"past: {week_past}\nnow:  {ts}\npres: {minute_future}")

        if not (week_past <= ts <= minute_future):
            raise HTTPException(status_code=400,
                                detail="Timestamp out of range")