Merge remote-tracking branch 'upstream/develop' into annando/issue8514
This commit is contained in:
commit
2a56370cf4
|
@ -376,7 +376,7 @@ function conversation(App $a, array $items, $mode, $update, $preview = false, $o
|
||||||
. "<script> var profile_uid = " . $_SESSION['uid']
|
. "<script> var profile_uid = " . $_SESSION['uid']
|
||||||
. "; var netargs = '" . substr(DI::args()->getCommand(), 8)
|
. "; var netargs = '" . substr(DI::args()->getCommand(), 8)
|
||||||
. '?f='
|
. '?f='
|
||||||
. (!empty($_GET['cid']) ? '&cid=' . rawurlencode($_GET['cid']) : '')
|
. (!empty($_GET['contactid']) ? '&contactid=' . rawurlencode($_GET['contactid']) : '')
|
||||||
. (!empty($_GET['search']) ? '&search=' . rawurlencode($_GET['search']) : '')
|
. (!empty($_GET['search']) ? '&search=' . rawurlencode($_GET['search']) : '')
|
||||||
. (!empty($_GET['star']) ? '&star=' . rawurlencode($_GET['star']) : '')
|
. (!empty($_GET['star']) ? '&star=' . rawurlencode($_GET['star']) : '')
|
||||||
. (!empty($_GET['order']) ? '&order=' . rawurlencode($_GET['order']) : '')
|
. (!empty($_GET['order']) ? '&order=' . rawurlencode($_GET['order']) : '')
|
||||||
|
|
|
@ -58,8 +58,8 @@ function network_init(App $a)
|
||||||
$group_id = (($a->argc > 1 && is_numeric($a->argv[1])) ? intval($a->argv[1]) : 0);
|
$group_id = (($a->argc > 1 && is_numeric($a->argv[1])) ? intval($a->argv[1]) : 0);
|
||||||
|
|
||||||
$cid = 0;
|
$cid = 0;
|
||||||
if (!empty($_GET['cid'])) {
|
if (!empty($_GET['contactid'])) {
|
||||||
$cid = $_GET['cid'];
|
$cid = $_GET['contactid'];
|
||||||
$_GET['nets'] = '';
|
$_GET['nets'] = '';
|
||||||
$group_id = 0;
|
$group_id = 0;
|
||||||
}
|
}
|
||||||
|
@ -466,7 +466,7 @@ function networkThreadedView(App $a, $update, $parent)
|
||||||
|
|
||||||
$o = '';
|
$o = '';
|
||||||
|
|
||||||
$cid = intval($_GET['cid'] ?? 0);
|
$cid = intval($_GET['contactid'] ?? 0);
|
||||||
$star = intval($_GET['star'] ?? 0);
|
$star = intval($_GET['star'] ?? 0);
|
||||||
$bmark = intval($_GET['bmark'] ?? 0);
|
$bmark = intval($_GET['bmark'] ?? 0);
|
||||||
$conv = intval($_GET['conv'] ?? 0);
|
$conv = intval($_GET['conv'] ?? 0);
|
||||||
|
@ -786,6 +786,13 @@ function networkThreadedView(App $a, $update, $parent)
|
||||||
$top_limit = DateTimeFormat::utcNow();
|
$top_limit = DateTimeFormat::utcNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle bad performance situations when the distance between top and bottom is too high
|
||||||
|
// See issue https://github.com/friendica/friendica/issues/8619
|
||||||
|
if (strtotime($top_limit) - strtotime($bottom_limit) > 86400) {
|
||||||
|
// Set the bottom limit to one day in the past at maximum
|
||||||
|
$bottom_limit = DateTimeFormat::utc(date('c', strtotime($top_limit) - 86400));
|
||||||
|
}
|
||||||
|
|
||||||
$items = DBA::p("SELECT `item`.`parent-uri` AS `uri`, 0 AS `item_id`, `item`.$ordering AS `order_date`, `author`.`url` AS `author-link` FROM `item`
|
$items = DBA::p("SELECT `item`.`parent-uri` AS `uri`, 0 AS `item_id`, `item`.$ordering AS `order_date`, `author`.`url` AS `author-link` FROM `item`
|
||||||
STRAIGHT_JOIN (SELECT `uri-id` FROM `tag-search-view` WHERE `name` IN
|
STRAIGHT_JOIN (SELECT `uri-id` FROM `tag-search-view` WHERE `name` IN
|
||||||
(SELECT SUBSTR(`term`, 2) FROM `search` WHERE `uid` = ? AND `term` LIKE '#%') AND `uid` = 0) AS `tag-search`
|
(SELECT SUBSTR(`term`, 2) FROM `search` WHERE `uid` = ? AND `term` LIKE '#%') AND `uid` = 0) AS `tag-search`
|
||||||
|
@ -891,8 +898,8 @@ function network_tabs(App $a)
|
||||||
$cmd = DI::args()->getCommand();
|
$cmd = DI::args()->getCommand();
|
||||||
|
|
||||||
$def_param = [];
|
$def_param = [];
|
||||||
if (!empty($_GET['cid'])) {
|
if (!empty($_GET['contactid'])) {
|
||||||
$def_param['cid'] = $_GET['cid'];
|
$def_param['contactid'] = $_GET['contactid'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// tabs
|
// tabs
|
||||||
|
|
|
@ -126,7 +126,7 @@ class ForumManager
|
||||||
$selected = (($cid == $contact['id']) ? ' forum-selected' : '');
|
$selected = (($cid == $contact['id']) ? ' forum-selected' : '');
|
||||||
|
|
||||||
$entry = [
|
$entry = [
|
||||||
'url' => 'network?cid=' . $contact['id'],
|
'url' => 'network?contactid=' . $contact['id'],
|
||||||
'external_url' => Contact::magicLink($contact['url']),
|
'external_url' => Contact::magicLink($contact['url']),
|
||||||
'name' => $contact['name'],
|
'name' => $contact['name'],
|
||||||
'cid' => $contact['id'],
|
'cid' => $contact['id'],
|
||||||
|
|
|
@ -1727,6 +1727,14 @@ class BBCode
|
||||||
$text = Smilies::replace($text);
|
$text = Smilies::replace($text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$for_plaintext && DI::config()->get('system', 'big_emojis') && ($simple_html != self::DIASPORA)) {
|
||||||
|
$conv = html_entity_decode(str_replace([' ', "\n", "\r"], '', $text));
|
||||||
|
// Emojis are always 4 byte Unicode characters
|
||||||
|
if (!empty($conv) && (strlen($conv) / mb_strlen($conv) == 4)) {
|
||||||
|
$text = '<span style="font-size: xx-large; line-height: initial;">' . $text . '</span>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!$for_plaintext) {
|
if (!$for_plaintext) {
|
||||||
if (in_array($simple_html, [self::OSTATUS, self::ACTIVITYPUB])) {
|
if (in_array($simple_html, [self::OSTATUS, self::ACTIVITYPUB])) {
|
||||||
$text = preg_replace_callback("/\[url\](.*?)\[\/url\]/ism", 'self::convertUrlForActivityPubCallback', $text);
|
$text = preg_replace_callback("/\[url\](.*?)\[\/url\]/ism", 'self::convertUrlForActivityPubCallback', $text);
|
||||||
|
|
|
@ -135,8 +135,9 @@ class Database
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->emulate_prepares = (bool)$this->configCache->get('database', 'emulate_prepares');
|
$this->emulate_prepares = (bool)$this->configCache->get('database', 'emulate_prepares');
|
||||||
|
$this->pdo_emulate_prepares = (bool)$this->configCache->get('database', 'pdo_emulate_prepares');
|
||||||
|
|
||||||
if (class_exists('\PDO') && in_array('mysql', PDO::getAvailableDrivers())) {
|
if (!$this->configCache->get('database', 'disable_pdo') && class_exists('\PDO') && in_array('mysql', PDO::getAvailableDrivers())) {
|
||||||
$this->driver = 'pdo';
|
$this->driver = 'pdo';
|
||||||
$connect = "mysql:host=" . $server . ";dbname=" . $db;
|
$connect = "mysql:host=" . $server . ";dbname=" . $db;
|
||||||
|
|
||||||
|
@ -150,7 +151,7 @@ class Database
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->connection = @new PDO($connect, $user, $pass);
|
$this->connection = @new PDO($connect, $user, $pass);
|
||||||
$this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
|
$this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, $this->pdo_emulate_prepares);
|
||||||
$this->connected = true;
|
$this->connected = true;
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
$this->connected = false;
|
$this->connected = false;
|
||||||
|
@ -504,6 +505,7 @@ class Database
|
||||||
$sql = "/*" . System::callstack() . " */ " . $sql;
|
$sql = "/*" . System::callstack() . " */ " . $sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$is_error = false;
|
||||||
$this->error = '';
|
$this->error = '';
|
||||||
$this->errorno = 0;
|
$this->errorno = 0;
|
||||||
$this->affected_rows = 0;
|
$this->affected_rows = 0;
|
||||||
|
@ -533,6 +535,7 @@ class Database
|
||||||
$this->error = $errorInfo[2];
|
$this->error = $errorInfo[2];
|
||||||
$this->errorno = $errorInfo[1];
|
$this->errorno = $errorInfo[1];
|
||||||
$retval = false;
|
$retval = false;
|
||||||
|
$is_error = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$this->affected_rows = $retval->rowCount();
|
$this->affected_rows = $retval->rowCount();
|
||||||
|
@ -545,6 +548,7 @@ class Database
|
||||||
$this->error = $errorInfo[2];
|
$this->error = $errorInfo[2];
|
||||||
$this->errorno = $errorInfo[1];
|
$this->errorno = $errorInfo[1];
|
||||||
$retval = false;
|
$retval = false;
|
||||||
|
$is_error = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,6 +566,7 @@ class Database
|
||||||
$this->error = $errorInfo[2];
|
$this->error = $errorInfo[2];
|
||||||
$this->errorno = $errorInfo[1];
|
$this->errorno = $errorInfo[1];
|
||||||
$retval = false;
|
$retval = false;
|
||||||
|
$is_error = true;
|
||||||
} else {
|
} else {
|
||||||
$retval = $stmt;
|
$retval = $stmt;
|
||||||
$this->affected_rows = $retval->rowCount();
|
$this->affected_rows = $retval->rowCount();
|
||||||
|
@ -580,6 +585,7 @@ class Database
|
||||||
$this->error = $this->connection->error;
|
$this->error = $this->connection->error;
|
||||||
$this->errorno = $this->connection->errno;
|
$this->errorno = $this->connection->errno;
|
||||||
$retval = false;
|
$retval = false;
|
||||||
|
$is_error = true;
|
||||||
} else {
|
} else {
|
||||||
if (isset($retval->num_rows)) {
|
if (isset($retval->num_rows)) {
|
||||||
$this->affected_rows = $retval->num_rows;
|
$this->affected_rows = $retval->num_rows;
|
||||||
|
@ -596,6 +602,7 @@ class Database
|
||||||
$this->error = $stmt->error;
|
$this->error = $stmt->error;
|
||||||
$this->errorno = $stmt->errno;
|
$this->errorno = $stmt->errno;
|
||||||
$retval = false;
|
$retval = false;
|
||||||
|
$is_error = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,6 +630,7 @@ class Database
|
||||||
$this->error = $this->connection->error;
|
$this->error = $this->connection->error;
|
||||||
$this->errorno = $this->connection->errno;
|
$this->errorno = $this->connection->errno;
|
||||||
$retval = false;
|
$retval = false;
|
||||||
|
$is_error = true;
|
||||||
} else {
|
} else {
|
||||||
$stmt->store_result();
|
$stmt->store_result();
|
||||||
$retval = $stmt;
|
$retval = $stmt;
|
||||||
|
@ -631,6 +639,16 @@ class Database
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See issue https://github.com/friendica/friendica/issues/8572
|
||||||
|
// Ensure that we always get an error message on an error.
|
||||||
|
if ($is_error && empty($this->errorno)) {
|
||||||
|
$this->errorno = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($is_error && empty($this->error)) {
|
||||||
|
$this->error = 'Unknown database error';
|
||||||
|
}
|
||||||
|
|
||||||
// We are having an own error logging in the function "e"
|
// We are having an own error logging in the function "e"
|
||||||
if (($this->errorno != 0) && !$called_from_e) {
|
if (($this->errorno != 0) && !$called_from_e) {
|
||||||
// We have to preserve the error code, somewhere in the logging it get lost
|
// We have to preserve the error code, somewhere in the logging it get lost
|
||||||
|
@ -642,8 +660,8 @@ class Database
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger->error('DB Error', [
|
$this->logger->error('DB Error', [
|
||||||
'code' => $this->errorno,
|
'code' => $errorno,
|
||||||
'error' => $this->error,
|
'error' => $error,
|
||||||
'callstack' => System::callstack(8),
|
'callstack' => System::callstack(8),
|
||||||
'params' => $this->replaceParameters($sql, $args),
|
'params' => $this->replaceParameters($sql, $args),
|
||||||
]);
|
]);
|
||||||
|
@ -654,21 +672,21 @@ class Database
|
||||||
// It doesn't make sense to continue when the database connection was lost
|
// It doesn't make sense to continue when the database connection was lost
|
||||||
if ($this->in_retrial) {
|
if ($this->in_retrial) {
|
||||||
$this->logger->notice('Giving up retrial because of database error', [
|
$this->logger->notice('Giving up retrial because of database error', [
|
||||||
'code' => $this->errorno,
|
'code' => $errorno,
|
||||||
'error' => $this->error,
|
'error' => $error,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
$this->logger->notice('Couldn\'t reconnect after database error', [
|
$this->logger->notice('Couldn\'t reconnect after database error', [
|
||||||
'code' => $this->errorno,
|
'code' => $errorno,
|
||||||
'error' => $this->error,
|
'error' => $error,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
exit(1);
|
exit(1);
|
||||||
} else {
|
} else {
|
||||||
// We try it again
|
// We try it again
|
||||||
$this->logger->notice('Reconnected after database error', [
|
$this->logger->notice('Reconnected after database error', [
|
||||||
'code' => $this->errorno,
|
'code' => $errorno,
|
||||||
'error' => $this->error,
|
'error' => $error,
|
||||||
]);
|
]);
|
||||||
$this->in_retrial = true;
|
$this->in_retrial = true;
|
||||||
$ret = $this->p($sql, $args);
|
$ret = $this->p($sql, $args);
|
||||||
|
@ -745,8 +763,8 @@ class Database
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger->error('DB Error', [
|
$this->logger->error('DB Error', [
|
||||||
'code' => $this->errorno,
|
'code' => $errorno,
|
||||||
'error' => $this->error,
|
'error' => $error,
|
||||||
'callstack' => System::callstack(8),
|
'callstack' => System::callstack(8),
|
||||||
'params' => $this->replaceParameters($sql, $params),
|
'params' => $this->replaceParameters($sql, $params),
|
||||||
]);
|
]);
|
||||||
|
@ -755,8 +773,8 @@ class Database
|
||||||
// A reconnect like in $this->p could be dangerous with modifications
|
// A reconnect like in $this->p could be dangerous with modifications
|
||||||
if ($errorno == 2006) {
|
if ($errorno == 2006) {
|
||||||
$this->logger->notice('Giving up because of database error', [
|
$this->logger->notice('Giving up because of database error', [
|
||||||
'code' => $this->errorno,
|
'code' => $errorno,
|
||||||
'error' => $this->error,
|
'error' => $error,
|
||||||
]);
|
]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -1029,7 +1047,7 @@ class Database
|
||||||
$success = $this->e("LOCK TABLES " . DBA::buildTableString($table) . " WRITE");
|
$success = $this->e("LOCK TABLES " . DBA::buildTableString($table) . " WRITE");
|
||||||
|
|
||||||
if ($this->driver == 'pdo') {
|
if ($this->driver == 'pdo') {
|
||||||
$this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
|
$this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, $this->pdo_emulate_prepares);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$success) {
|
if (!$success) {
|
||||||
|
@ -1062,7 +1080,7 @@ class Database
|
||||||
$success = $this->e("UNLOCK TABLES");
|
$success = $this->e("UNLOCK TABLES");
|
||||||
|
|
||||||
if ($this->driver == 'pdo') {
|
if ($this->driver == 'pdo') {
|
||||||
$this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
|
$this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, $this->pdo_emulate_prepares);
|
||||||
$this->e("SET autocommit=1");
|
$this->e("SET autocommit=1");
|
||||||
} else {
|
} else {
|
||||||
$this->connection->autocommit(true);
|
$this->connection->autocommit(true);
|
||||||
|
|
|
@ -353,6 +353,15 @@ class GServer
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sanitize incoming data, see https://github.com/friendica/friendica/issues/8565
|
||||||
|
$data['subscribe'] = (bool)$data['subscribe'] ?? false;
|
||||||
|
|
||||||
|
if (!$data['subscribe'] || empty($data['scope']) || !in_array(strtolower($data['scope']), ['all', 'tags'])) {
|
||||||
|
$data['scope'] = '';
|
||||||
|
$data['subscribe'] = false;
|
||||||
|
$data['tags'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
$gserver = DBA::selectFirst('gserver', ['id', 'relay-subscribe', 'relay-scope'], ['nurl' => Strings::normaliseLink($server_url)]);
|
$gserver = DBA::selectFirst('gserver', ['id', 'relay-subscribe', 'relay-scope'], ['nurl' => Strings::normaliseLink($server_url)]);
|
||||||
if (!DBA::isResult($gserver)) {
|
if (!DBA::isResult($gserver)) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -3139,7 +3139,9 @@ class Diaspora
|
||||||
$json = json_encode(["iv" => $b_iv, "key" => $b_aes_key]);
|
$json = json_encode(["iv" => $b_iv, "key" => $b_aes_key]);
|
||||||
|
|
||||||
$encrypted_key_bundle = "";
|
$encrypted_key_bundle = "";
|
||||||
openssl_public_encrypt($json, $encrypted_key_bundle, $pubkey);
|
if (!@openssl_public_encrypt($json, $encrypted_key_bundle, $pubkey)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$json_object = json_encode(
|
$json_object = json_encode(
|
||||||
["aes_key" => base64_encode($encrypted_key_bundle),
|
["aes_key" => base64_encode($encrypted_key_bundle),
|
||||||
|
|
|
@ -45,8 +45,23 @@ return [
|
||||||
'database' => '',
|
'database' => '',
|
||||||
|
|
||||||
// charset (String)
|
// charset (String)
|
||||||
// Database connexion charset. Changing this value will likely corrupt special characters.
|
// Database connection charset. Changing this value will likely corrupt special characters.
|
||||||
'charset' => 'utf8mb4',
|
'charset' => 'utf8mb4',
|
||||||
|
|
||||||
|
// emulate_prepares (Boolean) (Experimental)
|
||||||
|
// If enabled, prepared statements will be emulated.
|
||||||
|
// In combination with MySQLi this will cast all return values to strings.
|
||||||
|
'emulate_prepares' => false,
|
||||||
|
|
||||||
|
// pdo_emulate_prepares (Boolean) (Experimental)
|
||||||
|
// If enabled, the builtin emulation for prepared statements is used.
|
||||||
|
// Due to limitations of that emulation (all return values are casted as strings)
|
||||||
|
// this will most likely cause issues and should not be used on production systems.
|
||||||
|
'pdo_emulate_prepares' => false,
|
||||||
|
|
||||||
|
// disable_pdo (Boolean)
|
||||||
|
// PDO is used by default (if available). Otherwise MySQLi will be used.
|
||||||
|
'disable_pdo' => false,
|
||||||
],
|
],
|
||||||
'config' => [
|
'config' => [
|
||||||
// admin_email (Comma-separated list)
|
// admin_email (Comma-separated list)
|
||||||
|
@ -88,6 +103,10 @@ return [
|
||||||
// chose "Remember me" when logging in is considered logged out.
|
// chose "Remember me" when logging in is considered logged out.
|
||||||
'auth_cookie_lifetime' => 7,
|
'auth_cookie_lifetime' => 7,
|
||||||
|
|
||||||
|
// big_emojis (Boolean)
|
||||||
|
// Display "Emoji Only" posts in big.
|
||||||
|
'big_emojis' => false,
|
||||||
|
|
||||||
// block_local_dir (Boolean)
|
// block_local_dir (Boolean)
|
||||||
// Deny public access to the local user directory.
|
// Deny public access to the local user directory.
|
||||||
'block_local_dir' => false,
|
'block_local_dir' => false,
|
||||||
|
|
|
@ -56,6 +56,8 @@ class StaticDatabase extends Database
|
||||||
$this->driver = 'pdo';
|
$this->driver = 'pdo';
|
||||||
$this->connection = self::$staticConnection;
|
$this->connection = self::$staticConnection;
|
||||||
$this->connected = true;
|
$this->connected = true;
|
||||||
|
$this->emulate_prepares = false;
|
||||||
|
$this->pdo_emulate_prepares = false;
|
||||||
|
|
||||||
return $this->connected;
|
return $this->connected;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,9 @@ class BBCodeTest extends MockedTest
|
||||||
$this->configMock->shouldReceive('get')
|
$this->configMock->shouldReceive('get')
|
||||||
->with('system', 'no_smilies')
|
->with('system', 'no_smilies')
|
||||||
->andReturn(false);
|
->andReturn(false);
|
||||||
|
$this->configMock->shouldReceive('get')
|
||||||
|
->with('system', 'big_emojis')
|
||||||
|
->andReturn(false);
|
||||||
|
|
||||||
$l10nMock = \Mockery::mock(L10n::class);
|
$l10nMock = \Mockery::mock(L10n::class);
|
||||||
$l10nMock->shouldReceive('t')->withAnyArgs()->andReturnUsing(function ($args) { return $args; });
|
$l10nMock->shouldReceive('t')->withAnyArgs()->andReturnUsing(function ($args) { return $args; });
|
||||||
|
|
|
@ -202,7 +202,7 @@ function vier_community_info()
|
||||||
$selected = (($cid == $contact['id']) ? ' forum-selected' : '');
|
$selected = (($cid == $contact['id']) ? ' forum-selected' : '');
|
||||||
|
|
||||||
$entry = [
|
$entry = [
|
||||||
'url' => 'network?cid=' . $contact['id'],
|
'url' => 'network?contactid=' . $contact['id'],
|
||||||
'external_url' => Contact::magicLink($contact['url']),
|
'external_url' => Contact::magicLink($contact['url']),
|
||||||
'name' => $contact['name'],
|
'name' => $contact['name'],
|
||||||
'cid' => $contact['id'],
|
'cid' => $contact['id'],
|
||||||
|
|
Loading…
Reference in New Issue
Block a user