Skip to content

Commit

Permalink
Show archives on front page (#338)
Browse files Browse the repository at this point in the history
  • Loading branch information
shaldengeki authored Aug 4, 2024
1 parent 38149ec commit a3fefcd
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 8 deletions.
4 changes: 3 additions & 1 deletion ark_nova_stats/api/gql/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
from ark_nova_stats.api.gql.types.game_log import (
game_log_field,
game_logs_field,
recent_game_log_archives_field,
recent_game_logs_field,
stats_field,
submit_game_logs_field,
)
from ark_nova_stats.models import GameLog, User
from ark_nova_stats.models import GameLog, GameLogArchive, User


def Schema(app: flask.Flask):
Expand All @@ -19,6 +20,7 @@ def Schema(app: flask.Flask):
"gameLog": game_log_field(GameLog),
"gameLogs": game_logs_field(GameLog),
"recentGameLogs": recent_game_logs_field(GameLog),
"recentGameLogArchives": recent_game_log_archives_field(GameLogArchive),
"stats": stats_field(GameLog, User),
},
),
Expand Down
70 changes: 68 additions & 2 deletions ark_nova_stats/api/gql/types/game_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from ark_nova_stats.bga_log_parser.game_log import GameLog as ParsedGameLog
from ark_nova_stats.config import app, db
from ark_nova_stats.models import GameLog as GameLogModel
from ark_nova_stats.models import GameLogArchive as GameLogArchiveModel
from ark_nova_stats.models import GameLogArchiveType
from ark_nova_stats.models import User as UserModel

