diff options
Diffstat (limited to 'clients/screens_audit.c')
| -rw-r--r-- | clients/screens_audit.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/clients/screens_audit.c b/clients/screens_audit.c new file mode 100644 index 0000000..8f54dd5 --- /dev/null +++ b/clients/screens_audit.c @@ -0,0 +1,132 @@ +#include <dirent.h> +#include <errno.h> +#include <locale.h> +#include <math.h> +#include <ncursesw/ncurses.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> + +#include "client.h" +#include "tui.h" +#include "formula.h" +#include "util.h" +#include "version.h" +#include "yyjson.h" +#include "ui.h" + +static void audit_verify_run(struct app *a, int full) +{ + char *resp = client_rpc(&a->conn, "audit.verify", a->session, a->org, + full ? "{\"full\":true}" : "{}"); + if (!resp || !client_ok(resp)) { + show_error("Revision", resp); + free(resp); + return; + } + int64_t checked = jint_val(resp, "result.checked", 0); + int64_t vouchers = jint_val(resp, "result.vouchers_checked", 0); + int is_ok = jbool_val(resp, "result.ok", 0); + if (is_ok) { + if (full) + tui_message("Hashkedjor", + "Kedjorna är intakta.\n%lld verifikat och %lld " + "händelser kontrollerade.\n%lld underlag " + "hash-kontrollerade.", + (long long)vouchers, (long long)checked, + (long long)jint_val(resp, "result.attachments_checked", + 0)); + else + tui_message("Hashkedjor", + "Kedjorna är intakta.\n%lld verifikat och %lld " + "händelser kontrollerade.", + (long long)vouchers, (long long)checked); + } else { + int64_t bad_v = jint_val(resp, "result.first_bad_voucher_id", 0); + int64_t bad_a = jint_val(resp, "result.first_bad_seq", 0); + int64_t unbal = jint_val(resp, "result.first_unbalanced_voucher_id", 0); + int64_t bad_att = + jint_val(resp, "result.first_bad_attachment_id", 0); + char detail[320] = ""; + if (bad_v) + snprintf(detail + strlen(detail), sizeof detail - strlen(detail), + "Första trasiga verifikat: %lld\n", (long long)bad_v); + if (bad_a) + snprintf(detail + strlen(detail), sizeof detail - strlen(detail), + "Första trasiga händelse: %lld\n", (long long)bad_a); + if (unbal) + snprintf(detail + strlen(detail), sizeof detail - strlen(detail), + "Första obalanserade verifikat: %lld\n", + (long long)unbal); + if (bad_att) + snprintf(detail + strlen(detail), sizeof detail - strlen(detail), + "Första trasiga underlag: %lld\n", (long long)bad_att); + tui_message("Hashkedjor", "KEDJORNA ÄR BRUTNA!\n%s", detail); + } + free(resp); +} + +void audit_screen(struct app *a) +{ + static const char *const audit_items[] = { "Verifiera hashkedjan", + "Verifiera allt (inkl. underlag)", + "Senaste händelser" }; + static int last_sel = 0; + for (;;) { + if (g_quit) + return; + int sel = tui_menu("Revision", audit_items, 3, 0, &last_sel); + if (sel < 0) + return; + if (sel == 0) { + audit_verify_run(a, 0); + } else if (sel == 1) { + audit_verify_run(a, 1); + } else { + for (;;) { + char *resp = client_rpc(&a->conn, "audit.list", a->session, + a->org, "{\"limit\":200}"); + if (!resp || !client_ok(resp)) { + show_error("Revision", resp); + free(resp); + break; + } + struct buf text; + buf_init(&text); + size_t n = jarr_size(resp, "result.items"); + for (size_t i = 0; i < n; i++) { + char path[64], line[512]; + snprintf(path, sizeof path, "result.items.%zu.at", i); + char *at = jstr_dup(resp, path); + snprintf(path, sizeof path, "result.items.%zu.action", i); + char *action = jstr_dup(resp, path); + snprintf(path, sizeof path, + "result.items.%zu.result_code", i); + char *code = jstr_dup(resp, path); + snprintf(path, sizeof path, + "result.items.%zu.actor_user_id", i); + int64_t actor = jint_val(resp, path, 0); + snprintf(line, sizeof line, "%s anv %lld %-22s %s\n", + at ? at : "", (long long)actor, + action ? action : "", code ? code : ""); + buf_append(&text, line, strlen(line)); + free(at); + free(action); + free(code); + } + buf_append(&text, "\0", 1); + int again = tui_pager("Behandlingshistorik", (char *)text.p, NULL); + buf_free(&text); + free(resp); + if (!again) + break; + } + } + } +} |
