implement logs support in interface

This commit is contained in:
Evgenii Alekseev 2022-11-21 01:33:24 +02:00
parent 88c9b29e74
commit abd77e655b
16 changed files with 187 additions and 40 deletions

View File

@ -40,7 +40,6 @@
</div> </div>
<table id="packages" class="table table-striped table-hover" <table id="packages" class="table table-striped table-hover"
data-click-to-select="true"
data-export-options='{"fileName": "packages"}' data-export-options='{"fileName": "packages"}'
data-page-list="[10, 25, 50, 100, all]" data-page-list="[10, 25, 50, 100, all]"
data-page-size="10" data-page-size="10"
@ -76,14 +75,14 @@
<div class="container"> <div class="container">
<footer class="d-flex flex-wrap justify-content-between align-items-center border-top"> <footer class="d-flex flex-wrap justify-content-between align-items-center border-top">
<ul class="nav"> <ul class="nav">
<li><a class="nav-link" href="https://github.com/arcan1s/ahriman" title="sources">ahriman</a></li> <li><a class="nav-link" href="https://github.com/arcan1s/ahriman" title="sources"><i class="bi bi-github"></i> ahriman</a></li>
<li><a class="nav-link" href="https://github.com/arcan1s/ahriman/releases" title="releases list">releases</a></li> <li><a class="nav-link" href="https://github.com/arcan1s/ahriman/releases" title="releases list">releases</a></li>
<li><a class="nav-link" href="https://github.com/arcan1s/ahriman/issues" title="issues tracker">report a bug</a></li> <li><a class="nav-link" href="https://github.com/arcan1s/ahriman/issues" title="issues tracker">report a bug</a></li>
</ul> </ul>
{% if index_url is not none %} {% if index_url is not none %}
<ul class="nav"> <ul class="nav">
<li><a class="nav-link" href="{{ index_url }}" title="repo index">repo index</a></li> <li><a class="nav-link" href="{{ index_url }}" title="repo index"><i class="bi bi-house"></i> repo index</a></li>
</ul> </ul>
{% endif %} {% endif %}
@ -92,7 +91,7 @@
{{ auth.control|safe }} {{ auth.control|safe }}
{% else %} {% else %}
<form action="/api/v1/logout" method="post"> <form action="/api/v1/logout" method="post">
<button class="btn btn-link" style="text-decoration: none">logout ({{ auth.username }})</button> <button class="btn btn-link" style="text-decoration: none"><i class="bi bi-box-arrow-right"></i> logout ({{ auth.username }})</button>
</form> </form>
{% endif %} {% endif %}
{% endif %} {% endif %}
@ -110,6 +109,8 @@
{% include "build-status/package-add-modal.jinja2" %} {% include "build-status/package-add-modal.jinja2" %}
{% include "build-status/package-info-modal.jinja2" %}
{% include "build-status/table.jinja2" %} {% include "build-status/table.jinja2" %}
</body> </body>

View File

@ -1,16 +1,16 @@
<div id="failed-form" tabindex="-1" role="dialog" class="modal fade"> <div id="failed-form" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header bg-danger"> <div class="modal-header bg-danger text-white">
<h4 class="modal-title">failed</h4> <h4 id="error-title" class="modal-title"></h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<p>Packages update has failed.</p> <p id="error-description"></p>
<p id="error-details"></p> <p id="error-details"></p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">close</button> <button type="button" class="btn btn-primary" data-bs-dismiss="modal"><i class="bi bi-x"></i> close</button>
</div> </div>
</div> </div>
</div> </div>
@ -18,10 +18,14 @@
<script> <script>
const failedForm = $("#failed-form"); const failedForm = $("#failed-form");
const errorDescription = $("#error-description");
const errorDetails = $("#error-details"); const errorDetails = $("#error-details");
const errorTitle = $("#error-title");
failedForm.on("hidden.bs.modal", () => { reload(); }); failedForm.on("hidden.bs.modal", () => { reload(); });
function showFailure(details) { function showFailure(title, description, details) {
errorTitle.text(title);
errorDescription.text(description);
errorDetails.text(details); errorDetails.text(details);
failedForm.modal("show"); failedForm.modal("show");
} }

