mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-07-23 18:59:56 +00:00
migrate to tox
this also requires to move default configuration files to share/ahriman. Thus the following features have been added * default configuration is not stored in /usr/share/ahriman/settings * package installed via PKGBUILD now copies files from /usr * configuration class now fallbacks to default in /usr
This commit is contained in:
133
package/share/ahriman/templates/build-status.jinja2
Normal file
133
package/share/ahriman/templates/build-status.jinja2
Normal file
@ -0,0 +1,133 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ repository }}</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<link rel="shortcut icon" href="/static/favicon.ico">
|
||||
|
||||
{% include "utils/style.jinja2" %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
<h1>ahriman
|
||||
{% if auth.authenticated %}
|
||||
<img src="https://img.shields.io/badge/version-{{ version }}-informational" alt="{{ version }}">
|
||||
<img src="https://img.shields.io/badge/repository-{{ repository | replace("-", "--") }}-informational" alt="{{ repository }}">
|
||||
<img src="https://img.shields.io/badge/architecture-{{ architecture }}-informational" alt="{{ architecture }}">
|
||||
<img src="https://img.shields.io/badge/service%20status-{{ service.status }}-{{ service.status_color }}" alt="{{ service.status }}" title="{{ service.timestamp }}">
|
||||
{% endif %}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div id="toolbar">
|
||||
{% if not auth.enabled or auth.username is not none %}
|
||||
<button id="add" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addForm">
|
||||
<i class="fa fa-plus"></i> add
|
||||
</button>
|
||||
<button id="update" class="btn btn-secondary" onclick="updatePackages()" disabled>
|
||||
<i class="fa fa-play"></i> update
|
||||
</button>
|
||||
<button id="remove" class="btn btn-danger" onclick="removePackages()" disabled>
|
||||
<i class="fa fa-trash"></i> remove
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<table id="packages" class="table table-striped table-hover"
|
||||
data-click-to-select="true"
|
||||
data-export-options='{"fileName": "packages"}'
|
||||
data-page-list="[10, 25, 50, 100, all]"
|
||||
data-page-size="10"
|
||||
data-pagination="true"
|
||||
data-resizable="true"
|
||||
data-search="true"
|
||||
data-show-columns="true"
|
||||
data-show-columns-search="true"
|
||||
data-show-columns-toggle-all="true"
|
||||
data-show-export="true"
|
||||
data-show-fullscreen="true"
|
||||
data-show-search-clear-button="true"
|
||||
data-sortable="true"
|
||||
data-sort-reset="true"
|
||||
data-toggle="table"
|
||||
data-toolbar="#toolbar">
|
||||
<thead class="table-primary">
|
||||
<tr>
|
||||
<th data-checkbox="true"></th>
|
||||
<th data-sortable="true" data-switchable="false">package base</th>
|
||||
<th data-sortable="true">version</th>
|
||||
<th data-sortable="true">packages</th>
|
||||
<th data-sortable="true" data-visible="false">groups</th>
|
||||
<th data-sortable="true" data-visible="false">licenses</th>
|
||||
<th data-sortable="true">last update</th>
|
||||
<th data-sortable="true">status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% if auth.authenticated %}
|
||||
{% for package in packages %}
|
||||
<tr data-package-base="{{ package.base }}">
|
||||
<td data-checkbox="true"></td>
|
||||
<td><a href="{{ package.web_url }}" title="{{ package.base }}">{{ package.base }}</a></td>
|
||||
<td>{{ package.version }}</td>
|
||||
<td>{{ package.packages|join("<br>"|safe) }}</td>
|
||||
<td>{{ package.groups|join("<br>"|safe) }}</td>
|
||||
<td>{{ package.licenses|join("<br>"|safe) }}</td>
|
||||
<td>{{ package.timestamp }}</td>
|
||||
<td class="table-{{ package.status_color }}">{{ package.status }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="100%">In order to see statuses you must login first.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<footer class="d-flex flex-wrap justify-content-between align-items-center border-top">
|
||||
<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/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>
|
||||
</ul>
|
||||
|
||||
{% if index_url is not none %}
|
||||
<ul class="nav">
|
||||
<li><a class="nav-link" href="{{ index_url }}" title="repo index">repo index</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% if auth.enabled %}
|
||||
{% if auth.username is none %}
|
||||
{{ auth.control|safe }}
|
||||
{% else %}
|
||||
<form action="/user-api/v1/logout" method="post">
|
||||
<button class="btn btn-link" style="text-decoration: none">logout ({{ auth.username }})</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
{% if auth.enabled %}
|
||||
{% include "build-status/login-modal.jinja2" %}
|
||||
{% endif %}
|
||||
|
||||
{% include "build-status/package-actions-modals.jinja2" %}
|
||||
|
||||
{% include "utils/bootstrap-scripts.jinja2" %}
|
||||
|
||||
{% include "build-status/package-actions-script.jinja2" %}
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -0,0 +1,29 @@
|
||||
<div id="loginForm" tabindex="-1" role="dialog" class="modal fade">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<form action="/user-api/v1/login" method="post">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">login</h4>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group row">
|
||||
<label for="username" class="col-sm-2 col-form-label">username</label>
|
||||
<div class="col-sm-10">
|
||||
<input id="username" type="text" class="form-control" placeholder="enter username" name="username" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="password" class="col-sm-2 col-form-label">password</label>
|
||||
<div class="col-sm-10">
|
||||
<input id="password" type="password" class="form-control" placeholder="enter password" name="password" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary">login</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,60 @@
|
||||
<div id="addForm" tabindex="-1" role="dialog" class="modal fade">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">add new packages</h4>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group row">
|
||||
<label for="package" class="col-sm-2 col-form-label">package</label>
|
||||
<div class="col-sm-10">
|
||||
<input id="package" type="text" list="knownPackages" class="form-control" placeholder="AUR package" name="package" required>
|
||||
<datalist id="knownPackages"></datalist>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">close</button>
|
||||
<button type="button" class="btn btn-success" data-bs-dismiss="modal" onclick="requestPackages()">request</button>
|
||||
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" onclick="addPackages()">add</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="failedForm" tabindex="-1" role="dialog" class="modal fade">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-danger">
|
||||
<h4 class="modal-title">failed</h4>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Packages update has failed.</p>
|
||||
<p id="errorDetails"></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="successForm" tabindex="-1" role="dialog" class="modal fade">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-success">
|
||||
<h4 class="modal-title">success</h4>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Packages update has been run.</p>
|
||||
<ul id="successDetails"></ul>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,95 @@
|
||||
<script>
|
||||
const $remove = $("#remove");
|
||||
const $update = $("#update");
|
||||
|
||||
const $table = $("#packages");
|
||||
$table.on("check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table",
|
||||
function () {
|
||||
$remove.prop("disabled", !$table.bootstrapTable("getSelections").length);
|
||||
$update.prop("disabled", !$table.bootstrapTable("getSelections").length);
|
||||
})
|
||||
|
||||
const $successForm = $("#successForm");
|
||||
const $successDetails = $("#successDetails");
|
||||
$successForm.on("hidden.bs.modal", function() { window.location.reload(); });
|
||||
|
||||
const $failedForm = $("#failedForm");
|
||||
const $errorDetails = $("#errorDetails");
|
||||
$failedForm.on("hidden.bs.modal", function() { window.location.reload(); });
|
||||
|
||||
const $package = $("#package");
|
||||
const $knownPackages = $("#knownPackages");
|
||||
$package.keyup(function () {
|
||||
const $this = $(this);
|
||||
clearTimeout($this.data("timeout"));
|
||||
|
||||
$this.data("timeout", setTimeout($.proxy(function () {
|
||||
const $value = $package.val();
|
||||
|
||||
$.ajax({
|
||||
url: "/service-api/v1/search",
|
||||
data: {"for": $value},
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function (resp) {
|
||||
const $options = resp.map(function (pkg) {
|
||||
const $option = document.createElement("option");
|
||||
$option.value = pkg.package;
|
||||
$option.innerText = `${pkg.package} (${pkg.description})`;
|
||||
return $option;
|
||||
});
|
||||
$knownPackages.empty().append($options);
|
||||
$this.focus();
|
||||
},
|
||||
})
|
||||
}, this), 500));
|
||||
})
|
||||
|
||||
function doPackageAction($uri, $packages) {
|
||||
if ($packages.length === 0)
|
||||
return;
|
||||
$.ajax({
|
||||
url: $uri,
|
||||
data: JSON.stringify({packages: $packages}),
|
||||
type: "POST",
|
||||
contentType: "application/json",
|
||||
success: function (_) {
|
||||
const $details = $packages.map(function (pkg) {
|
||||
const $li = document.createElement("li");
|
||||
$li.innerText = pkg;
|
||||
return $li;
|
||||
});
|
||||
$successDetails.empty().append($details);
|
||||
$successForm.modal("show");
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
$errorDetails.text(errorThrown);
|
||||
$failedForm.modal("show");
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function getSelection() {
|
||||
return $.map($table.bootstrapTable("getSelections"), function(row) {
|
||||
return row._data["package-base"];
|
||||
})
|
||||
}
|
||||
|
||||
function addPackages() {
|
||||
const $packages = [$package.val()]
|
||||
doPackageAction("/service-api/v1/add", $packages);
|
||||
}
|
||||
|
||||
function requestPackages() {
|
||||
const $packages = [$package.val()]
|
||||
doPackageAction("/service-api/v1/request", $packages);
|
||||
}
|
||||
|
||||
function removePackages() { doPackageAction("/service-api/v1/remove", getSelection()); }
|
||||
|
||||
function updatePackages() { doPackageAction("/service-api/v1/add", getSelection()); }
|
||||
|
||||
$(function () {
|
||||
$table.bootstrapTable("uncheckAll");
|
||||
})
|
||||
</script>
|
42
package/share/ahriman/templates/email-index.jinja2
Normal file
42
package/share/ahriman/templates/email-index.jinja2
Normal file
@ -0,0 +1,42 @@
|
||||
{#simplified version of full report#}
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ repository }}</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
{% include "utils/style.jinja2" %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
<table id="packages" class="table table-striped">
|
||||
<thead class="table-primary">
|
||||
<tr>
|
||||
<th>package</th>
|
||||
<th>version</th>
|
||||
<th>archive size</th>
|
||||
<th>installed size</th>
|
||||
<th>build date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for package in packages %}
|
||||
<tr>
|
||||
<td><a href="{{ link_path }}/{{ package.filename }}" title="{{ package.name }}">{{ package.name }}</a></td>
|
||||
<td>{{ package.version }}</td>
|
||||
<td>{{ package.archive_size }}</td>
|
||||
<td>{{ package.installed_size }}</td>
|
||||
<td>{{ package.build_date }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
95
package/share/ahriman/templates/repo-index.jinja2
Normal file
95
package/share/ahriman/templates/repo-index.jinja2
Normal file
@ -0,0 +1,95 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ repository }}</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
{% include "utils/style.jinja2" %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
<h1>Arch Linux user repository</h1>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
{% if pgp_key is not none %}
|
||||
<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 %}
|
||||
|
||||
<pre>$ cat /etc/pacman.conf
|
||||
[{{ repository }}]
|
||||
Server = {{ link_path }}
|
||||
SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Package{% if has_package_signed %}Required{% else %}Never{% endif %} TrustedOnly</pre>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<table id="packages" class="table table-striped table-hover"
|
||||
data-export-options='{"fileName": "packages"}'
|
||||
data-page-list="[10, 25, 50, 100, all]"
|
||||
data-page-size="10"
|
||||
data-pagination="true"
|
||||
data-resizable="true"
|
||||
data-search="true"
|
||||
data-show-columns="true"
|
||||
data-show-columns-search="true"
|
||||
data-show-columns-toggle-all="true"
|
||||
data-show-export="true"
|
||||
data-show-fullscreen="true"
|
||||
data-show-search-clear-button="true"
|
||||
data-sortable="true"
|
||||
data-sort-reset="true"
|
||||
data-toggle="table">
|
||||
<thead class="table-primary">
|
||||
<tr>
|
||||
<th data-sortable="true" data-switchable="false">package</th>
|
||||
<th data-sortable="true">version</th>
|
||||
<th data-sortable="true" data-visible="false">architecture</th>
|
||||
<th data-sortable="true" data-visible="false">description</th>
|
||||
<th data-sortable="true" data-visible="false">upstream url</th>
|
||||
<th data-sortable="true" data-visible="false">licenses</th>
|
||||
<th data-sortable="true" data-visible="false">groups</th>
|
||||
<th data-sortable="true" data-visible="false">depends</th>
|
||||
<th data-sortable="true">archive size</th>
|
||||
<th data-sortable="true">installed size</th>
|
||||
<th data-sortable="true">build date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for package in packages %}
|
||||
<tr>
|
||||
<td><a href="{{ link_path }}/{{ package.filename }}" title="{{ package.name }}">{{ package.name }}</a></td>
|
||||
<td>{{ package.version }}</td>
|
||||
<td>{{ package.architecture }}</td>
|
||||
<td>{{ package.description }}</td>
|
||||
<td><a href="{{ package.url }}" title="{{ package.name }} upstream url">{{ package.url }}</a></td>
|
||||
<td>{{ package.licenses|join("<br>"|safe) }}</td>
|
||||
<td>{{ package.groups|join("<br>"|safe) }}</td>
|
||||
<td>{{ package.depends|join("<br>"|safe) }}</td>
|
||||
<td>{{ package.archive_size }}</td>
|
||||
<td>{{ package.installed_size }}</td>
|
||||
<td>{{ package.build_date }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<footer class="d-flex flex-wrap justify-content-between align-items-center border-top">
|
||||
<ul class="nav">
|
||||
{% if homepage is not none %}
|
||||
<li><a class="nav-link" href="{{ homepage }}" title="homepage">homepage</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
{% include "utils/bootstrap-scripts.jinja2" %}
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
BIN
package/share/ahriman/templates/static/favicon.ico
Normal file
BIN
package/share/ahriman/templates/static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
@ -0,0 +1,23 @@
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>
|
||||
|
||||
<script src="https://unpkg.com/tableexport.jquery.plugin/tableExport.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.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-U1DAWAznBHeqEIlVSCgzq+c9gqGAJn5c/t99JyeKa9xxaYpSvHU5awsuZVVFIhvj" crossorigin="anonymous"></script>
|
||||
<script src="https://unpkg.com/bootstrap-table@1.18.3/dist/bootstrap-table.min.js"></script>
|
||||
|
||||
<script src="https://unpkg.com/bootstrap-table@1.18.3/dist/extensions/export/bootstrap-table-export.min.js"></script>
|
||||
|
||||
<script src="https://unpkg.com/bootstrap-table@1.18.3/dist/extensions/resizable/bootstrap-table-resizable.js"></script>
|
||||
|
||||
<script>
|
||||
$("#packages").bootstrapTable({
|
||||
formatClearSearch: function () {
|
||||
return "Clear search";
|
||||
},
|
||||
formatSearch: function () {
|
||||
return "search";
|
||||
}
|
||||
})
|
||||
</script>
|
9
package/share/ahriman/templates/utils/style.jinja2
Normal file
9
package/share/ahriman/templates/utils/style.jinja2
Normal file
@ -0,0 +1,9 @@
|
||||
<script src="https://kit.fontawesome.com/0d6d6d5226.js" crossorigin="anonymous"></script>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">
|
||||
|
||||
<link href="https://unpkg.com/bootstrap-table@1.18.3/dist/bootstrap-table.min.css" rel="stylesheet">
|
||||
|
||||
<link href="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.css" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
</style>
|
Reference in New Issue
Block a user