Expand Down Expand Up @@ -139,7 +140,7 @@ def game_logs_field(

def fetch_recent_game_logs(game_log_model: Type[GameLogModel]) -> list[GameLogModel]:
return (
game_log_model.query.order_by(desc(game_log_model.created_at)).limit(10).all()
game_log_model.query.order_by(desc(game_log_model.bga_table_id)).limit(10).all()
)


Expand Down Expand Up @@ -241,6 +242,42 @@ def stats_field(
)


def game_log_archive_archive_type_resolver(
game_log_archive: GameLogArchiveModel, info, **args
) -> str:
return GameLogArchiveType(game_log_archive.archive_type).name


def game_log_archive_size_bytes_resolver(
game_log_archive: GameLogArchiveModel, info, **args
) -> int:
return game_log_archive.size_bytes


def game_log_archive_num_game_logs_resolver(
game_log_archive: GameLogArchiveModel, info, **args
) -> int:
return game_log_archive.num_game_logs


def game_log_archive_num_users_resolver(
game_log_archive: GameLogArchiveModel, info, **args
) -> int:
return game_log_archive.num_users


def game_log_archive_max_game_log_resolver(
game_log_archive: GameLogArchiveModel, info, **args
) -> Optional[GameLogModel]:
return game_log_archive.last_game_log()


def game_log_archive_created_at_resolver(
game_log_archive: GameLogArchiveModel, info, **args
) -> int:
return int(round(game_log_archive.created_at.timestamp()))


def game_log_archive_fields() -> dict[str, GraphQLField]:
archive_types = set(t.name for t in GameLogArchiveType)
return {
Expand All @@ -251,6 +288,7 @@ def game_log_archive_fields() -> dict[str, GraphQLField]:
"archiveType": GraphQLField(
GraphQLNonNull(GraphQLString),
description=f"Type of game logs. Possible values are: {', '.join(archive_types)}.",
resolve=game_log_archive_archive_type_resolver,
),
"url": GraphQLField(
GraphQLNonNull(GraphQLString),
Expand All @@ -259,22 +297,27 @@ def game_log_archive_fields() -> dict[str, GraphQLField]:
"sizeBytes": GraphQLField(
GraphQLNonNull(GraphQLInt),
description=f"Size of archive, in bytes.",
resolve=game_log_archive_size_bytes_resolver,
),
"numGameLogs": GraphQLField(
GraphQLNonNull(GraphQLInt),
description=f"Number of game logs in this archive.",
resolve=game_log_archive_num_game_logs_resolver,
),
"numUsers": GraphQLField(
GraphQLNonNull(GraphQLInt),
description=f"Number of users in this archive.",
resolve=game_log_archive_num_users_resolver,
),
"maxGameLog": GraphQLField(
GraphQLNonNull(GraphQLInt),
game_log_type,
description=f"The game log with the highest BGA table ID.",
resolve=game_log_archive_max_game_log_resolver,
),
"createdAt": GraphQLField(
GraphQLInt,
description="UNIX timestamp for when this archive was created.",
resolve=game_log_archive_created_at_resolver,
),
}

Expand All @@ -284,3 +327,26 @@ def game_log_archive_fields() -> dict[str, GraphQLField]:
description="An archive of game logs.",
fields=game_log_archive_fields,
)


def fetch_recent_game_log_archives(
game_log_archive_model: Type[GameLogArchiveModel],
) -> list[GameLogArchiveModel]:
return (
game_log_archive_model.query.order_by(desc(game_log_archive_model.created_at))
.limit(10)
.all()
)


def recent_game_log_archives_field(
game_log_archive_model: Type[GameLogArchiveModel],
) -> GraphQLField:
return GraphQLField(
GraphQLNonNull(GraphQLList(game_log_archive_type)),
description="List recent game log archives.",
args={},
resolve=lambda root, info, **args: fetch_recent_game_log_archives(
game_log_archive_model
),
)
7 changes: 5 additions & 2 deletions ark_nova_stats/frontend/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ ts_project(
"src/**/*.ts",
"src/**/*.jsx",
"src/**/*.js",
"tsconfig.json",
],
),
) + [
"tsconfig.json",
],
allow_js = True,
assets = [
"src/App.src.css",
Expand Down Expand Up @@ -114,6 +115,7 @@ jest_test(
"src/DateUtils.test.js",
"src/components/DatabaseStatistics.js",
"src/components/DatabaseStatistics.test.js",
"src/components/GameLogArchivesTable.js",
"src/components/GameLogsTable.js",
"src/components/NavBar.js",
"src/components/PageContainer.js",
Expand All @@ -122,6 +124,7 @@ jest_test(
"src/globals.d.ts",
"src/setupTests.js",
"src/types/GameLog.js",
"src/types/GameLogArchive.js",
"src/types/Stats.js",
"src/types/User.js",
"src/views/HomeView.js",
Expand Down
43 changes: 43 additions & 0 deletions ark_nova_stats/frontend/src/components/GameLogArchivesTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import { Link } from 'react-router-dom';

import {getDate} from '../DateUtils';
import GameLogArchive from '../types/GameLogArchive';
import User from '../types/User';
import Table from './Table';

type GameLogArchivesTableParams = {
gameLogArchives: GameLogArchive[];
}

const GameLogArchivesTable = ({gameLogArchives}: GameLogArchivesTableParams) => {
let innerContent = <p></p>;
if (!gameLogArchives) {
innerContent = <p>Error: game log archives could not be retrieved!</p>;
} else {
var rows = gameLogArchives.map((gameLogArchive: GameLogArchive) => {
let latestTablePlayers = gameLogArchive.maxGameLog.users.map((u: User) => { return u.name }).join(', ');
let latestTableDescription = <Link to={"https://boardgamearena.com/table?table=" + gameLogArchive.maxGameLog.bgaTableId}>{gameLogArchive.maxGameLog.bgaTableId}, between {latestTablePlayers}</Link>;
return {
"Link": <Link to={gameLogArchive.url}>Download</Link>,
"Date": getDate(gameLogArchive.createdAt),
"Type": gameLogArchive.archiveType,
"Games": gameLogArchive.numGameLogs,
"Users": gameLogArchive.numUsers,
"Latest table": latestTableDescription,
"Size (MB)": Math.round((gameLogArchive.sizeBytes) / (1024 * 1024)),
}
});
innerContent = (
<Table
cols={["Link", "Date", "Type", "Games", "Users", "Latest table", "Size, MB"]}
rows={rows}
key="game-log-archives"
showFilters={false}
/>
);
}
return innerContent
}

export default GameLogArchivesTable;
25 changes: 25 additions & 0 deletions ark_nova_stats/frontend/src/types/GameLogArchive.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import GameLog, {emptyGameLog} from "./GameLog";

type GameLogArchive = {
id: number;
archiveType: string;
url: string;
sizeBytes: number;
numGameLogs: number;
numUsers: number;
maxGameLog: GameLog;
createdAt: number;
}

export const emptyGameLogArchive: GameLogArchive = {
id: 0,
archiveType: "",
url: "",
sizeBytes: 0,
numGameLogs: 0,
numUsers: 0,
maxGameLog: emptyGameLog,
createdAt: 0,
}

export default GameLogArchive;
22 changes: 22 additions & 0 deletions ark_nova_stats/frontend/src/views/HomeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import PageContainer from '../components/PageContainer';
import PageTitle from "../components/PageTitle";
import DatabaseStatistics from '../components/DatabaseStatistics';
import GameLogsTable from '../components/GameLogsTable';
import GameLogArchivesTable from '../components/GameLogArchivesTable';
import Stats from '../types/Stats';
import GameLog from '../types/GameLog';
import GameLogArchive from '../types/GameLogArchive';

export const HOME_VIEW_QUERY = gql`
query FetchHome {
Expand All @@ -23,6 +25,21 @@ export const HOME_VIEW_QUERY = gql`
name
}
}
recentGameLogArchives {
id
archiveType
url
sizeBytes
numGameLogs
numUsers
maxGameLog {
bgaTableId
users {
name
}
}
createdAt
}
}
`;

Expand All @@ -43,6 +60,7 @@ const HomeView = () => {
else {
var stats: Stats = data.stats;
var gameLogs: GameLog[] = data.recentGameLogs;
var gameLogArchives: GameLogArchive[] = data.recentGameLogArchives;
innerContent = (
<div>
<div className={"py-2"}>
Expand All @@ -54,6 +72,10 @@ const HomeView = () => {
<h2 className={"text-xl"}>Recently-submitted games:</h2>
<GameLogsTable gameLogs={gameLogs} />
</div>
<div className={"py-2"}>
<h2 className={"text-xl"}>Recent game log archives:</h2>
<GameLogArchivesTable gameLogArchives={gameLogArchives} />
</div>
</div>
);
}
Expand Down
6 changes: 5 additions & 1 deletion ark_nova_stats/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import datetime
import enum
from typing import Optional

from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
Expand Down Expand Up @@ -93,7 +94,7 @@ class User(db.Model): # type: ignore
)


class GameLogArchiveType(enum.Enum):
class GameLogArchiveType(enum.IntEnum):
GAME_LOG_ARCHIVE_TYPE_UNKNOWN = 0
RAW_BGA_JSONL = 1

Expand All @@ -112,3 +113,6 @@ class GameLogArchive(db.Model): # type: ignore
db.TIMESTAMP(timezone=True),
default=lambda: datetime.datetime.now(tz=datetime.timezone.utc),
)

def last_game_log(self) -> Optional[GameLog]:
return GameLog.query.where(GameLog.id == self.last_game_log_id).first()
4 changes: 2 additions & 2 deletions ark_nova_stats/worker/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def archive_logs_to_tigris(
archive_type.name
+ "_"
+ datetime.datetime.now(tz=datetime.timezone.utc).strftime("%Y_%m_%d")
+ ".gz"
+ ".jsonl.gz"
)

# Upload the compressed gzip jsonl to Tigris.
Expand All @@ -68,7 +68,7 @@ def archive_logs_to_tigris(
os.getenv("BUCKET_NAME"),
archive_type.name + "/" + filename,
)
url = f"{os.getenv('TIGRIS_CUSTOM_DOMAIN_HOST')}/{filename}"
url = f"{os.getenv('TIGRIS_CUSTOM_DOMAIN_HOST')}/{archive_type.name}/{filename}"
logger.info(f"Uploaded game log archive at: {url} with size: {size_bytes}")

# Record this archive in the database.
Expand Down

0 comments on commit a3fefcd

Please sign in to comment.