aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Zotlabs/Module/Admin/Accounts.php258
-rw-r--r--doc/en/context/ru/connections/help.html4
-rw-r--r--include/account.php94
-rw-r--r--tests/unit/Module/AdminAccountsTest.php173
-rw-r--r--tests/unit/includes/dba/_files/account.yml15
-rw-r--r--tests/unit/includes/dba/_files/register.yml20
-rw-r--r--view/js/main.js21
-rw-r--r--view/tpl/contact_edit_header.tpl2
-rw-r--r--view/tpl/direntry.tpl2
-rw-r--r--view/tpl/event_form.tpl8
-rw-r--r--view/tpl/event_item_header.tpl2
-rw-r--r--view/tpl/events-js.tpl10
-rw-r--r--view/tpl/generic_addon_settings.tpl2
-rw-r--r--view/tpl/install_checks.tpl4
-rw-r--r--view/tpl/uexport.tpl12
15 files changed, 428 insertions, 199 deletions
diff --git a/Zotlabs/Module/Admin/Accounts.php b/Zotlabs/Module/Admin/Accounts.php
index 6f7cb0311..108231d7d 100644
--- a/Zotlabs/Module/Admin/Accounts.php
+++ b/Zotlabs/Module/Admin/Accounts.php
@@ -6,133 +6,33 @@ use Zotlabs\Lib\Config;
class Accounts {
- /**
- * @brief Handle POST actions on accounts admin page.
- *
- * This function is called when on the admin user/account page the form was
- * submitted to handle multiple operations at once. If one of the icons next
- * to an entry are pressed the function admin_page_accounts() will handle this.
- *
- */
const MYP = 'ZAR'; // ZAR2x
const VERSION = '2.0.0';
- function post() {
+ /**
+ * Handle POST actions on accounts admin page.
+ */
+ public function post() {
- $pending = ( x($_POST, 'pending') ? $_POST['pending'] : array() );
- $users = ( x($_POST, 'user') ? $_POST['user'] : array() );
- $blocked = ( x($_POST, 'blocked') ? $_POST['blocked'] : array() );
+ $pending = x($_POST, 'pending') ? $_POST['pending'] : array();
check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts');
- $isajax = is_ajax();
- $rc = 0;
-
- If (!is_site_admin()) {
- if ($isajax) {
- killme();
- exit;
- }
- goaway(z_root() . '/');
- }
-
- if ($isajax) {
- //$debug = print_r($_SESSION[self::MYP],true);
- $zarop = (x($_POST['zardo']) && preg_match('/^[ad]{1,1}$/', $_POST['zardo']) )
- ? $_POST['zardo'] : '';
- // zarat arrives with leading underscore _n
- $zarat = (x($_POST['zarat']) && preg_match('/^_{1,1}[0-9]{1,6}$/', $_POST['zarat']) )
- ? substr($_POST['zarat'],1) : '';
- $zarse = (x($_POST['zarse']) && preg_match('/^[0-9a-f]{8,8}$/', $_POST['zarse']) )
- ? hex2bin($_POST['zarse']) : '';
-
- if ($zarop && $zarat >= 0 && $zarse && $zarse == $_SESSION[self::MYP]['h'][$zarat]) {
-
- //
- if ($zarop == 'd') {
- $rd = q("UPDATE register SET reg_vital = 0 WHERE reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
- intval($_SESSION[self::MYP]['i'][$zarat]),
- dbesc($_SESSION[self::MYP]['h'][$zarat])
- );
- $rc = '×';
- }
- elseif ($zarop == 'a') {
- // approval, REGISTER_DENIED by user 0x0040, REGISTER_AGREED by user 0x0020 @Regate
- $rd = q("UPDATE register SET reg_flags = (reg_flags & ~ 16), "
- . " reg_vital = (CASE (reg_flags & ~ 48) WHEN 0 THEN 0 ELSE 1 END) "
- . " WHERE reg_vital = 1 AND reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
- intval($_SESSION[self::MYP]['i'][$zarat]),
- dbesc($_SESSION[self::MYP]['h'][$zarat])
- );
- $rc = 0;
- $rs = q("SELECT * from register WHERE reg_id = %d ",
- intval($_SESSION[self::MYP]['i'][$zarat])
- );
- if ($rs && ($rs[0]['reg_flags'] & ~ 48) == 0) {
- // create account
- $rc = 'ok'.$rs[0]['reg_id'];
- $ac = create_account_from_register($rs[0]);
- if ( $ac['success'] ) {
- $rc .= '✔';
-
- $auto_create = Config::Get('system','auto_channel_create',1);
-
- if($auto_create) {
- $reonar = json_decode($rs[0]['reg_stuff'], true);
- // prepare channel creation
- if($reonar['chan.name'])
- set_aconfig($ac['account']['account_id'], 'register', 'channel_name', $reonar['chan.name']);
-
- if($reonar['chan.did1'])
- set_aconfig($ac['account']['account_id'], 'register', 'channel_address', $reonar['chan.did1']);
-
- $permissions_role = Config::Get('system','default_permissions_role');
- if($permissions_role)
- set_aconfig($ac['account']['account_id'], 'register', 'permissions_role', $permissions_role);
-
- // create channel
- $new_channel = auto_channel_create($ac['account']['account_id']);
-
- if($new_channel['success']) {
- $rc .= ' c,ok' . $new_channel['channel']['channel_id'] . '✔';
- }
- else {
- $rc .= ' c ×';
- }
- }
-
-
- }
- } else {
- $rc='oh ×';
- }
- }
- echo json_encode(array('re' => $zarop, 'at' => '_' . $zarat, 'rc' => $rc));
- }
+ if (is_ajax()) {
+ $this->handle_ajax_request();
killme();
- exit;
}
// change to switch structure?
// account block/unblock button was submitted
if (x($_POST, 'page_accounts_block')) {
- for ($i = 0; $i < count($users); $i++) {
- // if account is blocked remove blocked bit-flag, otherwise add blocked bit-flag
- $op = ($blocked[$i]) ? '& ~' : '| ';
- q("UPDATE account SET account_flags = (account_flags $op%d) WHERE account_id = %d",
- intval(ACCOUNT_BLOCKED),
- intval($users[$i])
- );
- }
- notice( sprintf( tt("%s account blocked/unblocked", "%s account blocked/unblocked", count($users)), count($users)) );
+ $this->block_unblock_accounts();
}
+
// account delete button was submitted
if (x($_POST, 'page_accounts_delete')) {
- foreach ($users as $uid){
- account_remove($uid, true, false);
- }
- notice( sprintf( tt("%s account deleted", "%s accounts deleted", count($users)), count($users)) );
+ $this->delete_accounts();
}
// registration approved button was submitted
if (x($_POST, 'page_accounts_approve')) {
@@ -351,5 +251,143 @@ class Accounts {
return $o;
}
+ private function handle_ajax_request(): void {
+ //$debug = print_r($_SESSION[self::MYP],true);
+ $zarop = (x($_POST['zardo']) && preg_match('/^[ad]{1,1}$/', $_POST['zardo']) )
+ ? $_POST['zardo'] : '';
+ // zarat arrives with leading underscore _n
+ $zarat = (x($_POST['zarat']) && preg_match('/^_{1,1}[0-9]{1,6}$/', $_POST['zarat']) )
+ ? substr($_POST['zarat'],1) : '';
+ $zarse = (x($_POST['zarse']) && preg_match('/^[0-9a-f]{8,8}$/', $_POST['zarse']) )
+ ? hex2bin($_POST['zarse']) : '';
+
+ if ($zarop && $zarat >= 0 && $zarse && $zarse == $_SESSION[self::MYP]['h'][$zarat]) {
+
+ //
+ if ($zarop == 'd') {
+ $rd = q("UPDATE register SET reg_vital = 0 WHERE reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
+ intval($_SESSION[self::MYP]['i'][$zarat]),
+ dbesc($_SESSION[self::MYP]['h'][$zarat])
+ );
+ $rc = '×';
+ }
+ elseif ($zarop == 'a') {
+ // approval, REGISTER_DENIED by user 0x0040, REGISTER_AGREED by user 0x0020 @Regate
+ $rd = q("UPDATE register SET reg_flags = (reg_flags & ~ 16), "
+ . " reg_vital = (CASE (reg_flags & ~ 48) WHEN 0 THEN 0 ELSE 1 END) "
+ . " WHERE reg_vital = 1 AND reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
+ intval($_SESSION[self::MYP]['i'][$zarat]),
+ dbesc($_SESSION[self::MYP]['h'][$zarat])
+ );
+ $rc = 0;
+ $rs = q("SELECT * from register WHERE reg_id = %d ",
+ intval($_SESSION[self::MYP]['i'][$zarat])
+ );
+ if ($rs && ($rs[0]['reg_flags'] & ~ 48) == 0) {
+ // create account
+ $rc = 'ok'.$rs[0]['reg_id'];
+ $ac = create_account_from_register($rs[0]);
+ if ( $ac['success'] ) {
+ $rc .= '✔';
+
+ $auto_create = Config::Get('system','auto_channel_create',1);
+
+ if($auto_create) {
+ $reonar = json_decode($rs[0]['reg_stuff'], true);
+ // prepare channel creation
+ if($reonar['chan.name'])
+ set_aconfig($ac['account']['account_id'], 'register', 'channel_name', $reonar['chan.name']);
+
+ if($reonar['chan.did1'])
+ set_aconfig($ac['account']['account_id'], 'register', 'channel_address', $reonar['chan.did1']);
+
+ $permissions_role = Config::Get('system','default_permissions_role');
+ if($permissions_role)
+ set_aconfig($ac['account']['account_id'], 'register', 'permissions_role', $permissions_role);
+
+ // create channel
+ $new_channel = auto_channel_create($ac['account']['account_id']);
+
+ if($new_channel['success']) {
+ $rc .= ' c,ok' . $new_channel['channel']['channel_id'] . '✔';
+ }
+ else {
+ $rc .= ' c ×';
+ }
+ }
+
+
+ }
+ } else {
+ $rc='oh ×';
+ }
+ }
+ echo json_encode(array('re' => $zarop, 'at' => '_' . $zarat, 'rc' => $rc));
+ }
+ }
+
+ /**
+ * Block or unblock accounts given by the `user` and `blocked` POST params.
+ *
+ * The post params `user` and `blocked` must be present and arrays of equal
+ * lengths. The `user` array should contain account id's or the accounts to
+ * process, and the `blocked` array holds a corresponding boolean value to
+ * indicate that the account at the same offset in the `user` array is or is
+ * not blocked.
+ *
+ * An account that is _not_ blocked will be blocked, and accounts that _are_
+ * blocked will be unblocked.
+ *
+ * @SuppressWarnings(PHPMD.ShortVariable)
+ */
+ private function block_unblock_accounts(): void {
+ if (!isset($_POST['user']) || !isset($_POST['blocked'])) {
+ return;
+ }
+
+ $users = $_POST['user'];
+ $blocked = $_POST['blocked'];
+
+ if (!is_array($users) || !is_array($blocked)) {
+ return;
+ }
+
+ foreach($users as $i => $id) {
+ // if account is blocked remove blocked bit-flag, otherwise add blocked bit-flag
+ $op = $blocked[$i] ? '& ~' : '| ';
+
+ q("UPDATE account SET account_flags = (account_flags $op%d) WHERE account_id = %d",
+ intval(ACCOUNT_BLOCKED),
+ intval($id)
+ );
+ }
+
+ $count = count($users);
+ $fmt = tt("%s account blocked/unblocked", "%s account blocked/unblocked", $count);
+ notice(sprintf($fmt, $count));
+ }
+
+ /**
+ * Delete multiple accounts given by the `user` POST param.
+ */
+ private function delete_accounts(): void {
+ if (!isset($_POST['user'])) {
+ return;
+ }
+
+ $users = $_POST['user'];
+
+ if (!is_array($users)) {
+ return;
+ }
+
+ foreach ($users as $uid){
+ account_remove($uid, true, false);
+ }
+
+ $count = count($users);
+ $fmt = tt("%s account deleted", "%s accounts deleted", $count);
+ notice(sprintf($fmt, $count));
+ }
}
diff --git a/doc/en/context/ru/connections/help.html b/doc/en/context/ru/connections/help.html
index 6c9b9a0e9..b5996e0d0 100644
--- a/doc/en/context/ru/connections/help.html
+++ b/doc/en/context/ru/connections/help.html
@@ -1,7 +1,7 @@
<dl class="dl-horizontal">
- <dd>На этой странице отображается список всех подключений этого канала. Список можно отсортировать и отфильтровать с помощью кнопки <a href='#' onclick='contextualHelpFocus(".section-title-wrapper", 0); return false;' title="Нажмите чтобы выделить элемент..."><button class='btn btn-outline-secondary btn-sm'><i class="fa fa-filter"></i></button></a> рядом с кнопкой поиска.</dd>
+ <dd>На этой странице отображается список всех подключений этого канала. Список можно отсортировать и отфильтровать с помощью кнопки <a href='#' onclick='contextualHelpFocus(".section-title-wrapper", 0); return false;' title="Нажмите чтобы выделить элемент..."><button class='btn btn-outline-secondary btn-sm'><i class="bi bi-funnel-fill"></i></button></a> рядом с кнопкой поиска.</dd>
<dt>Сведения о контакте</dt>
<dd>Каждая запись в списке показывает информацию о конкретном контакте. Полупрозрачное изображение профиля указывает на заархивированное соединение.</dd>
<dt>Статус контакта</dt>
<dd>Контакт может находиться в разных состояниях: <ul><li>Заархивирован</li><li>Игнорируется</li><li>Заблокирован</li><li>Скрыт</li></ul></dd>
-</dl> \ No newline at end of file
+</dl>
diff --git a/include/account.php b/include/account.php
index 884c07389..615c802f4 100644
--- a/include/account.php
+++ b/include/account.php
@@ -613,59 +613,45 @@ function send_register_success_email($email,$password) {
}
/**
- * @brief Allows a user registration.
+ * Mark a pending registration as approved, and notify the account
+ * holder by email.
*
- * @param string $hash
- * @return array|boolean
+ * @param string $hash The registration hash of the entry to approve
+ *
+ * @return bool
*/
-function account_allow($hash) {
-
- $ret = array('success' => false);
+function account_allow(string $hash): bool {
$register = q("SELECT * FROM register WHERE reg_hash = '%s' LIMIT 1",
dbesc($hash)
);
- if(! $register)
- return $ret;
+ if (! $register) {
+ logger(
+ "Entry with hash '{$hash}' was not found in the register table.",
+ LOGGER_NORMAL,
+ LOG_ERR
+ );
+ return false;
+ }
- $account = q("SELECT * FROM account WHERE account_id = %d LIMIT 1",
- intval($register[0]['reg_uid'])
- );
+ $account = get_account_by_id($register[0]['reg_uid']);
- // a register entry without account assigned to
- if(! $account)
- return $ret;
+ if (! $account) {
+ logger(
+ "Account '{$register[0]['reg_uid']}' mentioned by registration hash '{$hash}' was not found.",
+ LOGGER_NORMAL,
+ LOG_ERR
+ );
+ return false;
+ }
- // [hilmar ->
+ $transaction = new DbaTransaction(DBA::$dba);
- q("START TRANSACTION");
- //q("DELETE FROM register WHERE reg_hash = '%s'",
- // dbesc($register[0]['reg_hash'])
- //);
$r1 = q("UPDATE register SET reg_vital = 0 WHERE reg_hash = '%s'",
dbesc($register[0]['reg_hash'])
);
- /* instead of ...
-
- // unblock
- q("UPDATE account SET account_flags = (account_flags & ~%d) "
- . " WHERE (account_flags & %d)>0 AND account_id = %d",
- intval(ACCOUNT_BLOCKED),
- intval(ACCOUNT_BLOCKED),
- intval($register[0]['reg_uid'])
- );
-
- // unpend
- q("UPDATE account SET account_flags = (account_flags & ~%d) "
- . " WHERE (account_flags & %d)>0 AND account_id = %d",
- intval(ACCOUNT_PENDING),
- intval(ACCOUNT_PENDING),
- intval($register[0]['reg_uid'])
- );
-
- */
// together unblock and unpend
$r2 = q("UPDATE account SET account_flags = %d WHERE account_id = %d",
intval($account['account_flags']
@@ -674,9 +660,7 @@ function account_allow($hash) {
);
if($r1 && $r2) {
- q("COMMIT");
-
- // <- hilmar]
+ $transaction->commit();
push_lang($register[0]['reg_lang']);
@@ -684,35 +668,35 @@ function account_allow($hash) {
$email_msg = replace_macros($email_tpl, array(
'$sitename' => Config::Get('system','sitename'),
'$siteurl' => z_root(),
- '$username' => $account[0]['account_email'],
- '$email' => $account[0]['account_email'],
+ '$username' => $account['account_email'],
+ '$email' => $account['account_email'],
'$password' => '',
- '$uid' => $account[0]['account_id']
+ '$uid' => $account['account_id']
));
$res = z_mail(
[
- 'toEmail' => $account[0]['account_email'],
+ 'toEmail' => $account['account_email'],
'messageSubject' => sprintf( t('Registration details for %s'), Config::Get('system','sitename')),
'textVersion' => $email_msg,
]
);
- pop_lang();
+ if (! $res) {
+ info(t("Sending account approval email to {$account['email']} failed..."));
+ }
- if(Config::Get('system', 'auto_channel_create', 1))
- auto_channel_create($register[0]['uid']);
+ pop_lang();
- if ($res) {
- info( t('Account approved.') . EOL );
- return true;
+ if(Config::Get('system', 'auto_channel_create', 1)) {
+ auto_channel_create($register[0]['reg_uid']);
}
- // [hilmar ->
- } else {
- q("ROLLBACK");
+ info( t('Account approved.') . EOL );
+ return true;
}
- // <- hilmar]
+
+ return false;
}
diff --git a/tests/unit/Module/AdminAccountsTest.php b/tests/unit/Module/AdminAccountsTest.php
new file mode 100644
index 000000000..2c76f2779
--- /dev/null
+++ b/tests/unit/Module/AdminAccountsTest.php
@@ -0,0 +1,173 @@
+<?php
+/*
+ * SPDX-FileCopyrightText: 2024 Hubzilla Community
+ * SPDX-FileContributor: Harald Eilertsen
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+namespace Zotlabs\Tests\Unit\Module;
+
+use PHPUnit\Framework\Attributes\Before;
+
+class AdminAccountsTest extends TestCase {
+
+ protected $stub_check_security;
+ protected $stub_is_site_admin;
+ protected $stub_goaway;
+ protected $stub_notice;
+
+ protected array $notice;
+
+ /**
+ * Set up the stubs common for the tests.
+ */
+ #[Before]
+ public function setup_stubs(): void {
+ $this->stub_check_form_security();
+ $this->stub_is_site_admin();
+ $this->stub_goaway();
+ $this->stub_notice();
+ }
+
+ public function test_blocking_accounts_marks_selected_accounts_as_blocked(): void {
+ $params = [
+ 'user' => [ 42 ],
+ 'blocked' => [ false ],
+ 'page_accounts_block' => true,
+ ];
+
+ try {
+ $this->post('admin/accounts', [], $params);
+ } catch (RedirectException $redirect) {
+ $this->assertEquals(z_root() . '/admin/accounts', $redirect->getMessage());
+ }
+
+ $account = get_account_by_id(42);
+ $this->assertEquals(ACCOUNT_BLOCKED, $account['account_flags'] & ACCOUNT_BLOCKED);
+
+ $this->assertEquals('1 account blocked/unblocked', $this->notice[0]);
+ }
+
+ public function test_unblocking_accounts_clears_the_blocked_flag(): void {
+ // Pass two users to the module, one that is not blocked,
+ // and one that is.
+ $params = [
+ 'user' => [ 42, 44 ],
+ 'blocked' => [ false, true ],
+ 'page_accounts_block' => true,
+ ];
+
+ try {
+ $this->post('admin/accounts', [], $params);
+ } catch (RedirectException $redirect) {
+ $this->assertEquals(z_root() . '/admin/accounts', $redirect->getMessage());
+ }
+
+ // We expect the previously unblocked account to be blocked.
+ $account = get_account_by_id(42);
+ $this->assertEquals(ACCOUNT_BLOCKED, $account['account_flags'] & ACCOUNT_BLOCKED);
+
+ // We expect the previously blocked account to be unblocked.
+ $blocked_account = get_account_by_id(44);
+ $this->assertEquals(0, $blocked_account['account_flags'] & ACCOUNT_BLOCKED);
+
+ $this->assertEquals('2 account blocked/unblocked', $this->notice[0]);
+ }
+
+ public function test_deleting_accouns_remove_them_from_db(): void {
+ $params = [
+ 'user' => [ 42, 44 ],
+ 'page_accounts_delete' => true,
+ ];
+
+ try {
+ $this->post('admin/accounts', [], $params);
+ } catch (RedirectException $redirect) {
+ $this->assertEquals(z_root() . '/admin/accounts', $redirect->getMessage());
+ }
+
+ $this->assertEquals(null, get_account_by_id(42));
+ $this->assertEquals(null, get_account_by_id(44));
+ }
+
+ public function test_approving_pending_accounts_clears_pending_flag(): void {
+
+ // Catch calls to the php mail function
+ //
+ // This is just to get it out of the way, we don't care about
+ // how many times it's called, or with what args here.
+ $this->getFunctionMock('Zotlabs\Lib', 'mail')
+ ->expects($this->any())
+ ->willReturn(true);
+
+ $params = [
+ 'pending' => [
+ $this->fixtures['register'][0]['reg_hash'],
+ $this->fixtures['register'][1]['reg_hash']
+ ],
+ 'page_accounts_approve' => true,
+ ];
+
+ try {
+ $this->post('admin/accounts', [], $params);
+ } catch (RedirectException $redirect) {
+ $this->assertEquals(z_root() . '/admin/accounts', $redirect->getMessage());
+ }
+
+ foreach ([45, 46] as $id) {
+ $account = get_account_by_id($id);
+ $this->assertEquals(0, $account['account_flags'] & ACCOUNT_PENDING);
+ }
+ }
+
+ /**
+ * Stub the check_form_security_token_ForbiddenOnErr.
+ */
+ protected function stub_check_form_security(): void {
+ $this->stub_check_security =
+ $this->getFunctionMock('Zotlabs\Module\Admin', 'check_form_security_token_redirectOnErr')
+ ->expects($this->once())
+ ->with(
+ $this->identicalTo('/admin/accounts'),
+ $this->identicalTo('admin_accounts'))
+ ->willReturn(true);
+ }
+
+ /**
+ * Stub the call to is_site_admin in the Admin main module.
+ */
+ protected function stub_is_site_admin(): void {
+ $this->stub_is_site_admin =
+ $this->getFunctionMock('Zotlabs\Module', 'is_site_admin')
+ ->expects($this->once())
+ ->willReturn(true);
+ }
+
+ /**
+ * Stub the goaway function.
+ *
+ * Will throw an RedirectException with the URL being redirected to
+ * as the exception message.
+ *
+ * @throws RedirectException
+ */
+ protected function stub_goaway(): void {
+ $this->stub_goaway =
+ $this->getFunctionMock('Zotlabs\Module\Admin', 'goaway')
+ ->expects($this->once())
+ ->willReturnCallback(function (string $uri) {
+ throw new RedirectException($uri);
+ });
+ }
+
+ protected function stub_notice(): void {
+ $this->notice = [];
+ $this->stub_notice =
+ $this->getFunctionMock('Zotlabs\Module\Admin', 'notice')
+ ->expects($this->any())
+ ->willReturnCallback(function (string $arg) {
+ $this->notice[] = $arg;
+ });
+ }
+}
diff --git a/tests/unit/includes/dba/_files/account.yml b/tests/unit/includes/dba/_files/account.yml
index b7a49529e..9c3d00ec8 100644
--- a/tests/unit/includes/dba/_files/account.yml
+++ b/tests/unit/includes/dba/_files/account.yml
@@ -11,3 +11,18 @@ account:
account_language: "de"
account_level: 5
account_flags: 1
+ -
+ account_id: 44
+ account_email: "blocked@example.org"
+ account_level: 5
+ account_flags: 2
+ -
+ account_id: 45
+ account_email: "pending@example.org"
+ account_level: 5
+ account_flags: 0x10
+ -
+ account_id: 46
+ account_email: "unverified@example.org"
+ account_level: 5
+ account_flags: 0x11
diff --git a/tests/unit/includes/dba/_files/register.yml b/tests/unit/includes/dba/_files/register.yml
new file mode 100644
index 000000000..2ef1a5365
--- /dev/null
+++ b/tests/unit/includes/dba/_files/register.yml
@@ -0,0 +1,20 @@
+---
+register:
+ -
+ reg_vital: 1
+ reg_flags: 0x10
+ reg_did2: 'verified@example.com'
+ reg_email: 'verified@example.com'
+ reg_hash: '123'
+ reg_uid: 45
+ reg_pass: 'verify'
+ reg_stuff: ''
+ -
+ reg_vital: 1
+ reg_flags: 0x11
+ reg_did2: 'unverified@example.com'
+ reg_email: 'unverified@example.com'
+ reg_hash: '666'
+ reg_uid: 46
+ reg_pass: 'verify'
+ reg_stuff: ''
diff --git a/view/js/main.js b/view/js/main.js
index c1b0d410c..94e860575 100644
--- a/view/js/main.js
+++ b/view/js/main.js
@@ -86,9 +86,7 @@ $(document).ready(function() {
$(document).on('click', '.conversation-settings-link', getConversationSettings);
$(document).on('click', '#settings_module_ajax_submit', postConversationSettings);
- $(document).on('click', '#expand-aside', function() {
- toggleAside();
- });
+ $(document).on('click', '#expand-aside', toggleAside);
$(document).on('click focus', '.comment-edit-form textarea', function(e) {
if(! this.autocomplete_handled) {
@@ -175,14 +173,19 @@ $(document).ready(function() {
let singlethread_modules = ['display', 'hq'];
let redirect_modules = ['display', 'notify'];
- if(! b64mid && ! notify_id)
+ if (!b64mid && !notify_id) {
return;
+ }
- if(localUser && redirect_modules.indexOf(path) !== -1) {
+ if (document.querySelector('main').classList.contains('region_1-on')) {
+ toggleAside();
+ }
+
+ if (localUser && redirect_modules.indexOf(path) !== -1) {
path = 'hq';
}
- if(notify_id) {
+ if (notify_id) {
$.ajax({
type: 'post',
url: 'notify',
@@ -198,17 +201,13 @@ $(document).ready(function() {
window.location.href = path + '/' + b64mid;
}
else {
-
if (singlethread_modules.indexOf(module) !== -1) {
history.pushState(stateObj, '', module + '/' + b64mid);
-
}
if (b64mid) {
-
e.preventDefault();
-
- if(! page_load) {
+ if (!page_load) {
prepareLiveUpdate(b64mid, notify_id);
$('.message').removeClass('active');
$('[data-b64mid="' + b64mid + '"].message').addClass('active');
diff --git a/view/tpl/contact_edit_header.tpl b/view/tpl/contact_edit_header.tpl
index 8ec6054a3..32ef3b2fb 100644
--- a/view/tpl/contact_edit_header.tpl
+++ b/view/tpl/contact_edit_header.tpl
@@ -4,6 +4,6 @@
</a>
</div>
<div class="m-1">
- <div class="text-truncate h3 m-0"><strong>{{if $is_group}}<i class="bi fa-comments-o" title="{{$group_label}}"></i> {{/if}}{{$name}}</strong></div>
+ <div class="text-truncate h3 m-0"><strong>{{if $is_group}}<i class="bi bi-chat-fill" title="{{$group_label}}"></i> {{/if}}{{$name}}</strong></div>
<div class="text-truncate text-muted">{{$addr}}</div>
</div>
diff --git a/view/tpl/direntry.tpl b/view/tpl/direntry.tpl
index 79d66d3aa..076d2739f 100644
--- a/view/tpl/direntry.tpl
+++ b/view/tpl/direntry.tpl
@@ -14,7 +14,7 @@
<a class="btn btn-success btn-sm" href="{{$entry.connect}}"><i class="bi bi-plus-lg connect-icon"></i> {{$entry.conn_label}}</a>
{{/if}}
</div>
- <h3>{{if $entry.public_forum}}<i class="bi bi-chat-quote" title="{{$entry.forum_label}} @{{$entry.nickname}}+"></i>&nbsp;{{/if}}<a href='{{$entry.profile_link}}' >{{$entry.name}}</a>{{if $entry.online}}&nbsp;<i class="bi fa-asterisk online-now" title="{{$entry.online}}"></i>{{/if}}</h3>
+ <h3>{{if $entry.public_forum}}<i class="bi bi-chat-quote" title="{{$entry.forum_label}} @{{$entry.nickname}}+"></i>&nbsp;{{/if}}<a href='{{$entry.profile_link}}' >{{$entry.name}}</a>{{if $entry.online}}&nbsp;<i class="bi bi-asterisk online-now" title="{{$entry.online}}"></i>{{/if}}</h3>
</div>
<div class="section-content-tools-wrapper directory-collapse">
<div class="contact-photo-wrapper" id="directory-photo-wrapper-{{$entry.hash}}" >
diff --git a/view/tpl/event_form.tpl b/view/tpl/event_form.tpl
index 43c6942e1..c469e9378 100644
--- a/view/tpl/event_form.tpl
+++ b/view/tpl/event_form.tpl
@@ -57,13 +57,13 @@
</div>
<div class='btn-group'>
<button type="button" class="btn btn-outline-secondary btn-sm" title="{{$edimg}}" onclick="insertbbcomment('none','img', 'desc');">
- <i class="bi fa-camera comment-icon"></i>
+ <i class="bi bi-camera comment-icon"></i>
</button>
<button type="button" class="btn btn-outline-secondary btn-sm" title="{{$edurl}}" onclick="insertbbcomment('none','url', 'desc');">
<i class="bi bi-link-45deg comment-icon"></i>
</button>
<button type="button" class="btn btn-outline-secondary btn-sm" title="{{$edvideo}}" onclick="insertbbcomment('none','video', 'desc');">
- <i class="bi fa-video-camera comment-icon"></i>
+ <i class="bi bi-video-camera comment-icon"></i>
</button>
</div>
</div>
@@ -95,13 +95,13 @@
</div>
<div class='btn-group'>
<button type="button" class="btn btn-outline-secondary btn-sm" title="{{$edimg}}" onclick="insertbbcomment('none','img', 'loc');">
- <i class="bi fa-camera comment-icon"></i>
+ <i class="bi bi-camera comment-icon"></i>
</button>
<button type="button" class="btn btn-outline-secondary btn-sm" title="{{$edurl}}" onclick="insertbbcomment('none','url', 'loc');">
<i class="bi bi-link-45deg comment-icon"></i>
</button>
<button type="button" class="btn btn-outline-secondary btn-sm" title="{{$edvideo}}" onclick="insertbbcomment('none','video', 'loc');">
- <i class="bi fa-video-camera comment-icon"></i>
+ <i class="bi bi-camera-video comment-icon"></i>
</button>
<button type="button" class="btn btn-outline-secondary btn-sm" title="{{$mapper}}" onclick="insertbbcomment('none','map','loc');">
<i class="bi bi-globe comment-icon"></i>
diff --git a/view/tpl/event_item_header.tpl b/view/tpl/event_item_header.tpl
index 1c8fe034c..36c3164d6 100644
--- a/view/tpl/event_item_header.tpl
+++ b/view/tpl/event_item_header.tpl
@@ -1,5 +1,5 @@
<div class="event-item-title">
- <h3><i class="bi fa-calendar"></i>&nbsp;{{$title}}</h3>
+ <h3><i class="bi bi-calendar3"></i>&nbsp;{{$title}}</h3>
</div>
{{if $oneday && $allday}}
<span class="dtstart">{{$dtstart_dt}}</span>
diff --git a/view/tpl/events-js.tpl b/view/tpl/events-js.tpl
index e2c3167f4..8f10d4e06 100644
--- a/view/tpl/events-js.tpl
+++ b/view/tpl/events-js.tpl
@@ -10,12 +10,12 @@
</div>
<button class="btn btn-success btn-sm" onclick="openClose('form');">{{$new_event.1}}</button>
<div class="btn-group">
- <button class="btn btn-outline-secondary btn-sm" onclick="changeView('prev', false);" title="{{$prev}}"><i class="bi fa-backward"></i></button>
- <button id="today-btn" class="btn btn-outline-secondary btn-sm" onclick="changeView('today', false);" title="{{$today}}"><div id="events-spinner" class="spinner s"></div><i class="bi fa-bullseye" style="display: none; width: 1rem;"></i></button>
- <button class="btn btn-outline-secondary btn-sm" onclick="changeView('next', false);" title="{{$next}}"><i class="bi fa-forward"></i></button>
+ <button class="btn btn-outline-secondary btn-sm" onclick="changeView('prev', false);" title="{{$prev}}"><i class="bi bi-rewind-fill"></i></button>
+ <button id="today-btn" class="btn btn-outline-secondary btn-sm" onclick="changeView('today', false);" title="{{$today}}"><div id="events-spinner" class="spinner s"></div><i class="bi bi-bullseye" style="display: none; width: 1rem;"></i></button>
+ <button class="btn btn-outline-secondary btn-sm" onclick="changeView('next', false);" title="{{$next}}"><i class="bi bi-fast-forward-fill"></i></button>
</div>
- <button id="fullscreen-btn" type="button" class="btn btn-outline-secondary btn-sm" onclick="makeFullScreen();"><i class="bi fa-expand"></i></button>
- <button id="inline-btn" type="button" class="btn btn-outline-secondary btn-sm" onclick="makeFullScreen(false);"><i class="bi fa-compress"></i></button>
+ <button id="fullscreen-btn" type="button" class="btn btn-outline-secondary btn-sm" onclick="makeFullScreen();"><i class="bi bi-arrows-angle-expand"></i></button>
+ <button id="inline-btn" type="button" class="btn btn-outline-secondary btn-sm" onclick="makeFullScreen(false);"><i class="bi bi-arrows-angle-contract"></i></button>
</div>
</div>
<h2 id="title"></h2>
diff --git a/view/tpl/generic_addon_settings.tpl b/view/tpl/generic_addon_settings.tpl
index 685099807..a331dbb5d 100644
--- a/view/tpl/generic_addon_settings.tpl
+++ b/view/tpl/generic_addon_settings.tpl
@@ -5,7 +5,7 @@
{{if $addon.1|substr:0:1 === '<'}}
{{$addon.1}}
{{else}}
- <i class="bi fa-gear"></i> {{$addon.1}}
+ <i class="bi bi-gear"></i> {{$addon.1}}
{{/if}}
</a>
</h3>
diff --git a/view/tpl/install_checks.tpl b/view/tpl/install_checks.tpl
index f9743d02a..f5f4df137 100644
--- a/view/tpl/install_checks.tpl
+++ b/view/tpl/install_checks.tpl
@@ -2,7 +2,7 @@
<div class="jumbotron">
<h1>{{$title}}</h1>
<hr class="my-4">
- <h2><i class="bi fa-heartbeat"></i>&nbsp; {{$pass}}</h2>
+ <h2><i class="bi bi-heart-pulse"></i>&nbsp; {{$pass}}</h2>
</div>
<form action="{{$baseurl}}/index.php?q=setup" method="post">
<table class="table">
@@ -23,7 +23,7 @@
<button class="btn btn-success" type="submit"><i class="bi bi-check-lg"></i> {{$next}}</button>
{{else}}
<input type="hidden" name="pass" value="1">
- <button class="btn btn-warning" type="submit"><i class="bi fa-refresh"></i> {{$reload}}</button>
+ <button class="btn btn-warning" type="submit"><i class="bi bi-arrow-clockwise"></i> {{$reload}}</button>
{{/if}}
</form>
</div>
diff --git a/view/tpl/uexport.tpl b/view/tpl/uexport.tpl
index 099a574e8..ca529f8f7 100644
--- a/view/tpl/uexport.tpl
+++ b/view/tpl/uexport.tpl
@@ -8,7 +8,7 @@
<p>
{{$channel_info}}
</p>
- <a href="uexport/channel" class="btn btn-outline-primary"><i class="bi fa-download"></i> {{$channel_title}}</a>
+ <a href="uexport/channel" class="btn btn-outline-primary"><i class="bi bi-download"></i> {{$channel_title}}</a>
</p>
<p class="mb-3">
<h3>{{$content_title}}</h3>
@@ -17,7 +17,7 @@
{{$items_extra_info}}
</p>
{{foreach $years as $year}}
- <a href="uexport/{{$year}}" class="btn btn-outline-primary"><i class="bi fa-download"></i> {{$year}}</a>
+ <a href="uexport/{{$year}}" class="btn btn-outline-primary"><i class="bi bi-download"></i> {{$year}}</a>
{{/foreach}}
</p>
<p class="mb-3">
@@ -26,7 +26,7 @@
{{$wikis_info}}
{{$items_extra_info}}
</p>
- <a href="uexport/wikis" class="btn btn-outline-primary"><i class="bi fa-download"></i> {{$wikis_title}}</a>
+ <a href="uexport/wikis" class="btn btn-outline-primary"><i class="bi bi-download"></i> {{$wikis_title}}</a>
</p>
<p class="mb-3">
<h3>{{$webpages_title}}</h3>
@@ -34,7 +34,7 @@
{{$webpages_info}}
{{$items_extra_info}}
</p>
- <a href="uexport/webpages" class="btn btn-outline-primary"><i class="bi fa-download"></i> {{$webpages_title}}</a>
+ <a href="uexport/webpages" class="btn btn-outline-primary"><i class="bi bi-download"></i> {{$webpages_title}}</a>
</p>
<p class="mb-3">
<h3>{{$events_title}}</h3>
@@ -42,7 +42,7 @@
{{$events_info}}
{{$items_extra_info}}
</p>
- <a href="uexport/events" class="btn btn-outline-primary"><i class="bi fa-download"></i> {{$events_title}}</a>
+ <a href="uexport/events" class="btn btn-outline-primary"><i class="bi bi-download"></i> {{$events_title}}</a>
</p>
<p class="mb-3">
<h3>{{$chatrooms_title}}</h3>
@@ -50,7 +50,7 @@
{{$chatrooms_info}}
{{$items_extra_info}}
</p>
- <a href="uexport/chatrooms" class="btn btn-outline-primary"><i class="bi fa-download"></i> {{$chatrooms_title}}</a>
+ <a href="uexport/chatrooms" class="btn btn-outline-primary"><i class="bi bi-download"></i> {{$chatrooms_title}}</a>
</p>
</div>
</div>