Add a page for each cache

These pages will list missing groups and keys in the future, which we
won't be able to fit in the table.

Signed-off-by: Graham <gpe@openrs2.org>
pull/132/head
Graham 3 years ago
parent 47b1bd5bf0
commit aa7b59e4b9
  1. 60
      archive/src/main/kotlin/org/openrs2/archive/cache/CacheExporter.kt
  2. 16
      archive/src/main/kotlin/org/openrs2/archive/web/CachesController.kt
  3. 1
      archive/src/main/kotlin/org/openrs2/archive/web/WebServer.kt
  4. 20
      archive/src/main/resources/org/openrs2/archive/templates/caches/index.html
  5. 69
      archive/src/main/resources/org/openrs2/archive/templates/caches/show.html
  6. 23
      archive/src/main/resources/org/openrs2/archive/templates/layout.html

@ -48,6 +48,7 @@ public class CacheExporter @Inject constructor(
val build: Int?,
val timestamp: Instant?,
val name: String?,
val description: String?,
val archiveStats: ArchiveStats?,
val groupStats: GroupStats?
)
@ -109,7 +110,7 @@ public class CacheExporter @Inject constructor(
null
}
caches += Cache(id, game, build, timestamp, name, archiveStats, groupStats)
caches += Cache(id, game, build, timestamp, name, description = null, archiveStats, groupStats)
}
caches
@ -118,6 +119,63 @@ public class CacheExporter @Inject constructor(
}
}
public suspend fun get(id: Int): Cache? {
return database.execute { connection ->
connection.prepareStatement(
"""
SELECT
g.name, m.build, m.timestamp, m.name, m.description,
a.indexes, a.valid_indexes, gs.groups, gs.valid_groups, gs.keys, gs.valid_keys
FROM master_indexes m
JOIN games g ON g.id = m.game_id
JOIN containers c ON c.id = m.container_id
LEFT JOIN master_index_archive_stats a ON a.master_index_id = m.id
LEFT JOIN master_index_group_stats gs ON gs.master_index_id = m.id
WHERE m.id = ?
""".trimIndent()
).use { stmt ->
stmt.setInt(1, id)
stmt.executeQuery().use { rows ->
if (!rows.next()) {
return@execute null
}
val game = rows.getString(1)
var build: Int? = rows.getInt(2)
if (rows.wasNull()) {
build = null
}
val timestamp = rows.getTimestamp(3)?.toInstant()
val name = rows.getString(4)
val description = rows.getString(5)
val indexes = rows.getLong(6)
val archiveStats = if (!rows.wasNull()) {
val validIndexes = rows.getLong(7)
ArchiveStats(indexes, validIndexes)
} else {
null
}
val groups = rows.getLong(8)
val groupStats = if (!rows.wasNull()) {
val validGroups = rows.getLong(9)
val keys = rows.getLong(10)
val validKeys = rows.getLong(11)
GroupStats(groups, validGroups, keys, validKeys)
} else {
null
}
return@execute Cache(id, game, build, timestamp, name, description, archiveStats, groupStats)
}
}
}
}
public suspend fun export(id: Int, store: Store) {
database.execute { connection ->
connection.prepareStatement(

@ -26,6 +26,22 @@ public class CachesController @Inject constructor(
call.respond(ThymeleafContent("caches/index.html", mapOf("caches" to caches)))
}
public suspend fun show(call: ApplicationCall) {
val id = call.parameters["id"]?.toIntOrNull()
if (id == null) {
call.respond(HttpStatusCode.NotFound)
return
}
val cache = exporter.get(id)
if (cache == null) {
call.respond(HttpStatusCode.NotFound)
return
}
call.respond(ThymeleafContent("caches/show.html", mapOf("cache" to cache)))
}
public suspend fun export(call: ApplicationCall) {
val id = call.parameters["id"]?.toIntOrNull()
if (id == null) {

@ -43,6 +43,7 @@ public class WebServer @Inject constructor(
routing {
get("/caches") { cachesController.index(call) }
get("/caches/{id}") { cachesController.show(call) }
get("/caches/{id}.zip") { cachesController.export(call) }
get("/caches/{id}.json") { cachesController.exportKeys(call) }
}

@ -1,21 +1,13 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<title>OpenRS2 Archive</title>
<head th:replace="layout.html :: head(title='Caches')">
<title>Caches - OpenRS2 Archive</title>
<link rel="stylesheet" href="/webjars/bootstrap/css/bootstrap.min.css" />
</head>
<body>
<nav class="navbar navbar-dark bg-dark mb-4">
<div class="container">
<a class="navbar-brand" href="/">OpenRS2 Archive</a>
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link active" href="/caches">Caches</a>
</li>
</ul>
</div>
</nav>
<nav th:replace="layout.html :: nav(active='caches')"></nav>
<main class="container">
<h1>Caches</h1>
<div class="table-responsive">
<table class="table table-striped table-bordered table-hover">
<thead class="thead-dark">
@ -27,7 +19,7 @@
<th>Indexes</th>
<th>Groups</th>
<th>Keys<sup><a href="#empty-locs">1</a></sup></th>
<th>Download</th>
<th>Links</th>
</tr>
</thead>
<tbody>
@ -62,6 +54,8 @@
class="btn btn-primary btn-sm">Cache</a>
<a th:href="${'/caches/' + cache.id + '.json'}"
class="btn btn-primary btn-sm">Keys</a>
<a th:href="${'/caches/' + cache.id}"
class="btn btn-secondary btn-sm">More</a>
</div>
</td>
</tr>

@ -0,0 +1,69 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head th:replace="layout.html :: head(title='Cache')">
<title>Cache - OpenRS2 Archive</title>
<link rel="stylesheet" href="/webjars/bootstrap/css/bootstrap.min.css" />
</head>
<body>
<nav th:replace="layout.html :: nav"></nav>
<main class="container">
<h1>Cache</h1>
<!--/*@thymesVar id="cache" type="org.openrs2.archive.cache.CacheExporter.Cache"*/-->
<table class="table table-striped table-bordered table-hover">
<tr class="thead-dark">
<th>Game</th>
<td th:text="${cache.game}">runescape</td>
</tr>
<tr class="thead-dark">
<th>Build</th>
<td th:text="${cache.build}">550</td>
</tr>
<tr class="thead-dark">
<th>Timestamp</th>
<td th:text="${#temporals.format(cache.timestamp, 'yyyy-MM-dd HH:mm:ss')}"></td>
</tr>
<tr class="thead-dark">
<th>Name</th>
<td th:text="${cache.name}"></td>
</tr>
<tr class="thead-dark">
<th>Description</th>
<td th:text="${cache.description}"></td>
</tr>
<tr class="thead-dark">
<th>Indexes</th>
<td th:class="${cache.archiveStats}? (${cache.archiveStats.allIndexesValid}? 'table-success' : 'table-danger')"
th:text="${cache.archiveStats}? ${cache.archiveStats.validIndexes} + ' / ' + ${cache.archiveStats.indexes} + ' (' + ${#numbers.formatPercent(cache.archiveStats.validIndexesFraction, 1, 2)} + ')' : 'Calculating...'">
Calculating...
</td>
</tr>
<tr class="thead-dark">
<th>Groups</th>
<td th:class="${cache.groupStats}? (${cache.groupStats.allGroupsValid}? 'table-success' : 'table-warning')"
th:text="${cache.groupStats}? ${#numbers.formatInteger(cache.groupStats.validGroups, 1, 'COMMA')} + ' / ' + ${#numbers.formatInteger(cache.groupStats.groups, 1, 'COMMA')} + ' (' + ${#numbers.formatPercent(cache.groupStats.validGroupsFraction, 1, 2)} + ')' : 'Calculating...'">
Calculating...
</td>
</tr>
<tr class="thead-dark">
<th>Keys<sup><a href="/caches#empty-locs">1</a></sup></th>
<td th:class="${cache.groupStats}? (${cache.groupStats.allKeysValid}? 'table-success' : 'table-warning')"
th:text="${cache.groupStats}? ${#numbers.formatInteger(cache.groupStats.validKeys, 1, 'COMMA')} + ' / ' + ${#numbers.formatInteger(cache.groupStats.keys, 1, 'COMMA')} + ' (' + ${#numbers.formatPercent(cache.groupStats.validKeysFraction, 1, 2)} + ')' : 'Calculating...'">
Calculating...
</td>
</tr>
<tr class="thead-dark">
<th>Download</th>
<td>
<div class="btn-group">
<a th:href="${'/caches/' + cache.id + '.zip'}"
class="btn btn-primary btn-sm">Cache</a>
<a th:href="${'/caches/' + cache.id + '.json'}"
class="btn btn-primary btn-sm">Keys</a>
</div>
</td>
</tr>
</table>
</main>
</body>
</html>

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head th:fragment="head">
<!--/*@thymesVar id="title" type="java.lang.String"*/-->
<title th:text="${title}? ${title} + ' - OpenRS2 Archive' : 'OpenRS2 Archive'">OpenRS2 Archive</title>
<link rel="stylesheet" href="/webjars/bootstrap/css/bootstrap.min.css" />
</head>
<body>
<nav class="navbar navbar-dark bg-dark mb-4" th:fragment="nav">
<div class="container">
<a class="navbar-brand" href="/">OpenRS2 Archive</a>
<ul class="navbar-nav mr-auto">
<!--/*@thymesVar id="active" type="java.lang.String"*/-->
<li class="nav-item" th:classappend="${active == 'caches'}? 'active'">
<a class="nav-link" href="/caches">Caches</a>
</li>
</ul>
</div>
</nav>
<main class="container">
</main>
</body>
</html>
Loading…
Cancel
Save