View File

@ -3,7 +3,7 @@
<div class="modal-content"> <div class="modal-content">
<form action="/api/v1/login" method="post"> <form action="/api/v1/login" method="post">
<div class="modal-header"> <div class="modal-header">
<h4 class="modal-title">login</h4> <h4 class="modal-title">Login</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@ -21,7 +21,7 @@
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-primary">login</button> <button class="btn btn-primary"><i class="bi bi-person"></i> login</button>
</div> </div>
</form> </form>
</div> </div>

View File

@ -2,7 +2,7 @@
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h4 class="modal-title">add new packages</h4> <h4 class="modal-title">Add new packages</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@ -15,9 +15,9 @@
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">close</button> <button type="button" class="btn btn-primary" data-bs-dismiss="modal" onclick="addPackages()"><i class="bi bi-play"></i> add</button>
<button type="button" class="btn btn-success" data-bs-dismiss="modal" onclick="requestPackages()">request</button> <button type="button" class="btn btn-success" data-bs-dismiss="modal" onclick="requestPackages()"><i class="bi bi-plus"></i> request</button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" onclick="addPackages()">add</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><i class="bi bi-x"></i> close</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,71 @@
<div id="package-info-form" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div id="package-info-modal-header" class="modal-header">
<h4 id="package-info" class="modal-title"></h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div>
<div class="modal-body">
<pre class="pre-scrollable language-logs"><code id="package-info-logs" class="language-logs"></code><button id="copy-btn" type="button" class="btn language-logs" onclick="copyLogs()"><i class="bi bi-clipboard"></i> copy</button></pre>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="showLogs()"><i class="bi bi-arrow-clockwise"></i> reload</button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal"><i class="bi bi-x"></i> close</button>
</div>
</div>
</div>
</div>
<script>
const packageInfo = $("#package-info");
const packageInfoForm = $("#package-info-form");
const packageInfoHeader = $("#package-info-modal-header");
const packageInfoLogs = $("#package-info-logs");
const packageInfoLogsCopyButton = $("#copy-btn");
async function copyLogs() {
const logs = packageInfoLogs.text();
await navigator.clipboard.writeText(logs);
packageInfoLogsCopyButton.html("<i class=\"bi bi-clipboard-check\"></i> copied");
setTimeout(()=> {
packageInfoLogsCopyButton.html("<i class=\"bi bi-clipboard\"></i> copy");
}, 2000);
}
function showLogs(package) {
const isPackageBaseSet = package !== undefined;
if (isPackageBaseSet)
packageInfoForm.data("package", package); // set package base as currently used
else
package = packageInfoForm.data("package"); // read package base from the current window attribute
const headerClass = status => {
if (status === "pending") return ["bg-warning"];
if (status === "building") return ["bg-warning"];
if (status === "failed") return ["bg-danger", "text-white"];
if (status === "success") return ["bg-success", "text-white"];
return ["bg-secondary", "text-white"];
};
$.ajax({
url: `/api/v1/packages/${package}/logs`,
type: "GET",
dataType: "json",
success: response => {
packageInfo.text(`${response.package_base} ${response.status.status} at ${new Date(1000 * response.status.timestamp).toISOString()}`);
packageInfoLogs.text(response.logs);
packageInfoHeader.removeClass();
packageInfoHeader.addClass("modal-header");
headerClass(response.status.status).forEach((clz) => packageInfoHeader.addClass(clz));
if (isPackageBaseSet) packageInfoForm.modal("show"); // we don't need to show window again
},
error: (jqXHR, _, errorThrown) => {
// show failed modal in case if first time loading
if (isPackageBaseSet) showFailure("Load failure", `Could not load package ${package} logs:`, errorThrown);
},
});
}
</script>

View File

