summaryrefslogtreecommitdiff
path: root/clients/screens_audit.c
blob: 8f54dd53e52575a1d85245ef54efc835c251c7c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
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;
            }
        }
    }
}