aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG4
-rw-r--r--Zotlabs/Daemon/Notifier.php2
-rw-r--r--Zotlabs/Lib/Activity.php53
-rw-r--r--Zotlabs/Lib/Apps.php2
-rw-r--r--Zotlabs/Lib/Libzot.php1
-rw-r--r--Zotlabs/Module/Activity.php4
-rw-r--r--Zotlabs/Module/Contactedit.php16
-rw-r--r--Zotlabs/Module/Conversation.php2
-rw-r--r--Zotlabs/Module/Cover_photo.php45
-rw-r--r--Zotlabs/Module/Item.php4
-rw-r--r--Zotlabs/Module/Like.php36
-rw-r--r--Zotlabs/Module/Mood.php163
-rw-r--r--Zotlabs/Module/Photos.php1
-rw-r--r--Zotlabs/Module/Poke.php205
-rw-r--r--Zotlabs/Module/Profile_photo.php3
-rw-r--r--Zotlabs/Module/Profiles.php6
-rw-r--r--Zotlabs/Module/React.php103
-rw-r--r--Zotlabs/Module/Sse_bs.php10
-rw-r--r--Zotlabs/Module/Subthread.php8
-rw-r--r--Zotlabs/Storage/Directory.php18
-rw-r--r--Zotlabs/Update/_1263.php26
-rw-r--r--Zotlabs/Widget/Messages.php4
-rw-r--r--Zotlabs/Widget/Pinned.php20
-rw-r--r--app/mood.apd7
-rw-r--r--app/poke.apd7
-rw-r--r--boot.php31
-rw-r--r--include/activities.php125
-rw-r--r--include/channel.php3
-rw-r--r--include/contact_widgets.php2
-rw-r--r--include/conversation.php129
-rw-r--r--include/dba/dba_transaction.php64
-rw-r--r--include/items.php90
-rw-r--r--include/photo/photo_driver.php9
-rw-r--r--include/taxonomy.php4
-rw-r--r--include/text.php73
-rw-r--r--tests/fakes/fake_dba.php18
-rw-r--r--tests/unit/UnitTestCase.php64
-rw-r--r--tests/unit/includes/dba/TransactionTest.php207
-rw-r--r--view/js/mod_poke.js5
-rw-r--r--view/tpl/mood_content.tpl33
-rw-r--r--view/tpl/poke_content.tpl48
41 files changed, 563 insertions, 1092 deletions
diff --git a/CHANGELOG b/CHANGELOG
index ca7bb5f07..0f3926e26 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,7 @@
+Hubzilla 8.8.8 (2024-02-29)
+ - Streams compatibility fixes
+
+
Hubzilla 8.8.7 (2024-01-19)
- Fix regression in Activity::actor_store()
diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php
index 948aba80c..4e7ca3911 100644
--- a/Zotlabs/Daemon/Notifier.php
+++ b/Zotlabs/Daemon/Notifier.php
@@ -276,7 +276,7 @@ class Notifier {
}
// follow/unfollow is for internal use only
- if (in_array($target_item['verb'], [ACTIVITY_FOLLOW, ACTIVITY_UNFOLLOW])) {
+ if (in_array($target_item['verb'], ['Follow', 'Ignore', ACTIVITY_FOLLOW, ACTIVITY_UNFOLLOW])) {
logger('not fowarding follow/unfollow note activity');
return;
}
diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php
index 844dc5905..1e0ce6ae2 100644
--- a/Zotlabs/Lib/Activity.php
+++ b/Zotlabs/Lib/Activity.php
@@ -172,10 +172,6 @@ class Activity {
}
static function fetch_person($x) {
- return self::fetch_profile($x);
- }
-
- static function fetch_profile($x) {
$r = q("select * from xchan where xchan_url = '%s' limit 1",
dbesc($x['id'])
);
@@ -189,7 +185,14 @@ class Activity {
return [];
return self::encode_person($r[0]);
+ }
+ static function fetch_profile($x) {
+ if (isset($x['describes'])) {
+ return $x;
+ }
+
+ return [];
}
static function fetch_thing($x) {
@@ -448,13 +451,7 @@ class Activity {
$ret = [];
- if ($i['verb'] === ACTIVITY_FRIEND) {
- // Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
- $objtype = 'Note';
- }
- else {
- $objtype = self::activity_obj_mapper($i['obj_type']);
- }
+ $objtype = self::activity_obj_mapper($i['obj_type']);
if (intval($i['item_deleted'])) {
$ret['type'] = 'Tombstone';
@@ -789,11 +786,6 @@ class Activity {
$ret = [];
$reply = false;
- if ($i['verb'] === ACTIVITY_FRIEND) {
- // Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
- $ret['obj'] = [];
- }
-
$ret['type'] = self::activity_mapper($i['verb']);
if ((isset($i['item_deleted']) && intval($i['item_deleted'])) && !$recurse) {
@@ -989,6 +981,7 @@ class Activity {
$ret['to'] = [ACTIVITY_PUBLIC_INBOX];
}
+
$hookinfo = [
'item' => $i,
'encoded' => $ret
@@ -1227,20 +1220,6 @@ class Activity {
return $acts[$verb];
}
- // Reactions will just map to normal activities
-
- if (strpos($verb, ACTIVITY_REACT) !== false)
- return 'Create';
-
- if (strpos($verb, ACTIVITY_MOOD) !== false)
- return 'Create';
-
- if (strpos($verb, ACTIVITY_FRIEND) !== false)
- return 'Create';
-
- if (strpos($verb, ACTIVITY_POKE) !== false)
- return 'Activity';
-
// We should return false, however this will trigger an uncaught execption and crash
// the delivery system if encountered by the JSON-LDSignature library
@@ -2074,6 +2053,10 @@ class Activity {
$s['mid'] = $act->obj['data']['id'];
}
+ if ($act->objprop('type') === 'Profile') {
+ $s['mid'] = $act->id;
+ }
+
if (!$s['mid']) {
return false;
}
@@ -2178,6 +2161,7 @@ class Activity {
$content['content'] = sprintf(t('🔁 Repeated %1$s\'s %2$s'), $mention, $act->obj['type']);
}
+ // TODO: Deprecated
if ($act->type === 'emojiReaction') {
$content['content'] = (($act->tgt && $act->tgt['type'] === 'Image') ? '[img=32x32]' . $act->tgt['url'] . '[/img]' : '&#x' . $act->tgt['name'] . ';');
}
@@ -2317,6 +2301,12 @@ class Activity {
if (!$response_activity) {
+ if ($act->objprop('type') === 'Profile') {
+ $s['parent_mid'] = $s['mid'];
+ $s['item_thread_top'] = 1;
+ }
+
+
// we will need a hook here to extract magnet links e.g. peertube
// right now just link to the largest mp4 we find that will fit in our
// standard content region
@@ -2462,7 +2452,6 @@ class Activity {
}
}
-
if ($act->objprop('type') === 'Page' && !$s['body']) {
$ptr = null;
@@ -2503,7 +2492,7 @@ class Activity {
}
}
- if (in_array($act->objprop('type', ''), ['Note', 'Article', 'Page'])) {
+ if (in_array($act->objprop('type'), ['Note', 'Article', 'Page'])) {
$ptr = null;
if (array_key_exists('url', $act->obj)) {
diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php
index 00e65479e..1c05d69b1 100644
--- a/Zotlabs/Lib/Apps.php
+++ b/Zotlabs/Lib/Apps.php
@@ -352,8 +352,6 @@ class Apps {
'Directory' => t('Directory'),
'Help' => t('Help'),
'Mail' => t('Mail'),
- 'Mood' => t('Mood'),
- 'Poke' => t('Poke'),
'Chat' => t('Chat'),
'Search' => t('Search'),
'Probe' => t('Probe'),
diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php
index a98ae8f20..942c3082a 100644
--- a/Zotlabs/Lib/Libzot.php
+++ b/Zotlabs/Lib/Libzot.php
@@ -1143,7 +1143,6 @@ class Libzot {
if ($env['encoding'] === 'activitystreams') {
$AS = new ActivityStreams($data);
-
if (!$AS->is_valid()) {
logger('Activity rejected: ' . print_r($data, true));
return;
diff --git a/Zotlabs/Module/Activity.php b/Zotlabs/Module/Activity.php
index b2f0ce498..133312e28 100644
--- a/Zotlabs/Module/Activity.php
+++ b/Zotlabs/Module/Activity.php
@@ -25,7 +25,7 @@ class Activity extends Controller {
$portable_id = EMPTY_STR;
- $item_normal_extra = sprintf(" and not verb in ('%s', '%s') ",
+ $item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
dbesc(ACTIVITY_FOLLOW),
dbesc(ACTIVITY_UNFOLLOW)
);
@@ -186,7 +186,7 @@ class Activity extends Controller {
}
}
- $item_normal_extra = sprintf(" and not verb in ('%s', '%s') ",
+ $item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
dbesc(ACTIVITY_FOLLOW),
dbesc(ACTIVITY_UNFOLLOW)
);
diff --git a/Zotlabs/Module/Contactedit.php b/Zotlabs/Module/Contactedit.php
index e20e90872..3527e9380 100644
--- a/Zotlabs/Module/Contactedit.php
+++ b/Zotlabs/Module/Contactedit.php
@@ -177,22 +177,8 @@ class Contactedit extends Controller {
intval($channel['channel_id'])
);
if (($pr) && (!intval($contact['abook_hidden'])) && (intval(get_pconfig($channel['channel_id'], 'system', 'post_newfriend')))) {
- $xarr = [];
-
- $xarr['item_wall'] = 1;
- $xarr['item_origin'] = 1;
- $xarr['item_thread_top'] = 1;
- $xarr['owner_xchan'] = $xarr['author_xchan'] = $channel['channel_hash'];
- $xarr['allow_cid'] = $channel['channel_allow_cid'];
- $xarr['allow_gid'] = $channel['channel_allow_gid'];
- $xarr['deny_cid'] = $channel['channel_deny_cid'];
- $xarr['deny_gid'] = $channel['channel_deny_gid'];
- $xarr['item_private'] = (($xarr['allow_cid'] || $xarr['allow_gid'] || $xarr['deny_cid'] || $xarr['deny_gid']) ? 1 : 0);
-
$xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . $contact['xchan_url'] . ']' . $contact['xchan_name'] . '[/zrl]';
-
- $xarr['body'] .= "\n\n\n" . '[zrl=' . $contact['xchan_url'] . '][zmg=80x80]' . $contact['xchan_photo_m'] . '[/zmg][/zrl]';
-
+ $xarr['body'] .= "\n\n\n" . '[zrl=' . $contact['xchan_url'] . '][zmg=' . $contact['xchan_photo_m'] . ']' . $contact['xchan_name'] . '[/zmg][/zrl]';
post_activity_item($xarr);
}
diff --git a/Zotlabs/Module/Conversation.php b/Zotlabs/Module/Conversation.php
index 86ce66caa..aa8349f55 100644
--- a/Zotlabs/Module/Conversation.php
+++ b/Zotlabs/Module/Conversation.php
@@ -25,7 +25,7 @@ class Conversation extends Controller {
$portable_id = EMPTY_STR;
- $item_normal_extra = sprintf(" and not verb in ('%s', '%s') ",
+ $item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
dbesc(ACTIVITY_FOLLOW),
dbesc(ACTIVITY_UNFOLLOW)
);
diff --git a/Zotlabs/Module/Cover_photo.php b/Zotlabs/Module/Cover_photo.php
index 1ecbfce3e..f4f9480c0 100644
--- a/Zotlabs/Module/Cover_photo.php
+++ b/Zotlabs/Module/Cover_photo.php
@@ -93,8 +93,6 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$image_id = substr($image_id,0,-2);
}
-
-
$srcX = intval($_POST['xstart']);
$srcY = intval($_POST['ystart']);
$srcW = intval($_POST['xfinal']) - $srcX;
@@ -228,7 +226,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
return;
}
- $this->send_cover_photo_activity($channel,$base_image,$profile);
+ profile_activity([t('Cover Photo')], $base_image['resource_id']);
$sync = attach_export_data($channel,$base_image['resource_id']);
if($sync)
@@ -245,7 +243,6 @@ class Cover_photo extends \Zotlabs\Web\Controller {
}
-
$hash = photo_new_resource();
$smallest = 0;
@@ -287,45 +284,6 @@ class Cover_photo extends \Zotlabs\Web\Controller {
}
- function send_cover_photo_activity($channel,$photo,$profile) {
-
- $arr = array();
- $arr['item_thread_top'] = 1;
- $arr['item_origin'] = 1;
- $arr['item_wall'] = 1;
-
- if($profile && stripos($profile['gender'],t('female')) !== false)
- $t = t('%1$s updated her %2$s');
- elseif($profile && stripos($profile['gender'],t('male')) !== false)
- $t = t('%1$s updated his %2$s');
- else
- $t = t('%1$s updated their %2$s');
-
- $ptext = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo['resource_id'] . ']' . t('cover photo') . '[/zrl]';
-
- $ltext = '[zrl=' . z_root() . '/profile/' . $channel['channel_address'] . ']' . '[zmg]' . z_root() . '/photo/' . $photo['resource_id'] . '-8[/zmg][/zrl]';
-
- $arr['body'] = sprintf($t,$channel['channel_name'],$ptext) . "\n\n" . $ltext;
-
- $acl = new \Zotlabs\Access\AccessList($channel);
- $x = $acl->get();
- $arr['allow_cid'] = $x['allow_cid'];
-
- $arr['allow_gid'] = $x['allow_gid'];
- $arr['deny_cid'] = $x['deny_cid'];
- $arr['deny_gid'] = $x['deny_gid'];
-
- $arr['uid'] = $channel['channel_id'];
- $arr['aid'] = $channel['channel_account_id'];
-
- $arr['owner_xchan'] = $channel['channel_hash'];
- $arr['author_xchan'] = $channel['channel_hash'];
-
- post_activity_item($arr);
-
-
- }
-
/**
* @brief Generate content of profile-photo view
@@ -334,7 +292,6 @@ class Cover_photo extends \Zotlabs\Web\Controller {
*
*/
-
function get() {
if(! local_channel()) {
diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php
index 7d71edc99..9c967cb88 100644
--- a/Zotlabs/Module/Item.php
+++ b/Zotlabs/Module/Item.php
@@ -52,7 +52,7 @@ class Item extends Controller {
$portable_id = EMPTY_STR;
- $item_normal_extra = sprintf(" and not verb in ('%s', '%s') ",
+ $item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
dbesc(ACTIVITY_FOLLOW),
dbesc(ACTIVITY_UNFOLLOW)
);
@@ -168,7 +168,7 @@ class Item extends Controller {
$portable_id = EMPTY_STR;
- $item_normal_extra = sprintf(" and not verb in ('%s', '%s') ",
+ $item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
dbesc(ACTIVITY_FOLLOW),
dbesc(ACTIVITY_UNFOLLOW)
);
diff --git a/Zotlabs/Module/Like.php b/Zotlabs/Module/Like.php
index e19a74a23..86ae48365 100644
--- a/Zotlabs/Module/Like.php
+++ b/Zotlabs/Module/Like.php
@@ -22,9 +22,6 @@ class Like extends Controller {
'like' => 'Like',
'dislike' => 'Dislike',
'announce' => ACTIVITY_SHARE,
- 'agree' => ACTIVITY_AGREE,
- 'disagree' => ACTIVITY_DISAGREE,
- 'abstain' => ACTIVITY_ABSTAIN,
'attendyes' => 'Accept',
'attendno' => 'Reject',
'attendmaybe' => 'TentativeAccept'
@@ -325,6 +322,8 @@ class Like extends Controller {
// parent, copy that as well.
if ($r) {
+ $obj_type = $r[0]['obj_type'];
+
if ($r[0]['uid'] === $sys_channel['channel_id'] && local_channel()) {
$r = [copy_of_pubitem(App::get_channel(), $r[0]['mid'])];
}
@@ -372,17 +371,13 @@ class Like extends Controller {
$multi_undo = false;
- // event participation and consensus items are essentially radio toggles. If you make a subsequent choice,
+ // event participation items are essentially radio toggles. If you make a subsequent choice,
// we need to eradicate your first choice.
if (in_array($activity, ['Accept', 'Reject', 'TentativeAccept', ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE])) {
$verbs = "'Accept','Reject','TentativeAccept','" . dbesc(ACTIVITY_ATTEND) . "','" . dbesc(ACTIVITY_ATTENDNO) . "','" . dbesc(ACTIVITY_ATTENDMAYBE) . "' ";
$multi_undo = true;
}
- if ($activity === ACTIVITY_AGREE || $activity === ACTIVITY_DISAGREE || $activity === ACTIVITY_ABSTAIN) {
- $verbs = " '" . dbesc(ACTIVITY_AGREE) . "','" . dbesc(ACTIVITY_DISAGREE) . "','" . dbesc(ACTIVITY_ABSTAIN) . "' ";
- $multi_undo = true;
- }
$item_normal = item_normal();
@@ -439,7 +434,7 @@ class Like extends Controller {
}
}
- $uuid = item_message_id();
+ $uuid = new_uuid();
$arr = array();
@@ -452,17 +447,17 @@ class Like extends Controller {
$arr['item_wall'] = 1;
}
else {
- switch ($item['resource_type']) {
- case 'photo':
- $obj_type = 'Image';
- $post_type = t('photo');
+ switch ($item['object_type']) {
+ case 'Image':
+ $post_type = t('image');
break;
- case 'event':
- $obj_type = 'Invite';
+ case 'Invite':
$post_type = t('event');
break;
+ case 'Profile':
+ $post_type = t('profile');
+ break;
default:
- $obj_type = 'Note';
$post_type = t('status');
break;
}
@@ -493,12 +488,6 @@ class Like extends Controller {
$bodyverb = t('%1$s likes %2$s\'s %3$s');
if ($verb === 'dislike')
$bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s');
- if ($verb === 'agree')
- $bodyverb = t('%1$s agrees with %2$s\'s %3$s');
- if ($verb === 'disagree')
- $bodyverb = t('%1$s doesn\'t agree with %2$s\'s %3$s');
- if ($verb === 'abstain')
- $bodyverb = t('%1$s abstains from a decision on %2$s\'s %3$s');
if ($verb === 'attendyes')
$bodyverb = t('%1$s is attending %2$s\'s %3$s');
if ($verb === 'attendno')
@@ -540,7 +529,7 @@ class Like extends Controller {
if ($obj_type === 'thing' && $r[0]['imgurl']) {
$arr['body'] .= "\n\n[zmg=80x80]" . $r[0]['imgurl'] . '[/zmg]';
}
- if ($obj_type === 'profile') {
+ if ($obj_type === 'Profile') {
if ($public) {
$arr['body'] .= "\n\n" . '[embed]' . z_root() . '/profile/' . $ch[0]['channel_address'] . '[/embed]';
}
@@ -594,6 +583,7 @@ class Like extends Controller {
Libsync::build_sync_packet($profile_uid, ['item' => [encode_item($sync_item[0], true)]]);
}
+
if ($extended_like) {
$r = q("insert into likes (channel_id,liker,likee,iid,i_mid,verb,target_type,target_id,target) values (%d,'%s','%s',%d,'%s','%s','%s','%s','%s')",
intval($ch[0]['channel_id']),
diff --git a/Zotlabs/Module/Mood.php b/Zotlabs/Module/Mood.php
deleted file mode 100644
index edd3f0e1a..000000000
--- a/Zotlabs/Module/Mood.php
+++ /dev/null
@@ -1,163 +0,0 @@
-<?php
-namespace Zotlabs\Module;
-
-use App;
-use Zotlabs\Lib\Apps;
-use Zotlabs\Web\Controller;
-
-require_once('include/security.php');
-require_once('include/bbcode.php');
-require_once('include/items.php');
-
-
-
-class Mood extends Controller {
-
- function init() {
-
- if(! local_channel())
- return;
-
- if(! Apps::system_app_installed(local_channel(), 'Mood')) {
- return;
- }
-
- $uid = local_channel();
- $channel = App::get_channel();
- $verb = ((isset($_GET['verb'])) ? notags(trim($_GET['verb'])) : '');
-
- if(! $verb)
- return;
-
- $verbs = get_mood_verbs();
-
- if(! array_key_exists($verb,$verbs))
- return;
-
- $activity = ACTIVITY_MOOD . '#' . urlencode($verb);
-
- $parent = ((x($_GET,'parent')) ? intval($_GET['parent']) : 0);
-
-
- logger('mood: verb ' . $verb, LOGGER_DEBUG);
-
-
- if($parent) {
- $r = q("select mid, owner_xchan, private, allow_cid, allow_gid, deny_cid, deny_gid
- from item where id = %d and parent = %d and uid = %d limit 1",
- intval($parent),
- intval($parent),
- intval($uid)
- );
- if(count($r)) {
- $parent_mid = $r[0]['mid'];
- $private = $r[0]['item_private'];
- $allow_cid = $r[0]['allow_cid'];
- $allow_gid = $r[0]['allow_gid'];
- $deny_cid = $r[0]['deny_cid'];
- $deny_gid = $r[0]['deny_gid'];
- }
- }
- else {
-
- $private = 0;
-
- $allow_cid = $channel['channel_allow_cid'];
- $allow_gid = $channel['channel_allow_gid'];
- $deny_cid = $channel['channel_deny_cid'];
- $deny_gid = $channel['channel_deny_gid'];
- }
-
- $poster = App::get_observer();
-
- $uuid = item_message_id();
- $mid = z_root() . '/item/' . $uuid;
-
- $action = sprintf( t('%1$s is %2$s','mood'), '[zrl=' . $poster['xchan_url'] . ']' . $poster['xchan_name'] . '[/zrl]' , $verbs[$verb]);
-
- $arr = array();
-
- $arr['aid'] = get_account_id();
- $arr['uid'] = $uid;
- $arr['uuid'] = $uuid;
- $arr['mid'] = $mid;
- $arr['parent_mid'] = (($parent_mid) ? $parent_mid : $mid);
- $arr['author_xchan'] = $poster['xchan_hash'];
- $arr['owner_xchan'] = (($parent_mid) ? $r[0]['owner_xchan'] : $poster['xchan_hash']);
- $arr['title'] = '';
- $arr['allow_cid'] = $allow_cid;
- $arr['allow_gid'] = $allow_gid;
- $arr['deny_cid'] = $deny_cid;
- $arr['deny_gid'] = $deny_gid;
- $arr['item_private'] = $private;
- $arr['verb'] = $activity;
- $arr['body'] = $action;
- $arr['item_origin'] = 1;
- $arr['item_wall'] = 1;
- $arr['item_unseen'] = 1;
- if(! $parent_mid)
- $item['item_thread_top'] = 1;
-
- if ((! $arr['plink']) && intval($arr['item_thread_top'])) {
- $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']);
- }
-
-
- $post = item_store($arr);
- $item_id = $post['item_id'];
-
- if($item_id) {
- \Zotlabs\Daemon\Master::Summon(array('Notifier','activity', $item_id));
- }
-
- call_hooks('post_local_end', $arr);
-
- if($_SESSION['return_url'])
- goaway(z_root() . '/' . $_SESSION['return_url']);
-
- return;
- }
-
-
-
- function get() {
-
- if(! local_channel()) {
- notice( t('Permission denied.') . EOL);
- return;
- }
-
- if(! Apps::system_app_installed(local_channel(), 'Mood')) {
- //Do not display any associated widgets at this point
- App::$pdl = '';
- $papp = Apps::get_papp('Mood');
- return Apps::app_render($papp, 'module');
- }
-
- nav_set_selected('Mood');
-
- $parent = ((x($_GET,'parent')) ? intval($_GET['parent']) : '0');
-
- $verbs = get_mood_verbs();
-
- $shortlist = array();
- foreach($verbs as $k => $v)
- if($v !== 'NOTRANSLATION')
- $shortlist[] = array($k,$v);
-
-
- $tpl = get_markup_template('mood_content.tpl');
-
- $o = replace_macros($tpl,array(
- '$title' => t('Mood'),
- '$desc' => t('Set your current mood and tell your friends'),
- '$verbs' => $shortlist,
- '$parent' => $parent,
- '$submit' => t('Submit'),
- ));
-
- return $o;
-
- }
-
-}
diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php
index 0a490d1db..870a2cb79 100644
--- a/Zotlabs/Module/Photos.php
+++ b/Zotlabs/Module/Photos.php
@@ -1108,7 +1108,6 @@ class Photos extends \Zotlabs\Web\Controller {
$conv_responses = array(
'like' => array('title' => t('Likes','title')),'dislike' => array('title' => t('Dislikes','title')),
- 'agree' => array('title' => t('Agree','title')),'disagree' => array('title' => t('Disagree','title')), 'abstain' => array('title' => t('Abstain','title')),
'attendyes' => array('title' => t('Attending','title')), 'attendno' => array('title' => t('Not attending','title')), 'attendmaybe' => array('title' => t('Might attend','title'))
);
diff --git a/Zotlabs/Module/Poke.php b/Zotlabs/Module/Poke.php
deleted file mode 100644
index ee355f2a9..000000000
--- a/Zotlabs/Module/Poke.php
+++ /dev/null
@@ -1,205 +0,0 @@
-<?php
-namespace Zotlabs\Module; /** @file */
-
-use App;
-use Zotlabs\Lib\Apps;
-use Zotlabs\Lib\Activity;
-use Zotlabs\Web\Controller;
-
-/**
- *
- * Poke, prod, finger, or otherwise do unspeakable things to somebody - who must be a connection in your address book
- * This function can be invoked with the required arguments (verb and cid and private and possibly parent) silently via ajax or
- * other web request. You must be logged in and connected to a channel.
- * If the required arguments aren't present, we'll display a simple form to choose a recipient and a verb.
- * parent is a special argument which let's you attach this activity as a comment to an existing conversation, which
- * may have started with somebody else poking (etc.) somebody, but this isn't necessary. This can be used in the adult
- * plugin version to have entire conversations where Alice poked Bob, Bob fingered Alice, Alice hugged Bob, etc.
- *
- * private creates a private conversation with the recipient. Otherwise your channel's default post privacy is used.
- *
- */
-
-require_once('include/items.php');
-
-
-class Poke extends Controller {
-
- function init() {
-
- if(! local_channel())
- return;
-
- if(! Apps::system_app_installed(local_channel(), 'Poke')) {
- return;
- }
-
- $uid = local_channel();
- $channel = App::get_channel();
-
- $verb = ((isset($_GET['verb'])) ? notags(trim($_GET['verb'])) : '');
-
- if(! $verb)
- return;
-
- $verbs = get_poke_verbs();
-
- if(! array_key_exists($verb,$verbs))
- return;
-
- $contact_id = intval($_REQUEST['cid']);
-
- $xchan = trim($_REQUEST['xchan']);
-
- if(! ($contact_id || $xchan))
- return;
-
- $parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : 0);
-
- logger('poke: verb ' . $verb . ' contact ' . $contact_id, LOGGER_DEBUG);
-
-
- if($contact_id) {
- $r = q("SELECT * FROM abook left join xchan on xchan_hash = abook_xchan where abook_id = %d and abook_channel = %d LIMIT 1",
- intval($contact_id),
- intval($uid)
- );
- }
- if($xchan) {
- $r = q("SELECT * FROM xchan where xchan_hash like ( '%s' ) LIMIT 1",
- dbesc($xchan . '%')
- );
- }
-
- if(! $r) {
- logger('poke: no target.');
- return;
- }
-
- $target = $r[0];
- $parent_item = null;
-
- if($parent) {
- $r = q("select mid, item_private, owner_xchan, allow_cid, allow_gid, deny_cid, deny_gid
- from item where id = %d and parent = %d and uid = %d limit 1",
- intval($parent),
- intval($parent),
- intval($uid)
- );
- if($r) {
- $parent_item = $r[0];
- $parent_mid = $r[0]['mid'];
- $item_private = $r[0]['item_private'];
- $allow_cid = $r[0]['allow_cid'];
- $allow_gid = $r[0]['allow_gid'];
- $deny_cid = $r[0]['deny_cid'];
- $deny_gid = $r[0]['deny_gid'];
- }
- }
- elseif($contact_id) {
-
- $item_private = ((x($_GET,'private')) ? intval($_GET['private']) : 0);
-
- $allow_cid = (($item_private) ? '<' . $target['abook_xchan']. '>' : $channel['channel_allow_cid']);
- $allow_gid = (($item_private) ? '' : $channel['channel_allow_gid']);
- $deny_cid = (($item_private) ? '' : $channel['channel_deny_cid']);
- $deny_gid = (($item_private) ? '' : $channel['channel_deny_gid']);
- }
-
- $arr['item_wall'] = 1;
- $arr['owner_xchan'] = (($parent_item) ? $parent_item['owner_xchan'] : $channel['channel_hash']);
- $arr['parent_mid'] = (($parent_mid) ? $parent_mid : '');
- $arr['title'] = '';
- $arr['allow_cid'] = $allow_cid;
- $arr['allow_gid'] = $allow_gid;
- $arr['deny_cid'] = $deny_cid;
- $arr['deny_gid'] = $deny_gid;
- $arr['verb'] = 'Create';
- $arr['item_private'] = $item_private;
- $arr['obj_type'] = 'Note';
- $arr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t($verbs[$verb][0]) . ' ' . '[zrl=' . $target['xchan_url'] . ']' . $target['xchan_name'] . '[/zrl]';
- $arr['item_origin'] = 1;
- $arr['item_unseen'] = 1;
- if(! $parent_item)
- $arr['item_thread_top'] = 1;
-
- $arr['obj'] = Activity::encode_item($arr);
-
-
- post_activity_item($arr);
-
- return;
- }
-
-
-
- function get() {
-
- if(! local_channel()) {
- notice( t('Permission denied.') . EOL);
- return;
- }
-
- if(! Apps::system_app_installed(local_channel(), 'Poke')) {
- //Do not display any associated widgets at this point
- App::$pdl = '';
- $papp = Apps::get_papp('Poke');
- return Apps::app_render($papp, 'module');
- }
-
- nav_set_selected('Poke');
-
- $name = '';
- $id = '';
-
- if(isset($_REQUEST['c']) && intval($_REQUEST['c'])) {
- $r = q("select abook_id, xchan_name from abook left join xchan on abook_xchan = xchan_hash
- where abook_id = %d and abook_channel = %d limit 1",
- intval($_REQUEST['c']),
- intval(local_channel())
- );
- if($r) {
- $name = $r[0]['xchan_name'];
- $id = $r[0]['abook_id'];
- }
- }
-
- $parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : '0');
-
- $verbs = get_poke_verbs();
-
- $shortlist = array();
- foreach($verbs as $k => $v)
- if($v[1] !== 'NOTRANSLATION')
- $shortlist[] = array($k,$v[1]);
-
-
- $poke_basic = get_config('system','poke_basic');
- if($poke_basic) {
- $title = t('Poke');
- $desc = t('Poke somebody');
- }
- else {
- $title = t('Poke');
- $desc = t('Poke or ping somebody');
- }
-
- $o = replace_macros(get_markup_template('poke_content.tpl'),array(
- '$title' => $title,
- '$poke_basic' => $poke_basic,
- '$desc' => $desc,
- '$clabel' => t('Recipient'),
- '$choice' => t('Choose action'),
- '$verbs' => $shortlist,
- '$parent' => $parent,
- '$prv_desc' => t('Make this post private'),
- '$private' => array('private', t('Make this post private'), false, ''),
- '$submit' => t('Submit'),
- '$name' => $name,
- '$id' => $id
- ));
-
- return $o;
-
- }
-}
diff --git a/Zotlabs/Module/Profile_photo.php b/Zotlabs/Module/Profile_photo.php
index d7e2bbce1..dc47d213b 100644
--- a/Zotlabs/Module/Profile_photo.php
+++ b/Zotlabs/Module/Profile_photo.php
@@ -223,7 +223,7 @@ class Profile_photo extends Controller {
intval(local_channel())
);
- send_profile_photo_activity($channel, $base_image, $profile);
+ profile_activity([t('Profile Photo')], $base_image['resource_id']);
}
else {
q("update profile set photo = '%s', thumb = '%s' where id = %d and uid = %d",
@@ -269,7 +269,6 @@ class Profile_photo extends Controller {
// Update directory in background
Master::Summon(['Directory', $channel['channel_id']]);
-
}
else
notice(t('Unable to process image') . EOL);
diff --git a/Zotlabs/Module/Profiles.php b/Zotlabs/Module/Profiles.php
index ce496252b..15252d6e6 100644
--- a/Zotlabs/Module/Profiles.php
+++ b/Zotlabs/Module/Profiles.php
@@ -3,10 +3,6 @@ namespace Zotlabs\Module;
use Zotlabs\Lib\Libsync;
-require_once('include/channel.php');
-require_once('include/selectors.php');
-
-
class Profiles extends \Zotlabs\Web\Controller {
function init() {
@@ -492,7 +488,7 @@ class Profiles extends \Zotlabs\Web\Controller {
$publish = ((x($_POST, 'profile_in_directory') && (intval($_POST['profile_in_directory']) == 1)) ? 1 : 0);
- profile_activity($changes,$value);
+ profile_activity($changes, $value);
}
diff --git a/Zotlabs/Module/React.php b/Zotlabs/Module/React.php
index f80b04a3f..6a3b525b2 100644
--- a/Zotlabs/Module/React.php
+++ b/Zotlabs/Module/React.php
@@ -2,82 +2,79 @@
namespace Zotlabs\Module;
+use App;
+use Zotlabs\Web\Controller;
+use Zotlabs\Lib\Activity;
+use Zotlabs\Daemon\Master;
-class React extends \Zotlabs\Web\Controller {
+class React extends Controller {
function get() {
- if(! local_channel())
+ if (!local_channel()) {
return;
+ }
$sys = get_sys_channel();
- $channel = \App::get_channel();
+ $channel = App::get_channel();
$postid = $_REQUEST['postid'];
- if(! $postid)
+ if (!$postid) {
return;
+ }
$emoji = $_REQUEST['emoji'];
+ if (!$emoji) {
+ return;
+ }
- if($_REQUEST['emoji']) {
+ $i = q("select * from item where id = %d and uid = %d",
+ intval($postid),
+ intval(local_channel())
+ );
+ if (!$i) {
$i = q("select * from item where id = %d and uid = %d",
intval($postid),
- intval(local_channel())
+ intval($sys['channel_id'])
);
- if(! $i) {
- $i = q("select * from item where id = %d and uid = %d",
- intval($postid),
- intval($sys['channel_id'])
- );
-
- if($i) {
- $i = [ copy_of_pubitem($channel, $i[0]['mid']) ];
- $postid = (($i) ? $i[0]['id'] : 0);
- }
- }
-
- if(! $i) {
- return;
- }
-
- $uuid = item_message_id();
-
- $n = array();
- $n['aid'] = $channel['channel_account_id'];
- $n['uid'] = $channel['channel_id'];
- $n['item_origin'] = true;
- $n['item_type'] = $i[0]['item_type'];
- $n['parent'] = $postid;
- $n['parent_mid'] = $i[0]['mid'];
- $n['uuid'] = $uuid;
- $n['mid'] = z_root() . '/item/' . $uuid;
- $n['verb'] = ACTIVITY_REACT . '#' . $emoji;
- $n['body'] = "\n\n[zmg=32x32]" . z_root() . '/images/emoji/' . $emoji . '.png[/zmg]' . "\n\n";
- $n['author_xchan'] = $channel['channel_hash'];
-
- $n['tgt_type'] = 'Image';
- $n['target'] = [
- 'type' => 'Image',
- 'name' => $emoji,
- 'url' => z_root() . '/images/emoji/' . $emoji . '.png'
- ];
-
-
- $x = item_store($n);
-
- retain_item($postid);
-
- if($x['success']) {
- $nid = $x['item_id'];
- \Zotlabs\Daemon\Master::Summon(array('Notifier','like',$nid));
+ if ($i) {
+ $i = [ copy_of_pubitem($channel, $i[0]['mid']) ];
+ $postid = (($i) ? $i[0]['id'] : 0);
}
+ }
+ if (!$i) {
+ return;
}
+ $uuid = item_message_id();
+
+ $n['aid'] = $channel['channel_account_id'];
+ $n['uid'] = $channel['channel_id'];
+ $n['item_origin'] = true;
+ $n['item_type'] = $i[0]['item_type'];
+ $n['parent'] = $postid;
+ $n['parent_mid'] = $i[0]['mid'];
+ $n['uuid'] = $uuid;
+ $n['mid'] = z_root() . '/item/' . $uuid;
+ $n['verb'] = 'Create';
+ $n['body'] = '[zmg=32x32]' . z_root() . '/images/emoji/' . $emoji . '.png[/zmg]';
+ $n['author_xchan'] = $channel['channel_hash'];
+ $n['obj'] = Activity::fetch_item(['id' => $item['mid']]);
+ $n['obj_type'] = ((array_path_exists('obj/type', $n)) ? $n['obj']['type'] : EMPTY_STR);
+
+ $x = item_store($n);
+
+ retain_item($postid);
+
+ if ($x['success']) {
+ $nid = $x['item_id'];
+ Master::Summon(['Notifier', 'like', $nid]);
+ }
}
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Module/Sse_bs.php b/Zotlabs/Module/Sse_bs.php
index a621f3608..71fc16aae 100644
--- a/Zotlabs/Module/Sse_bs.php
+++ b/Zotlabs/Module/Sse_bs.php
@@ -194,7 +194,7 @@ class Sse_bs extends Controller {
$item_normal = item_normal();
// Filter internal follow activities and strerams add/remove activities
- $item_normal .= " AND verb NOT IN ('Add', 'Remove', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
+ $item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
if ($notifications) {
$items = q("SELECT * FROM item
@@ -277,7 +277,7 @@ class Sse_bs extends Controller {
$item_normal = item_normal();
// Filter internal follow activities and strerams add/remove activities
- $item_normal .= " AND verb NOT IN ('Add', 'Remove', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
+ $item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
if ($notifications) {
$items = q("SELECT * FROM item
@@ -360,7 +360,7 @@ class Sse_bs extends Controller {
$item_normal = item_normal();
// Filter internal follow activities and strerams add/remove activities
- $item_normal .= " AND verb NOT IN ('Add', 'Remove', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
+ $item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
if ($notifications) {
$items = q("SELECT * FROM item
@@ -467,7 +467,7 @@ class Sse_bs extends Controller {
$item_normal = item_normal();
// Filter internal follow activities and strerams add/remove activities
- $item_normal .= " AND verb NOT IN ('Add', 'Remove', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
+ $item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
if ($notifications) {
$items = q("SELECT * FROM item
@@ -663,7 +663,7 @@ class Sse_bs extends Controller {
$item_normal = item_normal();
// Filter internal follow activities and strerams add/remove activities
- $item_normal .= " AND verb NOT IN ('Add', 'Remove', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
+ $item_normal .= " AND verb NOT IN ('Add', 'Remove', 'Follow', 'Ignore', '" . dbesc(ACTIVITY_FOLLOW) . "') ";
$r = q("SELECT * FROM item
WHERE (verb = 'Create' OR verb = '%s')
diff --git a/Zotlabs/Module/Subthread.php b/Zotlabs/Module/Subthread.php
index 5ddcaffc6..b927ee480 100644
--- a/Zotlabs/Module/Subthread.php
+++ b/Zotlabs/Module/Subthread.php
@@ -24,9 +24,9 @@ class Subthread extends \Zotlabs\Web\Controller {
$item_id = ((argc() > 2) ? notags(trim(argv(2))) : 0);
if(argv(1) === 'sub')
- $activity = ACTIVITY_FOLLOW;
+ $activity = 'Follow';
elseif(argv(1) === 'unsub')
- $activity = ACTIVITY_UNFOLLOW;
+ $activity = 'Ignore';
$i = q("select * from item where id = %d and uid = %d",
@@ -121,9 +121,9 @@ class Subthread extends \Zotlabs\Web\Controller {
if(! intval($item['item_thread_top']))
$post_type = 'comment';
- if($activity === ACTIVITY_FOLLOW)
+ if($activity === 'Follow')
$bodyverb = t('%1$s is following %2$s\'s %3$s');
- if($activity === ACTIVITY_UNFOLLOW)
+ if($activity === 'Ignore')
$bodyverb = t('%1$s stopped following %2$s\'s %3$s');
$arr = array();
diff --git a/Zotlabs/Storage/Directory.php b/Zotlabs/Storage/Directory.php
index 683887b31..333251f69 100644
--- a/Zotlabs/Storage/Directory.php
+++ b/Zotlabs/Storage/Directory.php
@@ -173,7 +173,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
intval($this->auth->owner_id)
);
- $x = attach_syspaths($this->auth->owner_id,$this->folder_hash);
+ $x = attach_syspaths($this->auth->owner_id, $this->folder_hash);
$y = q("update attach set display_path = '%s' where hash = '%s' and uid = %d",
dbesc($x['path']),
@@ -181,6 +181,20 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
intval($this->auth->owner_id)
);
+ $z = q("select hash from attach where folder = '%s' and uid = %d",
+ dbesc($this->folder_hash),
+ intval($this->auth->owner_id)
+ );
+
+ if($z) {
+ foreach ($z as $zz) {
+ $rs = attach_move($this->auth->owner_id, $zz['hash'], $this->folder_hash, '', false);
+ if(!$rs['success']) {
+ break;
+ }
+ }
+ }
+
$ch = channelx_by_n($this->auth->owner_id);
if ($ch) {
$sync = attach_export_data($ch, $this->folder_hash);
@@ -481,7 +495,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
}
- public function moveInto($targetName,$sourcePath, DAV\INode $sourceNode) {
+ public function moveInto($targetName, $sourcePath, DAV\INode $sourceNode) {
$channel_id = $this->auth->owner_id;
// Files have $sourceNode->data['hash'] set. For directories rely on $sourceNode->folder_hash.
diff --git a/Zotlabs/Update/_1263.php b/Zotlabs/Update/_1263.php
new file mode 100644
index 000000000..bd12e7321
--- /dev/null
+++ b/Zotlabs/Update/_1263.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Zotlabs\Update;
+
+class _1263 {
+
+ function run() {
+
+ dbq("START TRANSACTION");
+
+ $poke = hash('whirlpool', 'Poke');
+ $mood = hash('whirlpool', 'Mood');
+
+ $r = dbq("DELETE FROM app WHERE (app_id = '$poke' OR app_id = '$mood') AND app_system = 1");
+
+ if($r) {
+ dbq("COMMIT");
+ return UPDATE_SUCCESS;
+ }
+
+ dbq("ROLLBACK");
+ return UPDATE_FAILED;
+
+ }
+
+}
diff --git a/Zotlabs/Widget/Messages.php b/Zotlabs/Widget/Messages.php
index 519bb27fe..8654d8e8f 100644
--- a/Zotlabs/Widget/Messages.php
+++ b/Zotlabs/Widget/Messages.php
@@ -62,7 +62,7 @@ class Messages {
$channel = App::get_channel();
$item_normal = item_normal();
// Filter internal follow activities and strerams add/remove activities
- $item_normal .= " and item.verb not in ('Add', 'Remove', '" . ACTIVITY_FOLLOW . "') ";
+ $item_normal .= " and item.verb not in ('Add', 'Remove', 'Follow', 'Ignore', '" . ACTIVITY_FOLLOW . "') ";
$item_normal_i = str_replace('item.', 'i.', $item_normal);
$item_normal_c = str_replace('item.', 'c.', $item_normal);
$entries = [];
@@ -85,7 +85,7 @@ class Messages {
}
if($author) {
- $author_sql = " AND (i.owner_xchan = '" . protect_sprintf(dbesc($author)) . "' OR i.source_xchan = '" . protect_sprintf(dbesc($author)) . "') ";
+ $author_sql = " AND (i.owner_xchan = '" . protect_sprintf(dbesc($author)) . "') ";
}
switch($type) {
diff --git a/Zotlabs/Widget/Pinned.php b/Zotlabs/Widget/Pinned.php
index 3c6484b36..1380c156b 100644
--- a/Zotlabs/Widget/Pinned.php
+++ b/Zotlabs/Widget/Pinned.php
@@ -77,17 +77,6 @@ class Pinned {
}
}
- $consensus = (intval($item['item_consensus']) ? true : false);
- if($consensus) {
- $conv_responses['agree'] = [ 'title' => t('Agree','title') ];
- $conv_responses['disagree'] = [ 'title' => t('Disagree','title') ];
- $conv_responses['abstain'] = [ 'title' => t('Abstain','title') ];
- if($commentable && $observer) {
- $conlabels = [ t('I agree'), t('I disagree'), t('I abstain') ];
- $canvote = true;
- }
- }
-
$this->activity($item, $conv_responses);
$verified = (intval($item['item_verified']) ? t('Message signature validated') : '');
@@ -234,15 +223,6 @@ class Pinned {
case 'dislike':
$verb_sql = " AND verb IN ('Dislike', '" . ACTIVITY_DISLIKE . "') ";
break;
- case 'agree':
- $verb_sql = " AND verb = '" . ACTIVITY_AGREE . "' ";
- break;
- case 'disagree':
- $verb_sql = " AND verb = '" . ACTIVITY_DISAGREE . "' ";
- break;
- case 'abstain':
- $verb_sql = " AND verb = '" . ACTIVITY_ABSTAIN . "' ";
- break;
case 'attendyes':
$verb_sql = " AND verb IN ('Accept', '" . ACTIVITY_ATTEND . "') ";
break;
diff --git a/app/mood.apd b/app/mood.apd
deleted file mode 100644
index 81b53a2ce..000000000
--- a/app/mood.apd
+++ /dev/null
@@ -1,7 +0,0 @@
-version: 3
-url: $baseurl/mood
-requires: local_channel
-name: Mood
-photo: icon:smile-o
-categories: Social
-desc: Set your current mood and tell your friends.
diff --git a/app/poke.apd b/app/poke.apd
deleted file mode 100644
index 490f98740..000000000
--- a/app/poke.apd
+++ /dev/null
@@ -1,7 +0,0 @@
-version: 3
-url: $baseurl/poke
-requires: local_channel
-name: Poke
-photo: icon:hand-o-right
-categories: Social
-desc: Poke somebody in your addressbook.
diff --git a/boot.php b/boot.php
index 635687a66..c3e508684 100644
--- a/boot.php
+++ b/boot.php
@@ -60,12 +60,14 @@ require_once('include/bbcode.php');
require_once('include/items.php');
require_once('include/conversation.php');
require_once('include/acl_selectors.php');
+require_once('include/selectors.php');
+require_once('include/activities.php');
define('PLATFORM_NAME', 'hubzilla');
-define('STD_VERSION', '8.9.8');
+define('STD_VERSION', '8.9.9');
define('ZOT_REVISION', '6.0');
-define('DB_UPDATE_VERSION', 1262);
+define('DB_UPDATE_VERSION', 1263);
define('PROJECT_BASE', __DIR__);
@@ -488,45 +490,46 @@ define('NAMESPACE_YMEDIA', 'http://search.yahoo.com/mrss/');
define('ACTIVITYSTREAMS_JSONLD_REV', 'https://www.w3.org/ns/activitystreams');
define('ZOT_APSCHEMA_REV', '/apschema/v1.11');
+
/**
* activity stream defines
*/
define('ACTIVITY_PUBLIC_INBOX', 'https://www.w3.org/ns/activitystreams#Public');
-define('ACTIVITY_REACT', NAMESPACE_ZOT . '/activity/react');
+define('ACTIVITY_REACT', NAMESPACE_ZOT . '/activity/react'); // deprecated
define('ACTIVITY_LIKE', NAMESPACE_ACTIVITY_SCHEMA . 'like'); // AS2 Like
define('ACTIVITY_DISLIKE', NAMESPACE_ZOT . '/activity/dislike'); // AS2 Dislike
-define('ACTIVITY_AGREE', NAMESPACE_ZOT . '/activity/agree'); // deprecated - remove from code?
-define('ACTIVITY_DISAGREE', NAMESPACE_ZOT . '/activity/disagree'); // deprecated - remove from code?
-define('ACTIVITY_ABSTAIN', NAMESPACE_ZOT . '/activity/abstain'); // deprecated - remove from code?
+define('ACTIVITY_AGREE', NAMESPACE_ZOT . '/activity/agree'); // deprecated
+define('ACTIVITY_DISAGREE', NAMESPACE_ZOT . '/activity/disagree'); // deprecated
+define('ACTIVITY_ABSTAIN', NAMESPACE_ZOT . '/activity/abstain'); // deprecated
define('ACTIVITY_ATTEND', NAMESPACE_ZOT . '/activity/attendyes'); // AS2 Accept
define('ACTIVITY_ATTENDNO', NAMESPACE_ZOT . '/activity/attendno'); // AS2 Reject
define('ACTIVITY_ATTENDMAYBE', NAMESPACE_ZOT . '/activity/attendmaybe'); // AS2 TentativeAccept
-define('ACTIVITY_FRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'make-friend'); // deprecated - remove from code?
+define('ACTIVITY_FRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'make-friend'); // deprecated
-define('ACTIVITY_FOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'follow');
-define('ACTIVITY_UNFOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'stop-following');
+define('ACTIVITY_FOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'follow'); // AS2 Follow
+define('ACTIVITY_UNFOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'stop-following'); // AS2 Ignore
define('ACTIVITY_POST', NAMESPACE_ACTIVITY_SCHEMA . 'post'); // AS2 Create
-define('ACTIVITY_UPDATE', NAMESPACE_ACTIVITY_SCHEMA . 'update');
+define('ACTIVITY_UPDATE', NAMESPACE_ACTIVITY_SCHEMA . 'update'); // AS2 Update
define('ACTIVITY_TAG', NAMESPACE_ACTIVITY_SCHEMA . 'tag'); // unused
define('ACTIVITY_SHARE', 'Announce');
-define('ACTIVITY_CREATE', NAMESPACE_ACTIVITY_SCHEMA . 'create'); // unused
+define('ACTIVITY_CREATE', NAMESPACE_ACTIVITY_SCHEMA . 'create'); // deprecated
define('ACTIVITY_DELETE', NAMESPACE_ACTIVITY_SCHEMA . 'delete'); // AS2 Delete
-define('ACTIVITY_POKE', NAMESPACE_ZOT . '/activity/poke');
-define('ACTIVITY_MOOD', NAMESPACE_ZOT . '/activity/mood');
+define('ACTIVITY_POKE', NAMESPACE_ZOT . '/activity/poke'); // deprecated
+define('ACTIVITY_MOOD', NAMESPACE_ZOT . '/activity/mood'); // deprecated
define('ACTIVITY_OBJ_COMMENT', NAMESPACE_ACTIVITY_SCHEMA . 'comment'); // AS2 Note
define('ACTIVITY_OBJ_NOTE', NAMESPACE_ACTIVITY_SCHEMA . 'note'); // AS2 Note
@@ -536,7 +539,7 @@ define('ACTIVITY_OBJ_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'photo'); // AS2 Image
define('ACTIVITY_OBJ_EVENT', NAMESPACE_ACTIVITY_SCHEMA . 'event'); // AS2 Event
define('ACTIVITY_OBJ_TAGTERM', NAMESPACE_ZOT . '/activity/tagterm'); // unused
-define('ACTIVITY_OBJ_PROFILE', NAMESPACE_ZOT . '/activity/profile'); // AS2 Profile (broken)
+define('ACTIVITY_OBJ_PROFILE', NAMESPACE_ZOT . '/activity/profile'); // AS2 Profile
define('ACTIVITY_OBJ_THING', NAMESPACE_ZOT . '/activity/thing'); // AS2 Page??? (broken)
diff --git a/include/activities.php b/include/activities.php
index f5f0e55da..c06a8f6c4 100644
--- a/include/activities.php
+++ b/include/activities.php
@@ -1,100 +1,83 @@
<?php /** @file */
-function profile_activity($changed, $value) {
-
- // TODO: we should probably send an Update/Profile or Person activity here.
- // We could also just send a Note with some changed info?
- // Profiles are currently a hubzilla specific thing.
- return;
+use Zotlabs\Lib\Activity;
+use Zotlabs\Daemon\Master;
- if(! local_channel() || ! is_array($changed) || ! count($changed))
- return;
+function profile_activity($changed, $value) {
- if(! get_pconfig(local_channel(),'system','post_profilechange'))
+ if (!local_channel() || !is_array($changed) || !count($changed)) {
return;
+ }
- require_once('include/items.php');
-
- $self = App::get_channel();
-
- if(! count($self))
+ if (!get_pconfig(local_channel(), 'system', 'post_profilechange')) {
return;
+ }
- $arr = array();
- $arr['uuid'] = item_message_id();
- $arr['mid'] = $arr['parent_mid'] = z_root() . '/item/' . $arr['uuid'];
- $arr['uid'] = local_channel();
- $arr['aid'] = $self['channel_account_id'];
- $arr['owner_xchan'] = $arr['author_xchan'] = $self['xchan_hash'];
-
- $arr['item_wall'] = 1;
- $arr['item_origin'] = 1;
- $arr['item_thread_top'] = 1;
- $arr['verb'] = ACTIVITY_UPDATE;
- $arr['obj_type'] = 'Profile';
-
- $arr['plink'] = z_root() . '/channel/' . $self['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']);
+ $channel = App::get_channel();
- $A = '[url=' . z_root() . '/channel/' . $self['channel_address'] . ']' . $self['channel_name'] . '[/url]';
+ $arr['verb'] = 'Update';
+ $arr['obj_type'] = 'Profile';
+ $channel_link = '[url=' . z_root() . '/channel/' . $channel['channel_address'] . ']' . $channel['channel_name'] . '[/url]';
$changes = '';
$t = count($changed);
$z = 0;
- foreach($changed as $ch) {
- if(strlen($changes)) {
- if ($z == ($t - 1))
+ $photo = false;
+ foreach ($changed as $ch) {
+ if (strlen($changes)) {
+ if ($z == ($t - 1)) {
$changes .= t(' and ');
- else
- $changes .= ', ';
+ } else {
+ $changes .= t(', ');
+ }
}
- $z ++;
+
+ if (in_array($ch, [t('Profile Photo'), t('Cover Photo')])) {
+ $photo = true;
+ $photo_size = (($ch === t('Profile Photo')) ? 4 : 8);
+ }
+
+ $z++;
$changes .= $ch;
}
- $prof = '[url=' . z_root() . '/profile/' . $self['channel_address'] . ']' . t('public profile') . '[/url]';
+ $profile_link = '[url=' . z_root() . '/profile/' . $channel['channel_address'] . ']' . t('public profile') . '[/url]';
- if($t == 1 && strlen($value)) {
+ if ($t == 1 && strlen($value)) {
// if it's a url, the HTML quotes will mess it up, so link it and don't try and zidify it because we don't know what it points to.
- $value = preg_replace_callback("/([^\]\='".'"'."]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\+\,]+)/ismu", 'red_zrl_callback', $value);
+ $value = preg_replace_callback("/([^='" . '"' . "]|^|#\^)(https?:\/\/[a-zA-Z0-9\pL:\/\-?&;.=@_~#%\$!+,]+)/ismu", 'red_zrl_callback', $value);
// take out the bookmark indicator
- if(substr($value,0,2) === '#^')
- $value = str_replace('#^','',$value);
-
- $message = sprintf( t('%1$s changed %2$s to &ldquo;%3$s&rdquo;'), $A, $changes, $value);
- $message .= "\n\n" . sprintf( t('Visit %1$s\'s %2$s'), $A, $prof);
- }
- else
- $message = sprintf( t('%1$s has an updated %2$s, changing %3$s.'), $A, $prof, $changes);
-
-
- $arr['body'] = $message;
-
- $links = array();
- $links[] = array('rel' => 'alternate', 'type' => 'text/html',
- 'href' => z_root() . '/profile/' . $self['channel_address']);
- $links[] = array('rel' => 'photo', 'type' => $self['xchan_photo_mimetype'],
- 'href' => $self['xchan_photo_l']);
+ if (str_starts_with($value, '#^')) {
+ $value = str_replace('#^', '', $value);
+ }
- $arr['object'] = json_encode(array(
- 'type' => 'Profile',
- 'title' => $self['channel_name'],
- 'id' => $self['xchan_url'] . '/' . $self['xchan_hash'],
- 'link' => $links
- ));
+ if ($photo) {
+ $value = "\n\n" . '[zmg=' . z_root() . '/photo/' . $value . '-' . $photo_size . ']' . $ch . ' ' . $channel['xchan_name'] . '[/zmg]';
+ }
+ else {
+ $value = '"' . $value . '"';
+ }
+ $message = sprintf(t('%1$s %2$s has been updated to %3$s.'), $channel_link . '\'s' . (($photo) ? '' : ' ' . $profile_link), strtolower($changes), $value);
- $arr['allow_cid'] = $self['channel_allow_cid'];
- $arr['allow_gid'] = $self['channel_allow_gid'];
- $arr['deny_cid'] = $self['channel_deny_cid'];
- $arr['deny_gid'] = $self['channel_deny_gid'];
+ } else {
+ $message = sprintf(t('%1$s updated the %2$s. Changed %3$s.'), $channel_link, $profile_link, strtolower($changes));
+ }
- $res = item_store($arr);
- $i = $res['item_id'];
+ $arr['body'] = $message;
- if($i) {
- // FIXME - limit delivery in notifier.php to those specificed in the perms argument
- Zotlabs\Daemon\Master::Summon(array('Notifier','activity', $i, 'PERMS_R_PROFILE'));
- }
+ $arr['obj'] = [
+ 'type' => 'Profile',
+ 'content' => bbcode($message),
+ 'source' => [
+ 'content' => $message,
+ 'mediaType' => 'text/bbcode'
+ ],
+ 'describes' => Activity::encode_person($channel),
+ 'url' => z_root() . '/profile/' . $channel['channel_address']
+ ];
+
+ post_activity_item($arr);
}
diff --git a/include/channel.php b/include/channel.php
index b8affa3ca..a82794bfd 100644
--- a/include/channel.php
+++ b/include/channel.php
@@ -1771,6 +1771,7 @@ function advanced_profile() {
if(App::$profile['gender']) $profile['gender'] = array( t('Gender:'), App::$profile['gender'] );
$ob_hash = get_observer_hash();
+/* TODO: AS2 compatibility
if($ob_hash && perm_is_allowed(App::$profile['profile_uid'],$ob_hash,'post_like')) {
$profile['canlike'] = true;
$profile['likethis'] = t('Like this channel');
@@ -1790,7 +1791,7 @@ function advanced_profile() {
foreach($likers as $l)
$profile['likers'][] = array('name' => $l['xchan_name'],'photo' => zid($l['xchan_photo_s']), 'url' => zid($l['xchan_url']));
}
-
+*/
if((App::$profile['dob']) && (App::$profile['dob'] != '0000-00-00')) {
$val = '';
diff --git a/include/contact_widgets.php b/include/contact_widgets.php
index 182f674ca..c05ecaf7c 100644
--- a/include/contact_widgets.php
+++ b/include/contact_widgets.php
@@ -85,7 +85,7 @@ function categories_widget($baseurl,$selected = '') {
AND term.otype = %d
AND item.owner_xchan = '%s'
AND item.item_wall = 1
- AND item.verb != '%s'
+ AND item.verb NOT IN ('Update', '%s')
$item_normal
$sql_extra
ORDER BY term.term ASC",
diff --git a/include/conversation.php b/include/conversation.php
index 7074e1c36..79fe12d54 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -217,96 +217,6 @@ function localize_item(&$item){
}
- if (activity_match($item['verb'], ACTIVITY_FRIEND)) {
-
- if ($item['obj_type'] == "" || !in_array($item['obj_type'], ['Person', ACTIVITY_OBJ_PERSON]))
- return;
-
- $Aname = $item['author']['xchan_name'];
- $Alink = $item['author']['xchan_url'];
-
-
- $obj= json_decode($item['obj'],true);
-
- $Blink = $Bphoto = '';
-
- if($obj['link']) {
- $Blink = get_rel_link($obj['link'],'alternate');
- $Bphoto = get_rel_link($obj['link'],'photo');
- }
- $Bname = $obj['title'];
-
-
- $A = '[zrl=' . chanlink_url($Alink) . '][bdi]' . $Aname . '[/bdi][/zrl]';
- $B = '[zrl=' . chanlink_url($Blink) . '][bdi]' . $Bname . '[/bdi][/zrl]';
- if ($Bphoto!="") $Bphoto = '[zrl=' . chanlink_url($Blink) . '][zmg=80x80]' . $Bphoto . '[/zmg][/zrl]';
-
- $item['shortlocalize'] = sprintf( t('%1$s is now connected with %2$s'), '[bdi]' . $Aname . '[/bdi]', '[bdi]' . $Bname . '[/bdi]');
-
- $item['body'] = $item['localize'] = sprintf( t('%1$s is now connected with %2$s'), $A, $B);
- $item['body'] .= "\n\n\n" . $Bphoto;
- }
-
- if (stristr($item['verb'], ACTIVITY_POKE)) {
-
- /** @FIXME for obscured private posts, until then leave untranslated */
- return;
-
- $verb = urldecode(substr($item['verb'],strpos($item['verb'],'#')+1));
- if(! $verb)
- return;
-
- if ($item['obj_type']=="" || !in_array($item['obj_type'], ['Person', ACTIVITY_OBJ_PERSON]))
- return;
-
- $Aname = $item['author']['xchan_name'];
- $Alink = $item['author']['xchan_url'];
-
- $obj= json_decode($item['obj'],true);
-
- $Blink = $Bphoto = '';
-
- if($obj['link']) {
- $Blink = get_rel_link($obj['link'],'alternate');
- $Bphoto = get_rel_link($obj['link'],'photo');
- }
- $Bname = $obj['title'];
-
- $A = '[zrl=' . chanlink_url($Alink) . '][bdi]' . $Aname . '[/bdi][/zrl]';
- $B = '[zrl=' . chanlink_url($Blink) . '][bdi]' . $Bname . '[/bdi][/zrl]';
- if ($Bphoto!="") $Bphoto = '[zrl=' . chanlink_url($Blink) . '][zmg=80x80]' . $Bphoto . '[/zmg][/zrl]';
-
- // we can't have a translation string with three positions but no distinguishable text
- // So here is the translate string.
-
- $txt = t('%1$s poked %2$s');
-
- // now translate the verb
-
- $txt = str_replace( t('poked'), t($verb), $txt);
-
- // then do the sprintf on the translation string
-
- $item['shortlocalize'] = sprintf($txt, '[bdi]' . $Aname . '[/bdi]', '[bdi]' . $Bname . '[/bdi]');
-
- $item['body'] = $item['localize'] = sprintf($txt, $A, $B);
- $item['body'] .= "\n\n\n" . $Bphoto;
- }
- if (stristr($item['verb'],ACTIVITY_MOOD)) {
- $verb = urldecode(substr($item['verb'],strpos($item['verb'],'#')+1));
- if(! $verb)
- return;
-
- $Aname = $item['author']['xchan_name'];
- $Alink = $item['author']['xchan_url'];
-
- $A = '[zrl=' . chanlink_url($Alink) . '][bdi]' . $Aname . '[/bdi][/zrl]';
-
- $txt = t('%1$s is %2$s','mood');
-
- $item['body'] = sprintf($txt, $A, t($verb));
- }
-
}
/**
@@ -345,7 +255,7 @@ function count_descendants($item) {
* @return boolean
*/
function visible_activity($item) {
- $hidden_activities = ['Like', 'Dislike', 'Accept', 'Reject', 'TentativeAccept', ACTIVITY_LIKE, ACTIVITY_DISLIKE, ACTIVITY_SHARE, ACTIVITY_AGREE, ACTIVITY_DISAGREE, ACTIVITY_ABSTAIN, ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE];
+ $hidden_activities = ['Like', 'Dislike', 'Accept', 'Reject', 'TentativeAccept', ACTIVITY_LIKE, ACTIVITY_DISLIKE, ACTIVITY_SHARE, ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE];
if(intval($item['item_notshown']))
return false;
@@ -553,9 +463,6 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
$conv_responses = [
'like' => ['title' => t('Likes','title')],
'dislike' => ['title' => t('Dislikes','title')],
- 'agree' => ['title' => t('Agree','title')],
- 'disagree' => ['title' => t('Disagree','title')],
- 'abstain' => ['title' => t('Abstain','title')],
'attendyes' => ['title' => t('Attending','title')],
'attendno' => ['title' => t('Not attending','title')],
'attendmaybe' => ['title' => t('Might attend','title')],
@@ -973,13 +880,10 @@ function thread_author_menu($item, $mode = '') {
}
}
-
$contact_url = '';
$posts_link = '';
- $poke_link = '';
if($contact) {
- $poke_link = ((Apps::system_app_installed($local_channel, 'Poke')) ? z_root() . '/poke/?f=&c=' . $contact['abook_id'] : '');
if (isset($contact['abook_self']) && !intval($contact['abook_self']))
$contact_url = z_root() . '/connections#' . $contact['abook_id'];
$posts_link = z_root() . '/network/?cid=' . $contact['abook_id'];
@@ -1033,18 +937,6 @@ function thread_author_menu($item, $mode = '') {
];
}
- if($poke_link) {
- $menu[] = [
- 'menu' => 'poke',
- 'title' => t('Poke'),
- 'icon' => 'fw',
- 'action' => '',
- 'href' => $poke_link,
- 'data' => '',
- 'class' => ''
- ];
- }
-
$args = [ 'item' => $item, 'mode' => $mode, 'menu' => $menu ];
call_hooks('thread_author_menu', $args);
@@ -1082,15 +974,6 @@ function builtin_activity_puller($item, &$conv_responses) {
case 'dislike':
$verb = ['Dislike', ACTIVITY_DISLIKE];
break;
- case 'agree':
- $verb = ACTIVITY_AGREE;
- break;
- case 'disagree':
- $verb = ACTIVITY_DISAGREE;
- break;
- case 'abstain':
- $verb = ACTIVITY_ABSTAIN;
- break;
case 'attendyes':
$verb = ['Accept', ACTIVITY_ATTEND];
break;
@@ -1112,6 +995,7 @@ function builtin_activity_puller($item, &$conv_responses) {
}
if((activity_match($item['verb'], $verb)) && ($item['id'] != $item['parent'])) {
+
$name = (($item['author']['xchan_name']) ? $item['author']['xchan_name'] : t('Unknown'));
$moderate = ((intval($item['item_blocked']) === ITEM_MODERATED) ? '<a href="moderate/' . $item['id'] . '/approve" onclick="moderate_approve(' . $item['id'] . '); return false;" class="text-success pe-2" title="' . t('Approve this item') . '"><i class="fa fa-check" ></i></a><a href="moderate/' . $item['id'] . '/drop" onclick="moderate_drop(' . $item['id'] . '); return false;" class="text-danger pe-2" title="' . t('Delete this item') . '"><i class="fa fa-trash-o" ></i></a>' : '');
@@ -1680,15 +1564,6 @@ function get_response_button_text($v,$count) {
case 'attendmaybe':
return ['label' => tt('Undecided','Undecided',$count,'noun'), 'icon' => 'calendar-o', 'class' => 'attendmaybe'];
break;
- case 'agree':
- return ['label' => tt('Agree','Agrees',$count,'noun'), 'icon' => '', 'class' => ''];
- break;
- case 'disagree':
- return ['label' => tt('Disagree','Disagrees',$count,'noun'), 'icon' => '', 'class' => ''];
- break;
- case 'abstain':
- return ['label' => tt('Abstain','Abstains',$count,'noun'), 'icon' => '', 'class' => ''];
- break;
default:
return '';
break;
diff --git a/include/dba/dba_transaction.php b/include/dba/dba_transaction.php
new file mode 100644
index 000000000..02e9945ca
--- /dev/null
+++ b/include/dba/dba_transaction.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * Class to represent a database transaction.
+ *
+ * A database transaction is initiated upon construction of an object of this
+ * class. The transaction will be automatically rolled back upon destruction
+ * unless it has been explicitly committed by calling the `commit` method.
+ *
+ * Wrapping multiple database operation within a transaction ensures that all
+ * (or none) of the operations are successfully completed at the same time.
+ *
+ * If a transaction is already active when constructing an object of this
+ * class, it will _not_ try to initiate a transaction, but constructs an object
+ * that will in practice be a stub. This prevents that "nested" transactions
+ * will cause problems with the existing active transaction.
+ *
+ * It also means that any rollbacks or commits perfomed on the "nested"
+ * transaction will be ignored, and postponed to the outer transaction is
+ * committed or rolled back.
+ *
+ * Also note that any modification to the database schema will implicitly
+ * commit active transactions in most cases, so be careful about relying on
+ * transactions in those cases.
+ *
+ * @Note This class assumes the actual underlying database driver is PDO.
+ */
+class DbaTransaction {
+ private bool $committed = false;
+ private bool $active = false;
+
+ /**
+ * Creates a database transaction object.
+ *
+ * If a transaction is already active for this db connection,
+ * no transaction is initiated, and the constructed object will
+ * not perform any commit or rollback actions.
+ */
+ public function __construct(private dba_driver $dba) {
+ if (! $this->dba->db->inTransaction()) {
+ $this->active = $this->dba->db->beginTransaction();
+ }
+ }
+
+ /**
+ * Roll back the transaction if it is active and not already committed.
+ */
+ public function __destruct() {
+ if ($this->active && ! $this->committed) {
+ $this->dba->db->rollBack();
+ }
+ }
+
+ /**
+ * Commit the transaction if active.
+ *
+ * This will also mark the transaction as committed, preventing it from
+ * being attempted rolled back on destruction.
+ */
+ public function commit(): void {
+ if ($this->active && ! $this->committed) {
+ $this->committed = $this->dba->db->commit();
+ }
+ }
+}
diff --git a/include/items.php b/include/items.php
index f689cc7b5..e26366af5 100644
--- a/include/items.php
+++ b/include/items.php
@@ -459,7 +459,7 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
if(! $arr['mid']) {
- $arr['uuid'] = ((x($arr,'uuid')) ? $arr['uuid'] : item_message_id());
+ $arr['uuid'] = ((x($arr,'uuid')) ? $arr['uuid'] : new_uuid());
}
$arr['mid'] = ((x($arr,'mid')) ? $arr['mid'] : z_root() . '/item/' . $arr['uuid']);
$arr['parent_mid'] = ((x($arr,'parent_mid')) ? $arr['parent_mid'] : $arr['mid']);
@@ -520,7 +520,7 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
return $ret;
if($post_id && $deliver) {
- Master::Summon([ 'Notifier','activity',$post_id ]);
+ Master::Summon(['Notifier','activity', $post_id]);
}
$ret['success'] = true;
@@ -2487,7 +2487,7 @@ function send_status_notifications($post_id,$item) {
// check for an unfollow thread activity - we should probably decode the obj and check the id
// but it will be extremely rare for this to be wrong.
- if(($xx['verb'] === ACTIVITY_UNFOLLOW)
+ if((in_array($xx['verb'], ['Ignore', ACTIVITY_UNFOLLOW]))
&& (in_array($xx['obj_type'], ['Note', 'Image', ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_PHOTO]))
&& ($xx['parent'] != $xx['id']))
$unfollowed = true;
@@ -2514,7 +2514,6 @@ function send_status_notifications($post_id,$item) {
if(! $notify)
return;
-
Enotify::submit(array(
'type' => $type,
'from_xchan' => $item['author_xchan'],
@@ -2607,7 +2606,6 @@ function tag_deliver($uid, $item_id) {
return;
}
-
if ($is_group && intval($item['item_thread_top']) && intval($item['item_wall']) && $item['author_xchan'] !== $item['owner_xchan']) {
if($item['resource_type'] === 'group_item') {
@@ -2625,39 +2623,6 @@ function tag_deliver($uid, $item_id) {
}
/*
- * Seems like a good place to plug in a poke notification.
- */
-
- if (stristr($item['verb'],ACTIVITY_POKE)) {
- $poke_notify = true;
-
- if(($item['obj_type'] == "") || (!in_array($item['obj_type'], ['Person', ACTIVITY_OBJ_PERSON])) || (! $item['obj']))
- $poke_notify = false;
-
- $obj = json_decode($item['obj'],true);
- if($obj) {
- if($obj['id'] !== $u[0]['channel_hash'])
- $poke_notify = false;
- }
- if(intval($item['item_deleted']))
- $poke_notify = false;
-
- $verb = urldecode(substr($item['verb'],strpos($item['verb'],'#')+1));
- if($poke_notify) {
- Enotify::submit(array(
- 'to_xchan' => $u[0]['channel_hash'],
- 'from_xchan' => $item['author_xchan'],
- 'type' => NOTIFY_POKE,
- 'item' => $item,
- 'link' => $i[0]['llink'],
- 'verb' => ACTIVITY_POKE,
- 'activity' => $verb,
- 'otype' => 'item'
- ));
- }
- }
-
- /*
* Do community tagging
*/
@@ -4411,7 +4376,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
$item_normal = item_normal();
if (! (isset($arr['include_follow']) && intval($arr['include_follow']))) {
- $item_normal .= sprintf(" and not verb in ('%s', '%s') ",
+ $item_normal .= sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
dbesc(ACTIVITY_FOLLOW),
dbesc(ACTIVITY_UNFOLLOW)
);
@@ -4824,54 +4789,7 @@ function comment_local_origin($item) {
return false;
}
-
-
-function send_profile_photo_activity($channel,$photo,$profile) {
-
- // for now only create activities for the default profile
-
- if(! intval($profile['is_default']))
- return;
-
- $arr = array();
- $arr['item_thread_top'] = 1;
- $arr['item_origin'] = 1;
- $arr['item_wall'] = 1;
-
- if(stripos($profile['gender'],t('female')) !== false)
- $t = t('%1$s updated her %2$s');
- elseif(stripos($profile['gender'],t('male')) !== false)
- $t = t('%1$s updated his %2$s');
- else
- $t = t('%1$s updated their %2$s');
-
- $ptext = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo['resource_id'] . ']' . t('profile photo') . '[/zrl]';
-
- $ltext = '[zrl=' . z_root() . '/profile/' . $channel['channel_address'] . ']' . '[zmg=150x150]' . z_root() . '/photo/' . $photo['resource_id'] . '-4[/zmg][/zrl]';
-
- $arr['body'] = sprintf($t,$channel['channel_name'],$ptext) . "\n\n" . $ltext;
-
- $acl = new Zotlabs\Access\AccessList($channel);
- $x = $acl->get();
-
- $arr['allow_cid'] = $x['allow_cid'];
-
- $arr['allow_gid'] = $x['allow_gid'];
- $arr['deny_cid'] = $x['deny_cid'];
- $arr['deny_gid'] = $x['deny_gid'];
-
- $arr['uid'] = $channel['channel_id'];
- $arr['aid'] = $channel['channel_account_id'];
-
- $arr['owner_xchan'] = $channel['channel_hash'];
- $arr['author_xchan'] = $channel['channel_hash'];
-
- post_activity_item($arr);
-}
-
-
function sync_an_item($channel_id,$item_id) {
-
$r = q("select * from item where id = %d",
intval($item_id)
);
diff --git a/include/photo/photo_driver.php b/include/photo/photo_driver.php
index 522e638de..4394d3238 100644
--- a/include/photo/photo_driver.php
+++ b/include/photo/photo_driver.php
@@ -117,7 +117,14 @@ function guess_image_type($filename, $data = '') {
$body = $data['body'];
if ($body) {
$image = new Imagick();
- $image->readImageBlob($body);
+
+ try{
+ $image->readImageBlob($body);
+ } catch (\Exception $e) {
+ logger('Imagick readImageBlob() exception:' . print_r($e, true));
+ return $type;
+ }
+
$r = $image->identifyImage();
if ($r && is_array($r) && array_key_exists($r['mimetype'], $types))
$type = $r['mimetype'];
diff --git a/include/taxonomy.php b/include/taxonomy.php
index cfec8414a..90ccb6142 100644
--- a/include/taxonomy.php
+++ b/include/taxonomy.php
@@ -58,7 +58,7 @@ function term_item_parent_query($uid,$table,$s,$type = TERM_UNKNOWN, $type2 = ''
$s = str_replace('*','%',$s);
if($type2) {
- $r = q("select parent from item left join term on term.oid = item.id where term.ttype in (%d, %d) and term.term like '%s' and term.uid = %d and term.otype = 1 and item.verb != '%s'",
+ $r = q("select parent from item left join term on term.oid = item.id where term.ttype in (%d, %d) and term.term like '%s' and term.uid = %d and term.otype = 1 and item.verb NOT IN ('Update', '%s')",
intval($type),
intval($type2),
dbesc($s),
@@ -67,7 +67,7 @@ function term_item_parent_query($uid,$table,$s,$type = TERM_UNKNOWN, $type2 = ''
);
}
else {
- $r = q("select parent from item left join term on term.oid = item.id where term.ttype = %d and term.term like '%s' and term.uid = %d and term.otype = 1 and item.verb != '%s'",
+ $r = q("select parent from item left join term on term.oid = item.id where term.ttype = %d and term.term like '%s' and term.uid = %d and term.otype = 1 and item.verb NOT IN ('Update', '%s')",
intval($type),
dbesc($s),
intval($uid),
diff --git a/include/text.php b/include/text.php
index ea9cf45e1..aa9650a25 100644
--- a/include/text.php
+++ b/include/text.php
@@ -1270,77 +1270,6 @@ function sslify($s) {
return $s;
}
-/**
- * @brief Get an array of poke verbs.
- *
- * @return array
- * * \e index is present tense verb
- * * \e value is array containing past tense verb, translation of present, translation of past
- */
-function get_poke_verbs() {
-
- $arr = [
- 'poke' => ['poked', t('poke'), t('poked')],
- 'ping' => ['pinged', t('ping'), t('pinged')],
-
- // Those might be better suited for a nsfw poke addon
-
- // 'prod' => ['prodded', t('prod'), t('prodded')],
- // 'slap' => ['slapped', t('slap'), t('slapped')],
- // 'finger' => ['fingered', t('finger'), t('fingered')],
- // 'rebuff' => ['rebuffed', t('rebuff'), t('rebuffed')]
- ];
-
- /**
- * @hooks poke_verbs
- * * \e array associative array with another array as value
- */
- call_hooks('poke_verbs', $arr);
-
- return $arr;
-}
-
-/**
- * @brief Get an array of mood verbs.
- *
- * @return array
- * * \e index is the verb
- * * \e value is the translated verb
- */
-function get_mood_verbs() {
-
- $arr = [
- 'happy' => t('happy'),
- 'sad' => t('sad'),
- 'mellow' => t('mellow'),
- 'tired' => t('tired'),
- 'perky' => t('perky'),
- 'angry' => t('angry'),
- 'stupefied' => t('stupefied'),
- 'puzzled' => t('puzzled'),
- 'interested' => t('interested'),
- 'bitter' => t('bitter'),
- 'cheerful' => t('cheerful'),
- 'alive' => t('alive'),
- 'annoyed' => t('annoyed'),
- 'anxious' => t('anxious'),
- 'cranky' => t('cranky'),
- 'disturbed' => t('disturbed'),
- 'frustrated' => t('frustrated'),
- 'depressed' => t('depressed'),
- 'motivated' => t('motivated'),
- 'relaxed' => t('relaxed'),
- 'surprised' => t('surprised'),
- ];
-
- /**
- * @hooks mood_verbs
- * * \e array associative array with mood verbs
- */
- call_hooks('mood_verbs', $arr);
-
- return $arr;
-}
/**
* @brief Function to list all smilies, both internal and from addons.
@@ -1821,7 +1750,7 @@ function prepare_body(&$item,$attach = false,$opts = false) {
}
- $poll = (($item['obj_type'] === 'Question' && in_array($item['verb'],['Create', ACTIVITY_POST, ACTIVITY_UPDATE, ACTIVITY_SHARE])) ? format_poll($item, $s, $opts) : false);
+ $poll = (($item['obj_type'] === 'Question' && in_array($item['verb'],['Create', 'Update', ACTIVITY_POST, ACTIVITY_UPDATE, ACTIVITY_SHARE])) ? format_poll($item, $s, $opts) : false);
if ($poll) {
$s = $poll;
}
diff --git a/tests/fakes/fake_dba.php b/tests/fakes/fake_dba.php
new file mode 100644
index 000000000..2289f5c80
--- /dev/null
+++ b/tests/fakes/fake_dba.php
@@ -0,0 +1,18 @@
+<?php
+namespace Zotlabs\Tests\Fakes;
+
+require_once 'include/dba/dba_pdo.php';
+
+/**
+ * Fake dba_driver implementation.
+ *
+ * This is a subclass of the dba_pdo class, that essentially lets us inject a
+ * stub for the PDO class that is the actual database driver.
+ */
+class FakeDba extends \dba_pdo {
+ public function __construct($stub) {
+ $this->db = $stub;
+ $this->connected = true;
+ }
+}
+
diff --git a/tests/unit/UnitTestCase.php b/tests/unit/UnitTestCase.php
index 0bf7b547a..18467d91e 100644
--- a/tests/unit/UnitTestCase.php
+++ b/tests/unit/UnitTestCase.php
@@ -23,6 +23,7 @@
namespace Zotlabs\Tests\Unit;
use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\TestResult;
/*
* Make sure global constants and the global App object is available to the
@@ -41,10 +42,39 @@ require_once 'include/dba/dba_driver.php' ;
* @author Klaus Weidenbach
*/
class UnitTestCase extends TestCase {
- private bool $in_transaction = false;
protected array $fixtures = array();
- public static function setUpBeforeClass() : void {
+ /**
+ * Override the PHPUnit\Framework\TestCase::run method, so we can
+ * wrap it in a database transaction.
+ *
+ * @SuppressWarnings(PHPMD.UnusedLocalVariable)
+ */
+ public function run(TestResult $result = null): TestResult {
+ // $myclass = get_class($this);
+ // logger("[*] Running test: {$myclass}::{$this->getName(true)}", LOGGER_DEBUG);
+
+ if (! \DBA::$dba) {
+ //logger('[*] Connecting to test db...');
+ $this->connect_to_test_db();
+ }
+
+ // The $transactuion variable is needed to hold the transaction until the
+ // function returns.
+ $transaction = new \DbaTransaction(\DBA::$dba);
+
+ $this->loadFixtures();
+
+ // Make sure app config is reset and loaded from fixtures
+ \App::$config = array();
+ \Zotlabs\Lib\Config::Load('system');
+
+ $result = parent::run($result);
+
+ return $result;
+ }
+
+ protected function connect_to_test_db() : void {
if ( !\DBA::$dba ) {
\DBA::dba_factory(
getenv('HZ_TEST_DB_HOST') ?: 'db',
@@ -71,36 +101,6 @@ class UnitTestCase extends TestCase {
}
}
- protected function setUp() : void {
- $myclass = get_class($this);
- logger("[*] Running test: {$myclass}::{$this->getName(true)}", LOGGER_DEBUG);
- if ( \DBA::$dba->connected ) {
- // Create a transaction, so that any actions taken by the
- // tests does not change the actual contents of the database.
- $this->in_transaction = \DBA::$dba->db->beginTransaction();
-
- $this->loadFixtures();
- }
-
- // Make sure app config is reset and loaded from fixtures
- \App::$config = array();
- \Zotlabs\Lib\Config::Load('system');
- }
-
- protected function tearDown() : void {
- if ( \DBA::$dba->connected && $this->in_transaction ) {
- // Roll back the transaction, restoring the db to the
- // state it was before the test was run.
- if ( \DBA::$dba->db->rollBack() ) {
- $this->in_transaction = false;
- } else {
- throw new \Exception(
- "Transaction rollback failed! Error is: "
- . \DBA::$dba->db->errorInfo());
- }
- }
- }
-
private static function dbtype(string $type): int {
if (trim(strtolower($type)) === 'postgres') {
return DBTYPE_POSTGRES;
diff --git a/tests/unit/includes/dba/TransactionTest.php b/tests/unit/includes/dba/TransactionTest.php
new file mode 100644
index 000000000..99e3f459d
--- /dev/null
+++ b/tests/unit/includes/dba/TransactionTest.php
@@ -0,0 +1,207 @@
+<?php
+/*
+ * Copyright (c) 2024 Hubzilla
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+require_once 'tests/fakes/fake_dba.php';
+require_once 'include/dba/dba_transaction.php';
+
+use \PHPUnit\Framework\TestCase;
+use \Zotlabs\Tests\Fakes\FakeDba;
+
+/**
+ * Test database transactions.
+ *
+ * This class subclass the base PHPUnit TestCase class, since we do _not_
+ * want a real database connection for these tests. We're testing functionality
+ * of the database adapter itself, so we choose to stub the underlying db driver
+ * to be able to assert that the adapter behaves as it should.
+ */
+class DbaTransactionTest extends TestCase {
+ private $pdo_stub;
+
+ public function setUp(): void {
+ $this->pdo_stub = $this->createStub(PDO::class);
+ }
+
+
+ /**
+ * Test that creating a DbaTransaction object initiates a database transaction.
+ *
+ * @SuppressWarnings(PHPMD.UnusedLocalVariable)
+ */
+ public function test_transaction_initialized_on_construction(): void {
+ // Stub PDO::inTransaction()
+ // Expect that it's called once, and return false to simulate that no
+ // transactions are active.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('inTransaction')
+ ->willReturn(false);
+
+ // Stub PDO::beginTransaction to ensure that it is being called.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('beginTransaction')
+ ->willReturn(true);
+
+ $dba = new FakeDba($this->pdo_stub);
+
+ $transaction = new DbaTransaction($dba);
+ }
+
+ /**
+ * Test that a transaction is rolled back when the DbaTransaction object
+ * is destroyed.
+ *
+ * @SuppressWarnings(PHPMD.UnusedLocalVariable)
+ */
+ public function test_uncommitted_transaction_is_rolled_back_on_destruction(): void {
+ // Stub PDO::inTransaction()
+ // Expect that it's called once, and return false to simulate that no
+ // transactions are active.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('inTransaction')
+ ->willReturn(false);
+
+ // Stub PDO::beginTransaction to ensure that it is being called.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('beginTransaction')
+ ->willReturn(true);
+
+ // Stub PDO::rollBack to make sure we test it is being called.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('rollBack')
+ ->willReturn(true);
+
+ $dba = new FakeDba($this->pdo_stub);
+
+ $transaction = new DbaTransaction($dba);
+ }
+
+ /**
+ * Test that a committed transaction is not rolled back when the
+ * DbaTransaction object goes out of scope.
+ */
+ public function test_committed_transaction_is_not_rolled_back(): void {
+ // Stub PDO::inTransaction()
+ // Return false to simulate that no transaction is active when called.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('inTransaction')
+ ->willReturn(false);
+
+ // Stub PDO::beginTransaction to ensure that it is being called.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('beginTransaction')
+ ->willReturn(true);
+
+ // Stub PDO::rollBack to ensure it is _not_ called
+ $this->pdo_stub
+ ->expects($this->never())
+ ->method('rollBack');
+
+ // Stub PDO::commit to make the test check that it is being called
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('commit')
+ ->willReturn(true);
+
+ $dba = new FakeDba($this->pdo_stub);
+
+ $transaction = new DbaTransaction($dba);
+ $transaction->commit();
+ }
+
+ /**
+ * Test that commiting a transaction more than once is a no-op.
+ */
+ public function test_that_committing_an_already_committed_transaction_does_nothing(): void {
+ // Stub PDO::inTransaction()
+ // Return false to simulate that no transaction is active when called.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('inTransaction')
+ ->willReturn(false);
+
+ // Stub PDO::beginTransaction to ensure that it is being called.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('beginTransaction')
+ ->willReturn(true);
+
+ // Stub PDO::rollBack to ensure it is _not_ called
+ $this->pdo_stub
+ ->expects($this->never())
+ ->method('rollBack');
+
+ // Stub PDO::commit to make the test check that it is being called
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('commit')
+ ->willReturn(true);
+
+ $dba = new FakeDba($this->pdo_stub);
+
+ $transaction = new DbaTransaction($dba);
+ $transaction->commit();
+ $transaction->commit();
+ }
+
+ /**
+ * Test simulating constructing a DbaTransaction object when a transaction
+ * is already active.
+ *
+ * This should _not_ initiate an actual DB transaction, not call the rollBack
+ * method on destruction.
+ *
+ * @SuppressWarnings(PHPMD.UnusedLocalVariable)
+ */
+ public function test_that_nesting_a_transaction_does_not_create_a_new_transaction_in_db(): void {
+ // Stub PDO::inTransaction()
+ // We simulate that a transaction is already active, by returning true from
+ // this method.
+ $this->pdo_stub
+ ->expects($this->once())
+ ->method('inTransaction')
+ ->willReturn(true);
+
+ // Stub PDO::beginTransaction
+ // Since a transaction is already active, we should _not_ initiate
+ // a new transaction when the DbaTransaction object is constructed.
+ $this->pdo_stub
+ ->expects($this->never())
+ ->method('beginTransaction');
+
+ // Stub PDO::rollBack to ensure it is _not_ called
+ $this->pdo_stub
+ ->expects($this->never())
+ ->method('rollBack');
+
+ $dba = new FakeDba($this->pdo_stub);
+
+ $transaction = new DbaTransaction($dba);
+ }
+}
diff --git a/view/js/mod_poke.js b/view/js/mod_poke.js
deleted file mode 100644
index 88fa9f7c2..000000000
--- a/view/js/mod_poke.js
+++ /dev/null
@@ -1,5 +0,0 @@
-$(document).ready(function() {
- $("#poke-recip").contact_autocomplete(baseurl + '/acl', 'a', false, function(data) {
- $("#poke-recip-complete").val(data.id);
- });
-});
diff --git a/view/tpl/mood_content.tpl b/view/tpl/mood_content.tpl
deleted file mode 100644
index 4cb5207f6..000000000
--- a/view/tpl/mood_content.tpl
+++ /dev/null
@@ -1,33 +0,0 @@
-
-<div id="mood-content" class="generic-content-wrapper">
- <div class="section-title-wrapper">
- <h2>{{$title}}</h2>
- </div>
- <div class="section-content-wrapper">
-
- <div id="mood-desc">{{$desc}}</div>
-
- <br />
- <br />
-
-
- <form action="mood" method="get">
- <br />
- <br />
-
- <input id="mood-parent" type="hidden" value="{{$parent}}" name="parent" />
-
- <div class="mb-3 field custom">
- <select name="verb" id="mood-verb-select" class="form-control" >
- {{foreach $verbs as $v}}
- <option value="{{$v.0}}">{{$v.1}}</option>
- {{/foreach}}
- </select>
- </div>
- <br />
- <br />
-
- <input type="submit" name="submit" value="{{$submit}}" />
- </form>
- </div>
-</div>
diff --git a/view/tpl/poke_content.tpl b/view/tpl/poke_content.tpl
deleted file mode 100644
index 3872d21ff..000000000
--- a/view/tpl/poke_content.tpl
+++ /dev/null
@@ -1,48 +0,0 @@
-
-<div id="poke-content" class="generic-content-wrapper">
- <div class="section-title-wrapper">
- <h2>{{$title}}</h2>
- </div>
- <div class="section-content-wrapper">
-
- <div id="poke-desc">{{$desc}}</div>
-
-<br />
-<br />
-
-
-<form action="poke" method="get">
-
-
-<div class="mb-3 field input">
- <label id="poke-recip-label" for="poke-recip">{{$clabel}}</label>
- <input class="form-control" id="poke-recip" type="text" value="{{$name}}" name="pokename" autocomplete="off" />
-</div>
-
- <input id="poke-recip-complete" type="hidden" value="{{$id}}" name="cid" />
- <input id="poke-parent" type="hidden" value="{{$parent}}" name="parent" />
-
-
-{{if $poke_basic}}
-<input type="hidden" name="verb" value="poke" />
-{{else}}
-<div class="mb-3 field custom">
- <label for="poke-verb-select" id="poke-verb-lbl">{{$choice}}</label>
- <select class="form-control" name="verb" id="poke-verb-select" >
- {{foreach $verbs as $v}}
- <option value="{{$v.0}}">{{$v.1}}</option>
- {{/foreach}}
- </select>
-</div>
-{{/if}}
-
-{{if ! $parent}}
-{{include file="field_checkbox.tpl" field=$private}}
-{{/if}}
-
-<input type="submit" name="submit" value="{{$submit}}" />
-</form>
-
-
- </div>
-</div>