@ -1,16 +1,16 @@
<div id="success-form" tabindex="-1" role="dialog" class="modal fade"> <div id="success-form" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header bg-success"> <div class="modal-header bg-success text-white">
<h4 class="modal-title">success</h4> <h4 id="success-title" class="modal-title"></h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<p>Packages update has been run.</p> <p id="success-description"></p>
<ul id="success-details"></ul> <ul id="success-details"></ul>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">close</button> <button type="button" class="btn btn-primary" data-bs-dismiss="modal"><i class="bi bi-x"></i> close</button>
</div> </div>
</div> </div>
</div> </div>
@ -18,10 +18,14 @@
<script> <script>
const successForm = $("#success-form"); const successForm = $("#success-form");
const successDescription = $("#success-description");
const successDetails = $("#success-details"); const successDetails = $("#success-details");
const successTitle = $("#success-title");
successForm.on("hidden.bs.modal", () => { reload(); }); successForm.on("hidden.bs.modal", () => { reload(); });
function showSuccess(details) { function showSuccess(title, description, details) {
successTitle.text(title);
successDescription.text(description);
successDetails.empty().append(details); successDetails.empty().append(details);
successForm.modal("show"); successForm.modal("show");
} }

View File

@ -8,6 +8,7 @@
() => { () => {
removeButton.prop("disabled", !table.bootstrapTable("getSelections").length); removeButton.prop("disabled", !table.bootstrapTable("getSelections").length);
}); });
table.on("click-row.bs.table", (_, row) => { showLogs(row.id); });
const architectureBadge = $("#badge-architecture"); const architectureBadge = $("#badge-architecture");
const repositoryBadge = $("#badge-repository"); const repositoryBadge = $("#badge-repository");
@ -26,9 +27,11 @@
li.innerText = pkg; li.innerText = pkg;
return li; return li;
}); });
showSuccess(details); showSuccess("Success", `Package action at ${uri} has been run on:`, details);
},
error: (jqXHR, _, errorThrown) => {
showFailure("Action failed", `Package action request at ${uri} on ${packages} has failed:`, errorThrown);
}, },
error: (jqXHR, _, errorThrown) => { showFailure(errorThrown); },
}); });
} }
@ -38,7 +41,11 @@
function removePackages() { doPackageAction("/api/v1/service/remove", getSelection()); } function removePackages() { doPackageAction("/api/v1/service/remove", getSelection()); }
function updatePackages() { doPackageAction("/api/v1/service/add", getSelection()); } function updatePackages() {
const currentSelection = getSelection();
const url = currentSelection.length === 0 ? "/api/v1/service/update" : "/api/v1/service/add";
doPackageAction(url, getSelection());
}
function hideControls(hidden) { function hideControls(hidden) {
addButton.attr("hidden", hidden); addButton.attr("hidden", hidden);
@ -95,7 +102,7 @@
table.bootstrapTable("hideLoading"); table.bootstrapTable("hideLoading");
} else { } else {
// other errors // other errors
showFailure(errorThrown); showFailure("Load failure", "Could not load list of packages:", errorThrown);
} }
hideControls(true); hideControls(true);
}, },

View File

