-simplify table drop logic
This commit is contained in:
parent
40858f0952
commit
de83b055d5
@ -64,11 +64,6 @@ static int force_create_partitions;
|
||||
*/
|
||||
static uint32_t shard_idx;
|
||||
|
||||
/**
|
||||
* -R option: do full shard DB reset
|
||||
*/
|
||||
static uint32_t reset_shard_db;
|
||||
|
||||
/**
|
||||
* Main function that will be run.
|
||||
*
|
||||
@ -98,31 +93,18 @@ run (void *cls,
|
||||
}
|
||||
if (reset_db)
|
||||
{
|
||||
if (GNUNET_OK != plugin->drop_tables (plugin->cls))
|
||||
if (GNUNET_OK !=
|
||||
plugin->drop_tables (plugin->cls))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Could not drop tables as requested. Either database was not yet initialized, or permission denied. Consult the logs. Will still try to create new tables.\n");
|
||||
}
|
||||
}
|
||||
if (0 <
|
||||
reset_shard_db)
|
||||
if (0 < shard_idx)
|
||||
{
|
||||
if (GNUNET_OK != plugin->drop_shard_tables (plugin->cls, reset_shard_db))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Could not drop shard tables as requested. Either database was not yet initialized or permission denied. Consult the logs.\n");
|
||||
global_ret = EXIT_FAILURE;
|
||||
return;
|
||||
}
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
|
||||
"Dropped shard database, please call taler-exchange-dbinit -S <N> to initialize a new shard database\n");
|
||||
return;
|
||||
}
|
||||
if (0 <
|
||||
shard_idx)
|
||||
{
|
||||
if (GNUNET_OK != plugin->create_shard_tables (plugin->cls,
|
||||
shard_idx))
|
||||
if (GNUNET_OK !=
|
||||
plugin->create_shard_tables (plugin->cls,
|
||||
shard_idx))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Could not create shard database\n");
|
||||
@ -249,11 +231,6 @@ main (int argc,
|
||||
"INDEX",
|
||||
"Setup a shard server, creates tables with INDEX as suffix",
|
||||
&shard_idx),
|
||||
GNUNET_GETOPT_option_uint ('R',
|
||||
"reset-shard",
|
||||
"OLD_SHARD_IDX",
|
||||
"reset a shard database, does not reinitialize i.e. call taler-exchange-dbinit -S afterwards (DANGEROUS: all existing data is lost!)",
|
||||
&reset_shard_db),
|
||||
GNUNET_GETOPT_option_flag ('f',
|
||||
"force",
|
||||
"Force partitions to be created if there is only one partition",
|
||||
|
@ -16,11 +16,8 @@ sqldir = $(prefix)/share/taler/sql/exchange/
|
||||
|
||||
sqlinputs = \
|
||||
common-0001.sql \
|
||||
drop-common.sql \
|
||||
exchange-0001-part.sql \
|
||||
drop-exchange-part.sql \
|
||||
shard-0001-part.sql \
|
||||
drop-shard-part.sql
|
||||
shard-0001-part.sql
|
||||
|
||||
sql_DATA = \
|
||||
benchmark-0001.sql \
|
||||
@ -28,22 +25,17 @@ sql_DATA = \
|
||||
exchange-0001.sql \
|
||||
drop.sql \
|
||||
procedures.sql \
|
||||
shard-0001.sql \
|
||||
shard-drop.sql
|
||||
|
||||
shard-0001.sql
|
||||
|
||||
BUILT_SOURCES = \
|
||||
shard-0001.sql \
|
||||
exchange-0001.sql \
|
||||
drop.sql \
|
||||
procedures.sql \
|
||||
shard-drop.sql
|
||||
procedures.sql
|
||||
|
||||
CLEANFILES = \
|
||||
shard-0001.sql \
|
||||
exchange-0001.sql \
|
||||
drop.sql \
|
||||
shard-drop.sql
|
||||
exchange-0001.sql
|
||||
|
||||
exchange-0001.sql: common-0001.sql exchange-0001-part.sql
|
||||
chmod +w $@ || true
|
||||
@ -55,16 +47,6 @@ shard-0001.sql: common-0001.sql shard-0001-part.sql
|
||||
cat common-0001.sql shard-0001-part.sql >$@
|
||||
chmod ugo-w $@
|
||||
|
||||
drop.sql: drop-common.sql drop-exchange-part.sql
|
||||
chmod +w $@ || true
|
||||
cat drop-common.sql drop-exchange-part.sql >$@
|
||||
chmod ugo-w $@
|
||||
|
||||
shard-drop.sql: drop-common.sql drop-shard-part.sql
|
||||
chmod +w $@ || true
|
||||
cat drop-common.sql drop-shard-part.sql >$@
|
||||
chmod ugo-w $@
|
||||
|
||||
EXTRA_DIST = \
|
||||
exchangedb.conf \
|
||||
exchangedb-postgres.conf \
|
||||
|
@ -1,97 +0,0 @@
|
||||
--
|
||||
-- This file is part of TALER
|
||||
-- Copyright (C) 2014--2021 Taler Systems SA
|
||||
--
|
||||
-- TALER is free software; you can redistribute it and/or modify it under the
|
||||
-- terms of the GNU General Public License as published by the Free Software
|
||||
-- Foundation; either version 3, or (at your option) any later version.
|
||||
--
|
||||
-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License along with
|
||||
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
--
|
||||
|
||||
-- Everything in one big transaction
|
||||
BEGIN;
|
||||
|
||||
-- This script DROPs all of the common functions we create.
|
||||
--
|
||||
-- Unlike the other SQL files, it SHOULD be updated to reflect the
|
||||
-- latest requirements for dropping tables.
|
||||
|
||||
|
||||
DROP FUNCTION IF EXISTS create_table_prewire;
|
||||
DROP FUNCTION IF EXISTS create_table_recoup;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_recoup_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_recoup_by_reserve;
|
||||
DROP FUNCTION IF EXISTS create_table_recoup_refresh;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_recoup_refresh_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_aggregation_transient;
|
||||
DROP FUNCTION IF EXISTS create_table_aggregation_tracking;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_aggregation_tracking_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_wire_out;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_wire_out_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_wire_targets;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_wire_targets_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_deposits;
|
||||
DROP FUNCTION IF EXISTS create_table_deposits_by_ready;
|
||||
DROP FUNCTION IF EXISTS create_table_deposits_for_matching;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_deposits_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_refunds;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_refunds_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_refresh_commitments;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_refresh_commitments_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_refresh_revealed_coins;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_refresh_revealed_coins_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_refresh_transfer_keys;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_refresh_transfer_keys_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_known_coins;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_known_coins_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_reserves_close;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_reserves_close_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_reserves_out;
|
||||
DROP FUNCTION IF EXISTS create_table_reserves_out_by_reserve;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_reserves_out_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_reserves_in;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_reserves_in_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_reserves;
|
||||
DROP FUNCTION IF EXISTS create_table_cs_nonce_locks;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_cs_nonce_locks_partition;
|
||||
|
||||
DROP FUNCTION IF EXISTS create_table_purse_requests;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_purse_requests_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_purse_refunds;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_purse_refunds_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_purse_merges;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_purse_merges_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_account_merges;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_account_merges_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_contracts;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_contracts_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_history_requests;
|
||||
DROP FUNCTION IF EXISTS create_table_close_requests;
|
||||
DROP FUNCTION IF EXISTS create_table_purse_deposits;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_purse_deposits_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_wad_out_entries;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_wad_out_entries_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_wads_in;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_wads_in_partition;
|
||||
DROP FUNCTION IF EXISTS create_table_wad_in_entries;
|
||||
DROP FUNCTION IF EXISTS add_constraints_to_wad_in_entries_partition;
|
||||
|
||||
DROP FUNCTION IF EXISTS create_partitioned_table;
|
||||
DROP FUNCTION IF EXISTS create_hash_partition;
|
||||
DROP FUNCTION IF EXISTS create_range_partition;
|
||||
DROP FUNCTION IF EXISTS create_partitions;
|
||||
DROP FUNCTION IF EXISTS detach_default_partitions;
|
||||
DROP FUNCTION IF EXISTS drop_default_partitions;
|
||||
DROP FUNCTION IF EXISTS prepare_sharding;
|
||||
DROP FUNCTION IF EXISTS create_foreign_hash_partition;
|
||||
DROP FUNCTION IF EXISTS create_foreign_range_partition;
|
||||
DROP FUNCTION IF EXISTS create_foreign_servers;
|
||||
DROP FUNCTION IF EXISTS create_shard_server;
|
||||
|
||||
COMMIT;
|
@ -1,108 +0,0 @@
|
||||
--
|
||||
-- This file is part of TALER
|
||||
-- Copyright (C) 2014--2021 Taler Systems SA
|
||||
--
|
||||
-- TALER is free software; you can redistribute it and/or modify it under the
|
||||
-- terms of the GNU General Public License as published by the Free Software
|
||||
-- Foundation; either version 3, or (at your option) any later version.
|
||||
--
|
||||
-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License along with
|
||||
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
--
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- Unregister patch (exchange-0001.sql)
|
||||
SELECT _v.unregister_patch('exchange-0001');
|
||||
|
||||
|
||||
-- Drops for exchange-0001-part.sql
|
||||
DROP TRIGGER IF EXISTS reserves_out_on_insert ON reserves_out;
|
||||
DROP TRIGGER IF EXISTS reserves_out_on_delete ON reserves_out;
|
||||
DROP TRIGGER IF EXISTS deposits_on_insert ON deposits;
|
||||
DROP TRIGGER IF EXISTS deposits_on_delete ON deposits;
|
||||
DROP TRIGGER IF EXISTS recoup_on_insert ON recoup;
|
||||
DROP TRIGGER IF EXISTS recoup_on_delete ON recoup;
|
||||
|
||||
DROP TABLE IF EXISTS revolving_work_shards CASCADE;
|
||||
DROP TABLE IF EXISTS extensions CASCADE;
|
||||
DROP TABLE IF EXISTS auditors CASCADE;
|
||||
DROP TABLE IF EXISTS auditor_denom_sigs CASCADE;
|
||||
DROP TABLE IF EXISTS exchange_sign_keys CASCADE;
|
||||
DROP TABLE IF EXISTS wire_accounts CASCADE;
|
||||
DROP TABLE IF EXISTS signkey_revocations CASCADE;
|
||||
DROP TABLE IF EXISTS work_shards CASCADE;
|
||||
DROP TABLE IF EXISTS prewire CASCADE;
|
||||
DROP TABLE IF EXISTS recoup CASCADE;
|
||||
DROP TABLE IF EXISTS recoup_refresh CASCADE;
|
||||
DROP TABLE IF EXISTS aggregation_transient CASCADE;
|
||||
DROP TABLE IF EXISTS aggregation_tracking CASCADE;
|
||||
DROP TABLE IF EXISTS wire_out CASCADE;
|
||||
DROP TABLE IF EXISTS wire_targets CASCADE;
|
||||
DROP TABLE IF EXISTS wire_fee CASCADE;
|
||||
DROP TABLE IF EXISTS deposits CASCADE;
|
||||
DROP TABLE IF EXISTS deposits_by_ready CASCADE;
|
||||
DROP TABLE IF EXISTS deposits_for_matching CASCADE;
|
||||
DROP TABLE IF EXISTS extension_details CASCADE;
|
||||
DROP TABLE IF EXISTS refunds CASCADE;
|
||||
DROP TABLE IF EXISTS refresh_commitments CASCADE;
|
||||
DROP TABLE IF EXISTS refresh_revealed_coins CASCADE;
|
||||
DROP TABLE IF EXISTS refresh_transfer_keys CASCADE;
|
||||
DROP TABLE IF EXISTS known_coins CASCADE;
|
||||
DROP TABLE IF EXISTS reserves_close CASCADE;
|
||||
DROP TABLE IF EXISTS reserves_out CASCADE;
|
||||
DROP TABLE IF EXISTS reserves_out_by_reserve CASCADE;
|
||||
DROP TABLE IF EXISTS reserves_in CASCADE;
|
||||
DROP TABLE IF EXISTS reserves CASCADE;
|
||||
DROP TABLE IF EXISTS denomination_revocations CASCADE;
|
||||
DROP TABLE IF EXISTS denominations CASCADE;
|
||||
DROP TABLE IF EXISTS cs_nonce_locks CASCADE;
|
||||
DROP TABLE IF EXISTS global_fee CASCADE;
|
||||
DROP TABLE IF EXISTS recoup_by_reserve CASCADE;
|
||||
|
||||
|
||||
DROP TABLE IF EXISTS partners CASCADE;
|
||||
DROP TABLE IF EXISTS account_merges CASCADE;
|
||||
DROP TABLE IF EXISTS purse_merges CASCADE;
|
||||
DROP TABLE IF EXISTS purse_deposits CASCADE;
|
||||
DROP TABLE IF EXISTS contracts CASCADE;
|
||||
DROP TABLE IF EXISTS history_requests CASCADE;
|
||||
DROP TABLE IF EXISTS close_requests CASCADE;
|
||||
DROP TABLE IF EXISTS purse_requests CASCADE;
|
||||
DROP TABLE IF EXISTS purse_refunds CASCADE;
|
||||
DROP TABLE IF EXISTS wads_out CASCADE;
|
||||
DROP TABLE IF EXISTS wad_out_entries CASCADE;
|
||||
DROP TABLE IF EXISTS wads_in CASCADE;
|
||||
DROP TABLE IF EXISTS wad_in_entries CASCADE;
|
||||
DROP TABLE IF EXISTS partner_accounts CASCADE;
|
||||
DROP TABLE IF EXISTS purse_actions CASCADE;
|
||||
|
||||
DROP FUNCTION IF EXISTS exchange_do_withdraw;
|
||||
DROP FUNCTION IF EXISTS exchange_do_withdraw_limit_check;
|
||||
DROP FUNCTION IF EXISTS exchange_do_recoup_by_reserve;
|
||||
DROP FUNCTION IF EXISTS recoup_insert_trigger;
|
||||
DROP FUNCTION IF EXISTS recoup_delete_trigger;
|
||||
DROP FUNCTION IF EXISTS deposits_insert_trigger;
|
||||
DROP FUNCTION IF EXISTS deposits_update_trigger;
|
||||
DROP FUNCTION IF EXISTS deposits_delete_trigger;
|
||||
DROP FUNCTION IF EXISTS reserves_out_by_reserve_insert_trigger;
|
||||
DROP FUNCTION IF EXISTS reserves_out_by_reserve_delete_trigger;
|
||||
DROP FUNCTION IF EXISTS exchange_do_deposit;
|
||||
DROP FUNCTION IF EXISTS exchange_do_melt;
|
||||
DROP FUNCTION IF EXISTS exchange_do_refund;
|
||||
DROP FUNCTION IF EXISTS exchange_do_recoup_to_coin;
|
||||
DROP FUNCTION IF EXISTS exchange_do_recoup_to_reserve;
|
||||
DROP FUNCTION IF EXISTS exchange_do_purse_deposit;
|
||||
DROP FUNCTION IF EXISTS exchange_do_purse_merge;
|
||||
DROP FUNCTION IF EXISTS exchange_do_account_merge;
|
||||
DROP FUNCTION IF EXISTS exchange_do_history_request;
|
||||
DROP FUNCTION IF EXISTS exchange_do_close_request;
|
||||
DROP FUNCTION IF EXISTS exchange_do_reserve_purse;
|
||||
|
||||
-- And we're out of here...
|
||||
|
||||
COMMIT;
|
@ -1,6 +1,6 @@
|
||||
--
|
||||
-- This file is part of TALER
|
||||
-- Copyright (C) 2014--2021 Taler Systems SA
|
||||
-- Copyright (C) 2014--2022 Taler Systems SA
|
||||
--
|
||||
-- TALER is free software; you can redistribute it and/or modify it under the
|
||||
-- terms of the GNU General Public License as published by the Free Software
|
||||
@ -14,14 +14,15 @@
|
||||
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
--
|
||||
|
||||
-- Everything in one big transaction
|
||||
BEGIN;
|
||||
|
||||
-- Unregister patch (shard-0001.sql)
|
||||
SELECT _v.unregister_patch('shard-0001');
|
||||
|
||||
-- Drops for shard-0001-part.sql
|
||||
SELECT _v.unregister_patch('exchange-0001');
|
||||
|
||||
DROP FUNCTION IF EXISTS drop_shard;
|
||||
DROP FUNCTION IF EXISTS setup_shard;
|
||||
DROP SCHEMA public CASCADE;
|
||||
CREATE SCHEMA public;
|
||||
GRANT ALL ON SCHEMA public TO postgres;
|
||||
COMMENT ON SCHEMA public IS 'standard public schema';
|
||||
|
||||
COMMIT;
|
@ -177,58 +177,6 @@ postgres_drop_tables (void *cls)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Drop all Taler shard tables. This should only be used by testcases.
|
||||
*
|
||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||
* @param old_idx the index which was used when the shard database was initialized
|
||||
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
postgres_drop_shard_tables (void *cls,
|
||||
uint32_t old_idx)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_Context *conn;
|
||||
enum GNUNET_GenericReturnValue ret = GNUNET_OK;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_uint32 (&old_idx),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
struct GNUNET_PQ_PreparedStatement ps[] = {
|
||||
GNUNET_PQ_make_prepare ("drop_shard_tables",
|
||||
"SELECT"
|
||||
" drop_shard"
|
||||
" ($1);",
|
||||
1),
|
||||
GNUNET_PQ_PREPARED_STATEMENT_END
|
||||
};
|
||||
|
||||
if (NULL != pg->conn)
|
||||
{
|
||||
GNUNET_PQ_disconnect (pg->conn);
|
||||
pg->conn = NULL;
|
||||
pg->init = false;
|
||||
}
|
||||
conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
|
||||
"exchangedb-postgres",
|
||||
NULL,
|
||||
NULL,
|
||||
ps);
|
||||
if (NULL == conn)
|
||||
return GNUNET_SYSERR;
|
||||
if (0 > GNUNET_PQ_eval_prepared_non_select (conn,
|
||||
"drop_shard_tables",
|
||||
params))
|
||||
ret = GNUNET_SYSERR;
|
||||
if (GNUNET_OK == ret)
|
||||
ret = GNUNET_PQ_exec_sql (conn,
|
||||
"shard-drop");
|
||||
GNUNET_PQ_disconnect (conn);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the necessary tables if they are not present
|
||||
*
|
||||
@ -16275,7 +16223,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
|
||||
plugin = GNUNET_new (struct TALER_EXCHANGEDB_Plugin);
|
||||
plugin->cls = pg;
|
||||
plugin->drop_tables = &postgres_drop_tables;
|
||||
plugin->drop_shard_tables = &postgres_drop_shard_tables;
|
||||
plugin->create_tables = &postgres_create_tables;
|
||||
plugin->create_shard_tables = &postgres_create_shard_tables;
|
||||
plugin->setup_partitions = &postgres_setup_partitions;
|
||||
|
@ -2760,17 +2760,6 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
enum GNUNET_GenericReturnValue
|
||||
(*drop_tables)(void *cls);
|
||||
|
||||
/**
|
||||
* Drop the Taler tables on a shard. This should only be used in testcases.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param old_idx the index which was used then the database was initialized.
|
||||
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
(*drop_shard_tables)(void *cls,
|
||||
uint32_t old_idx);
|
||||
|
||||
/**
|
||||
* Create the necessary tables if they are not present
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user