Compare commits

...

453 Commits
9.2 ... 10.0.3

Author SHA1 Message Date
Mario
49cb73c8c7 version 10.0.3 2024-12-26 08:04:05 +00:00
Mario
2a00bd9a28 Merge branch 'dev' 2024-12-26 08:03:26 +00:00
Mario
553b3f6faa changelog and bump version 2024-12-26 08:02:29 +00:00
Mario
2980827925 fix another possible loop 2024-12-26 07:55:08 +00:00
Mario
45a78dcbc0 this should fix the infinite loop caused by a regression in Daemon/Expire 2024-12-25 20:53:32 +00:00
Mario
5813b65aed hotfix release version 10.0.2 2024-12-25 12:03:43 +00:00
Mario
f8acd1d3a5 Merge branch 'dev' 2024-12-25 12:02:32 +00:00
Mario
c9ebb23b69 hotfix for loop caused in Daemon/Expire 2024-12-25 12:00:27 +00:00
Mario
bc998eacd0 bump version 2024-12-22 17:40:41 +00:00
Mario
648979467a do not allow a new zid to override an existing remote login - otherwise a prfactored request with an added zid can log us out 2024-12-22 17:39:58 +00:00
Mario
5c0ff6f584 once more improved imagesLoaded() 2024-12-22 17:35:25 +00:00
Mario
632721da4e version 10.0.1 2024-12-22 08:51:48 +00:00
Mario
f3a702e927 Merge branch 'dev' 2024-12-22 08:51:15 +00:00
Mario
58985f2200 update changelog 2024-12-22 08:51:04 +00:00
Mario
c55662510d fetch missing commit from dev 2024-12-22 08:31:04 +00:00
Mario
f01e917fff Merge branch 'dev' 2024-12-22 08:26:26 +00:00
Mario
3940187d19 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-12-22 08:20:24 +00:00
Mario
1215e8a030 Revert "Drop obsolete library LightOpenID"
This reverts commit e516c1352f
2024-12-22 08:19:55 +00:00
Mario
5b6e27233a fix sql error 2024-12-22 08:15:16 +00:00
Mario
b80cba4e68 Merge branch '10.0RC' 2024-12-21 18:49:06 +00:00
Mario
f2b28f5bbb version 10.0 2024-12-21 18:46:40 +00:00
Mario
4aeb4963a4 Merge branch 'dev' into 10.0RC 2024-12-21 18:44:04 +00:00
Mario
de9b10e850 more changelog 2024-12-21 18:43:41 +00:00
Mario
36a1d98c52 changelog 2024-12-21 18:09:56 +00:00
Mario
cf66f245b4 RC2 2024-12-21 12:34:05 +00:00
Mario
b1f2f67a04 better pubs notofication fiy and also fix a javascript error and remove last bit of jquery from notifications 2024-12-21 12:07:31 +00:00
Mario
bd10c1e40a fix anomaly in pubs notification 2024-12-21 11:55:19 +00:00
Mario
e146eaa8f8 bump version 2024-12-21 10:28:07 +00:00
Mario
92e21c4f3d deduplicate the images array by src 2024-12-21 10:27:28 +00:00
Mario
55265c8a3e track processed images 2024-12-20 20:53:47 +00:00
Mario
c3cc624621 bump version 2024-12-20 19:13:21 +00:00
Mario
b466932e37 improved imagesLoaded() and formatting 2024-12-20 19:12:09 +00:00
Mario
a3248e8b3b version 2024-12-20 12:36:00 +00:00
Mario
9ec2db7c97 port scrollToItem() to vanilla js and more fixes 2024-12-20 12:35:29 +00:00
Mario
9bd94287dd improved imagesLoaded() and notifications fixes 2024-12-20 11:47:38 +00:00
Mario
faca95b21c bump version 2024-12-19 23:18:59 +00:00
Mario
79f8b06ede various fixes for the last commit 2024-12-19 23:17:56 +00:00
Mario
a2dde34b1b refactor notifications widget and updateConvItems() to not require jquery 2024-12-19 18:49:07 +00:00
Mario
fb5824417e Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-12-19 10:37:44 +00:00
Mario
804b4effa2 changelog 2024-12-19 10:37:19 +00:00
Mario Vavti
4c8e1de4c6 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-12-13 10:09:07 +01:00
Mario
d9c69b747d bump dev version 2024-12-13 09:07:55 +00:00
Mario Vavti
0e4be679e4 composer dump autoload 2024-12-13 09:59:31 +01:00
Mario
14360c4735 version 10.0RC and strings 2024-12-13 08:49:18 +00:00
Mario
2da55d3bd8 remove jquery.timeago.js in favor of a native js implementation 2024-12-12 14:18:55 +00:00
Mario Vavti
e9222d0d9a add test for item_forwardable() 2024-12-10 22:45:56 +01:00
Mario
93f72a53f5 introduce item_forwardable() and check it before we call the notifier to possibly safe some processes - test will follow, also add some other possibly blocking flags to the add item 2024-12-10 10:27:48 +00:00
Mario
93c4bd4692 pubcrawl: support for inbound add/remove activities and minor cleanup 2024-12-10 09:22:17 +00:00
Mario
486c21b519 hq: improved file filtering 2024-12-09 08:42:01 +00:00
Mario
7785487d77 fix delayed post handling in cron, always set item_delayed if we select a create date 2024-12-08 22:46:21 +00:00
Mario
9756023e39 fix expiration 2024-12-07 23:25:59 +00:00
Mario Vavti
bb0a22ee58 add test for relative_time() 2024-12-07 23:49:17 +01:00
Mario
e88ae54bef add more indicators and a new function to return relative time in the past and the future 2024-12-07 20:41:13 +00:00
Mario
d37d181d94 Libzot: remove commented code which duplicates code in Activity::decode_note() 2024-12-07 19:43:17 +00:00
Mario
d59d808883 more cleanup 2024-12-07 19:38:18 +00:00
Mario
b59fe77906 provide a comments disabled indicator and some cleanup 2024-12-07 19:34:30 +00:00
Mario
1941b4f026 only allow disable_comments on thread top 2024-12-07 18:40:56 +00:00
Mario
5c82229e34 Ãfix issue where poll updates were dismissed due to missing edited update, fix wrong array key when retaining item, update dreport push to also push the related item 2024-12-06 23:31:49 +00:00
Mario
66d502d8e1 an attempt to fix some comments on/off anomalies 2024-12-06 19:24:14 +00:00
Mario
66acfc66ce set item_type so that notifier can do the right thing 2024-12-06 11:41:01 +00:00
Mario
2e13640ab4 wrong class 2024-12-05 13:14:07 +00:00
Mario
277b4f7d10 even more fa2bi 2024-12-05 13:08:48 +00:00
Mario
edf2a6db1b we use the chat-quote icon for forums throughout the app. basically because the forum posts a quote of the original post 2024-12-05 13:02:18 +00:00
Mario
8ad000ec70 more fa2bi issues 2024-12-05 12:42:37 +00:00
Mario
563628fef8 another fa2bi issue 2024-12-05 12:33:55 +00:00
Mario
15b6353c1c filtering censored xchans in mod pubstream queries has possible performance issues. we will filter them in process_delivery() instead 2024-12-05 11:27:56 +00:00
Mario
1a86348a6c Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-12-02 09:23:16 +00:00
Mario
a80ab5887c also copy the item_restrict field to the add activity and check for this field in the notifier 2024-12-02 09:17:15 +00:00
Mario
475ae7ba13 Merge branch 'fix/chat-icon-fix' into 'dev'
Fixed notification icons in chat

See merge request hubzilla/core!2177
2024-12-02 09:15:32 +00:00
SK
e107298125 Fixed notification icons in chat 2024-12-02 04:32:48 +05:30
Mario
428ffa5e35 save a loop by ordering results by item_wall and more uuid only lookup 2024-11-28 15:34:16 +00:00
Mario
0bffe6e019 sql lookup by uuid should be sufficient by now, remove superfluous require_once() 2024-11-28 15:12:57 +00:00
Mario Vavti
9e2f3dc05f fix more issues reported by phpstan 2024-11-27 10:25:37 +01:00
Mario
9fa18a5557 Merge branch 'phpstan-ignore-some-warnings' into 'dev'
phpstan: Ignore warnings on missing return statement.

See merge request hubzilla/core!2175
2024-11-27 08:18:58 +00:00
Mario
9608ab27c4 Merge branch 'dev' into 'dev'
updated fork-awesome icons to bootstrap

See merge request hubzilla/core!2174
2024-11-27 08:18:09 +00:00
Mario
464b331deb Merge branch 'module-admin-accounts-enhancements' into 'dev'
Fix and refactor module Admin\Accounts part I

See merge request hubzilla/core!2173
2024-11-27 08:15:59 +00:00
Harald Eilertsen
0189d04614 Fix and refactor module Admin\Accounts part I 2024-11-27 08:15:59 +00:00
Mario
cbb3ad1620 make sure to toggle aside if a notification or message is clicked and some whitespace cleanup 2024-11-26 09:57:55 +00:00
Harald Eilertsen
c0f9d55cfb phpstan: Ignore warnings on missing return statement.
While some of these may be fixable without too much hassle, quite a few
of them will possibly require architectural restructuring. We should
revisit these, but let's silence them for now.
2024-11-25 13:11:58 +01:00
Mario
0da51e0f71 fix superfluous slash in some cases 2024-11-25 08:11:33 +00:00
SK
9014a288b0 updated fork-awesome icons to bootstrap 2024-11-22 18:49:13 +05:30
Mario
dcef9f61b5 remove logging 2024-11-22 10:28:21 +00:00
Mario
3d80db0cdc Merge branch 'add-mailer-class' into 'dev'
Add Zotlabs\Lib\Mailer class to replace z_mail function.

See merge request hubzilla/core!2172
2024-11-22 09:59:14 +00:00
Harald Eilertsen
3a2f787f96 Add Zotlabs\Lib\Mailer class to replace z_mail function. 2024-11-22 09:59:14 +00:00
Mario
f7a9b84943 mod cal: if a day is provided default to week view except the date has a ! prepended 2024-11-21 09:36:31 +00:00
Mario
46e6600169 mod cal: provide a possibility to link to a specific month or day by passing a fragment 2024-11-21 09:04:55 +00:00
Mario
243a2a9bdf Update chat.tpl to correct expand and contract icons from forkawesome to bootstrap icons.
(cherry picked from commit c626985448)

Co-authored-by: Saiwal K <sk@utsukta.org>
2024-11-19 21:08:55 +00:00
Mario
91baa52b8b Merge branch 'saiwal-master-patch-76831' into 'master'
Update chat.tpl to correct expand and contract icons from forkawesome to bootstrap icons.

See merge request hubzilla/core!2171
2024-11-19 21:08:32 +00:00
Harald Eilertsen
5338793883 Ubreak tests: update MagicTest for new behaviour of Magic module. 2024-11-19 11:10:49 +01:00
Mario Vavti
9acc73b273 some cleanup for mod magic 2024-11-18 23:15:29 +01:00
Saiwal K
c626985448 Update chat.tpl to correct expand and contract icons from forkawesome to bootstrap icons. 2024-11-17 19:59:31 +00:00
Mario Vavti
5cfb3842f1 more phpstan errors 2024-11-17 20:52:13 +01:00
Mario Vavti
25b089c1a9 fix some errors detected by phpstan 2024-11-17 16:17:05 +01:00
Mario
67a9292aaa Merge branch 'issue-1879-emails-with-plus-addressing-rejected' into 'dev'
Fix #1879: Emails with + in local part was rejected.

See merge request hubzilla/core!2170
2024-11-17 10:26:25 +00:00
Mario
81dda15669 fix undefined variables 2024-11-17 07:58:11 +00:00
Harald Eilertsen
5b7f8d986c Fix #1879: Emails with + in local part was rejected. 2024-11-16 13:45:36 +01:00
Mario
5dee600735 Merge branch 'add-dev-dependecy-phpstan' into 'dev'
Add PHPStan as a developer dependency.

See merge request hubzilla/core!2169
2024-11-14 18:45:29 +00:00
Mario
01da60b385 Merge branch 'various-phpstan-issues' into 'dev'
Several issues discovered by PHPStan

See merge request hubzilla/core!2168
2024-11-14 18:40:15 +00:00
Harald Eilertsen
951800eca6 Several issues discovered by PHPStan 2024-11-14 18:40:15 +00:00
Mario
72c47cd8db version 9.5.2 - merge containers 2024-11-14 17:14:15 +00:00
Mario
e3a8668c32 Merge branch 'dev' into containers 2024-11-14 17:09:22 +00:00
Mario
fd9977eada css fixes 2024-11-14 14:22:18 +00:00
Mario
bd3304ff94 Merge branch 'oops-fix-db-update' into 'dev'
Fix invocation of DB_Update::run.

See merge request hubzilla/core!2167
2024-11-14 13:32:48 +00:00
Mario
586cda5155 fix some conent import issues
(cherry picked from commit c9a8914b07)

Co-authored-by: Mario Vavti <mario@mariovavti.com>
2024-11-14 13:30:07 +00:00
Mario Vavti
c9a8914b07 fix some conent import issues 2024-11-14 12:47:40 +01:00
Mario
b21b9260d9 fix race condition when updating multiple choice polls 2024-11-13 14:01:14 +00:00
Mario
b5c07e4c01 this is not true anymore - check owner perms 2024-11-13 11:08:18 +00:00
Harald Eilertsen
28b5b0cab5 Add PHPStan as a developer dependency.
PHPStan is a static PHP code analyzer that's aimed at finding actual
bugs in the code. Where PHP Code Sniffer is about codeing standards,
PHPStan is about correctness of code.

The provided configuration file (`phpstan.neon.dist`) is configured to
use the _lowest_ level of checks that PHPStan will report on. See
https://phpstan.org/user-guide/rule-levels for information about the
various rule levels.

Run an analysis of the code base like this:

    % ./vendor/bin/phpstan

It will output any found issues to stdout.

You can also run it like this:

    % ./vendor/bin/phpstan --error-format=raw > phpstan.log

This will give you an output file in a format that's suitable for use
with typical editors for mapping errors to source locations.
2024-11-12 09:42:11 +01:00
Mario
39d0a3f1f6 containers: poll testing 2024-11-11 22:25:53 +00:00
Mario
513cd3b99a fix click area in dropdown add/remove reaction
(cherry picked from commit 8268ed1ba7)

Co-authored-by: Mario <mario@mariovavti.com>

(cherry picked from commit ce9d67f7b1)

Co-authored-by: Mario <mario@mariovavti.com>
2024-11-11 20:00:36 +00:00
Mario
ce9d67f7b1 fix click area in dropdown add/remove reaction
(cherry picked from commit 8268ed1ba7)

Co-authored-by: Mario <mario@mariovavti.com>
2024-11-11 20:00:25 +00:00
Mario
8268ed1ba7 fix click area in dropdown add/remove reaction 2024-11-11 19:53:20 +00:00
Harald Eilertsen
6c1d0851d7 Fix invocation of DB_Update::run.
Thought this should have been part of the change set that turned the
DB_Update routine to a static function instead of a constructor to an
object that is not used.
2024-11-11 17:05:13 +01:00
Mario
3bc0fd5db4 fix undefined var warning 2024-11-11 09:18:56 +00:00
Mario Vavti
4c3f3d1477 Merge branch 'dev' into containers 2024-11-10 23:38:30 +01:00
Mario Vavti
17411a501c containers: testing sourced items 2024-11-10 23:37:45 +01:00
Mario
d446f171c5 Revert "Module\Item: Make $item_id an object property."
This reverts commit 2c17d0b031
2024-11-10 22:36:35 +00:00
Mario Vavti
b24b409a01 Merge branch 'dev' into containers 2024-11-10 19:01:40 +01:00
Mario
3791dfab3a Merge branch 'begin-refactoring-module-item' into 'dev'
Begin refactoring Module\Item

See merge request hubzilla/core!2166
2024-11-10 18:01:06 +00:00
Mario
31a146b23a Merge branch 'oops-ref-to-nonexisting-class' into 'dev'
Remove import of non-existing class in test.

See merge request hubzilla/core!2165
2024-11-10 17:55:27 +00:00
Mario Vavti
e52714ed16 make sure to notify the drop if necessary 2024-11-10 18:53:46 +01:00
Harald Eilertsen
2c17d0b031 Module\Item: Make $item_id an object property.
This also allows us to deduplicate initialization and validation.
2024-11-10 16:43:48 +01:00
Harald Eilertsen
57e69372d3 Module\Item: Move processing of zot and as requests to functions.
These seem to be entirely independent, so moving the body of the if
statements to separate functions should be fine.
2024-11-10 16:43:48 +01:00
Mario Vavti
43acb86aab fix encoding and attribution 2024-11-10 11:49:09 +01:00
Mario Vavti
e339fbcc46 container fixes for photo and file upload 2024-11-10 11:40:56 +01:00
Mario
f05b8bd87d Do not filter deleted hublocs in xchan_query because it will result in empty profile info in conversations if the hubloc was deleted. Deleting a hublocation does not neccesarily delete its content and the author could appear again from another location.
(cherry picked from commit 4e6696b049)

Co-authored-by: Mario Vavti <mario@mariovavti.com>
2024-11-09 20:12:21 +00:00
Mario Vavti
4e6696b049 Do not filter deleted hublocs in xchan_query because it will result in empty profile info in conversations if the hubloc was deleted. Deleting a hublocation does not neccesarily delete its content and the author could appear again from another location. 2024-11-09 21:11:33 +01:00
Harald Eilertsen
fbc79e36e0 Remove import of non-existing class in test.
This one snuck in by mistake. No harm done, as the actual class was
never referenced, but it should still not be there.
2024-11-09 14:38:27 +01:00
Mario Vavti
c9d4b068c2 remove extensiv logging to syslog 2024-11-09 12:49:10 +01:00
Mario Vavti
b6dbbbc82f fix regression propagating deletes 2024-11-09 12:39:24 +01:00
Mario Vavti
954d92c354 Merge branch 'dev' into containers 2024-11-09 11:27:53 +01:00
Mario Vavti
8dbebc2b42 update border color 2024-11-09 11:27:13 +01:00
Mario
14207c68ca Merge branch 'fix-incorrect-module-imports' into 'dev'
Fix incorrect module imports.

See merge request hubzilla/core!2163
2024-11-09 10:26:23 +00:00
Mario
0ed08274f1 Merge branch 'clean-up-some-dependencies' into 'dev'
Clean up deps and upgrade EpubMeta

See merge request hubzilla/core!2162
2024-11-09 10:24:26 +00:00
Mario
2a152e0803 Merge branch 'more-deprecations-in-tests' into 'dev'
Fix some more deprecation warnings in the tests.

See merge request hubzilla/core!2161
2024-11-09 10:18:27 +00:00
Mario Vavti
a0c54c5f04 make sure to store target information when decoding and indicate contained conversations with a colored border for now 2024-11-09 10:55:10 +01:00
Harald Eilertsen
ac8c80ddbe Fix incorrect module imports.
When importing modules with use statements, they always require the
fully qualified module name. Iow, there's no need to prefix them with an
extra backslash.

Ref: https://www.php.net/manual/en/language.namespaces.importing.php
2024-11-09 08:45:45 +01:00
Mario Vavti
ebad9d56c9 port to containers item_store() continued 2024-11-08 22:24:33 +01:00
Mario Vavti
0481901b59 refactor drop_item[s]() for containers 2024-11-08 20:18:20 +01:00
Harald Eilertsen
0534fe6886 Thumbs\Epubthumb: Adapt to new version of EPub meta lib.
Also fixes a few issues and refactor the code a bit.
2024-11-08 16:48:23 +01:00
Harald Eilertsen
6e51571309 Remove epub-meta from library 2024-11-08 16:48:23 +01:00
Harald Eilertsen
fe30b54975 Update php-epub-meta and use composer for dep handling.
Note that we upgrade to the 2.x branch of the dependency, as the 3.x
branch requires PHP version 8.2 or later. There's no reason for us to
move our minimum supported version of PHP just yet.
2024-11-08 16:43:29 +01:00
Harald Eilertsen
b00ae997a5 Remove obsolete and unused symfony/options-resover and process
These actually look like they could be useful, but since unused, let's
drop them for now. They can always be re-added via composer if needed
later.
2024-11-08 16:39:26 +01:00
Harald Eilertsen
b5b7d0cda9 Remove obsolete and unused sticky-kit 2024-11-08 16:39:26 +01:00
Harald Eilertsen
300d461a1a Remove obsolete and unused tiptip library 2024-11-08 16:39:26 +01:00
Harald Eilertsen
e516c1352f Drop obsolete library LightOpenID
We're not using it anyways.
2024-11-08 16:39:26 +01:00
Mario Vavti
4b4cac63fd Merge branch 'dev' into containers 2024-11-08 11:19:42 +01:00
Harald Eilertsen
47f109451d Fix some more deprecation warnings in the tests. 2024-11-07 17:29:54 +01:00
Mario
e466c73407 fix allday not set if a rsource is provided
(cherry picked from commit 17183cc5dc)

Co-authored-by: Mario <mario@mariovavti.com>
2024-11-07 14:31:18 +00:00
Mario
17183cc5dc fix allday not set if a rsource is provided 2024-11-07 14:29:52 +00:00
Mario
e5aae2af0f fix allday variable not set when clicking an event
(cherry picked from commit 939e5d9ca5)

Co-authored-by: Mario <mario@mariovavti.com>
2024-11-06 16:17:18 +00:00
Mario
939e5d9ca5 fix allday variable not set when clicking an event 2024-11-06 16:16:23 +00:00
Mario
600209e21e bump dev version 2024-11-06 15:48:18 +00:00
Mario
173c4d242d version 9.4.4 2024-11-06 13:06:05 +00:00
Mario
76b8c36f7c changelog
(cherry picked from commit 12c88c06d8)

Co-authored-by: Mario <mario@mariovavti.com>
2024-11-06 13:05:18 +00:00
Mario
12c88c06d8 changelog 2024-11-06 13:04:03 +00:00
Mario
f35352090e Update translations for Norwegian Bokmål
(cherry picked from commit 35a05073f2)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-11-06 12:30:37 +00:00
Mario
e5db47e0d5 Module\Thing: Don't try to escape field that's not present
The `profile_assign` field is only present if the multiple profiles
feature is enabled.


(cherry picked from commit 472484dde0)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-11-06 12:30:16 +00:00
Mario
6a52e502aa Module\Thing: Don't use $_REQUEST superglobal.
Replaces all occurences with $_POST or $_GET instead.


(cherry picked from commit 5c3bdbd1e0)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-11-06 12:29:46 +00:00
Mario
6a866fe904 Move Norwegian translations from nb-no to nb
(cherry picked from commit ec02453d37)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-11-06 12:28:51 +00:00
Mario
229efddbf1 Merge branch 'fix-mariadb-support-for-test-setup' into 'dev'
tests: Update test db setup script for mariadb

See merge request hubzilla/core!2160
2024-11-06 11:50:40 +00:00
Mario
abb67a4565 Merge branch 'make-phpcs-a-bit-more-lax' into 'dev'
Make phpcs a bit more lax...

See merge request hubzilla/core!2159
2024-11-06 11:49:25 +00:00
Mario
2e324d4cef Merge branch 'move-norwegian-locale' into 'dev'
Move and update norwegian locale

See merge request hubzilla/core!2158
2024-11-06 11:48:54 +00:00
Mario
d4d1a7523d Merge branch 'fix-module-thing' into 'dev'
Fix error adding Things when multiple profiles not enabled

See merge request hubzilla/core!2157
2024-11-06 11:47:57 +00:00
Mario
d9d239bf3a only zot6 hublocs have a sitekey so only query such hublocs. This will safe alternative network hublocs from being marked deleted allthough they are intact
(cherry picked from commit 7a3f2c1ba9)

Co-authored-by: Mario <mario@mariovavti.com>
2024-11-06 11:16:46 +00:00
Mario
429d15f009 correctly hide modals and remove unneeded toString() conversion since we are not dealing with string objects here
(cherry picked from commit 9f473fc204)

Co-authored-by: Mario <mario@mariovavti.com>
2024-11-06 11:16:20 +00:00
Mario
7a3f2c1ba9 only zot6 hublocs have a sitekey so only query such hublocs. This will safe alternative network hublocs from being marked deleted allthough they are intact 2024-11-06 11:12:42 +00:00
Mario
9f473fc204 correctly hide modals and remove unneeded toString() conversion since we are not dealing with string objects here 2024-11-06 09:44:07 +00:00
Harald Eilertsen
35a05073f2 Update translations for Norwegian Bokmål 2024-11-04 10:22:13 +01:00
Harald Eilertsen
472484dde0 Module\Thing: Don't try to escape field that's not present
The `profile_assign` field is only present if the multiple profiles
feature is enabled.
2024-11-03 20:42:59 +01:00
Harald Eilertsen
5c3bdbd1e0 Module\Thing: Don't use $_REQUEST superglobal.
Replaces all occurences with $_POST or $_GET instead.
2024-11-03 20:42:59 +01:00
Harald Eilertsen
ec02453d37 Move Norwegian translations from nb-no to nb 2024-11-03 18:06:42 +01:00
Mario
2b44be58c3 explicit check for channel_address
(cherry picked from commit e20327d267)

Co-authored-by: Mario <mario@mariovavti.com>
2024-11-03 11:02:35 +00:00
Mario
c44db397ff Zotlabs\Module\Setup: Fix deprecation.
Using `self` in callables has been deprecated, so change to proper fully
qualified class name.


(cherry picked from commit 8ab3ad6531)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-11-03 11:02:04 +00:00
Mario
a385fdff37 Zotlabs\Web\HttpMeta: Declare and init properties.
The $ogproperty was not declared, which triggered a warning in PHP 8.2.

Also fixed the initialization of the properties, and removed the now
superfluous constructor.


(cherry picked from commit bf008465ad)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-11-03 11:01:50 +00:00
Mario
20aacb82c6 tests: Declare private property $output.
Uncovered by PHP 8.2 because dynamic properties are deprecated.


(cherry picked from commit a29a1c768d)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-11-03 11:01:38 +00:00
Mario
0d17d8dad9 tests: Fix typo in UnitTestCase.
Uncovered by PHP 8.2 because dynamic properties are deprecated.


(cherry picked from commit 90bc987ea7)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-11-03 11:01:21 +00:00
Mario
2ab0118c13 Fix missing CSRF checks in admin/account_edit
(cherry picked from commit 38c947590e)

342d94c3 tpl: Fix warnings in templates.
bccaeb1e tests: Update Module\TestCase to support POST requests
f627e55b tests: Update account fixtures with fixed account_level.
ee62aff4 Module\Admin\Account_edit: Add missing CSRF checks.

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-11-03 10:59:41 +00:00
Mario
30419bdbf6 add ocap tokens to all media files and attachments
(cherry picked from commit 2f0a47e583)

Co-authored-by: Mario <mario@mariovavti.com>
2024-11-03 10:59:16 +00:00
Mario Vavti
21b60bf119 Merge branch 'dev' into containers 2024-11-03 11:57:45 +01:00
Mario
5db3f93be9 Merge branch 'php8.2-deprecations' into 'dev'
Fix deprecations uncovered by running tests on PHP 8.2

See merge request hubzilla/core!2156
2024-11-03 10:57:03 +00:00
Mario Vavti
d25314c75b Merge branch 'dev' into containers 2024-11-03 11:45:08 +01:00
Mario
e20327d267 explicit check for channel_address 2024-11-03 10:43:17 +00:00
Harald Eilertsen
8ab3ad6531 Zotlabs\Module\Setup: Fix deprecation.
Using `self` in callables has been deprecated, so change to proper fully
qualified class name.
2024-11-03 08:48:53 +01:00
Harald Eilertsen
bf008465ad Zotlabs\Web\HttpMeta: Declare and init properties.
The $ogproperty was not declared, which triggered a warning in PHP 8.2.

Also fixed the initialization of the properties, and removed the now
superfluous constructor.
2024-11-03 08:42:11 +01:00
Harald Eilertsen
a29a1c768d tests: Declare private property $output.
Uncovered by PHP 8.2 because dynamic properties are deprecated.
2024-11-03 08:39:21 +01:00
Harald Eilertsen
90bc987ea7 tests: Fix typo in UnitTestCase.
Uncovered by PHP 8.2 because dynamic properties are deprecated.
2024-11-03 08:32:01 +01:00
Mario
46fdce4402 Merge branch 'admin-account-edit-csrf-check' into 'dev'
Fix missing CSRF checks in admin/account_edit

See merge request hubzilla/core!2155
2024-11-02 14:42:01 +00:00
Harald Eilertsen
38c947590e Fix missing CSRF checks in admin/account_edit 2024-11-02 14:42:00 +00:00
Mario
c5faa012b5 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-11-02 14:35:42 +00:00
Mario
2f0a47e583 add ocap tokens to all media files and attachments 2024-11-02 14:35:04 +00:00
Mario
c958cc6f90 URL escape zid param in head.tpl
This should fix issue #1877 fully.


(cherry picked from commit 065f85bab1)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-11-01 09:03:21 +00:00
Mario
541a0f6476 Merge branch 'issue-1877-more-fixes' into 'dev'
URL escape zid param in head.tpl

See merge request hubzilla/core!2154
2024-11-01 09:02:37 +00:00
Harald Eilertsen
065f85bab1 URL escape zid param in head.tpl
This should fix issue #1877 fully.
2024-10-31 19:15:52 +01:00
Mario
38ac60e618 make sure the objects published date has the correct time format
(cherry picked from commit 160c40b580)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-31 11:12:54 +00:00
Mario
160c40b580 make sure the objects published date has the correct time format 2024-10-31 11:07:42 +00:00
Mario Vavti
005d4ad351 Merge branch 'dev' into containers 2024-10-30 12:50:08 +01:00
Mario
90a1dad02c Merge branch 'make-db-upgrade-static-method' into 'dev'
Change DB_Upgrade to a static function instead.

See merge request hubzilla/core!2151
2024-10-30 11:47:52 +00:00
Harald Eilertsen
4daba84223 Make phpcs a bit more lax...
Allow spaces for indent, and newlines before braces.
2024-10-30 12:35:08 +01:00
Harald Eilertsen
fc182f1b07 tests: Update test db setup script for mariadb
Mariadb now issues warnings when using the deprecated `mysql` binary. So
we make sure to use the proper name for the binary depending on the
actual DB engine installed.
2024-10-30 12:13:21 +01:00
Mario
23a19ecf1f escape the zid parameter - issue #1877
(cherry picked from commit 0207c02420)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-30 09:18:23 +00:00
Mario
0207c02420 escape the zid parameter - issue #1877 2024-10-30 09:12:26 +00:00
Mario Vavti
68135c28da Merge branch 'dev' into containers 2024-10-30 09:50:17 +01:00
Mario
274bfa9024 Merge branch 'add-missing-test-for-bbcode-cleanup-fix' into 'dev'
tests: Tests for BBCode cleanup fix

See merge request hubzilla/core!2152
2024-10-30 08:27:44 +00:00
Mario Vavti
4bb28a21c4 Merge branch 'dev' into containers 2024-10-27 14:05:25 +01:00
Mario
8b75f50f23 fix en tos page
(cherry picked from commit 0e50b1d10c)

Co-authored-by: Mario Vavti <mario@mariovavti.com>
2024-10-27 12:57:02 +00:00
Mario Vavti
0e50b1d10c fix en tos page 2024-10-27 13:53:31 +01:00
Harald Eilertsen
8f4c3a2f88 Merge branch 'dev' into make-db-upgrade-static-method 2024-10-23 14:56:41 +02:00
Harald Eilertsen
73006ccdf5 tests: Tests for BBCode cleanup fix
Somehow I forgot to include this in the patch that fixed the issue.
2024-10-23 14:31:21 +02:00
Mario Vavti
1006ebbf61 Merge branch 'dev' into containers 2024-10-23 14:19:45 +02:00
Mario
436b1673cf make sure we select only sys channel items and remove dupes checking (this will be checked in item_store() anyway)
(cherry picked from commit e530476e6c)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-23 12:08:03 +00:00
Mario
e530476e6c make sure we select only sys channel items and remove dupes checking (this will be checked in item_store() anyway) 2024-10-23 12:06:32 +00:00
Mario
e0a91bed7a allow to file items from the public stream 2024-10-23 12:04:15 +00:00
Mario Vavti
168ec53686 Merge branch 'dev' into containers 2024-10-19 20:50:48 +02:00
Mario
4d1be3aea5 bring filed items to mod hq 2024-10-19 18:49:47 +00:00
Mario Vavti
e8f816a981 Merge branch 'dev' into containers 2024-10-18 21:36:48 +02:00
Mario
e649ba5b13 remove attach_upgrade() after 7 years it should not be required anymore 2024-10-18 19:32:41 +00:00
Mario
92ce66e766 i guess a couple of weeks have passed by now 2024-10-18 19:20:20 +00:00
Mario
96210f5ecc fix edit button not clickable if below right aside
(cherry picked from commit 1411eafa9b)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-18 19:14:04 +00:00
Mario
1411eafa9b fix edit button not clickable if below right aside 2024-10-18 19:06:35 +00:00
Mario Vavti
20db45c815 Merge branch 'dev' into containers 2024-10-18 20:19:36 +02:00
Mario Vavti
4acdb8fb10 containers: port events 2024-10-18 20:18:55 +02:00
Mario
9e9e8efb2d fix tags rendering in the editor
(cherry picked from commit f4495fd441)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-17 09:04:25 +00:00
Mario
f4495fd441 fix tags rendering in the editor 2024-10-17 09:03:32 +00:00
Harald Eilertsen
e2ae8f0c4d Zotlabs\Lib\DB_Upgrade: Add API documentation. 2024-10-14 23:07:42 +02:00
Harald Eilertsen
074dc440cc Change DB_Upgrade to a static function instead.
No need for this to be an object, since it's never referenced or even
kept after construction. Further all the functionality was in the
constructor anyways.

Also removed some unused properties.
2024-10-14 22:52:13 +02:00
Mario
e9dc4b553b Fix regex to detect URLs in cleanup_bbcode.
This fixes the issue where the text after the URL would be included in
the link if it was immediately followed by a newline.

Example:

    https://example.com
	this is a test.

Would become:

	#^[url=https://example.com_this]https://example.com_this[/url]
	is a test


(cherry picked from commit 687cda3673)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-10-12 17:08:15 +00:00
Mario Vavti
d7fa6f6709 Merge branch 'dev' into containers 2024-10-12 19:06:35 +02:00
Mario
40a9989be2 Merge branch 'fix-cleanup-bbcode-url-regex' into 'dev'
Fix naked URLs immediately followed by a newline

See merge request hubzilla/core!2150
2024-10-12 17:05:19 +00:00
Harald Eilertsen
d1648927b5 Fix some whitespace issues in zid.php.
No functional change.
2024-10-12 18:23:30 +02:00
Harald Eilertsen
ecde4a3ded Change config used by Markdown tests to reflect actual use.
This makes the configuration used align better with how it is being used
in the mdpost addon. This also reveals some issues that are less than
ideal for Markdown posts. The relevant test cases have been adjusted to
pass with the new config, but have been commented.
2024-10-12 18:19:43 +02:00
Harald Eilertsen
687cda3673 Fix regex to detect URLs in cleanup_bbcode.
This fixes the issue where the text after the URL would be included in
the link if it was immediately followed by a newline.

Example:

    https://example.com
	this is a test.

Would become:

	#^[url=https://example.com_this]https://example.com_this[/url]
	is a test
2024-10-12 18:15:54 +02:00
Mario Vavti
47cdef390a Merge branch 'dev' into containers 2024-10-12 17:17:11 +02:00
Mario
05a5b644bf Merge branch 'remove-repo-handling-from-admin-addons' into 'dev'
Remove addon repo management from admin/addons.