@ -19,10 +19,11 @@
<p>This repository is signed with <a href="https://pgp.mit.edu/pks/lookup?search=0x{{ pgp_key }}&fingerprint=on&op=index" title="key search">{{ pgp_key }}</a> by default.</p> <p>This repository is signed with <a href="https://pgp.mit.edu/pks/lookup?search=0x{{ pgp_key }}&fingerprint=on&op=index" title="key search">{{ pgp_key }}</a> by default.</p>
{% endif %} {% endif %}
<pre>$ cat /etc/pacman.conf <p>In order to use this repository edit your <code>/etc/pacman.conf</code> as following:</p>
[{{ repository }}]
<pre class="language-ini"><code id="pacman-conf" class="language-ini">[{{ repository }}]
Server = {{ link_path }} Server = {{ link_path }}
SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Package{% if has_package_signed %}Required{% else %}Never{% endif %} TrustedOnly</pre> SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Package{% if has_package_signed %}Required{% else %}Never{% endif %} TrustedOnly</code><button id="copy-btn" type="button" class="btn language-ini" onclick="copyPacmanConf()"><i class="bi bi-clipboard"></i> copy</button></pre>
</div> </div>
<div class="container"> <div class="container">
@ -83,17 +84,32 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa
<footer class="d-flex flex-wrap justify-content-between align-items-center border-top"> <footer class="d-flex flex-wrap justify-content-between align-items-center border-top">
<ul class="nav"> <ul class="nav">
{% if homepage is not none %} {% if homepage is not none %}
<li><a class="nav-link" href="{{ homepage }}" title="homepage">homepage</a></li> <li><a class="nav-link" href="{{ homepage }}" title="homepage"><i class="bi bi-house"></i> homepage</a></li>
{% endif %} {% endif %}
</ul> </ul>
<ul class="nav"> <ul class="nav">
<li><a class="nav-link" href="https://github.com/arcan1s/ahriman" title="sources">ahriman</a></li> <li><a class="nav-link" href="https://github.com/arcan1s/ahriman" title="sources"><i class="bi bi-github"></i> ahriman</a></li>
</ul> </ul>
</footer> </footer>
</div> </div>
{% include "utils/bootstrap-scripts.jinja2" %} {% include "utils/bootstrap-scripts.jinja2" %}
<script>
const pacmanConf = $("#pacman-conf");
const pacmanConfCopyButton = $("#copy-btn");
async function copyPacmanConf() {
const conf = pacmanConf.text();
await navigator.clipboard.writeText(conf);
pacmanConfCopyButton.html("<i class=\"bi bi-clipboard-check\"></i> copied");
setTimeout(() => {
pacmanConfCopyButton.html("<i class=\"bi bi-clipboard\"></i> copy");
}, 2000);
}
</script>
</body> </body>
</html> </html>

View File

@ -4,9 +4,10 @@
<script src="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.min.js"></script> <script src="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js" integrity="sha384-oBqDVmMz9ATKxIep9tiCxS/Z9fNfEXiDAYTujMAeBAsjFuCZSmKbSSUnQlmh/jp3" crossorigin="anonymous"></script>
<script src="https://unpkg.com/bootstrap-table@1.20.2/dist/bootstrap-table.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.min.js" integrity="sha384-IDwe1+LCz02ROU9k972gdyvl+AESN10+x7tBKgc9I5HFtuNz0wWnPclzo6p9vxnk" crossorigin="anonymous"></script>
<script src="https://unpkg.com/bootstrap-table@1.21.1/dist/bootstrap-table.min.js"></script>
<script src="https://unpkg.com/bootstrap-table@1.20.2/dist/extensions/export/bootstrap-table-export.min.js"></script> <script src="https://unpkg.com/bootstrap-table@1.21.1/dist/extensions/export/bootstrap-table-export.min.js"></script>
<script src="https://unpkg.com/bootstrap-table@1.20.2/dist/extensions/resizable/bootstrap-table-resizable.js"></script> <script src="https://unpkg.com/bootstrap-table@1.21.1/dist/extensions/resizable/bootstrap-table-resizable.js"></script>

View File

@ -1,9 +1,23 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" type="text/css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous" type="text/css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.3/font/bootstrap-icons.css" type="text/css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css" type="text/css">
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.20.2/dist/bootstrap-table.min.css" type="text/css"> <link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.21.1/dist/bootstrap-table.min.css" type="text/css">
<link href="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.css" rel="stylesheet"> <link href="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.css" rel="stylesheet">
<style> <style>
.pre-scrollable {
max-height: 680px;
overflow-y: scroll;
}
pre[class*="language-"] {
position: relative;
}
pre[class*="language-"] button{
position: absolute;
top: 0px;
right: 5px;
}
</style> </style>

View File

