mirror of
https://framagit.org/hubzilla/core.git
synced 2026-06-23 09:45:45 -04:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
173c4d242d | ||
|
|
76b8c36f7c | ||
|
|
f35352090e | ||
|
|
e5db47e0d5 | ||
|
|
6a52e502aa | ||
|
|
6a866fe904 | ||
|
|
d9d239bf3a | ||
|
|
429d15f009 | ||
|
|
2b44be58c3 | ||
|
|
c44db397ff | ||
|
|
a385fdff37 | ||
|
|
20aacb82c6 | ||
|
|
0d17d8dad9 | ||
|
|
2ab0118c13 | ||
|
|
30419bdbf6 | ||
|
|
c958cc6f90 | ||
|
|
38ac60e618 | ||
|
|
23a19ecf1f | ||
|
|
8b75f50f23 | ||
|
|
436b1673cf | ||
|
|
96210f5ecc | ||
|
|
9e9e8efb2d | ||
|
|
e9dc4b553b | ||
|
|
c70bd08c10 | ||
|
|
69109a558b | ||
|
|
4aff6d19d6 | ||
|
|
3cb5d14037 | ||
|
|
5f685bcf63 | ||
|
|
cb44f7e360 | ||
|
|
8f74ee67e3 | ||
|
|
b0a11537de | ||
|
|
4de9cb1142 |
32
CHANGELOG
32
CHANGELOG
@@ -1,3 +1,35 @@
|
||||
Hubzilla 9.4.4 (2024-11-06)
|
||||
- Update Norwegian translations
|
||||
- Fix error adding things when multiple profiles not enabled
|
||||
- Port mod thing to use $_GET/$_POST instead of $_REQUEST
|
||||
- Move Norwegian translations from nb-no to nb
|
||||
- Fix intact alernative network hublocs being marked deleted in Libsync::sync_locations()
|
||||
- Fix modals only partly removed when DOM emlement updated via ajax
|
||||
- Add explicit check for channel_address in channel_url()
|
||||
- Fix PHP deprecation warnings in mod setup
|
||||
- Fix PHP warning in Web/HttpMeta
|
||||
- Fix typo in UnitTestCase
|
||||
- Fix missing CSRF token checks in mod account_edit
|
||||
- Fix OCAP tokens only added to images
|
||||
- Fix unescaped zid parameter
|
||||
- Fix wrong date format in published date in update question activities
|
||||
- Fix include for en TOS page
|
||||
- Fix query in copy_of_pubitem() returning duplicate items
|
||||
- Fix edit button not clickable if below right aside when viewing webpages
|
||||
- Fix rendering of category tags icons in the editor
|
||||
- Fix regex to detect URLs in cleanup_bbcode
|
||||
- Fix duplicate posts from forum clones
|
||||
- Fix follow to non primary hub location in pubcrawl addon
|
||||
- Fix id host not rewritten to local host in pubcrawl addon
|
||||
- Fix regression when manually fetching items in pubcrawl addon
|
||||
|
||||
|
||||
Hubzilla 9.4.3 (2024-10-10)
|
||||
- Discard Add/Remove activities (Hubzilla 10 and (streams) compatibility)
|
||||
- Fix HQ channel activities icons
|
||||
- Fix saved search icons
|
||||
|
||||
|
||||
Hubzilla 9.4.2 (2024-10-04)
|
||||
- Indicate reacted state via icon color (community wish)
|
||||
- Fix modal backdrop not removed when reacting from the modal
|
||||
|
||||
@@ -503,15 +503,21 @@ class Activity {
|
||||
$ret['diaspora:guid'] = $i['uuid'];
|
||||
|
||||
$images = [];
|
||||
$audios = [];
|
||||
$videos = [];
|
||||
|
||||
$has_images = preg_match_all('/\[[zi]mg(.*?)](.*?)\[/ism', $i['body'], $images, PREG_SET_ORDER);
|
||||
$has_audios = preg_match_all('/\[zaudio](.*?)\[/ism', $i['body'], $audios, PREG_SET_ORDER);
|
||||
$has_videos = preg_match_all('/\[zvideo](.*?)\[/ism', $i['body'], $videos, PREG_SET_ORDER);
|
||||
|
||||
// provide ocap access token for private media.
|
||||
// set this for descendants even if the current item is not private
|
||||
// because it may have been relayed from a private item.
|
||||
|
||||
$token = IConfig::Get($i, 'ocap', 'relay');
|
||||
$matches_processed = [];
|
||||
|
||||
if ($token && $has_images) {
|
||||
$matches_processed = [];
|
||||
for ($n = 0; $n < count($images); $n++) {
|
||||
$match = $images[$n];
|
||||
if (str_starts_with($match[1], '=http') && str_contains($match[1], z_root() . '/photo/') && !in_array($match[1], $matches_processed)) {
|
||||
@@ -526,6 +532,28 @@ class Activity {
|
||||
}
|
||||
}
|
||||
|
||||
if ($token && $has_audios) {
|
||||
for ($n = 0; $n < count($audios); $n++) {
|
||||
$match = $audios[$n];
|
||||
if (str_contains($match[1], z_root() . '/attach/') && !in_array($match[1], $matches_processed)) {
|
||||
$i['body'] = str_replace($match[1], $match[1] . '?token=' . $token, $i['body']);
|
||||
$audios[$n][1] = $match[1] . '?token=' . $token;
|
||||
$matches_processed[] = $match[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($token && $has_videos) {
|
||||
for ($n = 0; $n < count($videos); $n++) {
|
||||
$match = $videos[$n];
|
||||
if (str_contains($match[1], z_root() . '/attach/') && !in_array($match[1], $matches_processed)) {
|
||||
$i['body'] = str_replace($match[1], $match[1] . '?token=' . $token, $i['body']);
|
||||
$videos[$n][1] = $match[1] . '?token=' . $token;
|
||||
$matches_processed[] = $match[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($i['title'])
|
||||
$ret['name'] = unescape_tags($i['title']);
|
||||
|
||||
@@ -694,6 +722,8 @@ class Activity {
|
||||
|
||||
$ret = [];
|
||||
|
||||
$token = IConfig::Get($item, 'ocap', 'relay');
|
||||
|
||||
if (!$iconfig && array_key_exists('attach', $item)) {
|
||||
$atts = ((is_array($item['attach'])) ? $item['attach'] : json_decode($item['attach'], true));
|
||||
if ($atts) {
|
||||
@@ -702,11 +732,17 @@ class Activity {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($att['type']) && strpos($att['type'], 'image')) {
|
||||
$ret[] = ['type' => 'Image', 'mediaType' => $att['type'], 'name' => $att['title'], 'url' => $att['href']];
|
||||
if (str_starts_with($att['type'], 'image')) {
|
||||
$ret[] = ['type' => 'Image', 'mediaType' => $att['type'], 'name' => $att['title'], 'url' => $att['href'] . (($token) ? '?token=' . $token : '')];
|
||||
}
|
||||
elseif (str_starts_with($att['type'], 'audio')) {
|
||||
$ret[] = ['type' => 'Audio', 'mediaType' => $att['type'], 'name' => $att['title'], 'url' => $att['href'] . (($token) ? '?token=' . $token : '')];
|
||||
}
|
||||
elseif (str_starts_with($att['type'], 'video')) {
|
||||
$ret[] = ['type' => 'Video', 'mediaType' => $att['type'], 'name' => $att['title'], 'url' => $att['href'] . (($token) ? '?token=' . $token : '')];
|
||||
}
|
||||
else {
|
||||
$ret[] = ['type' => 'Link', 'mediaType' => $att['type'], 'name' => $att['title'], 'href' => $att['href']];
|
||||
$ret[] = ['type' => 'Link', 'mediaType' => $att['type'], 'name' => $att['title'], 'href' => $att['href'] . (($token) ? '?token=' . $token : '')];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3054,13 +3090,6 @@ class Activity {
|
||||
}
|
||||
|
||||
$a = new ActivityStreams($n);
|
||||
if ($a->type === 'Announce' && is_array($a->obj)
|
||||
&& array_key_exists('object', $a->obj) && array_key_exists('actor', $a->obj)) {
|
||||
// This is a relayed/forwarded Activity (as opposed to a shared/boosted object)
|
||||
// Reparse the encapsulated Activity and use that instead
|
||||
logger('relayed activity', LOGGER_DEBUG);
|
||||
$a = new ActivityStreams($a->obj);
|
||||
}
|
||||
|
||||
logger($a->debug(), LOGGER_DATA);
|
||||
|
||||
@@ -3069,6 +3098,24 @@ class Activity {
|
||||
break;
|
||||
}
|
||||
|
||||
if (in_array($a->type, ['Add', 'Remove'])
|
||||
&& is_array($a->obj)
|
||||
&& array_key_exists('object', $a->obj)
|
||||
&& array_key_exists('actor', $a->obj)
|
||||
&& !empty($a->tgt)) {
|
||||
|
||||
logger('unsupported collection operation', LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($a->type === 'Announce' && is_array($a->obj)
|
||||
&& array_key_exists('object', $a->obj) && array_key_exists('actor', $a->obj)) {
|
||||
// This is a relayed/forwarded Activity (as opposed to a shared/boosted object)
|
||||
// Reparse the encapsulated Activity and use that instead
|
||||
logger('relayed activity', LOGGER_DEBUG);
|
||||
$a = new ActivityStreams($a->obj);
|
||||
}
|
||||
|
||||
$item = Activity::decode_note($a);
|
||||
|
||||
if (!$item) {
|
||||
|
||||
@@ -885,7 +885,7 @@ class Libsync {
|
||||
dbesc($t)
|
||||
);
|
||||
|
||||
q("update hubloc set hubloc_error = 1, hubloc_deleted = 1 where hubloc_url = '%s' and hubloc_sitekey != '%s'",
|
||||
q("update hubloc set hubloc_error = 1, hubloc_deleted = 1 where hubloc_url = '%s' and hubloc_sitekey != '%s' and hubloc_network = 'zot6'",
|
||||
dbesc($r[0]['hubloc_url']),
|
||||
dbesc($r[0]['hubloc_sitekey'])
|
||||
);
|
||||
|
||||
@@ -1148,6 +1148,17 @@ class Libzot {
|
||||
logger('Activity rejected: ' . print_r($data, true));
|
||||
return;
|
||||
}
|
||||
|
||||
if (in_array($AS->type, ['Add', 'Remove'])
|
||||
&& is_array($AS->obj)
|
||||
&& array_key_exists('object', $AS->obj)
|
||||
&& array_key_exists('actor', $AS->obj)
|
||||
&& !empty($AS->tgt)) {
|
||||
|
||||
logger('unsupported collection operation', LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_array($AS->obj)) {
|
||||
$item = Activity::decode_note($AS);
|
||||
if (!$item) {
|
||||
@@ -1158,6 +1169,7 @@ class Libzot {
|
||||
else {
|
||||
$item = [];
|
||||
}
|
||||
|
||||
logger($AS->debug(), LOGGER_DATA);
|
||||
|
||||
}
|
||||
@@ -2006,7 +2018,13 @@ class Libzot {
|
||||
foreach ($items as $activity) {
|
||||
|
||||
$AS = new ActivityStreams($activity);
|
||||
if ($AS->is_valid() && $AS->type === 'Announce' && is_array($AS->obj)
|
||||
|
||||
if (!$AS->is_valid()) {
|
||||
logger('Fetched activity rejected: ' . print_r($activity, true));
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($AS->type === 'Announce' && is_array($AS->obj)
|
||||
&& array_key_exists('object', $AS->obj) && array_key_exists('actor', $AS->obj)) {
|
||||
// This is a relayed/forwarded Activity (as opposed to a shared/boosted object)
|
||||
// Reparse the encapsulated Activity and use that instead
|
||||
@@ -2014,9 +2032,14 @@ class Libzot {
|
||||
$AS = new ActivityStreams($AS->obj);
|
||||
}
|
||||
|
||||
if (!$AS->is_valid()) {
|
||||
logger('Fetched activity rejected: ' . print_r($activity, true));
|
||||
continue;
|
||||
if (in_array($AS->type, ['Add', 'Remove'])
|
||||
&& is_array($AS->obj)
|
||||
&& array_key_exists('object', $AS->obj)
|
||||
&& array_key_exists('actor', $AS->obj)
|
||||
&& !empty($AS->tgt)) {
|
||||
|
||||
logger('unsupported collection operation', LOGGER_DEBUG);
|
||||
return;
|
||||
}
|
||||
|
||||
// logger($AS->debug());
|
||||
|
||||
@@ -8,6 +8,11 @@ class Account_edit {
|
||||
|
||||
function post() {
|
||||
|
||||
// Validate CSRF token
|
||||
//
|
||||
// We terminate with a 403 Forbidden status if the check fails.
|
||||
check_form_security_token_ForbiddenOnErr('admin_account_edit', 'security');
|
||||
|
||||
$account_id = $_REQUEST['aid'];
|
||||
|
||||
if(! $account_id)
|
||||
@@ -18,7 +23,7 @@ class Account_edit {
|
||||
if($pass1 && $pass2 && ($pass1 === $pass2)) {
|
||||
$salt = random_string(32);
|
||||
$password_encoded = hash('whirlpool', $salt . $pass1);
|
||||
$r = q("update account set account_salt = '%s', account_password = '%s',
|
||||
$r = q("update account set account_salt = '%s', account_password = '%s',
|
||||
account_password_changed = '%s' where account_id = %d",
|
||||
dbesc($salt),
|
||||
dbesc($password_encoded),
|
||||
@@ -34,7 +39,7 @@ class Account_edit {
|
||||
$account_level = 5;
|
||||
$account_language = trim($_REQUEST['account_language']);
|
||||
|
||||
$r = q("update account set account_service_class = '%s', account_level = %d, account_language = '%s'
|
||||
$r = q("update account set account_service_class = '%s', account_level = %d, account_language = '%s'
|
||||
where account_id = %d",
|
||||
dbesc($service_class),
|
||||
intval($account_level),
|
||||
@@ -62,8 +67,8 @@ class Account_edit {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
$a = replace_macros(get_markup_template('admin_account_edit.tpl'), [
|
||||
'$security' => get_form_security_token('admin_account_edit'),
|
||||
'$account' => $x[0],
|
||||
'$title' => t('Account Edit'),
|
||||
'$pass1' => [ 'pass1', t('New Password'), ' ','' ],
|
||||
|
||||
@@ -1060,7 +1060,7 @@ class Item extends Controller {
|
||||
$obj['id'] = $mid;
|
||||
$obj['diaspora:guid'] = $uuid;
|
||||
$obj['attributedTo'] = channel_url($channel);
|
||||
$obj['published'] = $created;
|
||||
$obj['published'] = datetime_convert('UTC', 'UTC', $created, ATOM_TIME);
|
||||
$obj['name'] = $title;
|
||||
|
||||
$datarray['obj'] = $obj;
|
||||
|
||||
@@ -263,7 +263,10 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
|
||||
$this->check_htaccess($checks);
|
||||
|
||||
$checkspassed = array_reduce($checks, "self::check_passed", true);
|
||||
$checkspassed = array_reduce(
|
||||
$checks,
|
||||
"Zotlabs\Module\Setup::check_passed",
|
||||
true);
|
||||
|
||||
$tpl = get_markup_template('install_checks.tpl');
|
||||
$o .= replace_macros($tpl, array(
|
||||
|
||||
@@ -50,24 +50,31 @@ class Thing extends \Zotlabs\Web\Controller {
|
||||
|
||||
$channel = \App::get_channel();
|
||||
|
||||
$term_hash = (($_REQUEST['term_hash']) ? $_REQUEST['term_hash'] : '');
|
||||
$term_hash = (($_POST['term_hash']) ? $_POST['term_hash'] : '');
|
||||
|
||||
$name = escape_tags($_REQUEST['term']);
|
||||
$verb = escape_tags($_REQUEST['verb']);
|
||||
$activity = intval($_REQUEST['activity']);
|
||||
$profile_guid = escape_tags($_REQUEST['profile_assign']);
|
||||
$url = $_REQUEST['url'];
|
||||
$photo = $_REQUEST['img'];
|
||||
$name = escape_tags($_POST['term']);
|
||||
$verb = escape_tags($_POST['verb']);
|
||||
$activity = intval($_POST['activity']);
|
||||
$url = $_POST['url'];
|
||||
$photo = $_POST['img'];
|
||||
|
||||
$profile_guid = isset($_POST['profile_assign'])
|
||||
? escape_tags($_POST['profile_assign'])
|
||||
: null;
|
||||
|
||||
$hash = new_uuid();
|
||||
|
||||
$verbs = obj_verbs();
|
||||
|
||||
/**
|
||||
* verbs: [0] = first person singular, e.g. "I want", [1] = 3rd person singular, e.g. "Bill wants"
|
||||
* We use the first person form when creating an activity, but the third person for use in activities
|
||||
* @FIXME There is no accounting for verb gender for languages where this is significant. We may eventually
|
||||
* require obj_verbs() to provide full conjugations and specify which form to use in the $_REQUEST params to this module.
|
||||
/*
|
||||
* verbs: [0] = first person singular, e.g. "I want", [1] = 3rd person
|
||||
* singular, e.g. "Bill wants" We use the first person form when
|
||||
* creating an activity, but the third person for use in activities
|
||||
*
|
||||
* @FIXME There is no accounting for verb gender for languages where
|
||||
* this is significant. We may eventually require obj_verbs() to
|
||||
* provide full conjugations and specify which form to use in the
|
||||
* $_POST params to this module.
|
||||
*/
|
||||
|
||||
$translated_verb = $verbs[$verb][1];
|
||||
@@ -100,7 +107,7 @@ class Thing extends \Zotlabs\Web\Controller {
|
||||
return;
|
||||
|
||||
$acl = new \Zotlabs\Access\AccessList($channel);
|
||||
$acl->set_from_array($_REQUEST);
|
||||
$acl->set_from_array($_POST);
|
||||
|
||||
$x = $acl->get();
|
||||
|
||||
@@ -394,7 +401,7 @@ class Thing extends \Zotlabs\Web\Controller {
|
||||
'$profile_lbl' => t('Select a profile'),
|
||||
'$profile_select' => contact_profile_assign(''),
|
||||
'$verb_lbl' => $channel['channel_name'],
|
||||
'$activity' => array('activity',t('Post an activity'),((array_key_exists('activity',$_REQUEST)) ? $_REQUEST['activity'] : true),t('Only sends to viewers of the applicable profile')),
|
||||
'$activity' => array('activity',t('Post an activity'),((array_key_exists('activity',$_GET)) ? $_GET['activity'] : true),t('Only sends to viewers of the applicable profile')),
|
||||
'$verb_select' => obj_verb_selector(),
|
||||
'$thing_lbl' => t('Name of thing e.g. something'),
|
||||
'$url_lbl' => t('URL of thing (optional)'),
|
||||
|
||||
@@ -5,16 +5,9 @@ namespace Zotlabs\Web;
|
||||
|
||||
class HttpMeta {
|
||||
|
||||
private $vars = null;
|
||||
private $og = null;
|
||||
|
||||
function __construct() {
|
||||
|
||||
$this->vars = [];
|
||||
$this->og = [];
|
||||
$this->ogproperties = [];
|
||||
|
||||
}
|
||||
private $vars = [];
|
||||
private $og = [];
|
||||
private $ogproperties = [];
|
||||
|
||||
//Set Meta Value
|
||||
// Mode:
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Web;
|
||||
|
||||
use Zotlabs\Lib\Text;
|
||||
|
||||
class WebServer {
|
||||
|
||||
public function run() {
|
||||
@@ -60,7 +62,7 @@ class WebServer {
|
||||
\App::$query_string = strip_zids(\App::$query_string);
|
||||
if(! local_channel()) {
|
||||
if (!isset($_SESSION['my_address']) || $_SESSION['my_address'] != $_GET['zid']) {
|
||||
$_SESSION['my_address'] = $_GET['zid'];
|
||||
$_SESSION['my_address'] = Text::escape_tags($_GET['zid']);
|
||||
$_SESSION['authenticated'] = 0;
|
||||
}
|
||||
if(!$_SESSION['authenticated']) {
|
||||
|
||||
@@ -91,7 +91,7 @@ class Channel_activities {
|
||||
|
||||
self::$activities['photos'] = [
|
||||
'label' => t('Photos'),
|
||||
'icon' => 'photo',
|
||||
'icon' => 'image',
|
||||
'url' => z_root() . '/photos/' . self::$channel['channel_address'],
|
||||
'date' => $r[0]['edited'],
|
||||
'items' => $i,
|
||||
@@ -123,7 +123,7 @@ class Channel_activities {
|
||||
|
||||
self::$activities['files'] = [
|
||||
'label' => t('Files'),
|
||||
'icon' => 'folder-open',
|
||||
'icon' => 'folder',
|
||||
'url' => z_root() . '/cloud/' . self::$channel['channel_address'],
|
||||
'date' => $r[0]['edited'],
|
||||
'items' => $i,
|
||||
@@ -166,7 +166,7 @@ class Channel_activities {
|
||||
|
||||
self::$activities['webpages'] = [
|
||||
'label' => t('Webpages'),
|
||||
'icon' => 'newspaper-o',
|
||||
'icon' => 'layout-text-sidebar',
|
||||
'url' => z_root() . '/webpages/' . self::$channel['channel_address'],
|
||||
'date' => $r[0]['edited'],
|
||||
'items' => $i,
|
||||
@@ -237,7 +237,7 @@ class Channel_activities {
|
||||
|
||||
self::$activities['channels'] = [
|
||||
'label' => t('Channels'),
|
||||
'icon' => 'home',
|
||||
'icon' => 'house',
|
||||
'url' => z_root() . '/manage',
|
||||
'date' => datetime_convert(),
|
||||
'items' => $i,
|
||||
|
||||
2
boot.php
2
boot.php
@@ -66,7 +66,7 @@ require_once('include/security.php');
|
||||
|
||||
|
||||
define('PLATFORM_NAME', 'hubzilla');
|
||||
define('STD_VERSION', '9.4.2');
|
||||
define('STD_VERSION', '9.4.4');
|
||||
define('ZOT_REVISION', '6.0');
|
||||
|
||||
define('DB_UPDATE_VERSION', 1263);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
Privacy Policy
|
||||
==============
|
||||
|
||||
#include doc/gdpr1.md;
|
||||
#include doc/en/gdpr1.md;
|
||||
|
||||
|
||||
Terms of Service
|
||||
================
|
||||
|
||||
#include doc/SiteTOS.md;
|
||||
#include doc/en/SiteTOS.md;
|
||||
|
||||
|
||||
@@ -3106,7 +3106,7 @@ function pchan_to_chan($pchan) {
|
||||
}
|
||||
|
||||
function channel_url($channel) {
|
||||
return (($channel) ? z_root() . '/channel/' . $channel['channel_address'] : z_root());
|
||||
return ((isset($channel['channel_address'])) ? z_root() . '/channel/' . $channel['channel_address'] : z_root());
|
||||
}
|
||||
|
||||
function get_channel_hashes() {
|
||||
|
||||
@@ -3196,7 +3196,9 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
|
||||
|
||||
}
|
||||
else {
|
||||
$arr['uuid'] = item_message_id();
|
||||
// To prevent duplicates from possible clones of the forum/group,
|
||||
// will create a v5 UUID of the source item mid.
|
||||
$arr['uuid'] = uuid_from_url($item['mid']);
|
||||
$arr['mid'] = z_root() . '/item/' . $arr['uuid'];
|
||||
$arr['parent_mid'] = $arr['mid'];
|
||||
}
|
||||
@@ -5110,25 +5112,19 @@ function copy_of_pubitem($channel,$mid) {
|
||||
return $item[0];
|
||||
}
|
||||
|
||||
|
||||
$r = q("select * from item where parent_mid = (select parent_mid from item where mid = '%s' and uid = %d ) order by id ",
|
||||
$r = q("select * from item where parent_mid = (select parent_mid from item where mid = '%s' and uid = %d) and uid = %d order by id ",
|
||||
dbesc($mid),
|
||||
intval($syschan['channel_id']),
|
||||
intval($syschan['channel_id'])
|
||||
);
|
||||
|
||||
if($r) {
|
||||
$items = fetch_post_tags($r,true);
|
||||
foreach($items as $rv) {
|
||||
$d = q("select id from item where mid = '%s' and uid = %d limit 1",
|
||||
dbesc($rv['mid']),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
if($d) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unset($rv['id']);
|
||||
unset($rv['parent']);
|
||||
|
||||
$rv['aid'] = $channel['channel_account_id'];
|
||||
$rv['uid'] = $channel['channel_id'];
|
||||
$rv['item_wall'] = 0;
|
||||
@@ -5141,5 +5137,6 @@ function copy_of_pubitem($channel,$mid) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -3755,12 +3755,9 @@ function cleanup_bbcode($body) {
|
||||
$body = preg_replace_callback('/\[img(.*?)\[\/(img)\]/ism','\red_escape_codeblock',$body);
|
||||
$body = preg_replace_callback('/\[zmg(.*?)\[\/(zmg)\]/ism','\red_escape_codeblock',$body);
|
||||
|
||||
$body = preg_replace_callback("/([^\]\='".'"'."\;\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\
|
||||
+\,\(\)]+)/ismu", '\nakedoembed', $body);
|
||||
|
||||
$body = preg_replace_callback("/([^\]\='".'"'."\;\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\
|
||||
+\,\(\)]+)/ismu", '\red_zrl_callback', $body);
|
||||
$body = preg_replace_callback("/([^\]\='".'"'."\;\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\+\,\(\)]+)/ismu", '\nakedoembed', $body);
|
||||
|
||||
$body = preg_replace_callback("/([^\]\='".'"'."\;\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\+\,\(\)]+)/ismu", '\red_zrl_callback', $body);
|
||||
|
||||
$body = preg_replace_callback('/\[\$b64code(.*?)\[\/(code)\]/ism','\red_unescape_codeblock',$body);
|
||||
$body = preg_replace_callback('/\[\$b64summary(.*?)\[\/(summary)\]/ism','\red_unescape_codeblock',$body);
|
||||
|
||||
214
tests/unit/Module/AdminAccountEditTest.php
Normal file
214
tests/unit/Module/AdminAccountEditTest.php
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
/* Tests for Account_edit module
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2024 Hubzilla Community
|
||||
* SPDX-FileContributor: Harald Eilertsen
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
namespace Zotlabs\Tests\Unit\Module;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use PHPUnit\Framework\Attributes\{Before, After};
|
||||
use Zotlabs\Model\Account;
|
||||
|
||||
class AdminAccountEditTest extends TestCase {
|
||||
|
||||
#[Before]
|
||||
public function setup_mocks(): void {
|
||||
/*
|
||||
* As we're testing pages that should only be reachable by the
|
||||
* site admin, it makes no sense to have it return anything else
|
||||
* than true.
|
||||
*/
|
||||
$this->stub_is_site_admin =
|
||||
$this->getFunctionMock('Zotlabs\Module', 'is_site_admin')
|
||||
->expects($this->once())
|
||||
->willReturn(true);
|
||||
|
||||
$this->info = [];
|
||||
$this->stub_info =
|
||||
$this->getFunctionMock('Zotlabs\Module\Admin', 'info')
|
||||
->expects($this->any())
|
||||
->willReturnCallback(function (string $arg) {
|
||||
$this->info[] = $arg;
|
||||
});
|
||||
|
||||
$this->notice = [];
|
||||
$this->stub_notice =
|
||||
$this->getFunctionMock('Zotlabs\Module\Admin', 'notice')
|
||||
->expects($this->any())
|
||||
->willReturnCallback(function (string $arg) {
|
||||
$this->notice[] = $arg;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
#[After]
|
||||
public function tear_down_mocks(): void {
|
||||
$this->stub_is_site_admin = null;
|
||||
$this->stub_info = null;
|
||||
$this->stub_notice = null;
|
||||
$this->stub_check_security = null;
|
||||
$this->stub_get_form_security_token = null;
|
||||
}
|
||||
|
||||
public function test_rendering_admin_account_edit_page(): void {
|
||||
$this->stub_get_form_security_token =
|
||||
$this->getFunctionMock('Zotlabs\Module\Admin', 'get_form_security_token')
|
||||
->expects($this->once())
|
||||
->willReturn('the-csrf-token');
|
||||
|
||||
$account = $this->fixtures['account'][0];
|
||||
|
||||
$this->get("admin/account_edit/{$account['account_id']}");
|
||||
|
||||
$this->assertPageContains("<form action=\"admin/account_edit/{$account['account_id']}\" method=\"post\"");
|
||||
$this->assertPageContains($account['account_email']);
|
||||
|
||||
// Check that we generate a CSRF token for the form
|
||||
$this->assertPageContains("<input type=\"hidden\" name=\"security\" value=\"the-csrf-token\"");
|
||||
}
|
||||
|
||||
public function test_rendering_admin_account_edit_page_fails_if_id_is_not_found(): void {
|
||||
$this->get("admin/account_edit/666");
|
||||
|
||||
$this->assertEquals('', \App::$page['content']);
|
||||
}
|
||||
|
||||
public function test_rendering_admin_account_edit_page_fails_if_id_is_not_numeric(): void {
|
||||
$this->get("admin/account_edit/66invalid");
|
||||
|
||||
$this->assertEquals('', \App::$page['content']);
|
||||
}
|
||||
|
||||
public function test_post_empty_form_does_not_modify_account(): void {
|
||||
$this->stub_goaway();
|
||||
$this->stub_check_form_security(true);
|
||||
|
||||
$account = get_account_by_id($this->fixtures['account'][0]['account_id']);
|
||||
|
||||
try {
|
||||
$this->post(
|
||||
"admin/account_edit/{$account['account_id']}",
|
||||
[],
|
||||
[
|
||||
'aid' => $account['account_id'],
|
||||
'pass1' => '',
|
||||
'pass2' => '',
|
||||
'service_class' => $account['account_service_class'],
|
||||
'account_language' => $account['account_language'],
|
||||
'security' => 'The security token',
|
||||
]
|
||||
);
|
||||
} catch (RedirectException $ex) {
|
||||
$this->assertEquals(z_root() . '/admin/accounts', $ex->getMessage());
|
||||
}
|
||||
|
||||
$reloaded = get_account_by_id($account['account_id']);
|
||||
|
||||
$this->assertEquals($account, $reloaded);
|
||||
|
||||
// Not sure if this is expected behaviour, but this is how it is today.
|
||||
$this->assertContains('Account settings updated.' . EOL, $this->info);
|
||||
}
|
||||
|
||||
public function test_post_form_changes_account(): void {
|
||||
$this->stub_goaway();
|
||||
$this->stub_check_form_security(true);
|
||||
|
||||
// clone account from fixture, to ensure it's not replaced with
|
||||
// the reloaded one below.
|
||||
$account = get_account_by_id($this->fixtures['account'][0]['account_id']);
|
||||
|
||||
try {
|
||||
$this->post(
|
||||
"admin/account_edit/{$account['account_id']}",
|
||||
[],
|
||||
[
|
||||
'aid' => $account['account_id'],
|
||||
'pass1' => 'hunter2',
|
||||
'pass2' => 'hunter2',
|
||||
'service_class' => 'Some other class',
|
||||
'account_language' => 'nn',
|
||||
'security' => 'The security token',
|
||||
]
|
||||
);
|
||||
} catch (RedirectException $ex) {
|
||||
$this->assertEquals(z_root() . '/admin/accounts', $ex->getMessage());
|
||||
}
|
||||
|
||||
$reloaded = get_account_by_id($account['account_id']);
|
||||
|
||||
$this->assertNotEquals($account, $reloaded);
|
||||
$this->assertEquals('Some other class', $reloaded['account_service_class']);
|
||||
$this->assertEquals('nn', $reloaded['account_language']);
|
||||
|
||||
$now = new DateTimeImmutable('now');
|
||||
$this->assertEquals($now->format('Y-m-d H:i:s'), $reloaded['account_password_changed']);
|
||||
|
||||
$this->assertContains('Account settings updated.' . EOL, $this->info);
|
||||
$this->assertContains("Password changed for account {$account['account_id']}." . EOL, $this->info);
|
||||
}
|
||||
|
||||
public function test_form_with_missing_or_incalid_csrf_token_is_rejected(): void {
|
||||
$this->expectException(KillmeException::class);
|
||||
|
||||
// Emulate a failed CSRF check
|
||||
$this->stub_check_form_security(false);
|
||||
|
||||
$account_id = $this->fixtures['account'][0]['account_id'];
|
||||
|
||||
$this->post(
|
||||
"admin/account_edit/{$account_id}",
|
||||
[],
|
||||
[
|
||||
'aid' => $account_id,
|
||||
'pass1' => 'hunter2',
|
||||
'pass2' => 'hunter2',
|
||||
'service_class' => 'Some other class',
|
||||
'account_language' => 'nn',
|
||||
'security' => 'Invalid security token',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Override the stub_goaway method because we need the stub to live in the
|
||||
* Admin namespace.
|
||||
*/
|
||||
protected function stub_goaway(): void {
|
||||
$this->goaway_stub = $this->getFunctionMock('Zotlabs\Module\Admin', 'goaway')
|
||||
->expects($this->once())
|
||||
->willReturnCallback(
|
||||
function (string $uri) {
|
||||
throw new RedirectException($uri);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stub the check_form_security_token_ForbiddenOnErr.
|
||||
*
|
||||
* In these tests we're not really interested in _how_ the form security
|
||||
* tokens work, but that the code under test perform the checks. This stub
|
||||
* allows us to do that without having to worry if everything is set up so
|
||||
* that the real function would work or not.
|
||||
*
|
||||
* @param bool $valid true if emulating a valid token, false otherwise.
|
||||
*/
|
||||
protected function stub_check_form_security(bool $valid): void {
|
||||
$this->stub_check_security =
|
||||
$this->getFunctionMock('Zotlabs\Module\Admin', 'check_form_security_token_ForbiddenOnErr')
|
||||
->expects($this->once())
|
||||
->with(
|
||||
$this->identicalTo('admin_account_edit'),
|
||||
$this->identicalTo('security'))
|
||||
->willReturnCallback(function () use ($valid) {
|
||||
if (! $valid) {
|
||||
throw new KillmeException();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
namespace Zotlabs\Tests\Unit\Module;
|
||||
|
||||
use PHPUnit\Framework\Attributes\After;
|
||||
use Zotlabs\Tests\Unit\UnitTestCase;
|
||||
use App;
|
||||
|
||||
@@ -25,6 +26,31 @@ class TestCase extends UnitTestCase {
|
||||
// Import PHPMock methods into this class
|
||||
use \phpmock\phpunit\PHPMock;
|
||||
|
||||
#[After]
|
||||
public function cleanup_stubs(): void {
|
||||
$this->killme_stub = null;
|
||||
$this->goaway_stub = null;
|
||||
}
|
||||
|
||||
protected function do_request(string $method, string $uri, array $query = [], array $params = []): void {
|
||||
$_GET['q'] = $uri;
|
||||
$_GET = array_merge($_GET, $query);
|
||||
$_POST = $params;
|
||||
|
||||
$_SERVER['REQUEST_METHOD'] = $method;
|
||||
$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
|
||||
$_SERVER['QUERY_STRING'] = "q={$uri}";
|
||||
// phpcs:disable Generic.PHP.DisallowRequestSuperglobal.Found
|
||||
$_REQUEST = array_merge($_GET, $_POST);
|
||||
// phpcs::enable
|
||||
|
||||
\App::init();
|
||||
\App::$page['content'] = '';
|
||||
|
||||
$router = new \Zotlabs\Web\Router();
|
||||
$router->Dispatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Emulate a GET request.
|
||||
*
|
||||
@@ -34,24 +60,21 @@ class TestCase extends UnitTestCase {
|
||||
* as keys.
|
||||
*/
|
||||
protected function get(string $uri, array $query = []): void {
|
||||
$_GET['q'] = $uri;
|
||||
$this->do_request('GET', $uri, $query);
|
||||
}
|
||||
|
||||
if (!empty($query)) {
|
||||
$_GET = array_merge($_GET, $query);
|
||||
}
|
||||
|
||||
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||
$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
|
||||
$_SERVER['QUERY_STRING'] = "q={$uri}";
|
||||
// phpcs:disable Generic.PHP.DisallowRequestSuperglobal.Found
|
||||
$_REQUEST = $_GET;
|
||||
// phpcs::enable
|
||||
|
||||
\App::init();
|
||||
\App::$page['content'] = '';
|
||||
|
||||
$router = new \Zotlabs\Web\Router();
|
||||
$router->Dispatch();
|
||||
/**
|
||||
* Emulate a POST request.
|
||||
*
|
||||
* @param string $uri The URI to request. Typically this will be the module
|
||||
* name, followed by any req args separated by slashes.
|
||||
* @param array $query Associative array of query args, with the parameters
|
||||
* as keys.
|
||||
* @param array $params Associative array of POST params, with the param names
|
||||
* as keys.
|
||||
*/
|
||||
protected function post(string $uri, array $query = [], array $params = []): void {
|
||||
$this->do_request('POST', $uri, $query, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,8 +123,7 @@ class TestCase extends UnitTestCase {
|
||||
* @throws KillmeException
|
||||
*/
|
||||
protected function stub_killme(): void {
|
||||
$killme_stub = $this->getFunctionMock('Zotlabs\Module', 'killme');
|
||||
$killme_stub
|
||||
$this->killme_stub = $this->getFunctionMock('Zotlabs\Module', 'killme')
|
||||
->expects($this->once())
|
||||
->willReturnCallback(
|
||||
function () {
|
||||
@@ -147,8 +169,7 @@ class TestCase extends UnitTestCase {
|
||||
* @throws RedirectException
|
||||
*/
|
||||
protected function stub_goaway(): void {
|
||||
$goaway_stub = $this->getFunctionMock('Zotlabs\Module', 'goaway');
|
||||
$goaway_stub
|
||||
$this->goaway_stub = $this->getFunctionMock('Zotlabs\Module', 'goaway')
|
||||
->expects($this->once())
|
||||
->willReturnCallback(
|
||||
function (string $uri) {
|
||||
|
||||
@@ -47,7 +47,7 @@ require_once 'include/dba/dba_transaction.php';
|
||||
*/
|
||||
class UnitTestCase extends TestCase {
|
||||
protected array $fixtures = array();
|
||||
protected ?\DbaTransaction $db_transacton = null;
|
||||
protected ?\DbaTransaction $db_transaction = null;
|
||||
|
||||
/**
|
||||
* Connect to the test db, load fixtures and global config.
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
use PHPUnit\Framework\Attributes\Before;
|
||||
|
||||
/**
|
||||
* Test class for testing the Helpindex widget.
|
||||
*/
|
||||
@@ -15,6 +17,8 @@ class HelpindexTest extends \Zotlabs\Tests\Unit\Module\TestCase {
|
||||
|
||||
use \phpmock\phpunit\PHPMock;
|
||||
|
||||
private string $output;
|
||||
|
||||
/**
|
||||
* Define the stubs to make sure they work later in the test.
|
||||
*
|
||||
@@ -27,6 +31,12 @@ class HelpindexTest extends \Zotlabs\Tests\Unit\Module\TestCase {
|
||||
self::defineFunctionMock('Zotlabs\Widget', 'file_get_contents');
|
||||
}
|
||||
|
||||
#[Before]
|
||||
public function setup_state(): void {
|
||||
// Make sure the output is cleared before running the test
|
||||
$this->output = '';
|
||||
}
|
||||
|
||||
public function test_loading_toc(): void {
|
||||
// Stub `file_get_contents` to plant our own content.
|
||||
$fgc_stub = $this->getFunctionMock('Zotlabs\Widget', 'file_get_contents');
|
||||
|
||||
@@ -3,9 +3,11 @@ account:
|
||||
account_id: 42
|
||||
account_email: "hubzilla@example.com"
|
||||
account_language: "no"
|
||||
account_level: 5
|
||||
account_flags: 0
|
||||
-
|
||||
account_id: 43
|
||||
account_email: "hubzilla@example.org"
|
||||
account_language: "de"
|
||||
account_level: 5
|
||||
account_flags: 1
|
||||
|
||||
@@ -1178,20 +1178,27 @@ function justifyPhotosAjax(id) {
|
||||
}
|
||||
|
||||
function dolike(ident, verb) {
|
||||
$('#like-rotator-' + ident.toString()).show();
|
||||
$('#like-rotator-' + ident).show();
|
||||
|
||||
if(typeof conv_mode == typeof undefined)
|
||||
if (typeof conv_mode == typeof undefined) {
|
||||
conv_mode = '';
|
||||
}
|
||||
|
||||
if(typeof page_mode == typeof undefined)
|
||||
if (typeof page_mode == typeof undefined) {
|
||||
page_mode = '';
|
||||
}
|
||||
|
||||
var reload = '';
|
||||
if(module == 'photos')
|
||||
let reload = 0;
|
||||
|
||||
if (module == 'photos') {
|
||||
reload = 1;
|
||||
}
|
||||
|
||||
$.get('like/' + ident.toString() + '?verb=' + verb + '&conv_mode=' + conv_mode + '&page_mode=' + page_mode + '&reload=' + reload, function (data) {
|
||||
if(data.success) {
|
||||
|
||||
$.get('like/' + ident + '?verb=' + verb + '&conv_mode=' + conv_mode + '&page_mode=' + page_mode + '&reload=' + reload, function (data) {
|
||||
if (data.success) {
|
||||
|
||||
close_modal();
|
||||
|
||||
// mod photos
|
||||
if (data.reload) {
|
||||
@@ -1213,10 +1220,9 @@ function dolike(ident, verb) {
|
||||
$('#wall-item-ago-' + data.id + ' .autotime').timeago();
|
||||
collapseHeight();
|
||||
liking = 0;
|
||||
// remove modal backdrop in case the update was triggered from a modal
|
||||
$('.modal-backdrop').remove();
|
||||
}
|
||||
});
|
||||
|
||||
liking = 1;
|
||||
}
|
||||
|
||||
@@ -1332,26 +1338,28 @@ function dropItem(url, object, b64mid) {
|
||||
}
|
||||
|
||||
function dosubthread(ident) {
|
||||
$('#like-rotator-' + ident.toString()).show();
|
||||
$.get('subthread/sub/' + ident.toString(), updateInit );
|
||||
$('#like-rotator-' + ident).show();
|
||||
$.get('subthread/sub/' + ident, updateInit );
|
||||
liking = 1;
|
||||
}
|
||||
|
||||
function dounsubthread(ident) {
|
||||
$('#like-rotator-' + ident.toString()).show();
|
||||
$.get('subthread/unsub/' + ident.toString(), updateInit );
|
||||
$('#like-rotator-' + ident).show();
|
||||
$.get('subthread/unsub/' + ident, updateInit );
|
||||
liking = 1;
|
||||
}
|
||||
|
||||
function moderate_approve(ident) {
|
||||
$('#like-rotator-' + ident.toString()).show();
|
||||
$.get('moderate/' + ident.toString() + '/approve', updateInit );
|
||||
function moderate_approve(ident, verb) {
|
||||
$('#like-rotator-' + ident).show();
|
||||
close_modal();
|
||||
$.get('moderate/' + ident + '/approve', updateInit );
|
||||
liking = 1;
|
||||
}
|
||||
|
||||
function moderate_drop(ident) {
|
||||
$('#like-rotator-' + ident.toString()).show();
|
||||
$.get('moderate/' + ident.toString() + '/drop', $('#thread-wrapper-' + ident.toString()).fadeOut(function() { this.remove(); }));
|
||||
$('#like-rotator-' + ident).show();
|
||||
close_modal();
|
||||
$.get('moderate/' + ident + '/drop', $('#thread-wrapper-' + ident).fadeOut(function() { this.remove(); }));
|
||||
liking = 1;
|
||||
}
|
||||
|
||||
@@ -1723,3 +1731,11 @@ function toast(string, severity) {
|
||||
|
||||
toastInstance.show();
|
||||
}
|
||||
|
||||
function close_modal() {
|
||||
let modal = bootstrap.Modal.getInstance(document.querySelector('.modal.show'));
|
||||
|
||||
if (modal) {
|
||||
modal.hide();
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1363,12 +1363,16 @@ dl.bb-dl > dd > li {
|
||||
}
|
||||
|
||||
.bootstrap-tagsinput .tag:before {
|
||||
/* Copied from fa-asterisk, is there a better way to do it? */
|
||||
font-family: ForkAwesome;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
text-decoration: inherit;
|
||||
content:"\f069 ";
|
||||
font-family: bootstrap-icons;
|
||||
font-size: 0.5rem;
|
||||
content: "\F151";
|
||||
margin-right: .25rem;
|
||||
}
|
||||
|
||||
.bootstrap-tagsinput .tag [data-role="remove"]:after {
|
||||
font-family: bootstrap-icons;
|
||||
font-size: 0.5rem;
|
||||
content: "\F659";
|
||||
}
|
||||
|
||||
/* Modified original CSS to match input in Redbasic */
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
<form action="admin/account_edit/{{$account.account_id}}" method="post" >
|
||||
<input type="hidden" name="aid" value="{{$account.account_id}}" />
|
||||
<input type="hidden" name="security" value="{{$security}}">
|
||||
|
||||
{{include file="field_password.tpl" field=$pass1}}
|
||||
{{include file="field_password.tpl" field=$pass2}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div id="id_{{$field.0}}_wrapper" class="mb-3">
|
||||
<label for="id_{{$field.0}}" id="label_{{$field.0}}">
|
||||
{{$field.1}}{{if $field.4}}<sup class="required zuiqmid"> {{$field.4}}</sup>{{/if}}
|
||||
{{$field.1}}{{if isset($field.4)}}<sup class="required zuiqmid"> {{$field.4}}</sup>{{/if}}
|
||||
</label>
|
||||
<input
|
||||
class="form-control"
|
||||
@@ -8,7 +8,7 @@
|
||||
id="id_{{$field.0}}"
|
||||
type="text"
|
||||
value="{{$field.2|escape:'html':'UTF-8':FALSE}}"
|
||||
{{if $field.5}}{{$field.5}}{{/if}}
|
||||
{{if isset($field.5)}}{{$field.5}}{{/if}}
|
||||
>
|
||||
<small id="help_{{$field.0}}" class="form-text text-muted">
|
||||
{{$field.3}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="mb-3">
|
||||
<label for="id_{{$field.0}}">{{$field.1}}</label>
|
||||
<input class="form-control" type="password" name="{{$field.0}}" id="id_{{$field.0}}" value="{{$field.2}}"{{if $field.5}} {{$field.5}}{{/if}}>{{if $field.4}} <span class="required">{{$field.4}}</span> {{/if}}
|
||||
<input class="form-control" type="password" name="{{$field.0}}" id="id_{{$field.0}}" value="{{$field.2}}"{{if isset($field.5)}} {{$field.5}}{{/if}}>{{if isset($field.4)}} <span class="required">{{$field.4}}</span> {{/if}}
|
||||
<small id="help_{{$field.0}}" class="form-text text-muted">{{$field.3}}</small>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<div id="id_{{$field.0}}_wrapper" class="mb-3">
|
||||
<label for="id_{{$field.0}}">{{$field.1}}{{if $field.5}}<sup class="required zuiqmid"> {{$field.5}}</sup>{{/if}}</label>
|
||||
<label for="id_{{$field.0}}">{{$field.1}}{{if isset($field.5)}}<sup class="required zuiqmid"> {{$field.5}}</sup>{{/if}}</label>
|
||||
<select class="form-control" name="{{$field.0}}" id="id_{{$field.0}}">
|
||||
{{foreach $field.4 as $opt=>$val}}<option value="{{$opt}}" {{if $opt==$field.2}}selected="selected"{{/if}}>{{$val}}</option>{{/foreach}}
|
||||
</select>
|
||||
<small class="form-text text-muted">{{$field.3}}</small >
|
||||
</div>
|
||||
{{*
|
||||
{{*
|
||||
COMMENTS for this template:
|
||||
@author hilmar runge, 2020.01
|
||||
$field array index:
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
var updateInterval = {{$update_interval}};
|
||||
var sse_enabled = {{$sse_enabled}};
|
||||
var localUser = {{if $local_channel}}{{$local_channel}}{{else}}false{{/if}};
|
||||
var zid = {{if $zid}}'{{$zid}}'{{else}}null{{/if}};
|
||||
var zid = {{if $zid}}'{{$zid|escape:url}}'{{else}}null{{/if}};
|
||||
var justifiedGalleryActive = false;
|
||||
{{if $channel_hash}}var channelHash = '{{$channel_hash}}';{{/if}}
|
||||
var channelId = {{if $channel_id}}{{$channel_id}}{{else}}false{{/if}};{{* Used in e.g. autocomplete *}}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="page-date">{{$date}}</div>
|
||||
<div class="page-body">{{$body}}</div>
|
||||
{{if $edit_link}}
|
||||
<div class="position-fixed bottom-0 end-0 m-3">
|
||||
<div class="position-fixed bottom-0 end-0 m-3 z-1">
|
||||
<a href="{{$edit_link}}" class="btn btn-lg btn-primary rounded-circle"><i class="bi bi-pencil"></i></a>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{{$body}}
|
||||
{{if $edit_link}}
|
||||
<div class="position-fixed bottom-0 end-0 m-3">
|
||||
<a href="{{$edit_link}}" class="btn btn-lg btn-primary rounded-circle"><i class="bi bi-pencil"></i></a>
|
||||
<a href="{{$edit_link}}" class="btn btn-lg btn-primary rounded-circle z-1"><i class="bi bi-pencil"></i></a>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<ul id="saved-search-list" class="nav nav-pills flex-column">
|
||||
{{foreach $saved as $search}}
|
||||
<li class="nav-item nav-item-hack" id="search-term-{{$search.id}}">
|
||||
<a class="nav-link widget-nav-pills-icons" title="{{$search.delete}}" onclick="return confirmDelete();" id="drop-saved-search-term-{{$search.id}}" href="{{$search.dellink}}"><i id="dropfa-floppy-od-search-term-{{$search.id}}" class="bi bi-trash drop-icons" ></i></a>
|
||||
<a class="nav-link widget-nav-pills-icons{{if $search.selected}} active{{/if}}" title="{{$search.delete}}" onclick="return confirmDelete();" id="drop-saved-search-term-{{$search.id}}" href="{{$search.dellink}}"><i class="bi bi-trash"></i></a>
|
||||
<a id="saved-search-term-{{$search.id}}" class="nav-link{{if $search.selected}} active{{/if}}" href="{{$search.srchlink}}">{{$search.displayterm}}</a>
|
||||
</li>
|
||||
{{/foreach}}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<input class="form-control" type="text" name="search" id="search-text" value="{{$s}}" onclick="this.submit();" />
|
||||
<button type="submit" name="submit" class="btn btn-outline-secondary" id="search-submit" value="{{$search_label}}"><i class="bi bi-search"></i></button>
|
||||
{{if $savedsearch}}
|
||||
<button type="submit" name="searchsave" class="btn btn-outline-secondary" id="search-save" value="{{$save_label}}"><i class="bi fa-floppy-o"></i></button>
|
||||
<button type="submit" name="searchsave" class="btn btn-outline-secondary" id="search-save" value="{{$save_label}}"><i class="bi bi-save"></i></button>
|
||||
{{/if}}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user