See merge request hubzilla/core!2149
2024-10-12 15:15:40 +00:00
Mario
84556854e8 Merge branch 'drop-unused-html5-library' into 'dev'
Remove HTML5 parser lib deprecated in Hubzilla 5.0

See merge request hubzilla/core!2148
2024-10-12 15:10:02 +00:00
Mario
314443d41e Merge branch 'first-tests-for-module-magic' into 'dev'
tests: Add some tests for the Zotlabs\Magic module.

See merge request hubzilla/core!2147
2024-10-12 15:08:29 +00:00
Mario Vavti
c23a71c936 code consistency 2024-10-12 17:05:35 +02:00
Mario Vavti
12b33a23de containers: port start_delivery_chain() 2024-10-12 16:31:00 +02:00
Mario Vavti
a305c20e08 Merge branch 'dev' into containers 2024-10-12 16:24:58 +02:00
Mario
c70bd08c10 Fix duplicate posts from forum clones
(cherry picked from commit e2cfe245b7)

Co-authored-by: Mario Vavti <mario@mariovavti.com>
2024-10-12 13:59:12 +00:00
Mario Vavti
e2cfe245b7 Fix duplicate posts from forum clones 2024-10-12 15:58:00 +02:00
Mario Vavti
12b24e0e5e containers: port mod impel 2024-10-11 17:16:44 +02:00
Mario Vavti
d5291e9b07 containers: port core modules and attach_store_item() 2024-10-11 17:10:56 +02:00
Mario Vavti
a1818b1a29 document some special handling 2024-10-10 15:10:51 +02:00
Mario Vavti
e8eb283fd8 fix c/p typo 2024-10-10 14:18:23 +02:00
Mario Vavti
96d5370122 update item entity for hubzilla 2024-10-10 14:17:13 +02:00
Mario Vavti
2bcb6a4fed merge dev and resolve conflicts 2024-10-10 13:13:17 +02:00
Mario Vavti
aee396421a revert 2024-10-10 13:09:04 +02:00
Mario Vavti
897568a087 resolve merge conflict 2024-10-10 13:07:48 +02:00
Mario Vavti
69109a558b version 9.4.3 2024-10-10 12:16:33 +02:00
Mario
4aff6d19d6 changelog
(cherry picked from commit a5c1b669b4)

Co-authored-by: Mario Vavti <mario@mariovavti.com>
2024-10-10 10:11:31 +00:00
Mario Vavti
a5c1b669b4 changelog 2024-10-10 12:09:39 +02:00
Mario
3cb5d14037 also discard Add/Remove at the AP side
(cherry picked from commit 2aee659cbd)

Co-authored-by: Mario Vavti <mario@mariovavti.com>
2024-10-10 10:04:17 +00:00
Mario
5f685bcf63 also dismiss add/remove collection activities in fetch_conversation()
(cherry picked from commit 44232677c8)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-10 10:03:51 +00:00
Mario
cb44f7e360 dismiss add/remove collection activities until we support themÃ
(cherry picked from commit 16603ca854)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-10 10:03:32 +00:00
Mario Vavti
2aee659cbd also discard Add/Remove at the AP side 2024-10-10 12:01:46 +02:00
Harald Eilertsen
b117cf9dc7 emove another PHPGit related file. 2024-10-09 23:38:01 +02:00
Mario Vavti
c2ce1d9881 containers: send add in mod like, send remove on delete 2024-10-09 22:43:01 +02:00
Harald Eilertsen
2ed8908127 Remove now unused PHPGit from library. 2024-10-09 21:02:08 +02:00
Harald Eilertsen
6588e272db Remove addon repo management from admin/addons.
This functionality was broken anyways, and needs to be rethought. Addon
reporitories can still be managed from the terminal using the tools in
util/.
2024-10-09 21:00:12 +02:00
Harald Eilertsen
c13645f136 Remove HTML5 parser lib deprecated in Hubzilla 5.0 2024-10-09 18:47:35 +02:00
Mario Vavti
8cee16be1b enable the hooks again 2024-10-09 18:26:15 +02:00
Mario Vavti
45c0091d3d more work on porting containers from streams 2024-10-09 18:17:37 +02:00
Mario
44232677c8 also dismiss add/remove collection activities in fetch_conversation() 2024-10-09 15:41:40 +00:00
Mario
16603ca854 dismiss add/remove collection activities until we support themà 2024-10-09 07:39:13 +00:00
Mario
75184355d0 whitespace and use empty for check 2024-10-06 16:47:15 +00:00
Mario
1988d21e6c start containers 2024-10-06 15:53:39 +00:00
Harald Eilertsen
bccac55cf9 tests: Add some tests for the Zotlabs\Magic module.
Only tests the delegate functionality at the moment.

This patch also includes some minor fixes to the Magic module, triggered
by the tests with empty destination URL's.
2024-10-06 11:47:45 +02:00
Mario
19eeadfe5b port some libs from streams repo 2024-10-06 08:59:36 +00:00
Mario
8f74ee67e3 css fixes
(cherry picked from commit 2693e9e990)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-04 11:27:56 +00:00
Mario
b0a11537de remove bogus icon id
(cherry picked from commit 04741c761a)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-04 11:27:40 +00:00
Mario
2693e9e990 css fixes 2024-10-04 11:26:48 +00:00
Mario
04741c761a remove bogus icon id 2024-10-04 11:14:41 +00:00
Mario
4de9cb1142 more fa2bi fixes
(cherry picked from commit 8f890fb6fa)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-04 11:07:50 +00:00
Mario
8f890fb6fa more fa2bi fixes 2024-10-04 11:06:35 +00:00
Mario
158ddfb009 changelog
(cherry picked from commit 1afb2a4ce8)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-04 07:09:21 +00:00
Mario
2b4f344181 Version 9.4.2 2024-10-04 07:07:31 +00:00
Mario
1afb2a4ce8 changelog 2024-10-04 07:06:24 +00:00
Mario
2e5f922561 due to popular demand: indicate reacted state via icon color
(cherry picked from commit afbeb58c16)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-04 06:59:50 +00:00
Mario
a6498a0cfc Reflect change to btn-link in js template
(cherry picked from commit 8ffab25f5d)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-04 06:59:16 +00:00
Mario
8ffab25f5d Reflect change to btn-link in js template 2024-10-04 06:57:46 +00:00
Mario
1073392398 Fix modal backdrop not removed when like/unlike from the modal
(cherry picked from commit 7d41deebce)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-04 06:51:15 +00:00
Mario
7d41deebce Fix modal backdrop not removed when like/unlike from the modal 2024-10-04 06:50:06 +00:00
Mario
76064dbb33 Fix missing handle icon in mod pdledit_gui
(cherry picked from commit 7e48caae6b)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-04 06:27:37 +00:00
Mario
7e48caae6b Fix missing handle icon in mod pdledit_gui 2024-10-04 06:26:34 +00:00
Mario
afbeb58c16 due to popular demand: indicate reacted state via icon color 2024-10-03 08:18:59 +00:00
Mario
1ab4f36a1b Merge branch 'master' of https://framagit.org/hubzilla/core 2024-10-03 04:52:40 +00:00
Mario
cea9c88b9e version 9.4.1 2024-10-03 04:52:18 +00:00
Mario
babe118383 Tests: Unbreak help test.
(cherry picked from commit 5b93aa1148)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-10-02 20:27:26 +00:00
Mario
2b140e53cc changelog
(cherry picked from commit 9008760aa6)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-02 20:21:51 +00:00
Mario
9008760aa6 changelog 2024-10-02 20:20:56 +00:00
Mario
fb1514a782 Help: Drop language specifier in URL when redirecting
This finally fixes the help for languages other than english.


(cherry picked from commit 4daa03f025)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-10-02 20:09:36 +00:00
Mario
7679894684 Replace drop shadow in help toc with brighter color.
The drop shadow looked terrible in dark mode. While that could be fixed,
I think it looks better with just using the link hover color and making
the selected item bold.


(cherry picked from commit 8ae9df3bb7)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-10-02 20:08:55 +00:00
Mario
520cf1015c Move some help related styling from redbasic to module css.
(cherry picked from commit 25d9d3ba1b)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-10-02 20:08:33 +00:00
Mario
64bd8eef4b Use html details element for toc on top of help pages.
This allows us to get rid of some more unneccessary JavaScript that just
implements stuff that web browsers now do anyways.


(cherry picked from commit 26ce231951)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-10-02 20:08:04 +00:00
Mario
aa42f6a6b2 Remove link to "Contents" from the help table of contect sidebar.
Changes the element where the jQuery.toc plugin looks for headings to
only include the actual help contents, not the toc itself.


(cherry picked from commit fb9464437e)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-10-02 20:07:31 +00:00
Mario
13345d3cbe deps: Upgrade smarty/smarty to version 4.5.4
This eliminates a potential vulnerability where an template author could
inject arbitrary PHP files to be run via the 'extends' tag.

See:
  - https://github.com/smarty-php/smarty/security/advisories/GHSA-4rmg-292m-wg3w
  - 0be92bc8a6

Impact assessment:

In our case I would consider this a low severity issue as we don't
allow users to dynamically add or edit smarty templates. Templates has
to be updated via merge requests, or by installing a theme. In both
cases a malicious attacker already has easier ways to inject whatever
code they want.

Further, the extend tag is not in use in any of our core templates.


(cherry picked from commit 4dff1a1e5b)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-10-02 20:06:10 +00:00
Mario
888ee16d52 fix german about page title
(cherry picked from commit 1c45030c58)

Co-authored-by: Mario <mario@mariovavti.com>
2024-10-02 20:05:06 +00:00
Mario
0f3e01f343 markdown: Don't link URLs in code blocks.
When passing a content throught the `markdown_to_bb` function
to convert any markdown in the content, any recognized URLs in the
content would be converted to BBCode links as a post processing step
after the main conversion.

After commit a1ccacb825 this did no longer
consider content within code blocks, and would thus convert them as
to BBCode links.

Example: The following content

	[code]
	example url: https://example.com
	[/code]