@ -74,6 +74,7 @@ setup(
"package/share/ahriman/templates/build-status/failed-modal.jinja2", "package/share/ahriman/templates/build-status/failed-modal.jinja2",
"package/share/ahriman/templates/build-status/login-modal.jinja2", "package/share/ahriman/templates/build-status/login-modal.jinja2",
"package/share/ahriman/templates/build-status/package-add-modal.jinja2", "package/share/ahriman/templates/build-status/package-add-modal.jinja2",
"package/share/ahriman/templates/build-status/package-info-modal.jinja2",
"package/share/ahriman/templates/build-status/success-modal.jinja2", "package/share/ahriman/templates/build-status/success-modal.jinja2",
"package/share/ahriman/templates/build-status/table.jinja2", "package/share/ahriman/templates/build-status/table.jinja2",
]), ]),

View File

@ -62,7 +62,7 @@ class Auth(LazyLogging):
Returns: Returns:
str: login control as html code to insert str: login control as html code to insert
""" """
return """<button type="button" class="btn btn-link" data-bs-toggle="modal" data-bs-target="#loginForm" style="text-decoration: none">login</button>""" return """<button type="button" class="btn btn-link" data-bs-toggle="modal" data-bs-target="#loginForm" style="text-decoration: none"><i class="bi bi-box-arrow-in-right"></i> login</button>"""
@classmethod @classmethod
def load(cls: Type[Auth], configuration: Configuration, database: SQLite) -> Auth: def load(cls: Type[Auth], configuration: Configuration, database: SQLite) -> Auth:

View File

@ -69,7 +69,7 @@ class OAuth(Mapping):
Returns: Returns:
str: login control as html code to insert str: login control as html code to insert
""" """
return """<a class="nav-link" href="/api/v1/login" title="login via OAuth2">login</a>""" return """<a class="nav-link" href="/api/v1/login" title="login via OAuth2"><i class="bi bi-google"></i> login</a>"""
@staticmethod @staticmethod
def get_provider(name: str) -> Type[aioauth_client.OAuth2Client]: def get_provider(name: str) -> Type[aioauth_client.OAuth2Client]:

View File

@ -18,7 +18,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from aiohttp.web import HTTPBadRequest, HTTPNoContent, Response, json_response from aiohttp.web import HTTPBadRequest, HTTPNoContent, Response, json_response
from aiohttp.web_exceptions import HTTPNotFound
from ahriman.core.exceptions import UnknownPackageError
from ahriman.models.log_record_id import LogRecordId from ahriman.models.log_record_id import LogRecordId
from ahriman.models.user_access import UserAccess from ahriman.models.user_access import UserAccess
from ahriman.web.views.base import BaseView from ahriman.web.views.base import BaseView
@ -58,10 +60,16 @@ class LogsView(BaseView):
Response: 200 with package logs on success Response: 200 with package logs on success
""" """
package_base = self.request.match_info["package"] package_base = self.request.match_info["package"]
try:
_, status = self.service.get(package_base)
except UnknownPackageError:
raise HTTPNotFound()
logs = self.service.get_logs(package_base) logs = self.service.get_logs(package_base)
response = { response = {
"package_base": package_base, "package_base": package_base,
"status": status.view(),
"logs": logs "logs": logs
} }
return json_response(response) return json_response(response)

View File

@ -327,6 +327,7 @@ def test_walk(resource_path_root: Path) -> None:
resource_path_root / "web" / "templates" / "build-status" / "failed-modal.jinja2", resource_path_root / "web" / "templates" / "build-status" / "failed-modal.jinja2",
resource_path_root / "web" / "templates" / "build-status" / "login-modal.jinja2", resource_path_root / "web" / "templates" / "build-status" / "login-modal.jinja2",
resource_path_root / "web" / "templates" / "build-status" / "package-add-modal.jinja2", resource_path_root / "web" / "templates" / "build-status" / "package-add-modal.jinja2",
resource_path_root / "web" / "templates" / "build-status" / "package-info-modal.jinja2",
resource_path_root / "web" / "templates" / "build-status" / "success-modal.jinja2", resource_path_root / "web" / "templates" / "build-status" / "success-modal.jinja2",
resource_path_root / "web" / "templates" / "build-status" / "table.jinja2", resource_path_root / "web" / "templates" / "build-status" / "table.jinja2",
resource_path_root / "web" / "templates" / "static" / "favicon.ico", resource_path_root / "web" / "templates" / "static" / "favicon.ico",

