Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2024 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : TALER is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file exchangedb/select_aml_decisions.c
18 : * @brief Implementation of the select_aml_decisions function for Postgres
19 : * @author Christian Grothoff
20 : */
21 : #include "taler/taler_pq_lib.h"
22 : #include "exchange-database/select_aml_decisions.h"
23 : #include "helper.h"
24 :
25 :
26 : /**
27 : * Closure for #handle_aml_result.
28 : */
29 : struct AmlProcessResultContext
30 : {
31 : /**
32 : * Function to call on each result.
33 : */
34 : TALER_EXCHANGEDB_AmlDecisionCallback cb;
35 :
36 : /**
37 : * Closure for @e cb.
38 : */
39 : void *cb_cls;
40 :
41 : /**
42 : * Plugin context.
43 : */
44 : struct TALER_EXCHANGEDB_PostgresContext *pg;
45 :
46 : /**
47 : * Set to #GNUNET_SYSERR on serious errors.
48 : */
49 : enum GNUNET_GenericReturnValue status;
50 : };
51 :
52 :
53 : /**
54 : * Function to be called with the results of a SELECT statement
55 : * that has returned @a num_results results. Helper function
56 : * for #TALER_EXCHANGEDB_select_aml_decisions().
57 : *
58 : * @param cls closure of type `struct AmlProcessResultContext *`
59 : * @param result the postgres result
60 : * @param num_results the number of results in @a result
61 : */
62 : static void
63 3 : handle_aml_result (void *cls,
64 : PGresult *result,
65 : unsigned int num_results)
66 : {
67 3 : struct AmlProcessResultContext *ctx = cls;
68 :
69 9 : for (unsigned int i = 0; i<num_results; i++)
70 : {
71 : struct TALER_NormalizedPaytoHashP h_payto;
72 : uint64_t rowid;
73 6 : char *justification = NULL;
74 : struct GNUNET_TIME_Timestamp decision_time;
75 : struct GNUNET_TIME_Absolute expiration_time;
76 6 : json_t *jproperties = NULL;
77 : bool is_wallet;
78 : bool to_investigate;
79 : bool is_active;
80 : json_t *account_rules;
81 : struct TALER_FullPayto payto;
82 6 : struct GNUNET_PQ_ResultSpec rs[] = {
83 6 : GNUNET_PQ_result_spec_uint64 ("outcome_serial_id",
84 : &rowid),
85 6 : GNUNET_PQ_result_spec_auto_from_type ("h_payto",
86 : &h_payto),
87 6 : GNUNET_PQ_result_spec_bool ("is_wallet",
88 : &is_wallet),
89 6 : GNUNET_PQ_result_spec_allow_null (
90 : GNUNET_PQ_result_spec_string ("justification",
91 : &justification),
92 : NULL),
93 6 : GNUNET_PQ_result_spec_timestamp ("decision_time",
94 : &decision_time),
95 6 : GNUNET_PQ_result_spec_absolute_time ("expiration_time",
96 : &expiration_time),
97 6 : GNUNET_PQ_result_spec_allow_null (
98 : TALER_PQ_result_spec_json ("jproperties",
99 : &jproperties),
100 : NULL),
101 6 : TALER_PQ_result_spec_json ("jnew_rules",
102 : &account_rules),
103 6 : GNUNET_PQ_result_spec_bool ("to_investigate",
104 : &to_investigate),
105 6 : GNUNET_PQ_result_spec_bool ("is_active",
106 : &is_active),
107 6 : GNUNET_PQ_result_spec_string ("payto_uri",
108 : &payto.full_payto),
109 : GNUNET_PQ_result_spec_end
110 : };
111 :
112 6 : if (GNUNET_OK !=
113 6 : GNUNET_PQ_extract_result (result,
114 : rs,
115 : i))
116 : {
117 0 : GNUNET_break (0);
118 0 : ctx->status = GNUNET_SYSERR;
119 0 : return;
120 : }
121 6 : if (GNUNET_TIME_absolute_is_past (expiration_time))
122 0 : is_active = false;
123 6 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
124 : "Returning AML decisions for `%s' (%s)\n",
125 : TALER_B2S (&h_payto),
126 : is_wallet
127 : ? "wallet"
128 : : "account");
129 6 : ctx->cb (ctx->cb_cls,
130 : rowid,
131 : justification,
132 : &h_payto,
133 : decision_time,
134 : expiration_time,
135 : jproperties,
136 : to_investigate,
137 : is_active,
138 : is_wallet,
139 : payto,
140 : account_rules);
141 6 : GNUNET_PQ_cleanup_result (rs);
142 : }
143 : }
144 :
145 :
146 : enum GNUNET_DB_QueryStatus
147 3 : TALER_EXCHANGEDB_select_aml_decisions (
148 : struct TALER_EXCHANGEDB_PostgresContext *pg,
149 : const struct TALER_NormalizedPaytoHashP *h_payto,
150 : enum TALER_EXCHANGE_YesNoAll investigation_only,
151 : enum TALER_EXCHANGE_YesNoAll active_only,
152 : uint64_t offset,
153 : int64_t limit,
154 : TALER_EXCHANGEDB_AmlDecisionCallback cb,
155 : void *cb_cls)
156 : {
157 3 : uint64_t ulimit = (limit > 0) ? limit : -limit;
158 3 : struct GNUNET_PQ_QueryParam params[] = {
159 3 : GNUNET_PQ_query_param_bool (NULL == h_payto),
160 : NULL == h_payto
161 1 : ? GNUNET_PQ_query_param_null ()
162 3 : : GNUNET_PQ_query_param_auto_from_type (h_payto),
163 3 : GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL ==
164 : investigation_only)),
165 3 : GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES ==
166 : investigation_only)),
167 3 : GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_ALL ==
168 : active_only)),
169 3 : GNUNET_PQ_query_param_bool ((TALER_EXCHANGE_YNA_YES ==
170 : active_only)),
171 3 : GNUNET_PQ_query_param_uint64 (&offset),
172 3 : GNUNET_PQ_query_param_uint64 (&ulimit),
173 : GNUNET_PQ_query_param_end
174 : };
175 3 : struct AmlProcessResultContext ctx = {
176 : .cb = cb,
177 : .cb_cls = cb_cls,
178 : .pg = pg,
179 : .status = GNUNET_OK
180 : };
181 : enum GNUNET_DB_QueryStatus qs;
182 3 : const char *stmt = (limit > 0)
183 : ? "select_aml_decisions_inc"
184 : : "select_aml_decisions_dec";
185 :
186 3 : PREPARE (pg,
187 : "select_aml_decisions_inc",
188 : "SELECT"
189 : " lo.outcome_serial_id"
190 : ",lo.h_payto"
191 : ",ah.justification"
192 : ",lo.decision_time"
193 : ",lo.expiration_time"
194 : ",lo.jproperties::TEXT"
195 : ",lo.to_investigate"
196 : ",lo.is_active"
197 : ",lo.jnew_rules::TEXT"
198 : ",kt.is_wallet"
199 : ",wt.payto_uri"
200 : " FROM legitimization_outcomes lo"
201 : " JOIN kyc_targets kt"
202 : " ON (lo.h_payto = kt.h_normalized_payto)"
203 : " JOIN wire_targets wt"
204 : " ON (lo.h_payto = wt.h_normalized_payto)"
205 : " LEFT JOIN aml_history ah"
206 : " USING (outcome_serial_id)"
207 : " WHERE (outcome_serial_id > $7)"
208 : " AND ($1 OR (lo.h_payto = $2))"
209 : " AND ($3 OR (lo.to_investigate = $4))"
210 : " AND ($5 OR (lo.is_active = $6))"
211 : " ORDER BY lo.outcome_serial_id ASC"
212 : " LIMIT $8");
213 3 : PREPARE (pg,
214 : "select_aml_decisions_dec",
215 : "SELECT"
216 : " lo.outcome_serial_id"
217 : ",lo.h_payto"
218 : ",ah.justification"
219 : ",lo.decision_time"
220 : ",lo.expiration_time"
221 : ",lo.jproperties::TEXT"
222 : ",lo.to_investigate"
223 : ",lo.is_active"
224 : ",lo.jnew_rules::TEXT"
225 : ",kt.is_wallet"
226 : ",wt.payto_uri"
227 : " FROM legitimization_outcomes lo"
228 : " JOIN kyc_targets kt"
229 : " ON (lo.h_payto = kt.h_normalized_payto)"
230 : " JOIN wire_targets wt"
231 : " ON (lo.h_payto = wt.h_normalized_payto)"
232 : " LEFT JOIN aml_history ah"
233 : " USING (outcome_serial_id)"
234 : " WHERE lo.outcome_serial_id < $7"
235 : " AND ($1 OR (lo.h_payto = $2))"
236 : " AND ($3 OR (lo.to_investigate = $4))"
237 : " AND ($5 OR (lo.is_active = $6))"
238 : " ORDER BY lo.outcome_serial_id DESC"
239 : " LIMIT $8");
240 3 : qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
241 : stmt,
242 : params,
243 : &handle_aml_result,
244 : &ctx);
245 3 : if (GNUNET_OK != ctx.status)
246 0 : return GNUNET_DB_STATUS_HARD_ERROR;
247 3 : return qs;
248 : }
|