Would be converted to

	[code]
	example url: [url=https://example.com]https://example.com[/url]
	[/code]

Prior to commit a1ccacb825, code blocks
would be protected, so this would not happen.

This patch removes the post processing step for converting plain URLs to
links completely from this routine. This functionality is in any case
covered in the actual BBCode parser where it belongs.

This will have some other side effects as well, such as images and links
created using Markdown, will not be converted to [zmg] or [zrl] tags
where that would be done automatically before. If you intend to use a
[zrl] or [zmg] tag, you now need to do so explicitly.


(cherry picked from commit 803cd74b48)

Co-authored-by: Harald Eilertsen <haraldei@anduin.net>
2024-10-02 20:04:30 +00:00
Mario
79220ede66 rewrite sql logic to rename photos - there are more DB queries involved now but the previous logic was throwing error in postgresql (while the result was correct anyway)
(cherry picked from commit a5f0253aef)

Co-authored-by: Mario Vavti <mario@mariovavti.com>
2024-10-02 20:03:54 +00:00
Mario
6b98b799c8 Merge branch 'tests-for-activitystreams' into 'dev'
tests: Add a basic test for ActivityStreams

See merge request hubzilla/core!2146
2024-10-02 13:13:42 +00:00
Mario
9f49d313f5 Merge branch 'markdown/dont-link-urls-in-code-blocks' into 'dev'
markdown: Don't link URLs in code blocks.

See merge request hubzilla/core!2145
2024-10-02 13:10:05 +00:00
Mario Vavti
a5f0253aef rewrite sql logic to rename photos - there are more DB queries involved now but the previous logic was throwing error in postgresql (while the result was correct anyway) 2024-10-02 14:45:10 +02:00
Harald Eilertsen
4e6f871bc4 tests: Add a basic test for ActivityStreams
This is just a basic test that parses a specific object, and tests that
all the referenced objects are fetched from the originating servers.
2024-10-02 09:51:22 +02:00
Harald Eilertsen
803cd74b48 markdown: Don't link URLs in code blocks.
When passing a content throught the `markdown_to_bb` function
to convert any markdown in the content, any recognized URLs in the
content would be converted to BBCode links as a post processing step
after the main conversion.

After commit a1ccacb825 this did no longer
consider content within code blocks, and would thus convert them as
to BBCode links.

Example: The following content

	[code]
	example url: https://example.com
	[/code]

Would be converted to

	[code]
	example url: [url=https://example.com]https://example.com[/url]
	[/code]

Prior to commit a1ccacb825, code blocks
would be protected, so this would not happen.

This patch removes the post processing step for converting plain URLs to
links completely from this routine. This functionality is in any case
covered in the actual BBCode parser where it belongs.

This will have some other side effects as well, such as images and links
created using Markdown, will not be converted to [zmg] or [zrl] tags
where that would be done automatically before. If you intend to use a
[zrl] or [zmg] tag, you now need to do so explicitly.
2024-09-30 13:54:50 +02:00
Mario
0bfdb958f5 update symfony/polyfill-php81 2024-09-30 07:13:55 +00:00
Mario
becd4c6ffd update sabre/vobject 2024-09-30 07:12:30 +00:00
Mario
3f411787c1 update spomky-labs/otphp 2024-09-30 07:11:05 +00:00
Mario
5782a674b0 update ramsey/uuid 2024-09-30 07:09:20 +00:00
Mario
fc79e47d88 update scssphp 2024-09-30 07:07:30 +00:00
Mario
1c45030c58 fix german about page title 2024-09-30 06:29:37 +00:00
Mario
18f3887050 Merge branch 'more-help-improvements' into 'dev'
Fix help for other languages than english

See merge request hubzilla/core!2144
2024-09-30 06:22:28 +00:00
Mario
2cc962e53a Merge branch 'security/update/smarty' into 'dev'
deps: Upgrade smarty/smarty to version 4.5.4

See merge request hubzilla/core!2143
2024-09-30 06:20:48 +00:00
Harald Eilertsen
5b93aa1148 Tests: Unbreak help test. 2024-09-29 14:28:17 +02:00
Harald Eilertsen
4daa03f025 Help: Drop language specifier in URL when redirecting
This finally fixes the help for languages other than english.
2024-09-29 14:09:41 +02:00
Harald Eilertsen
8ae9df3bb7 Replace drop shadow in help toc with brighter color.
The drop shadow looked terrible in dark mode. While that could be fixed,
I think it looks better with just using the link hover color and making
the selected item bold.
2024-09-29 14:00:53 +02:00
Harald Eilertsen
25d9d3ba1b Move some help related styling from redbasic to module css. 2024-09-29 14:00:53 +02:00
Harald Eilertsen
26ce231951 Use html details element for toc on top of help pages.
This allows us to get rid of some more unneccessary JavaScript that just
implements stuff that web browsers now do anyways.
2024-09-29 14:00:45 +02:00
Harald Eilertsen
fb9464437e Remove link to "Contents" from the help table of contect sidebar.
Changes the element where the jQuery.toc plugin looks for headings to
only include the actual help contents, not the toc itself.
2024-09-29 13:58:41 +02:00
Harald Eilertsen
4dff1a1e5b deps: Upgrade smarty/smarty to version 4.5.4
This eliminates a potential vulnerability where an template author could
inject arbitrary PHP files to be run via the 'extends' tag.

See:
  - https://github.com/smarty-php/smarty/security/advisories/GHSA-4rmg-292m-wg3w
  - 0be92bc8a6

Impact assessment:

In our case I would consider this a low severity issue as we don't
allow users to dynamically add or edit smarty templates. Templates has
to be updated via merge requests, or by installing a theme. In both
cases a malicious attacker already has easier ways to inject whatever
code they want.

Further, the extend tag is not in use in any of our core templates.
2024-09-28 15:07:23 +02:00
Mario
b498e50f74 adjust post app icon and remove obsolete arguments
(cherry picked from commit 5cbd42bbc4)

Co-authored-by: Mario <mario@mariovavti.com>
2024-09-27 16:51:57 +00:00
Mario
2c05638776 Merge branch 'cherry-pick-d1811ea1' into 'dev'
Update Spanish strings

See merge request hubzilla/core!2142
2024-09-27 16:39:24 +00:00
Mario
5cbd42bbc4 adjust post app icon and remove obsolete arguments 2024-09-27 16:36:25 +00:00
Manuel Jiménez Friaza
ac6720e118 Update Spanish strings
(cherry picked from commit d1811ea1f3f7249023c51104154d680f09df8572)

Co-authored-by: mjfriaza:4GF~eYj,-iAv <mjfriaza@disroot.org>
2024-09-27 15:36:32 +00:00
Mario
8c87b06caa Merge branch '9.4RC' 2024-09-25 19:39:51 +00:00
Mario
339e702beb version 9.4 2024-09-25 19:38:12 +00:00
Mario
8750c5f7bc update changelog
(cherry picked from commit 5281f4dd9b)

Co-authored-by: Mario <mario@mariovavti.com>
2024-09-25 19:36:46 +00:00
Mario
5281f4dd9b update changelog 2024-09-25 19:35:01 +00:00
Mario
c3b4397ea3 update changelog
(cherry picked from commit 424b31b7f0)

Co-authored-by: Mario <mario@mariovavti.com>
2024-09-25 09:48:57 +00:00
Mario
c12ef4fbf4 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-09-25 09:47:21 +00:00
Mario
424b31b7f0 update changelog 2024-09-25 09:46:57 +00:00
Mario
20ee1a5b5b Merge branch 'remove-tests-from-autoload' into 'dev'
Don't autoload test cases using composer.

See merge request hubzilla/core!2141
2024-09-25 08:40:45 +00:00
Harald Eilertsen
2cd779cbe9 Don't autoload test cases using composer.
Introduces a bootstrap file that ensures that the base test case classes
are loaded and available instead.

This reduces the number of warnings when running composer install.
2024-09-24 13:54:42 +02:00
Mario
a3f1189df7 Merge branch 'dev' into 9.4RC 2024-09-24 09:26:12 +00:00
Mario
2bc088e555 mod help: only abort requests without topic if we have not got a search request 2024-09-24 09:24:56 +00:00
Mario
67d8b977b6 version 9.4RC1 2024-09-24 08:59:26 +00:00
Mario
5b1e532791 Merge branch 'dev' into 9.4RC 2024-09-24 08:58:33 +00:00
Mario
0e1bf2cef0 update changelog 2024-09-24 08:58:06 +00:00
Mario
4f129e05e5 notes: make sure we set App::$profile_uid in the module - issue #1865 and minor code cleanup
(cherry picked from commit 3733a80c1d)

Co-authored-by: Mario Vavti <mario@mariovavti.com>
2024-09-22 15:26:52 +00:00
Mario Vavti
3733a80c1d notes: make sure we set App::$profile_uid in the module - issue #1865 and minor code cleanup 2024-09-22 17:24:28 +02:00
Mario Vavti
220571d2a9 bump dev version 2024-09-20 13:04:50 +02:00
Mario Vavti
f6b9a1dd3c version 9.4RC, strings, autoload dump 2024-09-20 12:59:36 +02:00
Mario
393d5020f8 changelog 2024-09-20 11:21:51 +02:00
Mario
06ac41c005 whitespace 2024-09-19 06:59:55 +00:00
Mario
39ee872f49 prefer token if available 2024-09-19 06:59:27 +00:00
Mario
a7c51f5d65 display title only for toplevel items 2024-09-18 19:59:33 +00:00
Mario
5309c032db Adjust fix_attached_permissions() so that if we got a token, we will just add the token to the original ACL instead of rewriting the ACL to theitem ACL - it probably makes much more sense that way 2024-09-18 19:53:07 +00:00
Mario
176298ffeb remove garbage 2024-09-18 15:09:56 +00:00
Mario
fdf19e659e not yet ready for primetime 2024-09-18 15:09:10 +00:00
Mario
e799589781 allow uploading to comments if ocap tokens are enabled 2024-09-18 09:34:10 +00:00
Mario
10acf90d06 refactor get_security_ids() to remove some legacy code from the zot/zot6 transition and re-add scope sql to item_permissions_sql() 2024-09-18 08:48:25 +00:00
Mario
b184533115 fa2bi fixes 2024-09-05 13:26:13 +00:00
Mario
b50e06a9d9 fa2bi fixes 2024-08-28 08:44:32 +00:00
Mario
66901dbe3e fa2bi fixes 2024-08-09 09:55:18 +00:00
Mario
4a7879aad2 fa2bi fixes 2024-08-09 09:08:33 +00:00
Mario
30aa0e3822 fa2bi fixes 2024-08-09 08:56:52 +00:00
Mario
cadc7ee29e bump version 2024-08-08 20:43:51 +00:00
Mario
5a44b8c40c remove fork awesome 2024-08-08 20:42:51 +00:00
Mario
487e68ebd1 fa2bi fix 2024-08-08 20:40:17 +00:00
Mario
6cdbc28d79 missing class 2024-08-08 16:14:08 +00:00
Mario
4113bea104 fa2bi fixes 2024-08-05 10:03:09 +00:00
Mario
294359d7f5 improved content and comment collapse/expand rendering 2024-08-04 13:40:22 +00:00
Mario
8ff870482f add support for inbound locations 2024-08-02 16:56:59 +00:00
Mario
56cb6f1034 streamline location rendering 2024-08-02 16:02:29 +00:00
Mario
7eb23aa8b8 fa2bi fixes 2024-08-02 15:08:27 +00:00
Mario
c793cea2f0 fa2bi: catch some remains 2024-08-02 08:50:50 +00:00
Mario
4e19f1c8be fa2bi: fix directory sort icon 2024-08-02 08:19:08 +00:00
Mario
3d3fcd7334 fa2bi: some sed woodoo on templates and manual fixes in js and php files 2024-08-02 08:06:15 +00:00
Mario
61c03e4b4e fix html2bbcode table and add test 2024-08-02 07:17:54 +00:00
Mario
dd0be272d0 fa2bi continued 2024-07-31 19:24:36 +00:00
Mario
b781739949 fa2bi continued 2024-07-31 13:53:09 +00:00
Mario
2221d8dd12 fa2bi continued 2024-07-30 15:11:08 +00:00
Mario
d67a0b14e3 fa2bi continued 2024-07-30 15:10:47 +00:00
Mario
b838632318 fa2bi continued 2024-07-30 15:10:32 +00:00
Mario
8c38466b75 fa2bi continued 2024-07-30 14:40:33 +00:00
Mario
2919b36e91 streamline calendar icon 2024-07-30 11:39:58 +00:00
Mario
52f7b508af Merge branch 'improve-help-locale-handling' into 'dev'
Improve handling of locale in Help module

See merge request hubzilla/core!2140
2024-07-29 09:59:04 +00:00
Mario
15f6bc93cf minor line height fix 2024-07-29 09:56:15 +00:00
Mario
8c4269d037 fa2bi continued 2024-07-29 09:38:51 +00:00
Mario
7394c97f23 simplified syntax 2024-07-29 07:57:47 +00:00
Mario
33e45d98a3 fa2bi adjustions 2024-07-28 18:49:04 +00:00
Mario
241cc1ad63 storing info and notice messages in the session has some disadvantages if the functions are called via ajax. revert to storing them in xconfig. 2024-07-28 18:44:07 +00:00
Mario
b26db5bde6 fa2bi more fix notifications 2024-07-24 21:04:22 +00:00
Mario
9be799de15 fa2bi fix notifications 2024-07-24 20:09:07 +00:00
Mario
014737fe21 fa2bi fixes 2024-07-24 18:26:50 +00:00
Harald Eilertsen
d3093dce1b Improve translation message for help pages.
Display the target language instead of "your preferred language". Makes
it a bit more explicit.
2024-07-24 11:57:41 +02:00
Harald Eilertsen
61f9ad8274 Add a notice to help pages when defaulting to english. 2024-07-24 11:46:18 +02:00
Harald Eilertsen
7067a0adc2 Move language member to HelpHelperTrait.
Should have been there from the start, was just a miss.
2024-07-24 10:59:03 +02:00
Mario
eb8cab37f3 bi adjustments 2024-07-24 08:01:38 +00:00
Mario
467e0b32b4 fa2bi and a php error in mod appman 2024-07-23 22:08:42 +00:00
Mario
204d91c3c3 this will be a longer journey - we will start to use bootstrap icons now since forkawesome is dead 2024-07-23 18:07:30 +00:00
Harald Eilertsen
1bd52867fb Fallback to english help topic if localized topic is not found. 2024-07-23 18:52:12 +02:00
Harald Eilertsen
898fb4f800 Refactor HelpTest.php.
Move default stubs to a function to make them reusable.
2024-07-23 18:51:22 +02:00
Harald Eilertsen
63a01c0214 Replace $Projectname in help index/toc file. 2024-07-23 18:47:39 +02:00
Mario
39933052a9 do not run set_linkified_perms() if editing an existing post 2024-07-23 14:40:36 +00:00
Mario
719dbf091a some cleanup 2024-07-23 14:17:06 +00:00
Mario
2dad3a8fe5 the tag_deliver permission is not used anymore 2024-07-23 14:00:07 +00:00
Mario
d99ba64206 make sure to failà the tgroup_check() for group posts if they do not have the post_wall permission. 2024-07-23 13:11:24 +00:00
Harald Eilertsen
202b797fe6 Remove language selector from help pages.
It is not in sync with the languages available for the rest of the
Hubzilla UI, so it was confusing and in the way of just supporting
localized help using the same mechanism as the rest of the code.

Also allowed deleting a good chunck of javascript from the help logic.
2024-07-23 13:26:44 +02:00
Harald Eilertsen
9df96fa03b Don't modify address bar when loading help topic.
Modifying the current URL like this causes several problems, and is imo
bad practice.

When requesting a help topic without specifying the language in the URL
(like `help/member/member_guide`) the locale for the current channel is
used to fetch the topic.

On the other hand, if fetching a topic with the language in the URL, the
detected language will be used. Since the channel locale may not match
the locale supported by the help system, weird situations may arise.
I.e. fetching the topic without language in the URL works, but as the
URL has now been rewritten, reloading the page will fail with a 404
status.

Being a bit less clever solves this issue, and leaves the web browser to
behave more as expected by the user.
2024-07-23 12:56:48 +02:00
Harald Eilertsen
7afb01e488 Redirect help to about page when locale but no topic specified in URL 2024-07-23 12:24:42 +02:00
Mario
ae140465d7 only allow repeats if we are the profile owner and minor code simplification 2024-07-23 08:44:18 +00:00
Mario
475cbf6510 more fix logic 2024-07-22 21:32:24 +00:00
Mario
39e5e29ce5 fix logic and add translateable strings 2024-07-22 21:19:28 +00:00
Mario
f4ffef967a undo announce is not yet supported - hide it in the UI until it is 2024-07-22 20:26:14 +00:00
Mario
77a6a21ea2 bump version 2024-07-22 19:25:26 +00:00
Mario
4e35d34226 item buttons redesign - initial checkin 2024-07-22 19:07:19 +00:00
Mario
3708896a65 Merge branch 'dev' into 'dev'
Added util/update_db

See merge request hubzilla/core!2139
2024-07-22 07:03:51 +00:00
Dale Hitchenor
7c3f28f9d2 Added util/update_db 2024-07-22 07:03:51 +00:00
Mario
afc8b88933 Merge branch 'dev' into 'dev'
Added util/update_db

See merge request hubzilla/core!2139
2024-07-22 06:56:17 +00:00
Dale Hitchenor
4668178dee Added util/update_db 2024-07-22 06:56:16 +00:00
Mario
bfec7b6901 Merge branch 'dev' into 'dev'
Added util/update_db

See merge request hubzilla/core!2139
2024-07-22 06:55:43 +00:00
Dale Hitchenor
f026afe11c Added util/update_db 2024-07-22 06:55:43 +00:00
Mario
f388fcaf08 Merge branch 'dev' into 'dev'
Added util/update_db

See merge request hubzilla/core!2139
2024-07-22 06:53:27 +00:00
Dale Hitchenor
9bd2b3ab17 Added util/update_db 2024-07-22 06:53:25 +00:00
Mario
2d0b216a2c version 2024-07-20 18:01:17 +00:00
Mario
c5bca0279c Revert "Revert "sse: reset session after connection aborted""
This reverts commit c71eb401c0
2024-07-20 13:09:05 +00:00
Mario
3fca63a15f Revert "Revert "more work on sse sys messages""
This reverts commit c22f633ae0
2024-07-20 13:08:52 +00:00
Mario
c47900f366 Revert "sse: more work on notifications"
This reverts commit 82f69018a6
2024-07-20 13:08:31 +00:00
Mario
84f64214c3 Revert "sse: add pdl files"
This reverts commit 1055718935
2024-07-20 13:08:04 +00:00
Mario
9cd01e2e13 Revert "sse: add pdl files"
This reverts commit 2461e709d2
2024-07-20 13:07:49 +00:00
Mario
841b4f7d81 Revert "sse: add pdl files"
This reverts commit 6276f36b90
2024-07-20 13:07:32 +00:00
Mario
70212cdb59 Revert "version"
This reverts commit 5f77e9f4ce
2024-07-20 13:07:07 +00:00
Mario
5f77e9f4ce version 2024-07-20 10:17:12 +00:00
Mario
6276f36b90 sse: add pdl files 2024-07-20 10:16:32 +00:00
Mario
2461e709d2 sse: add pdl files 2024-07-20 10:16:24 +00:00
Mario
1055718935 sse: add pdl files 2024-07-20 10:16:13 +00:00
Mario
82f69018a6 sse: more work on notifications 2024-07-20 10:15:44 +00:00
Mario
c22f633ae0 Revert "more work on sse sys messages"
This reverts commit 983fc84f28
2024-07-20 10:00:47 +00:00
Mario
c71eb401c0 Revert "sse: reset session after connection aborted"
This reverts commit 3d03c24f06
2024-07-20 10:00:14 +00:00
Mario
5a1079750e bump version 2024-07-20 07:09:27 +00:00
Mario
3d03c24f06 sse: reset session after connection aborted 2024-07-19 23:14:47 +00:00
Mario
983fc84f28 more work on sse sys messages 2024-07-19 19:35:21 +00:00
Mario
1861eeeb0a more f arg removal 2024-07-19 11:55:21 +00:00
Mario Vavti
663aeca2a7 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2024-07-19 13:54:16 +02:00
Mario Vavti
526730672a use the same url for attachment and body. otherwise we can not deduplicate at the receiving side. 2024-07-19 13:53:58 +02:00
Mario
7f292d4765 remove unused functions and start removing the ominous f argument 2024-07-19 09:12:50 +00:00
Mario
99bff67168 version 9.2.1 2024-07-18 08:55:07 +00:00
Mario
bb3caeb629 Merge branch 'dev' 2024-07-18 08:54:21 +00:00
Mario
65185a70d5 changelog 2024-07-18 08:52:28 +00:00
Mario
6d1f34284b bump version 2024-07-17 14:58:49 +00:00
Mario
2cfdbbd956 sse: revert removing of reset after 30 seconds and save a db lookup if we have just reset 2024-07-17 14:34:46 +00:00
Mario
5f66ad5bc5 fix php warning 2024-07-17 13:22:17 +00:00
Mario
aff11443b4 gd: check if function exists - obviously this can change after the initial install where we check this 2024-07-17 13:17:30 +00:00
Mario
6ced7ecf89 missing pdl for mod import 2024-07-15 10:34:43 +00:00
Mario
2d467a15ba dbesc the workinfo json 2024-07-15 10:29:12 +00:00
Mario
28c8229218 always use ob_end_flush() and reduce code duplication 2024-07-15 10:16:54 +00:00
Mario
0bcecc4baa make sure we always have an object which was not the case when repeating one of our own items 2024-07-15 10:12:02 +00:00
Mario
78e68519e8 do not handle non sys notifications if we are in sys only mode 2024-07-10 08:52:23 +00:00
Mario
d2b06995c7 more work on making sure system notifications appear on page reload 2024-07-10 08:40:51 +00:00
Mario
5cbae0fb81 improve handling of sse especially in relation with page reloads 2024-07-08 20:35:08 +00:00
Mario
2ddc087512 notifications: provide possibility to only display system notofications 2024-07-07 13:24:26 +00:00
Mario
b0fe94b4b3 adjust release date 2024-07-06 11:29:36 +00:00
4974 changed files with 105537 additions and 73266 deletions

View File

@@ -48,6 +48,10 @@
<exclude name="Generic.Files.OneClassPerFile.MultipleFound"/>
<exclude name="Generic.Files.OneObjectStructurePerFile.MultipleFound"/>
<exclude name="Generic.Formatting.SpaceAfterCast.NoSpace"/>
<exclude name="Generic.Classes.OpeningBraceSameLine.BraceOnNewLine" />
<exclude name="Generic.WhiteSpace.DisallowSpaceIndent.SpacesUsed" />
<exclude name="Generic.Functions.OpeningFunctionBraceKernighanRitchie.BraceOnNewLine" />
</rule>
<!--

153
CHANGELOG
View File

@@ -1,4 +1,155 @@
Hubzilla 9.2 (2024-??-??)
Hubzilla 10.0.3 (2024-12-26)
- Fix regression in Daemon/Channel_purge which could cause a possible infinite loop
- Fix regression in Daemon/Expire which could cause a infinite loop
Hubzilla 10.0.2 (2024-12-25)
- Hotfix comment out Daemon/Expire
- Fix zid parameter allowed to override an existing remote login
- Slightly improved imagesLoaded()
Hubzilla 10.0.1 (2024-12-22)
- Revert removing of openid library
- Fix SQL query in Daemon/Importdoc
Hubzilla 10.0 (2024-12-21)
- Port updateConvItem() and notifications widget to vanilla javascript
- Remove jquery.timeago.js in favor of a native js implementation
- Introduce item_forwardable() a function to check if an item should be frowarded
- Always set item_delayed flag if we use a custom created date
- Add indicators to items in case they are delayed, have an expiration time or commenting is disabled
- Introduce relative_time() a new function to calculate the relative time
- Refactor mod admin/accounts
- Toggle aside if a notification or message is clicked
- Add Mailer class to replace z_mail()
- Provide a possibility to link to a specific day or month in mod cal via URL fragment e.g. #2024-12-24
- Refactor mod magic
- Introduce conversation containers a.k.a. FEP-171b
- Refactor mod item
- Refactor Thumbs\Epubthumb to adapt to new version of EPub meta lib
- Remove unused libraries
- Bring filed items to mod hq
Bugfixes
- Fix comments on/off toggle
- Fix various missing icons after transition from fork-awesome
- Fix performance issue in mod pubstream
- Fix mails with + in local part rejected
- Fix % calculation in mod import_progress
- Fix query vars not unset when constructing the server address
- Fix can_comment_on_post() logic after introduction of repeats
- Fix xchan_query() not including deleted hublocs
- Fix allday variable not set when clicking an event or a resource is provided
Addons
- Introduce conversation containers a.k.a. FEP-171b
- Cards: fix comments on/off state
- Articles: fix comments on/off state
- Pubcrawl: fix encoding of stored raw message
- Gallery fix zoom icon toggle
- Pubcrawl: fix follow to non primary hub location
- Pubcrawl: rewrite id host to local host instead of primary host
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
- Fix missing handle icon in mod pdledit_gui
Hubzilla 9.4.1 (2024-10-02)
- Various fixes for the help module
- Update smarty library via composer
- Fix URLs replaced with bbcode in codeblocks if markdown enabled
- Fix unable to move multiple files when using postgresql DB backend
- Adjust icon for post app
- Fix check for while loop in wiki addon
Hubzilla 9.4 (2024-09-25)
- If we got an ocap token try to authenticate with it first
- Hide comment titles
- Adjust fix_attached_permissions() to only add the token if we got one
- Allow uploading to comments if ocap tokens are enabled
- Refactor get_security_ids() to remove legacy code
- Add privacy scope sql to item_permissions_sql()
- Removed fork awesome in favour of bootstrap icons
- Improved content and comment collapse/expand rendering
- Add support for inbound locations
- Streamline item location rendering (use icon)
- Fix html2bbcode table and add test
- Store info/notice messages in xconfig instead of session
- Refactor help and add tests
- Do not run set_linkified_perms() if editing a post
- Remove deprecated tag_deliver permissions
- Make sure that tgroup_check() fails for group posts if they do not have the post_wall permission
- Show repeat button to channel owners only
- Refactor item buttons
- Add util/update_db
- Remove the unused f argument in various places
- Streamline URLs used in attachments and body to ease deduplication
- Code cleanup and remove some unused/deprecated functions
Bugfixes
- Fix broken help pages search
- Fix notes app not displaying anything - issue #1865
Addons
- Cards: fix decoding issue when editing and minor cleanup
- Articles: fix decoding issue when editing and minor cleanup
- Wiki: fix markdown content not unescaped when undoing history - issue #1864
- Gallery: update to photoswipe 5.4.4
- Openstreemap: streamline location rendering
- Socialauth: update version and contact details
- Socialauth: fix rendering issue
Hubzilla 9.2.1 (2024-07-18)
- Fix fatal error if gd function image{jpeg, png, webp}() does not exist for some reason
- Add missing pdl for mod import
- Escape queueworker json data
- Fix missing object when repeating own posts
- Improve display of system notifications in relation with page reloads
- Add possibility to only display system notifications with notifications widget
- Fix layout issue with socialauth addon
- Save a db lookup if we have just reset notifications in sse addon
- Fix php error if attachment was an empty string in pubcrawl addon
Hubzilla 9.2 (2024-07-06)
- Fail to import more gracefully if a channel has already been imported at some point but was deleted again
- Use the doubleleft template by default for admin pages to work around some display issues
- Reflect the censored state in the local xchan

View File

@@ -0,0 +1,776 @@
<?php
namespace Zotlabs\ActivityStreams;
use Zotlabs\Lib\BaseObject;
class ASObject extends BaseObject
{
public $id;
public $type;
public $attachment;
public $attributedTo;
public $audience;
public $content;
public $context;
public $name;
public $endTime;
public $generator;
public $icon;
public $image;
public $inReplyTo;
public $location;
public $preview;
public $published;
public $replies;
public $startTime;
public $summary;
public $tag;
public $updated;
public $url;
public $to;
public $bto;
public $cc;
public $bcc;
public $mediaType;
public $duration;
public $source;
// Extension properties
public $signature;
public $proof;
public $sensitive;
public $replyTo;
public $wall;
public $isContainedConversation;
public $expires;
public $canReply;
public $canSearch;
public $directMessage;
public $commentPolicy;
/**
* @return mixed
*/
public function getDirectMessage()
{
return $this->directMessage;
}
/**
* @param mixed $directMessage
* @return ASObject
*/
public function setDirectMessage($directMessage)
{
$this->directMessage = $directMessage;
return $this;
}
/**
* @return mixed
*/
public function getSignature()
{
return $this->signature;
}
/**
* @param mixed $signature
* @return ASObject
*/
public function setSignature($signature)
{
$this->signature = $signature;
return $this;
}
/**
* @return mixed
*/
public function getProof()
{
return $this->proof;
}
/**
* @param mixed $proof
* @return ASObject
*/
public function setProof($proof)
{
$this->proof = $proof;
return $this;
}
/**
* @return mixed
*/
public function getSensitive()
{
return $this->sensitive;
}
/**
* @param mixed $sensitive
* @return ASObject
*/
public function setSensitive($sensitive)
{
$this->sensitive = $sensitive;
return $this;
}
/**
* @return mixed
*/
public function getReplyTo()
{
return $this->replyTo;
}
/**
* @param mixed $replyTo
* @return ASObject
*/
public function setReplyTo($replyTo)
{
$this->replyTo = $replyTo;
return $this;
}
/**
* @return mixed
*/
public function getWall()
{
return $this->wall;
}
/**
* @param mixed $wall
* @return ASObject
*/
public function setWall($wall)
{
$this->wall = $wall;
return $this;
}
/**
* @return mixed
*/
public function getIsContainedConversation()
{
return $this->isContainedConversation;
}
/**
* @param mixed $isContainedConversation
* @return ASObject
*/
public function setIsContainedConversation($isContainedConversation)
{
$this->isContainedConversation = $isContainedConversation;
return $this;
}
/**
* @return mixed
*/
public function getExpires()
{
return $this->expires;
}
/**
* @param mixed $expires
* @return ASObject
*/
public function setExpires($expires)
{
$this->expires = $expires;
return $this;
}
/**
* @return mixed
*/
public function getCanReply()
{
return $this->canReply;
}
/**
* @param mixed $canReply
* @return ASObject
*/
public function setCanReply($canReply)
{
$this->canReply = $canReply;
return $this;
}
/**
* @return mixed
*/
public function getCanSearch()
{
return $this->canSearch;
}
/**
* @param mixed $canSearch
* @return ASObject
*/
public function setCanSearch($canSearch)
{
$this->canSearch = $canSearch;
return $this;
}
/**
* @return mixed
*/
public function getCommentPolicy()
{
return $this->commentPolicy;
}
/**
* @param mixed $commentPolicy
* @return ASObject
*/
public function setCommentPolicy($commentPolicy)
{
$this->commentPolicy = $commentPolicy;
return $this;
}
/**
* @return mixed
*/
public function getId()
{
return $this->id;
}
/**
* @param mixed $id
* @return ASObject
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* @return mixed
*/
public function getType()
{
return $this->type;
}
/**
* @param mixed $type
* @return ASObject
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* @return mixed
*/
public function getAttachment()
{
return $this->attachment;
}
/**
* @param mixed $attachment
* @return ASObject
*/
public function setAttachment($attachment)
{
$this->attachment = $attachment;
return $this;
}
/**
* @return mixed
*/
public function getAttributedTo()
{
return $this->attributedTo;
}
/**
* @param mixed $attributedTo
* @return ASObject
*/
public function setAttributedTo($attributedTo)
{
$this->attributedTo = $attributedTo;
return $this;
}
/**
* @return mixed
*/
public function getAudience()
{
return $this->audience;
}
/**
* @param mixed $audience
* @return ASObject
*/
public function setAudience($audience)
{
$this->audience = $audience;
return $this;
}
/**
* @return mixed
*/
public function getContent()
{
return $this->content;
}
/**
* @param mixed $content
* @return ASObject
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* @return mixed
*/
public function getContext()
{
return $this->context;
}
/**
* @param mixed $context
* @return ASObject
*/
public function setContext($context)
{
$this->context = $context;
return $this;
}
/**
* @return mixed
*/
public function getName()
{
return $this->name;
}
/**
* @param mixed $name
* @return ASObject
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* @return mixed
*/
public function getEndTime()
{
return $this->endTime;
}
/**
* @param mixed $endTime
* @return ASObject
*/
public function setEndTime($endTime)
{
$this->endTime = $endTime;
return $this;
}
/**
* @return mixed
*/
public function getGenerator()
{
return $this->generator;
}
/**
* @param mixed $generator
* @return ASObject
*/
public function setGenerator($generator)
{
$this->generator = $generator;
return $this;
}
/**
* @return mixed
*/
public function getIcon()
{
return $this->icon;
}
/**
* @param mixed $icon
* @return ASObject
*/
public function setIcon($icon)
{
$this->icon = $icon;
return $this;
}
/**
* @return mixed
*/
public function getImage()
{
return $this->image;
}
/**
* @param mixed $image
* @return ASObject
*/
public function setImage($image)
{
$this->image = $image;
return $this;
}
/**
* @return mixed
*/
public function getInReplyTo()
{
return $this->inReplyTo;
}
/**
* @param mixed $inReplyTo
* @return ASObject
*/
public function setInReplyTo($inReplyTo)
{
$this->inReplyTo = $inReplyTo;
return $this;
}
/**
* @return mixed
*/
public function getLocation()
{
return $this->location;
}
/**
* @param mixed $location
* @return ASObject
*/
public function setLocation($location)
{
$this->location = $location;
return $this;
}
/**
* @return mixed
*/
public function getPreview()
{
return $this->preview;
}
/**
* @param mixed $preview
* @return ASObject
*/
public function setPreview($preview)
{
$this->preview = $preview;
return $this;
}
/**
* @return mixed
*/
public function getPublished()
{
return $this->published;
}
/**
* @param mixed $published
* @return ASObject
*/
public function setPublished($published)
{
$this->published = $published;
return $this;
}
/**
* @return mixed
*/
public function getReplies()
{
return $this->replies;
}
/**
* @param mixed $replies
* @return ASObject
*/
public function setReplies($replies)
{
$this->replies = $replies;
return $this;
}
/**
* @return mixed
*/
public function getStartTime()
{
return $this->startTime;
}
/**
* @param mixed $startTime
* @return ASObject
*/
public function setStartTime($startTime)
{
$this->startTime = $startTime;
return $this;
}
/**
* @return mixed
*/
public function getSummary()
{
return $this->summary;
}
/**
* @param mixed $summary
* @return ASObject
*/
public function setSummary($summary)
{
$this->summary = $summary;
return $this;
}
/**
* @return mixed
*/
public function getTag()
{
return $this->tag;
}
/**
* @param mixed $tag
* @return ASObject
*/
public function setTag($tag)
{
$this->tag = $tag;
return $this;
}
/**
* @return mixed
*/
public function getUpdated()
{
return $this->updated;
}
/**
* @param mixed $updated
* @return ASObject
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* @return mixed
*/
public function getUrl()
{
return $this->url;
}
/**
* @param mixed $url
* @return ASObject
*/
public function setUrl($url)
{
$this->url = $url;
return $this;
}
/**
* @return mixed
*/
public function getTo()
{
return $this->to;
}
/**
* @param mixed $to
* @return ASObject
*/
public function setTo($to)
{
$this->to = $to;
return $this;
}
/**
* @return mixed
*/
public function getBto()
{
return $this->bto;
}
/**
* @param mixed $bto
* @return ASObject
*/
public function setBto($bto)
{
$this->bto = $bto;
return $this;
}
/**
* @return mixed
*/
public function getCc()
{
return $this->cc;
}
/**
* @param mixed $cc
* @return ASObject
*/
public function setCc($cc)
{
$this->cc = $cc;
return $this;
}
/**
* @return mixed
*/
public function getBcc()
{
return $this->bcc;
}
/**
* @param mixed $bcc
* @return ASObject
*/
public function setBcc($bcc)
{
$this->bcc = $bcc;
return $this;
}
/**
* @return mixed
*/
public function getMediaType()
{
return $this->mediaType;
}
/**
* @param mixed $mediaType
* @return ASObject
*/
public function setMediaType($mediaType)
{
$this->mediaType = $mediaType;
return $this;
}
/**
* @return mixed
*/
public function getDuration()
{
return $this->duration;
}
/**
* @param mixed $duration
* @return ASObject
*/
public function setDuration($duration)
{
$this->duration = $duration;
return $this;
}
/**
* @return mixed
*/
public function getSource()
{
return $this->source;
}
/**
* @param mixed $source
* @return ASObject
*/
public function setSource($source)
{
$this->source = $source;
return $this;
}
}

View File

@@ -0,0 +1,122 @@
<?php
namespace Zotlabs\ActivityStreams;
class Activity extends ASObject
{
public $actor;
public $object;
public $target;
public $result;
public $origin;
public $instrument;
/**
* @return mixed
*/
public function getActor()
{
return $this->actor;
}
/**
* @param mixed $actor
* @return Activity
*/
public function setActor($actor)
{
$this->actor = $actor;
return $this;
}
/**
* @return mixed
*/
public function getObject()
{
return $this->object;
}
/**
* @param mixed $object
* @return Activity
*/
public function setObject($object)
{
$this->object = $object;
return $this;
}
/**
* @return mixed
*/
public function getTarget()
{
return $this->target;
}
/**
* @param mixed $target
* @return Activity
*/
public function setTarget($target)
{
$this->target = $target;
return $this;
}
/**
* @return mixed
*/
public function getResult()
{
return $this->result;
}
/**
* @param mixed $result
* @return Activity
*/
public function setResult($result)
{
$this->result = $result;
return $this;
}
/**
* @return mixed
*/
public function getOrigin()
{
return $this->origin;
}
/**
* @param mixed $origin
* @return Activity
*/
public function setOrigin($origin)
{
$this->origin = $origin;
return $this;
}
/**
* @return mixed
*/
public function getInstrument()
{
return $this->instrument;
}
/**
* @param mixed $instrument
* @return Activity
*/
public function setInstrument($instrument)
{
$this->instrument = $instrument;
return $this;
}
}

View File

@@ -0,0 +1,428 @@
<?php
namespace Zotlabs\ActivityStreams;
class Actor extends ASObject
{
public $inbox;
public $outbox;
public $followers;
public $following;
public $permissions; /* extension property */
public $endpoints;
public $publicKey;
public $preferredUsername;
public $alsoKnownAs;
// Extension properties
public $movedTo;
public $copiedTo;
public $discoverable;
public $manuallyApprovesFollowers;
public $webfinger;
public $canSearch;
public $indexable;
public $assertionMethod;
public $gateways;
public $openwebauth;
public $authredirect;
/**
* @return mixed
*/
public function getAlsoKnownAs()
{
return $this->alsoKnownAs;
}
/**
* @param mixed $alsoKnownAs
* @return Actor
*/
public function setAlsoKnownAs($alsoKnownAs)
{
$this->alsoKnownAs = $alsoKnownAs;
return $this;
}
/**
* @return mixed
*/
public function getMovedTo()
{
return $this->movedTo;
}
/**
* @return mixed
*/
public function getCopiedTo()
{
return $this->copiedTo;
}
/**
* @param mixed $copiedTo
* @return Actor
*/
public function setCopiedTo($copiedTo)
{
$this->copiedTo = $copiedTo;
return $this;
}
/**
* @param mixed $movedTo
* @return Actor
*/
public function setMovedTo($movedTo)
{
$this->movedTo = $movedTo;
return $this;
}
/**
* @return mixed
*/
public function getDiscoverable()
{
return $this->discoverable;
}
/**
* @param mixed $discoverable
* @return Actor
*/
public function setDiscoverable($discoverable)
{
$this->discoverable = $discoverable;
return $this;
}
/**
* @return mixed
*/
public function getManuallyApprovesFollowers()
{
return $this->manuallyApprovesFollowers;
}
/**
* @param mixed $manuallyApprovesFollowers
* @return Actor
*/
public function setManuallyApprovesFollowers($manuallyApprovesFollowers)
{
$this->manuallyApprovesFollowers = $manuallyApprovesFollowers;
return $this;
}
/**
* @return mixed
*/
public function getPreferredUsername()
{
return $this->preferredUsername;
}
/**
* @param mixed $preferredUsername
* @return Actor
*/
public function setPreferredUsername($preferredUsername)
{
$this->preferredUsername = $preferredUsername;
return $this;
}
/**
* @return mixed
*/
public function getId()
{
return $this->id;
}
/**
* @param mixed $id
* @return Actor
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* @return mixed
*/
public function getType()
{
return $this->type;
}
/**
* @param mixed $type
* @return Actor
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* @return mixed
*/
public function getInbox()
{
return $this->inbox;
}
/**
* @param mixed $inbox
* @return Actor
*/
public function setInbox($inbox)
{
$this->inbox = $inbox;
return $this;
}
/**
* @return mixed
*/
public function getOutbox()
{
return $this->outbox;
}
/**
* @param mixed $outbox
* @return Actor
*/
public function setOutbox($outbox)
{
$this->outbox = $outbox;
return $this;
}
/**
* @return mixed
*/
public function getFollowers()
{
return $this->followers;
}
/**
* @param mixed $followers
* @return Actor
*/
public function setFollowers($followers)
{
$this->followers = $followers;
return $this;
}
/**
* @return mixed
*/
public function getFollowing()
{
return $this->following;
}
/**
* @param mixed $following
* @return Actor
*/
public function setFollowing($following)
{
$this->following = $following;
return $this;
}
/**
* @return mixed
*/
public function getEndpoints()
{
return $this->endpoints;
}
/**
* @param mixed $endpoints
* @return Actor
*/
public function setEndpoints($endpoints)
{
$this->endpoints = $endpoints;
return $this;
}
/**
* @return mixed
*/
public function getPublicKey()
{
return $this->publicKey;
}
/**
* @param mixed $publicKey
* @return Actor
*/
public function setPublicKey($publicKey)
{
$this->publicKey = $publicKey;
return $this;
}
/**
* @return mixed
*/
public function getWebfinger()
{
return $this->webfinger;
}
/**
* @param mixed $webfinger
* @return Actor
*/
public function setWebfinger($webfinger)
{
$this->webfinger = $webfinger;
return $this;
}
/**
* @return mixed
*/
public function getCanSearch()
{
return $this->canSearch;
}
/**
* @param mixed $canSearch
* @return Actor
*/
public function setCanSearch($canSearch)
{
$this->canSearch = $canSearch;
return $this;
}
/**
* @return mixed
*/
public function getIndexable()
{
return $this->indexable;
}
/**
* @param mixed $indexable
* @return Actor
*/
public function setIndexable($indexable)
{
$this->indexable = $indexable;
return $this;
}
/**
* @return mixed
*/
public function getAssertionMethod()
{
return $this->assertionMethod;
}
/**
* @param mixed $assertionMethod
* @return Actor
*/
public function setAssertionMethod($assertionMethod)
{
$this->assertionMethod = $assertionMethod;
return $this;
}
/**
* @return mixed
*/
public function getGateways()
{
return $this->gateways;
}
/**
* @param mixed $gateways
* @return Actor
*/
public function setGateways($gateways)
{
$this->gateways = $gateways;
return $this;
}
/**
* @return mixed
*/
public function getPermissions()
{
return $this->permissions;
}
/**
* @param mixed $permissions
* @return Actor
*/
public function setPermissions($permissions)
{
$this->permissions = $permissions;
return $this;
}
/**
* @return mixed
*/
public function getOpenwebauth()
{
return $this->openwebauth;
}
/**
* @param mixed $openwebauth
* @return Actor
*/
public function setOpenwebauth($openwebauth)
{
$this->openwebauth = $openwebauth;
return $this;
}
/**
* @return mixed
*/
public function getAuthredirect()
{
return $this->authredirect;
}
/**
* @param mixed $authredirect
* @return Actor
*/
public function setAuthredirect($authredirect)
{
$this->authredirect = $authredirect;
return $this;
}
}

View File

@@ -0,0 +1,87 @@
<?php
namespace Zotlabs\ActivityStreams;
class AssertionMethod extends ASObject
{
public $id;
public $type;
public $controller;
public $publicKeyMultibase;
/**
* @return mixed
*/
public function getId()
{
return $this->id;
}
/**
* @param mixed $id
* @return AssertionMethod
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* @return mixed
*/
public function getType()
{
return $this->type;
}
/**
* @param mixed $type
* @return AssertionMethod
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* @return mixed
*/
public function getController()
{
return $this->controller;
}
/**
* @param mixed $controller
* @return AssertionMethod
*/
public function setController($controller)
{
$this->controller = $controller;
return $this;
}
/**
* @return mixed
*/
public function getPublicKeyMultibase()
{
return $this->publicKeyMultibase;
}
/**
* @param mixed $publicKeyMultibase
* @return AssertionMethod
*/
public function setPublicKeyMultibase($publicKeyMultibase)
{
$this->publicKeyMultibase = $publicKeyMultibase;
return $this;
}
}

View File

@@ -0,0 +1,124 @@
<?php
namespace Zotlabs\ActivityStreams;
class Collection extends ASObject
{
public int $totalItems;
public string $current;
public string $first;
public string $last;
public array $items;
public mixed $collectionOf;
/**
* @return int
*/
public function getTotalItems(): int
{
return $this->totalItems;
}
/**
* @param mixed $totalItems
* @return Collection
*/
public function setTotalItems(mixed $totalItems): static
{
$this->totalItems = $totalItems;
return $this;
}
/**
* @return string
*/
public function getCurrent(): string
{
return $this->current;
}
/**
* @param mixed $current
* @return Collection
*/
public function setCurrent(mixed $current): static
{
$this->current = $current;
return $this;
}
/**
* @return string
*/
public function getFirst(): string
{
return $this->first;
}
/**
* @param mixed $first
* @return Collection
*/
public function setFirst(mixed $first): static
{
$this->first = $first;
return $this;
}
/**
* @return string
*/
public function getLast(): string
{
return $this->last;
}
/**
* @param mixed $last
* @return Collection
*/
public function setLast(mixed $last): static
{
$this->last = $last;
return $this;
}
/**
* @return array
*/
public function getItems(): array
{
return $this->items;
}
/**
* @param mixed $items
* @return Collection
*/
public function setItems(mixed $items): static
{
$this->items = $items;
return $this;
}
/**
* @return mixed
*/
public function getCollectionOf(): mixed
{
return $this->collectionOf;
}
/**
* @param mixed $collectionOf
* @return Collection
*/
public function setCollectionOf(mixed $collectionOf): static
{
$this->collectionOf = $collectionOf;
return $this;
}
}

View File

@@ -0,0 +1,73 @@
<?php
namespace Zotlabs\ActivityStreams;
class CollectionPage extends Collection
{
public $partOf;
public $next;
public $prev;
// startIndex only applies for OrderedCollectionPage. See
// https://www.w3.org/ns/activitystreams#OrderedCollectionPage
// It is provided here to avoid multiple inheritance
public $startIndex;
/**
* @return mixed
*/
public function getPartOf()
{
return $this->partOf;
}
/**
* @param mixed $partOf
* @return CollectionPage
*/
public function setPartOf($partOf)
{
$this->partOf = $partOf;
return $this;
}
/**
* @return mixed
*/
public function getNext()
{
return $this->next;
}
/**
* @param mixed $next
* @return CollectionPage
*/
public function setNext($next)
{
$this->next = $next;
return $this;
}
/**
* @return mixed
*/
public function getPrev()
{
return $this->prev;
}
/**
* @param mixed $prev
* @return CollectionPage
*/
public function setPrev($prev)
{
$this->prev = $prev;
return $this;
}
}

View File

@@ -0,0 +1,104 @@
<?php
namespace Zotlabs\ActivityStreams;
class IntransitiveActivity extends ASObject
{
public $actor;
public $target;
public $result;
public $origin;
public $instrument;
/**
* @return mixed
*/
public function getActor()
{
return $this->actor;
}
/**
* @param mixed $actor
* @return IntransitiveActivity
*/
public function setActor($actor)
{
$this->actor = $actor;
return $this;
}
/**
* @return mixed
*/
public function getTarget()
{
return $this->target;
}
/**
* @param mixed $target
* @return IntransitiveActivity
*/
public function setTarget($target)
{
$this->target = $target;
return $this;
}
/**
* @return mixed
*/
public function getResult()
{
return $this->result;
}
/**
* @param mixed $result
* @return IntransitiveActivity
*/
public function setResult($result)
{
$this->result = $result;
return $this;
}
/**
* @return mixed
*/
public function getOrigin()
{
return $this->origin;
}
/**
* @param mixed $origin
* @return IntransitiveActivity
*/
public function setOrigin($origin)
{
$this->origin = $origin;
return $this;
}
/**
* @return mixed
*/
public function getInstrument()
{
return $this->instrument;
}
/**
* @param mixed $instrument
* @return IntransitiveActivity
*/
public function setInstrument($instrument)
{
$this->instrument = $instrument;
return $this;
}
}

View File

@@ -0,0 +1,183 @@
<?php
namespace Zotlabs\ActivityStreams;
use Zotlabs\Lib\BaseObject;
class Link extends BaseObject
{
public $type;
public $href;
public $rel;
public $mediaType;
public $name;
public $hreflang;
public $height;
public $width;
public $preview;
/**
* @return mixed
*/
public function getType()
{
return $this->type;
}
/**
* @param mixed $type
* @return Link
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* @return mixed
*/
public function getHref()
{
return $this->href;
}
/**
* @param mixed $href
* @return Link
*/
public function setHref($href)
{
$this->href = $href;
return $this;
}
/**
* @return mixed
*/
public function getRel()
{
return $this->rel;
}
/**
* @param mixed $rel
* @return Link
*/
public function setRel($rel)
{
$this->rel = $rel;
return $this;
}
/**
* @return mixed
*/
public function getMediaType()
{
return $this->mediaType;
}
/**
* @param mixed $mediaType
* @return Link
*/
public function setMediaType($mediaType)
{
$this->mediaType = $mediaType;
return $this;
}
/**
* @return mixed
*/
public function getName()
{
return $this->name;
}
/**
* @param mixed $name
* @return Link
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* @return mixed
*/
public function getHreflang()
{
return $this->hreflang;
}
/**
* @param mixed $hreflang
* @return Link
*/
public function setHreflang($hreflang)
{
$this->hreflang = $hreflang;
return $this;
}
/**
* @return mixed
*/
public function getHeight()
{
return $this->height;
}
/**
* @param mixed $height
* @return Link
*/
public function setHeight($height)
{
$this->height = $height;
return $this;
}
/**
* @return mixed
*/
public function getWidth()
{
return $this->width;
}
/**
* @param mixed $width
* @return Link
*/
public function setWidth($width)
{
$this->width = $width;
return $this;
}
/**
* @return mixed
*/
public function getPreview()
{
return $this->preview;
}
/**
* @param mixed $preview
* @return Link
*/
public function setPreview($preview)
{
$this->preview = $preview;
return $this;
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Zotlabs\ActivityStreams;
class OrderedCollection extends Collection
{
}

View File

@@ -0,0 +1,92 @@
<?php
namespace Zotlabs\ActivityStreams;
/**
* According to the specification, OrderedCollectionPage extends
* both OrderedCollection and CollectionPage, but PHP is still a bit awkward
* when it comes to multiple inheritance. Rather than try and do this with
* traits, we'll just include the CollectionPage elements here - as this only
* consists of three properties.
*/
class OrderedCollectionPage extends OrderedCollection
{
public $partOf;
public $next;
public $prev;
public $startIndex;
/**
* @return mixed
*/
public function getPartOf()
{
return $this->partOf;
}
/**
* @param mixed $partOf
* @return OrderedCollectionPage
*/
public function setPartOf($partOf)
{
$this->partOf = $partOf;
return $this;
}
/**
* @return mixed
*/
public function getNext()
{
return $this->next;
}
/**
* @param mixed $next
* @return OrderedCollectionPage
*/
public function setNext($next)
{
$this->next = $next;
return $this;
}
/**
* @return mixed
*/
public function getPrev()
{
return $this->prev;
}
/**
* @param mixed $prev
* @return OrderedCollectionPage
*/
public function setPrev($prev)
{
$this->prev = $prev;
return $this;
}
/**
* @return mixed
*/
public function getStartIndex()
{
return $this->startIndex;
}
/**
* @param mixed $startIndex
* @return OrderedCollectionPage
*/
public function setStartIndex($startIndex)
{
$this->startIndex = $startIndex;
return $this;
}
}

View File

@@ -0,0 +1,125 @@
<?php
namespace Zotlabs\ActivityStreams;
class Place extends ASObject
{
public $accuracy;
public $altitude;
public $latitude;
public $longitude;
public $radius;
public $units;
/**
* @return mixed
*/
public function getAccuracy()
{
return $this->accuracy;
}
/**
* @param mixed $accuracy
* @return Place
*/
public function setAccuracy($accuracy)
{
$this->accuracy = $accuracy;
return $this;
}
/**
* @return mixed
*/
public function getAltitude()
{
return $this->altitude;
}
/**
* @param mixed $altitude
* @return Place
*/
public function setAltitude($altitude)
{
$this->altitude = $altitude;
return $this;
}
/**
* @return mixed
*/
public function getLatitude()
{
return $this->latitude;
}
/**
* @param mixed $latitude
* @return Place
*/
public function setLatitude($latitude)
{
$this->latitude = $latitude;
return $this;
}
/**
* @return mixed
*/
public function getLongitude()
{
return $this->longitude;
}
/**
* @param mixed $longitude
* @return Place
*/
public function setLongitude($longitude)
{
$this->longitude = $longitude;
return $this;
}
/**
* @return mixed
*/
public function getRadius()
{
return $this->radius;
}
/**
* @param mixed $radius
* @return Place
*/
public function setRadius($radius)
{
$this->radius = $radius;
return $this;
}
/**
* @return mixed
*/
public function getUnits()
{
return $this->units;
}
/**
* @param mixed $units
* @return Place
*/
public function setUnits($units)
{
$this->units = $units;
return $this;
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Zotlabs\ActivityStreams;
class Profile extends ASObject
{
public $describes;
/**
* @return mixed
*/
public function getDescribes()
{
return $this->describes;
}
/**
* @param mixed $describes
* @return Profile
*/
public function setDescribes($describes)
{
$this->describes = $describes;
return $this;
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace Zotlabs\ActivityStreams;
class PublicKey extends ASObject
{
public $owner;
public $signatureAlgorithm;
public $publicKeyPem;
/**
* @return mixed
*/
public function getOwner()
{
return $this->owner;
}
/**
* @param mixed $owner
* @return PublicKey
*/
public function setOwner($owner)
{
$this->owner = $owner;
return $this;
}
/**
* @return mixed
*/
public function getSignatureAlgorithm()
{
return $this->signatureAlgorithm;
}
/**
* @param mixed $signatureAlgorithm
* @return PublicKey
*/
public function setSignatureAlgorithm($signatureAlgorithm)
{
$this->signatureAlgorithm = $signatureAlgorithm;
return $this;
}
/**
* @return mixed
*/
public function getPublicKeyPem()
{
return $this->publicKeyPem;
}
/**
* @param mixed $publicKeyPem
* @return PublicKey
*/
public function setPublicKeyPem($publicKeyPem)
{
$this->publicKeyPem = $publicKeyPem;
return $this;
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace Zotlabs\ActivityStreams;
class Question extends ASObject
{
public $oneOf;
public $anyOf;
public $closed;
/**
* @return mixed
*/
public function getOneOf()
{
return $this->oneOf;
}
/**
* @param mixed $oneOf
* @return Question
*/
public function setOneOf($oneOf)
{
$this->oneOf = $oneOf;
return $this;
}
/**
* @return mixed
*/
public function getAnyOf()
{
return $this->anyOf;
}
/**
* @param mixed $anyOf
* @return Question
*/
public function setAnyOf($anyOf)
{
$this->anyOf = $anyOf;
return $this;
}
/**
* @return mixed
*/
public function getClosed()
{
return $this->closed;
}
/**
* @param mixed $closed
* @return Question
*/
public function setClosed($closed)
{
$this->closed = $closed;
return $this;
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace Zotlabs\ActivityStreams;
class Relationship extends ASObject
{
public $subject;
public $object;
public $relationship;
/**
* @return mixed
*/
public function getSubject()
{
return $this->subject;
}
/**
* @param mixed $subject
* @return Relationship
*/
public function setSubject($subject)
{
$this->subject = $subject;
return $this;
}
/**
* @return mixed
*/
public function getObject()
{
return $this->object;
}
/**
* @param mixed $object
* @return Relationship
*/
public function setObject($object)
{
$this->object = $object;
return $this;
}
/**
* @return mixed
*/
public function getRelationship()
{
return $this->relationship;
}
/**
* @param mixed $relationship
* @return Relationship
*/
public function setRelationship($relationship)
{
$this->relationship = $relationship;
return $this;
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace Zotlabs\ActivityStreams;
class Signature extends ASObject
{
public $nonce;
public $creator;
public $signatureValue;
/**
* @return mixed
*/
public function getCreator()
{
return $this->creator;
}
/**
* @param mixed $creator
* @return Signature
*/
public function setCreator($creator)
{
$this->creator = $creator;
return $this;
}
/**
* @return mixed
*/
public function getSignatureValue()
{
return $this->signatureValue;
}
/**
* @param mixed $signatureValue
* @return Signature
*/
public function setSignatureValue($signatureValue)
{
$this->signatureValue = $signatureValue;
return $this;
}
/**
* @return mixed
*/
public function getNonce()
{
return $this->nonce;
}
/**
* @param mixed $nonce
* @return Signature
*/
public function setNonce($nonce)
{
$this->nonce = $nonce;
return $this;
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace Zotlabs\ActivityStreams;
class Tombstone extends ASObject
{
public $formerType;
public $deleted;
/**
* @return mixed
*/
public function getFormerType()
{
return $this->formerType;
}
/**
* @param mixed $formerType
* @return Tombstone
*/
public function setFormerType($formerType)
{
$this->formerType = $formerType;
return $this;
}
/**
* @return mixed
*/
public function getDeleted()
{
return $this->deleted;
}
/**
* @param mixed $deleted
* @return Tombstone
*/
public function setDeleted($deleted)
{
$this->deleted = $deleted;
return $this;
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Zotlabs\ActivityStreams;
class UnhandledElementException extends \Exception
{
}

View File

@@ -24,7 +24,7 @@ class Channel_purge {
);
if ($r) {
foreach ($r as $rv) {
drop_item($rv['id'], false);
drop_item($rv['id'], $channel_id);
}
}
} while ($r);

View File

@@ -38,7 +38,13 @@ class Content_importer {
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512');
$x = z_fetch_url($hz_server . '/api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page,false,$redirects,[ 'headers' => $headers ]);
$redirects = 0;
$x = z_fetch_url(
$hz_server . '/api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page,
false,
$redirects,
[ 'headers' => $headers ]
);
// logger('item fetch: ' . print_r($x,true));
@@ -47,9 +53,9 @@ class Content_importer {
killme();
}
$j = json_decode($x['body'],true);
$j = json_decode($x['body'], true);
if(! is_array($j['item']) || ! count($j['item'])) {
if($j && empty($j['item'])) {
PConfig::Set($channel['channel_id'], 'import', 'content_completed', 1);
return;
}

View File

@@ -69,18 +69,18 @@ class Cron {
// expire any expired items
$r = q("select id,item_wall from item where expires > '2001-01-01 00:00:00' and expires < %s
$r = q("select id, uid, item_wall from item where expires > '2001-01-01 00:00:00' and expires < %s
and item_deleted = 0 ",
db_utcnow()
);
if ($r) {
require_once('include/items.php');
foreach ($r as $rr) {
drop_item($rr['id'], false, (($rr['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL));
// pass uid of the message for permission check as we are running as a daemon process with no session.
drop_item($rr['id'], (($rr['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL), uid: intval($rr['uid']));
if ($rr['item_wall']) {
// The notifier isn't normally invoked unless item_drop is interactive.
Master::Summon(['Notifier', 'drop', $rr['id']]);
if ($interval) {
usleep($interval);
}
@@ -147,40 +147,29 @@ class Cron {
// (time travel posts). Restrict to items that have come of age in the last
// couple of days to limit the query to something reasonable.
$r = q("select id from item where item_delayed = 1 and created <= %s and created > '%s' ",
$r = q("select * from item where item_delayed = 1 and created <= %s and created > '%s' ",
db_utcnow(),
dbesc(datetime_convert('UTC', 'UTC', 'now - 2 days'))
);
if ($r) {
foreach ($r as $rr) {
$x = q("update item set item_delayed = 0 where id = %d",
intval($rr['id'])
);
if ($x) {
$z = q("select * from item where id = %d",
intval($rr['id'])
);
if ($z) {
xchan_query($z);
$sync_item = fetch_post_tags($z);
Libsync::build_sync_packet($sync_item[0]['uid'],
[
'item' => [encode_item($sync_item[0], true)]
]
);
}
Master::Summon(array('Notifier', 'wall-new', $rr['id']));
if ($interval) {
usleep($interval);
if ($r) {
xchan_query($r);
$items = fetch_post_tags($r);
foreach ($items as $item) {
$item['item_delayed'] = 0;
$post = item_store_update($item);
if($post['success']) {
Master::Summon(['Notifier', 'wall-new', $post['item_id']]);
if (!empty($post['approval_id'])) {
Master::Summon(['Notifier', 'wall-new', $post['approval_id']]);
}
}
}
}
require_once('include/attach.php');
attach_upgrade();
if ($interval) {
usleep($interval);
}
}
}
// once daily run birthday_updates and then expire in background
// FIXME: add birthday updates, both locally and for xprof for use

View File

@@ -23,13 +23,13 @@ class Expire {
// perform final cleanup on previously delete items
$r = q("select id from item where item_deleted = 1 and item_pending_remove = 0 and changed < %s - INTERVAL %s",
$r = q("select id, uid from item where item_deleted = 1 and item_pending_remove = 0 and changed < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval('10 DAY')
);
if ($r) {
foreach ($r as $rr) {
drop_item($rr['id'], false, DROPITEM_PHASE2);
drop_item($rr['id'], DROPITEM_PHASE2, uid: $rr['uid']);
}
}

View File

@@ -38,7 +38,13 @@ class File_importer {
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),true,'sha512');
// TODO: implement total count
$x = z_fetch_url($hz_server . '/api/z/1.0/file/export_page?f=records=1&page=' . $page, false, $redirects, [ 'headers' => $headers ]);
$redirects = 0;
$x = z_fetch_url(
$hz_server . '/api/z/1.0/file/export_page?f=records=1&page=' . $page,
false,
$redirects,
[ 'headers' => $headers ]
);
// logger('file fetch: ' . print_r($x,true));
if(! $x['success']) {

View File

@@ -18,9 +18,13 @@ class Importdoc {
static public function update_docs_dir($s) {
$f = basename($s);
$d = dirname($s);
if ($s === 'doc/html')
if ($s === 'doc/html') {
return;
}
$files = glob("$d/$f");
if ($files) {
foreach ($files as $fi) {
if ($fi === 'doc/html') {
@@ -37,6 +41,18 @@ class Importdoc {
}
}
}
// remove old files that weren't updated (indicates they were most likely deleted).
$i = q("select * from item where item_type = 5 and edited < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval('14 DAY', true)
);
if ($i) {
foreach ($i as $iv) {
drop_item($iv['id'], DROPITEM_NORMAL, true);
}
}
}
}

View File

@@ -241,11 +241,6 @@ class Notifier {
$target_item = $r[0];
if (in_array($target_item['author']['xchan_network'], ['rss', 'anon', 'token'])) {
logger('notifier: target item author is not a fetchable actor', LOGGER_DEBUG);
return;
}
if (intval($target_item['item_deleted'])) {
logger('notifier: target item ITEM_DELETED', LOGGER_DEBUG);
}
@@ -268,22 +263,9 @@ class Notifier {
}
// Check for non published items, but allow an exclusion for transmitting hidden file activities
if (intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) ||
intval($target_item['item_blocked']) || intval($target_item['item_hidden'])) {
logger('notifier: target item not published, so not forwardable', LOGGER_DEBUG);
return;
}
// follow/unfollow is for internal use only
if (in_array($target_item['verb'], ['Follow', 'Ignore', ACTIVITY_FOLLOW, ACTIVITY_UNFOLLOW])) {
logger('not fowarding follow/unfollow note activity');
return;
}
if (strpos($target_item['postopts'], 'nodeliver') !== false) {
logger('notifier: target item is undeliverable', LOGGER_DEBUG);
if (!item_forwardable($target_item)) {
//hz_syslog(print_r($target_item,true));
logger('notifier: target item not forwardable', LOGGER_DEBUG);
return;
}
@@ -299,7 +281,7 @@ class Notifier {
return;
}
if ($target_item['verb'] === ACTIVITY_SHARE) {
if (in_array($target_item['verb'], [ACTIVITY_SHARE])) {
// Provide correct representation across the wire. Internally this is treated as a comment.
$target_item['parent_mid'] = $target_item['thr_parent'] = $target_item['mid'];
}
@@ -374,7 +356,6 @@ class Notifier {
if (($relay_to_owner || $uplink) && ($cmd !== 'relay')) {
logger('notifier: followup relay', LOGGER_DEBUG);
// If the Parent item is an Announce the real owner is the parent author
$sendto = (($uplink) ? $parent_item['source_xchan'] : $parent_item['owner_xchan']);
self::$recipients = [$sendto];
self::$private = true;
@@ -389,7 +370,7 @@ class Notifier {
logger('normal (downstream) distribution', LOGGER_DEBUG);
}
if ($parent_item && $parent_item['item_private'] !== $target_item['item_private']) {
if (($parent_item && $parent_item['item_private'] !== $target_item['item_private']) || (intval($target_item['item_restrict']) & 1)) {
logger('conversation privacy mismatch - downstream delivery prevented');
return;
}
@@ -589,8 +570,6 @@ class Notifier {
foreach ($dhubs as $hub) {
logger('notifier_hub: ' . $hub['hubloc_url'], LOGGER_DEBUG);
if ($hub['hubloc_network'] !== 'zot6') {
$narr = [
'channel' => self::$channel,

352
Zotlabs/Entity/Account.php Normal file
View File

@@ -0,0 +1,352 @@
<?php
namespace Zotlabs\Entity;
use Zotlabs\Lib\BaseObject;
class Account extends BaseObject
{
public $account_id;
public $account_parent;
public $account_default_channel;
public $account_salt;
public $account_password;
public $account_email;
public $account_external;
public $account_language;
public $account_created;
public $account_lastlog;
public $account_flags;
public $account_roles;
public $account_reset;
public $account_expires;
public $account_expire_notified;
public $account_service_class;
public $account_level;
public $account_password_change;
/**
* @return mixed
*/
public function getId()
{
return $this->account_id;
}
/**
* @param mixed $account_id
* @return Account
*/
public function setId($account_id)
{
$this->account_id = $account_id;
return $this;
}
/**
* @return mixed
*/
public function getParent()
{
return $this->account_parent;
}
/**
* @param mixed $account_parent
* @return Account
*/
public function setParent($account_parent)
{
$this->account_parent = $account_parent;
return $this;
}
/**
* @return mixed
*/
public function getDefaultChannel()
{
return $this->account_default_channel;
}
/**
* @param mixed $account_default_channel
* @return Account
*/
public function setDefaultChannel($account_default_channel)
{
$this->account_default_channel = $account_default_channel;
return $this;
}
/**
* @return mixed
*/
public function getSalt()
{
return $this->account_salt;
}
/**
* @param mixed $account_salt
* @return Account
*/
public function setSalt($account_salt)
{
$this->account_salt = $account_salt;
return $this;
}
/**
* @return mixed
*/
public function getPassword()
{
return $this->account_password;
}
/**
* @param mixed $account_password
* @return Account
*/
public function setPassword($account_password)
{
$this->account_password = $account_password;
return $this;
}
/**
* @return mixed
*/
public function getEmail()
{
return $this->account_email;
}
/**
* @param mixed $account_email
* @return Account
*/
public function setEmail($account_email)
{
$this->account_email = $account_email;
return $this;
}
/**
* @return mixed
*/
public function getExternal()
{
return $this->account_external;
}
/**
* @param mixed $account_external
* @return Account
*/
public function setExternal($account_external)
{
$this->account_external = $account_external;
return $this;
}
/**
* @return mixed
*/
public function getLanguage()
{
return $this->account_language;
}
/**
* @param mixed $account_language
* @return Account
*/
public function setLanguage($account_language)
{
$this->account_language = $account_language;
return $this;
}
/**
* @return mixed
*/
public function getCreated()
{
return $this->account_created;
}
/**
* @param mixed $account_created
* @return Account
*/
public function setCreated($account_created)
{
$this->account_created = $account_created;
return $this;
}
/**
* @return mixed
*/
public function getLastlog()
{
return $this->account_lastlog;
}
/**
* @param mixed $account_lastlog
* @return Account
*/
public function setLastlog($account_lastlog)
{
$this->account_lastlog = $account_lastlog;
return $this;
}
/**
* @return mixed
*/
public function getFlags()
{
return $this->account_flags;
}
/**
* @param mixed $account_flags
* @return Account
*/
public function setFlags($account_flags)
{
$this->account_flags = $account_flags;
return $this;
}
/**
* @return mixed
*/
public function getRoles()
{
return $this->account_roles;
}
/**
* @param mixed $account_roles
* @return Account
*/
public function setRoles($account_roles)
{
$this->account_roles = $account_roles;
return $this;
}
/**
* @return mixed
*/
public function getReset()
{
return $this->account_reset;
}
/**
* @param mixed $account_reset
* @return Account
*/
public function setReset($account_reset)
{
$this->account_reset = $account_reset;
return $this;
}
/**
* @return mixed
*/
public function getExpires()
{
return $this->account_expires;
}
/**
* @param mixed $account_expires
* @return Account
*/
public function setExpires($account_expires)
{
$this->account_expires = $account_expires;
return $this;
}
/**
* @return mixed
*/
public function getExpireNotified()
{
return $this->account_expire_notified;
}
/**
* @param mixed $account_expire_notified
* @return Account
*/
public function setExpireNotified($account_expire_notified)
{
$this->account_expire_notified = $account_expire_notified;
return $this;
}
/**
* @return mixed
*/
public function getServiceClass()
{
return $this->account_service_class;
}
/**
* @param mixed $account_service_class
* @return Account
*/
public function setServiceClass($account_service_class)
{
$this->account_service_class = $account_service_class;
return $this;
}
/**
* @return mixed
*/
public function getLevel()
{
return $this->account_level;
}
/**
* @param mixed $account_level
* @return Account
*/
public function setLevel($account_level)
{
$this->account_level = $account_level;
return $this;
}
/**
* @return mixed
*/
public function getPasswordChange()
{
return $this->account_password_change;
}
/**
* @param mixed $account_password_change
* @return Account
*/
public function setPasswordChange($account_password_change)
{
$this->account_password_change = $account_password_change;
return $this;
}
}

714
Zotlabs/Entity/Channel.php Normal file
View File

@@ -0,0 +1,714 @@
<?php
namespace Zotlabs\Entity;
use Zotlabs\Lib\BaseObject;
class Channel extends BaseObject
{
public $channel_id;
public $channel_account_id;
public $channel_primary;
public $channel_name;
public $channel_parent;
public $channel_address;
public $channel_guid;
public $channel_guid_sig;
public $channel_hash;
public $channel_timezone;
public $channel_location;
public $channel_theme;
public $channel_startpage;
public $channel_pubkey;
public $channel_prvkey;
public $channel_epubkey;
public $channel_eprvkey;
public $channel_notifyflags;
public $channel_pageflags;
public $channel_dirdate;
public $channel_lastpost;
public $channel_deleted;
public $channel_active;
public $channel_max_anon_mail;
public $channel_max_friend_req;
public $channel_expire_days;
public $channel_passwd_reset;
public $channel_default_group;
public $channel_allow_cid;
public $channel_allow_gid;
public $channel_deny_cid;
public $channel_deny_gid;
public $channel_removed;
public $channel_system;
public $channel_moved;
public $channel_password;
public $channel_salt;
/**
* @return mixed
*/
public function getId()
{
return $this->channel_id;
}
/**
* @param mixed $channel_id
* @return Channel
*/
public function setId($channel_id)
{
$this->channel_id = $channel_id;
return $this;
}
/**
* @return mixed
*/
public function getAccountId()
{
return $this->channel_account_id;
}
/**
* @param mixed $channel_account_id
* @return Channel
*/
public function setAccountId($channel_account_id)
{
$this->channel_account_id = $channel_account_id;
return $this;
}
/**
* @return mixed
*/
public function getPrimary()
{
return $this->channel_primary;
}
/**
* @param mixed $channel_primary
* @return Channel
*/
public function setPrimary($channel_primary)
{
$this->channel_primary = $channel_primary;
return $this;
}
/**
* @return mixed
*/
public function getName()
{
return $this->channel_name;
}
/**
* @param mixed $channel_name
* @return Channel
*/
public function setName($channel_name)
{
$this->channel_name = $channel_name;
return $this;
}
/**
* @return mixed
*/
public function getParent()
{
return $this->channel_parent;
}
/**
* @param mixed $channel_parent
* @return Channel
*/
public function setParent($channel_parent)
{
$this->channel_parent = $channel_parent;
return $this;
}
/**
* @return mixed
*/
public function getAddress()
{
return $this->channel_address;
}
/**
* @param mixed $channel_address
* @return Channel
*/
public function setAddress($channel_address)
{
$this->channel_address = $channel_address;
return $this;
}
/**
* @return mixed
*/
public function getGuid()
{
return $this->channel_guid;
}
/**
* @param mixed $channel_guid
* @return Channel
*/
public function setGuid($channel_guid)
{
$this->channel_guid = $channel_guid;
return $this;
}
/**
* @return mixed
*/
public function getGuidSig()
{
return $this->channel_guid_sig;
}
/**
* @param mixed $channel_guid_sig
* @return Channel
*/
public function setGuidSig($channel_guid_sig)
{
$this->channel_guid_sig = $channel_guid_sig;
return $this;
}
/**
* @return mixed
*/
public function getHash()
{
return $this->channel_hash;
}
/**
* @param mixed $channel_hash
* @return Channel
*/
public function setHash($channel_hash)
{
$this->channel_hash = $channel_hash;
return $this;
}
/**
* @return mixed
*/
public function getTimezone()
{
return $this->channel_timezone;
}
/**
* @param mixed $channel_timezone
* @return Channel
*/
public function setTimezone($channel_timezone)
{
$this->channel_timezone = $channel_timezone;
return $this;
}
/**
* @return mixed
*/
public function getLocation()
{
return $this->channel_location;
}
/**
* @param mixed $channel_location
* @return Channel
*/
public function setLocation($channel_location)
{
$this->channel_location = $channel_location;
return $this;
}
/**
* @return mixed
*/
public function getTheme()
{
return $this->channel_theme;
}
/**
* @param mixed $channel_theme
* @return Channel
*/
public function setTheme($channel_theme)
{
$this->channel_theme = $channel_theme;
return $this;
}
/**
* @return mixed
*/
public function getStartpage()
{
return $this->channel_startpage;
}
/**
* @param mixed $channel_startpage
* @return Channel
*/
public function setStartpage($channel_startpage)
{
$this->channel_startpage = $channel_startpage;
return $this;
}
/**
* @return mixed
*/
public function getPubkey()
{
return $this->channel_pubkey;
}
/**
* @param mixed $channel_pubkey
* @return Channel
*/
public function setPubkey($channel_pubkey)
{
$this->channel_pubkey = $channel_pubkey;
return $this;
}
/**
* @return mixed
*/
public function getPrvkey()
{
return $this->channel_prvkey;
}
/**
* @param mixed $channel_prvkey
* @return Channel
*/
public function setPrvkey($channel_prvkey)
{
$this->channel_prvkey = $channel_prvkey;
return $this;
}
/**
* @return mixed
*/
public function getEpubkey()
{
return $this->channel_epubkey;
}
/**
* @param mixed $channel_epubkey
* @return Channel
*/
public function setEpubkey($channel_epubkey)
{
$this->channel_epubkey = $channel_epubkey;
return $this;
}
/**
* @return mixed
*/
public function getEprvkey()
{
return $this->channel_eprvkey;
}
/**
* @param mixed $channel_eprvkey
* @return Channel
*/
public function setEprvkey($channel_eprvkey)
{
$this->channel_eprvkey = $channel_eprvkey;
return $this;
}
/**
* @return mixed
*/
public function getNotifyflags()
{
return $this->channel_notifyflags;
}
/**
* @param mixed $channel_notifyflags
* @return Channel
*/
public function setNotifyflags($channel_notifyflags)
{
$this->channel_notifyflags = $channel_notifyflags;
return $this;
}
/**
* @return mixed
*/
public function getPageflags()
{
return $this->channel_pageflags;
}
/**
* @param mixed $channel_pageflags
* @return Channel
*/
public function setPageflags($channel_pageflags)
{
$this->channel_pageflags = $channel_pageflags;
return $this;
}
/**
* @return mixed
*/
public function getDirdate()
{
return $this->channel_dirdate;
}
/**
* @param mixed $channel_dirdate
* @return Channel
*/
public function setDirdate($channel_dirdate)
{
$this->channel_dirdate = $channel_dirdate;
return $this;
}
/**
* @return mixed
*/
public function getLastpost()
{
return $this->channel_lastpost;
}
/**
* @param mixed $channel_lastpost
* @return Channel
*/
public function setLastpost($channel_lastpost)
{
$this->channel_lastpost = $channel_lastpost;
return $this;
}
/**
* @return mixed
*/
public function getDeleted()
{
return $this->channel_deleted;
}
/**
* @param mixed $channel_deleted
* @return Channel
*/
public function setDeleted($channel_deleted)
{
$this->channel_deleted = $channel_deleted;
return $this;
}
/**
* @return mixed
*/
public function getActive()
{
return $this->channel_active;
}
/**
* @param mixed $channel_active
* @return Channel
*/
public function setActive($channel_active)
{
$this->channel_active = $channel_active;
return $this;
}
/**
* @return mixed
*/
public function getMaxAnonMail()
{
return $this->channel_max_anon_mail;
}
/**
* @param mixed $channel_max_anon_mail
* @return Channel
*/
public function setMaxAnonMail($channel_max_anon_mail)
{
$this->channel_max_anon_mail = $channel_max_anon_mail;
return $this;
}
/**
* @return mixed
*/
public function getMaxFriendReq()
{
return $this->channel_max_friend_req;
}
/**
* @param mixed $channel_max_friend_req
* @return Channel
*/
public function setMaxFriendReq($channel_max_friend_req)
{
$this->channel_max_friend_req = $channel_max_friend_req;
return $this;
}
/**
* @return mixed
*/
public function getExpireDays()
{
return $this->channel_expire_days;
}
/**
* @param mixed $channel_expire_days
* @return Channel
*/
public function setExpireDays($channel_expire_days)
{
$this->channel_expire_days = $channel_expire_days;
return $this;
}
/**
* @return mixed
*/
public function getPasswdReset()
{
return $this->channel_passwd_reset;
}
/**
* @param mixed $channel_passwd_reset
* @return Channel
*/
public function setPasswdReset($channel_passwd_reset)
{
$this->channel_passwd_reset = $channel_passwd_reset;
return $this;
}
/**
* @return mixed
*/
public function getDefaultGroup()
{
return $this->channel_default_group;
}
/**
* @param mixed $channel_default_group
* @return Channel
*/
public function setDefaultGroup($channel_default_group)
{
$this->channel_default_group = $channel_default_group;
return $this;
}
/**
* @return mixed
*/
public function getAllowCid()
{
return $this->channel_allow_cid;
}
/**
* @param mixed $channel_allow_cid
* @return Channel
*/
public function setAllowCid($channel_allow_cid)
{
$this->channel_allow_cid = $channel_allow_cid;
return $this;
}
/**
* @return mixed
*/
public function getAllowGid()
{
return $this->channel_allow_gid;
}
/**
* @param mixed $channel_allow_gid
* @return Channel
*/
public function setAllowGid($channel_allow_gid)
{
$this->channel_allow_gid = $channel_allow_gid;
return $this;
}
/**
* @return mixed
*/
public function getDenyCid()
{
return $this->channel_deny_cid;
}
/**
* @param mixed $channel_deny_cid
* @return Channel
*/
public function setDenyCid($channel_deny_cid)
{
$this->channel_deny_cid = $channel_deny_cid;
return $this;
}
/**
* @return mixed
*/
public function getDenyGid()
{
return $this->channel_deny_gid;
}
/**
* @param mixed $channel_deny_gid
* @return Channel
*/
public function setDenyGid($channel_deny_gid)
{
$this->channel_deny_gid = $channel_deny_gid;
return $this;
}
/**
* @return mixed
*/
public function getRemoved()
{
return $this->channel_removed;
}
/**
* @param mixed $channel_removed
* @return Channel
*/
public function setRemoved($channel_removed)
{
$this->channel_removed = $channel_removed;
return $this;
}
/**
* @return mixed
*/
public function getSystem()
{
return $this->channel_system;
}
/**
* @param mixed $channel_system
* @return Channel
*/
public function setSystem($channel_system)
{
$this->channel_system = $channel_system;
return $this;
}
/**
* @return mixed
*/
public function getMoved()
{
return $this->channel_moved;
}
/**
* @param mixed $channel_moved
* @return Channel
*/
public function setMoved($channel_moved)
{
$this->channel_moved = $channel_moved;
return $this;
}
/**
* @return mixed
*/
public function getPassword()
{
return $this->channel_password;
}
/**
* @param mixed $channel_password
* @return Channel
*/
public function setPassword($channel_password)
{
$this->channel_password = $channel_password;
return $this;
}
/**
* @return mixed
*/
public function getSalt()
{
return $this->channel_salt;
}
/**
* @param mixed $channel_salt
* @return Channel
*/
public function setSalt($channel_salt)
{
$this->channel_salt = $channel_salt;
return $this;
}
}

1498
Zotlabs/Entity/Item.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,7 @@ use Zotlabs\Access\PermissionRoles;
use Zotlabs\Access\Permissions;
use Zotlabs\Daemon\Master;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Entity\Item;
require_once('include/event.php');
require_once('include/html2plain.php');
@@ -503,15 +504,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 +533,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']);
@@ -570,6 +599,25 @@ class Activity {
if ($i['mid'] !== $i['parent_mid']) {
$ret['inReplyTo'] = ((strpos($i['thr_parent'], 'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
$cnv = IConfig::Get($i['parent'], 'activitypub', 'context');
if (!$cnv) {
$cnv = $i['parent_mid'];
}
}
if (empty($cnv)) {
$cnv = IConfig::Get($i, 'activitypub', 'context');
if (!$cnv) {
$cnv = $i['parent_mid'];
}
}
if (!empty($cnv)) {
if (is_string($cnv) && str_starts_with($cnv, z_root())) {
$cnv = str_replace(['/item/', '/activity/'], ['/conversation/', '/conversation/'], $cnv);
}
$ret['context'] = $cnv;
}
if ($i['mimetype'] === 'text/bbcode') {
@@ -589,6 +637,12 @@ class Activity {
$t = self::encode_taxonomy($i);
if ($t) {
foreach($t as $tag) {
if (strcasecmp($tag['name'], '#nsfw') === 0 || strcasecmp($tag['name'], '#sensitive') === 0) {
$ret['sensitive'] = true;
}
}
$ret['tag'] = $t;
}
@@ -596,7 +650,20 @@ class Activity {
if ($a) {
$ret['attachment'] = $a;
}
/*
if ($i['target']) {
if (is_string($i['target'])) {
$tmp = json_decode($i['target'], true);
if ($tmp !== null) {
$i['target'] = $tmp;
}
}
$tgt = self::encode_object($i['target']);
if ($tgt) {
$ret['target'] = $tgt;
}
}
*/
if (intval($i['item_private']) === 0) {
$ret['to'] = [ACTIVITY_PUBLIC_INBOX];
}
@@ -694,6 +761,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 +771,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 : '')];
}
}
}
@@ -807,12 +882,32 @@ class Activity {
$ret['type'] = self::activity_mapper($i['verb']);
if ((isset($i['item_deleted']) && intval($i['item_deleted'])) && !$recurse) {
$is_response = false;
if (ActivityStreams::is_response_activity($ret['type'])) {
if ($i['verb'] === 'Add' && str_contains($i['tgt_type'], 'Collection')) {
$ret['id'] = str_replace('/item/', '/activity/', $i['mid']) . '#Remove';
$ret['type'] = 'Remove';
if (is_string($i['obj'])) {
$obj = json_decode($i['obj'], true);
}
elseif(is_array($i['obj'])) {
$obj = $i['obj'];
}
if (isset($obj['id'])) {
$ret['object'] = $obj['id'];
}
else {
$ret['object'] = str_replace('/item/', '/activity/', $i['mid']);
}
$ret['target'] = is_array($i['target']) ? $i['target'] : json_decode($i['target'], true);
return $ret;
}
$is_response = ActivityStreams::is_response_activity($ret['type']);
if ($is_response) {
$ret['type'] = 'Undo';
$fragment = 'undo';
$is_response = true;
}
else {
$ret['type'] = 'Delete';
@@ -935,9 +1030,28 @@ class Activity {
// inReplyTo needs to be set in the activity for followup actions (Like, Dislike, Announce, etc.),
// but *not* for comments and RSVPs, where it should only be present in the object
if (!in_array($ret['type'], ['Create', 'Update', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject'])) {
if (!in_array($ret['type'], ['Create', 'Update', 'Add', 'Remove', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject'])) {
$ret['inReplyTo'] = ((strpos($i['thr_parent'], 'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
}
$cnv = IConfig::Get($i['parent'], 'activitypub', 'context');
if (!$cnv) {
$cnv = $i['parent_mid'];
}
}
if (empty($cnv)) {
$cnv = IConfig::Get($i, 'activitypub', 'context');
if (!$cnv) {
$cnv = $i['parent_mid'];
}
}
if (!empty($cnv)) {
if (is_string($cnv) && str_starts_with($cnv, z_root())) {
$cnv = str_replace(['/item/', '/activity/'], ['/conversation/', '/conversation/'], $cnv);
}
$ret['context'] = $cnv;
}
$actor = self::encode_person($i['author'], false);
@@ -1010,6 +1124,7 @@ class Activity {
call_hooks('encode_activity', $hookinfo);
return $hookinfo['encoded'];
}
// Returns an array of URLS for any mention tags found in the item array $i.
@@ -1253,81 +1368,6 @@ class Activity {
// return false;
}
static function activity_decode_mapper($verb) {
$acts = [
'http://activitystrea.ms/schema/1.0/post' => 'Create',
// 'http://activitystrea.ms/schema/1.0/share' => 'Announce',
'http://activitystrea.ms/schema/1.0/update' => 'Update',
'http://activitystrea.ms/schema/1.0/like' => 'Like',
'http://activitystrea.ms/schema/1.0/favorite' => 'Like',
'http://purl.org/zot/activity/dislike' => 'Dislike',
// 'http://activitystrea.ms/schema/1.0/tag' => 'Add',
'http://activitystrea.ms/schema/1.0/follow' => 'Follow',
'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow',
'http://activitystrea.ms/schema/1.0/stop-following' => 'Unfollow',
'http://purl.org/zot/activity/attendyes' => 'Accept',
'http://purl.org/zot/activity/attendno' => 'Reject',
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept',
'Announce' => 'Announce',
'Invite' => 'Invite',
'Delete' => 'Delete',
'Undo' => 'Undo',
'Add' => 'Add',
'Remove' => 'Remove'
];
call_hooks('activity_decode_mapper', $acts);
foreach ($acts as $k => $v) {
if ($verb === $v) {
return $k;
}
}
logger('Unmapped activity: ' . $verb);
return 'Create';
}
static function activity_obj_decode_mapper($obj) {
$objs = [
'http://activitystrea.ms/schema/1.0/note' => 'Note',
'http://activitystrea.ms/schema/1.0/note' => 'Article',
'http://activitystrea.ms/schema/1.0/comment' => 'Note',
'http://activitystrea.ms/schema/1.0/person' => 'Person',
'http://purl.org/zot/activity/profile' => 'Profile',
'http://activitystrea.ms/schema/1.0/photo' => 'Image',
'http://activitystrea.ms/schema/1.0/profile-photo' => 'Icon',
'http://activitystrea.ms/schema/1.0/event' => 'Event',
'http://purl.org/zot/activity/location' => 'Place',
'http://purl.org/zot/activity/chessgame' => 'Game',
'http://purl.org/zot/activity/tagterm' => 'zot:Tag',
'http://purl.org/zot/activity/thing' => 'Object',
'http://purl.org/zot/activity/file' => 'zot:File',
'http://purl.org/zot/activity/mood' => 'zot:Mood',
'Invite' => 'Invite',
'Question' => 'Question',
'Document' => 'Document',
'Audio' => 'Audio',
'Video' => 'Video',
'Delete' => 'Delete',
'Undo' => 'Undo'
];
call_hooks('activity_obj_decode_mapper', $objs);
foreach ($objs as $k => $v) {
if ($obj === $v) {
return $k;
}
}
logger('Unmapped activity object: ' . $obj);
return 'Note';
}
static function activity_obj_mapper($obj) {
$objs = [
@@ -1606,9 +1646,9 @@ class Activity {
}
if (in_array($observer, [$r[0]['author_xchan'], $r[0]['owner_xchan']])) {
drop_item($r[0]['id'], false, (($r[0]['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL));
drop_item($r[0]['id'], (($r[0]['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL), observer_hash: $observer);
} elseif (in_array($act->actor['id'], [$r[0]['author_xchan'], $r[0]['owner_xchan']])) {
drop_item($r[0]['id'], false, (($r[0]['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL));
drop_item($r[0]['id'], (($r[0]['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL));
}
sync_an_item($channel['channel_id'], $r[0]['id']);
@@ -1906,129 +1946,173 @@ class Activity {
}
static function update_poll($item_id, $post) {
static function update_poll($pollItem, $response) {
$multi = false;
$mid = $post['mid'];
$content = $post['title'];
logger('updating poll');
if (!$item_id) {
$multi = false;
if (!$pollItem) {
logger('no item');
return false;
}
if (intval($post['item_blocked']) === ITEM_MODERATED) {
if (intval($pollItem['item_blocked']) === ITEM_MODERATED) {
logger('item blocked');
return false;
}
$channel = channelx_by_n($pollItem['uid']);
if (!$channel) {
logger('no channel');
return false;
}
$relatedItem = find_related($pollItem);
$ids = (($relatedItem) ? $pollItem['id'] . ',' . $relatedItem['id'] : $pollItem['id']);
dbq("START TRANSACTION");
// Using the provided items as is will produce desastrous race conditions
// in case of multiple choice polls - hence:
$item = q("SELECT * FROM item WHERE id = %d FOR UPDATE",
intval($item_id)
);
$items = dbq("SELECT * FROM item WHERE id in ($ids) FOR UPDATE");
if (!$item) {
dbq("COMMIT");
return false;
foreach ($items as $item) {
if ($item['id'] === $pollItem['id']) {
$pollItem = $item;
}
if (!empty($relatedItem['id']) && $item['id'] === $relatedItem['id']) {
$relatedItem = $item;
}
}
$item = $item[0];
$o = json_decode($pollItem['obj'], true);
$o = json_decode($item['obj'], true);
if ($o && array_key_exists('anyOf', $o)) {
$multi = true;
}
$r = q("select mid, title from item where parent_mid = '%s' and author_xchan = '%s'",
dbesc($item['mid']),
dbesc($post['author_xchan'])
);
if ($response) {
$mid = $response['mid'];
$content = trim($response['title']);
// prevent any duplicate votes by same author for oneOf and duplicate votes with same author and same answer for anyOf
if ($r) {
if ($multi) {
foreach ($r as $rv) {
if ($rv['title'] === $content && $rv['mid'] !== $mid) {
return false;
}
}
}
else {
foreach ($r as $rv) {
if ($rv['mid'] !== $mid) {
return false;
}
}
}
}
$answer_found = false;
$found = false;
if ($multi) {
for ($c = 0; $c < count($o['anyOf']); $c++) {
if ($o['anyOf'][$c]['name'] === $content) {
$answer_found = true;
if (is_array($o['anyOf'][$c]['replies'])) {
foreach ($o['anyOf'][$c]['replies'] as $reply) {
if (is_array($reply) && array_key_exists('id', $reply) && $reply['id'] === $mid) {
$found = true;
}
}
}
if (!$found) {
$o['anyOf'][$c]['replies']['totalItems']++;
$o['anyOf'][$c]['replies']['items'][] = ['id' => $mid, 'type' => 'Note'];
}
}
}
}
else {
for ($c = 0; $c < count($o['oneOf']); $c++) {
if ($o['oneOf'][$c]['name'] === $content) {
$answer_found = true;
if (is_array($o['oneOf'][$c]['replies'])) {
foreach ($o['oneOf'][$c]['replies'] as $reply) {
if (is_array($reply) && array_key_exists('id', $reply) && $reply['id'] === $mid) {
$found = true;
}
}
}
if (!$found) {
$o['oneOf'][$c]['replies']['totalItems']++;
$o['oneOf'][$c]['replies']['items'][] = ['id' => $mid, 'type' => 'Note'];
}
}
}
}
logger('updated_poll: ' . print_r($o, true), LOGGER_DATA);
if ($answer_found && !$found) {
$u = q("update item set obj = '%s', edited = '%s' where id = %d",
dbesc(json_encode($o)),
dbesc(datetime_convert()),
intval($item['id'])
$r = q("select mid, title from item where parent_mid = '%s' and author_xchan = '%s' and mid != parent_mid ",
dbesc($pollItem['mid']),
dbesc($response['author_xchan'])
);
if ($u) {
dbq("COMMIT");
// prevent any duplicate votes by same author for oneOf and duplicate votes with same author and same answer for anyOf
if ($r) {
if ($multi) {
// wait some seconds for possible multiple answers to be processed
// before calling the notifier
sleep(3);
foreach ($r as $rv) {
if (trim($rv['title']) === $content && $rv['mid'] !== $mid) {
logger('already voted multi');
return false;
}
}
} else {
foreach ($r as $rv) {
if ($rv['mid'] !== $mid && $content) {
logger('already voted');
return false;
}
}
}
Master::Summon(['Notifier', 'wall-new', $item['id']]);
return true;
}
dbq("ROLLBACK");
$answer_found = false;
$foundPrevious = false;
if ($multi) {
for ($c = 0; $c < count($o['anyOf']); $c++) {
if (trim($o['anyOf'][$c]['name']) === $content) {
$answer_found = true;
if (is_array($o['anyOf'][$c]['replies'])) {
foreach ($o['anyOf'][$c]['replies'] as $reply) {
if (is_array($reply) && array_key_exists('id', $reply) && $reply['id'] === $mid) {
$foundPrevious = true;
}
}
}
if (!$foundPrevious) {
$o['anyOf'][$c]['replies']['totalItems']++;
$o['anyOf'][$c]['replies']['items'][] = ['id' => $mid, 'type' => 'Note'];
}
}
}
} else {
for ($c = 0; $c < count($o['oneOf']); $c++) {
if (trim($o['oneOf'][$c]['name']) === $content) {
$answer_found = true;
if (is_array($o['oneOf'][$c]['replies'])) {
foreach ($o['oneOf'][$c]['replies'] as $reply) {
if (is_array($reply) && array_key_exists('id', $reply) && $reply['id'] === $mid) {
$foundPrevious = true;
}
}
}
if (!$foundPrevious) {
$o['oneOf'][$c]['replies']['totalItems']++;
$o['oneOf'][$c]['replies']['items'][] = ['id' => $mid, 'type' => 'Note'];
}
}
}
}
}
if ($pollItem['comments_closed'] > NULL_DATE) {
if ($pollItem['comments_closed'] > datetime_convert()) {
$o['closed'] = datetime_convert('UTC', 'UTC', $pollItem['comments_closed'], ATOM_TIME);
// set this to force an update
$answer_found = true;
}
}
dbq("COMMIT");
return false;
// A change was made locally
if ($response && $answer_found && !$foundPrevious) {
// update this copy
$i = [$pollItem];
xchan_query($i, true);
$i = fetch_post_tags($i);
$i[0]['obj'] = $o;
$edited = datetime_convert();
$i[0]['edited'] = $edited;
// create the new object
$newObj = self::build_packet(self::encode_activity($i[0]), $channel, true);
// and immediately update the db
$u = q("UPDATE item
SET obj = (
CASE
WHEN item.id = %d THEN '%s'
WHEN item.id = %d THEN '%s'
END
),
edited = '%s'
WHERE id IN ($ids)",
intval($pollItem['id']),
dbesc(json_encode($o)),
intval($relatedItem['id']),
dbesc($newObj),
dbesc($edited)
);
dbq("COMMIT");
Master::Summon(['Notifier', 'edit_post', $pollItem['id'], $response['mid']]);
if (!empty($relatedItem['id'])) {
Master::Summon(['Notifier', 'edit_post', $relatedItem['id'], $response['mid']]);
}
}
return true;
}
static function decode_note($act) {
@@ -2116,6 +2200,13 @@ class Activity {
$s['expires'] = datetime_convert('UTC', 'UTC', $act->obj['expires']);
}
if ($act->objprop('location')) {
$s['location'] = ((isset($act->objprop('location')['name'])) ? html2plain(purify_html($act->objprop('location')['name'])) : '');
if (isset($act->objprop('location')['latitude'], $act->objprop('location')['longitude'])) {
$s['coord'] = floatval($act->objprop('location')['latitude']) . ' ' . floatval($act->objprop('location')['longitude']);
}
}
if (in_array($act->type, ['Invite', 'Create']) && $act->objprop('type') === 'Event') {
$s['mid'] = $s['parent_mid'] = $act->id;
}
@@ -2218,6 +2309,8 @@ class Activity {
if ($s['mid'] === $s['parent_mid']) {
$s['item_thread_top'] = 1;
$s['item_nocomment'] = 0;
$s['comments_closed'] = NULL_DATE;
// it is a parent node - decode the comment policy info if present
if ($act->objprop('commentPolicy')) {
@@ -2225,7 +2318,7 @@ class Activity {
if ($until !== false) {
$s['comments_closed'] = datetime_convert('UTC', 'UTC', substr($act->obj['commentPolicy'], $until + 6));
if ($s['comments_closed'] < datetime_convert()) {
$s['nocomment'] = true;
$s['item_nocomment'] = 1;
}
}
@@ -2277,6 +2370,16 @@ class Activity {
$s['obj']['actor'] = $s['obj']['actor']['id'];
}
if (is_array($act->tgt) && $act->tgt) {
if (array_key_exists('type', $act->tgt)) {
$s['tgt_type'] = self::activity_obj_mapper($act->tgt['type']);
}
// We shouldn't need to store collection contents which could be large. We will often only require the meta-data
if (isset($s['tgt_type']) && str_contains($s['tgt_type'], 'Collection')) {
$s['target'] = ['id' => $act->tgt['id'], 'type' => $s['tgt_type'], 'attributedTo' => $act->tgt['attributedTo'] ?? $act->tgt['actor']];
}
}
$generator = $act->get_property_obj('generator');
if ((!$generator) && (!$response_activity)) {
$generator = $act->get_property_obj('generator', $act->obj);
@@ -2582,6 +2685,7 @@ class Activity {
}
}
if (!$ap_rawmsg && array_key_exists('signed', $raw_arr)) {
// zap
$ap_rawmsg = json_encode($act->data, JSON_UNESCAPED_SLASHES);
@@ -2615,8 +2719,7 @@ class Activity {
return $hookinfo['s'];
}
static function store($channel, $observer_hash, $act, $item, $fetch_parents = true, $force = false) {
static function store($channel, $observer_hash, $act, $item, $fetch_parents = true, $force = false, $is_collection_operation = false) {
$is_sys_channel = is_sys_channel($channel['channel_id']);
$is_child_node = false;
$parent = null;
@@ -2647,6 +2750,8 @@ class Activity {
}
$allowed = false;
$relay = false;
$permit_mentions = intval(PConfig::Get($channel['channel_id'], 'system','permit_all_mentions') && i_am_mentioned($channel, $item));
if ($is_child_node) {
@@ -2673,13 +2778,22 @@ class Activity {
return;
}
$relay = $channel['channel_hash'] === $parent[0]['owner_xchan'];
if (str_contains($parent[0]['tgt_type'], 'Collection') && !$relay && !$isCollectionOperation) {
logger('not a collection activity');
return;
}
if ($parent[0]['obj_type'] === 'Question') {
if (in_array($item['obj_type'], ['Note', ACTIVITY_OBJ_COMMENT]) && $item['title'] && (!$item['body'])) {
$item['obj_type'] = 'Answer';
$item['item_hidden'] = 1;
}
}
if ($parent[0]['item_wall']) {
// set the owner to the owner of the parent
$item['owner_xchan'] = $parent[0]['owner_xchan'];
@@ -2860,6 +2974,10 @@ class Activity {
// This isn't perfect but the best we can do for now.
$item['comment_policy'] = ((isset($act->data['commentPolicy'])) ? $act->data['commentPolicy'] : 'authenticated');
if (!empty($act->obj['context'])) {
IConfig::Set($item, 'activitypub', 'context', $act->obj['context'], 1);
}
IConfig::Set($item, 'activitypub', 'recips', $act->raw_recips);
if (intval($act->sigok)) {
@@ -2930,17 +3048,48 @@ class Activity {
dbesc($item['mid']),
intval($item['uid'])
);
if ($r) {
if ($item['edited'] > $r[0]['edited']) {
$item['id'] = $r[0]['id'];
$x = item_store_update($item);
$x = item_store_update($item, deliver: false);
}
else {
return;
}
}
else {
$x = item_store($item);
$x = item_store($item, deliver: false, addAndSync: false);
}
if ($x['success']) {
if ($relay && $channel['channel_hash'] === $x['item']['owner_xchan'] && $x['item']['verb'] !== 'Add' && !$isCollectionOperation) {
$approval = Activity::addToCollection($channel, $act->data, $x['item']['parent_mid'], $x['item'], deliver: false);
}
if (check_item_source($channel['channel_id'], $x['item']) && in_array($x['item']['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
event_addtocal($x['item_id'], $channel['channel_id']);
}
tag_deliver($channel['channel_id'], $x['item_id']);
if ($relay && $is_child_node) {
// We are the owner of this conversation, so send all received comments back downstream
Master::Summon(['Notifier', 'comment-import', $x['item_id']]);
if (!empty($approval['item_id'])) {
Master::Summon(['Notifier', 'comment-import', $approval['item_id']]);
}
}
$r = q("select * from item where id = %d limit 1",
intval($x['item_id'])
);
if ($r) {
send_status_notifications($x['item_id'], $r[0]);
}
sync_an_item($channel['channel_id'], $x['item_id']);
}
if ($fetch_parents && $parent && !intval($parent[0]['item_private'])) {
@@ -2967,28 +3116,6 @@ class Activity {
}
}
}
if ($x['success']) {
if (check_item_source($channel['channel_id'], $x['item']) && in_array($x['item']['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
event_addtocal($x['item_id'], $channel['channel_id']);
}
if ($is_child_node) {
if ($item['owner_xchan'] === $channel['channel_hash']) {
// We are the owner of this conversation, so send all received comments back downstream
Master::Summon(['Notifier', 'comment-import', $x['item_id']]);
}
$r = q("select * from item where id = %d limit 1",
intval($x['item_id'])
);
if ($r) {
send_status_notifications($x['item_id'], $r[0]);
}
}
sync_an_item($channel['channel_id'], $x['item_id']);
}
}
/**
@@ -3271,7 +3398,7 @@ class Activity {
return $content;
}
if ($act['type'] === 'Event') {
if (isset($act['type']) && $act['type'] === 'Event') {
$adjust = false;
$event = [];
$event['event_hash'] = $act['id'];
@@ -3464,7 +3591,7 @@ class Activity {
$ret[$collection] = $actor_record[$collection];
}
}
if (array_path_exists('endpoints/sharedInbox', $actor_record) && $actor_record['endpoints']['sharedInbox']) {
if (!empty($actor_record['endpoints']['sharedInbox'])) {
$ret['sharedInbox'] = $actor_record['endpoints']['sharedInbox'];
}
@@ -3669,5 +3796,76 @@ class Activity {
}
}
public static function addToCollection($channel, $object, $target, $sourceItem = null, $deliver = true) {
if (!isset($channel['xchan_hash'])) {
$channel = channelx_by_hash($channel['channel_hash']);
}
$item = ((new Item())
->setUid($channel['channel_id'])
->setVerb('Add')
->setAuthorXchan($channel['channel_hash'])
->setOwnerXchan($channel['channel_hash'])
->setObj($object)
->setObjType($object['type'])
->setParentMid(str_replace('/conversation/','/item/', $target))
->setThrParent(str_replace('/conversation/','/item/', $target))
->setTgtType('Collection')
->setTarget([
'id' => str_replace('/item/','/conversation/', $target),
'type' => 'Collection',
'attributedTo' => z_root() . '/channel/' . $channel['channel_address'],
])
);
if ($sourceItem) {
$item->setSourceXchan($sourceItem['source_xchan'])
->setAllowCid($sourceItem['allow_cid'])
->setAllowGid($sourceItem['allow_gid'])
->setDenyCid($sourceItem['deny_cid'])
->setDenyGid($sourceItem['deny_gid'])
->setPrivate($sourceItem['item_private'])
->setRestrict($sourceItem['item_restrict'])
->setHidden($sourceItem['item_hidden'])
->setDelayed($sourceItem['item_delayed'])
->setUnpublished($sourceItem['item_unpublished'])
->setBlocked($sourceItem['item_blocked'])
->setType($sourceItem['item_type'])
->setCommentPolicy($sourceItem['comment_policy'])
->setPublicPolicy($sourceItem['public_policy'])
->setPostopts($sourceItem['postopts']);
}
$result = post_activity_item($item->toArray(), deliver: $deliver, channel: $channel, observer: $channel, addAndSync: false);
logger('addToCollection: ' . print_r($result, true));
return $result;
}
public static function removeFromCollection($channel, $object, $target, $deliver = true) {
if (!isset($channel['xchan_hash'])) {
$channel = channelx_by_hash($channel['channel_hash']);
}
$item = ((new Item())
->setUid($channel['channel_id'])
->setVerb('Remove')
->setAuthorXchan($channel['channel_hash'])
->setOwnerXchan($channel['channel_hash'])
->setObj($object)
->setObjType($object['type'])
->setParentMid(str_replace('/conversation/','/item/', $target))
->setThrParent(str_replace('/conversation/','/item/', $target))
->setReplyto(z_root() . '/channel/' . $channel['channel_address'])
->setTgtType('Collection')
->setTarget([
'id' => str_replace('/item/','/conversation/', $target),
'type' => 'Collection',
'attributedTo' => z_root() . '/channel/' . $channel['channel_address']
])
);
$result = post_activity_item($item->toArray(), deliver: $deliver, channel: $channel, observer: $channel, addAndSync: false);
logger('removeFromCollection: ' . print_r($result, true));
return $result;
}
}

View File

@@ -0,0 +1,80 @@
<?php
namespace Zotlabs\Lib;
use Zotlabs\ActivityStreams\UnhandledElementException;
class BaseObject
{
public $string;
public $ldContext;
/**
* @param $input
* @param $strict
* @throws UnhandledElementException if $strict
*/
public function __construct($input = null, $strict = false)
{
if (isset($input)) {
if (is_string($input)) {
$this->string = $input;
}
elseif(is_array($input)) {
foreach ($input as $key => $value) {
$key = ($key === '@context') ? 'ldContext' : $key;
if ($strict && !property_exists($this, $key)) {
throw new UnhandledElementException("Unhandled element: $key");
}
$this->{$key} = $value;
}
}
}
return $this;
}
public function getDataType($element, $object = null)
{
$object = $object ?? $this;
$type = gettype($object[$element]);
if ($type === 'array' && array_is_list($object[$element])) {
return 'list';
}
return $type;
}
public function toArray()
{
if ($this->string) {
return $this->string;
}
$returnValue = [];
foreach ((array) $this as $key => $value) {
if (isset($value)) {
$key = ($key === 'ldContext') ? '@context' : $key;
$returnValue[$key] = (($value instanceof BaseObject) ? $value->toArray() : $value);
}
}
return $returnValue;
}
/**
* @return mixed
*/
public function getLdContext()
{
return $this->ldContext;
}
/**
* @param mixed $ldContext
* @return BaseObject
*/
public function setLdContext($ldContext)
{
$this->ldContext = $ldContext;
return $this;
}
}

View File

@@ -181,7 +181,7 @@ class Chatroom {
}
function leave($observer_xchan, $room_id, $client) {
public static function leave($observer_xchan, $room_id, $client) {
if(! $room_id || ! $observer_xchan)
return;

View File

@@ -1,18 +1,35 @@
<?php
/**
* A class to handle database schema upgrades.
*
* SPDX-FileCopyrightText: 2024 Hubzilla Community
* SPDX-FileContributor: Harald Eilertsen
*
* SPDX-License-Identifier: MIT
*/
namespace Zotlabs\Lib;
use Zotlabs\Lib\Config;
/**
* Upgrade the database schema if necessary.
*
* Compares the currently active database schema version with the version
* required for this version of Hubzilla, and performs the upgrade if needed.
*
* If the difference consists of more than one revision of the schema, each of
* the intermediate upgrades are performed in turn.
*/
class DB_Upgrade {
public $config_name = '';
public $func_prefix = '';
function __construct($db_revision) {
$this->config_name = 'db_version';
$this->func_prefix = '_';
/**
* Check the installed and required schema versions and perform the upgrade
* if necessary.
*
* @param int $db_version The required DB schema version.
*/
public static function run(int $db_revision): void {
$build = Config::Get('system', 'db_version', 0);
if(! intval($build))

View File

@@ -406,6 +406,7 @@ class Enotify {
}
elseif (isset($params['type']) && $params['type'] === NOTIFY_TAGSHARE) {
$itemlink = $params['link'];
$subject = sprintf( t('[$Projectname:Notify] %s tagged your post') , $sender['xchan_name']);
$preamble = sprintf( t('%1$s tagged your post at %2$s'),$sender['xchan_name'], $sitename);
$epreamble = sprintf( t('%1$s tagged [zrl=%2$s]your post[/zrl]') ,
@@ -415,7 +416,6 @@ class Enotify {
$sitelink = t('Please visit %s to view and/or reply to the conversation.');
$tsitelink = sprintf( $sitelink, $siteurl );
$hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>');
$itemlink = $params['link'];
}
elseif (isset($params['type']) && $params['type'] === NOTIFY_INTRO) {
@@ -433,6 +433,7 @@ class Enotify {
}
elseif (isset($params['type']) && $params['type'] === NOTIFY_SUGGEST) {
$itemlink = $params['link'];
$subject = sprintf( t('[$Projectname:Notify] Friend suggestion received'));
$preamble = sprintf( t('You\'ve received a friend suggestion from \'%1$s\' at %2$s'), $sender['xchan_name'], $sitename);
$epreamble = sprintf( t('You\'ve received [zrl=%1$s]a friend suggestion[/zrl] for %2$s from %3$s.'),
@@ -447,7 +448,6 @@ class Enotify {
$sitelink = t('Please visit %s to approve or reject the suggestion.');
$tsitelink = sprintf( $sitelink, $siteurl );
$hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>');
$itemlink = $params['link'];
}
elseif (isset($params['type']) && $params['type'] === NOTIFY_CONFIRM) {
@@ -595,7 +595,7 @@ class Enotify {
// send email notification if notification preferences permit
require_once('bbcode.php');
require_once('include/bbcode.php');
if ((intval($recip['channel_notifyflags']) & intval($params['type'])) || $params['type'] == NOTIFY_SYSTEM) {
logger('notification: sending notification email');

View File

@@ -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'])
);

View File

@@ -1134,6 +1134,7 @@ class Libzot {
}
$message_request = false;
$is_collection_operation = false;
$has_data = array_key_exists('data', $env) && $env['data'];
@@ -1141,15 +1142,37 @@ class Libzot {
$AS = null;
if ($env['encoding'] === 'activitystreams') {
$AS = new ActivityStreams($data);
if (!$AS->is_valid()) {
logger('Activity rejected: ' . print_r($data, true));
return;
// process add/remove from collection separately, as it requires a target.
// use the data object, as it will not include actor expansion
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('relayed collection operation', LOGGER_DEBUG);
$is_collection_operation = true;
$original_id = $AS->id;
$original_type = $AS->type;
$raw_activity = $AS->data;
$AS = new ActivityStreams($raw_activity['object'], portable_id: $env['sender']);
// Store the original activity id and type for later usage
$AS->meta['original_id'] = $original_id;
$AS->meta['original_type'] = $original_type;
}
if (is_array($AS->obj)) {
$item = Activity::decode_note($AS);
if (!$item) {
logger('Could not decode activity: ' . print_r($AS, true));
return;
@@ -1158,6 +1181,12 @@ class Libzot {
else {
$item = [];
}
if (!$AS->is_valid()) {
logger('Activity rejected: ' . print_r($data, true));
return;
}
logger($AS->debug(), LOGGER_DATA);
}
@@ -1198,7 +1227,6 @@ class Libzot {
logger('public post');
// Public post. look for any site members who are or may be accepting posts from this sender
// and who are allowed to see them based on the sender's permissions
// @fixme;
@@ -1265,25 +1293,6 @@ class Libzot {
$item['item_private'] = 1;
}
if ($item['mid'] === $item['parent_mid']) {
if (is_array($AS->obj) && array_key_exists('commentPolicy', $AS->obj)) {
$p = strstr($AS->obj['commentPolicy'], 'until=');
if ($p !== false) {
$comments_closed_at = datetime_convert('UTC', 'UTC', substr($p, 6));
if ($comments_closed_at === $item['created']) {
$item['item_nocomment'] = 1;
}
else {
$item['comments_closed'] = $comments_closed_at;
$aritemr['comment_policy'] = trim(str_replace($p, '', $AS->obj['commentPolicy']));
}
}
else {
$item['comment_policy'] = $AS->obj['commentPolicy'];
}
}
}
if (!empty($AS->meta['hubloc']) || $AS->sigok) {
$item['item_verified'] = true;
}
@@ -1301,7 +1310,7 @@ class Libzot {
$relay = (($env['type'] === 'response') ? true : false);
$result = self::process_delivery($env['sender'], $AS, $item, $deliveries, $relay, false, $message_request);
$result = self::process_delivery($env['sender'], $AS, $item, $deliveries, $relay, false, $message_request, false, $is_collection_operation);
Activity::init_background_fetch($env['sender']);
}
@@ -1517,7 +1526,7 @@ class Libzot {
* @return array
*/
static function process_delivery($sender, $act, $arr, $deliveries, $relay, $public = false, $request = false, $force = false) {
static function process_delivery($sender, $act, $arr, $deliveries, $relay, $public = false, $request = false, $force = false, $is_collection_operation = false) {
$result = [];
// We've validated the sender. Now make sure that the sender is the owner or author
@@ -1545,6 +1554,14 @@ class Libzot {
$DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
$conversation_operation = $is_collection_operation && isset($arr['target']['attributedTo']);
if (str_contains($arr['tgt_type'], 'Collection') && !$relay && !$conversation_operation) {
$DR->update('not a collection activity');
$result[] = $DR->get();
continue;
}
if (($act) && ($act->obj) && (!is_array($act->obj))) {
// The initial object fetch failed using the sys channel credentials.
// Try again using the delivery channel credentials.
@@ -1578,6 +1595,8 @@ class Libzot {
*
*/
if ($sender === $channel['channel_hash'] && $arr['author_xchan'] === $channel['channel_hash'] && !str_starts_with($arr['mid'], z_root())) {
$DR->update('self delivery ignored');
$result[] = $DR->get();
@@ -1624,15 +1643,6 @@ class Libzot {
if (intval($channel['channel_system']) && (!$arr['item_private']) && (!$relay)) {
$local_public = true;
$r = q("select xchan_selfcensored from xchan where xchan_hash = '%s' limit 1",
dbesc($sender)
);
// don't import sys channel posts from selfcensored authors
if ($r && (intval($r[0]['xchan_selfcensored']))) {
$local_public = false;
continue;
}
$incl = Config::Get('system','pubstream_incl');
$excl = Config::Get('system','pubstream_excl');
@@ -1640,6 +1650,17 @@ class Libzot {
$local_public = false;
continue;
}
$r = q("select xchan_selfcensored, xchan_censored from xchan where xchan_hash = '%s'",
dbesc($sender)
);
// don't import sys channel posts from selfcensored or censored authors
if ($r && ($r[0]['xchan_selfcensored'] || $r[0]['xchan_censored'])) {
$local_public = false;
continue;
}
}
$tag_delivery = tgroup_check($channel['channel_id'], $arr);
@@ -1701,6 +1722,7 @@ class Libzot {
// If this is a poll response, convert the obj_type to our (internal-only) "Answer" type
if (in_array($arr['obj_type'], ['Note', ACTIVITY_OBJ_COMMENT]) && $arr['title'] && (!$arr['body'])) {
$arr['obj_type'] = 'Answer';
$arr['item_hidden'] = 1;
}
}
@@ -1826,11 +1848,19 @@ class Libzot {
dbesc($arr['author_xchan'])
);
// reactions such as like and dislike could have an mid with /activity/ in it.
// If we import an add/remove activity ($is_collection_operation) we strip off the
// add/remove part and only process the object.
// When looking up the item to pass it to the notifier for relay, we need to look up
// the original (stripped off) message id which we stored in $act->meta.
$sql_mid = (($is_collection_operation && $relay && $channel['channel_hash'] === $arr['owner_xchan']) ? $act->meta['original_id'] : $arr['mid']);
// Reactions such as like and dislike could have an mid with /activity/ in it.
// Check for both forms in order to prevent duplicates.
$r = q("select * from item where mid in ('%s','%s') and uid = %d limit 1",
dbesc($arr['mid']),
dbesc(str_replace(z_root() . '/activity/', z_root() . '/item/', $arr['mid'])),
$r = q("select * from item where mid in ('%s', '%s') and uid = %d limit 1",
dbesc($sql_mid),
dbesc(reverse_activity_mid($sql_mid)),
intval($channel['channel_id'])
);
@@ -1859,21 +1889,29 @@ class Libzot {
$DR->update('update ignored');
$result[] = $DR->get();
}
if ($relay && $channel['channel_hash'] === $item_result['item']['owner_xchan'] && $item_result['item']['verb'] !== 'Add' && !$is_collection_operation) {
$approval = Activity::addToCollection($channel, $act->data, $item_result['item']['parent_mid'], $item_result['item'], deliver: false);
}
}
else {
$DR->update('update ignored');
$result[] = $DR->get();
// We need this line to ensure wall-to-wall comments are relayed (by falling through to the relay bit),
// We need this line to ensure wall-to-wall comments and add/remove activities are relayed (by falling through to the relay bit),
// and at the same time not relay any other relayable posts more than once, because to do so is very wasteful.
if (!intval($r[0]['item_origin']))
continue;
}
}
else {
$arr['aid'] = $channel['channel_account_id'];
$arr['uid'] = $channel['channel_id'];
// if it's a sourced post, call the post_local hooks as if it were
// posted locally so that crosspost connectors will be triggered.
$item_source = check_item_source($arr['uid'], $arr);
@@ -1902,10 +1940,15 @@ class Libzot {
}
if (post_is_importable($arr['uid'], $arr, $abook)) {
$item_result = item_store($arr);
$item_result = item_store($arr, addAndSync: false);
if ($item_result['success']) {
$item_id = $item_result['item_id'];
if ($relay && $channel['channel_hash'] === $item_result['item']['owner_xchan'] && $item_result['item']['verb'] !== 'Add' && !$is_collection_operation) {
$approval = Activity::addToCollection($channel, $act->data, $item_result['item']['parent_mid'], $item_result['item'], deliver: false);
}
if ($item_source && in_array($item_result['item']['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
event_addtocal($item_id, $channel['channel_id']);
}
@@ -1948,12 +1991,16 @@ class Libzot {
if ((is_array($stored)) && ($stored['id'] != $stored['parent'])
&& ($stored['author_xchan'] === $channel['channel_hash'])) {
retain_item($stored['item']['parent']);
retain_item($stored['parent']);
}
if ($relay && $item_id && $stored['item_blocked'] !== ITEM_MODERATED) {
if ($relay && $item_id && item_forwardable($stored)) {
logger('Invoking relay');
Master::Summon(['Notifier', 'relay', intval($item_id)]);
if (!empty($approval) && $approval['item_id']) {
Master::Summon(['Notifier', 'relay', intval($approval['item_id'])]);
}
$DR->addto_update('relayed');
$result[] = $DR->get();
}
@@ -2006,6 +2053,7 @@ class Libzot {
foreach ($items as $activity) {
$AS = new ActivityStreams($activity);
if ($AS->is_valid() && $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)
@@ -2014,6 +2062,30 @@ class Libzot {
$AS = new ActivityStreams($AS->obj);
}
// process add/remove from collection separately, as it requires a target.
// use the raw object, as it will not include actor expansion
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('relayed collection operation', LOGGER_DEBUG);
$is_collection_operation = true;
$original_id = $AS->id;
$original_type = $AS->type;
$raw_activity = $AS->data;
$AS = new ActivityStreams($raw_activity['object']);
// Store the original activity id and type for later usage
$AS->meta['original_id'] = $original_id;
$AS->meta['original_type'] = $original_type;
}
if (!$AS->is_valid()) {
logger('Fetched activity rejected: ' . print_r($activity, true));
continue;
@@ -2207,7 +2279,7 @@ class Libzot {
}
$x = item_store_update($item);
$x = item_store_update($item, addAndSync: false);
// If we're updating an event that we've saved locally, we store the item info first
// because event_addtocal will parse the body to get the 'new' event details
@@ -2323,21 +2395,20 @@ class Libzot {
);
}
} else {
if ($stored['id'] !== $stored['parent']) {
q(
"update item set commented = '%s', changed = '%s' where id = %d",
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($stored['parent'])
);
}
}
if ($stored['id'] !== $stored['parent']) {
q("update item set commented = '%s', changed = '%s' where id = %d",
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($stored['parent'])
);
}
}
// Use phased deletion to set the deleted flag, call both tag_deliver and the notifier to notify downstream channels
// and then clean up after ourselves with a cron job after several days to do the delete_item_lowlevel() (DROPITEM_PHASE2).
drop_item($post_id, false, DROPITEM_PHASE1);
drop_item($post_id, DROPITEM_PHASE1, uid: $uid);
tag_deliver($uid, $post_id);
}

86
Zotlabs/Lib/Mailer.php Normal file
View File

@@ -0,0 +1,86 @@
<?php
/**
* Mailer class for sending emails from Hubzilla.
*
* SPDX-FileCopyrightText: 2024 Hubzilla Community
* SPDX-FileContributor: Harald Eilertsen
*
* SPDX-License-Identifier: MIT
*/
namespace Zotlabs\Lib;
use App;
/**
* A class for sending emails.
*
* Based on the previous `z_mail` function, but adaped and made more
* robust and usable as a class.
*/
class Mailer {
public function __construct(private array $params = []) {
}
public function deliver(): bool {
if(empty($this->params['fromEmail'])) {
$this->params['fromEmail'] = Config::Get('system','from_email');
if(empty($this->params['fromEmail'])) {
$this->params['fromEmail'] = 'Administrator@' . App::get_hostname();
}
}
if(empty($this->params['fromName'])) {
$this->params['fromName'] = Config::Get('system','from_email_name');
if(empty($this->params['fromName'])) {
$this->params['fromName'] = System::get_site_name();
}
}
if(empty($this->params['replyTo'])) {
$this->params['replyTo'] = Config::Get('system','reply_address');
if(empty($this->params['replyTo'])) {
$this->params['replyTo'] = 'noreply@' . App::get_hostname();
}
}
if (!isset($this->params['additionalMailHeader'])) {
$this->params['additionalMailHeader'] = '';
}
$this->params['sent'] = false;
$this->params['result'] = false;
/**
* @hooks email_send
* * \e params @see z_mail()
*/
call_hooks('email_send', $this->params);
if($this->params['sent']) {
logger('notification: z_mail returns ' . (($this->params['result']) ? 'success' : 'failure'), LOGGER_DEBUG);
return $this->params['result'];
}
$fromName = email_header_encode(html_entity_decode($this->params['fromName'],ENT_QUOTES,'UTF-8'),'UTF-8');
$messageSubject = email_header_encode(html_entity_decode($this->params['messageSubject'],ENT_QUOTES,'UTF-8'),'UTF-8');
$messageHeader =
$this->params['additionalMailHeader'] .
"From: $fromName <{$this->params['fromEmail']}>" . PHP_EOL .
"Reply-To: $fromName <{$this->params['replyTo']}>" . PHP_EOL .
"Content-Type: text/plain; charset=UTF-8";
// send the message
$res = mail(
$this->params['toEmail'], // send to address
$messageSubject, // subject
$this->params['textVersion'],
$messageHeader // message headers
);
logger('notification: z_mail returns ' . (($res) ? 'success' : 'failure'), LOGGER_DEBUG);
return $res;
}
}

View File

@@ -117,7 +117,7 @@ class PermissionDescription {
}
/**
* Returns an icon css class name if an appropriate one is available, e.g. "fa-globe" for Public,
* Returns an icon css class name if an appropriate one is available, e.g. "bi-globe" for Public,
* otherwise returns empty string.
*
* @return string icon css class name (often FontAwesome)
@@ -125,12 +125,12 @@ class PermissionDescription {
public function get_permission_icon() {
switch($this->channel_perm) {
case 0:/* only me */ return 'fa-eye-slash';
case PERMS_PUBLIC: return 'fa-globe';
case PERMS_NETWORK: return 'fa-share-alt-square'; // fa-share-alt-square is very similiar to the hubzilla logo, but we should create our own logo class to use
case PERMS_SITE: return 'fa-sitemap';
case PERMS_CONTACTS: return 'fa-group';
case PERMS_SPECIFIC: return 'fa-list';
case 0:/* only me */ return 'bi-eye-slash';
case PERMS_PUBLIC: return 'bi-globe';
case PERMS_NETWORK: return 'bi-share'; // bi-share is very similiar to the hubzilla logo, but we should create our own logo class to use
case PERMS_SITE: return 'bi-geo';
case PERMS_CONTACTS: return 'bi-people';
case PERMS_SPECIFIC: return 'bi-list-ul';
case PERMS_AUTHED: return '';
case PERMS_PENDING: return '';
default: return '';

View File

@@ -59,7 +59,7 @@ class QueueWorker {
$transaction = new \DbaTransaction(\DBA::$dba);
$r = q("INSERT INTO workerq (workerq_priority, workerq_data, workerq_uuid, workerq_cmd) VALUES (%d, '%s', '%s', '%s')",
intval($priority),
$workinfo_json,
dbesc($workinfo_json),
dbesc($uuid),
dbesc($argv[0])
);
@@ -105,7 +105,7 @@ class QueueWorker {
$transaction = new \DbaTransaction(\DBA::$dba);
$r = q("INSERT INTO workerq (workerq_priority, workerq_data, workerq_uuid, workerq_cmd) VALUES (%d, '%s', '%s', '%s')",
intval($priority),
$workinfo_json,
dbesc($workinfo_json),
dbesc($uuid),
dbesc($argv[0])
);

View File

@@ -1,127 +0,0 @@
<?php
namespace Zotlabs\Lib;
/**
* @brief wrapper for z_fetch_url() which can be instantiated with several built-in parameters and
* these can be modified and re-used. Useful for CalDAV and other processes which need to authenticate
* and set lots of CURL options (many of which stay the same from one call to the next).
*/
class SuperCurl {
private $auth;
private $url;
private $curlopt = array();
private $headers = null;
public $filepos = 0;
public $filehandle = 0;
public $request_data = '';
private $request_method = 'GET';
private $upload = false;
private $cookies = false;
private function set_data($s) {
$this->request_data = $s;
$this->filepos = 0;
}
public function curl_read($ch,$fh,$size) {
if($this->filepos < 0) {
unset($fh);
return '';
}
$s = substr($this->request_data,$this->filepos,$size);
if(strlen($s) < $size)
$this->filepos = (-1);
else
$this->filepos = $this->filepos + $size;
return $s;
}
public function __construct($opts = array()) {
$this->set($opts);
}
private function set($opts = array()) {
if($opts) {
foreach($opts as $k => $v) {
switch($k) {
case 'http_auth':
$this->auth = $v;
break;
case 'magicauth':
// currently experimental
$this->magicauth = $v;
\Zotlabs\Daemon\Master::Summon([ 'CurlAuth', $v ]);
break;
case 'custom':
$this->request_method = $v;
break;
case 'url':
$this->url = $v;
break;
case 'data':
$this->set_data($v);
if($v) {
$this->upload = true;
}
else {
$this->upload = false;
}
break;
case 'headers':
$this->headers = $v;
break;
default:
$this->curlopts[$k] = $v;
break;
}
}
}
}
function exec() {
$opts = $this->curlopts;
$url = $this->url;
if($this->auth)
$opts['http_auth'] = $this->auth;
if($this->magicauth) {
$opts['cookiejar'] = 'store/[data]/cookie_' . $this->magicauth;
$opts['cookiefile'] = 'store/[data]/cookie_' . $this->magicauth;
$opts['cookie'] = 'PHPSESSID=' . trim(file_get_contents('store/[data]/cookien_' . $this->magicauth));
$c = channelx_by_n($this->magicauth);
if($c)
$url = zid($this->url,channel_reddress($c));
}
if($this->custom)
$opts['custom'] = $this->custom;
if($this->headers)
$opts['headers'] = $this->headers;
if($this->upload) {
$opts['upload'] = true;
$opts['infile'] = $this->filehandle;
$opts['infilesize'] = strlen($this->request_data);
$opts['readfunc'] = [ $this, 'curl_read' ] ;
}
$recurse = 0;
return z_fetch_url($this->url,true,$recurse,(($opts) ? $opts : null));
}
}

View File

@@ -93,7 +93,7 @@ class ThreadItem {
$buttons = '';
$dropping = false;
$star = false;
$isstarred = "unstarred fa-star-o";
$isstarred = "unstarred bi-star";
$is_comment = false;
$is_item = false;
$osparkle = '';
@@ -123,13 +123,13 @@ class ThreadItem {
$locktype = 0;
}
$shareable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && (intval($item['item_private']) === 0)) ? true : false);
$shareable = ((local_channel() && $conv->get_profile_owner() == local_channel()) && (intval($item['item_private']) === 0));
// allow an exemption for sharing stuff from your private feeds
if($item['author']['xchan_network'] === 'rss')
$shareable = true;
$repeatable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && (intval($item['item_private']) === 0) && (in_array($item['author']['xchan_network'], ['zot6', 'activitypub']))) ? true : false);
$repeatable = ((local_channel() && $conv->get_profile_owner() == local_channel()) && intval($item['item_private']) === 0 && in_array($item['author']['xchan_network'], ['zot6', 'activitypub']));
// @fixme
// Have recently added code to properly handle polls in group reshares by redirecting all of the poll responses to the group.
@@ -187,7 +187,7 @@ class ThreadItem {
$drop = [ 'dropping' => true, 'delete' => t('Admin Delete') ];
}
$filer = ((($conv->get_profile_owner() == local_channel()) && (! array_key_exists('real_uid',$item))) ? t("Save to Folder") : false);
$filer = (((local_channel() && $conv->get_profile_owner() === local_channel()) || (local_channel() && App::$module === 'pubstream')) ? t("Save to Folder") : false);
$profile_avatar = $item['author']['xchan_photo_s'];
$profile_link = chanlink_hash($item['author_xchan']);
@@ -204,9 +204,11 @@ class ThreadItem {
$response_verbs[] = 'dislike';
}
$response_verbs[] = 'announce';
if ($repeatable) {
$response_verbs[] = 'announce';
}
if(in_array($item['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
if (in_array($item['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
$response_verbs[] = 'attendyes';
$response_verbs[] = 'attendno';
$response_verbs[] = 'attendmaybe';
@@ -216,60 +218,21 @@ class ThreadItem {
}
}
if($item['obj_type'] === 'Question') {
if ($item['obj_type'] === 'Question') {
$response_verbs[] = 'answer';
}
if(! feature_enabled($conv->get_profile_owner(),'dislike'))
if (!feature_enabled($conv->get_profile_owner(),'dislike')) {
unset($conv_responses['dislike']);
}
$responses = get_responses($conv_responses,$response_verbs,$this,$item);
$my_responses = [];
foreach($response_verbs as $v) {
$my_responses[$v] = ((isset($conv_responses[$v][$item['mid'] . '-m'])) ? 1 : 0);
}
/*
$like_count = ((x($conv_responses['like'],$item['mid'])) ? $conv_responses['like'][$item['mid']] : '');
$like_list = ((x($conv_responses['like'],$item['mid'])) ? $conv_responses['like'][$item['mid'] . '-l'] : '');
if (($like_list) && (count($like_list) > MAX_LIKERS)) {
$like_list_part = array_slice($like_list, 0, MAX_LIKERS);
array_push($like_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#likeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
} else {
$like_list_part = '';
}
$like_button_label = tt('Like','Likes',$like_count,'noun');
$repeat_count = ((x($conv_responses['announce'],$item['mid'])) ? $conv_responses['announce'][$item['mid']] : '');
$repeat_list = ((x($conv_responses['announce'],$item['mid'])) ? $conv_responses['announce'][$item['mid'] . '-l'] : '');
if (($repeat_list) && (count($repeat_list) > MAX_LIKERS)) {
$repeat_list_part = array_slice($repeat_list, 0, MAX_LIKERS);
array_push($repeat_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#repeatModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
} else {
$repeat_list_part = '';
}
$repeat_button_label = tt('Repeat','Repeats',$repeat_count,'noun');
$showdislike = '';
if (feature_enabled($conv->get_profile_owner(),'dislike')) {
$dislike_count = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid']] : '');
$dislike_list = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid'] . '-l'] : '');
$dislike_button_label = tt('Dislike','Dislikes',$dislike_count,'noun');
if (($dislike_list) && (count($dislike_list) > MAX_LIKERS)) {
$dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS);
array_push($dislike_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#dislikeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
} else {
$dislike_list_part = '';
}
$showdislike = ((x($conv_responses['dislike'],$item['mid'])) ? format_like($conv_responses['dislike'][$item['mid']],$conv_responses['dislike'][$item['mid'] . '-l'],'dislike',$item['mid']) : '');
}
$showlike = ((x($conv_responses['like'],$item['mid'])) ? format_like($conv_responses['like'][$item['mid']],$conv_responses['like'][$item['mid'] . '-l'],'like',$item['mid']) : '');
*/
/*
* We should avoid doing this all the time, but it depends on the conversation mode
@@ -327,11 +290,13 @@ class ThreadItem {
$like = [];
$dislike = [];
$reply_to = [];
$reactions_allowed = false;
if($this->is_commentable() && $observer) {
$like = array( t("I like this \x28toggle\x29"), t("like"));
$dislike = array( t("I don't like this \x28toggle\x29"), t("dislike"));
$reply_to = array( t("Reply on this comment"), t("reply"), t("Reply to"));
$reply_to = array( t("Reply to this comment"), t("reply"), t("Reply to"));
$reactions_allowed = true;
}
$share = [];
@@ -411,7 +376,6 @@ class ThreadItem {
'template' => $this->get_template(),
'mode' => $mode,
'item_type' => intval($item['item_type']),
//'type' => implode("",array_slice(explode("/",$item['verb']),-1)),
'body' => $body['html'],
'tags' => $body['tags'],
'categories' => $body['categories'],
@@ -446,16 +410,15 @@ class ThreadItem {
'sparkle' => $sparkle,
'title' => $item['title'],
'title_tosource' => get_pconfig($conv->get_profile_owner(),'system','title_tosource'),
//'ago' => relative_date($item['created']),
'app' => $item['app'],
'str_app' => sprintf( t('from %s'), $item['app']),
'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'),
'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'),
'editedtime' => (($item['edited'] != $item['created']) ? sprintf( t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r')) : ''),
'expiretime' => (($item['expires'] > NULL_DATE) ? sprintf( t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r')):''),
'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created']),
'editedtime' => (($item['edited'] != $item['created']) ? sprintf(t('Last edited %s'), relative_time($item['edited'])) : ''),
'expiretime' => (($item['expires'] > NULL_DATE) ? sprintf(t('Expires %s'), relative_time($item['expires'])) : ''),
'lock' => $lock,
'locktype' => $locktype,
'delayed' => $item['item_delayed'],
'delayed' => (($item['item_delayed']) ? sprintf(t('Published %s'), relative_time($item['created'])) : ''),
'privacy_warning' => $privacy_warning,
'verified' => $verified,
'unverified' => $unverified,
@@ -475,7 +438,7 @@ class ThreadItem {
'event' => $body['event'],
'has_tags' => $has_tags,
'reactions' => $this->reactions,
// Item toolbar buttons
// Item toolbar buttons
'emojis' => (($this->is_toplevel() && $this->is_commentable() && $observer && feature_enabled($conv->get_profile_owner(),'emojis')) ? '1' : ''),
'like' => $like,
'dislike' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike : ''),
@@ -485,7 +448,7 @@ class ThreadItem {
'embed' => $embed,
'rawmid' => $item['mid'],
'plink' => get_plink($item),
'edpost' => $edpost, // ((feature_enabled($conv->get_profile_owner(),'edit_posts')) ? $edpost : ''),
'edpost' => $edpost,
'star' => ((feature_enabled($conv->get_profile_owner(),'star_posts') && ($item['item_type'] == ITEM_TYPE_POST)) ? $star : ''),
'tagger' => ((feature_enabled($conv->get_profile_owner(),'commtag')) ? $tagger : ''),
'filer' => ((feature_enabled($conv->get_profile_owner(),'filing') && ($item['item_type'] == ITEM_TYPE_POST)) ? $filer : ''),
@@ -496,7 +459,7 @@ class ThreadItem {
'addtocal' => (($has_event) ? t('Add to Calendar') : ''),
'drop' => $drop,
'dropdown_extras' => $dropdown_extras,
// end toolbar buttons
// end toolbar buttons
'unseen_comments' => $unseen_comments,
'comment_count' => $total_children,
'comment_count_txt' => $comment_count_txt,
@@ -504,30 +467,9 @@ class ThreadItem {
'markseen' => t('Mark all comments seen'),
'responses' => $responses,
'my_responses' => $my_responses,
/*
'like_count' => $like_count,
'like_list' => $like_list,
'like_list_part' => $like_list_part,
'like_button_label' => $like_button_label,
'like_modal_title' => t('Likes','noun'),
'repeat_count' => $repeat_count,
'repeat_list' => $repeat_list,
'repeat_list_part' => $repeat_list_part,
'repeat_button_label' => $repeat_button_label,
'repeat_modal_title' => t('Repeats','noun'),
'dislike_modal_title' => t('Dislikes','noun'),
'dislike_count' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_count : ''),
'dislike_list' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_list : ''),
'dislike_list_part' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_list_part : ''),
'dislike_button_label' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_button_label : ''),
*/
'modal_dismiss' => t('Close'),
// 'showlike' => $showlike,
// 'showdislike' => $showdislike,
'comment' => ($item['item_delayed'] ? '' : $this->get_comment_box()),
'no_comment' => (($item['item_thread_top'] && $item['item_nocomment'])? t('Comments disabled') : ''),
'previewing' => ($conv->is_preview() ? true : false ),
'preview_lbl' => t('This is an unsaved preview'),
'wait' => t('Please wait'),
@@ -539,6 +481,9 @@ class ThreadItem {
'moderate_approve' => t('Approve'),
'moderate_delete' => t('Delete'),
'rtl' => in_array($item['lang'], rtl_languages()),
'reactions_allowed' => $reactions_allowed,
'reaction_str' => [t('Add yours'), t('Remove yours')],
'is_contained' => $this->is_toplevel() && str_contains($item['tgt_type'], 'Collection')
);
$arr = array('item' => $item, 'output' => $tmp_item);
@@ -549,15 +494,7 @@ class ThreadItem {
$result['children'] = array();
$nb_children = count($children);
$visible_comments = Config::Get('system','expanded_comments');
if($visible_comments === false)
$visible_comments = 3;
// needed for scroll to comment from notification but needs more work
// as we do not want to open all comments unless there is actually an #item_xx anchor
// and the url fragment is not sent to the server.
// if(in_array(\App::$module,['display','update_display']))
// $visible_comments = 99999;
$visible_comments = Config::Get('system', 'expanded_comments', 3);
if(($this->get_display_mode() === 'normal') && ($nb_children > 0)) {
foreach($children as $child) {
@@ -567,7 +504,7 @@ class ThreadItem {
if(($nb_children > $visible_comments) || ($thread_level > 1)) {
$result['children'][0]['comment_firstcollapsed'] = true;
$result['children'][0]['num_comments'] = $comment_count_txt['label'];
$result['children'][0]['hide_text'] = sprintf( t('%s show all'), '<i class="fa fa-chevron-down"></i>');
$result['children'][0]['hide_text'] = t('show all');
if($thread_level > 1) {
$result['children'][$nb_children - 1]['comment_lastcollapsed'] = true;
}
@@ -869,7 +806,7 @@ class ThreadItem {
'$edatt' => t('Attach/Upload file'),
'$edurl' => t('Insert Link'),
'$edvideo' => t('Video'),
'$preview' => t('Preview'), // ((feature_enabled($conv->get_profile_owner(),'preview')) ? t('Preview') : ''),
'$preview' => t('Preview'),
'$can_upload' => (perm_is_allowed($conv->get_profile_owner(),get_observer_hash(),'write_storage') && $conv->is_uploadable()),
'$feature_encrypt' => ((feature_enabled($conv->get_profile_owner(),'content_encrypt')) ? true : false),
'$encrypt' => t('Encrypt text'),
@@ -890,7 +827,7 @@ class ThreadItem {
}
/**
* Check if we are a wall to wall item and set the relevant properties
* Check if we are a wall to wall or announce item and set the relevant properties
*/
protected function check_wall_to_wall() {
$conv = $this->get_conversation();

View File

@@ -14,6 +14,15 @@ trait HelpHelperTrait {
private string $file_name = '';
private string $file_type = '';
/**
* Associative array containing the detected language.
*/
private array $lang = [
'language' => 'en', //! Detected language, 2-letter ISO 639-1 code ("en")
'from_url' => false, //! true if language from URL overrides browser default
'missing' => false, //! true if topic not found in detected language
];
/**
* Determines help language.
*
@@ -28,17 +37,15 @@ trait HelpHelperTrait {
$languages = $language_repository->getList();
if(array_key_exists(argv(1), $languages)) {
$lang = argv(1);
$from_url = true;
$this->lang['language'] = argv(1);
$this->lang['from_url'] = true;
} else {
$lang = \App::$language;
if(! isset($lang))
$lang = 'en';
if(isset(\App::$language)) {
$this->lang['language'] = \App::$language;
}
$from_url = false;
$this->lang['from_url'] = false;
}
$this->lang = array('language' => $lang, 'from_url' => $from_url);
}
/**
@@ -53,10 +60,10 @@ trait HelpHelperTrait {
// Use local variable until we can use trait constants.
$valid_file_ext = ['md', 'bb', 'html'];
$base_path = "doc/{$lang}/${base_path}";
$base_path_with_lang = "doc/{$lang}/${base_path}";
foreach ($valid_file_ext as $ext) {
$path = "{$base_path}.{$ext}";
$path = "{$base_path_with_lang}.{$ext}";
if (file_exists($path)) {
$this->file_name = $path;
$this->file_type = $ext;
@@ -64,5 +71,25 @@ trait HelpHelperTrait {
break;
}
}
if (empty($this->file_name) && $lang !== 'en') {
$this->lang['missing'] = true;
$this->find_help_file($base_path, 'en');
}
}
public function missing_translation(): bool {
return !!$this->lang['missing'];
}
public function missing_translation_message(): string {
$prefered_language_name = get_language_name(
$this->lang['language'],
$this->lang['language']
);
return bbcode(
t("This page is not yet available in {$prefered_language_name}. See [observer.baseurl]/help/developer/developer_guide#Translations for information about how to help.")
);
}
}

View File

@@ -83,7 +83,7 @@ class XConfig {
return $default;
if(! array_key_exists($xchan, \App::$config))
load_xconfig($xchan);
self::Load($xchan);
if((! array_key_exists($family, \App::$config[$xchan])) || (! array_key_exists($key, \App::$config[$xchan][$family])))
return $default;

View File

@@ -8,25 +8,25 @@ class Achievements extends \Zotlabs\Web\Controller {
// This doesn't work, so
if (! is_developer())
return;
if(argc() > 1)
$which = argv(1);
else {
notice( t('Requested profile is not available.') . EOL );
return;
}
$profile = 0;
$profile = argv(1);
$profile = argv(1);
profile_load($which,$profile);
$r = q("select channel_id from channel where channel_address = '%s'",
dbesc($which)
);
if($r) {
$owner = intval($r[0]['channel_id']);
}
$observer = \App::get_observer();
$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
$perms = get_all_perms($owner,$ob_hash);
@@ -34,60 +34,60 @@ class Achievements extends \Zotlabs\Web\Controller {
notice( t('Permission denied.') . EOL);
return;
}
$newmembertext = t('Some blurb about what to do when you\'re new here');
// By default, all badges are false
$contactbadge = false;
$profilebadge = false;
$keywordsbadge = false;
// Check number of contacts. Award a badge if over 10
// We'll figure these out on each page load instead of
// We'll figure these out on each page load instead of
// writing them to the DB because that will mean one needs
// to retain their achievements - eg, you can't add
// a bunch of channels just to get your badge, and then
// delete them all again. If these become popular or
// used in profiles or something, we may need to reconsider
// and add a table for this - because this won't scale.
$r = q("select * from abook where abook_channel = %d",
intval($owner)
);
if (count($r))
$contacts = count($r);
// We're checking for 11 to adjust for the abook record for self
if ($contacts >= 11)
$contactbadge = true;
// Check if an about field in the profile has been created.
$r = q("select * from profile where uid = %d and about <> ''",
intval($owner)
);
if ($r)
$profilebadge = 1;
// Check if keywords have been set
$r = q("select * from profile where uid = %d and keywords <> ''",
intval($owner)
);
if($r)
$keywordsbadge = 1;
return replace_macros(get_markup_template("achievements.tpl"), array(
'$newmembertext' => $newmembertext,
'$profilebadge' => $profilebadge,
'$contactbadge' => $contactbadge,
'$keywordsbadge' => $keywordsbadge,
'$channelsbadge' => $channelsbadge
'$channelsbadge' => null,
));
}
}

View File

@@ -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'), ' ','' ],

View File

@@ -6,133 +6,33 @@ use Zotlabs\Lib\Config;
class Accounts {
/**
* @brief Handle POST actions on accounts admin page.
*
* This function is called when on the admin user/account page the form was
* submitted to handle multiple operations at once. If one of the icons next
* to an entry are pressed the function admin_page_accounts() will handle this.
*
*/
const MYP = 'ZAR'; // ZAR2x
const VERSION = '2.0.0';
function post() {
/**
* Handle POST actions on accounts admin page.
*/
public function post() {
$pending = ( x($_POST, 'pending') ? $_POST['pending'] : array() );
$users = ( x($_POST, 'user') ? $_POST['user'] : array() );
$blocked = ( x($_POST, 'blocked') ? $_POST['blocked'] : array() );
$pending = x($_POST, 'pending') ? $_POST['pending'] : array();
check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts');
$isajax = is_ajax();
$rc = 0;
If (!is_site_admin()) {
if ($isajax) {
killme();
exit;
}
goaway(z_root() . '/');
}
if ($isajax) {
//$debug = print_r($_SESSION[self::MYP],true);
$zarop = (x($_POST['zardo']) && preg_match('/^[ad]{1,1}$/', $_POST['zardo']) )
? $_POST['zardo'] : '';
// zarat arrives with leading underscore _n
$zarat = (x($_POST['zarat']) && preg_match('/^_{1,1}[0-9]{1,6}$/', $_POST['zarat']) )
? substr($_POST['zarat'],1) : '';
$zarse = (x($_POST['zarse']) && preg_match('/^[0-9a-f]{8,8}$/', $_POST['zarse']) )
? hex2bin($_POST['zarse']) : '';
if ($zarop && $zarat >= 0 && $zarse && $zarse == $_SESSION[self::MYP]['h'][$zarat]) {
//
if ($zarop == 'd') {
$rd = q("UPDATE register SET reg_vital = 0 WHERE reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
intval($_SESSION[self::MYP]['i'][$zarat]),
dbesc($_SESSION[self::MYP]['h'][$zarat])
);
$rc = '×';
}
elseif ($zarop == 'a') {
// approval, REGISTER_DENIED by user 0x0040, REGISTER_AGREED by user 0x0020 @Regate
$rd = q("UPDATE register SET reg_flags = (reg_flags & ~ 16), "
. " reg_vital = (CASE (reg_flags & ~ 48) WHEN 0 THEN 0 ELSE 1 END) "
. " WHERE reg_vital = 1 AND reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
intval($_SESSION[self::MYP]['i'][$zarat]),
dbesc($_SESSION[self::MYP]['h'][$zarat])
);
$rc = 0;
$rs = q("SELECT * from register WHERE reg_id = %d ",
intval($_SESSION[self::MYP]['i'][$zarat])
);
if ($rs && ($rs[0]['reg_flags'] & ~ 48) == 0) {
// create account
$rc = 'ok'.$rs[0]['reg_id'];
$ac = create_account_from_register($rs[0]);
if ( $ac['success'] ) {
$rc .= '✔';
$auto_create = Config::Get('system','auto_channel_create',1);
if($auto_create) {
$reonar = json_decode($rs[0]['reg_stuff'], true);
// prepare channel creation
if($reonar['chan.name'])
set_aconfig($ac['account']['account_id'], 'register', 'channel_name', $reonar['chan.name']);
if($reonar['chan.did1'])
set_aconfig($ac['account']['account_id'], 'register', 'channel_address', $reonar['chan.did1']);
$permissions_role = Config::Get('system','default_permissions_role');
if($permissions_role)
set_aconfig($ac['account']['account_id'], 'register', 'permissions_role', $permissions_role);
// create channel
$new_channel = auto_channel_create($ac['account']['account_id']);
if($new_channel['success']) {
$rc .= ' c,ok' . $new_channel['channel']['channel_id'] . '✔';
}
else {
$rc .= ' c ×';
}
}
}
} else {
$rc='oh ×';
}
}
echo json_encode(array('re' => $zarop, 'at' => '_' . $zarat, 'rc' => $rc));
}
if (is_ajax()) {
$this->handle_ajax_request();
killme();
exit;
}
// change to switch structure?
// account block/unblock button was submitted
if (x($_POST, 'page_accounts_block')) {
for ($i = 0; $i < count($users); $i++) {
// if account is blocked remove blocked bit-flag, otherwise add blocked bit-flag
$op = ($blocked[$i]) ? '& ~' : '| ';
q("UPDATE account SET account_flags = (account_flags $op%d) WHERE account_id = %d",
intval(ACCOUNT_BLOCKED),
intval($users[$i])
);
}
notice( sprintf( tt("%s account blocked/unblocked", "%s account blocked/unblocked", count($users)), count($users)) );
$this->block_unblock_accounts();
}
// account delete button was submitted
if (x($_POST, 'page_accounts_delete')) {
foreach ($users as $uid){
account_remove($uid, true, false);
}
notice( sprintf( tt("%s account deleted", "%s accounts deleted", count($users)), count($users)) );
$this->delete_accounts();
}
// registration approved button was submitted
if (x($_POST, 'page_accounts_approve')) {
@@ -351,5 +251,143 @@ class Accounts {
return $o;
}
private function handle_ajax_request(): void {
//$debug = print_r($_SESSION[self::MYP],true);
$zarop = (x($_POST['zardo']) && preg_match('/^[ad]{1,1}$/', $_POST['zardo']) )
? $_POST['zardo'] : '';
// zarat arrives with leading underscore _n
$zarat = (x($_POST['zarat']) && preg_match('/^_{1,1}[0-9]{1,6}$/', $_POST['zarat']) )
? substr($_POST['zarat'],1) : '';
$zarse = (x($_POST['zarse']) && preg_match('/^[0-9a-f]{8,8}$/', $_POST['zarse']) )
? hex2bin($_POST['zarse']) : '';
if ($zarop && $zarat >= 0 && $zarse && $zarse == $_SESSION[self::MYP]['h'][$zarat]) {
//
if ($zarop == 'd') {
$rd = q("UPDATE register SET reg_vital = 0 WHERE reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
intval($_SESSION[self::MYP]['i'][$zarat]),
dbesc($_SESSION[self::MYP]['h'][$zarat])
);
$rc = '×';
}
elseif ($zarop == 'a') {
// approval, REGISTER_DENIED by user 0x0040, REGISTER_AGREED by user 0x0020 @Regate
$rd = q("UPDATE register SET reg_flags = (reg_flags & ~ 16), "
. " reg_vital = (CASE (reg_flags & ~ 48) WHEN 0 THEN 0 ELSE 1 END) "
. " WHERE reg_vital = 1 AND reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
intval($_SESSION[self::MYP]['i'][$zarat]),
dbesc($_SESSION[self::MYP]['h'][$zarat])
);
$rc = 0;
$rs = q("SELECT * from register WHERE reg_id = %d ",
intval($_SESSION[self::MYP]['i'][$zarat])
);
if ($rs && ($rs[0]['reg_flags'] & ~ 48) == 0) {
// create account
$rc = 'ok'.$rs[0]['reg_id'];
$ac = create_account_from_register($rs[0]);
if ( $ac['success'] ) {
$rc .= '✔';
$auto_create = Config::Get('system','auto_channel_create',1);
if($auto_create) {
$reonar = json_decode($rs[0]['reg_stuff'], true);
// prepare channel creation
if($reonar['chan.name'])
set_aconfig($ac['account']['account_id'], 'register', 'channel_name', $reonar['chan.name']);
if($reonar['chan.did1'])
set_aconfig($ac['account']['account_id'], 'register', 'channel_address', $reonar['chan.did1']);
$permissions_role = Config::Get('system','default_permissions_role');
if($permissions_role)
set_aconfig($ac['account']['account_id'], 'register', 'permissions_role', $permissions_role);
// create channel
$new_channel = auto_channel_create($ac['account']['account_id']);
if($new_channel['success']) {
$rc .= ' c,ok' . $new_channel['channel']['channel_id'] . '✔';
}
else {
$rc .= ' c ×';
}
}
}
} else {
$rc='oh ×';
}
}
echo json_encode(array('re' => $zarop, 'at' => '_' . $zarat, 'rc' => $rc));
}
}
/**
* Block or unblock accounts given by the `user` and `blocked` POST params.
*
* The post params `user` and `blocked` must be present and arrays of equal
* lengths. The `user` array should contain account id's or the accounts to
* process, and the `blocked` array holds a corresponding boolean value to
* indicate that the account at the same offset in the `user` array is or is
* not blocked.
*
* An account that is _not_ blocked will be blocked, and accounts that _are_
* blocked will be unblocked.
*
* @SuppressWarnings(PHPMD.ShortVariable)
*/
private function block_unblock_accounts(): void {
if (!isset($_POST['user']) || !isset($_POST['blocked'])) {
return;
}
$users = $_POST['user'];
$blocked = $_POST['blocked'];
if (!is_array($users) || !is_array($blocked)) {
return;
}
foreach($users as $i => $id) {
// if account is blocked remove blocked bit-flag, otherwise add blocked bit-flag
$op = $blocked[$i] ? '& ~' : '| ';
q("UPDATE account SET account_flags = (account_flags $op%d) WHERE account_id = %d",
intval(ACCOUNT_BLOCKED),
intval($id)
);
}
$count = count($users);
$fmt = tt("%s account blocked/unblocked", "%s account blocked/unblocked", $count);
notice(sprintf($fmt, $count));
}
/**
* Delete multiple accounts given by the `user` POST param.
*/
private function delete_accounts(): void {
if (!isset($_POST['user'])) {
return;
}
$users = $_POST['user'];
if (!is_array($users)) {
return;
}
foreach ($users as $uid){
account_remove($uid, true, false);
}
$count = count($users);
$fmt = tt("%s account deleted", "%s accounts deleted", $count);
notice(sprintf($fmt, $count));
}
}

View File

@@ -3,9 +3,8 @@
namespace Zotlabs\Module\Admin;
use App;
use \Zotlabs\Lib\Config;
use \Zotlabs\Storage\GitRepo;
use \Michelf\MarkdownExtra;
use Zotlabs\Lib\Config;
use Michelf\MarkdownExtra;
class Addons {
@@ -24,227 +23,6 @@ class Addons {
goaway(z_root() . '/admin/addons/' . argv(2) );
}
elseif(argc() > 2) {
switch(argv(2)) {
case 'updaterepo':
if (array_key_exists('repoName', $_REQUEST)) {
$repoName = $_REQUEST['repoName'];
}
else {
json_return_and_die(array('message' => 'No repo name provided.', 'success' => false));
}
$extendDir = 'store/[data]/git/sys/extend';
$addonDir = $extendDir . '/addon';
if (!file_exists($extendDir)) {
if (!mkdir($extendDir, 0770, true)) {
logger('Error creating extend folder: ' . $extendDir);
json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
}
else {
if (!symlink(realpath('extend/addon'), $addonDir)) {
logger('Error creating symlink to addon folder: ' . $addonDir);
json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
}
}
}
$repoDir = 'store/[data]/git/sys/extend/addon/' . $repoName;
if (!is_dir($repoDir)) {
logger('Repo directory does not exist: ' . $repoDir);
json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false));
}
if (!is_writable($repoDir)) {
logger('Repo directory not writable to web server: ' . $repoDir);
json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false));
}
$git = new GitRepo('sys', null, false, $repoName, $repoDir);
try {
if ($git->pull()) {
$files = array_diff(scandir($repoDir), array('.', '..'));
foreach ($files as $file) {
if (is_dir($repoDir . '/' . $file) && $file !== '.git') {
$source = '../extend/addon/' . $repoName . '/' . $file;
$target = realpath('addon/') . '/' . $file;
unlink($target);
if (!symlink($source, $target)) {
logger('Error linking addons to /addon');
json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false));
}
}
}
json_return_and_die(array('message' => 'Repo updated.', 'success' => true));
} else {
json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false));
}
} catch (\PHPGit\Exception\GitException $e) {
json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false));
}
break;
case 'removerepo':
if (array_key_exists('repoName', $_REQUEST)) {
$repoName = $_REQUEST['repoName'];
} else {
json_return_and_die(array('message' => 'No repo name provided.', 'success' => false));
}
$extendDir = 'store/[data]/git/sys/extend';
$addonDir = $extendDir . '/addon';
if (!file_exists($extendDir)) {
if (!mkdir($extendDir, 0770, true)) {
logger('Error creating extend folder: ' . $extendDir);
json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
} else {
if (!symlink(realpath('extend/addon'), $addonDir)) {
logger('Error creating symlink to addon folder: ' . $addonDir);
json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
}
}
}
$repoDir = 'store/[data]/git/sys/extend/addon/' . $repoName;
if (!is_dir($repoDir)) {
logger('Repo directory does not exist: ' . $repoDir);
json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false));
}
if (!is_writable($repoDir)) {
logger('Repo directory not writable to web server: ' . $repoDir);
json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false));
}
/// @TODO remove directory and unlink /addon/files
if (rrmdir($repoDir)) {
json_return_and_die(array('message' => 'Repo deleted.', 'success' => true));
} else {
json_return_and_die(array('message' => 'Error deleting addon repo.', 'success' => false));
}
break;
case 'installrepo':
if (array_key_exists('repoURL', $_REQUEST)) {
require_once('library/PHPGit.autoload.php'); // Load PHPGit dependencies
$repoURL = $_REQUEST['repoURL'];
$extendDir = 'store/[data]/git/sys/extend';
$addonDir = $extendDir . '/addon';
if (!file_exists($extendDir)) {
if (!mkdir($extendDir, 0770, true)) {
logger('Error creating extend folder: ' . $extendDir);
json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
} else {
if (!symlink(realpath('extend/addon'), $addonDir)) {
logger('Error creating symlink to addon folder: ' . $addonDir);
json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
}
}
}
if (!is_writable($extendDir)) {
logger('Directory not writable to web server: ' . $extendDir);
json_return_and_die(array('message' => 'Directory not writable to web server.', 'success' => false));
}
$repoName = null;
if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') {
$repoName = $_REQUEST['repoName'];
} else {
$repoName = GitRepo::getRepoNameFromURL($repoURL);
}
if (!$repoName) {
logger('Invalid git repo');
json_return_and_die(array('message' => 'Invalid git repo', 'success' => false));
}
$repoDir = $addonDir . '/' . $repoName;
$tempRepoBaseDir = 'store/[data]/git/sys/temp/';
$tempAddonDir = $tempRepoBaseDir . $repoName;
if (!is_writable($addonDir) || !is_writable($tempAddonDir)) {
logger('Temp repo directory or /extend/addon not writable to web server: ' . $tempAddonDir);
json_return_and_die(array('message' => 'Temp repo directory not writable to web server.', 'success' => false));
}
rename($tempAddonDir, $repoDir);
if (!is_writable(realpath('addon/'))) {
logger('/addon directory not writable to web server: ' . $tempAddonDir);
json_return_and_die(array('message' => '/addon directory not writable to web server.', 'success' => false));
}
$files = array_diff(scandir($repoDir), array('.', '..'));
foreach ($files as $file) {
if (is_dir($repoDir . '/' . $file) && $file !== '.git') {
$source = '../extend/addon/' . $repoName . '/' . $file;
$target = realpath('addon/') . '/' . $file;
unlink($target);
if (!symlink($source, $target)) {
logger('Error linking addons to /addon');
json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false));
}
}
}
$git = new GitRepo('sys', $repoURL, false, $repoName, $repoDir);
$repo = $git->probeRepo();
json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true));
}
break;
case 'addrepo':
if (array_key_exists('repoURL', $_REQUEST)) {
require_once('library/PHPGit.autoload.php'); // Load PHPGit dependencies
$repoURL = $_REQUEST['repoURL'];
$extendDir = 'store/[data]/git/sys/extend';
$addonDir = $extendDir . '/addon';
$tempAddonDir = realpath('store/[data]') . '/git/sys/temp';
if (!file_exists($extendDir)) {
if (!mkdir($extendDir, 0770, true)) {
logger('Error creating extend folder: ' . $extendDir);
json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
} else {
if (!symlink(realpath('extend/addon'), $addonDir)) {
logger('Error creating symlink to addon folder: ' . $addonDir);
json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
}
}
}
if (!is_dir($tempAddonDir)) {
if (!mkdir($tempAddonDir, 0770, true)) {
logger('Error creating temp plugin repo folder: ' . $tempAddonDir);
json_return_and_die(array('message' => 'Error creating temp plugin repo folder: ' . $tempAddonDir, 'success' => false));
}
}
$repoName = null;
if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') {
$repoName = $_REQUEST['repoName'];
} else {
$repoName = GitRepo::getRepoNameFromURL($repoURL);
}
if (!$repoName) {
logger('Invalid git repo');
json_return_and_die(array('message' => 'Invalid git repo: ' . $repoName, 'success' => false));
}
$repoDir = $tempAddonDir . '/' . $repoName;
if (!is_writable($tempAddonDir)) {
logger('Temporary directory for new addon repo is not writable to web server: ' . $tempAddonDir);
json_return_and_die(array('message' => 'Temporary directory for new addon repo is not writable to web server.', 'success' => false));
}
// clone the repo if new automatically
$git = new GitRepo('sys', $repoURL, true, $repoName, $repoDir);
$remotes = $git->git->remote();
$fetchURL = $remotes['origin']['fetch'];
if ($fetchURL !== $git->url) {
if (rrmdir($repoDir)) {
$git = new GitRepo('sys', $repoURL, true, $repoName, $repoDir);
} else {
json_return_and_die(array('message' => 'Error deleting existing addon repo.', 'success' => false));
}
}
$repo = $git->probeRepo();
$repo['readme'] = $repo['manifest'] = null;
foreach ($git->git->tree('master') as $object) {
if ($object['type'] == 'blob' && (strtolower($object['file']) === 'readme.md' || strtolower($object['file']) === 'readme')) {
$repo['readme'] = MarkdownExtra::defaultTransform($git->git->cat->blob($object['hash']));
} else if ($object['type'] == 'blob' && strtolower($object['file']) === 'manifest.json') {
$repo['manifest'] = $git->git->cat->blob($object['hash']);
}
}
json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true));
} else {
json_return_and_die(array('message' => 'No repo URL provided', 'success' => false));
}
break;
default:
break;
}
}
}
/**
@@ -408,37 +186,6 @@ class Addons {
usort($plugins,'self::plugin_sort');
$allowManageRepos = false;
if(is_writable('extend/addon') && is_writable('store/[data]')) {
$allowManageRepos = true;
}
$admin_plugins_add_repo_form= replace_macros(
get_markup_template('admin_plugins_addrepo.tpl'), array(
'$post' => 'admin/addons/addrepo',
'$desc' => t('Enter the public git repository URL of the addon repo.'),
'$repoURL' => array('repoURL', t('Addon repo git URL'), '', ''),
'$repoName' => array('repoName', t('Custom repo name'), '', '', t('(optional)')),
'$submit' => t('Download Addon Repo')
)
);
$newRepoModalID = random_string(3);
$newRepoModal = replace_macros(
get_markup_template('generic_modal.tpl'), array(
'$id' => $newRepoModalID,
'$title' => t('Install new repo'),
'$ok' => t('Install'),
'$cancel' => t('Cancel')
)
);
$reponames = $this->listAddonRepos();
$addonrepos = [];
foreach($reponames as $repo) {
$addonrepos[] = array('name' => $repo, 'description' => '');
/// @TODO Parse repo info to provide more information about repos
}
$t = get_markup_template('admin_plugins.tpl');
return replace_macros($t, array(
'$title' => t('Administration'),
@@ -449,37 +196,9 @@ class Addons {
'$plugins' => $plugins,
'$disabled' => t('Disabled - version incompatibility'),
'$form_security_token' => get_form_security_token('admin_addons'),
'$allowManageRepos' => $allowManageRepos,
'$managerepos' => t('Manage Repos'),
'$installedtitle' => t('Installed Addon Repositories'),
'$addnewrepotitle' => t('Install a New Addon Repository'),
'$expandform' => false,
'$form' => $admin_plugins_add_repo_form,
'$newRepoModal' => $newRepoModal,
'$newRepoModalID' => $newRepoModalID,
'$addonrepos' => $addonrepos,
'$repoUpdateButton' => t('Update'),
'$repoBranchButton' => t('Switch branch'),
'$repoRemoveButton' => t('Remove')
));
}
function listAddonRepos() {
$addonrepos = [];
$addonDir = 'extend/addon/';
if(is_dir($addonDir)) {
if ($handle = opendir($addonDir)) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
$addonrepos[] = $entry;
}
}
closedir($handle);
}
}
return $addonrepos;
}
static public function plugin_sort($a,$b) {
return(strcmp(strtolower($a[2]['name']),strtolower($b[2]['name'])));
}

View File

@@ -126,7 +126,7 @@ class Channels {
goaway(z_root() . '/admin/channels' );
}
$key = (($_REQUEST['key']) ? dbesc($_REQUEST['key']) : 'channel_id');
$key = ((isset($_REQUEST['key']) && $_REQUEST['key']) ? dbesc($_REQUEST['key']) : 'channel_id');
$dir = 'asc';
if(array_key_exists('dir',$_REQUEST))
$dir = ((intval($_REQUEST['dir'])) ? 'asc' : 'desc');

View File

@@ -59,14 +59,13 @@ class Features {
}
$tpl = get_markup_template("admin_settings_features.tpl");
$o .= replace_macros($tpl, array(
return replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("admin_manage_features"),
'$title' => t('Manage Additional Features'),
'$features' => $arr,
'$submit' => t('Submit'),
));
return $o;
}
}

View File

@@ -6,6 +6,8 @@ use Zotlabs\Lib\Config;
class Site {
private string $eol;
private string $joo;
/**
* @brief POST handler for Admin Site Page.
@@ -208,7 +210,6 @@ class Site {
//Config::Set('system','force_queue_threshold', $force_queue);
Config::Set('system','no_community_page', $no_community_page);
Config::Set('system','no_utf', $no_utf);
Config::Set('system','sse_enabled', $sse_enabled);

View File

@@ -2,7 +2,7 @@
namespace Zotlabs\Module\Admin;
use \Michelf\MarkdownExtra;
use Michelf\MarkdownExtra;
use Zotlabs\Lib\Config;
/**

View File

@@ -108,6 +108,9 @@ class Api extends \Zotlabs\Web\Controller {
echo api_call();
killme();
// not reached
return;
}
function oauth_get_client($request){

View File

@@ -16,21 +16,21 @@ class Appman extends \Zotlabs\Web\Controller {
if(isset($_POST['url']) && $_POST['url']) {
$arr = array(
'uid' => intval($_REQUEST['uid']),
'url' => escape_tags($_REQUEST['url']),
'guid' => escape_tags($_REQUEST['guid']),
'author' => escape_tags($_REQUEST['author']),
'addr' => escape_tags($_REQUEST['addr']),
'name' => escape_tags($_REQUEST['name']),
'desc' => escape_tags($_REQUEST['desc']),
'photo' => escape_tags($_REQUEST['photo']),
'version' => escape_tags($_REQUEST['version']),
'price' => escape_tags($_REQUEST['price']),
'page' => escape_tags($_REQUEST['page']),
'requires' => escape_tags($_REQUEST['requires']),
'url' => escape_tags($_REQUEST['url'] ?? ''),
'guid' => escape_tags($_REQUEST['guid'] ?? ''),
'author' => escape_tags($_REQUEST['author'] ?? ''),
'addr' => escape_tags($_REQUEST['addr'] ?? ''),
'name' => escape_tags($_REQUEST['name'] ?? ''),
'desc' => escape_tags($_REQUEST['desc'] ?? ''),
'photo' => escape_tags($_REQUEST['photo'] ?? ''),
'version' => escape_tags($_REQUEST['version'] ?? ''),
'price' => escape_tags($_REQUEST['price'] ?? ''),
'page' => escape_tags($_REQUEST['page'] ?? ''),
'requires' => escape_tags($_REQUEST['requires'] ?? ''),
'system' => intval($_REQUEST['system']),
'plugin' => escape_tags($_REQUEST['plugin']),
'sig' => escape_tags($_REQUEST['sig']),
'categories' => escape_tags($_REQUEST['categories'])
'plugin' => escape_tags($_REQUEST['plugin'] ?? ''),
'sig' => escape_tags($_REQUEST['sig'] ?? ''),
'categories' => escape_tags($_REQUEST['categories'] ?? '')
);
$_REQUEST['appid'] = Apps::app_install(local_channel(),$arr);

View File

@@ -2,7 +2,7 @@
namespace Zotlabs\Module;
use \Zotlabs\Lib as Zlib;
use Zotlabs\Lib as Zlib;
class Apporder extends \Zotlabs\Web\Controller {
@@ -25,7 +25,7 @@ class Apporder extends \Zotlabs\Web\Controller {
$syslist[] = Zlib\Apps::app_encode($li);
}
}
Zlib\Apps::translate_system_apps($syslist);
usort($syslist,'Zotlabs\\Lib\\Apps::app_name_compare');

View File

@@ -1,8 +1,8 @@
<?php
namespace Zotlabs\Module;
use \Zotlabs\Lib\Config;
use \Zotlabs\Lib as Zlib;
use Zotlabs\Lib\Config;
use Zotlabs\Lib as Zlib;
class Apps extends \Zotlabs\Web\Controller {

View File

@@ -9,7 +9,7 @@ class Authorize extends \Zotlabs\Web\Controller {
function get() {
if (! local_channel()) {
return login();
}
}
else {
$name = $_REQUEST['client_name'];
@@ -25,7 +25,7 @@ class Authorize extends \Zotlabs\Web\Controller {
$link = (($app['url']) ? '<a style="float: none;" href="' . $app['url'] . '">' . $app['name'] . '</a> ' : $app['name']);
$o .= replace_macros(get_markup_template('oauth_authorize.tpl'), [
return replace_macros(get_markup_template('oauth_authorize.tpl'), [
'$title' => t('Authorize'),
'$authorize' => sprintf( t('Do you authorize the app %s to access your channel data?'), $link ),
'$app' => $app,
@@ -35,7 +35,6 @@ class Authorize extends \Zotlabs\Web\Controller {
'$redirect_uri' => (x($_REQUEST, 'redirect_uri') ? $_REQUEST['redirect_uri'] : ''),
'$state' => (x($_REQUEST, 'state') ? $_REQUEST['state'] : ''),
]);
return $o;
}
}
@@ -50,7 +49,7 @@ class Authorize extends \Zotlabs\Web\Controller {
// TODO: The automatic client registration protocol below should adhere more
// closely to "OAuth 2.0 Dynamic Client Registration Protocol" defined
// at https://tools.ietf.org/html/rfc7591
// If no client_id was provided, generate a new one.
if (x($_POST, 'client_id')) {
$client_id = $_POST['client_id'];
@@ -67,7 +66,7 @@ class Authorize extends \Zotlabs\Web\Controller {
$request = \OAuth2\Request::createFromGlobals();
$response = new \OAuth2\Response();
// Note, "sub" field must match type and content. $user_id is used to populate - make sure it's a string.
// Note, "sub" field must match type and content. $user_id is used to populate - make sure it's a string.
$channel = channelx_by_n(local_channel());
$user_id = $channel['channel_id'];

View File

@@ -7,7 +7,7 @@ class Authtest extends \Zotlabs\Web\Controller {
$auth_success = false;
$o .= '<h3>Magic-Auth Diagnostic</h3>';
$o = '<h3>Magic-Auth Diagnostic</h3>';
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
@@ -27,7 +27,7 @@ class Authtest extends \Zotlabs\Web\Controller {
$_REQUEST['test'] = 1;
$mod = new Magic();
$x = $mod->init($a);
$x = $mod->init();
$o .= 'Local Setup returns: ' . print_r($x,true);

View File

@@ -5,30 +5,30 @@ namespace Zotlabs\Module;
class Changeaddr extends \Zotlabs\Web\Controller {
function post() {
if(! local_channel())
return;
if($_SESSION['delegate'])
return;
if((! x($_POST,'qxz_password')) || (! strlen(trim($_POST['qxz_password']))))
return;
if((! x($_POST,'verify')) || (! strlen(trim($_POST['verify']))))
return;
if($_POST['verify'] !== $_SESSION['remove_account_verify'])
return;
$account = \App::get_account();
$channel = \App::get_channel();
$x = account_verify_password($account['account_email'],$_POST['qxz_password']);
if(! ($x && $x['account']))
return;
if($account['account_password_changed'] > NULL_DATE) {
$d1 = datetime_convert('UTC','UTC','now - 48 hours');
if($account['account_password_changed'] > $d1) {
@@ -36,7 +36,7 @@ class Changeaddr extends \Zotlabs\Web\Controller {
return;
}
}
$new_address = trim($_POST['newname']);
if($new_address === $channel['channel_address'])
@@ -55,23 +55,23 @@ class Changeaddr extends \Zotlabs\Web\Controller {
channel_change_address($channel,$new_address);
goaway(z_root() . '/changeaddr');
}
function get() {
if(! local_channel())
goaway(z_root());
$channel = \App::get_channel();
$hash = random_string();
$_SESSION['remove_account_verify'] = $hash;
$tpl = get_markup_template('channel_rename.tpl');
$o .= replace_macros($tpl, array(
return replace_macros($tpl, array(
'$basedir' => z_root(),
'$hash' => $hash,
'$title' => t('Change channel nickname/address'),
@@ -80,9 +80,5 @@ class Changeaddr extends \Zotlabs\Web\Controller {
'$newname' => array('newname', t('New channel address'),$channel['channel_address'], ''),
'$submit' => t('Rename Channel')
));
return $o;
}
}

View File

@@ -179,26 +179,14 @@ class Channel_calendar extends Controller {
if ($post_tags)
$datarray['term'] = $post_tags;
$item_id = event_store_item($datarray, $event);
$post = event_store_item($datarray, $event);
if ($item_id) {
$r = q("select * from item where id = %d",
intval($item_id)
);
if ($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
$z = q("select * from event where event_hash = '%s' and uid = %d limit 1",
dbesc($r[0]['resource_id']),
intval($channel['channel_id'])
);
if ($z) {
Libsync::build_sync_packet($channel['channel_id'], array('event_item' => array(encode_item($sync_item[0], true)), 'event' => $z));
}
}
if (!empty($post['item_id'])) {
Master::Summon(['Notifier', 'event', $post['item_id']]);
}
if (!empty($post['approval_id'])) {
Master::Summon(['Notifier', 'event', $post['approval_id']]);
}
Master::Summon(array('Notifier', 'event', $item_id));
killme();
@@ -470,13 +458,14 @@ class Channel_calendar extends Controller {
}
else {
// complex deletion that needs to propagate and be performed in phases
drop_item($i[0]['id'], true, DROPITEM_PHASE1);
drop_item($i[0]['id'], DROPITEM_PHASE1);
$complex = true;
}
$ii = q("select * from item where id = %d",
intval($i[0]['id'])
);
if ($ii) {
xchan_query($ii);
$sync_item = fetch_post_tags($ii);
@@ -485,6 +474,9 @@ class Channel_calendar extends Controller {
if ($complex) {
tag_deliver($i[0]['uid'], $i[0]['id']);
if (intval($i[0]['item_wall'])) {
Master::Summon(['Notifier', 'drop', $i[0]['id']]);
}
}
}
}

View File

@@ -4,7 +4,7 @@ namespace Zotlabs\Module;
require_once('include/security.php');
use \Zotlabs\Lib as Zlib;
use Zotlabs\Lib as Zlib;
class Chatsvc extends \Zotlabs\Web\Controller {

View File

@@ -8,10 +8,10 @@ namespace Zotlabs\Module;
*/
use Sabre\DAV as SDAV;
use \Zotlabs\Web\Controller;
use \Zotlabs\Storage\BasicAuth;
use \Zotlabs\Storage\Directory;
use \Zotlabs\Storage\Browser;
use Zotlabs\Web\Controller;
use Zotlabs\Storage\BasicAuth;
use Zotlabs\Storage\Directory;
use Zotlabs\Storage\Browser;
// composer autoloader for SabreDAV

View File

@@ -16,7 +16,7 @@ class Conversation extends Controller {
public function init() {
if (ActivityStreams::is_as_request()) {
if (ActivityStreams::is_as_request() || Libzot::is_zot_request()) {
$item_id = argv(1);
if (!$item_id) {
@@ -36,8 +36,7 @@ class Conversation extends Controller {
// do we have the item (at all)?
$r = q("select parent_mid from item where mid = '%s' or uuid = '%s' $item_normal order by item_wall desc limit 1",
dbesc(z_root() . '/item/' . $item_id),
$r = q("select parent_mid from item where uuid = '%s' $item_normal order by item_wall desc limit 1",
dbesc($item_id)
);
@@ -77,7 +76,7 @@ class Conversation extends Controller {
}
}
}
elseif (Config::get('system', 'require_authenticated_fetch', false)) {
elseif (Config::Get('system', 'require_authenticated_fetch', false)) {
http_status_exit(403, 'Permission denied');
}

View File

@@ -371,7 +371,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$tpl = get_markup_template('cover_photo.tpl');
$o .= replace_macros($tpl,array(
$output = replace_macros($tpl,array(
'$user' => \App::$channel['channel_address'],
'$info' => t('Your cover photo may be visible to anybody on the internet'),
'$existing' => get_cover_photo(local_channel(),'array',PHOTO_RES_COVER_850),
@@ -397,15 +397,15 @@ class Cover_photo extends \Zotlabs\Web\Controller {
));
call_hooks('cover_photo_content_end', $o);
call_hooks('cover_photo_content_end', $output);
return $o;
return $output;
}
else {
$filename = \App::$data['imagecrop'] . '-3';
$resolution = 3;
$tpl = get_markup_template("cropcover.tpl");
$o .= replace_macros($tpl,array(
return replace_macros($tpl,array(
'$filename' => $filename,
'$profile' => intval($_REQUEST['profile']),
'$resource' => \App::$data['imagecrop'] . '-3',
@@ -415,7 +415,6 @@ class Cover_photo extends \Zotlabs\Web\Controller {
'$form_security_token' => get_form_security_token("cover_photo"),
'$done' => t('Done Editing')
));
return $o;
}
}

View File

@@ -9,6 +9,7 @@
namespace Zotlabs\Module;
use Sabre\DAV as SDAV;
use Zotlabs\Lib\Libzot;
use Zotlabs\Storage;
use Zotlabs\Web\HTTPSig;

View File

@@ -344,7 +344,12 @@ class Display extends Controller {
'$profile_page' => xmlify(z_root() . '/display/' . gen_link_id($target_item['mid'])),
));
$x = [ 'xml' => $atom, 'channel' => $channel, 'observer_hash' => $observer_hash, 'params' => $params ];
$x = [
'xml' => $atom,
'channel' => $channel,
'observer_hash' => $observer_hash,
'params' => [],
];
call_hooks('atom_feed_top',$x);
$atom = $x['xml'];

View File

@@ -19,7 +19,7 @@ class Dreport extends \Zotlabs\Web\Controller {
$table = 'push';
if($mid) {
$i = q("select id from item where mid = '%s' and uid = %d and ( author_xchan = '%s' or ( owner_xchan = '%s' and item_wall = 1 )) ",
$i = q("select * from item where mid = '%s' and uid = %d and ( author_xchan = '%s' or ( owner_xchan = '%s' and item_wall = 1 )) ",
dbesc($mid),
intval($channel['channel_id']),
dbesc($channel['channel_hash']),
@@ -27,6 +27,12 @@ class Dreport extends \Zotlabs\Web\Controller {
);
if($i) {
\Zotlabs\Daemon\Master::Summon([ 'Notifier', 'edit_post', $i[0]['id'] ]);
$relatedItem = find_related($i[0]);
if (isset($relatedItem['id'])) {
\Zotlabs\Daemon\Master::Summon([ 'Notifier', 'edit_post', $relatedItem['id'] ]);
}
}
}
sleep(3);

View File

@@ -86,6 +86,7 @@ class Editpost extends \Zotlabs\Web\Controller {
'bbco_autocomplete'=> 'bbcode',
'return_path' => 'hq',
'button' => t('Submit'),
'disable_comments' => (($itm[0]['item_thread_top']) ? false : true),
'hide_voting' => true,
'hide_future' => true,
'hide_location' => true,

View File

@@ -6,6 +6,8 @@ namespace Zotlabs\Module;
* @author Fabio Comuni <fabrixxm@kirgroup.com>
*/
use function Zotlabs\Render\template_escape;
require_once('include/photo/photo_driver.php');
/**

View File

@@ -1,43 +1,54 @@
<?php
namespace Zotlabs\Module;
require_once('include/security.php');
require_once('include/bbcode.php');
require_once('include/items.php');
use App;
class Filer extends \Zotlabs\Web\Controller {
function get() {
if(! local_channel()) {
if(!local_channel()) {
killme();
}
$term = unxmlify(trim($_GET['term']));
$item_id = ((\App::$argc > 1) ? intval(\App::$argv[1]) : 0);
$term = unxmlify(trim($_GET['term'] ?? ''));
$item_id = ((App::$argc > 1) ? intval(App::$argv[1]) : 0);
logger('filer: tag ' . $term . ' item ' . $item_id);
if($item_id && strlen($term)){
$sys = get_sys_channel();
$r = q("SELECT * FROM item WHERE (uid = %d OR uid = %d) AND id = %d
and item_type in (0,6,7) and item_deleted = 0 and item_unpublished = 0
and item_delayed = 0 and item_pending_remove = 0 and item_blocked = 0 LIMIT 1",
intval(local_channel()),
intval($sys['channel_id']),
intval($item_id)
);
if ($r && $r[0]['uid'] === $sys['channel_id']) {
$r = [copy_of_pubitem(App::get_channel(), $r[0]['mid'])];
}
if(!$r) {
killme();
}
$item_id = $r[0]['id'];
// file item
store_item_tag(local_channel(),$item_id,TERM_OBJ_POST,TERM_FILE,$term,'');
// protect the entire conversation from periodic expiration
$r = q("select parent from item where id = %d and uid = %d limit 1",
intval($item_id),
q("update item set item_retained = 1, changed = '%s' where id = %d and uid = %d",
dbesc(datetime_convert()),
intval($r[0]['parent']),
intval(local_channel())
);
if($r) {
$x = q("update item set item_retained = 1, changed = '%s' where id = %d and uid = %d",
dbesc(datetime_convert()),
intval($r[0]['parent']),
intval(local_channel())
);
}
}
}
else {
$filetags = array();
$r = q("select distinct(term) from term where uid = %d and ttype = %d order by term asc",
@@ -55,10 +66,10 @@ class Filer extends \Zotlabs\Web\Controller {
'$title' => t('Save to Folder'),
'$cancel' => t('Cancel')
));
echo $o;
}
killme();
}
}

View File

@@ -2,7 +2,7 @@
namespace Zotlabs\Module;
use Zorlabs\Lib\Config;
use Zotlabs\Lib\Config;
class Go extends \Zotlabs\Web\Controller {
@@ -19,7 +19,7 @@ class Go extends \Zotlabs\Web\Controller {
function get() {
if(! local_channel()) {
notify( t('This page is available only to site members') . EOL);
notice( t('This page is available only to site members') . EOL);
}
$channel = \App::get_channel();

View File

@@ -6,6 +6,7 @@ use Michelf\MarkdownExtra;
/**
* You can create local site resources in doc/Site.md and either link to doc/Home.md for the standard resources
* or use our include mechanism to include it on your local page.
*
*@code
* #include doc/Home.md;
*@endcode
@@ -18,14 +19,6 @@ class Help extends \Zotlabs\Web\Controller {
private string $heading_slug = '';
/**
* Associative array containing the detected language.
*/
public array $lang = [
'language' => 'en', //! Detected language, 2-letter ISO 639-1 code ("en")
'from_url' => false, //! true if language from URL overrides browser default
];
/**
* Pre-check before processing request.
*
@@ -36,8 +29,8 @@ class Help extends \Zotlabs\Web\Controller {
public function init() {
$this->determine_help_language();
if (argc() === 1) {
goaway("/help/{$this->lang['language']}/about/about");
if (empty($_REQUEST['search']) && argc() === 1) {
goaway("/help/about/about");
killme();
}
}
@@ -69,6 +62,7 @@ class Help extends \Zotlabs\Web\Controller {
$o .= '</div>';
$o .= '<div class="section-content-wrapper">';
require_once('include/help.php');
$r = search_doc_files($_REQUEST['search']);
if($r) {
$o .= '<ul class="help-searchlist">';
@@ -160,6 +154,10 @@ class Help extends \Zotlabs\Web\Controller {
array_shift($args);
}
if (empty($args)) {
goaway("/help/about/about");
}
// Keep the first remaining arg as the heading slug
$this->heading_slug = $args[0];

View File

@@ -230,6 +230,7 @@ class Hq extends \Zotlabs\Web\Controller {
$options['offset'] = $_REQUEST['offset'] ?? 0;
$options['type'] = $_REQUEST['type'] ?? '';
$options['author'] = ((isset($_REQUEST['author'])) ? urldecode($_REQUEST['author']) : '');
$options['file'] = ((isset($_REQUEST['file'])) ? urldecode($_REQUEST['file']) : '');
$ret = Messages::get_messages_page($options);

View File

@@ -164,7 +164,7 @@ class Impel extends \Zotlabs\Web\Controller {
$arr['id'] = $i[0]['id'];
// don't update if it has the same timestamp as the original
if($arr['edited'] > $i[0]['edited'])
$x = item_store_update($arr,$execflag);
$x = item_store_update($arr, $execflag , deliver: false, addAndSync: false);
}
else {
if(($i) && (intval($i[0]['item_deleted']))) {
@@ -175,7 +175,7 @@ class Impel extends \Zotlabs\Web\Controller {
);
}
else
$x = item_store($arr,$execflag);
$x = item_store($arr, $execflag, deliver: false, addAndSync: false);
}
if($x && $x['success']) {

View File

@@ -534,6 +534,7 @@ class Import extends Controller {
if ($api_path) {
$parsed = parse_url($api_path);
unset($parsed['path']);
unset($parsed['query']);
// store the import host so we can manually kick off item/file sync later in case anything did not work out
set_pconfig($channel['channel_id'], 'import', 'host', $parsed['host']);
@@ -551,7 +552,7 @@ class Import extends Controller {
$until = datetime_convert(date_default_timezone_get(), date_default_timezone_get(), 'now + 1 day');
//$poll_interval = Config::Get('system', 'poll_interval', 3);
$page = 0;
$page = 0;
Master::Summon(['Content_importer', sprintf('%d', $page), $since, $until, $channel['channel_address'], urlencode($hz_server)]);
Master::Summon(['File_importer', sprintf('%d', $page), $channel['channel_address'], urlencode($hz_server)]);

View File

@@ -29,14 +29,14 @@ class Import_progress extends \Zotlabs\Web\Controller {
$c = PConfig::Get(local_channel(), 'import', 'content_progress');
if ($c) {
$total_cpages = floor(intval($c['items_total']) / intval($c['items_page']));
$total_cpages = round(intval($c['items_total']) / intval($c['items_page']));
if(!$total_cpages) {
$total_cpages = 1; // because of floor
$total_cpages = 1; // because of round
}
$cpage = $c['last_page'] + 1; // because page count start at 0
$cprogress = intval(floor((intval($cpage) * 100) / $total_cpages));
$cprogress = intval(round((intval($cpage) * 100) / $total_cpages));
$ccompleted_str = t('Item sync completed!');
if(argv(1) === 'resume_itemsync' && $cprogress < 100) {
@@ -50,6 +50,7 @@ class Import_progress extends \Zotlabs\Web\Controller {
if ($alive) {
$parsed = parse_url($alive);
unset($parsed['path']);
unset($parsed['query']);
$hz_server = unparse_url($parsed);
$since = datetime_convert(date_default_timezone_get(), date_default_timezone_get(), '0001-01-01 00:00');
@@ -79,14 +80,14 @@ class Import_progress extends \Zotlabs\Web\Controller {
$f = PConfig::Get(local_channel(), 'import', 'files_progress');
if ($f) {
$total_fpages = floor(intval($f['files_total']) / intval($f['files_page']));
$total_fpages = round(intval($f['files_total']) / intval($f['files_page']));
if(!$total_fpages) {
$total_fpages = 1;
}
$fpage = $f['last_page'] + 1;
$fprogress = intval(floor((intval($fpage) * 100) / $total_fpages));
$fprogress = intval(round((intval($fpage) * 100) / $total_fpages));
$fcompleted_str = t('File sync completed!');
if(argv(1) === 'resume_filesync' && $fprogress < 100) {
@@ -120,6 +121,7 @@ class Import_progress extends \Zotlabs\Web\Controller {
}
$fcompleted_str = t('File sync completed but no files were found!');
}
$fprogress_str = ((intval($fprogress)) ? $fprogress . '%' : $fprogress);
@@ -127,13 +129,15 @@ class Import_progress extends \Zotlabs\Web\Controller {
if(is_ajax()) {
$ret = [
'cprogress' => $cprogress,
'fprogress' => $fprogress
'ccompleted_str' => $ccompleted_str,
'fprogress' => $fprogress,
'fcompleted_str' => $fcompleted_str
];
json_return_and_die($ret);
}
$o = replace_macros(get_markup_template("import_progress.tpl"), [
return replace_macros(get_markup_template('import_progress.tpl'), [
'$chtitle_str' => t('Channel clone status'),
'$ctitle_str' => t('Item sync status'),
'$ftitle_str' => t('File sync status'),
@@ -147,8 +151,6 @@ class Import_progress extends \Zotlabs\Web\Controller {
'$resume_str' => t('Resume'),
'$resume_helper_str' => t('Only resume if sync stalled!')
]);
return $o;
}
}

View File

@@ -44,253 +44,30 @@ class Item extends Controller {
function init() {
if (Libzot::is_zot_request()) {
$item_id = argv(1);
if (!$item_id)
http_status_exit(404, 'Not found');
$portable_id = EMPTY_STR;
$item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
dbesc(ACTIVITY_FOLLOW),
dbesc(ACTIVITY_UNFOLLOW)
);
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
$i = null;
// do we have the item (at all)?
$r = q("select parent_mid from item where uuid = '%s' $item_normal limit 1",
dbesc($item_id)
);
if (!$r) {
http_status_exit(404, 'Not found');
}
// process an authenticated fetch
$sigdata = HTTPSig::verify(($_SERVER['REQUEST_METHOD'] === 'POST') ? file_get_contents('php://input') : EMPTY_STR);
if ($sigdata['portable_id'] && $sigdata['header_valid']) {
$portable_id = $sigdata['portable_id'];
if (!check_channelallowed($portable_id)) {
http_status_exit(403, 'Permission denied');
}
if (!check_siteallowed($sigdata['signer'])) {
http_status_exit(403, 'Permission denied');
}
observer_auth($portable_id);
$i = q("select id as item_id, uid from item where mid = '%s' $item_normal and owner_xchan = '%s' limit 1",
dbesc($r[0]['parent_mid']),
dbesc($portable_id)
);
}
elseif (Config::get('system', 'require_authenticated_fetch', false)) {
http_status_exit(403, 'Permission denied');
}
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
// with a bias towards those items owned by channels on this site (item_wall = 1)
$sql_extra = item_permissions_sql(0);
if (!$i) {
$i = q("select id as item_id, uid, item_private from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
dbesc($r[0]['parent_mid'])
);
}
if (!$i) {
http_status_exit(403, 'Forbidden');
}
$chan = channelx_by_n($i[0]['uid']);
if (!$chan) {
http_status_exit(404, 'Not found');
}
if (!perm_is_allowed($chan['channel_id'], get_observer_hash(), 'view_stream')) {
http_status_exit(403, 'Forbidden');
}
$parents_str = ids_to_querystr($i, 'item_id');
// We won't need to check for privacy mismatches if the verified observer is also owner
$parent_item_private = ((isset($i[0]['item_private'])) ? " and item_private = " . intval($i[0]['item_private']) . " " : '');
$total = q("SELECT count(*) AS count FROM item WHERE parent = %d $parent_item_private $item_normal ",
intval($parents_str)
);
App::set_pager_total($total[0]['count']);
App::set_pager_itemspage(30);
if (App::$pager['total'] > App::$pager['itemspage']) {
// let mod conversation handle this request
App::$query_string = str_replace('item', 'conversation', App::$query_string);
$i = Activity::paged_collection_init(App::$pager['total'], App::$query_string);
as_return_and_die($i ,$chan);
}
else {
$items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent = %d $parent_item_private $item_normal ORDER BY item.id",
intval($parents_str)
);
xchan_query($items, true);
$items = fetch_post_tags($items, true);
$i = Activity::encode_item_collection($items, App::$query_string, 'OrderedCollection', App::$pager['total']);
}
if ($portable_id && (!intval($items[0]['item_private']))) {
$c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'",
intval($items[0]['uid']),
dbesc($portable_id)
);
if (!$c) {
ThreadListener::store(z_root() . '/item/' . $item_id, $portable_id);
}
}
as_return_and_die($i ,$chan);
$this->init_zot_request();
}
if (ActivityStreams::is_as_request()) {
$item_id = argv(1);
if (!$item_id)
http_status_exit(404, 'Not found');
$portable_id = EMPTY_STR;
$item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
dbesc(ACTIVITY_FOLLOW),
dbesc(ACTIVITY_UNFOLLOW)
);
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
$i = null;
// do we have the item (at all)?
// add preferential bias to item owners (item_wall = 1)
$r = q("select * from item where uuid = '%s' $item_normal order by item_wall desc limit 1",
dbesc($item_id)
);
if (!$r) {
http_status_exit(404, 'Not found');
}
// process an authenticated fetch
$sigdata = HTTPSig::verify(EMPTY_STR);
if ($sigdata['portable_id'] && $sigdata['header_valid']) {
$portable_id = $sigdata['portable_id'];
if (!check_channelallowed($portable_id)) {
http_status_exit(403, 'Permission denied');
}
if (!check_siteallowed($sigdata['signer'])) {
http_status_exit(403, 'Permission denied');
}
observer_auth($portable_id);
$i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan = '%s' limit 1 ",
dbesc($r[0]['parent_mid']),
dbesc($portable_id)
);
}
elseif (Config::get('system', 'require_authenticated_fetch', false)) {
http_status_exit(403, 'Permission denied');
}
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
// with a bias towards those items owned by channels on this site (item_wall = 1)
$sql_extra = item_permissions_sql(0);
if (!$i) {
$i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
dbesc($r[0]['parent_mid'])
);
}
$bear = Activity::token_from_request();
if ($bear) {
logger('bear: ' . $bear, LOGGER_DEBUG);
if (!$i) {
$t = q("select * from iconfig where cat = 'ocap' and k = 'relay' and v = '%s'",
dbesc($bear)
);
if ($t) {
$i = q("select id as item_id from item where uuid = '%s' and id = %d $item_normal limit 1",
dbesc($item_id),
intval($t[0]['iid'])
);
}
}
}
if (!$i) {
http_status_exit(403, 'Forbidden');
}
// If we get to this point we have determined we can access the original in $r (fetched much further above), so use it.
xchan_query($r, true);
$items = fetch_post_tags($r, false);
$chan = channelx_by_n($items[0]['uid']);
if (!$chan)
http_status_exit(404, 'Not found');
if (!perm_is_allowed($chan['channel_id'], get_observer_hash(), 'view_stream'))
http_status_exit(403, 'Forbidden');
$i = Activity::encode_item($items[0]);
if (!$i)
http_status_exit(404, 'Not found');
if ($portable_id && (!intval($items[0]['item_private']))) {
$c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'",
intval($items[0]['uid']),
dbesc($portable_id)
);
if (!$c) {
ThreadListener::store(z_root() . '/item/' . $item_id, $portable_id);
}
}
as_return_and_die($i ,$chan);
$this->init_as_request();
}
if (argc() > 1 && argv(1) !== 'drop') {
$x = q("select uid, item_wall, llink, mid, uuid from item where mid = '%s' or mid = '%s' or uuid = '%s'",
dbesc(z_root() . '/item/' . argv(1)),
dbesc(z_root() . '/activity/' . argv(1)),
$x = q("select uid, item_wall, llink, uuid from item where uuid = '%s' order by item_wall desc",
dbesc(argv(1))
);
if ($x) {
foreach ($x as $xv) {
if (intval($xv['item_wall'])) {
$c = channelx_by_n($xv['uid']);
if ($c) {
goaway(z_root() . '/channel/' . $c['channel_address'] . '?mid=' . $xv['uuid']);
}
if ($x[0]['item_wall']) {
$c = channelx_by_n($x[0]['uid']);
if ($c) {
goaway(z_root() . '/channel/' . $c['channel_address'] . '?mid=' . $x[0]['uuid']);
}
}
goaway($x[0]['llink']);
}
http_status_exit(404, 'Not found');
}
@@ -323,7 +100,6 @@ class Item extends Controller {
$item_deleted = false;
$item_hidden = false;
$item_unpublished = false;
$item_delayed = false;
$item_pending_remove = false;
$item_blocked = false;
@@ -401,6 +177,7 @@ class Item extends Controller {
$categories = ((x($_REQUEST, 'category')) ? escape_tags($_REQUEST['category']) : '');
$webpage = ((x($_REQUEST, 'webpage')) ? intval($_REQUEST['webpage']) : 0);
$item_obscured = ((x($_REQUEST, 'obscured')) ? intval($_REQUEST['obscured']) : 0);
$item_delayed = ((x($_REQUEST, 'delayed')) ? intval($_REQUEST['delayed']) : 0);
$pagetitle = ((x($_REQUEST, 'pagetitle')) ? escape_tags($_REQUEST['pagetitle']) : '');
$layout_mid = ((x($_REQUEST, 'layout_mid')) ? escape_tags($_REQUEST['layout_mid']) : '');
$plink = ((x($_REQUEST, 'permalink')) ? escape_tags($_REQUEST['permalink']) : '');
@@ -430,7 +207,6 @@ class Item extends Controller {
$expires = NULL_DATE;
$comments_closed = NULL_DATE;
$route = '';
$parent_item = null;
@@ -677,7 +453,7 @@ class Item extends Controller {
$title = escape_tags(trim($_REQUEST['title']));
$summary = escape_tags(trim($_REQUEST['summary']));
$body = trim($_REQUEST['body']);
$item_flags = $orig_post['item_flags'];
$item_flags = $orig_post['item_flags'];
$item_origin = $orig_post['item_origin'];
$item_unseen = $orig_post['item_unseen'];
$item_starred = $orig_post['item_starred'];
@@ -691,7 +467,7 @@ class Item extends Controller {
$item_mentionsme = $orig_post['item_mentionsme'];
$item_nocomment = $orig_post['item_nocomment'];
$item_obscured = $orig_post['item_obscured'];
$item_verified = $orig_post['item_verified'];
$item_verified = $orig_post['item_verified'];
$item_retained = $orig_post['item_retained'];
$item_rss = $orig_post['item_rss'];
$item_deleted = $orig_post['item_deleted'];
@@ -837,8 +613,10 @@ class Item extends Controller {
if ($results) {
// Set permissions based on tag replacements
set_linkified_perms($results, $str_contact_allow, $str_group_allow, $profile_uid, $private, $parent_item);
// Set permissions based on tag replacements only if not editing an existing post
if (!$orig_post) {
set_linkified_perms($results, $str_contact_allow, $str_group_allow, $profile_uid, $private, $parent_item);
}
foreach ($results as $result) {
$success = $result['success'];
@@ -1014,6 +792,7 @@ class Item extends Controller {
$item_origin = (($origin) ? 1 : 0);
$item_consensus = (($consensus) ? 1 : 0);
$item_nocomment = (($nocomment) ? 1 : 0);
$comments_closed = (($nocomment) ? $comments_closed : NULL_DATE);
// determine if this is a wall post
@@ -1027,18 +806,44 @@ class Item extends Controller {
}
if ($moderated)
if ($moderated) {
$item_blocked = ITEM_MODERATED;
}
if (!strlen($verb))
if (!strlen($verb)) {
$verb = 'Create';
}
$notify_type = (($parent) ? 'comment-new' : 'wall-new');
$uuid = $uuid ?? $message_id ?? item_message_id();
$mid = $mid ?? z_root() . '/item/' . $uuid;
// Set the conversation target.
if (empty($owner_hash)) {
$owner_hash = $owner_xchan['xchan_hash'];
}
if ($owner_hash === $channel['channel_hash']) {
$attributedTo = z_root() . '/channel/' . $channel['channel_address'];
$conversation = isset($parent_item) ? $parent_item['mid'] : $mid;
$datarray['target'] = [
'id' => str_replace('/item/', '/conversation/', $conversation),
'type' => 'Collection',
'attributedTo' => $attributedTo,
];
$datarray['tgt_type'] = 'Collection';
}
elseif (!empty($parent_item['target'])) {
$datarray['target'] = $parent_item['target'];
$datarray['tgt_type'] = $parent_item['tgt_type'];
}
if ($is_poll) {
$poll = [
'question' => $body,
@@ -1058,7 +863,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;
@@ -1243,6 +1048,7 @@ class Item extends Controller {
$this->add_listeners($datarray);
}
/* sync this is done in item_store_update()
if (!$parent) {
$r = q("select * from item where id = %d",
intval($post_id)
@@ -1253,9 +1059,14 @@ class Item extends Controller {
Libsync::build_sync_packet($profile_uid, ['item' => [encode_item($sync_item[0], true)]]);
}
}
if (!$nopush)
Master::Summon(['Notifier', 'edit_post', $post_id]);
*/
if (!$nopush) {
Master::Summon(['Notifier', 'edit_post', $post_id]);
if (intval($x['approval_id'])) {
Master::Summon(['Notifier', 'edit_post', $x['approval_id']]);
}
}
if ($api_source)
return ($x);
@@ -1279,6 +1090,7 @@ class Item extends Controller {
}
$post_id = $post['item_id'];
$approval_id = $post['approval_id'] ?? 0;
$datarray = $post['item'];
@@ -1353,6 +1165,7 @@ class Item extends Controller {
killme();
}
/* sync this is done in item_store_update()
if ($parent || $datarray['item_private'] == 1) {
$r = q("select * from item where id = %d",
intval($post_id)
@@ -1363,6 +1176,7 @@ class Item extends Controller {
Libsync::build_sync_packet($profile_uid, ['item' => [encode_item($sync_item[0], true)]]);
}
}
*/
$datarray['id'] = $post_id;
$datarray['llink'] = z_root() . '/display/' . $datarray['uuid'];
@@ -1373,8 +1187,12 @@ class Item extends Controller {
$nopush = false;
}
if (!$nopush)
if (!$nopush) {
Master::Summon(['Notifier', $notify_type, $post_id]);
if ($approval_id) {
Master::Summon(['Notifier', $notify_type, $approval_id]);
}
}
logger('post_complete');
@@ -1427,10 +1245,7 @@ class Item extends Controller {
if ((argc() == 3) && (argv(1) === 'drop') && intval(argv(2))) {
require_once('include/items.php');
$i = q("select id, uid, item_origin, author_xchan, owner_xchan, source_xchan, item_type from item where id = %d limit 1",
$i = q("select * from item where id = %d limit 1",
intval(argv(2))
);
@@ -1457,7 +1272,6 @@ class Item extends Controller {
$can_delete = true;
}
if (!($can_delete || $local_delete)) {
notice(t('Permission denied.') . EOL);
return;
@@ -1473,13 +1287,14 @@ class Item extends Controller {
}
else {
// complex deletion that needs to propagate and be performed in phases
drop_item($i[0]['id'], true, DROPITEM_PHASE1);
drop_item($i[0]['id'], DROPITEM_PHASE1);
$complex = true;
}
$r = q("select * from item where id = %d",
intval($i[0]['id'])
);
if ($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
@@ -1488,6 +1303,9 @@ class Item extends Controller {
if ($complex) {
tag_deliver($i[0]['uid'], $i[0]['id']);
if (intval($i[0]['item_wall']) || $i[0]['mid'] !== $i[0]['parent_mid']) {
Master::Summon(['Notifier', 'drop', $i[0]['id']]);
}
}
}
@@ -1671,5 +1489,234 @@ class Item extends Controller {
}
}
private function init_zot_request() {
$item_id = argv(1);
if (!$item_id)
http_status_exit(404, 'Not found');
$portable_id = EMPTY_STR;
$item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
dbesc(ACTIVITY_FOLLOW),
dbesc(ACTIVITY_UNFOLLOW)
);
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
$i = null;
// do we have the item (at all)?
$r = q("select parent_mid from item where uuid = '%s' $item_normal limit 1",
dbesc($item_id)
);
if (!$r) {
http_status_exit(404, 'Not found');
}
// process an authenticated fetch
$sigdata = HTTPSig::verify(($_SERVER['REQUEST_METHOD'] === 'POST') ? file_get_contents('php://input') : EMPTY_STR);
if ($sigdata['portable_id'] && $sigdata['header_valid']) {
$portable_id = $sigdata['portable_id'];
if (!check_channelallowed($portable_id)) {
http_status_exit(403, 'Permission denied');
}
if (!check_siteallowed($sigdata['signer'])) {
http_status_exit(403, 'Permission denied');
}
observer_auth($portable_id);
$i = q("select id as item_id, uid from item where mid = '%s' $item_normal and owner_xchan = '%s' limit 1",
dbesc($r[0]['parent_mid']),
dbesc($portable_id)
);
}
elseif (Config::get('system', 'require_authenticated_fetch', false)) {
http_status_exit(403, 'Permission denied');
}
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
// with a bias towards those items owned by channels on this site (item_wall = 1)
$sql_extra = item_permissions_sql(0);
if (!$i) {
$i = q("select id as item_id, uid, item_private from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
dbesc($r[0]['parent_mid'])
);
}
if (!$i) {
http_status_exit(403, 'Forbidden');
}
$chan = channelx_by_n($i[0]['uid']);
if (!$chan) {
http_status_exit(404, 'Not found');
}
if (!perm_is_allowed($chan['channel_id'], get_observer_hash(), 'view_stream')) {
http_status_exit(403, 'Forbidden');
}
$parents_str = ids_to_querystr($i, 'item_id');
// We won't need to check for privacy mismatches if the verified observer is also owner
$parent_item_private = ((isset($i[0]['item_private'])) ? " and item_private = " . intval($i[0]['item_private']) . " " : '');
$total = q("SELECT count(*) AS count FROM item WHERE parent = %d $parent_item_private $item_normal ",
intval($parents_str)
);
App::set_pager_total($total[0]['count']);
App::set_pager_itemspage(30);
if (App::$pager['total'] > App::$pager['itemspage']) {
// let mod conversation handle this request
App::$query_string = str_replace('item', 'conversation', App::$query_string);
$i = Activity::paged_collection_init(App::$pager['total'], App::$query_string);
as_return_and_die($i ,$chan);
}
else {
$items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent = %d $parent_item_private $item_normal ORDER BY item.id",
intval($parents_str)
);
xchan_query($items, true);
$items = fetch_post_tags($items, true);
$i = Activity::encode_item_collection($items, App::$query_string, 'OrderedCollection', App::$pager['total']);
}
if ($portable_id && (!intval($items[0]['item_private']))) {
$c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'",
intval($items[0]['uid']),
dbesc($portable_id)
);
if (!$c) {
ThreadListener::store(z_root() . '/item/' . $item_id, $portable_id);
}
}
as_return_and_die($i ,$chan);
}
private function init_as_request() {
$item_id = argv(1);
if (!$item_id)
http_status_exit(404, 'Not found');
$portable_id = EMPTY_STR;
$item_normal_extra = sprintf(" and not verb in ('Follow', 'Ignore', '%s', '%s') ",
dbesc(ACTIVITY_FOLLOW),
dbesc(ACTIVITY_UNFOLLOW)
);
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 $item_normal_extra ";
$i = null;
// do we have the item (at all)?
// add preferential bias to item owners (item_wall = 1)
$r = q("select * from item where uuid = '%s' $item_normal order by item_wall desc limit 1",
dbesc($item_id)
);
if (!$r) {
http_status_exit(404, 'Not found');
}
// process an authenticated fetch
$sigdata = HTTPSig::verify(EMPTY_STR);
if ($sigdata['portable_id'] && $sigdata['header_valid']) {
$portable_id = $sigdata['portable_id'];
if (!check_channelallowed($portable_id)) {
http_status_exit(403, 'Permission denied');
}
if (!check_siteallowed($sigdata['signer'])) {
http_status_exit(403, 'Permission denied');
}
observer_auth($portable_id);
$i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan = '%s' limit 1 ",
dbesc($r[0]['parent_mid']),
dbesc($portable_id)
);
}
elseif (Config::get('system', 'require_authenticated_fetch', false)) {
http_status_exit(403, 'Permission denied');
}
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
// with a bias towards those items owned by channels on this site (item_wall = 1)
$sql_extra = item_permissions_sql(0);
if (!$i) {
$i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
dbesc($r[0]['parent_mid'])
);
}
$bear = Activity::token_from_request();
if ($bear) {
logger('bear: ' . $bear, LOGGER_DEBUG);
if (!$i) {
$t = q("select * from iconfig where cat = 'ocap' and k = 'relay' and v = '%s'",
dbesc($bear)
);
if ($t) {
$i = q("select id as item_id from item where uuid = '%s' and id = %d $item_normal limit 1",
dbesc($item_id),
intval($t[0]['iid'])
);
}
}
}
if (!$i) {
http_status_exit(403, 'Forbidden');
}
// If we get to this point we have determined we can access the original in $r (fetched much further above), so use it.
xchan_query($r, true);
$items = fetch_post_tags($r, false);
$chan = channelx_by_n($items[0]['uid']);
if (!$chan)
http_status_exit(404, 'Not found');
if (!perm_is_allowed($chan['channel_id'], get_observer_hash(), 'view_stream'))
http_status_exit(403, 'Forbidden');
$i = Activity::encode_item($items[0]);
if (!$i)
http_status_exit(404, 'Not found');
if ($portable_id && (!intval($items[0]['item_private']))) {
$c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'",
intval($items[0]['uid']),
dbesc($portable_id)
);
if (!$c) {
ThreadListener::store(z_root() . '/item/' . $item_id, $portable_id);
}
}
as_return_and_die($i ,$chan);
}
}

View File

@@ -284,7 +284,7 @@ class Like extends Controller {
intval($ch[0]['channel_id'])
);
if ($r)
drop_item($r[0]['id'], false);
drop_item($r[0]['id']);
if ($interactive) {
notice(t('Previous action reversed.') . EOL);
return $o;
@@ -387,17 +387,20 @@ class Like extends Controller {
// already liked it. Drop that item.
require_once('include/items.php');
foreach ($r as $rr) {
drop_item($rr['id'], false, DROPITEM_PHASE1);
drop_item($rr['id'], DROPITEM_PHASE1);
// set the changed timestamp on the parent so we'll see the update without a page reload
q("update item set changed = '%s' where id = %d and uid = %d",
dbesc(datetime_convert()),
intval($rr['parent']),
intval($rr['uid'])
);
// Prior activity was a duplicate of the one we're submitting, just undo it;
// don't fall through and create another
if (activity_match($rr['verb'], $activity))
if (activity_match($rr['verb'], $activity)) {
$multi_undo = false;
}
$d = q("select * from item where id = %d",
intval($rr['id'])
@@ -559,6 +562,7 @@ class Like extends Controller {
$post = item_store($arr);
$post_id = $post['item_id'];
$approval_id = $post['approval_id'] ?? 0;
// save the conversation from expiration
@@ -569,6 +573,12 @@ class Like extends Controller {
call_hooks('post_local_end', $arr);
if ($is_rsvp && in_array($verb, ['attendyes', 'attendmaybe'])) {
event_addtocal($item_id, local_channel());
}
/* Item sync is now done in item_store()
$r = q("select * from item where id = %d",
intval($post_id)
);
@@ -577,7 +587,7 @@ class Like extends Controller {
$sync_item = fetch_post_tags($r);
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')",
@@ -604,7 +614,10 @@ class Like extends Controller {
}
Master::Summon(array('Notifier', 'like', $post_id));
Master::Summon(['Notifier', 'like', $post_id]);
if ($approval_id) {
Master::Summon(['Notifier', 'like', $approval_id]);
}
if ($interactive) {
notice(t('Action completed.') . EOL);

View File

@@ -227,7 +227,7 @@ class Lockview extends Controller {
$allowed_xchans = array_unique($allowed_xchans);
foreach ($atokens as $atoken) {
if (in_array($atoken['xchan_hash'], $allowed_xchans)) {
$guest_access_list[] = '<div class="dropdown-item d-flex justify-content-between cursor-pointer" title="' . sprintf(t('Click to copy link to this ressource for guest %s to clipboard'), $atoken['xchan_name']) . '" data-token="' . $url . '?zat=' . $atoken['atoken_token'] . '" onclick="navigator.clipboard.writeText(this.dataset.token); toast(\'' . t('Link copied') . '\', \'info\');"><span>' . $atoken['xchan_name'] . '</span><i class="fa fa-copy p-1"></i></div>';
$guest_access_list[] = '<div class="dropdown-item d-flex justify-content-between cursor-pointer" title="' . sprintf(t('Click to copy link to this ressource for guest %s to clipboard'), $atoken['xchan_name']) . '" data-token="' . $url . '?zat=' . $atoken['atoken_token'] . '" onclick="navigator.clipboard.writeText(this.dataset.token); toast(\'' . t('Link copied') . '\', \'info\');"><span>' . $atoken['xchan_name'] . '</span><i class="bi bi-copy p-1"></i></div>';
}
}
}

View File

@@ -12,5 +12,5 @@ class Login extends \Zotlabs\Web\Controller {
return login(true);
}
}

View File

@@ -11,37 +11,43 @@ class Magic extends Controller {
function init() {
$ret = [
'success' => false,
'url' => '',
'message' => ''
];
logger('mod_magic: invoked', LOGGER_DEBUG);
logger('args: ' . print_r($_REQUEST,true),LOGGER_DATA);
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$data = $_POST;
} elseif ($_SERVER['REQUEST_METHOD'] === 'GET') {
$data = $_GET;
} else {
http_status_exit(405, 'Method Not Allowed');
}
$addr = ((x($_REQUEST,'addr')) ? $_REQUEST['addr'] : '');
$bdest = ((x($_REQUEST,'bdest')) ? $_REQUEST['bdest'] : '');
$dest = ((x($_REQUEST,'dest')) ? $_REQUEST['dest'] : '');
$rev = ((x($_REQUEST,'rev')) ? intval($_REQUEST['rev']) : 0);
$owa = ((x($_REQUEST,'owa')) ? intval($_REQUEST['owa']) : 0);
$delegate = ((x($_REQUEST,'delegate')) ? $_REQUEST['delegate'] : '');
logger('request method: ' . print_r($_SERVER['REQUEST_METHOD'], true), LOGGER_DATA);
logger('args: ' . print_r($data, true), LOGGER_DATA);
$bdest = $data['bdest'] ?? '';
$owa = $data['owa'] ?? 0;
$delegate = $data['delegate'] ?? '';
// bdest is preferred as it is hex-encoded and can survive url rewrite and argument parsing
if ($bdest) {
$dest = hex2bin($bdest);
if (!$bdest) {
http_status_exit(400, 'Bad Request');
}
$dest = hex2bin($bdest);
$parsed = parse_url($dest);
if (! $parsed) {
goaway($dest);
if (!$parsed) {
http_status_exit(400, 'Bad Request');
}
$basepath = $parsed['scheme'] . '://' . $parsed['host'] . (isset($parsed['port']) ? ':' . $parsed['port'] : '');
$owapath = SConfig::get($basepath,'system','openwebauth', $basepath . '/owa');
$basepath = unparse_url(array_filter(
$parsed,
fn (string $key) => in_array($key, ['scheme', 'host', 'port']),
ARRAY_FILTER_USE_KEY
));
$owapath = SConfig::get($basepath, 'system', 'openwebauth', $basepath . '/owa');
// This is ready-made for a plugin that provides a blacklist or "ask me" before blindly authenticating.
// By default, we'll proceed without asking.
@@ -53,12 +59,14 @@ class Magic extends Controller {
];
call_hooks('magic_auth',$arr);
$dest = $arr['destination'];
if (! $arr['proceed']) {
if (!$arr['proceed']) {
goaway($dest);
}
if((get_observer_hash()) && (stripos($dest,z_root()) === 0)) {
if (get_observer_hash() && str_starts_with($dest, z_root())) {
// We are already authenticated on this site and a registered observer.
// First check if this is a delegate request on the local system and process accordingly.
@@ -106,29 +114,32 @@ class Magic extends Controller {
$headers['Content-Type'] = 'application/x-zot+json' ;
$headers['X-Open-Web-Auth'] = random_string();
$headers['Host'] = $parsed['host'];
$headers['(request-target)'] = 'get ' . '/owa';
$headers['(request-target)'] = 'get /owa';
$headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512');
$redirects = 0;
$x = z_fetch_url($owapath, false, $redirects, ['headers' => $headers]);
logger('owa fetch returned: ' . print_r($x,true),LOGGER_DATA);
if ($x['success']) {
$j = json_decode($x['body'],true);
if ($j['success'] && $j['encrypted_token']) {
// decrypt the token using our private key
$token = '';
openssl_private_decrypt(base64url_decode($j['encrypted_token']),$token,$channel['channel_prvkey']);
openssl_private_decrypt(base64url_decode($j['encrypted_token']), $token, $channel['channel_prvkey']);
$x = strpbrk($dest,'?&');
// redirect using the encrypted token which will be exchanged for an authenticated session
$args = (($x) ? '&owt=' . $token : '?f=&owt=' . $token) . (($delegate) ? '&delegate=1' : '');
$args = (($x) ? '&owt=' . $token : '?owt=' . $token) . (($delegate) ? '&delegate=1' : '');
goaway($dest . $args);
}
}
}
}
goaway($dest);
killme();
}
}

View File

@@ -184,8 +184,8 @@ class Mitem extends \Zotlabs\Web\Controller {
'$nick' => $which,
'$sys' => \App::$is_sys
));
$o .= replace_macros(get_markup_template('mitemlist.tpl'),array(
return replace_macros(get_markup_template('mitemlist.tpl'),array(
'$title' => t('Menu:'),
'$create' => $create,
'$nametitle' => t('Link Name'),
@@ -204,29 +204,27 @@ class Mitem extends \Zotlabs\Web\Controller {
'$hintedit' => t('Edit this menu item'),
'$nick' => $which,
));
return $o;
}
if(argc() > 3) {
if(intval(argv(3))) {
$m = q("select * from menu_item where mitem_id = %d and mitem_channel_id = %d limit 1",
intval(argv(3)),
intval($owner)
);
if(! $m) {
notice( t('Menu item not found.') . EOL);
goaway(z_root() . '/menu/'. $which . ((\App::$is_sys) ? '?f=&sys=1' : ''));
}
$mitem = $m[0];
$lockstate = (($mitem['allow_cid'] || $mitem['allow_gid'] || $mitem['deny_cid'] || $mitem['deny_gid']) ? 'lock' : 'unlock');
if(argc() == 5 && argv(4) == 'drop') {
menu_sync_packet($owner,get_observer_hash(),$mitem['mitem_menu_id']);
$r = menu_del_item($mitem['mitem_menu_id'], $owner, intval(argv(3)));
@@ -235,12 +233,12 @@ class Mitem extends \Zotlabs\Web\Controller {
info( t('Menu item deleted.') . EOL);
else
notice( t('Menu item could not be deleted.'). EOL);
goaway(z_root() . '/mitem/' . $which . '/' . $mitem['mitem_menu_id'] . ((\App::$is_sys) ? '?f=&sys=1' : ''));
}
// edit menu item
$o = replace_macros(get_markup_template('mitemedit.tpl'), array(
return replace_macros(get_markup_template('mitemedit.tpl'), array(
'$header' => t('Edit Menu Element'),
'$menu_id' => \App::$data['menu']['menu_id'],
'$permissions' => t('Menu Item Permissions'),
@@ -261,10 +259,8 @@ class Mitem extends \Zotlabs\Web\Controller {
'$menu_names' => $menu_names,
'$nick' => $which
));
return $o;
}
}
}
}

View File

@@ -74,7 +74,7 @@ class Moderate extends \Zotlabs\Web\Controller {
// let the sender know we received their comment but we don't permit spam here.
// Activity::send_rejection_activity(App::get_channel(), $item['author_xchan'], $item);
drop_item($post_id,false);
drop_item($post_id);
notice( t('Item deleted') . EOL);
}

View File

@@ -13,31 +13,34 @@ class Notes extends Controller {
function post() {
if(! local_channel())
return EMPTY_STR;
if(!local_channel()) {
return;
}
if(! Apps::system_app_installed(local_channel(), 'Notes'))
return EMPTY_STR;
if(!Apps::system_app_installed(local_channel(), 'Notes')) {
return;
}
$ret = [
'success' => false,
'html' => ''
];
if(array_key_exists('note_text',$_REQUEST)) {
if (array_key_exists('note_text',$_REQUEST)) {
$body = escape_tags($_REQUEST['note_text']);
// I've had my notes vanish into thin air twice in four years.
// Provide a backup copy if there were contents previously
// and there are none being saved now.
if(! $body) {
$old_text = get_pconfig(local_channel(),'notes','text');
if($old_text)
set_pconfig(local_channel(),'notes','text.bak',$old_text);
if(!$body) {
$old_text = get_pconfig(local_channel(), 'notes', 'text');
if ($old_text) {
set_pconfig(local_channel(), 'notes', 'text.bak', $old_text);
}
}
set_pconfig(local_channel(),'notes','text',$body);
set_pconfig(local_channel(), 'notes', 'text', $body);
$ret['html'] = bbcode($body, ['tryoembed' => false]);
$ret['success'] = true;
@@ -55,8 +58,9 @@ class Notes extends Controller {
}
function get() {
if(! local_channel())
if(!local_channel()) {
return EMPTY_STR;
}
if(! Apps::system_app_installed(local_channel(), 'Notes')) {
//Do not display any associated widgets at this point
@@ -65,6 +69,8 @@ class Notes extends Controller {
return Apps::app_render($papp, 'module');
}
App::$profile_uid = local_channel();
$w = new \Zotlabs\Widget\Notes;
$arr = ['app' => true];

View File

@@ -1,8 +1,8 @@
<?php
namespace Zotlabs\Module;
use \Zotlabs\Lib\PConfig;
use \Zotlabs\Web\Controller;
use Zotlabs\Lib\PConfig;
use Zotlabs\Web\Controller;
class Notify extends Controller {

View File

@@ -31,8 +31,8 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller {
$_SESSION['api_response'] = (x($_SESSION, 'api_response') ? $_SESSION['api_response'] : '');
}
function get() {
$o .= replace_macros(get_markup_template('oauth2testvehicle.tpl'), array(
$output = replace_macros(get_markup_template('oauth2testvehicle.tpl'), array(
'$baseurl' => z_root(),
'$api_response' => $_SESSION['api_response'],
/*
@@ -97,8 +97,10 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller {
)
)
));
$_SESSION['success'] = '';
return $o;
return $output;
}
function post() {

View File

@@ -103,7 +103,8 @@ class Oauth extends Controller {
if((argc() > 1) && (argv(1) === 'add')) {
$tpl = get_markup_template("oauth_edit.tpl");
$o .= replace_macros($tpl, array(
return replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("oauth"),
'$title' => t('Add application'),
'$submit' => t('Submit'),
@@ -114,7 +115,6 @@ class Oauth extends Controller {
'$redirect' => array('redirect', t('Redirect'), '', t('Redirect URI - leave blank unless your application specifically requires this')),
'$icon' => array('icon', t('Icon url'), '', t('Optional')),
));
return $o;
}
if((argc() > 2) && (argv(1) === 'edit')) {
@@ -129,7 +129,7 @@ class Oauth extends Controller {
$app = $r[0];
$tpl = get_markup_template("oauth_edit.tpl");
$o .= replace_macros($tpl, array(
return replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("oauth"),
'$title' => t('Add application'),
'$submit' => t('Update'),
@@ -140,7 +140,6 @@ class Oauth extends Controller {
'$redirect' => array('redirect', t('Redirect'), $app['redirect_uri'], ''),
'$icon' => array('icon', t('Icon url'), $app['icon'], ''),
));
return $o;
}
if((argc() > 2) && (argv(1) === 'delete')) {
@@ -163,7 +162,8 @@ class Oauth extends Controller {
$tpl = get_markup_template("oauth.tpl");
$o .= replace_macros($tpl, array(
return replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("oauth"),
'$baseurl' => z_root(),
'$title' => t('Connected OAuth Apps'),
@@ -175,8 +175,6 @@ class Oauth extends Controller {
'$remove' => t('Remove authorization'),
'$apps' => $r,
));
return $o;
}
}

View File

@@ -108,7 +108,8 @@ class Oauth2 extends Controller {
if((argc() > 1) && (argv(1) === 'add')) {
$tpl = get_markup_template("oauth2_edit.tpl");
$o .= replace_macros($tpl, array(
return replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("oauth2"),
'$title' => t('Add OAuth2 application'),
'$submit' => t('Submit'),
@@ -119,7 +120,6 @@ class Oauth2 extends Controller {
'$grant' => array('grant', t('Grant Types'), '', t('leave blank unless your application sepcifically requires this')),
'$scope' => array('scope', t('Authorization scope'), '', t('leave blank unless your application sepcifically requires this')),
));
return $o;
}
if((argc() > 2) && (argv(1) === 'edit')) {
@@ -136,7 +136,7 @@ class Oauth2 extends Controller {
$app = $r[0];
$tpl = get_markup_template("oauth2_edit.tpl");
$o .= replace_macros($tpl, array(
return replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("oauth2"),
'$title' => t('Add application'),
'$submit' => t('Update'),
@@ -147,7 +147,6 @@ class Oauth2 extends Controller {
'$grant' => array('grant', t('Grant Types'), $app['grant_types'], t('leave blank unless your application specifically requires this')),
'$scope' => array('scope', t('Authorization scope'), $app['scope'], t('leave blank unless your application specifically requires this')),
));
return $o;
}
if((argc() > 2) && (argv(1) === 'delete')) {
@@ -184,7 +183,8 @@ class Oauth2 extends Controller {
);
$tpl = get_markup_template("oauth2.tpl");
$o .= replace_macros($tpl, array(
return replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("oauth2"),
'$baseurl' => z_root(),
'$title' => t('Connected OAuth2 Apps'),
@@ -196,8 +196,6 @@ class Oauth2 extends Controller {
'$remove' => t('Remove authorization'),
'$apps' => $r,
));
return $o;
}
}

View File

@@ -183,9 +183,7 @@ class Page extends \Zotlabs\Web\Controller {
if($r[0]['mimetype'] === 'application/x-pdl')
\App::$page['pdl_content'] = true;
$o .= prepare_page($r[0]);
return $o;
return prepare_page($r[0]);
}
}

View File

@@ -51,7 +51,7 @@ class Pdledit extends Controller {
if(argc() > 1)
$module = 'mod_' . argv(1) . '.pdl';
else {
$o .= '<div class="generic-content-wrapper-styled">';
$o = '<div class="generic-content-wrapper-styled">';
$o .= '<h1>' . t('Edit System Page Description') . '</h1>';
$edited = [];

View File

@@ -2,7 +2,7 @@
namespace Zotlabs\Module;
use \Zotlabs\Lib as Zlib;
use Zotlabs\Lib as Zlib;
class Permcat extends \Zotlabs\Web\Controller {
@@ -22,4 +22,4 @@ class Permcat extends \Zotlabs\Web\Controller {
}
}
}

View File

@@ -1122,7 +1122,7 @@ class Photos extends \Zotlabs\Web\Controller {
if(is_array($like_list) && (count($like_list) > MAX_LIKERS)) {
$like_list_part = array_slice($like_list, 0, MAX_LIKERS);
array_push($like_list_part, '<a href="#" data-toggle="modal" data-target="#likeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
array_push($like_list_part, '<a href="#" data-bs-toggle="modal" data-bs-target="#likeModal-' . $link_item['id'] . '"><b>' . t('View all') . '</b></a>');
} else {
$like_list_part = '';
}
@@ -1134,7 +1134,7 @@ class Photos extends \Zotlabs\Web\Controller {
$dislike_button_label = tt('Dislike','Dislikes',$dislike_count,'noun');
if (is_array($dislike_list) && (count($dislike_list) > MAX_LIKERS)) {
$dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS);
array_push($dislike_list_part, '<a href="#" data-toggle="modal" data-target="#dislikeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
array_push($dislike_list_part, '<a href="#" data-bs-toggle="modal" data-bs-target="#dislikeModal-' . $link_item['id'] . '"><b>' . t('View all') . '</b></a>');
} else {
$dislike_list_part = '';
}

View File

@@ -55,6 +55,8 @@ class Profperm extends \Zotlabs\Web\Controller {
}
$o = '';
if((argc() > 1) && (intval(argv(1)))) {
$r = q("SELECT * FROM profile WHERE id = %d AND uid = %d AND is_default = 0 LIMIT 1",
intval(argv(1)),

View File

@@ -49,18 +49,18 @@ class Pubsites extends \Zotlabs\Web\Controller {
}
$m = parse_url($jj['url']);
$host = strtolower(substr($jj['url'],strpos($jj['url'],'://')+3));
$rate_links = ((local_channel()) ? '<td><a href="rate?f=&target=' . $host . '" class="btn-btn-default"><i class="fa fa-check-square-o"></i> ' . t('Rate') . '</a></td>' : '');
$rate_links = ((local_channel()) ? '<td><a href="rate?f=&target=' . $host . '" class="btn-btn-default"><i class="bi bi-check-square"></i> ' . t('Rate') . '</a></td>' : '');
$location = '';
if(!empty($jj['location'])) {
$location = '<p title="' . t('Location') . '" style="margin: 5px 5px 0 0; text-align: right"><i class="fa fa-globe"></i> ' . $jj['location'] . '</p>';
$location = '<p title="' . t('Location') . '" style="margin: 5px 5px 0 0; text-align: right"><i class="bi bi-globe"></i> ' . $jj['location'] . '</p>';
}
else {
$location = '<br />&nbsp;';
}
$urltext = str_replace(array('https://'), '', $jj['url']);
$o .= '<tr><td><a href="'. (($jj['sellpage']) ? $jj['sellpage'] : $jj['url'] . '/register' ) . '" ><i class="fa fa-link"></i> ' . $urltext . '</a>' . $location . '</td><td>' . $jj['access'] . '</td><td>' . $jj['register'] . '</td><!--td>' . '<a target="stats" href="https://hubchart-tarine.rhcloud.com/hub.jsp?hubFqdn=' . $m['host'] . '"><i class="fa fa-area-chart"></i></a></td--><td>' . ucwords($jj['project']) . (($jj['version']) ? ' ' . $jj['version'] : '') . '</td>';
$o .= '<tr><td><a href="'. (($jj['sellpage']) ? $jj['sellpage'] : $jj['url'] . '/register' ) . '" ><i class="bi bi-link-45deg"></i> ' . $urltext . '</a>' . $location . '</td><td>' . $jj['access'] . '</td><td>' . $jj['register'] . '</td><!--td>' . '<a target="stats" href="https://hubchart-tarine.rhcloud.com/hub.jsp?hubFqdn=' . $m['host'] . '"><i class="bi bi-graph-up"></i></a></td--><td>' . ucwords($jj['project']) . (($jj['version']) ? ' ' . $jj['version'] : '') . '</td>';
if($rating_enabled)
$o .= '<td><a href="ratings/' . $host . '" class="btn-btn-default"><i class="fa fa-eye"></i> ' . t('View') . '</a></td>' . $rate_links ;
$o .= '<td><a href="ratings/' . $host . '" class="btn-btn-default"><i class="bi bi-eye"></i> ' . t('View') . '</a></td>' . $rate_links ;
$o .= '</tr>';
}
}

View File

@@ -202,11 +202,9 @@ class Pubstream extends \Zotlabs\Web\Controller {
if($mid) {
$r = q("SELECT parent AS item_id FROM item
left join abook on item.author_xchan = abook.abook_xchan
left join xchan on item.author_xchan = xchan.xchan_hash
WHERE item.$identifier = '%s' and item.item_private = 0
$uids $site_firehose_sql
$item_normal
and xchan.xchan_censored = 0
and (abook.abook_blocked = 0 or abook.abook_flags is null)
$sql_extra $net_query2",
dbesc($mid)
@@ -216,11 +214,9 @@ class Pubstream extends \Zotlabs\Web\Controller {
// Fetch a page full of parent items for this page
$r = dbq("SELECT parent AS item_id FROM item
left join abook on ( item.author_xchan = abook.abook_xchan $abook_uids )
left join xchan on item.author_xchan = xchan.xchan_hash
WHERE item.item_private = 0 $thread_top
$uids $site_firehose_sql
$item_normal
and xchan.xchan_censored = 0
and (abook.abook_blocked = 0 or abook.abook_flags is null)
$sql_extra $net_query2
ORDER BY $ordering DESC $pager_sql "
@@ -231,10 +227,8 @@ class Pubstream extends \Zotlabs\Web\Controller {
if($mid) {
$r = q("SELECT parent AS item_id FROM item
left join abook on item.author_xchan = abook.abook_xchan
left join xchan on item.author_xchan = xchan.xchan_hash
WHERE item.$identifier = '%s' and item.item_private = 0
$uids $site_firehose_sql $item_normal_update $simple_update
and xchan.xchan_censored = 0
and (abook.abook_blocked = 0 or abook.abook_flags is null)
$sql_extra $net_query2",
dbesc($mid)
@@ -243,11 +237,9 @@ class Pubstream extends \Zotlabs\Web\Controller {
else {
$r = dbq("SELECT parent AS item_id FROM item
left join abook on item.author_xchan = abook.abook_xchan
left join xchan on item.author_xchan = xchan.xchan_hash
WHERE item.item_private = 0 $thread_top
$uids $site_firehose_sql $item_normal_update
$simple_update
and xchan.xchan_censored = 0
and (abook.abook_blocked = 0 or abook.abook_flags is null)
$sql_extra $net_query2"
);

View File

@@ -91,6 +91,9 @@ class React extends Controller {
if ($x['success']) {
$nid = $x['item_id'];
Master::Summon(['Notifier', 'like', $nid]);
if (!empty($x['approval_id'])) {
Master::Summon(['Notifier', 'like', $x['approval_id']]);
}
}
}

View File

@@ -36,22 +36,22 @@ class Removeaccount extends \Zotlabs\Web\Controller {
return;
}
}
$global_remove = 0; //intval($_POST['global']);
account_remove($account_id, 1 - $global_remove);
account_remove($account_id, 1 - $global_remove);
}
function get() {
if(! local_channel())
goaway(z_root());
$hash = random_string();
$_SESSION['remove_account_verify'] = $hash;
$tpl = get_markup_template('removeaccount.tpl');
$o .= replace_macros($tpl, array(
return replace_macros($tpl, array(
'$basedir' => z_root(),
'$hash' => $hash,
'$title' => t('Remove This Account'),
@@ -60,9 +60,5 @@ class Removeaccount extends \Zotlabs\Web\Controller {
// '$global' => array('global', t('Remove this account, all its channels and all its channel clones from the network'), false, t('By default only the instances of the channels located on this hub will be removed from the network')),
'$submit' => t('Remove Account')
));
return $o;
}
}

View File

@@ -54,7 +54,7 @@ class Removeme extends \Zotlabs\Web\Controller {
$_SESSION['remove_account_verify'] = $hash;
$tpl = get_markup_template('removeme.tpl');
$o .= replace_macros($tpl, array(
return replace_macros($tpl, array(
'$basedir' => z_root(),
'$hash' => $hash,
'$title' => t('Remove Channel'),
@@ -63,9 +63,5 @@ class Removeme extends \Zotlabs\Web\Controller {
// '$global' => [ 'global', t('Remove this channel and all its clones from the network'), false, t('By default only the instance of the channel located on this hub will be removed from the network'), [ t('No'),t('Yes') ] ],
'$submit' => t('Remove Channel')
));
return $o;
}
}

View File

@@ -29,7 +29,7 @@ class Rmagic extends \Zotlabs\Web\Controller {
if($r['hubloc_url'] === z_root())
goaway(z_root() . '/login');
$dest = bin2hex(z_root() . '/' . str_replace(['rmagic','zid='],['','zid_='],\App::$query_string));
goaway($r['hubloc_url'] . '/magic' . '?f=&owa=1&bdest=' . $dest);
goaway($r['hubloc_url'] . '/magic?owa=1&bdest=' . $dest);
}
}
}
@@ -84,7 +84,7 @@ class Rmagic extends \Zotlabs\Web\Controller {
else
$dest = bin2hex(z_root() . '/' . str_replace([ 'rmagic', 'zid=' ] ,[ '', 'zid_='],\App::$query_string));
goaway($url . '/magic' . '?f=&owa=1&bdest=' . $dest);
goaway($url . '/magic?owa=1&bdest=' . $dest);
}
}
}

View File

@@ -90,12 +90,7 @@ class Search_ac extends \Zotlabs\Web\Controller {
'items' => $results,
);
echo json_encode($o);
logger('search_ac: ' . print_r($x,true),LOGGER_DATA,LOG_INFO);
killme();
}
}

Some files were not shown because too many files have changed in this diff Show More