View File

@ -2,6 +2,7 @@ import pytest
from aiohttp.test_utils import TestClient from aiohttp.test_utils import TestClient
from ahriman.models.build_status import BuildStatusEnum
from ahriman.models.package import Package from ahriman.models.package import Package
from ahriman.models.user_access import UserAccess from ahriman.models.user_access import UserAccess
from ahriman.web.views.status.logs import LogsView from ahriman.web.views.status.logs import LogsView
@ -23,6 +24,11 @@ async def test_delete(client: TestClient, package_ahriman: Package, package_pyth
""" """
must delete logs for package must delete logs for package
""" """
await client.post(f"/api/v1/packages/{package_ahriman.base}",
json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()})
await client.post(f"/api/v1/packages/{package_python_schedule.base}",
json={"status": BuildStatusEnum.Success.value, "package": package_python_schedule.view()})
await client.post(f"/api/v1/packages/{package_ahriman.base}/logs", await client.post(f"/api/v1/packages/{package_ahriman.base}/logs",
json={"created": 0.001, "message": "message", "process_id": 42}) json={"created": 0.001, "message": "message", "process_id": 42})
await client.post(f"/api/v1/packages/{package_python_schedule.base}/logs", await client.post(f"/api/v1/packages/{package_python_schedule.base}/logs",
@ -44,6 +50,8 @@ async def test_get(client: TestClient, package_ahriman: Package) -> None:
""" """
must get logs for package must get logs for package
""" """
await client.post(f"/api/v1/packages/{package_ahriman.base}",
json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()})
await client.post(f"/api/v1/packages/{package_ahriman.base}/logs", await client.post(f"/api/v1/packages/{package_ahriman.base}/logs",
json={"created": 0.001, "message": "message", "process_id": 42}) json={"created": 0.001, "message": "message", "process_id": 42})
@ -51,20 +59,31 @@ async def test_get(client: TestClient, package_ahriman: Package) -> None:
assert response.status == 200 assert response.status == 200
logs = await response.json() logs = await response.json()
assert logs == {"package_base": package_ahriman.base, "logs": "message"} assert logs["logs"] == "message"
async def test_get_not_foud(client: TestClient, package_ahriman: Package) -> None:
"""
must return not found for missing package
"""
response = await client.get(f"/api/v1/packages/{package_ahriman.base}/logs")
assert response.status == 404
async def test_post(client: TestClient, package_ahriman: Package) -> None: async def test_post(client: TestClient, package_ahriman: Package) -> None:
""" """
must create logs record must create logs record
""" """
await client.post(f"/api/v1/packages/{package_ahriman.base}",
json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()})
post_response = await client.post(f"/api/v1/packages/{package_ahriman.base}/logs", post_response = await client.post(f"/api/v1/packages/{package_ahriman.base}/logs",
json={"created": 0.001, "message": "message", "process_id": 42}) json={"created": 0.001, "message": "message", "process_id": 42})
assert post_response.status == 204 assert post_response.status == 204
response = await client.get(f"/api/v1/packages/{package_ahriman.base}/logs") response = await client.get(f"/api/v1/packages/{package_ahriman.base}/logs")
logs = await response.json() logs = await response.json()
assert logs == {"package_base": package_ahriman.base, "logs": "message"} assert logs["logs"] == "message"
async def test_post_exception(client: TestClient, package_ahriman: Package) -> None: async def test_post_exception(client: TestClient, package_ahriman: Package) -> None: