mirror of
https://framagit.org/hubzilla/core.git
synced 2026-06-21 00:52:33 -04:00
Merge branch 'more-tests+speedups' into 'dev'
More tests + speed improvements See merge request hubzilla/core!2243
This commit is contained in:
@@ -696,10 +696,9 @@ class Profiles extends \Zotlabs\Web\Controller {
|
||||
$show_presence = ['show_presence', t('Reveal my online status'), $show_presence_val, '', [t('No'), t('Yes')]];
|
||||
}
|
||||
|
||||
$extra_fields = array();
|
||||
$q = q("select * from profdef where true");
|
||||
if($q) {
|
||||
$extra_fields = array();
|
||||
|
||||
foreach($q as $qq) {
|
||||
$mine = q("select v from profext where k = '%s' and hash = '%s' and channel_id = %d limit 1",
|
||||
dbesc($qq['field_name']),
|
||||
@@ -833,6 +832,8 @@ class Profiles extends \Zotlabs\Web\Controller {
|
||||
);
|
||||
if($r) {
|
||||
|
||||
$profiles = '';
|
||||
|
||||
$tpl = get_markup_template('profile_entry.tpl');
|
||||
foreach($r as $rr) {
|
||||
$profiles .= replace_macros($tpl, array(
|
||||
|
||||
@@ -10,11 +10,140 @@
|
||||
|
||||
namespace Zotlabs\Tests\Unit;
|
||||
|
||||
use phpmock\phpunit\PHPMock;
|
||||
use PHPUnit\Framework\Attributes\Before;
|
||||
|
||||
class CreateIdentityTest extends UnitTestCase {
|
||||
|
||||
use PHPMock;
|
||||
|
||||
//
|
||||
// Static private key used by the openssl stubs.
|
||||
//
|
||||
private const PRVKEY = <<<'PRVKEY'
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
0UH3yDnLoPuCvHeX2WAXdyWob6vBOA==
|
||||
-----END PRIVATE KEY-----
|
||||
PRVKEY;
|
||||
|
||||
//
|
||||
// Static public key corresponding to self::PRVKEY, used by the
|
||||
// openssl_stubs
|
||||
//
|
||||
private const PUBKEY = <<<'PUBKEY'
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvIcMderJEy61sNlpW00h
|
||||
1lF3KRVKV48heeClWtJ/rJql4yHSaAtC1ce1SS9fLX66evbAXy3ClKm8iPQ9We/P
|
||||
F6jzijyWj4w2CMB5GSX/mDq7z0D/eaAI0kcBQTcTSMypMr9vttgqJV9WWDT3uqw+
|
||||
VwxXV7Aic8UzMduv/rl4j3tx5EP319WUiTNqnBgXZpffCm1zONo3fi3q5kpZuRL0
|
||||
d28aYpXzyKt1kOBQe31OUVHt57imhVYZfpLVI7kp4tAxfbbRp5KDj5v0F0ElvwGy
|
||||
N+5KX5G3KhCRiMdJ1mBLFWeXE7PeJQSvxIhCD5CTTgoSjjzuzsqd/WNUJdze9q+p
|
||||
9xQzzGasQio1/kCPGmJLJhqpsvHF+YiMPgIP86w3wWwqAbO1imS/QgdqTMWT1/7T
|
||||
mLx22JMK/vIyZ5ZlOjOF/tBBi0Ls2iBwfl1uLRm1ILfXc2kwX7byWxmE5cFENLe+
|
||||
C3gzFLL7gsU9rLx5lTMg+mNWFT6OLZZUeNe9AN4muziXWeMpI/wAabEaAc6F67Cp
|
||||
Vv/VKhFbEB9S7rddzDC3vsSfVypa/Sqq+EBmMeTqIT5+PBMpVVA+/O2wzef44+pE
|
||||
NFFB3eoCswxl+S22A75OtJ1MuCh7D5rCMR7ptLWCt4YQ9kgxfOPjZzbvJEkm25+Z
|
||||
ZAjxDyWHEoxQr8oS6Fg1Lz8CAwEAAQ==
|
||||
-----END PUBLIC KEY-----
|
||||
PUBKEY;
|
||||
|
||||
private bool $queueworker_started = false;
|
||||
|
||||
public function test_empty_args() {
|
||||
#[Before]
|
||||
public function setup_openssl_mocks(): void {
|
||||
//
|
||||
// The `create_identity` function will call `Crypto::new_keypair()`,
|
||||
// which again will call `openssl_pkey_new`, to create a new
|
||||
// private/public keypair for the channel. While this is safe to call
|
||||
// from the code under test, it's also slow.
|
||||
//
|
||||
// Since we don't really care about the cryptography here, we can make
|
||||
// the tests run a bit faster by stubbing the slow function call and
|
||||
// return a sentinel value instead of actually generaing the keys.
|
||||
//
|
||||
$openssl_pkey_new =
|
||||
$this->getFunctionMock('Zotlabs\Lib', 'openssl_pkey_new')
|
||||
->expects($this->any())
|
||||
->willReturn('openssl_pkey_result');
|
||||
|
||||
//
|
||||
// Since we have stubbed `openssl_pkey_new` we also need to mock the
|
||||
// call to `openssl_pkey_export` that is used to get the private key
|
||||
// from the result of `openssl_pkey_new`.
|
||||
//
|
||||
// As this function returns the value in a output param, we need to
|
||||
// replace it with a callback function to simulate it.
|
||||
//
|
||||
$openssl_pkey_export =
|
||||
$this->getFunctionMock('Zotlabs\Lib', 'openssl_pkey_export')
|
||||
->expects($this->any())
|
||||
->willReturnCallback(function (string $result, string &$response): bool {
|
||||
$this->assertEquals('openssl_pkey_result', $result);
|
||||
$response = self::PRVKEY;
|
||||
return true;
|
||||
});
|
||||
|
||||
//
|
||||
// Finally we also need to stub the `openssl_pkey_get_details` function
|
||||
// used to retrevive the public key from the `openssl_pkey_new` result.
|
||||
//
|
||||
$openssl_pkey_get_details =
|
||||
$this->getFunctionMock('Zotlabs\Lib', 'openssl_pkey_get_details')
|
||||
->expects($this->any())
|
||||
->with($this->identicalTo('openssl_pkey_result'))
|
||||
->willReturn([ 'key' => self::PUBKEY ]);
|
||||
}
|
||||
|
||||
public function test_empty_args_fails_with_an_error_message() {
|
||||
insert_hook('proc_run', [$this, 'proc_run_hook']);
|
||||
$result = create_identity([]);
|
||||
$this->assertEquals(
|
||||
|
||||
118
tests/unit/Lib/ZotfingerTest.php
Normal file
118
tests/unit/Lib/ZotfingerTest.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The Hubzilla Community
|
||||
* SPDX-FileContributor: Harald Eilertsen <haraldei@anduin.net>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Tests\Unit\Lib;
|
||||
|
||||
use PHPUnit\Framework\Attributes\TestWith;
|
||||
use Zotlabs\Lib\Zotfinger;
|
||||
use Zotlabs\Tests\Unit\UnitTestCase;
|
||||
|
||||
use phpmock\phpunit\PHPMock;
|
||||
|
||||
class ZotfingerTest extends UnitTestCase
|
||||
{
|
||||
// Import PHPMock methods into this class
|
||||
use PHPMock;
|
||||
|
||||
#[TestWith([null])]
|
||||
#[TestWith([false])]
|
||||
#[TestWith([''])]
|
||||
public function testShouldReturnFalseOnNoResource($resource): void
|
||||
{
|
||||
$this->assertFalse(Zotfinger::exec($resource));
|
||||
}
|
||||
|
||||
public function testShouldReturnFalseIfResourceNotFound(): void
|
||||
{
|
||||
//
|
||||
// Mock z_post_url to prevent it fram connecting to an actual remote site,
|
||||
// and so that we can control what it should return.
|
||||
//
|
||||
// Here we simulate a request that return 404 Not Found.
|
||||
//
|
||||
$mock = $this->getFunctionMock('Zotlabs\Lib', 'z_post_url')
|
||||
->expects($this->once())
|
||||
->willReturn([
|
||||
'return_code' => 404,
|
||||
'success' => false,
|
||||
]);
|
||||
|
||||
$this->assertFalse(Zotfinger::exec('https://example.test/some-resource'));
|
||||
}
|
||||
|
||||
public function testShouldReturnBodyIfResourceFound(): void
|
||||
{
|
||||
//
|
||||
// Mock z_post_url to prevent it fram connecting to an actual remote site,
|
||||
// and so that we can control what it should return.
|
||||
//
|
||||
// Here we simulate a request returning 200 OK and some data
|
||||
//
|
||||
$mock = $this->getFunctionMock('Zotlabs\Lib', 'z_post_url')
|
||||
->expects($this->once())
|
||||
->willReturn([
|
||||
'return_code' => 200,
|
||||
'success' => true,
|
||||
'body' => '{"subject":"acct:user@example.test"}',
|
||||
]);
|
||||
|
||||
//
|
||||
// Initialize some $_SERVER superglobal values needed by HTTPSig:
|
||||
//
|
||||
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||
$_SERVER['REQUEST_URI'] = 'some_uri';
|
||||
$_SERVER['CONTENT_TYPE'] = 'application/json';
|
||||
$_SERVER['CONTENT_LENGTH'] = 42;
|
||||
|
||||
$result = Zotfinger::exec('https://example.test/some-resource');
|
||||
|
||||
//
|
||||
// Verify that the json payload has been decoded
|
||||
//
|
||||
$this->assertIsArray($result['data']);
|
||||
$this->assertArrayHasKey('subject', $result['data']);
|
||||
$this->assertEquals('acct:user@example.test', $result['data']['subject']);
|
||||
}
|
||||
|
||||
public function testThatRequestFromChannelIsSigned(): void
|
||||
{
|
||||
//
|
||||
// Mock z_post_url to prevent it fram connecting to an actual remote site,
|
||||
// and so that we can control what it should return.
|
||||
//
|
||||
// Here we simulate a request returning 200 OK and some data
|
||||
//
|
||||
$mock = $this->getFunctionMock('Zotlabs\Lib', 'z_post_url')
|
||||
->expects($this->once())
|
||||
->willReturn([
|
||||
'return_code' => 200,
|
||||
'success' => true,
|
||||
'body' => '{"subject":"acct:user@example.test"}',
|
||||
]);
|
||||
|
||||
//
|
||||
// Initialize some $_SERVER superglobal values needed by HTTPSig:
|
||||
//
|
||||
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||
$_SERVER['REQUEST_URI'] = 'some_uri';
|
||||
$_SERVER['CONTENT_TYPE'] = 'application/json';
|
||||
$_SERVER['CONTENT_LENGTH'] = 42;
|
||||
|
||||
|
||||
$channel = $this->fixtures['channel'][0];
|
||||
|
||||
$testresult = Zotfinger::exec('https://example.test/some-resource', $channel);
|
||||
|
||||
//
|
||||
// Verify that the json payload has been decoded
|
||||
//
|
||||
$this->assertIsArray($testresult['data']);
|
||||
$this->assertArrayHasKey('subject', $testresult['data']);
|
||||
$this->assertEquals('acct:user@example.test', $testresult['data']['subject']);
|
||||
}
|
||||
}
|
||||
@@ -76,13 +76,6 @@ class MagicTest extends TestCase {
|
||||
'xchan_hash' => 'foreign hash',
|
||||
]);
|
||||
|
||||
// Create the channel the foreign observer wants to access
|
||||
$result = create_identity([
|
||||
'account_id' => $this->fixtures['account'][0]['account_id'],
|
||||
'nickname' => 'testuser',
|
||||
'name' => 'Trish Testuser',
|
||||
]);
|
||||
|
||||
// Shortcut the permission checks, by saying this observer is allowed
|
||||
// the delegate privilege over the target channel
|
||||
insert_hook('perm_is_allowed', function (array &$perm) {
|
||||
@@ -101,18 +94,20 @@ class MagicTest extends TestCase {
|
||||
// assertions after the redirect is thrown.
|
||||
$this->stub_goaway();
|
||||
|
||||
$channel = $this->fixtures['channel'][1];
|
||||
|
||||
try {
|
||||
// Send a request to get delegate privileges for the `testuser` channel
|
||||
// on the local hub.
|
||||
$this->get('magic', [
|
||||
'bdest' => bin2hex($dest_url),
|
||||
'delegate' => 'testuser@hubzilla.test']
|
||||
);
|
||||
'delegate' => channel_reddress($channel)
|
||||
]);
|
||||
} catch (RedirectException $e) {
|
||||
$this->assertEquals($dest_url, $e->getMessage());
|
||||
$this->assertEquals($result['channel']['channel_id'], App::$channel['channel_id']);
|
||||
$this->assertEquals($channel['channel_id'], App::$channel['channel_id']);
|
||||
$this->assertEquals($original_session, $_SESSION['delegate_push']);
|
||||
$this->assertEquals($result['channel']['channel_id'], $_SESSION['delegate_channel']);
|
||||
$this->assertEquals($channel['channel_id'], $_SESSION['delegate_channel']);
|
||||
$this->assertEquals('foreign hash', $_SESSION['delegate']);
|
||||
$this->assertEquals($this->fixtures['account'][0]['account_id'], $_SESSION['account_id']);
|
||||
}
|
||||
|
||||
100
tests/unit/Module/ProfilesTest.php
Normal file
100
tests/unit/Module/ProfilesTest.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The Hubzilla Community
|
||||
* SPDX-FileContributor: Harald Eilertsen <haraldei@anduin.net>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Tests\Unit\Module;
|
||||
|
||||
use App;
|
||||
use PDOStatement;
|
||||
|
||||
/**
|
||||
* Tests for the Profiles module
|
||||
*/
|
||||
class ProfilesTest extends TestCase
|
||||
{
|
||||
public function testDisplaysProfileEditFormIfMultiProfilesDisabled(): void {
|
||||
// Set up the channel we'll be making the request for
|
||||
$channel = $this->fixtures['channel'][0];
|
||||
App::set_channel($channel);
|
||||
|
||||
// And set up the default profile
|
||||
$this->createDefaultProfile($channel);
|
||||
|
||||
// Replace calls to 'local_channel' and make sure they return
|
||||
// the id of the current channel.
|
||||
$local_channel_mock =
|
||||
$this->getFunctionMock('Zotlabs\Module', 'local_channel')
|
||||
->expects($this->any())
|
||||
->willReturn($channel['channel_id']);
|
||||
|
||||
// Replace calls to 'feature_enabled', and make it unconditionally
|
||||
// return true. This is called by the Profiles module to check that
|
||||
// multiple profiles are enabled.
|
||||
$feature_enabled_mock =
|
||||
$this->getFunctionMock('Zotlabs\Module', 'feature_enabled')
|
||||
->expects($this->any())
|
||||
->willReturn(false);
|
||||
|
||||
// Simulate a GET request to the module
|
||||
$this->get('profiles');
|
||||
|
||||
// Check that the rendered page has the expected entry.
|
||||
$this->assertPageContains('<form id="profile-edit-form"');
|
||||
}
|
||||
|
||||
public function testListDefaultProfileWithNoArgs(): void {
|
||||
// Set up the channel we'll be making the request for
|
||||
$channel = $this->fixtures['channel'][0];
|
||||
App::set_channel($channel);
|
||||
|
||||
// And set up the default profile
|
||||
$this->createDefaultProfile($channel);
|
||||
|
||||
// Replace calls to 'local_channel' and make sure they return
|
||||
// the id of the current channel.
|
||||
$local_channel_mock =
|
||||
$this->getFunctionMock('Zotlabs\Module', 'local_channel')
|
||||
->expects($this->any())
|
||||
->willReturn($channel['channel_id']);
|
||||
|
||||
// Replace calls to 'feature_enabled', and make it unconditionally
|
||||
// return true. This is called by the Profiles module to check that
|
||||
// multiple profiles are enabled.
|
||||
$feature_enabled_mock =
|
||||
$this->getFunctionMock('Zotlabs\Module', 'feature_enabled')
|
||||
->expects($this->once())
|
||||
->willReturn(true);
|
||||
|
||||
// Simulate a GET request to the module
|
||||
$this->get('profiles');
|
||||
|
||||
// Check that the rendered page has the expected entry.
|
||||
$this->assertPageContains('Default Profile');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create the default profile for a channel
|
||||
*
|
||||
* @param array $channel An associative array containing the channel.
|
||||
*/
|
||||
private function createDefaultProfile(array $channel): void {
|
||||
$res = profile_store_lowlevel([
|
||||
'aid' => intval($channel['channel_account_id']),
|
||||
'uid' => intval($channel['channel_id']),
|
||||
'profile_guid' => random_string(),
|
||||
'profile_name' => t('Default Profile'),
|
||||
'is_default' => 1,
|
||||
'publish' => true,
|
||||
'fullname' => $channel['channel_name'],
|
||||
'photo' => z_root() . "/photo/profile/l/{$channel['channel_id']}",
|
||||
'thumb' => z_root() . "/photo/profile/m/{$channel['channel_id']}"
|
||||
]);
|
||||
|
||||
$this->assertInstanceOf(PDOStatement::class, $res);
|
||||
$this->assertEquals('00000', $res->errorCode());
|
||||
}
|
||||
}
|
||||
60
tests/unit/includes/dba/_files/hubloc.yml
Normal file
60
tests/unit/includes/dba/_files/hubloc.yml
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
hubloc:
|
||||
- # sys channel
|
||||
hubloc_guid: uGp_IvDBQ7b_-s3HV7IehysbKFyx1w0oG4dm1Q3-trFlnw01H-rJhNRQ8QNdDRSiolJmIMizCiexogrHy3_kpg
|
||||
hubloc_guid_sig: sha256.bawP2sNBcfnjpKx2OCMlISbLJBByejs0KkbWcKvFj_vfQ_TnKvTZ9PvfxPz0puUkSqaJVskwz7mY59d56aRqc3kTCniuuR_3L8padNElwkyqoPLgIBQlffeqoa0ax0R_kF667_MmlUj6F6RyQHuCNeElWRfy0LW4SzIsn72ogHevvbOa5gh27jDcjUqkY5C0i8wyxEHzI5Ue4zNwJ7JS6WETZVL_z2WgFemKagZ8SWNVdFQfHCmhJ-scBZZK9rM0rdLf1O9HjkxgdvzImSHH3ODT-qOfE-IKwlum0hCUJqmGwOQAHTydRHKn-pdEHX1eFE_Y15lwBPToyQW1zTso9PPzwRXKqJkrqapO6hqerRCWqI5dtgE_6Up3AFolWCU82h5to0Y5LT2iEvMids9x64laGKNw-bzdYpJtKZZqgxejchIuYoqZZJp4ivGzHeJktBveTCluP2lRXw2W1TupMOVADlfUGPFMTYj2LPPIp3CTD6RsSZobh9VvT22J1SzwwTFvHG2VoZbezOPKvWj-PHRb3iBTSYoQAgL8ecI4oWnn9HK-KHwUsoWOtIXDSKVRiySun3AXGjI8iIVI7ORk7-33aVrxuVuh76_ni7LEadFFGClbxZtzoM44QizkPDHVS4rYl1fsuYDbxr93FvG7_QCBsOzgfWgE2eN65poE7mU
|
||||
hubloc_hash: de3-bhcFpdY5PZ-ef4vy-6PpSeGrEHB8DNQFC6uP9lG-RkPaMceUMdvIRYHvHIvRzjJ0RPII2sJ1ffz4ATQOHQ
|
||||
hubloc_id_url: https://hubzilla.test/channel/sys
|
||||
hubloc_addr: sys@hubzilla.test
|
||||
hubloc_primary: 1
|
||||
hubloc_url: https://hubzilla.test
|
||||
hubloc_url_sig: sha256.ORRyOWqsjER4i_Vx2HN5u_4u6djHb7NDEixTssCK9L-tpfBcbDmJD32pVgQvGs4UPexqlvIj7AwE-_fju2xlc_ZaI7UfII20Re0DWYfZR5xiexPxSbxtoUu-VuHoFNLjfnAwvj3Xleg_TQ4UBc5ap1_F0B7FsctOpx6P9ot_0tD7qDmyeiyU3OCCqDhAUASRYoXbkxzAZCSMHHT0Dnjz0IDJ8avi2FvrUns-ThKypxqyXzPz1Ie-Fz9XzdTCohrXUFixcIhIkUBtrL_pUe-Al6SVjICTqtoXNITqN5DEQLDEX5ObFiVotKZztg_IJxx6bzVta6e-9_Wu3ikM4DwFM-i_Lyybxoc745BnKVtZUfk4X3HF4_z0JLFW9YobcLzKU4KJgP4fMbmjEznqk4UXB_pGm-EgW90vou18Yi0_m4pGvQJgW2xRgioEDUNrkcBo6O_ej8Y71hsDfkv6SDNxqC-eZ6YFLYN5cJ2TKS05GXYCMdOrmtvH4TMEyxbwe0lfZa5eBSZby2qp26Ler51kft-VaZeXDowtK5Qr6Gg3YNCYHjBdeJz_ks9M9JUJqV-SHsRV2mC9OnFxkMGIzV1oRhn91wgJKMDJn6tEZDCXHVCcuC-4l7GstKRT-UbpqtkV__NYWuE9L3yvwXEDT9FXBw0hljBIn5EsG2CPkvFrf0U
|
||||
hubloc_site_id: xJFCfYhhPGPqHeDsNQKjaY9EdS0iLJmV5lvuR3rFi09LOwwt0uN6adhJND5gyzs-3EEILSG_OY7zPAUKSnMa6w
|
||||
hubloc_host: hubzilla.test
|
||||
hubloc_callback: https://hubzilla.test/zot
|
||||
hubloc_sitekey: |
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAquJ4YP2qctsfxG2nTmGU
|
||||
/yIojix38qGkDyEarmtLUfn7Rm+sg1zT1IjW3Zvw/q4rmK8zfC9doCFR6Z9zU6/v
|
||||
XlFDCY+EJ2vdw5U+D/OijvnDLABkOS1iKRII9225olh1ZbB2QpLq3tC1SbE04Wy6
|
||||
fTuyehBrufrvqDXX+CyUYYbCiVtMv01v6Lr8Qc498afASlOJd2spoGcppeNlqL8u
|
||||
6Ipf+fMoo89oIn5JOk3aLvKu+33i1NbVzC3NrVRjWV+D7MQgCroDAYHujNA1Kkuw
|
||||
QxYlxy+exeSnHD6YzZ1lAFHZSc+xPXQVc6wCFMuruk9KymrGNh5V4lFoU+Bm1bLw
|
||||
5berLIpQn8jKffZulSPeWcPw0cBQWgKMk3uEW1H6vJggepjunnjINDW7RvP7Thma
|
||||
wVmU45EUeL3uzZR2JO+gX+Ay3oLCBTNCFrIa1U/cgrdXgTLBKT6JVfLaVPWMxqfA
|
||||
n7f9e9DryEcB2pIq1l1CfUPMZdSYCI3pAT53io4imaUsB2HzWO39Ie1fGaHOo1Mk
|
||||
MCSny0ySLRTGeefYJur3LCCyGkxpxGxFzqmCG2oF0UdQgw6rf8ENjojG3KyGNeYO
|
||||
fkOd1kzv22NI8Zs+LEJQdkXWz16EeP8ZViZZ3lnG2lViFXAK3f4/U/fpuLCuMUi7
|
||||
pDhncIFqrTPRozFWL0xbPAsCAwEAAQ==
|
||||
-----END PUBLIC KEY-----
|
||||
hubloc_network: zot6
|
||||
hubloc_updated: 2025-11-19T21:27:19
|
||||
- # test channel
|
||||
hubloc_guid: "NTHCKiCblxvlLxdlu5SpOqoC_EWtKFqHEg6nc2Ps5X_UGJAfPBzENdOagS_IBC75RIQNtAYizZeobnpv0CEinA"
|
||||
hubloc_guid_sig: "sha256.cLzCjVb_kgDUsXg-SM2qnn-DQ55cRcXlbPeigeWtnT_pjlCD7Pg6trcLa12s3iPup4dudG9MIZkjuwBUUBv25mVER9w97NGYCqLx1OGFbjuuAuZJzYHMZLiWSfv4PNzjvkB4sOAsCY6CBCcpg6rno55FxFhJNz10zTYkaqJQbS2zKnBnxqseXEwULKDgBbU8yapP1BX505FedcJR3MyVMYg0teiINOFywTjKQHOm_Pe6mmU_wblOy7eWLfoWXU9lq_Z9D47UTgeJd0IB89btcF0WsfyUhg3NNLE_kpfk2Ow-DBO9Joz64qoBe8Ri68pnom5LPgGTWwGWJnSud123ZfTDLzFg1h9sFMcJMiMzvJnvFm4puKKu4K0jYNkAp0DROnaqadreACU5y_vOQyCT0aiicIX3uPkKGhNbwSjcquOylzricqgaZeK6iOOb_iHRLuQd4lJgYShr9xqBk2LU31QnWO3QUmBVlVPpM26YeoulmwVsoOSxC7QcLjYmQCgYpGOUaWWxGlJSwDyvm4DKiG88hp_clzN4MDilycVmS_JvmYxsw1Do_RDeDRxq0xLnqtBZpnafEjm-LXkZGVYJ5kqvEtl3DmPai2Wzrnyb24XxGmAhOZo1NvfjrvRWtFN-uNXLHKDZEcEqogmiqMUd20XMh1YGLqH2IsvbPyYShXo"
|
||||
hubloc_hash: "LAOCZBv-Cj6QVab_EpMFV6HIDmsUSDybKfSnH9I5cwYAkar4UvBcsj9ofsaIejYLTfgMy9BcGPWjy9-7Uk7rlQ"
|
||||
hubloc_id_url: https://hubzilla.test/channel/test
|
||||
hubloc_addr: test@hubzilla.test
|
||||
hubloc_primary: 1
|
||||
hubloc_url: https://hubzilla.test
|
||||
hubloc_url_sig: sha256.t8AdUv_uurSc1RMM5lHuifGxceSLuX6-fT5I4KflJg16qO6u1dUuAVcH1pWA0rYIi0J9LL0rSCAfGgwa53wx5-C8Vt1TfMVoz0xyUTFJLd6FeLKRrYKQBj2Bos1VjHlXKj3Pn1455dacvDTXhg7t1WISaBMdzNlPQrTQnZPgNEy7cnPVmLkHuu5SVtYtT3mFiZXXUbaK4nFuw3lR83WVauCFIiKm8kcFSWtsLJzTMlx2NDOxTO-IMiSYXU4KwhcxmzLOqWQrT_vBDJNrny3jm79lIu5DJDCJdoVp2pwL72c3Esi5NhUKMPG7dyH4tKev5Ug3z4MUEaF_DvtDMgC0hAEtE3sE6wzqp4Fg6zLLE7V3wZI5cOpdjeL8-3TJokKJoUCDwKUwcLMyd9vbJKDN5QPtVKguLb7-QCfFZHA-xEoZlBW5gRptan9fTE3-3jRJF0PIywOM9YpwbLWaaUikQ8BHkS_pCVjAM7wiFfJzD6ocQhz5mKC-HQsABCck_jYzzjHzE4lfVziPN3arS_1tPFwDFsdk7Q04gOJ2F--DRBqY6R_iajZq0aDQgXelFk4B_BVU2N8zaom-0djQw16RPWchzMk8A1ablZ53P-D5IlWaJhL8BUEUtrKCrAqh6ecoQGYBwGitIy2FP2M0qfDiyTxkqnx31lW04Uk2tOFtJWI
|
||||
hubloc_site_id: xJFCfYhhPGPqHeDsNQKjaY9EdS0iLJmV5lvuR3rFi09LOwwt0uN6adhJND5gyzs-3EEILSG_OY7zPAUKSnMa6w
|
||||
hubloc_host: hubzilla.test
|
||||
hubloc_callback: https://hubzilla.test/zot
|
||||
hubloc_sitekey: |
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAquJ4YP2qctsfxG2nTmGU
|
||||
/yIojix38qGkDyEarmtLUfn7Rm+sg1zT1IjW3Zvw/q4rmK8zfC9doCFR6Z9zU6/v
|
||||
XlFDCY+EJ2vdw5U+D/OijvnDLABkOS1iKRII9225olh1ZbB2QpLq3tC1SbE04Wy6
|
||||
fTuyehBrufrvqDXX+CyUYYbCiVtMv01v6Lr8Qc498afASlOJd2spoGcppeNlqL8u
|
||||
6Ipf+fMoo89oIn5JOk3aLvKu+33i1NbVzC3NrVRjWV+D7MQgCroDAYHujNA1Kkuw
|
||||
QxYlxy+exeSnHD6YzZ1lAFHZSc+xPXQVc6wCFMuruk9KymrGNh5V4lFoU+Bm1bLw
|
||||
5berLIpQn8jKffZulSPeWcPw0cBQWgKMk3uEW1H6vJggepjunnjINDW7RvP7Thma
|
||||
wVmU45EUeL3uzZR2JO+gX+Ay3oLCBTNCFrIa1U/cgrdXgTLBKT6JVfLaVPWMxqfA
|
||||
n7f9e9DryEcB2pIq1l1CfUPMZdSYCI3pAT53io4imaUsB2HzWO39Ie1fGaHOo1Mk
|
||||
MCSny0ySLRTGeefYJur3LCCyGkxpxGxFzqmCG2oF0UdQgw6rf8ENjojG3KyGNeYO
|
||||
fkOd1kzv22NI8Zs+LEJQdkXWz16EeP8ZViZZ3lnG2lViFXAK3f4/U/fpuLCuMUi7
|
||||
pDhncIFqrTPRozFWL0xbPAsCAwEAAQ==
|
||||
-----END PUBLIC KEY-----
|
||||
hubloc_network: zot6
|
||||
hubloc_updated: 2025-11-19T21:57:19
|
||||
@@ -1,6 +1,6 @@
|
||||
<div id="{{$field.0}}_container" class="clearfix onoffswitch checkbox mb-3">
|
||||
<label for="id_{{$field.0}}">{{$field.1}}{{if $field.6}}<sup class="required zuiqmid"> {{$field.6}}</sup>{{/if}}</label>
|
||||
<div class="float-end"><input type="checkbox" name="{{$field.0}}" id="id_{{$field.0}}" value="1" {{if $field.2}}checked="checked"{{/if}} {{if $field.5}}{{$field.5}}{{/if}} /><label class="switchlabel" for='id_{{$field.0}}'> <span class="onoffswitch-inner" data-on='{{if $field.4}}{{$field.4.1}}{{/if}}' data-off='{{if $field.4}}{{$field.4.0}}{{/if}}'></span><span class="onoffswitch-switch"></span></label></div>
|
||||
<label for="id_{{$field.0}}">{{$field.1}}{{if isset($field.6)}}<sup class="required zuiqmid"> {{$field.6}}</sup>{{/if}}</label>
|
||||
<div class="float-end"><input type="checkbox" name="{{$field.0}}" id="id_{{$field.0}}" value="1" {{if $field.2}}checked="checked"{{/if}} {{$field.5|default:''}} ><label class="switchlabel" for='id_{{$field.0}}'> <span class="onoffswitch-inner" data-on='{{if $field.4}}{{$field.4.1}}{{/if}}' data-off='{{if $field.4}}{{$field.4.0}}{{/if}}'></span><span class="onoffswitch-switch"></span></label></div>
|
||||
<small class="form-text text-muted">{{$field.3}}</small>
|
||||
</div>
|
||||
{{*
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
{{if isset($field.5)}}{{$field.5}}{{/if}}
|
||||
>
|
||||
<small id="help_{{$field.0}}" class="form-text text-muted">
|
||||
{{$field.3}}
|
||||
{{$field.3|default:''}}
|
||||
</small>
|
||||
</div>
|
||||
{{*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="mb-3">
|
||||
<label for="id_{{$field.0}}">{{$field.1}}</label>
|
||||
<textarea class="form-control" name="{{$field.0}}" id="id_{{$field.0}}" {{if $field.4}}{{$field.4}}{{/if}} >{{$field.2}}</textarea>
|
||||
<small class="form-text text-muted">{{$field.3}}</small>
|
||||
<textarea class="form-control" name="{{$field.0}}" id="id_{{$field.0}}" {{$field.4|default:''}}>{{$field.2}}</textarea>
|
||||
<small class="form-text text-muted">{{$field.3|default:''}}</small>
|
||||
</div>
|
||||
|
||||
@@ -225,7 +225,7 @@
|
||||
{{/if}}
|
||||
|
||||
|
||||
{{if $fields.address || $fields.locality || $fields.postal_code || $fields.region || $fields.country_name || $fields.hometown}}
|
||||
{{if isset($fields.address) || isset($fields.locality) || isset($fields.postal_code) || isset($fields.region) || isset($fields.country_name) || isset($fields.hometown)}}
|
||||
<div class="panel">
|
||||
<div class="section-subtitle-wrapper" role="tab" id="location">
|
||||
<h3>
|
||||
@@ -236,27 +236,27 @@
|
||||
</div>
|
||||
<div id="location-collapse" class="panel-collapse collapse" data-bs-parent="#profile-edit-wrapper" role="tabpanel" aria-labelledby="location">
|
||||
<div class="section-content-tools-wrapper">
|
||||
{{if $fields.address}}
|
||||
{{if $fields.address|default:false}}
|
||||
{{include file="field_input.tpl" field=$address}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.locality}}
|
||||
{{if $fields.locality|default:false}}
|
||||
{{include file="field_input.tpl" field=$locality}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.postal_code}}
|
||||
{{if $fields.postal_code|default:false}}
|
||||
{{include file="field_input.tpl" field=$postal_code}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.region}}
|
||||
{{if $fields.region|default:false}}
|
||||
{{include file="field_input.tpl" field=$region}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.country_name}}
|
||||
{{if $fields.country_name|default:false}}
|
||||
{{include file="field_input.tpl" field=$country_name}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.hometown}}
|
||||
{{if $fields.hometown|default:false}}
|
||||
{{include file="field_input.tpl" field=$hometown}}
|
||||
{{/if}}
|
||||
|
||||
@@ -281,7 +281,7 @@
|
||||
</div>
|
||||
<div id="relation-collapse" class="panel-collapse collapse" data-bs-parent="#profile-edit-wrapper" role="tabpanel" aria-labelledby="relation">
|
||||
<div class="section-content-tools-wrapper">
|
||||
{{if $fields.marital }}
|
||||
{{if $fields.marital|default:false }}
|
||||
<div id="profile-edit-marital-wrapper" class="mb-3 field" >
|
||||
<label id="profile-edit-marital-label" for="profile-edit-marital" ><span class="heart"><i class="bi fa-heart"></i> </span>{{$lbl_marital}}</label>
|
||||
{{if $advanced}}
|
||||
@@ -292,16 +292,16 @@
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
|
||||
{{if $fields.partner}}
|
||||
{{if isset($fields.partner)}}
|
||||
{{include file="field_input.tpl" field=$with}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.howlong}}
|
||||
{{if isset($fields.howlong)}}
|
||||
{{include file="field_input.tpl" field=$howlong}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.sexual}}
|
||||
{{if isset($fields.sexual)}}
|
||||
<div id="profile-edit-sexual-wrapper" class="mb-3 field" >
|
||||
<label id="profile-edit-sexual-label" for="sexual-select" >{{$lbl_sexual}}</label>
|
||||
{{if $advanced}}
|
||||
@@ -321,7 +321,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{if $fields.keywords || $fields.politic || $fields.religion || $fields.about || $fields.contact || $fields.homepage || $fields.interest || $fields.likes || $fields.dislikes || $fields.channels || $fields.music || $fields.book || $fields.tv || $fields.film || $fields.romance || $fields.employment || $fields.education || $extra_fields}}
|
||||
{{if isset($fields.keywords) || isset($fields.politic) || isset($fields.religion) || isset($fields.about) || isset($fields.contact) || isset($fields.homepage) || isset($fields.interest) || isset($fields.likes) || isset($fields.dislikes) || isset($fields.channels) || isset($fields.music) || isset($fields.book) || isset($fields.tv) || isset($fields.film) || isset($fields.romance) || isset($fields.employment) || isset($fields.education) || isset($extra_fields)}}
|
||||
<div class="panel">
|
||||
<div class="section-subtitle-wrapper" role="tab" id="miscellaneous">
|
||||
<h3>
|
||||
@@ -332,71 +332,71 @@
|
||||
</div>
|
||||
<div id="miscellaneous-collapse" class="panel-collapse collapse" data-bs-parent="#profile-edit-wrapper" role="tabpanel" aria-labelledby="miscellaneous">
|
||||
<div class="section-content-tools-wrapper">
|
||||
{{if $fields.homepage}}
|
||||
{{if isset($fields.homepage)}}
|
||||
{{include file="field_input.tpl" field=$homepage}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.keywords}}
|
||||
{{if isset($fields.keywords)}}
|
||||
{{include file="field_input.tpl" field=$keywords}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.politic}}
|
||||
{{if isset($fields.politic)}}
|
||||
{{include file="field_input.tpl" field=$politic}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.religion}}
|
||||
{{if isset($fields.religion)}}
|
||||
{{include file="field_input.tpl" field=$religion}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.about}}
|
||||
{{if isset($fields.about)}}
|
||||
{{include file="field_textarea.tpl" field=$about}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.contact}}
|
||||
{{if isset($fields.contact)}}
|
||||
{{include file="field_textarea.tpl" field=$contact}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.interest}}
|
||||
{{if isset($fields.interest)}}
|
||||
{{include file="field_textarea.tpl" field=$interest}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.likes}}
|
||||
{{if isset($fields.likes)}}
|
||||
{{include file="field_textarea.tpl" field=$likes}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.dislikes}}
|
||||
{{if isset($fields.dislikes)}}
|
||||
{{include file="field_textarea.tpl" field=$dislikes}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.channels}}
|
||||
{{if isset($fields.channels)}}
|
||||
{{include file="field_textarea.tpl" field=$channels}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.music}}
|
||||
{{if isset($fields.music)}}
|
||||
{{include file="field_textarea.tpl" field=$music}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.book}}
|
||||
{{if isset($fields.book)}}
|
||||
{{include file="field_textarea.tpl" field=$book}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.tv}}
|
||||
{{if isset($fields.tv)}}
|
||||
{{include file="field_textarea.tpl" field=$tv}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.film}}
|
||||
{{if isset($fields.film)}}
|
||||
{{include file="field_textarea.tpl" field=$film}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.romance}}
|
||||
{{if isset($fields.romance)}}
|
||||
{{include file="field_textarea.tpl" field=$romance}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.employment}}
|
||||
{{if isset($fields.employment)}}
|
||||
{{include file="field_textarea.tpl" field=$employ}}
|
||||
{{/if}}
|
||||
|
||||
{{if $fields.education}}
|
||||
{{if isset($fields.education)}}
|
||||
{{include file="field_textarea.tpl" field=$education}}
|
||||
{{/if}}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user