Compare commits

...

1256 Commits
6.2.1 ... 8.4

Author SHA1 Message Date
Mario
65d98af24c Merge branch '8.4RC' 2023-05-17 13:28:23 +00:00
Mario
62d35627f3 version 8.4 2023-05-17 13:28:05 +00:00
Mario
84f1ed1587 Merge branch 'dev' into 8.4RC 2023-05-17 13:26:01 +00:00
Mario
31b4fb343d changelog 2023-05-17 13:25:33 +00:00
Mario
3c3f5c60da changelog 2023-05-16 09:26:45 +00:00
Mario
18914f2081 Merge branch 'dev' into 8.4RC 2023-05-15 08:04:02 +00:00
Mario
b50da2d8b7 fix parent_mid and thr_parent not set correctly for response activities 2023-05-15 08:03:27 +00:00
Mario
5bdd699c9d Merge branch 'dev' into 8.4RC 2023-05-13 19:52:52 +00:00
Mario
29e8e6d95c fix parent and parent_mid for likes 2023-05-13 19:51:25 +00:00
Mario Vavti
049fc91615 Merge branch 'dev' into 8.4RC 2023-05-13 21:38:08 +02:00
Mario Vavti
b7c96f2cbd Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2023-05-13 21:37:45 +02:00
Mario Vavti
1e6408df13 fix regression decoding the uuid for responses 2023-05-13 21:37:33 +02:00
Mario
7b90548c1d save a query 2023-05-12 17:45:30 +00:00
Mario
5d330e18ff save a query 2023-05-12 16:29:42 +00:00
Mario
07662ff076 Merge branch 'dev' into 8.4RC 2023-05-12 08:02:19 +00:00
Mario
9252ae1596 css fixes 2023-05-12 08:01:25 +00:00
Mario
0155e9131d remove outdated comments 2023-05-11 12:51:25 +00:00
Mario
247cf40ace bump version 2023-05-10 20:45:33 +00:00
Mario
4a6b450c55 Merge branch 'dev' into 8.4RC 2023-05-10 20:44:43 +00:00
Mario
5b80d57a54 php warning 2023-05-10 20:40:10 +00:00
Mario
8ac4547e73 php warnings 2023-05-10 20:33:38 +00:00
Mario
3658975b69 typo 2023-05-10 20:22:18 +00:00
Mario
abc3545ef9 use act->objprop() in decode_note() 2023-05-10 20:11:54 +00:00
Mario
01f8cb698d check if we have a type and a href 2023-05-10 18:38:43 +00:00
Mario
5e4d0f45fc check if var is set and escape $ sign in ru translation 2023-05-10 16:43:00 +00:00
Mario
efd2f78274 check if var is set and escape $ sign in ru translation 2023-05-10 16:42:12 +00:00
Mario
690ff955fa Merge branch 'dev' into 8.4RC 2023-05-10 16:09:36 +00:00
Mario Vavti
3fb27bdc55 fix query for postgres 2023-05-10 18:04:19 +02:00
Mario
d8306fca6f Merge branch 'dev' into 8.4RC 2023-05-10 12:05:15 +00:00
Mario Vavti
380775540d missing function 2023-05-10 14:03:37 +02:00
Mario Vavti
65e3b0dafd deal with arrays and json 2023-05-10 13:53:03 +02:00
Mario
4ae81d753c Merge branch 'dev' into 8.4RC 2023-05-10 08:16:09 +00:00
Mario
0f01aac823 wording 2023-05-10 08:15:21 +00:00
Mario
ce0a96351e make sure we have a xchan and a hubloc - otherwise re-discover 2023-05-10 08:14:51 +00:00
Mario
93dda6f1fd Merge branch 'dev' into 8.4RC 2023-05-09 09:20:48 +00:00
Mario
5e83db959e more changelog 2023-05-09 09:20:21 +00:00
Mario
74436eb03e Merge branch 'dev' into 8.4RC 2023-05-09 09:08:06 +00:00
Mario
993178fc49 changelog 2023-05-09 09:07:32 +00:00
Mario
1c217cf446 es translation as per manuel 2023-05-09 07:58:41 +00:00
Mario
0bf2be1f9d Merge branch 'owa-compat-friendica' into 'dev'
Owa compatibility for Friendica

See merge request hubzilla/core!2036
2023-05-09 07:50:30 +00:00
Pascal Deklerck
548589be4d Owa compatibility for Friendica 2023-05-09 07:48:52 +00:00
Max Kostikov
697a1b1ed1 Merge branch 'dev' into 'dev'
Update Russian translation

See merge request hubzilla/core!2037
2023-05-08 12:44:18 +00:00
Max Kostikov
d893c7eb33 Update Russian hstrings.php 2023-05-08 12:42:17 +00:00
Max Kostikov
8957d24752 Update Russian hmessages.po 2023-05-08 12:41:46 +00:00
Mario
677e730235 Merge branch 'dev' into 8.4RC 2023-05-07 14:25:17 +00:00
Mario
4227d973b9 missing class 2023-05-07 14:24:59 +00:00
Mario
06c0af50c3 Merge branch 'dev' into 8.4RC 2023-05-07 12:48:14 +00:00
Mario
4d3a48d1c1 cropper fixup 2023-05-07 12:47:13 +00:00
Mario
f6b66f4cad Merge branch 'dev' into 8.4RC 2023-05-07 12:17:09 +00:00
Mario
a56f9ab4e6 more css and whitespace 2023-05-07 12:16:52 +00:00
Mario
ca913e5077 Merge branch 'dev' into 8.4RC 2023-05-07 12:04:54 +00:00
Mario
b25ebe12c5 more css 2023-05-07 12:03:42 +00:00
Mario
984980b170 version 2023-05-07 11:31:50 +00:00
Mario
be45005dbb css fixes 2023-05-07 11:29:45 +00:00
Mario
b8c9f04989 bump version 2023-05-07 09:04:10 +00:00
Mario
bf2d41eb14 composer autoload 2023-05-07 08:46:28 +00:00
Mario Vavti
158f9afb37 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2023-05-07 10:42:10 +02:00
Mario Vavti
f884e31d21 composer autoload 2023-05-07 10:41:57 +02:00
Mario
d3a5ff9d68 version and strings 2023-05-07 08:39:59 +00:00
Mario Vavti
7185780d4e h3 adds bottom margin - remove it 2023-05-07 10:30:34 +02:00
Mario Vavti
f995b2822f exclude deleted hublocs 2023-05-07 10:03:27 +02:00
Mario Vavti
d7490ac738 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2023-05-07 09:52:38 +02:00
Mario Vavti
383d0e17f2 fix directory search 2023-05-07 09:52:27 +02:00
Mario
7c1a3ab36e css fix 2023-05-07 07:11:54 +00:00
Mario
edc8d17031 slightly change online status display 2023-05-06 20:42:04 +00:00
Mario
f3f861234d minor css fix 2023-05-06 20:28:29 +00:00
Mario
93278c00b7 update profile vcard to implement the cover image 2023-05-06 19:41:02 +00:00
Mario
5bbe93d49f minor de strings update 2023-05-05 17:49:08 +00:00
Mario
21cd8d31d7 css fix 2023-05-05 17:46:53 +00:00
Mario
d649b4df28 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2023-05-05 16:10:12 +00:00
Mario
2bb9550343 slightly more robust get_quote_bbcode() 2023-05-05 16:09:53 +00:00
Mario Vavti
ef0feff4a5 Hidden > Spam 2023-05-05 12:33:39 +02:00
Mario
dfa43b4856 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2023-05-04 09:28:05 +00:00
Mario
a24a1ca6d7 update 1258 to remove traces of channelreputation 2023-05-04 09:27:31 +00:00
Mario Vavti
2d4b35fbc9 provide possibility to flag via ajax calls to prevent pageloads 2023-05-03 22:42:52 +02:00
Mario Vavti
57e2910477 flag new xtags with the xchan flag 2023-05-03 18:13:47 +02:00
Mario Vavti
ffbaa7e4dc when flagging an entry also flag its xtags and improved keywords query in dirsearch 2023-05-03 15:25:47 +02:00
Mario
df42036100 make sure config.system.trusted_directory_servers is an array 2023-05-03 08:47:21 +00:00
Mario Vavti
ca9491d343 move trusted directory servers to security and implement in backend 2023-04-29 22:43:49 +02:00
Mario
96ae569eaf trusted dir servers frontend 2023-04-29 19:38:34 +00:00
Mario Vavti
fb295d53f1 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2023-04-29 20:17:19 +02:00
Mario Vavti
95d07974f4 fix php warning 2023-04-29 20:13:52 +02:00
Mario
39d78064da Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2023-04-28 21:50:01 +00:00
Mario
a2bcbb90ed fix regression decoding obj type 2023-04-28 21:44:12 +00:00
Mario
c31b37f570 bootstrap files 2023-04-28 19:23:28 +00:00
Mario
2a1341b910 update bootstrap 2023-04-28 19:02:23 +00:00
Mario Vavti
354e341d69 mastodon says hashtag is a subset of link - issue #1750 2023-04-28 12:50:57 +02:00
Mario Vavti
13946b2b76 fix and document edge case 2023-04-28 10:03:05 +02:00
Mario Vavti
29aa52df6a fix poller after refactor 2023-04-28 09:29:15 +02:00
Mario Vavti
c3267a27d3 fix column name 2023-04-28 09:04:02 +02:00
Mario Vavti
3543e6dd32 slightly refactor dir sync 2023-04-28 08:57:21 +02:00
Mario Vavti
5412ba617d more dir sync testing 2023-04-28 00:58:46 +02:00
Mario Vavti
1f81a2cb1b remove updates entry if a xchan_hash mismatch is encountered 2023-04-27 22:54:45 +02:00
Mario Vavti
5da58d42f6 adjust args in libzotdir update and some dir sync fixes 2023-04-27 22:26:53 +02:00
Mario Vavti
299b6037c9 remove logging 2023-04-27 11:24:26 +02:00
Mario Vavti
1ed8b9dd14 fix php error 2023-04-27 11:17:53 +02:00
Mario Vavti
cf4912cb3d use shorter strings 2023-04-27 11:08:21 +02:00
Mario Vavti
e6ec87f910 update doco and fix safemode 2023-04-27 11:00:43 +02:00
Mario Vavti
f72fb974a9 for flag updates also match site directory and ud host 2023-04-27 07:07:38 +02:00
Mario Vavti
bdb25315b6 initial commit for directory flags federation 2023-04-26 23:01:56 +02:00
Mario
60f0739c3e update 1257 ud_guid > ud_host 2023-04-26 16:28:20 +00:00
Mario
0faab9277f fix update 2023-04-26 16:09:14 +00:00
Mario Vavti
51fce12cd7 update 1256 2023-04-26 17:59:20 +02:00
Mario Vavti
d79290df75 dirsync update column 2023-04-26 17:58:35 +02:00
Mario Vavti
0bf65bcad5 remove rate entry and move ignore button to the right 2023-04-26 13:46:25 +02:00
Mario Vavti
44dbf19e89 wrong variable 2023-04-26 12:59:04 +02:00
Mario Vavti
469a76f1f6 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2023-04-26 12:50:56 +02:00
Mario Vavti
f851c272fa enable dir admins to flag or hide entries 2023-04-26 12:50:37 +02:00
Mario
027a9fec61 fix potential security issue as per friendica 2023-04-26 06:28:24 +00:00
Mario
09fde2f839 correctly set some perms when our follow request was accepted 2023-04-25 08:36:20 +00:00
Mario
8a14e4261d check for uuid so that will be also catch items that were posted from alternate locations 2023-04-23 18:44:39 +00:00
Mario
6c9f1de265 remove logging 2023-04-23 18:05:17 +00:00
Mario
3ad0179b62 fix regression when rendering event items 2023-04-23 16:07:57 +00:00
Mario Vavti
81f33da499 improved fetch_conversation() 2023-04-23 13:02:38 +02:00
Mario
80d70e64f5 bump version 2023-04-23 09:26:30 +00:00
Mario
eec4845cd0 add the conversation endpoint and implement paginated fetch for zot requests in mod item 2023-04-23 09:23:39 +00:00
Mario
b99a4ade1a bump version 2023-04-21 10:39:17 +00:00
Mario
84e25e8fd2 Fetch conversations in the background. Otherwise it might sgnificantly delay delivery 2023-04-21 10:34:55 +00:00
Mario
39e14eb95c hotfix: make sure to not pass an empty path to fopen() 2023-04-21 10:33:05 +00:00
Mario
f277d08244 queue and poller testing 2023-04-21 07:45:32 +00:00
Mario
d7c479fa6d % values in format_poll() should be rounded 2023-04-19 11:01:49 +00:00
Mario Vavti
44e5dc7d97 bump version 2023-04-19 11:14:46 +02:00
Mario Vavti
fdd54057a8 also return deleted channels info in webfinger and document why 2023-04-19 11:12:35 +02:00
Mario Vavti
d43485141f use empty for check 2023-04-16 20:12:04 +02:00
Mario Vavti
2350561903 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2023-04-16 17:13:00 +02:00
Mario Vavti
5674badccd improved update_directory_entry(), update ud_last even if webfinger failed 2023-04-16 17:12:49 +02:00
Mario
a793f4414d fix php warning 2023-04-16 13:47:48 +00:00
Mario
e99957f99f fix php warning 2023-04-16 11:20:02 +00:00
Mario
ad5bbc463b fix wrong variable 2023-04-16 10:59:26 +00:00
Mario
81993cf2a3 cleanup 2023-04-15 15:15:55 +00:00
Mario
5d40742ee6 fix wrong variable 2023-04-15 07:53:30 +00:00
Mario
1ce050d911 update es strings as per Manuel 2023-04-14 19:02:37 +00:00
Mario
8e7393fc26 update it string as per Giaco 2023-04-14 18:55:45 +00:00
Mario Vavti
ad45205ddf this has been moved to cron for now 2023-04-14 10:45:01 +02:00
Mario Vavti
409e9208ee Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2023-04-14 09:21:46 +02:00
Mario Vavti
d8811b499d improved item_expire() 2023-04-14 09:21:33 +02:00
Mario
dd1f9494f1 css fix 2023-04-14 06:04:44 +00:00
Mario Vavti
20f4538db4 update remove_all_xchan_resources() and remove deletion of deprecated conv table 2023-04-13 22:28:08 +02:00
Mario Vavti
d08c8e6edc Revert "zot_info(): improved check for deleted"
This reverts commit f1667dbbe6.
2023-04-13 21:50:13 +02:00
Mario Vavti
f1667dbbe6 zot_info(): improved check for deleted 2023-04-13 21:25:03 +02:00
Mario Vavti
2bab7e2693 prevent duplicate definitions 2023-04-13 18:51:13 +02:00
Mario Vavti
824497b97a fix wrong array key, check for xchan_deleted with empty() which will also catch a possibly already removed xchan (which will be null) and bump version 2023-04-13 11:37:01 +02:00
Mario Vavti
0b7bece8e3 remove pre zot6 compatibility tweaks 2023-04-13 11:01:57 +02:00
Mario Vavti
6ddf1a5786 update zotinfo to use as much info as possible from channel since in some cases the xchan might be history already 2023-04-13 10:45:36 +02:00
Mario Vavti
b9827dfe02 move colon to the variable 2023-04-12 23:11:02 +02:00
Mario Vavti
64f30831ac rename update_modtime() to update() and only bump ud_date if something actually changed 2023-04-12 23:07:19 +02:00
Mario Vavti
bf5722cd25 always call update_modtime() foer now; 2023-04-12 19:07:28 +02:00
Mario Vavti
ae074153c8 remouve updates stuff from import_directory_profile() 2023-04-12 18:40:51 +02:00
Mario Vavti
63d46dbdfb more logging 2023-04-12 18:27:04 +02:00
Mario Vavti
bdf1b23198 reset ud_last if we had contact and some cleanup 2023-04-12 18:24:44 +02:00
Mario Vavti
6f1c261f6b deprecate ud_flags and ud_arr in import_xchan() 2023-04-12 18:01:35 +02:00
Mario Vavti
3233d5485f Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2023-04-12 17:51:09 +02:00
Mario Vavti
aa06400a50 deprecate flags and transaction_id and only return results which are currently updated 2023-04-12 17:50:39 +02:00
Mario
30724bd7c4 update updates if anything changed 2023-04-12 15:35:21 +00:00
Mario Vavti
0d3b389538 fix php warning 2023-04-12 13:35:41 +02:00
Mario Vavti
9f7dbe16fd adjust check 2023-04-12 13:21:26 +02:00
Mario Vavti
432024123a update updates if we are provided an ud_arr or we imported a new xchan 2023-04-12 13:17:23 +02:00
Mario Vavti
261762448e use url instead of addr for updates and clean up local_dir_update() and update_modtime() 2023-04-12 11:36:34 +02:00
Mario Vavti
7ce4175876 initial commit directory sync rewrite - should work but still requires lots of cleanup 2023-04-12 09:29:51 +02:00
Mario
a57739c462 Merge branch 'dev' 2023-04-09 20:01:22 +00:00
Mario
03bdbfa705 set ud_last after successfully probing a channel 2023-04-09 20:00:54 +00:00
Mario
92246ce3a8 Merge branch 'dev' 2023-04-09 19:53:27 +00:00
Mario
cdf74c2e41 Revert "make sure to update ud_last timestamp if we successfully fingered a channel"
This reverts commit f76d9b7908.
2023-04-09 19:52:54 +00:00
Mario
4a72ea6666 Merge branch 'dev' 2023-04-09 19:45:04 +00:00
Mario
f76d9b7908 make sure to update ud_last timestamp if we successfully fingered a channel 2023-04-09 19:44:35 +00:00
Mario
dcfdf3a5d7 Merge branch 'dev' 2023-04-09 19:02:36 +00:00
Mario
4873f61d6c disable thread listener interface by default and minor fixes 2023-04-09 18:51:55 +00:00
Mario
1538107ae4 minor queueworker fixes 2023-04-08 20:25:31 +00:00
Mario
9b93dc5137 split up a potentially long running sql query 2023-04-08 20:18:17 +00:00
Mario Vavti
5ec721b978 likes not synced between clones 2023-03-31 09:31:28 +02:00
Mario
24568c0e2f add some explanation and remove logging 2023-03-30 13:23:16 +00:00
Mario
92a89ca258 version 8.3.1 2023-03-30 13:10:47 +00:00
Mario
ba71c53bc6 ignore deliveries by our own channel which do not origin from the local hub. instead rely on the sync delivery. 2023-03-30 12:08:43 +00:00
Mario Vavti
b3cfeb573a do not add not_here, anon, token and rss contacts to receivers 2023-03-29 21:46:28 +02:00
Mario
9083e99d2a in fact this can be removed
(cherry picked from commit 70ca247c88)
2023-03-24 10:29:09 +01:00
Mario
70ca247c88 in fact this can be removed 2023-03-24 09:22:10 +00:00
Mario
14fc0c735b encode object after we have dealt with deleted items and work around a php error
(cherry picked from commit 70b3c8080e)
2023-03-24 10:05:37 +01:00
Mario
70b3c8080e encode object after we have dealt with deleted items and work around a php error 2023-03-24 09:01:06 +00:00
Mario
2c483c460a initial check in to allow all mentions option 2023-03-23 20:11:18 +00:00
Mario
79405cf1d3 Merge branch 'dev' 2023-03-21 09:20:57 +00:00
Mario
5c755fdd1c PHP 8.1 is the required minimum version 2023-03-21 09:20:22 +00:00
Mario
89285f1408 Merge branch '8.2RC' 2023-03-19 13:55:18 +00:00
Mario
17c0bb2069 version 8.2 2023-03-19 13:54:15 +00:00
Mario
192736f6d7 Merge branch 'dev' into 8.2RC 2023-03-19 13:53:12 +00:00
Mario
ae928b9aff changelog 2023-03-19 13:52:43 +00:00
Mario
4eee8ce770 Merge branch 'dev' into 8.2RC 2023-03-19 13:50:39 +00:00
Mario
723eb6597a simplify 2023-03-19 13:29:35 +00:00
Mario
3dcfdba74b simplify 2023-03-19 13:28:43 +00:00
Mario
5428053663 Merge branch 'dev' into 8.2RC 2023-03-19 09:43:34 +00:00
Mario
d0b41d0b07 more changelog 2023-03-19 09:41:17 +00:00
Mario
a82d861d2c update changelog 2023-03-19 09:25:56 +00:00
Mario
1e184b781b Merge branch 'dev' into 8.2RC 2023-03-19 08:22:29 +00:00
Mario
54b684fdb8 css fixes 2023-03-19 08:22:08 +00:00
Mario
c1ddb89990 Merge branch 'dev' into 8.2RC 2023-03-18 15:47:09 +00:00
Mario
2f5fa4df75 add the download attribute to prevent onbeforeunload 2023-03-18 15:46:30 +00:00
Mario
20735083b3 update bb_parse_b64_crypt() 2023-03-18 14:52:25 +00:00
Mario
7ac7cb129f Merge branch 'dev' into 8.2RC 2023-03-17 09:44:17 +00:00
Mario
f8b2f738bb remove redundant untranslated htconfig templates and add the db_skip_locked_supported config option 2023-03-17 09:30:17 +00:00
Mario
11b9e546a9 Merge branch 'dev' into 8.2RC 2023-03-14 10:43:03 +00:00
Mario
7e4721e4c7 work around friendica img attachment has different href than body which results in duplicate images 2023-03-14 10:35:01 +00:00
Mario
3a3fd38e3a Merge branch 'dev' into 8.2RC 2023-03-12 22:04:37 +00:00
Mario
63a8611579 fix issue #1728 2023-03-12 22:03:47 +00:00
Mario
38a1b79174 fix max_oembed_size check if content length header is an array (e.g. after a redirect with code 301) - fix issue #1727 2023-03-12 20:59:36 +00:00
Mario
0a679e503e make sure to only transform channel wall posts for group actors
(cherry picked from commit 95cbcf30d7)
2023-03-12 19:56:34 +01:00
Mario
e7c529f2c3 Merge branch 'dev' into 8.2RC 2023-03-12 18:44:28 +00:00
Mario
95cbcf30d7 make sure to only transform channel wall posts for group actors 2023-03-12 18:43:50 +00:00
Mario
dfc70021e3 fix version after merge 2023-03-12 09:38:31 +00:00
Mario
9daecca0ad make an format exception for repeated forum posts 2023-03-12 09:34:35 +00:00
Mario
c9d8a4dc1d bump dev version 2023-03-11 20:43:21 +00:00
Mario
5fada6a497 more strings and provide mfa feedback via jgrowl 2023-03-11 20:40:32 +00:00
Mario
ac9c33fb3b check form security token and require password to enable/diable mfa 2023-03-11 20:24:56 +00:00
Mario
641b1c2e1b fix php error 2023-03-11 19:38:37 +00:00
Mario
f031707563 strings and version 2023-03-11 19:37:34 +00:00
Mario
7f0518f693 merge es translations as per manuel 2023-03-11 19:28:17 +00:00
Mario
634d2f02b5 translateable strings 2023-03-11 19:25:27 +00:00
Mario
d7aee292d3 mark items as fetched in other places 2023-03-11 14:47:10 +00:00
Mario
1987517836 only set owner to observer if the item is not fetched otherwise the comment author could end up as owner 2023-03-09 18:31:43 +00:00
Mario
203d9d651f mfa strings update 2023-03-09 15:48:03 +00:00
Mario
8af5788fc1 more mfa cleanup, set the value in session if mfa is enabled and only allow enabling mfa after a test passed 2023-03-08 17:29:56 +00:00
Mario
3de81877c6 more mfa cleanup 2023-03-08 13:15:33 +00:00
Mario
2665b34962 whitespace 2023-03-08 10:21:05 +00:00
Mario
2ffef2be8f minor cleanup 2023-03-08 10:18:32 +00:00
Mario
c2e5610455 tests 2023-03-08 10:11:59 +00:00
Mario
234bb64250 port totp mfa from streams with some adjustions 2023-03-08 10:04:29 +00:00
Mario
d43a56614c position should be fixed 2023-03-04 21:33:50 +00:00
Mario
9f10e7e356 simplify pageloader animation 2023-03-04 17:03:37 +00:00
Mario
dc6075aa3f do not use zrl tag for non zot profiles and remove redundant foreach which was a leftover from zot to zot6 transition days 2023-03-03 19:33:39 +00:00
Mario
972d6917ac add fixme 2023-03-03 14:59:48 +00:00
Mario
ec3ba87f3a Revert "some work on bringing bang tags back for forums"
This reverts commit da034045cc.
2023-03-03 08:49:18 +00:00
Mario
da034045cc some work on bringing bang tags back for forums 2023-03-02 21:15:19 +00:00
Mario
65f001b4b7 provide a fake progress bar for pwa standalone mode 2023-03-02 16:45:10 +00:00
Mario
d81473487f minor cleanup and docu 2023-03-02 12:39:21 +00:00
Mario
06a8d5a4fa bump version 2023-03-02 11:48:52 +00:00
Mario
3653a86ad3 message filter entries are stored encoded - make sure to decode the word before we use it 2023-03-02 11:00:03 +00:00
Mario
c8d913fba7 wrong variable 2023-03-02 10:24:18 +00:00
Mario
b70acd0079 wrong variable 2023-03-02 10:20:43 +00:00
Mario
f167648115 improve mod hq to save some db lookups 2023-03-02 10:14:49 +00:00
Mario
b457c66bf9 do not include deleted hublocs when looking for author 2023-03-02 10:13:54 +00:00
Mario
ca0bd3ed32 fix some php warnings 2023-02-28 09:29:39 +00:00
Mario
7dacc7c268 Revert "fix second part of issue #1731"
This reverts commit 0db2e6b62c.
2023-02-27 20:38:42 +00:00
Mario
0db2e6b62c fix second part of issue #1731 2023-02-27 20:31:16 +00:00
Mario
e412bdbdbe bump version 2023-02-27 09:07:26 +00:00
Mario
f032bcc5f2 Default owner_xchan to $observer (sender) in Activity::store() - this is because in case where an announce holds a relayed activity we drop the announce and process the relayed activity only. In that case actor.id as set in Activity::decode_note() will not be the correct owner. In other cases actor.id and sender should be identical. 2023-02-27 08:42:13 +00:00
Mario
9ab9ac0e2e possible fix for issue #1731 2023-02-27 08:22:35 +00:00
Mario
fd3adf4d11 slightly improve contact search 2023-02-24 21:35:22 +00:00
Mario
c42911bd8d css fixes 2023-02-23 16:19:02 +00:00
Mario
828087ee8c fix syntax for get_compund_property() 2023-02-23 14:54:04 +00:00
Mario
efcda1d37d port some functions from streams 2023-02-23 09:51:37 +00:00
Mario
656400b418 look for owner instead of author - this way we will also catch the via posts 2023-02-22 17:07:53 +00:00
Mario
ca7bd49964 Activity: do not force new thread if the announce is from a group actor 2023-02-22 11:20:32 +00:00
Mario
3527137264 Activity: set xchan_pubforum if we deal with a group actor 2023-02-22 10:47:11 +00:00
Mario
e045a36559 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2023-02-17 10:18:30 +00:00
Mario
ee8fc701a6 do not try to oembed in notes 2023-02-17 10:18:01 +00:00
Mario Vavti
777fdeb462 realy make sure we will deduplicate even if there is a bogus second primary entry 2023-02-16 16:56:57 +01:00
Mario Vavti
1078b774ae make sure we will deduplicate even if there is a bogus second primary entry 2023-02-16 16:52:29 +01:00
Mario
62a363debc queue fixes 2023-02-16 14:17:05 +00:00
Mario Vavti
7839b931f1 make sure we provide a created timestamp for likes and remove the workaround which returned the wrong date format 2023-02-16 13:12:22 +01:00
Mario
cbf8c4bdb2 more queue updates from streams and remove a hz_syslog 2023-02-16 11:16:44 +00:00
Mario
321cd9f2e0 more restructure for better responsive behaviour 2023-02-15 18:06:16 +00:00
Mario
09a60774d7 we can sign messages which are not from the primary location 2023-02-15 13:33:23 +00:00
Mario
1ca988b177 revisit author_id and fix issue with pinned content 2023-02-15 09:41:48 +00:00
Mario
07fd8cf6cd restructure wall-item-head 2023-02-15 08:51:23 +00:00
Mario
e7fb56447a bump version 2023-02-14 07:35:41 +00:00
Mario
de3e83f0a2 fix mod cal after fullcalendar update 2023-02-14 07:33:05 +00:00
Mario
6c78f7b769 css fixes 2023-02-12 15:05:06 +00:00
Mario
2c459fefce remove deprecated functions 2023-02-12 14:13:59 +00:00
Mario
a1eb39872b implement hq widget author image and notifications updates 2023-02-12 10:43:31 +00:00
Mario
724b8cc6a5 port queue improvements from streams 2023-02-12 10:41:23 +00:00
Mario Vavti
2bfd18e6cd css fixes 2023-02-10 21:08:49 +01:00
Mario
20658f3b4a do not blur 2023-02-09 12:46:23 +00:00
Mario
c945698eb4 work around wierd textcomplete behaviour 2023-02-09 12:37:08 +00:00
Mario
5f89bd75a4 bump version 2023-02-09 01:53:46 +00:00
Mario
09c9b47265 fix more hubloc confusion, implement hq widget author filter and some autocomplete fixes 2023-02-09 01:52:48 +00:00
Mario
ea2b653b9b queueworker: do not wait for locked rows, use skip locked if configured via system.db_skip_locked_supported 2023-02-08 11:03:29 +00:00
Mario
9c3660e2f6 remove superfluous semicolon 2023-02-01 10:02:35 +00:00
Mario
4bcacf858b do not deduplicate notifications because the dupes could be valid and var -> let 2023-01-29 10:06:58 +00:00
Mario
7faa3359f0 fix undefined varable warning 2023-01-28 20:19:51 +00:00
Mario
71f1814477 remove redundant argument 2023-01-28 20:04:18 +00:00
Mario
a3913c5ca4 fix ics import 2023-01-28 16:57:32 +00:00
Mario
ae1cc65b23 do not use transparency for navbar togglers in dark mode 2023-01-28 15:00:11 +00:00
Mario
9a16bf65bd update simplepie 2023-01-27 07:28:21 +00:00
Mario
c3d3dc9d92 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2023-01-27 07:26:35 +00:00
Mario
e54eb21b71 update smarty 2023-01-27 07:24:50 +00:00
Harald Eilertsen
0140f9fe56 translations: Misc updates for nb_NO.
(cherry picked from commit ec6832687b)
2023-01-27 08:00:26 +01:00
Harald Eilertsen
03243df16a translations: Fix timeago for nb_NO.
(cherry picked from commit 9065a90ac0)
2023-01-27 08:00:07 +01:00
Mario
28dc8443a8 Merge branch 'translations/update-nb-no' into 'dev'
Translations/update nb no

See merge request hubzilla/core!2034
2023-01-27 06:58:45 +00:00
Harald Eilertsen
ec6832687b translations: Misc updates for nb_NO. 2023-01-26 20:07:59 +01:00
Harald Eilertsen
9065a90ac0 translations: Fix timeago for nb_NO. 2023-01-26 20:07:02 +01:00
Mario
94b26e1e66 redbasic: fix regression 2023-01-26 18:35:49 +00:00
Mario
a2fc2e776a bump version 2023-01-26 18:29:21 +00:00
Mario
79b40179b4 redbasic: implement setting for always light navbar icons and some minor fixes 2023-01-26 18:28:40 +00:00
Mario
60c968222f bump version 2023-01-26 10:26:55 +00:00
Mario
e99dc2193f remove unsused variables 2023-01-26 10:23:33 +00:00
Mario
cf1838f76e minor cleanup and prevent duplicate recipients in some places 2023-01-26 10:10:06 +00:00
Mario
0db5016666 remove redundant code 2023-01-26 09:15:46 +00:00
Mario
c4b37ba462 theme fixes 2023-01-26 07:22:21 +00:00
Mario
c3b908dcfc : fixes 2023-01-25 16:35:18 +00:00
Mario
23f93044c1 update forkawesome lib 2023-01-25 15:22:15 +00:00
Mario
32dcc28414 calendar: fixes 2023-01-25 14:05:20 +00:00
Mario
ddae3eaf84 calendar: remove deprecated options 2023-01-25 13:39:50 +00:00
Mario
a9ae17036d update fullcalendar 2023-01-25 13:09:00 +00:00
Mario
08e925758e update fullcalendar library 2023-01-25 13:08:05 +00:00
Mario
213c8a6eec according to spec this should be id instead of href 2023-01-25 13:06:50 +00:00
Mario
ca4ad836a3 revert theme color 2023-01-25 11:00:01 +00:00
Mario
56361fa2fc theme fixes 2023-01-25 10:59:17 +00:00
Mario
fedce4cd74 cleanup 2023-01-24 09:36:27 +00:00
Mario
cac48fc4bf use light colored navbar for light mode - this makes the focus light schema redundant 2023-01-24 09:29:00 +00:00
Mario
1cad844d2d theme fixes 2023-01-22 15:35:55 +00:00
Mario
2d5e09f930 theme fixes 2023-01-20 20:07:37 +00:00
Mario
fbda34935d remove dark schema quirks 2023-01-20 11:19:39 +00:00
Mario
c5ca7f236f bump version 2023-01-20 11:06:05 +00:00
Mario
9dc949b62c native dark theme initial checkin 2023-01-20 11:05:15 +00:00
Mario
40394b94d7 typo :\ 2023-01-17 10:33:31 +00:00
Mario
bae446973f reflect pubstream disable/enable logic change in can_view_public_stream() 2023-01-17 10:29:12 +00:00
Mario
2805520d1b Merge remote-tracking branch 'origin/8.0RC' 2023-01-13 20:01:05 +00:00
Mario
fb7ca18820 version 8.0 2023-01-13 19:56:11 +00:00
Mario
1b00d5657f Merge branch 'dev' into 8.0RC 2023-01-13 19:55:44 +00:00
Mario
cd9f35e78a update changelog 2023-01-13 19:55:18 +00:00
Mario
f9cedab964 update changelog 2023-01-13 09:42:57 +00:00
Mario
9ec516e5a4 Merge branch 'dev' into 8.0RC 2023-01-12 16:12:26 +00:00
Mario
550b6d90a4 missing semicolon 2023-01-12 16:11:42 +00:00
Mario
5cb92b6e21 Merge branch 'dev' into 8.0RC 2023-01-12 11:55:13 +00:00
Mario
8a7b221412 mark old hubloc entries from re-installed hubs deleted if we discover any 2023-01-12 11:28:48 +00:00
Mario
d092e79ebc remove fragment in notifier - it should not be required, when processing multiple choice polls sleep some time before calling the notifier 2023-01-12 11:04:03 +00:00
Mario
2ddb88a34d RC2 2023-01-11 19:57:35 +00:00
Mario
71761c9039 Merge branch 'dev' into 8.0RC 2023-01-11 16:35:21 +00:00
Mario
16555b93bb fix race conditions when processing multiple choice polls 2023-01-11 16:34:23 +00:00
Mario
bd5e834b42 Merge branch 'dev' into 8.0RC 2023-01-08 08:20:05 +00:00
Mario
2eb4f093be update theme requirements 2023-01-08 08:19:37 +00:00
Max Kostikov
d4bf587103 Merge branch 'dev' into 'dev'
Fix Russian translation escaping

See merge request hubzilla/core!2033
2023-01-07 14:06:54 +00:00
Max Kostikov
ae7bd8b644 Fix translation escaping 2023-01-07 14:05:52 +00:00
Max Kostikov
f89cede020 Merge branch 'dev' into 'dev'
Update Russian translations

See merge request hubzilla/core!2032
2023-01-07 13:58:39 +00:00
Max Kostikov
59facf6f00 Update hstrings.php 2023-01-06 11:29:49 +00:00
Max Kostikov
01d93733ae Update hmessages.po 2023-01-06 11:24:03 +00:00
Mario
4c434129a6 Merge branch 'dev' into 8.0RC 2023-01-05 18:25:45 +01:00
Mario
b40499b4c1 revert accidental change in session 2023-01-05 18:25:08 +01:00
Mario
66333aedb7 fix version 2023-01-05 18:23:00 +01:00
Mario
47071c58aa fix affinity slider updates - issue #1714 2023-01-05 18:21:49 +01:00
Mario
79d99688b4 bump version 2023-01-05 11:39:09 +01:00
Mario
edcb0631aa composer dump autoload 2023-01-05 11:35:15 +01:00
Mario
bc361e6469 strings and version 2023-01-05 11:33:50 +01:00
Mario
c95ef1a5c0 pdledit_gui: only show installed modules and widgets 2023-01-05 11:06:19 +01:00
Mario
0c0891f64f bump version 2023-01-05 10:37:40 +01:00
Mario
23828f53bc pubstream: when going to conv from unthreaded mode stay in the module 2023-01-05 10:29:42 +01:00
Mario
f909e129ab Merge branch 'nb-no/update-translations' into 'dev'
Update translations for nb-no (Norsk Bokmål)

See merge request hubzilla/core!2031
2023-01-04 20:34:57 +00:00
Mario
7d4bcc2e8b translateable strings 2023-01-04 20:20:14 +00:00
Mario
2eb4d87621 fix issue #1717 2023-01-04 20:14:11 +00:00
Mario
435888c1a3 bump version 2023-01-04 19:39:11 +00:00
Mario
e69fabcd71 pdledi_gui: sort widgets 2023-01-04 19:33:18 +00:00
Mario
1a283301cf Revert "pdledit_gui: minor cleanup"
This reverts commit 031df70cf8.
2023-01-04 19:29:42 +00:00
Mario
031df70cf8 pdledit_gui: minor cleanup 2023-01-04 19:29:11 +00:00
Mario
3ad36db7dd pdledit_gui: minor cleanup 2023-01-04 19:27:44 +00:00
Mario
e16ea1ae05 pdl editor for addon iitial commit 2023-01-04 14:25:46 +00:00
Mario
941135a0a6 we should look for owner_xchan just like in mod pubstream 2023-01-04 09:01:44 +00:00
Mario
29776ecea2 queueworker: implement auto_queue_worker_sleep setting in frontend 2023-01-03 13:50:22 +00:00
Mario
d2edef5c5a go away if method is not implemented 2023-01-03 13:30:53 +00:00
Mario
da9349ea62 provide inline error messages for mod cloud 2023-01-03 10:59:38 +00:00
Mario
de0d2afc15 fix issues with pubstream tagcloud 2023-01-02 21:56:20 +00:00
Mario Vavti
d8c94c2003 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2023-01-02 20:39:15 +01:00
Mario Vavti
0e71bfe222 add sys channel to receiveres for public items 2023-01-02 20:38:56 +01:00
Mario
0ae402e624 bump version 2023-01-02 18:38:44 +00:00
Mario
b96dc11ddd improve sse loop 2023-01-02 18:37:36 +00:00
Mario Vavti
37b539eaa5 fix wrong variable - issue #1720 2023-01-01 21:25:15 +01:00
Mario Vavti
0741708086 change the logic of building the site only public stream. we will now fetch sys channel items but restrict them to authors of this site only. this fixes a comment permission issue. 2023-01-01 21:21:13 +01:00
Mario
a30cfd8fec filter approvals 2022-12-27 16:08:08 +00:00
Mario
633cd11c5b move mod queueworker to /admin 2022-12-27 10:44:54 +00:00
Mario
3101c6540a add workerq to the install schemas 2022-12-27 10:33:29 +00:00
Mario
d2d6be73b8 fix subquery in hq widget and order by hubloc_id desc in handle_tag() to make sure we get the most recent entry when using privacy tags 2022-12-26 09:08:54 +00:00
Mario
a46e2c1e6d only display details if there are any 2022-12-22 13:35:46 +00:00
Mario
2b0404fefc queueworker: add some more details 2022-12-22 13:29:34 +00:00
Mario
7ef9462286 bring back item-highlight 2022-12-22 12:22:32 +00:00
Mario Vavti
c6e7a7eaee comment out unused code 2022-12-22 12:42:44 +01:00
Mario
999e142370 minor cleanup 2022-12-22 10:09:35 +00:00
Mario
a7ad117a83 there is no point in wrapping single queries into a transaction 2022-12-22 10:02:31 +00:00
Mario
1ba44fc117 update 2022-12-21 17:15:34 +00:00
Mario
ca5610ebf1 bump version 2022-12-21 17:13:09 +00:00
Mario
e5c70a1304 queueworker: adjust process query to be complient with mariadb < 10.6 and add process timeout exceptions for long running processes 2022-12-21 17:11:33 +00:00
Mario
7dd2308534 pooll fixes 2022-12-20 20:16:06 +00:00
Mario Vavti
62eee07b6e make sure to include only zot6 hublocs in this query. including other networks could lead to unexpected results 2022-12-20 14:06:14 +01:00
Mario
f6d9406063 streamline ap followers only privacy warning with current handling. also fixes possible php error.
(cherry picked from commit 34125177e8)
2022-12-19 10:05:02 +01:00
Mario
34125177e8 streamline ap followers only privacy warning with current handling. also fixes possible php error. 2022-12-19 09:04:24 +00:00
Mario
d977b5d662 bump version 2022-12-18 10:24:44 +00:00
Mario
e36677b757 queueworker: cleanup and implement auto sleep interval (hidden config for now) 2022-12-18 10:19:06 +00:00
Mario
4d54755057 queueworker: fix maxworkers check and cleanup 2022-12-15 16:53:17 +00:00
Mario
91917c98e4 bump version 2022-12-15 09:19:56 +00:00
Mario
2f687de477 queueworker testing and more logging to syslog 2022-12-15 09:18:58 +00:00
Mario Vavti
5446062b95 bump version 2022-12-12 23:28:26 +01:00
Mario Vavti
c9e170dfcc queueworker: introduce new interval config queueworker.queue_interval - defaults to 500000 microseconds. No config UI yet. 2022-12-12 23:26:45 +01:00
Mario
e3a19469eb bring back poll and delivery interval 2022-12-12 09:03:49 +00:00
Mario
45f8e43be4 debug from php log 2022-12-11 20:46:02 +00:00
Mario
7ef0b05ce6 fix typo 2022-12-11 20:24:22 +00:00
Mario
c5a0ec4e93 css fixes 2022-12-11 19:19:47 +00:00
Mario
1c17768dc5 minor fixes 2022-12-11 10:40:02 +00:00
Mario
86e1dd4673 remove debug logging 2022-12-10 17:06:54 +00:00
Mario
0ee41c3341 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2022-12-10 17:04:18 +00:00
Mario
e1c2835173 add option to set worker sleep based on load average, remove redundand code and add return to some daemons 2022-12-10 17:03:57 +00:00
Max Kostikov
5c6d3753ef Fix Redis session PHP warnings 2022-12-09 15:53:01 +00:00
Mario
6e881bcef2 exclude not tagable xchan networks handle_tag()
(cherry picked from commit 4f9a933108)
2022-12-08 21:41:56 +01:00
Mario
4f9a933108 exclude not tagable xchan networks handle_tag() 2022-12-08 20:40:37 +00:00
Mario
9f8585914c sse_bs: respect the site firehose setting 2022-12-07 14:07:31 +00:00
Mario
3ba27b9752 add mark to html2bbcode parser 2022-12-07 11:01:28 +00:00
Mario
abae5de4d8 when uploading a image file, embed it in the item. otherwise attach it 2022-12-07 10:50:26 +00:00
Mario
6952c5a3f5 $visitor is a string 2022-12-06 11:15:53 +00:00
Mario
0184d2c292 typo 2022-12-04 10:43:57 +00:00
Mario
7a40561aaa wording 2022-12-04 10:36:30 +00:00
Mario
79e6c9590a the logic for public stream has changed - adjust help text and externals, disable lockfile check in cron daemon 2022-12-04 10:27:02 +00:00
Mario
12a963cc40 version 7.8.7 2022-12-03 09:01:18 +00:00
Mario
f89975fd0e changelog 7.8.7
(cherry picked from commit b4dffe5946)
2022-12-03 09:59:06 +01:00
Mario
b4dffe5946 changelog 7.8.7 2022-12-03 08:57:56 +00:00
Mario
539b69d507 look for iconfig at the right place, fix mod sharedwithme, comment out unused configs 2022-12-03 08:53:53 +00:00
Harald Eilertsen
9927363f39 Update translations for nb-no (Norsk Bokmål) 2022-12-03 00:30:16 +01:00
Mario
1a4f59cd70 bump version 2022-12-02 19:32:47 +00:00
Mario
25727a24a5 fix typos 2022-12-02 19:29:46 +00:00
Mario
2fd2dc964b Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2022-12-02 19:28:52 +00:00
Mario
935b032f15 db update 1254 2022-12-02 19:22:50 +00:00
Mario
2bb58843ab move queueworker to core and bump version 2022-12-02 19:22:19 +00:00
Mario
00512579f3 fix regression when adding feed contacts
(cherry picked from commit 5216c5b232)
2022-12-02 18:47:40 +01:00
Mario
6f09796142 Merge branch 'fix-category-widget-urls' into 'dev'
Fix Category widget URLs

See merge request hubzilla/core!2030
2022-12-02 17:46:42 +00:00
Mario
697a74f37e fix regression: new event not created
(cherry picked from commit d16b6c3838)
2022-12-02 18:06:20 +01:00
Mario
d16b6c3838 fix regression: new event not created 2022-12-02 15:18:01 +00:00
Mario
e4461f2e61 adjust the query to work with postgres 2022-11-30 11:20:10 +00:00
Mario
baf1b8b02d fetch the unseen count in a subquery instead of a separate query and rename array key 2022-11-30 10:36:55 +00:00
Mario
3ce1373ae0 provide a pdl file for mod invite and set the profile 2022-11-30 09:18:57 +00:00
Mario
4002531b92 fix issue where site_firehose setting was always false 2022-11-29 10:00:07 +00:00
Mario
004d0f074d disable context help until its content will be updated - it is not helpful otherwise 2022-11-27 12:20:04 +00:00
Mario
e87887c328 re-install: make sure to fetch the latest hubloc in api_auth otherwise authentication might fail 2022-11-27 09:40:23 +00:00
Harald Eilertsen
2de2c8e207 Fix Category widget URLs
The category widget template expects a URL without any query params, as
it appends `/?cat=<selected category>` to the base URL passed to it.

The Widget code tried to preserve any query param passed to it except
for the `cat` query param. When passed to the template, this caused the
invalid URLs to be generated.

Example input url:

    https://example.com/channel/user?f=&tag=pasta

The URL generated for the "Dinner" category would then be:

    https://example.com/channel/user&tag=pasta&tag=pasta/?cat=Dinner

Which is troublesome in more than one way, and cause at least some
search bots to go wild by sending requests with increasingly long URLs.

This patch will simply discard the existing query params in the URL, so
with the same input url, the generated URL for the "Dinner" category
will now be:

    https://example.com/channel/user/?cat=Dinner

This is comparable to what the Category Cloud and Tag Cloud widgets
already do.
2022-11-26 15:45:37 +01:00
Mario
c76f19f19a bump version 2022-11-26 08:39:59 +00:00
Mario
a050e8c8f5 should compare against abook_updated to make sure we do not always poll broken feeds 2022-11-26 08:37:45 +00:00
Mario
ae1fad5de7 basically every incoming item should have a uuid by now 2022-11-25 18:44:33 +00:00
Mario
68ca8951a8 mark unseen items seen after a certain amount of time (default 90 days) 2022-11-25 18:37:22 +00:00
Mario Vavti
1e4718eae1 do not always trigger a sse event if pubs notification are off or the app is not installed for the channel 2022-11-24 16:42:09 +01:00
Mario Vavti
680cf25f37 de-duplicate by mid. there is no combined index for uid and uuid hence the query could be slow if an uid has a lot of items. the workaround for hubzilla < 4.0 is not required anymore 2022-11-24 16:08:57 +01:00
Mario Vavti
7ec6df495f slight restructure 2022-11-24 16:05:19 +01:00
Mario
aeda31fda7 fix warnings 2022-11-24 09:52:50 +00:00
Mario
5248aa3065 css fix 2022-11-24 09:42:35 +00:00
Mario
67767c5853 Merge branch 'redbasic/dark-theme-fixes' into 'dev'
redbasic: Dark scheme fixes

See merge request hubzilla/core!2029
2022-11-23 18:43:42 +00:00
Mario
6de1aec683 the blue dots were slightly too bold. 2022-11-22 21:10:11 +00:00
Harald Eilertsen
221d3cdf6a redbasic: Dark theme fixes
- Make rows in admin tables readable while hovering over them.
2022-11-22 15:31:54 +01:00
Harald Eilertsen
1ff12c5520 redbasic: Dark scheme fixes
- Changed background of category tags to make them readable.
- Changed background on "view source" dialog to make it readable.
2022-11-22 09:46:41 +01:00
Mario
41376ec2cd fix issue in tag_deliver() and silence some more warnings 2022-11-20 20:31:59 +00:00
Mario
bf335ecaf3 hq widget: use distinct classes for seen and unseen thread items count 2022-11-18 13:32:14 +00:00
Mario
424bc73f58 bump version 2022-11-18 10:45:42 +00:00
Mario
59e6989cbc hq widget: implement thread unseen items count 2022-11-18 10:43:33 +00:00
Mario
0e6b27c9f4 if a feed fails, do not update connected timestamp. attempt to poll feeds only once a day if we could not fetch it last time we tried 2022-11-17 11:50:13 +00:00
Mario
0e157e4e8b remove logging 2022-11-17 09:11:34 +00:00
Mario
805074a0f9 externals: fix warnings 2022-11-17 09:09:02 +00:00
Mario
5216c5b232 fix regression when adding feed contacts 2022-11-17 08:57:09 +00:00
Mario
8633162f0c bump versionà 2022-11-15 21:22:39 +00:00
Mario
c392a77b46 performance: just count the first 99 unseen items and display 99+ if there are more than 99 2022-11-15 21:22:10 +00:00
Mario
08c2c9bc22 possible fix for issue #1698 2022-11-15 19:29:29 +00:00
Mario
f64bd590a8 bump version 2022-11-14 05:51:32 +00:00
Mario
131ffcf582 changelog 7.8.6 2022-11-14 05:49:33 +00:00
Mario
b17a0aef17 fix typo and version 7.8.6 2022-11-14 05:47:16 +00:00
Mario
8a21783fa5 bump version 2022-11-13 19:45:36 +00:00
Mario
53152e2ef5 version 7.8.5 2022-11-13 19:44:08 +00:00
Mario
ca6ba92d82 Merge branch 'dev' 2022-11-13 19:43:12 +00:00
Mario
04516b787a update changelog 2022-11-13 19:42:07 +00:00
Mario
6e124a4d72 changelog 2022-11-13 19:40:03 +00:00
Mario
6da65c7ddc cast the type to update if it is an edit 2022-11-13 17:13:33 +00:00
Mario
9eb332f032 allow to look for pubstream items if we do not own one but make sure the permissons are checked correctly 2022-11-10 17:57:26 +00:00
Mario
30ddee65a4 fix wrong array key and undefined array key 2022-11-10 10:48:24 +00:00
Mario
63dc8d7fc4 fix undefined variable 2022-11-10 10:37:41 +00:00
Mario
a1a287bac7 fix typo in variable name 2022-11-10 10:34:05 +00:00
Mario
e9b786d5e8 Ãwrong array key 2022-11-09 13:05:48 +00:00
Mario
ad9fb411f6 address issue #1705 2022-11-09 11:52:55 +00:00
Mario
1ff982983e items_fetch(): check if set and if there is a value 2022-11-09 11:34:03 +00:00
Mario
8c6c43d762 items_fetch(): check if set and if there is a value 2022-11-09 11:33:10 +00:00
Mario
6baf197842 version 7.8.4 2022-11-09 09:38:09 +00:00
Mario
42e5a50e4f changelog and version 2022-11-09 09:33:18 +00:00
Mario
b713c9a491 fix new uuid created when editing post 2022-11-09 09:27:33 +00:00
Mario
64ade742d9 whitespace 2022-11-07 19:55:30 +00:00
Mario
1870c3c876 whitespace 2022-11-07 19:55:13 +00:00
Mario
23b272aafd merge conflict 2022-11-07 19:53:03 +00:00
Mario
057db41758 bump version 2022-11-07 19:50:55 +00:00
Mario
839c5a8e41 fix regression where automatically created directories were not public and pinned/featured state of apps was not displayed correctly 2022-11-07 19:41:22 +00:00
Mario
36b8b6bf6c Merge branch 'dev' 2022-11-06 08:27:18 +00:00
Mario
40d74fa779 fix case and german translation string 2022-11-06 08:27:00 +00:00
Mario
249bdeb642 Merge branch 'dev' 2022-11-05 10:26:14 +00:00
Mario
b4ee80d1ea changelog 2022-11-05 10:25:40 +00:00
Mario
96bf9d0769 version 7.8.2 2022-11-05 09:52:11 +00:00
Mario
7fc9c83986 Merge branch 'dev' 2022-11-05 09:50:55 +00:00
Mario
5502f1cc63 do not update the guid on xchan/hubloc updates and define some array keys 2022-11-04 10:31:05 +00:00
Mario
b55801323c fix warnings 2022-11-03 15:26:46 +00:00
Mario
818374c8cc wor around shares from streams not rendered correctly 2022-11-03 13:54:40 +00:00
Mario
e80191d4cd fix regression 2022-11-03 13:09:11 +00:00
Mario
c2a796b6ea rename variable and warning fixes 2022-11-03 11:57:35 +00:00
Mario
00694f0dfd css fixes 2022-11-02 19:19:24 +00:00
Mario
134f4c5b52 undefined array key 2022-11-02 18:59:47 +00:00
Mario
0840fc42f9 php warning 2022-11-02 18:49:36 +00:00
Mario
2650a647e9 php warnings 2022-11-02 18:32:52 +00:00
Mario Vavti
3311269162 throw a 404 if we could not determine which channel to load 2022-11-02 17:52:19 +01:00
Mario
b2172d39f6 re-install: if we have a cashed entry, make sure we fetch the latest 2022-11-02 15:54:12 +00:00
Mario Vavti
f4d39bd3c8 fix more php warnings 2022-11-02 16:52:42 +01:00
Mario Vavti
1cf659033b set hubloc_connected in mod fhublocs otherwise the hublocs might be removed by prune_hub_reinstalls() 2022-11-02 10:38:40 +01:00
Mario
3dc5527690 css variables 2022-10-31 14:01:00 +00:00
Mario
81b02d04b5 version 7.8.1 2022-10-26 21:57:53 +00:00
Mario
95f6f9e10a Merge branch 'dev' 2022-10-26 21:56:32 +00:00
Mario
9554f53519 update version and changelog 2022-10-26 21:54:29 +00:00
Mario
5d7081a224 fix php warnings 2022-10-26 21:40:27 +00:00
Mario
9cbdf3f31f wrong argument in documentation 2022-10-26 19:27:15 +00:00
Mario
c8bc1b560b missing field in query 2022-10-26 19:11:13 +00:00
Mario
40ae6b396f fix php warnings 2022-10-26 18:12:56 +00:00
Mario
9c117ffa05 fix php warnings 2022-10-26 15:56:41 +00:00
Mario Vavti
9e95f189ed fix php warnings 2022-10-26 17:56:04 +02:00
Mario Vavti
221b31bcc6 fix php warnings 2022-10-25 19:06:17 +02:00
Mario Vavti
8879776d64 fix php warnings 2022-10-23 14:02:19 +02:00
Mario
5edd13c6bb fix various issues 2022-10-21 11:20:23 +02:00
Mario
7ca289edd0 fix php warnings 2022-10-20 19:25:01 +00:00
Mario
bf434818d7 fix php warnings 2022-10-20 13:16:03 +00:00
Mario
03aeb88832 fix php warnings 2022-10-20 10:25:11 +00:00
Mario Vavti
bb5b33a0d3 fix more php warnings 2022-10-20 11:40:31 +02:00
Mario Vavti
53931017b9 fix php warnings 2022-10-20 11:15:06 +02:00
Mario Vavti
e9ca17cec1 fix php warnings 2022-10-18 12:39:13 +02:00
Mario
f70956964b fix php warning 2022-10-14 15:23:23 +00:00
Mario Vavti
4547a9d9d3 catch decryption failure edgecase 2022-10-14 17:13:23 +02:00
Mario Vavti
71accb6b0a fix php warnings 2022-10-13 16:38:18 +02:00
Mario Vavti
2a95500b65 fix more php warnings 2022-10-13 13:15:08 +02:00
Mario Vavti
2ddad66ce7 mod dirsearch: fix php warnings 2022-10-13 12:48:22 +02:00
Mario
108be24aed remove logging 2022-10-12 19:39:15 +00:00
Mario
71efb05658 fix php warnings 2022-10-12 19:36:24 +00:00
Mario
a9a36894cb fix php warnings 2022-10-12 12:15:30 +00:00
Mario
bc9778e02f poco: remove unused parameters 2022-10-12 10:02:18 +00:00
Mario
a83d2efe84 remove dead code and deal with conv privacy mismatches in Activity::store() 2022-10-12 09:47:47 +00:00
Mario
d3856caf81 composer update michelf/php-markdown 2022-10-12 09:09:55 +00:00
Mario
e1f9b1c47d composer update jbroadway/urlify 2022-10-12 09:01:22 +00:00
Mario
497c953d0e composer update bshaffer/oauth2-server-php 2022-10-12 08:54:51 +00:00
Mario
bec76bd057 composer update ezyang/htmlpurifier 2022-10-12 08:53:14 +00:00
Mario
54f4762e1a composer update symfony 2022-10-12 08:48:27 +00:00
Mario
8bf5c18425 composer update ramsey/uuid 2022-10-12 08:45:01 +00:00
Mario
c36bb17475 composer update sabre 2022-10-12 08:42:41 +00:00
Mario
2291fcdf11 composer update simplepie 2022-10-12 08:28:35 +00:00
Mario
4070c46d15 composer update smarty 2022-10-11 19:20:46 +00:00
Mario
a749db8d0f composer update twbs 2022-10-11 18:45:17 +00:00
Mario
10ba98c4f5 Revert "update composer libs"
This reverts commit 108a3efe0b.
2022-10-11 18:41:34 +00:00
Mario
108a3efe0b update composer libs 2022-10-11 18:34:03 +00:00
Mario
ccd826f63a Revert "update composer libs"
This reverts commit 5e5f0aa955.
2022-10-11 18:29:06 +00:00
Mario
5e5f0aa955 update composer libs 2022-10-11 18:18:57 +00:00
Mario
f9a4c53e3f jQuery.timeago.settings.strings should not be in document.ready 2022-10-11 10:03:05 +00:00
Mario
60b576568e more css fixes 2022-10-11 09:45:12 +00:00
Mario
d0e1b73205 css fixes 2022-10-11 09:18:40 +00:00
Mario
ef2448e17e Merge branch '7.8RC' 2022-10-10 18:05:26 +00:00
Mario
99a5cf1ad4 version 7.8 2022-10-10 18:03:48 +00:00
Mario
bc3113ae16 Merge branch 'dev' into 7.8RC 2022-10-10 16:50:04 +00:00
Mario
fb475da008 update changelog 2022-10-10 16:37:24 +00:00
Mario
d5fc3ad646 Merge branch 'dev' into 7.8RC 2022-10-10 16:29:50 +00:00
Mario
8b7da6e318 spanish translations as per Manuel 2022-10-10 15:06:48 +00:00
Mario
ed208c4bcc update changelog 2022-10-10 15:02:37 +00:00
Mario
6ab65519a0 when updating hubloc_connected also update hubloc_updated
(cherry picked from commit 4549bc89ec)
2022-10-05 10:49:19 +02:00
Mario
4549bc89ec when updating hubloc_connected also update hubloc_updated 2022-10-05 08:41:31 +00:00
Mario
a0430f91bd fix owa in case of hub reinstalls 2022-09-30 10:25:46 +00:00
Mario
624bb1db8d Merge branch 'dev' into 7.8RC 2022-09-30 07:56:24 +00:00
Mario
9f522bbe6c update strings 2022-09-30 07:54:46 +00:00
Mario
931da3b4f7 Merge branch 'dev' into 7.8RC 2022-09-30 07:38:47 +00:00
Mario
5a25fd54a4 fix issue #1694 2022-09-30 07:14:47 +00:00
Mario
9f0f4c50a4 update htconfig.tpl 2022-09-30 06:43:53 +00:00
Mario
0bf3d31578 make it an info 2022-09-29 15:36:02 +00:00
Mario Vavti
8ca293c3e4 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2022-09-29 16:59:07 +02:00
Mario Vavti
ba0c877ffc fix menu item display issue 2022-09-29 16:56:54 +02:00
Mario
b8e00c2dc9 remove custom navbar override from repo 2022-09-29 14:19:14 +00:00
Mario
2dd48898a8 Merge branch 'dev' into 'dev'
GERMAN TRANSLATION - fix for minutes, hours, years,... by polls in .po file and translation more competed  pdpr1 and SiteTOS added

See merge request hubzilla/core!2027
2022-09-29 14:16:22 +00:00
Rock
66fc807655 GERMAN TRANSLATION - fix for minutes, hours, years,... by polls in .po file and translation more competed pdpr1 and SiteTOS added 2022-09-29 14:16:22 +00:00
Mario
653eb2909b Merge branch 'dev' into 7.8RC 2022-09-29 09:03:29 +00:00
Mario
72520a2dd9 fix hq widget displaying superblocked items 2022-09-29 08:58:36 +00:00
Mario
a7d4666a70 Merge branch 'dev' into 7.8RC 2022-09-28 15:21:34 +00:00
Mario
13476d5003 remove unnecessary check 2022-09-28 15:21:11 +00:00
Mario
879cdedec3 Merge branch 'dev' into 7.8RC 2022-09-28 10:35:36 +00:00
Mario
05bd2a1f9e one more hub reinstall fix 2022-09-28 10:35:09 +00:00
Mario
c49d1547c4 Merge branch 'dev' into 7.8RC 2022-09-28 10:27:58 +00:00
Mario
ad35363c2e hub reinstall issues 2022-09-28 10:27:35 +00:00
Mario
b3f70140e5 Merge branch 'dev' into 7.8RC 2022-09-27 08:59:44 +00:00
Mario
2f21dc50b4 fix mod poke 2022-09-27 08:59:08 +00:00
Mario
cbd8c2483b fix versionà 2022-09-26 08:33:47 +00:00
Mario
03475bfb15 Ãfix regression 2022-09-26 08:31:57 +00:00
Mario
bb9411e7dc update dev version 2022-09-26 07:16:11 +00:00
Mario
bce4e2d022 update version and strings 2022-09-26 07:13:01 +00:00
Mario
7cfc14fef7 emit a notice if an item was deleted - issue #1691 2022-09-22 12:50:11 +00:00
Mario
f220cf3173 fix issue #1687 2022-09-22 12:02:21 +00:00
Mario
725359b1aa fix issue #1690 2022-09-22 10:55:58 +00:00
Mario
937d6cb1ef php8: fix warnings 2022-09-22 06:31:35 +00:00
Mario
118a5edebc fix warnings and regressions 2022-09-15 09:19:55 +00:00
Mario
1b4333e8d9 chek permissions in get_things() - partly fixes issue #1686 a lot more work is requird though 2022-09-14 18:35:36 +00:00
Mario
d66a0b50e9 address issue #1688 2022-09-14 17:43:12 +00:00
Mario
1d56b9a1bb php8: warning fixes 2022-09-14 12:31:19 +00:00
Mario
96535ee4df make actor_store() fetch the actor object if none is provided, remove announce from the is_response array and provide a function to find the attributedTo url 2022-09-13 11:20:35 +00:00
Mario
b55f314d7e php8: fix warnings 2022-09-11 18:26:27 +00:00
Mario
480862d714 php8: fix more warnings 2022-09-11 14:58:40 +00:00
Mario
990a3af2a7 php8: random cleanup and warning fixes 2022-09-08 20:02:22 +00:00
Mario
1f5a23143a remove debug code 2022-09-07 18:07:38 +00:00
Mario
fcfb9e9758 fix random php warnings 2022-09-07 12:50:46 +00:00
Mario
9beee689ce fix display of star and dreport links 2022-09-06 11:32:27 +00:00
Mario
2c388c3833 add missing modal 2022-09-06 10:52:59 +00:00
Mario
1a75066616 revert: do not wrap multi line code blocks into pre tag 2022-09-06 10:27:01 +00:00
Mario
3dfb0bcae9 do not wrap multi line code blocks into pre tag 2022-09-06 09:21:39 +00:00
Mario
9ac0b77e92 fix missing closing div tag if there are no recent channel activities to display 2022-09-05 08:04:37 +00:00
Mario
6421a32520 fix issue where an unkown diaspora author was not imported if the comment arrived via a relayed activity and a minor css fix 2022-08-30 13:51:59 +00:00
Mario
fdcae52740 do not escape tags here since it will destroy additional query params 2022-08-21 18:21:05 +00:00
Mario
a8752844ef Activity: check for other forms of as:Public, Search: make sure to run htmlspecialchars_decode on the AP url so that previously encoded chars will be decoded again 2022-08-21 16:02:51 +00:00
Mario
e04ce5028e more css fixes 2022-08-20 15:53:09 +00:00
Mario
f2c4d80ac0 more css fixes 2022-08-20 15:10:16 +00:00
Mario
d8a6226805 fix syntax error 2022-08-20 11:26:28 +00:00
Mario
fedf60a32c redbasic dark: fixes 2022-08-20 11:23:46 +00:00
Mario
b3548fefc1 bump version 2022-08-20 10:07:57 +00:00
Mario
febd64c527 pdledit_gui: fix offcanvas 2022-08-20 10:06:04 +00:00
Mario
d67a5c5070 redbasic dark schema major cleanup 2022-08-20 09:56:23 +00:00
Mario
aefe7ddd8f redbasic: make use of css variables and implement link_hover_colour 2022-08-20 09:31:30 +00:00
Mario
254dea7558 more css fixes 2022-08-19 15:02:06 +00:00
Mario
b1550f7922 more css fixes 2022-08-19 14:34:09 +00:00
Mario
2d07c3e45d more bs upgrade fixes 2022-08-19 13:39:31 +00:00
Mario
e5f3406cb5 time for a new screenshot 2022-08-19 13:30:38 +00:00
Mario
185ddf1eaf update to bootstrap 5.2 and fixes 2022-08-19 13:15:48 +00:00
Mario Vavti
2734335869 version 2022-08-07 14:16:56 +02:00
Mario Vavti
0132c4e36e Merge branch 'dev' 2022-08-07 14:16:31 +02:00
Mario Vavti
7dee47183d changelog 2022-08-07 14:16:00 +02:00
Mario Vavti
9c4988c297 Merge branch 'dev' 2022-08-07 14:07:10 +02:00
Mario Vavti
3bfbc70587 check against null 2022-08-07 14:06:08 +02:00
Mario Vavti
34858fce1c Merge branch 'dev' 2022-08-07 12:17:56 +02:00
Mario Vavti
b47dab0ee9 update widget description 2022-08-05 12:45:43 +02:00
Mario Vavti
6eeb033b96 only decode attachment and iconfig for nonresponse activities 2022-08-04 12:42:35 +02:00
Mario Vavti
0679cb8e00 fix wrong attribution in unseen like notifications 2022-08-04 12:13:00 +02:00
Mario
3abc9ee387 fix regression in dark schema
(cherry picked from commit 2e9211cf41)
2022-07-27 09:29:22 +02:00
Mario
2e9211cf41 fix regression in dark schema 2022-07-27 07:27:51 +00:00
Mario
40377796ed Merge branch '7.6RC' 2022-07-26 18:00:00 +00:00
Mario
fedad7f31a version 7.6 2022-07-26 17:59:11 +00:00
Mario
d2a34e0107 Merge branch 'dev' into 7.6RC 2022-07-26 17:20:30 +00:00
Vinzenz Vietzke
769c822568 StartSSL is defunct since 2018
https://www.thesslstore.com/blog/startcom-ssl-shutting-down-2018/
2022-07-26 17:19:16 +00:00
Mario
c452a621fe Merge branch 'remove-dead-startssl' into 'master'
StartSSL is defunct since 2018

See merge request hubzilla/core!2022
2022-07-26 17:18:26 +00:00
Mario
231ab95ef6 update changelog 2022-07-26 17:16:13 +00:00
Mario
7c01b59ffb version 2022-07-26 15:38:57 +00:00
Mario
e79668ddf4 fix lang tests if result is ambigous 2022-07-26 15:37:17 +00:00
Mario
dc6b6fc353 add "falsey" test 2022-07-26 15:22:05 +00:00
Vinzenz Vietzke
34ea58cf38 StartSSL is defunct since 2018
https://www.thesslstore.com/blog/startcom-ssl-shutting-down-2018/
2022-07-25 12:14:43 +00:00
Mario
199168c318 bump dev version 2022-07-19 12:44:46 +00:00
Mario
063d4bbd7d composer autoload 2022-07-19 12:41:53 +00:00
Mario
29fd9b9d64 version and strings 2022-07-19 12:40:08 +00:00
Mario
c301baafb5 check if the webpages app is installed 2022-07-18 17:52:00 +00:00
Mario
4282672201 bump version 2022-07-16 14:52:10 +00:00
Mario
ae705dd865 HQ dashboard - missing files 2022-07-16 14:49:56 +00:00
Mario
f0fa2ce171 bump version 2022-07-15 17:51:01 +00:00
Mario
d6a9a9927c HQ dashboard - initial checkin 2022-07-15 17:50:02 +00:00
Mario
40b4636858 fix vcard-card background for dark schema 2022-07-03 09:49:09 +00:00
Mario
97fe499b63 Merge branch 'redbasic/dark-fixes' into 'dev'
redbasic/dark: make category pills readable.

See merge request hubzilla/core!2021
2022-07-03 09:42:06 +00:00
Mario
e0915cffda es: update plural function 2022-06-23 17:10:35 +00:00
Mario
7602de85c3 make sure the document is loaded 2022-06-23 17:01:43 +00:00
Harald Eilertsen
0787817eb8 redbasic/dark: make category pills readable. 2022-06-21 19:24:21 +02:00
Mario
e030648957 Merge branch 'dev' of https://codeberg.org/hubzilla/hubzilla into dev 2022-06-21 08:57:43 +00:00
hubzilla
b815935fd7 Merge pull request 'Fixing some error in Spanish translation' (#12) from mjfriaza/hubzilla:dev into dev
Reviewed-on: https://codeberg.org/hubzilla/hubzilla/pulls/12
2022-06-21 10:57:12 +02:00
Mario
a5000ba311 Merge branch 'dev' into 'dev'
Fix Opengraph images inside zmg opening tag

See merge request hubzilla/core!2020
2022-06-21 08:52:47 +00:00
Max Kostikov
5e2bb874c8 Fix Opengraph images inside zmg opening tag 2022-06-14 23:19:09 +02:00
mjfriaza
fcb5a7f645 Revert "Fixing some error in Spanish translation"
This reverts commit 1d99c3d3f7.
2022-06-12 18:18:55 +02:00
mjfriaza
b8c6520abb Fix two errors in Spanish translation 2022-06-12 17:21:14 +02:00
mjfriaza
1d99c3d3f7 Fixing some error in Spanish translation 2022-06-05 17:29:44 +02:00
Mario
5e112b395d oembed: implement a max oembed size which defaults to 1MB and do not try to oembed text previews 2022-06-03 08:51:54 +00:00
Mario
d1a8e7813a Revert "composer updates"
This reverts commit 47448b11cd.
2022-06-02 08:00:45 +00:00
Mario
a0582fec12 Revert "composer update"
This reverts commit 2cd3a7b3f0.
2022-06-02 08:00:31 +00:00
Mario
2cd3a7b3f0 composer update 2022-06-02 07:56:13 +00:00
Mario
47448b11cd composer updates 2022-06-02 07:43:33 +00:00
Mario
e63f043841 Merge branch '7.4RC' 2022-06-01 07:00:21 +00:00
Mario
33dd0c83e3 version 7.4 2022-06-01 06:59:23 +00:00
Mario
32dad136f8 Merge branch 'dev' into 7.4RC 2022-06-01 06:58:19 +00:00
Mario
073ed52538 update changelog 2022-06-01 06:58:05 +00:00
Mario
eef828cf3e fix version after merge 2022-05-31 09:38:54 +00:00
Mario
d0b5930a3a Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2022-05-31 08:42:54 +00:00
Mario
c66ad9ccc8 update changelog 2022-05-31 08:42:27 +00:00
Max Kostikov
9959a15c8e Merge branch 'dev' into 'dev'
Update Russian translation

See merge request hubzilla/core!2019
2022-05-28 13:31:24 +00:00
Max Kostikov
f0e4b4dc84 Update Russian translation 2022-05-28 15:28:40 +02:00
Mario
f62f808368 bump dev version 2022-05-25 08:45:21 +00:00
Mario
530a521679 version and strings 2022-05-25 08:41:25 +00:00
Mario
50782dfb83 prevent php error and add some doco 2022-05-25 08:34:29 +00:00
Mario
27a142d5c5 cleanup 2022-05-25 08:17:37 +00:00
Mario
6d00b2e63d bump php version requirement 2022-05-25 08:14:59 +00:00
hubzilla
7be1415a3a Merge pull request 'Update Spanish' (#11) from mjfriaza/hubzilla:dev into dev
Reviewed-on: https://codeberg.org/hubzilla/hubzilla/pulls/11
2022-05-25 09:54:22 +02:00
Mario
0a30b12f7d move wiki related templates to addon 2022-05-25 07:02:15 +00:00
Mario
3058cbfbb2 categories widgets cleanup 2022-05-24 09:31:30 +00:00
Mario
ae780c977b move article and card categories widgets to addons 2022-05-24 09:18:41 +00:00
Mario
e146a67f4b fix photo permission if a photo description is available and use the filename as default photo description if uploading via the editor 2022-05-23 18:56:09 +00:00
Mario
162d86983a streamline inbound attachment handling and fix regression from issue #1679 2022-05-23 09:26:29 +00:00
Mario
8534366a31 move photo flag feature entry to core 2022-05-21 08:25:14 +00:00
Mario
d1c6617dc9 missing files after composer updates 2022-05-20 09:21:23 +00:00
Mario
6f994709b9 do not show deprecated warnings by default 2022-05-19 08:27:09 +00:00
Mario
55d833a9c8 update composer libs 2022-05-19 08:18:15 +00:00
Mario
8ba4745097 update to remove core apps (wiki, cards, articles) which have been moved to addons 2022-05-19 08:04:39 +00:00
Mario
940a0c8b10 add a hidden config for the hs2019 http sig algo 2022-05-19 07:36:57 +00:00
Mario
8928b24e23 rendering fixes 2022-05-19 07:22:10 +00:00
Mario
ae9a9191f3 implement starring of pubstream items 2022-05-18 08:47:45 +00:00
mjfriaza
cb553bd016 Update Spanish 2022-05-17 14:01:28 +02:00
mjfriaza
a75c61d71e Merge remote-tracking branch 'upstream/dev' into dev 2022-05-17 13:44:06 +02:00
Mario
c1dc16a89d make sure we use source.content when rendering events to correctly render observer related content. fix wrong media types. 2022-05-16 20:44:53 +00:00
Mario
66436ce4a2 fix php errors 2022-05-14 19:04:05 +00:00
Mario
62b1ff4ba1 add the title in forum post reshares 2022-05-14 18:30:39 +00:00
Mario
304d136437 do not set allowed to true if verb is ACTIVITY_SHARE and slightly changed logic for conv fetches 2022-05-13 19:13:47 +00:00
Mario
1b4268b9b0 do not stringify integer value 2022-05-11 11:52:22 +00:00
Mario
a7968e6525 update queries in mod search - fixes #1677 2022-05-11 11:50:29 +00:00
Mario
e59cc3d404 deal with pleroma reactions 2022-05-10 12:15:29 +00:00
Mario
3a2d126877 use rev instead of _updated and the unix timestamp is less likely to cause issues in the future 2022-05-09 08:27:50 +00:00
Mario
ee3d6fcfee use addr for webfinger and name for the real name in the userinfo array 2022-05-09 08:23:55 +00:00
Mario
09d929bd56 add the update date to the icon url. some platforms will not update if the icon url remains static 2022-05-07 13:42:14 +00:00
Mario
bd55ae15f2 cleanup channel apps 2022-05-07 07:09:31 +00:00
Mario
2ca80118bf more cleanup 2022-05-06 19:10:28 +00:00
Mario
04eb20ac35 some cleanup after moving articles and cards to addons 2022-05-06 14:58:27 +00:00
Mario
f299391aa1 fix core issue #1676 and a liked/disliked/commented confusion 2022-05-06 08:24:17 +00:00
Mario
c334fc9d22 move wiki to addons 2022-05-06 07:29:59 +00:00
Mario
8520088376 move articles to addon - also remove the pdl 2022-05-04 19:26:45 +00:00
Mario
9ada8518dc move articles to addon 2022-05-04 19:26:05 +00:00
Mario
f0c09b374c move cards to addon 2022-05-04 18:46:45 +00:00
Mario Vavti
c5f33baf27 version 7.2.2 2022-04-26 11:12:43 +02:00
Mario Vavti
2efcdd92e0 Merge branch 'dev' 2022-04-26 11:11:53 +02:00
Mario Vavti
38fda98b6d changelog and version 2022-04-26 11:11:17 +02:00
Mario Vavti
f9fd195c24 Merge branch 'dev' 2022-04-26 11:08:10 +02:00
Mario Vavti
01e82090b2 hubloc in AS has been moved from data to meta a while ago 2022-04-26 11:07:23 +02:00
Mario Vavti
39602ede37 version bump 2022-04-25 22:53:04 +02:00
Mario Vavti
98a311ae40 version 7.2.1 2022-04-25 22:23:47 +02:00
Mario Vavti
5c398b3e8f Merge branch 'dev' 2022-04-25 22:21:12 +02:00
Mario Vavti
83e585ee9b more changelog 2022-04-25 22:19:20 +02:00
Mario Vavti
e386499bfa Merge branch 'dev' 2022-04-25 22:16:39 +02:00
Mario Vavti
4552630bf8 changelog 2022-04-25 22:15:31 +02:00
Mario Vavti
2d8065a780 whitespace 2022-04-25 21:34:47 +02:00
Mario Vavti
b94da93c74 if we have not been provided a profile id set the profile id to the default profile - fixes #1671 2022-04-25 21:34:05 +02:00
Mario Vavti
695045f197 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2022-04-23 20:53:05 +02:00
Mario Vavti
376733bd08 fix regression with incoming poll answers from activitypub 2022-04-23 20:52:45 +02:00
Mario
4c7c5137c5 check if addons have been removed from the filesystem and also remove them from the db if that is the case 2022-04-22 07:42:31 +00:00
Mario
930b9820f2 Revert "move AP addressing to pubcrawl"
This reverts commit 1390e1db39
2022-04-07 07:28:43 +00:00
Mario Vavti
b2fa63f2c8 move AP addressing to pubcrawl
(cherry picked from commit 1390e1db39)
2022-04-07 09:27:12 +02:00
Mario Vavti
1390e1db39 move AP addressing to pubcrawl 2022-04-07 09:20:06 +02:00
Mario
e7768ae954 fixes in regard to hub re-installs: dismiss deleted hublocs, make sure we use the latest hubloc entry for addressing, in Queue::deliver() prefer primaries since their info is probably more accurate
(cherry picked from commit 38d977e546)
2022-04-01 11:56:07 +02:00
Mario
38d977e546 fixes in regard to hub re-installs: dismiss deleted hublocs, make sure we use the latest hubloc entry for addressing, in Queue::deliver() prefer primaries since their info is probably more accurate 2022-04-01 09:50:12 +00:00
Mario
3e38a24f0a fix PHP error 2022-03-31 10:07:15 +00:00
Mario Vavti
0784cd593a Merge branch '7.2RC' 2022-03-29 11:42:53 +02:00
Mario Vavti
9c5d2ee563 version 7.2 2022-03-29 11:41:33 +02:00
Mario Vavti
be5f7c2e67 Merge branch 'dev' into 7.2RC 2022-03-29 11:39:28 +02:00
Mario Vavti
0d0f73fb67 update changelog 2022-03-29 11:38:59 +02:00
Mario
680be6cfec Merge branch 'fix-changelog' into 'dev'
Update changelog with missing fix and cve

See merge request hubzilla/core!2018
2022-03-27 19:51:20 +00:00
Harald Eilertsen
2ab3d072b0 Update changelog with missing fix and cve 2022-03-25 22:14:39 +01:00
Mario
943ecff623 fix version 2022-03-25 09:27:39 +00:00
Mario
03973f5d1d changelog 2022-03-25 09:22:57 +00:00
Mario
c42a0fa9b6 bump dev version 2022-03-23 20:20:44 +00:00
Mario
61522ed31d strings 2022-03-23 20:16:33 +00:00
Mario Vavti
29a527426a make sure to set comments_closed to the created date if nocomment is set 2022-03-23 21:08:54 +01:00
Mario
62ac0ff21e streamline comment policy with downstream 2022-03-23 19:01:42 +00:00
Mario
a41c7caa18 Merge branch 'security-fixes-lfi-xss-open-redirect' into 'dev'
Security fixes

See merge request hubzilla/core!2017
2022-03-23 18:38:03 +00:00
Harald Eilertsen
b3ca31bce7 CVE-2022-27256: Open redirect via rpath query param.
Don't follow urls to external sites when submitting forms from the
settings modules. This mitigates an Open Redirect vulnerability where an
attacker could trick a user to go to an attacker controlled destination.

Fixes part of https://framagit.org/hubzilla/core/-/issues/1666
2022-03-20 15:34:24 +01:00
Harald Eilertsen
b02f6a1dae Add function is_local_url() to check if url is local. 2022-03-20 15:34:24 +01:00
Harald Eilertsen
d35609f33a CVE-2022-27258: XSS via rpath query param.
Escape URLs provided by the rpath query param in settings modules. This
prevents a possible Cross-Site scripting vulnerability, where an
attacker could inject web scripts and html into the settings form via
the rpath query parameter, and have a user execute the script by
tricking them to clicking a link.

Fixes part of https://framagit.org/hubzilla/core/-/issues/1666
2022-03-20 15:34:24 +01:00
Harald Eilertsen
8c19ab8f9f Add helper to escape URLs.
The escaping makes the URL safe for display and for use in HTML element
attributes (such as href="..." etc), but does not guarantee that the URL
itself is valid after conversion. This should be good enough for
mitigating XSS issues caused by injecting html or javascript into a URL.
Also probably good enough for _most_ normal URLs, but there may be
devils hidden in the details somewhere.
2022-03-20 15:34:24 +01:00
Harald Eilertsen
30ae198b89 CVE-2022-27257: LFI in Redbasic theme.
Limit valid chars in schema names, and discard attempts at loading
schemas with invalid names.

This prevents a local file inclusion vulnerability where an
unauthenticated attacker can include arbitrary php files readable by the
server process and potentially obtain remote code execution.

Valid schema names may consist of ascii letters, numbers, hyphens and
underscores. Should be good enough for most cases, I think.

Fixes https://framagit.org/hubzilla/core/-/issues/1665
2022-03-20 15:34:17 +01:00
Mario
bddeab3ac1 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2022-03-20 08:59:07 +00:00
Mario
591349ee74 add the signing algo to zotinfo, and store it in import_xchan() if present 2022-03-20 08:58:18 +00:00
Mario
9081a25e64 Merge branch 'volse-redbasic-dark' into 'dev'
redbasic/dark: Use bootstrap-nightfall for dark schema.

See merge request hubzilla/core!2016
2022-03-20 08:27:30 +00:00
Mario
1beadfc6e7 Merge branch 'volse-fix-stylesheet-root-path' into 'dev'
Use correct base url for stylesheets and js.

See merge request hubzilla/core!2015
2022-03-17 08:23:02 +00:00
Harald Eilertsen
f4af532c5a Trim trailing & from query_string.
When trying to fetch an image file from the Cloud module, the default
nginx config will add a trailing & if there's no args specified.

Example:

https://example.com/cloud/username/some_image.png

This will be rewritten to:

https://example.com/index.php?q=/cloud/username/some_image.png&

This in turn will cause the Cloud module to try to redirect back to the
original because it does not match the query_string (in which the
ampersand has been converted to a question mark). And this will repeat
until the browser get's tired of it.
2022-03-13 19:37:45 +01:00
Harald Eilertsen
76eb1a9d78 redbasic/dark: Tune button colours a bit.
Makes buttons a bit less bright so they don't stick out quite as much.
2022-03-13 17:08:06 +01:00
Harald Eilertsen
14a2790dcb redbasic/dark: Use schema colour for dropdown item 2022-03-13 17:08:06 +01:00
Harald Eilertsen
46f54db197 redbasic/dark: Use bootstrap-nightfall for dark schema.
This is a color only stylesheet, modifying the original Bootstrap colors
to a dark variant. Insert this as base before the redbasic dark schema
modifications, and any custom modifications to have a nicer base for the
dark schema.
2022-03-13 17:07:45 +01:00
Mario
4ffd7587a9 make sure an announce does not overwrite an item we already have and make sure it will be a toplevel post 2022-03-11 20:29:18 +00:00
Mario
c48c62c7a8 whitespace 2022-03-10 11:41:34 +00:00
Mario
9e7fd20ade support for hs2019 2022-03-10 09:44:37 +00:00
Mario
efa1d381ba move attachments to the top 2022-03-05 13:55:16 +00:00
Mario
740fa058aa remove logging 2022-03-04 18:43:54 +00:00
Mario
37f56e1efd event fixes 2022-03-04 18:43:21 +00:00
Mario
6294be371a bump version 2022-03-04 16:12:44 +00:00
Mario
bee7549a1e fix regression 2022-03-04 16:09:44 +00:00
Mario
db14dbacc9 streamline event activity handling 2022-03-04 15:05:58 +00:00
Mario
27058e6297 bump version 2022-03-04 09:51:21 +00:00
Mario
b41175e0e2 port some ap quirks from the addon 2022-03-04 09:45:11 +00:00
Mario
eeea3251ad more work on enhanced content filters 2022-03-03 20:31:43 +00:00
Harald Eilertsen
34ffff3947 Remove now unused function script_path. 2022-03-03 19:50:07 +01:00
Harald Eilertsen
65ed3818ec Use correct base url for stylesheets and js.
Use z_root instead of script_path when formatting stylesheet and
javascript links for the head section. script_path does not preserve
information about the port if the site uses a nonstandard port.
2022-03-03 19:47:33 +01:00
Mario
c8417df6f1 fix duplicate ids in login form and move login/register buttons into the hamburger menu on small screens 2022-03-03 16:52:04 +00:00
Mario
dc3be7ecf7 collect the accept headers in an array 2022-03-03 11:22:46 +00:00
Mario
cf3c0b593b Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2022-03-02 19:53:16 +00:00
Mario
34f64148e8 composer updates 2022-03-02 19:52:47 +00:00
Mario
fc5dad1983 port some peertube tweeks from pubcrawl to lib/activity 2022-03-02 19:52:26 +00:00
Mario
c3c40548b9 Merge branch 't0rum-master-patch-68993' into 'master'
Typo in Setup.php prevents users from using Postgres

See merge request hubzilla/core!2014

(cherry picked from commit 0e2e932102)

d384f55d Typo in Setup.php prevents users from using Postgres
2022-03-01 21:21:50 +01:00
Mario
0e2e932102 Merge branch 't0rum-master-patch-68993' into 'master'
Typo in Setup.php prevents users from using Postgres

See merge request hubzilla/core!2014
2022-03-01 20:20:58 +00:00
Mario
6930c4e23b fix feedutils regression 2022-03-01 20:06:10 +00:00
Mario
01b9f2dfcf enhanced content filters 2022-03-01 10:14:05 +00:00
Mario
0cc6f66a26 make gprobe deal with URLs, fix issue in get_actor_protocols and fix missing author issue if wall2wall comment arrives and author is not yet known 2022-02-28 10:16:19 +00:00
t0rum
d384f55dd1 Typo in Setup.php prevents users from using Postgres 2022-02-26 19:15:02 +00:00
Mario
1893368aa5 missing content region for directory 2022-02-23 13:52:49 +00:00
Mario
a520063265 widget descriptions and add content region to all pdl files for convenience 2022-02-23 11:52:11 +00:00
Mario
1e171a72a0 bump version 2022-02-21 10:18:39 +00:00
Mario
5b1a0d93b9 this was required for old style forum posts only and should not be needed anymore 2022-02-21 10:16:21 +00:00
Mario
7e04662a9c do not require network for forums widget 2022-02-21 10:03:43 +00:00
Mario
a804549781 remove deprecated widgets and add some more widget descriptions 2022-02-21 10:02:33 +00:00
Mario
2a60f1cc6e merge branch pdledit_gui into dev - many widgets still miss their description and requirements (this is work in progress) 2022-02-20 20:18:24 +00:00
Mario
2ddff785e5 thr_parent lost across edits 2022-02-18 18:52:38 +00:00
Mario
38882efb5c composer update 2022-02-18 12:43:10 +00:00
Mario
6f7786b068 Merge branch 'undefined' into 'dev'
Replace htconfig.tpl fr

See merge request hubzilla/core!2008
2022-02-15 10:41:36 +00:00
Mario
0819141f03 Merge branch 'dandauge-dev-patch-02109' into 'dev'
Update lostpass_eml.tpl fr

See merge request hubzilla/core!2009
2022-02-15 10:38:43 +00:00
Mario
329ef5049f Merge branch 'dandauge-dev-patch-69038' into 'dev'
Upload New File : invite.material.subject.tpl fr

See merge request hubzilla/core!2010
2022-02-15 10:38:12 +00:00
Mario
34bb8c65d6 Merge branch 'dandauge-dev-patch-34611' into 'dev'
Upload New File : invite.material.tpl fr

See merge request hubzilla/core!2011
2022-02-15 10:37:52 +00:00
Mario
575ccae6f9 Merge branch 'dandauge-dev-patch-30995' into 'dev'
Update passchanged_eml.tpl fr

See merge request hubzilla/core!2012
2022-02-15 10:37:30 +00:00
Mario
486be87e33 Merge branch 'dandauge-dev-patch-92660' into 'dev'
Update update_fail_eml.tpl fr

See merge request hubzilla/core!2013
2022-02-15 10:37:03 +00:00
Mario
c0350861ef php8 warnings 2022-02-13 19:31:51 +00:00
Mario
a7ec1805e3 address deprecation warnings 2022-02-13 18:58:12 +00:00
Mario
4b06bc552f add inbound support for quoteUrl 2022-02-13 16:53:43 +00:00
Dan d'Auge
76ee7b7eea Update update_fail_eml.tpl fr 2022-02-13 06:21:35 +00:00
Dan d'Auge
04b1e7e34f Update passchanged_eml.tpl fr 2022-02-13 06:08:31 +00:00
Dan d'Auge
17dbb156e1 Upload New File : invite.material.tpl fr 2022-02-13 06:03:17 +00:00
Dan d'Auge
135117c637 Upload New File : invite.material.subject.tpl fr 2022-02-13 05:54:55 +00:00
Dan d'Auge
d3348f7855 Update lostpass_eml.tpl fr 2022-02-13 05:51:23 +00:00
Dan d'Auge
39bbcb66c8 Replace htconfig.tpl fr 2022-02-13 05:22:33 +00:00
Mario
d45e8e4d20 make sure we have an array 2022-02-11 12:59:08 +00:00
Mario
d65052c1ac comment out failing tests for now 2022-02-11 12:19:50 +00:00
Mario
2fbc42753f language test 2022-02-11 11:42:33 +00:00
Mario
4195865965 add options 2022-02-11 11:29:08 +00:00
Mario
de3f6fbeba more dependencies 2022-02-11 11:25:24 +00:00
Mario
6a377120bd lets try this 2022-02-11 11:22:03 +00:00
Mario
502226b0a6 more ci testing 2022-02-11 11:16:03 +00:00
Mario
78206b48f4 add php-gd 2022-02-11 11:12:28 +00:00
Mario
dc3cec06ca restructure 2022-02-11 11:08:43 +00:00
Mario
5a7688e099 do phpunit though 2022-02-11 11:05:11 +00:00
Mario
c721f01c76 skip db tests for now 2022-02-11 11:02:50 +00:00
Mario
463806822c more ci testing 2022-02-11 10:56:23 +00:00
Mario
b74c2f001d more ci testing 2022-02-11 10:54:00 +00:00
Mario
9fc7a8b626 more ci testing 2022-02-11 10:47:27 +00:00
Mario
3ffd92a6c3 more ci testing 2022-02-11 10:45:31 +00:00
Mario
29b02e5329 more ci testing 2022-02-11 10:43:42 +00:00
Mario
97584e046f more ci testing 2022-02-11 10:40:04 +00:00
Mario
09d2fce85d run composer updatee 2022-02-11 10:33:54 +00:00
Mario
fc3060cb29 we do not actually require this for the tests 2022-02-11 10:28:22 +00:00
Mario
9804a67165 more version bumps 2022-02-11 10:24:51 +00:00
Mario
21eddefa41 typo 2022-02-11 10:18:10 +00:00
Mario
9b62e7eedb bump php image to 8.0 2022-02-11 10:17:04 +00:00
Mario
bf30cfd8a4 more composer updates 2022-02-11 10:01:39 +00:00
Mario
139ffae367 fix another deprecation warning 2022-02-11 09:51:21 +00:00
Mario
51a48cc264 bump php version 2022-02-11 09:42:54 +00:00
Mario
abbca12565 typo 2022-02-11 09:37:29 +00:00
Mario
9e9d96a2ec minor restructure to omit php 8.1 deprecation warning 2022-02-11 09:36:17 +00:00
Mario
615c9f1cbe composer update smarty to version 4.1 - new files 2022-02-11 09:27:57 +00:00
Mario
7d75d0cfbd composer update smarty to version 4.1 2022-02-11 09:27:35 +00:00
Mario
5468de2c6a composer libs minor version updates add new files 2022-02-11 09:23:29 +00:00
Mario
6d8aabab23 composer libs minor version updates 2022-02-11 09:21:19 +00:00
Mario
e74359fcfe 3rd arg in str_replace() can not be null 2022-02-11 09:10:19 +00:00
Mario
53c842c614 Merge branch 'dev' 2022-02-10 19:50:28 +00:00
Mario
23ececeb34 changelog and version 2022-02-10 19:48:52 +00:00
Mario
521c9eb566 Merge branch 'dev' 2022-02-10 19:45:08 +00:00
Mario
35877b1382 allow to override the DB charset via the $db_charset variable in .htconfig.php 2022-02-10 18:57:44 +00:00
Mario
c531287170 fix php8.1 deprecation warning 2022-02-09 19:25:55 +00:00
Mario
8e79a81b88 Merge branch 'dev' 2022-02-09 12:10:04 +00:00
Mario
b95ceb301f gc() returns bool 2022-02-09 12:09:33 +00:00
Mario
76a94495c4 Merge branch 'dev' 2022-02-09 12:02:00 +00:00
Mario
b6b2299b4e revert: union types are only possible from php version 8 and higher 2022-02-09 12:01:16 +00:00
Mario
34ddea87d3 version 2022-02-09 09:54:02 +00:00
Mario
3d318542cb Merge branch 'dev' 2022-02-09 09:50:08 +00:00
Mario
4a8c3cdc61 changelog 2022-02-09 09:49:46 +00:00
Mario
c0b6f2d95f fix missing asterisk 2022-02-09 09:23:12 +00:00
Mario
9ca7fccab8 Merge branch 'dandauge-dev-patch-55065' into 'dev'
Update register_verify_eml.tpl

See merge request hubzilla/core!1998
2022-02-09 09:15:10 +00:00
Mario
d91fcfc866 Merge branch 'dandauge-dev-patch-45641' into 'dev'
Update register_verify_member.tpl

See merge request hubzilla/core!1999
2022-02-09 09:14:44 +00:00
Mario
29b53f3b9d Merge branch 'dandauge-dev-patch-07376' into 'dev'
Update register_open_eml.tpl

See merge request hubzilla/core!2000
2022-02-09 09:13:58 +00:00
Mario
30987095c7 Merge branch 'dandauge-dev-patch-78369' into 'dev'
Upload New File : cert_bad_eml.tpl fr

See merge request hubzilla/core!2001
2022-02-09 09:13:16 +00:00
Mario
43b93de570 Merge branch 'dandauge-dev-patch-72709' into 'dev'
Upload New File : cron_bad_eml.tpl fr

See merge request hubzilla/core!2002
2022-02-09 09:12:59 +00:00
Mario
5b310cf315 Merge branch 'dandauge-dev-patch-59648' into 'dev'
Upload New File : invite.casual.subject.tpl fr

See merge request hubzilla/core!2004
2022-02-09 09:10:21 +00:00
Mario
a1c2a57ea6 Merge branch 'dandauge-dev-patch-81368' into 'dev'
Upload New File : invite.casual.tpl fr

See merge request hubzilla/core!2005
2022-02-09 09:08:36 +00:00
Mario
34bf8f1133 Merge branch 'dandauge-dev-patch-67694' into 'dev'
Upload New File : invite.formal.subject.tpl fr

See merge request hubzilla/core!2006
2022-02-09 09:06:57 +00:00
Mario
c708ec577e Merge branch 'dandauge-dev-patch-34373' into 'dev'
Upload New File : invite.formal.tpl fr

See merge request hubzilla/core!2007
2022-02-09 09:06:33 +00:00
Mario
c185685f2d pdo: add the charset to the connection string 2022-02-09 08:57:27 +00:00
Mario
daee5b3477 since we do not use feedutils for ostatus anymore, we can now safely use import_author_rss() instead of import_author_unknown() 2022-02-09 08:45:19 +00:00
Mario
5d0346ee30 rename variable 2022-02-08 20:44:30 +00:00
Mario
85ad5355cf revert logging 2022-02-08 20:13:19 +00:00
Mario
4c8b84633a revert deleted flag for webfinger and zotfinger key 2022-02-08 20:12:16 +00:00
Mario
c0dd4d748d HTTPSig: introduce the deleted keytype. this will allow us to not fetch an actor we have never seen before if we received a delete activity for this actor for some reason. this is only implemented in the activitypub inbox so far. 2022-02-08 19:51:10 +00:00
Mario
c94f25570b Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2022-02-08 15:15:18 +00:00
Mario
ffa5e08832 versionà 2022-02-08 15:15:03 +00:00
Mario Vavti
63243c8e04 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2022-02-08 15:15:34 +01:00
Mario Vavti
21c4ec2de0 fix php error in externals and streamline actor cache time 2022-02-08 15:14:16 +01:00
Mario
a8d87af418 to reduce overall network fetches cache actors in Activity::fetch() and fetch the ldsig creator with get_actor() instead of get_compound_property() so that it will check the cache before actually fetching 2022-02-08 14:09:54 +00:00
Dan d'Auge
7b084a065e Upload New File : invite.formal.tpl fr 2022-02-06 14:46:09 +00:00
Dan d'Auge
47f6b202e5 Upload New File : invite.formal.subject.tpl fr 2022-02-06 14:30:26 +00:00
Dan d'Auge
f588d8379b Upload New File : invite.casual.tpl fr 2022-02-06 10:20:05 +00:00
Dan d'Auge
58827e130b Upload New File : invite.casual.subject.tpl fr 2022-02-06 10:08:07 +00:00
Dan d'Auge
d702334604 Upload New File 2022-02-06 09:03:40 +00:00
Dan d'Auge
b04aa799e3 Upload New File : cert_bad_eml.tpl fr 2022-02-06 08:54:09 +00:00
Dan d'Auge
e113f6cb9d Update register_open_eml.tpl 2022-02-06 07:52:38 +00:00
Dan d'Auge
bc13b7eb72 Update register_verify_member.tpl 2022-02-06 07:42:00 +00:00
Dan d'Auge
f50b395da6 Update register_verify_eml.tpl 2022-02-06 06:41:23 +00:00
Mario
a0e8e40f1c whitespace 2022-02-04 12:50:25 +00:00
Mario
cb6055c1b8 clean the url from parameters 2022-02-04 12:48:47 +00:00
Mario
25424c16e4 unpack encoded mid and make sure to goaway to the right message 2022-02-03 19:09:15 +00:00
Mario
99dcdee67a move JSalmon stuff from the data to the meta field in Lib ActivityStreams and some more refinement on storing the raw ap and diaspora data in iconfig 2022-02-03 11:57:47 +00:00
Mario
99928f1aea only unset if set 2022-02-02 18:59:14 +00:00
Mario
1740ae2104 more PHP 8.1 deprecated warnings 2022-02-02 17:58:29 +00:00
Mario
d8372f8433 more PHP 8.1 deprecated warnings 2022-02-02 12:44:39 +00:00
Mario
2a15d2c421 more PHP 8.1 deprecated warnings 2022-02-02 12:40:09 +00:00
Mario
bacf19688f a like could be stored as item or activity so check both 2022-02-02 09:59:36 +00:00
Mario
31fbdcf6c5 typo 2022-02-01 10:32:54 +00:00
Mario
c8818cb7b3 formatting 2022-02-01 10:30:26 +00:00
Mario
eb20789821 allow zotfinger to recurse through all known hublocs if the one we got does not exist (404) or got removed (410). add functions for updating tables from array and deleting hublocs. 2022-02-01 10:01:56 +00:00
Mario
c90862217e bump version 2022-01-31 11:03:49 +00:00
Mario
df87d6feeb more work on relaying zap and diaspora, fix mod hcard 2022-01-31 10:18:58 +00:00
Mario Vavti
6c808abcfc PHP 8.1 band-aid 2022-01-31 09:49:00 +01:00
Mario Vavti
f1822bdfab add the signature 2022-01-31 08:46:12 +01:00
Mario
c3428acd80 make sure we never save a zot6 packet as ap raw message 2022-01-30 16:29:04 +00:00
Mario
d619192b22 attach iconfig to the activity and adjust ap raw message retrieval to handle both cases. also add a possibility to manually redeliver single hubs for debuging 2022-01-30 15:33:57 +00:00
Mario
5bdc713afe Merge branch 'dev' 2022-01-28 20:10:11 +00:00
Mario
46eff1c937 changelog 2022-01-28 20:09:29 +00:00
Mario
76e1ea1c02 version 7.0.1 2022-01-28 20:04:43 +00:00
Mario
755076a8e5 Merge branch 'dev' 2022-01-28 20:03:30 +00:00
Mario
b49f7b8b34 fix removing contacts from privacy groups 2022-01-28 19:40:42 +00:00
Mario
c4dd8885e4 $cmd should be a strig and not null 2022-01-28 13:32:28 +00:00
Mario
4c82952b58 formatting and unused variables 2022-01-28 13:29:25 +00:00
Mario
0da69cb9c7 do not use escape_tags() for inbox 2022-01-27 21:56:13 +00:00
Mario
36e244060c escape_tags() will turn & to &amp; and there for mess up the xchan hash 2022-01-27 21:51:56 +00:00
Mario
b13a9f57af fix for #1659 2022-01-27 21:10:13 +00:00
Mario
0aa67ad7f9 typo 2022-01-27 20:34:21 +00:00
Mario
195a3a6827 whitespace 2022-01-27 20:28:34 +00:00
Mario
38ecff1220 some refinement on storing the raw ap message, some comments and make sure the AS->raw is always a json string 2022-01-27 20:27:02 +00:00
Mario
67e64287af missing define of variable, remove deprecated zot-info and ofeed from webfinger 2022-01-26 19:28:04 +00:00
Mario
b022703b0b update to remove the mail app 2022-01-26 18:40:02 +00:00
Mario
e8069c0d93 use item_hidden instead of item_notshown for forum comment announces 2022-01-26 13:58:03 +00:00
Mario
7a1c6b64c2 $act->raw will not always hold the AP raw message. Look for it in iconfig. 2022-01-26 13:02:51 +00:00
Mario
8250cb1e8d always store the raw message 2022-01-26 09:35:08 +00:00
Mario
ffe2c4d42b make sure to escape the author name for the reply_to button 2022-01-24 08:51:14 +00:00
Mario
f06c970628 port z_curl_error() from zap 2022-01-23 20:23:40 +00:00
Mario
99bce46b32 fix doc 2022-01-23 15:08:13 +00:00
Mario
f711913778 fix doc 2022-01-23 15:06:18 +00:00
Mario
a8ac231667 make sure that if an existing contact role changes we will re-assign the permissions to all role members and cleanup 2022-01-23 15:03:26 +00:00
Mario
f7c8791a6d make sure we have an existing default role in any case 2022-01-23 13:43:33 +00:00
Mario
7acc775c91 wrong function name 2022-01-21 07:46:12 +00:00
Mario
c2e21e837f wrong function name 2022-01-21 07:45:42 +00:00
Mario
755d0f54f7 Merge branch '7.0RC' 2022-01-21 07:28:24 +00:00
Mario
f62d66ff25 version 7.0 2022-01-21 07:27:35 +00:00
Mario
406d19f930 Merge branch 'dev' into 7.0RC 2022-01-21 07:27:00 +00:00
Mario
42b13614eb update changelog 2022-01-21 07:26:23 +00:00
Mario
c942bd67fe Merge branch 'dev' into 7.0RC 2022-01-21 07:20:30 +00:00
Mario
b8dc3d74b6 update strings 2022-01-21 07:20:04 +00:00
Mario
38fb263737 string 2022-01-21 07:14:40 +00:00
Mario
b55beed2f9 string update 2022-01-20 14:27:28 +00:00
Mario
e9278c03c1 Merge branch 'dev' into 7.0RC 2022-01-20 10:29:52 +00:00
Mario
ae1fe83784 fix potential issue with ap addressing in mod hq 2022-01-20 10:27:55 +00:00
Mario
717a547c40 Merge branch 'dev' into 7.0RC 2022-01-20 10:03:02 +00:00
Mario
ec491e87ab remove deprecated template 2022-01-20 10:02:39 +00:00
Mario
42e30d0835 fix pgsql profile photo issue 2022-01-20 08:14:03 +00:00
Mario
5b19418e48 fix pgsql profile photo issue 2022-01-20 08:12:14 +00:00
Mario
1bc9a7373f Merge branch 'dev' into 7.0RC 2022-01-19 19:14:54 +00:00
Mario
23e59b5dcc update changelog 2022-01-19 19:14:30 +00:00
Mario
c6b459cf96 drop_item() requires the item id not the item array 2022-01-19 19:11:49 +00:00
Mario
33254b4cac Merge branch 'dev' into 7.0RC 2022-01-19 13:22:23 +00:00
Mario
44da40d18d revert background color 2022-01-19 13:21:32 +00:00
Mario
c742f25801 prevent duplicate ids and adjust spinner color 2022-01-19 13:19:32 +00:00
Mario
b153687bf1 prevent duplicate ids and adjust spinner color 2022-01-19 13:18:47 +00:00
Mario
3318f093da Merge branch 'dev' into 7.0RC 2022-01-19 11:25:06 +00:00
Mario
d98d56c3b5 provide a spinner for edit connection action in threads 2022-01-19 11:24:42 +00:00
Mario
c3f5f6c7ad Merge branch 'dev' into 7.0RC 2022-01-19 10:04:42 +00:00
Mario
5f21edcc53 update changelog 2022-01-19 10:04:20 +00:00
Mario
cd0731cbb0 version RC2 2022-01-19 09:51:32 +00:00
Mario
f392ddec2f Merge branch 'dev' into 7.0RC 2022-01-19 09:41:57 +00:00
Mario
df71168ab7 fix channel app naming and translation and cleanup apps with an db update 2022-01-19 09:41:16 +00:00
Mario
e93b26bf54 Merge branch 'dev' into 'dev'
Fix strings translation

See merge request hubzilla/core!1997
2022-01-19 09:21:55 +00:00
Mario
a73d4a8cbd Merge branch 'dev' into 7.0RC 2022-01-19 08:39:12 +00:00
Mario
20ee57801c we must check if actor.id is empty(). checking for isset() only could still end up in an empty string and produce unexpected results 2022-01-19 08:29:44 +00:00
Max Kostikov
6a270d7f02 Fix strings translation 2022-01-18 22:40:25 +02:00
Mario
68639637c9 RC1 2022-01-18 10:27:37 +00:00
Mario
0d1eabbc33 Merge branch 'dev' into 7.0RC 2022-01-18 10:26:21 +00:00
Mario
dce249f7a9 change name on all associated xchans by matching the url 2022-01-18 10:24:52 +00:00
Mario
1723d4fbd8 fix version 2022-01-18 09:59:54 +00:00
Mario
c4b09f1a4f check for existence of vcard 2022-01-18 10:50:25 +01:00
Mario
788c973c13 vcards are not actually implemented anymore 2022-01-18 10:39:00 +01:00
Mario
465c5c8cfb make sure to use the correct default role 2022-01-18 10:26:13 +01:00
Mario
ee28ba5be1 adjust lock hover text if item_private === 2 2022-01-17 08:23:15 +00:00
Mario
9a22e9cf39 bump dev version 2022-01-16 12:47:26 +00:00
Mario
2513f605b6 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2022-01-16 12:45:58 +00:00
Mario
3b1ffb2028 changelog 2022-01-16 12:45:00 +00:00
Max Kostikov
47c6624e12 Merge branch 'dev' into 'dev'
Update Russian translation

See merge request hubzilla/core!1996
2022-01-14 19:22:43 +00:00
Max Kostikov
b6f1b064d3 Update Russian translation 2022-01-14 21:20:40 +02:00
Mario
17d89467df composer dump autoload 2022-01-14 18:31:38 +00:00
Mario
1282214d48 strings and version 2022-01-14 18:28:33 +00:00
Mario
f4bc6ee615 ux improvements 2022-01-13 13:07:59 +00:00
Mario
f8b8d8c540 make sure to fallback if local_channel and no nav_bg is set 2022-01-13 10:32:36 +00:00
Mario
57ff667438 pwa improvements according to lighthouse 2022-01-13 10:18:53 +00:00
Mario
abe3039926 ux improvements 2022-01-12 21:08:29 +00:00
Mario
82a1117e91 mod profile_photo template cleanup 2022-01-12 13:43:30 +00:00
Mario
b6ff3a4d99 mod profile_photo cleanup 2022-01-12 13:35:51 +00:00
Mario
f4046efcb2 refactor mod profile_photo 2022-01-12 13:09:53 +00:00
Mario
fc1d3831cf revert commit 7e2aecd8 2022-01-11 09:59:07 +00:00
Mario
867deda247 remove legacy mail which has been deprecated since a year 2022-01-11 09:29:18 +00:00
Mario
f8149face5 toc: add headings 2022-01-11 09:17:39 +00:00
Mario
7e2aecd8bb lifetime->expires 2022-01-10 11:37:47 +00:00
Mario
105d121199 set samesite cookie flag to none - some browsers start to default the flag to lax (previous none) 2022-01-10 11:36:20 +00:00
Mario
37d662f2f5 css fixes 2022-01-10 09:29:59 +00:00
Mario
5b50454b4d make toc bbcode find its own container by default 2022-01-09 20:44:30 +00:00
Mario
b5e4c08fc5 fix get_tags() parsing toc bbcodes 2022-01-09 18:25:17 +00:00
Mario
db39cd8b7c fix php error 2022-01-09 16:38:10 +00:00
Mario
a35f741a35 deprecate AccessList::widget() 2022-01-09 15:40:54 +00:00
Mario
fc02e018cb mark group actors as such in items and minor text change 2022-01-08 18:57:59 +00:00
Mario
b14a530efb missing nav_set_selected() 2022-01-08 13:22:15 +00:00
Mario
f70bc571bd css fix 2022-01-08 13:17:19 +00:00
Mario
8cc64176b4 missing files 2022-01-07 20:14:11 +00:00
Mario
7450ac1a31 missing files 2022-01-07 20:07:09 +00:00
Mario
c72e5e3b66 streamline privacy groups 2022-01-07 20:03:40 +00:00
Mario
5e811819e2 add link to create new contact roles 2022-01-07 19:14:14 +00:00
Mario
f1c0034a18 more work on access tokens 2022-01-06 21:09:18 +00:00
Mario
7342cb81a3 bump version 2022-01-04 20:42:43 +00:00
Mario
b40e858556 only display connections widget if there are any connections to show 2022-01-04 20:42:07 +00:00
Mario
95a4ed7d6a do not show blocked or ignored contacts in connections 2022-01-04 20:31:42 +00:00
Mario
2c2d4b6b95 remove suggestions widget from mod directory 2022-01-04 19:57:04 +00:00
Mario
4490eae4fe remove suggestions widget from mod network 2022-01-04 19:55:53 +00:00
Mario
9d59cb0135 minor wording change and fix connections link 2022-01-04 19:48:15 +00:00
Mario
7d348fe69f fix Access^CccessList include and plink in post_activity_item() 2022-01-03 20:20:42 +00:00
Mario
fa8fb9e73f more lockview ui improvements 2022-01-03 11:00:14 +00:00
Mario
f6093872ec minor usability improvement 2022-01-03 09:35:42 +00:00
Mario
e8030e29d9 remove logging 2022-01-02 20:46:44 +00:00
Mario
df8bb0596a port new_token from zap, fixes and more cleanup 2022-01-02 20:45:25 +00:00
Mario
0003e0b8a5 lockview: fix guest links for profile groups and photos, cleanup 2022-01-02 19:33:10 +00:00
Mario
e42703d557 lockview: provide guest links for private resources 2022-01-02 08:49:36 +00:00
Mario
4636e56395 minor theme fixes 2021-12-29 18:45:03 +00:00
Mario
27ebeffad4 update_poll() can be called many times in a row for the same item if a multiple poll is being updated. This could result in the queueworker not processing duplicates. We are now adding the source item mid to the notifier call as the third argument (fragment) so that the queueworker will not think they are duplicates. The fragment is also passed to the deliver_hooks call in the notifier 2021-12-22 09:50:50 +00:00
Mario
07110cee17 add the title to the object 2021-12-21 09:58:07 +00:00
Mario
afa1f1416b string change 2021-12-21 09:20:53 +00:00
Mario
f8dfcab0ca string change 2021-12-21 09:20:21 +00:00
Mario
e14fd920d6 version 2021-12-21 09:19:07 +00:00
Mario
8c10fdae5b missing label 2021-12-21 09:14:48 +00:00
Mario
eee027d9ff Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-12-21 09:09:43 +00:00
Mario
1b1fb5d26a improve pconfig sync at the sending side 2021-12-21 09:08:36 +00:00
Mario Vavti
c36e0805d8 improve pconfig sync at the receiving side 2021-12-21 10:04:51 +01:00
Mario
5c56041185 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-12-18 19:45:42 +00:00
Mario
5aefe0b74f guest token xchan_network = "token" and remove permission checks since the guest tokens are now added to the abook automatically 2021-12-18 19:09:15 +00:00
Max Kostikov
20e0359efd Merge branch 'dev' into 'dev'
Update Russian translation

See merge request hubzilla/core!1995
2021-12-17 22:42:36 +00:00
Max Kostikov
9c790e5a90 Update Russian translation 2021-12-18 00:39:47 +02:00
Mario
9c79b5be77 version 2021-12-17 21:10:00 +00:00
Mario
2d9a4f4e42 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-12-17 21:08:54 +00:00
Mario
565602538c main.js simplify notify_id checks 2021-12-17 21:08:20 +00:00
Mario Vavti
78972725ae mod tokens cleanup and fixes 2021-12-17 22:05:45 +01:00
Mario
5ab90f7791 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-12-17 20:29:06 +01:00
Mario
b90d98fc2b implement background deleting of items in contact_remove() 2021-12-17 20:26:36 +01:00
Mario
eca3ae393b daemon to delete abbok items in the background 2021-12-17 19:25:28 +00:00
Mario
2bd69495d2 missing file 2021-12-17 19:52:54 +01:00
Mario
bfd3da43ac access token refactor 2021-12-17 19:48:09 +01:00
Mario
32a9eaf3b6 update db schemas 2021-12-17 15:30:26 +01:00
Mario
91cea1f28a add template 2021-12-17 15:01:25 +01:00
Mario
220ed35f58 implement contact role deletion 2021-12-17 14:59:25 +01:00
Mario
b1cf5d4e44 nag channel owners to select achannel role if they have not yet done so yet 2021-12-15 12:58:33 +00:00
Mario
fe330ec1bb bump version 2021-12-15 12:18:07 +00:00
Mario
2968bf8241 merge branch perms_ng into dev 2021-12-15 12:17:19 +00:00
Mario Vavti
a40babbf0d version 6.4.2 2021-12-14 11:12:43 +01:00
Mario Vavti
7822257e1c Merge branch 'dev' 2021-12-14 11:11:57 +01:00
Mario Vavti
b37165c62b changelog 2021-12-14 11:09:27 +01:00
Mario Vavti
5e9d267959 mod sse_bs: when processing returned mids, do not assume they are b64 encoded 2021-12-14 11:04:26 +01:00
Mario Vavti
1a1e6b6810 Announce missing in is_response_activity() 2021-12-11 10:56:50 +01:00
Mario Vavti
88140002e7 Merge branch 'dev' 2021-12-03 16:26:10 +01:00
Mario Vavti
efc203d958 fix blured profile images and pdl files 2021-12-03 16:25:42 +01:00
Mario Vavti
42d4cdcc39 Merge branch 'dev' 2021-12-03 15:13:57 +01:00
Mario Vavti
fd433b3eb6 main_width in rem 2021-12-03 15:10:59 +01:00
Mario Vavti
7483adb8ad Merge branch 'dev' 2021-12-03 14:55:39 +01:00
Mario Vavti
45fd462f80 fix content width for dark schema 2021-12-03 14:54:47 +01:00
Mario Vavti
807003adf7 version 6.4.1 2021-12-03 13:47:58 +01:00
Mario Vavti
1b0a17c7db Merge branch 'dev' 2021-12-03 13:46:41 +01:00
Mario Vavti
60b145833c changelog and version 2021-12-03 13:45:19 +01:00
Mario Vavti
39458b2ba8 fix hubloc_site_id in fix_system_urls() on detected site rename events and during sync_locations() if it changed or was stored incorrectly. 2021-11-30 10:50:31 +01:00
Mario Vavti
5de38b3632 mod channel: lookup zotinfo based on hash instead of address 2021-11-29 11:26:29 +01:00
Mario Vavti
6ced3426cf do not deliver to the same channel multiple times in case duplicate hubloc entries for the channel exist 2021-11-29 11:17:14 +01:00
Mario
43460c9d19 re-add css that was removed by accident 2021-11-26 19:29:43 +00:00
Mario
ca17fb01bc profile cleanup and fixes 2021-11-25 07:54:53 +00:00
Mario
a6f65aa9c5 add source option so that the right makros will be used in attach_store() 2021-11-25 07:44:31 +00:00
Mario
ae9a7727d6 maximum width of content region is now calculated in rem 2021-11-24 20:47:18 +00:00
Mario
3ac5d5257b fix issue where likes notices are emited allthough they are actually disabled 2021-11-24 20:19:35 +00:00
Mario
668d7c73ed address issue #1651 (reload page after comment or like) 2021-11-24 20:01:16 +00:00
Mario
c95f708c91 port httpmeta from zap 2021-11-24 09:08:11 +00:00
Mario
06e214e567 more work on responsive aside 2021-11-23 09:17:04 +00:00
Mario
18f8cafee0 minor vcard fixes 2021-11-21 20:17:14 +00:00
Mario
6bd6afac05 streamline profile vcard with xchan vcard 2021-11-21 19:50:36 +00:00
Mario
fe7ecede70 Merge branch '6.4RC' 2021-11-09 09:10:19 +00:00
Mario
089708ab9f version 6.4 2021-11-09 09:08:52 +00:00
Mario
daa844c038 Merge branch 'dev' into 6.4RC 2021-11-09 09:07:55 +00:00
Mario
4049992228 update changelog 2021-11-09 09:07:37 +00:00
Mario
7c576c91b7 Merge branch 'dev' into 6.4RC 2021-10-30 09:08:32 +00:00
Mario
17bd364614 remove logging 2021-10-30 09:07:56 +00:00
Mario
25ffd39519 Merge branch 'dev' into 6.4RC 2021-10-30 09:05:24 +00:00
Mario
acfa527e3e css fixes 2021-10-30 09:04:50 +00:00
Mario
b512416cb3 fix version 2021-10-28 14:17:53 +00:00
Mario
bd116c53a1 update changelog 2021-10-28 14:14:20 +00:00
Mario
1251fca256 remove mcrypt from the docs 2021-10-27 18:42:25 +00:00
Mario
b2fe21709c update sbom 2021-10-27 12:13:47 +00:00
Mario
c082d12b59 bump dev version 2021-10-27 08:11:09 +00:00
Mario
9a4ca44255 version and strings 2021-10-27 08:05:57 +00:00
Mario
6fce9a41b0 remove logging 2021-10-25 08:12:17 +00:00
Mario
65acdd7b15 mod regate: auto-connect the invitee with the inviter if auto channel create is enabled (default). fix issue where the default group was not set in the return array of create_identity() 2021-10-25 08:03:12 +00:00
Mario
a209374cbd invite: fix variable name in template and do not substitute the Â@ in the webfinger address with @+ 2021-10-22 09:52:30 +00:00
Mario
c1bb87db98 mod item: cleanup and remove some unused variables 2021-10-22 08:16:19 +00:00
Mario
8bae40449f remove library/urlify and use vendor/jbroadway/urlify instead 2021-10-22 08:07:19 +00:00
Mario
bc3bb4694a mod import: formating 2021-10-22 07:50:35 +00:00
Mario
22588e58f3 install urlify via composer 2021-10-22 07:46:30 +00:00
Mario
69ba4eb055 whitespace 2021-10-22 07:27:37 +00:00
Mario
687b9fb6a2 comment out warning about db version differences - it is not relevant 2021-10-22 07:26:30 +00:00
Mario
9b9ca9695c import_items: cleanup 2021-10-21 10:36:31 +00:00
Mario
6357c69868 import_items: provide a possibility to import exported zip files by year 2021-10-21 10:29:44 +00:00
Mario
15cb7ab7a1 nativeWikiPage: more whitespace and cleanup 2021-10-20 19:54:59 +00:00
Mario Vavti
2c741bd24d fix for issue #1640 - use item_store() instead of post_activity_item() which is checking for post_comment permission which we might not have in this case. item_store() requires slightly more data but basically does the same. Also some minor improvements and whitespace changes. 2021-10-20 21:35:42 +02:00
Mario
3f72a3beb6 fix xchan vcard rendering 2021-10-20 09:57:45 +00:00
Mario
42de18d96d fix dutch registration email verification email template
(cherry picked from commit c7515b8687)
2021-10-20 10:09:19 +02:00
Mario
4bdbdab399 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-10-20 08:08:09 +00:00
Mario
c7515b8687 fix dutch registration email verification email template 2021-10-20 08:07:06 +00:00
Mario
c79e39a488 improve code comments 2021-10-20 08:06:29 +00:00
Mario
d639104b71 invite: use the actual set language and check if we have a template for it
(cherry picked from commit c66a5ba732)
2021-10-18 21:44:06 +02:00
Mario
c66a5ba732 invite: use the actual set language and check if we have a template for it 2021-10-18 21:41:08 +02:00
Mario
79f9b49dd7 provide tags indicating the supported protocols in the actor object and probe for zot6 if appropiate 2021-10-18 07:53:45 +00:00
Mario
8b542c250a mod invite: skip the pre-check for valid email 2021-10-16 20:07:34 +00:00
Mario
55237683d2 xrd whitespace 2021-10-16 19:24:58 +00:00
Mario
27401794e1 rename functions after heavy lifting and expand custom sections to all possible sections 2021-10-16 18:10:23 +00:00
Mario
862a7c2dba manifest: remove orientation so that os default will be used and add default theme_color 2021-10-16 14:03:35 +00:00
Mario
bb31a4620e notes: provide translateable strings 2021-10-15 19:30:38 +00:00
Mario
7aaade8b23 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-10-15 19:17:31 +00:00
Mario
a622f533ad some heavylifting on manual item export 2021-10-15 19:17:06 +00:00
Max Kostikov
0dd27dabd6 Merge branch 'dev' into 'dev'
Update Russian translation

See merge request hubzilla/core!1994
2021-10-15 15:08:16 +00:00
Max Kostikov
8ab464acf2 Update Russian translation 2021-10-15 16:55:21 +02:00
Mario
db18438db2 escape_tags only once 2021-10-15 08:15:41 +00:00
Mario
f885f98611 use the proprt syntax 2021-10-14 18:59:41 +00:00
Mario
9b8b85545f Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-10-14 18:16:27 +00:00
Mario
532b479f96 provide local copies of the w3.org jsonld documents - addresses issue #1637 2021-10-14 18:15:38 +00:00
Mario
422dfca6d7 fix cacert missing some certificates after last update 2021-10-14 18:13:02 +00:00
Mario
c3d1474f59 Merge branch 'dev' into 'dev'
Support IDNA URLs embedding

See merge request hubzilla/core!1990
2021-10-14 13:16:18 +00:00
Max Kostikov
99873504e4 Support IDNA URLs embedding 2021-10-14 13:16:16 +00:00
Mario
138a67298d version 2021-10-13 11:36:18 +00:00
Mario
aca1551e86 implement AS representation of photos and albums, cleanup and minor fixes 2021-10-13 09:23:59 +00:00
Mario
ca32850a32 fix image object as per AS2 2021-10-12 20:06:11 +00:00
Mario
ba6f069997 HTTPSig: do not query for hubloc_addr 2021-10-12 19:05:21 +00:00
Mario
c6c6b52ccd notes: minor css fix 2021-10-12 18:59:52 +00:00
Mario
96c334e730 bbcode for notes app 2021-10-12 11:27:36 +00:00
Mario
3e503ec3a3 Revert "httpsig: add parentheses"
This reverts commit e455fae334.
2021-10-12 11:25:44 +00:00
Mario
e455fae334 httpsig: add parentheses 2021-10-12 11:25:24 +00:00
Mario
29f3dc2fa3 notifications_widget: fix regression hiding the #nav- * -sub element when there are no more notifications 2021-10-11 09:12:05 +00:00
Mario
aa41b16757 look for hubloc_id_url or hubloc_hash, otherwise we will always fetch the key from the net on platforms where those are different (e.g. mastodon). 2021-10-11 07:41:12 +00:00
Mario
f4d59abe41 streamline logic 2021-10-10 21:13:30 +00:00
Mario
18de58fd8b HTTPSig: cleanup, add some doco and implement missing force mechanism for fetching keys 2021-10-10 21:00:22 +00:00
Mario
4c2b188f8b if we do not have a display path, we are looking at the root directory 2021-10-10 18:16:13 +00:00
Mario
08f65420f4 messages widget: show user-plus icon for connection requests 2021-10-10 09:49:12 +00:00
Mario
b90228b319 make sure we do not select removed channels as importer in onepoll 2021-10-10 08:37:44 +00:00
Mario
ad2c165f26 bbcode: deal with codeblocks before we escape other tags 2021-10-10 08:10:49 +00:00
Mario
af5218593a update composer libs 2021-10-10 07:59:31 +00:00
Mario
f19acd9f50 remove redundant variable and provide missing phpdoc 2021-10-10 07:56:42 +00:00
Mario
59940e7f05 make sure to not include removed channels in xrd or webfinger queries 2021-10-09 19:46:27 +00:00
Mario Vavti
094536e633 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-10-09 20:08:23 +02:00
Mario Vavti
4f2a439873 mod import: only run automatic content and files import if api version is compatible 2021-10-09 20:08:11 +02:00
Mario
63bdab2b5f use Libzot::fetch_conversation to fetch conversations from search and add an optional force argument to process_delivery 2021-10-09 15:00:21 +00:00
Mario
14733f8482 more bs5 fixes 2021-10-09 08:58:11 +00:00
Mario
b830bbd084 remove hz_syslog and deal with intro notifications in the messages widget 2021-10-08 17:35:36 +00:00
Mario
c1894c5a39 bump version 2021-10-08 13:01:09 +00:00
Mario
e91e488e1f Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-10-08 12:26:08 +00:00
Mario
e6dac085cb update composer libs 2021-10-08 12:24:19 +00:00
Mario
5023a5b56b Merge branch 'Aksel-dev-patch-31902' into 'dev'
German roles.bb

See merge request hubzilla/core!1992
2021-10-06 15:22:43 +00:00
Aksel K
32d37d1178 Aktualisieren doc/de/roles.bb 2021-10-06 15:12:55 +00:00
Aksel K
848221649e Neue Datei hochladen 2021-10-06 14:56:01 +00:00
Mario
f5f357060b fix alt_pager() 2021-10-06 14:32:49 +00:00
Mario
98eea41865 fix drop_query_params() if no query params are left 2021-10-06 14:32:25 +00:00
Mario
8ac529f5ae simplify 2021-10-06 08:43:40 +00:00
Mario
b5fed08dd4 really de-duplicate entries for dead hubs 2021-10-06 08:33:10 +00:00
Mario
9bfcaf2669 do not show duplicate entries for dead hubs 2021-10-06 08:05:16 +00:00
Mario Vavti
af05ee7e1c Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-10-06 09:40:15 +02:00
Mario
3918439020 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-10-06 07:39:34 +00:00
Mario
3b71e115a4 implement sync logic in mod appman 2021-10-06 07:39:10 +00:00
Mario Vavti
c33660a015 move sync logic for apps to mod appman. this way we can re-use the functions without creating sync loops. 2021-10-06 09:36:14 +02:00
Max Kostikov
7963d4cb8f Merge branch 'ab-dev' into 'dev'
Polish translation: fixes and updates

See merge request hubzilla/core!1989
2021-10-05 18:27:42 +00:00
Mario
16281e0e7f disable app sync due to a possible loop 2021-10-04 19:16:38 +00:00
Mario Vavti
72c58e60d7 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-10-04 20:32:32 +02:00
Mario Vavti
4b48ff2868 also sync the undestroy action 2021-10-04 20:32:19 +02:00
Mario
8e212d30d0 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-10-04 18:21:08 +00:00
Mario
b9ae396e74 unset id before syncing 2021-10-04 18:20:51 +00:00
Mario Vavti
3a38946f8a more app sync 2021-10-04 20:19:16 +02:00
Andrzej Budziński
d0d3a5454e Polish translation: fixes and updates 2021-10-04 19:24:16 +02:00
Mario Vavti
04c6d77d2c set the sync flag to true 2021-10-04 14:14:30 +02:00
Mario Vavti
c2c5730d00 more app sync fixes 2021-10-04 14:08:39 +02:00
Mario Vavti
21a6dffd5f Revert "more app sync fixes"
This reverts commit 7430989212.
2021-10-04 13:54:45 +02:00
Mario Vavti
7430989212 more app sync fixes 2021-10-04 13:41:54 +02:00
Mario Vavti
2e26a13f81 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-10-04 13:31:30 +02:00
Mario Vavti
404ebd4d5e app sync fixes - part 2 2021-10-04 13:31:26 +02:00
Mario
11ea7bf0fc app sync fixes - part 1 2021-10-04 11:25:52 +00:00
Mario
6da7fe7d27 provide system app sync 2021-10-04 09:24:13 +00:00
Mario
538e540531 commment out deprecated code 2021-10-04 08:46:56 +00:00
Mario
53138f4b09 fix typo 2021-10-04 08:32:36 +00:00
Mario
3d71367f30 add pem 2021-10-04 08:31:00 +00:00
Mario
bb52ff9b4b fix site lookup and minor cleanup 2021-10-04 08:28:57 +00:00
Mario
ab5b82221c update certs 2021-10-03 18:24:26 +00:00
Mario
5c3b89a68b mod locs: do not show drop icon for local clones and get rid of redundant for loop 2021-10-03 17:48:00 +00:00
Mario
da923d7749 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-10-03 16:54:04 +00:00
Mario
55d905fdd9 clone channel delete issues - part 2 2021-10-03 16:53:48 +00:00
Mario Vavti
4ba70a3fae clone channel delete issues - part 1 2021-10-03 18:52:14 +02:00
Mario
a5835b0e85 disable pg tests 2021-10-03 12:59:10 +00:00
Mario
ed4e5c9bcf version 6.2.2 2021-10-03 12:40:48 +00:00
Mario
d8793de629 make sure we have a sender here
(cherry picked from commit 0722188ea6)
2021-10-03 14:38:59 +02:00
Mario
f45cb38cd3 make sure to return if we have no xchan here
(cherry picked from commit d6f81e139a)
2021-10-03 14:38:29 +02:00
Mario
0722188ea6 make sure we have a sender here 2021-10-03 12:36:17 +00:00
Mario
d6f81e139a make sure to return if we have no xchan here 2021-10-03 12:22:33 +00:00
Mario
58ee147653 fix typo 2021-10-03 08:20:16 +00:00
Mario
28ad6a6883 remove redundant query and exit with status 410 if channel was removed 2021-10-03 07:18:49 +00:00
Mario
9de8aefa98 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-10-03 07:11:27 +00:00
Mario
66c273ae8d channel_purge: raise limit by factor of 10 2021-10-03 07:11:12 +00:00
Mario Vavti
b27fbf209e Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-10-03 09:05:54 +02:00
Mario Vavti
4afd1ac705 add optional $removed argument to channelx_by functions to allow inclusion of removed channels which is required (mod channel, daemon notifier -> refresh_all) if a channel got removed also remove caching to App so we always get a fresh copy. In import_hublocs() add site_id to the array passed to Libzot::gethubs() because it is expected there. 2021-10-03 09:05:32 +02:00
Mario
d556ef59e6 sigh... 2021-10-02 14:09:55 +00:00
Mario
81e972b85c another try on pg test 2021-10-02 14:02:58 +00:00
Mario
3bb04cc323 nope - disable pg test until the issue is resolved 2021-10-02 13:28:35 +00:00
Mario
9ff43f081f another try to fix pg test 2021-10-02 13:23:44 +00:00
Mario
8c014e3b6b see if this fixes pgsql test issue 2021-10-02 13:15:17 +00:00
Mario
d8378a17c9 nav move header outsite of container - fixes app sticking above header when sorting 2021-10-02 13:04:10 +00:00
Mario
574a01727e fix removed channels counted for max id check and disable moving until we decide what to do with it 2021-10-02 12:56:35 +00:00
Mario
b5cea3301d cleanup api_auth and make it fetch the identity if we do not have it cached yet 2021-10-02 12:28:13 +00:00
Mario Vavti
9346a06f35 also check for vnotify 2021-10-01 22:48:09 +02:00
Mario Vavti
250e917c6e only show sse pubs if the app is installed 2021-10-01 22:44:26 +02:00
Mario Vavti
7b1cd37cd6 only bootstrap pubs if the app is installed 2021-10-01 22:30:00 +02:00
Mario Vavti
47e83a15c1 import_progress: deal with the situation where items/files are being imported but there are none to import 2021-10-01 21:52:30 +02:00
Mario
597e847a3b css fixes 2021-10-01 17:17:02 +00:00
Mario Vavti
47f3b41d5e remove redundant notice 2021-10-01 19:15:39 +02:00
Mario Vavti
e7f4c1ffd1 missing template class logic 2021-10-01 18:10:32 +02:00
Mario Vavti
9a87b8bf1b only allow resume if we are not completed yet 2021-10-01 17:24:19 +02:00
Mario Vavti
dac27aab68 remove logging 2021-10-01 17:11:14 +02:00
Mario Vavti
069a5429c9 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-10-01 17:09:54 +02:00
Mario Vavti
b1eaa810ce improve channel import progress page 2021-10-01 17:09:36 +02:00
Mario
e5e3c268a2 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-10-01 07:14:37 +00:00
Mario
22dff49673 improve file upload performance: start uploading next file only after the previous finished, make sure to not return when uploading via ajax 2021-10-01 07:14:05 +00:00
Max Kostikov
591905c282 Merge branch 'dev' into 'dev'
Fix possible storage conversion stuck on file save error

See merge request hubzilla/core!1988
2021-09-30 20:45:02 +00:00
Mario Vavti
6ed160e4fa wording 2021-09-30 17:50:36 +02:00
Mario Vavti
d462230b82 minor display change 2021-09-30 17:43:29 +02:00
Mario
e48ed9d06d Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-09-30 15:38:49 +00:00
Mario Vavti
6236869ebe implement file totals and add mod import_progress 2021-09-30 17:34:30 +02:00
Mario
2c7c9ae2d7 provide files total 2021-09-30 15:33:10 +00:00
Mario Vavti
b9b4e71f7d provide a very simple status page for content import 2021-09-30 12:25:03 +02:00
Mario Vavti
b0bf646d71 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-09-30 12:10:11 +02:00
Mario Vavti
5cb5ecdb54 implement channel purge daemon and send a notifier purge_all message if the xchan was deleted 2021-09-30 12:09:50 +02:00
Mario Vavti
44fa5ac9a1 add channel purge daemon 2021-09-30 12:06:28 +02:00
Max Kostikov
9a19f7eac9 Fix possible storage conversion stuck on file save error 2021-09-29 23:01:27 +02:00
Mario
af0896bb8b a possible fix for the nested list test 2021-09-29 20:57:16 +00:00
Mario
817237ef77 composer update league/html-to-markdown 2021-09-29 20:36:32 +00:00
Mario Vavti
fbefff6eed Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-09-29 21:47:36 +02:00
Mario Vavti
4ba47698d7 revise content import/export part 2 2021-09-29 21:47:12 +02:00
Mario
2688abf25a revise content import/export part 1 2021-09-29 19:43:22 +00:00
Mario
5eb79bd51e importer daemons: do not call with zap_compat flag and use return instead of kill so that queueworker can go on 2021-09-27 21:58:26 +00:00
Mario
d3f5f778a4 cleanup mod import and implement importer daemons ported from zap 2021-09-27 20:49:37 +02:00
Mario
3eeb2b0ee4 add importer daemons ported from zap 2021-09-27 18:37:09 +00:00
Mario
230a1919dd add outbox 2021-09-27 18:36:04 +00:00
Mario
14004fbf7f support un-starring of apps in app bin 2021-09-27 11:13:16 +00:00
Mario
73e8af98f2 fix notification panel collapsed state not saved if closed manually 2021-09-27 07:01:33 +00:00
Mario
0117a0019b make sure to also include ap hublocs here. we will select zot6 later in the function if present 2021-09-26 18:10:34 +00:00
Mario
35ff8781f0 always promote the outbox 2021-09-26 12:15:14 +00:00
Mario
2d17442f28 externals: if dealing with AP profiles also fetch comments. there is no way to fetch conversations later 2021-09-25 10:17:45 +00:00
Mario
5c179522bb bring back externals (slightly different approach), rename zotfeed to outbox for consistency wit AP naming. warning: this commit requires update of addons! 2021-09-25 09:03:16 +00:00
Mario
b35d95da52 dismiss deleted xchans in query 2021-09-25 08:47:39 +00:00
Mario
feca5afaa5 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-09-23 20:43:49 +00:00
Mario
9cb5274d30 add zot6 specific handling to onepoll 2021-09-23 20:43:37 +00:00
Mario Vavti
2870fd46da Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-09-23 21:54:12 +02:00
Mario Vavti
dff8ef91a6 implement the top option in items_fetch 2021-09-23 21:52:27 +02:00
Mario
0588975e37 Ãfix wrong variable name and streamline icon with unseen notifications icon 2021-09-23 14:59:40 +00:00
Mario
e0600b241a make sure we do not mix up likes on direct messages and commments on direct messages in notices 2021-09-23 12:45:55 +00:00
Mario
d19aa8fb3b make sure entries is initialized 2021-09-23 11:17:45 +00:00
Mario
989a4f3d49 add notices tab to HQ widget 2021-09-23 10:42:37 +00:00
Mario
2a2c4d3e9c fix bs regression 2021-09-23 08:50:44 +00:00
Mario
a451449766 Revert "composer update bootstrap to version 5.1.1"
This reverts commit 89e4006b2d.
2021-09-23 08:33:36 +00:00
Mario
3347fab105 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-09-22 16:16:50 +00:00
Mario
33a6c92629 version 2021-09-22 16:16:35 +00:00
Mario
0707d33493 bootstrap update fixes 2021-09-22 16:14:28 +00:00
Mario
89e4006b2d composer update bootstrap to version 5.1.1 2021-09-22 06:38:27 +00:00
Mario Vavti
4eb8921635 improve item_url_replace() - fixes #1507 2021-09-21 11:07:23 +02:00
Mario
26ac452c96 mod manage: do not query info which we do not use in the UI and probably should not due to performance considerations 2021-09-21 07:40:00 +00:00
Mario
7122e1522a perform profile sync after all the fields are updated otherwise we will sync outdated data 2021-09-21 07:33:02 +00:00
Mario
5497adfde6 add option to mark all notices of a thread read if a notice of the thread is clicked (default 1) and fix a php error in find_parent() if $act->obj is not an array 2021-09-18 18:06:32 +00:00
Mario
d4c2e50285 changelog and version 2021-09-16 09:50:08 +00:00
mjfriaza
481ecee9e8 Update Spanish 2021-06-01 11:57:11 +02:00
3095 changed files with 304369 additions and 235188 deletions

View File

@@ -1,7 +1,9 @@
# Select image from https://hub.docker.com/_/php/
#image: php:7.3
# Use a prepared Hubzilla image to optimise pipeline duration
image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
# image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
image: php:8.1
stages:
- test
@@ -35,7 +37,12 @@ before_script:
- if [ -f /usr/local/etc/php/conf.d/z_prod.ini ]; then mv /usr/local/etc/php/conf.d/z_prod.ini /usr/local/etc/php/conf.d/z_prod.ini.off; fi
# Install & enable Xdebug for code coverage reports
- pecl install xdebug
- apt-get update
- apt-get install zip unzip libjpeg-dev libpng-dev -yqq
- docker-php-ext-enable xdebug
- docker-php-ext-install gd
# Install composer
- curl -sS https://getcomposer.org/installer | php
# Install dev libraries from composer
@@ -43,31 +50,38 @@ before_script:
# php.ini settings
- echo 'xdebug.mode=coverage' >> /usr/local/etc/php/php.ini
# hidden job definition with template for MySQL/MariaDB
.job_template_mysql: &job_definition_mysql
# hidden job definition with template for PHP
.job_template_php: &job_definition_php
stage: test
script:
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
- vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
# hidden job definition with template for MySQL/MariaDB
#.job_template_mysql: &job_definition_mysql
# stage: test
# script:
# - echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
# - echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
# - echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
# - vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
# hidden job definition with template for PostgreSQL
.job_template_postgres: &job_definition_postgres
stage: test
services:
- postgres:latest
script:
- export PGPASSWORD=$POSTGRES_PASSWORD
- psql --version
- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT VERSION();"
#.job_template_postgres: &job_definition_postgres
# stage: test
# services:
# - postgres:latest
# script:
# - export PGPASSWORD=$POSTGRES_PASSWORD
# - psql --version
# - psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT VERSION();"
# Import hubzilla's DB schema
- psql -h "postgres" -U "$POSTGRES_USER" -v ON_ERROR_STOP=1 --quiet "$POSTGRES_DB" < ./install/schema_postgres.sql
# - psql -h "postgres" -U "$POSTGRES_USER" -v ON_ERROR_STOP=1 --quiet "$POSTGRES_DB" < ./install/schema_postgres.sql
# Show databases and relations/tables of hubzilla's database
#- psql -h "postgres" -U "$POSTGRES_USER" -l
#- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\dt;"
# Run the actual tests
- vendor/bin/phpunit --configuration tests/phpunit-pgsql.xml --testdox
# - vendor/bin/phpunit --configuration tests/phpunit-pgsql.xml --testdox
# hidden job definition with artifacts config template
.artifacts_template:
@@ -82,56 +96,61 @@ before_script:
- tests/results/
# PHP7.3 with MySQL 5.7
php7.3_mysql5.7:
<<: *job_definition_mysql
services:
- mysql:5.7
# PHP8.1
php8.1:
<<: *job_definition_php
# PHP8.0 with MySQL 5.7
#php8.0_mysql5.7:
# <<: *job_definition_mysql
# services:
# - mysql:5.7
# PHP7.3 with MySQL 8 (latest)
php7.3_mysql8:
<<: *job_definition_mysql
services:
- name: mysql:8
command: ["--default-authentication-plugin=mysql_native_password"]
# PHP8.0 with MySQL 8 (latest)
#php8.0_mysql8:
# <<: *job_definition_mysql
# services:
# - name: mysql:8
# command: ["--default-authentication-plugin=mysql_native_password"]
# PHP7.3 with MariaDB 10.2
php7.3_mariadb10.2:
<<: *job_definition_mysql
services:
- name: mariadb:10.2
alias: mysql
# PHP8.0 with MariaDB 10.2
#php8.0_mariadb10.2:
# <<: *job_definition_mysql
# services:
# - name: mariadb:10.2
# alias: mysql
# PHP7.3 with MariaDB 10.3 (latest)
php7.3_mariadb10.3:
<<: *job_definition_mysql
image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
services:
- name: mariadb:10.3
alias: mysql
# PHP8.0 with MariaDB 10.3 (latest)
#php8.0_mariadb10.3:
# <<: *job_definition_mysql
# image: php:8.0
#image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
# services:
# - name: mariadb:10.3
# alias: mysql
# PHP7.3 with PostgreSQL latest (11)
php7.3_postgres11:
<<: *job_definition_postgres
artifacts: *artifacts_template
#php7.3_postgres11:
# <<: *job_definition_postgres
# artifacts: *artifacts_template
# PHP7.3 with PostgreSQL latest (11)
php7.3_postgres11:
<<: *job_definition_postgres
image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
artifacts: *artifacts_template
#php7.3_postgres11:
# <<: *job_definition_postgres
# image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
# artifacts: *artifacts_template
# Generate Doxygen API Documentation and deploy it as GitLab pages
pages:
stage: deploy
cache: {}
image: php:7-cli-alpine
image: php:8-cli-alpine
before_script:
- apk update
- apk add doxygen ttf-freefont graphviz

548
CHANGELOG
View File

@@ -1,3 +1,551 @@
Hubzilla 8.4 (2023-05-17)
- Slightly rewrite Activity::store() to save a query
- Use act->objprop() in decode_note() to get activity values
- Make sure to re-discover a channel upon connecting if we have just an xchan but no hubloc
- Updated ES translations
- Updated RU translations
- Redesigned profile vcard to implement cover images
- Slightly improved discovery of AP quoted messages
- Updated bootstrap library
- Changed hashtag encoding to match mastodons expectations (issue #1750)
- Implement fedearted directory flags from trusted directory servers
- Use Activity::get_actor_hublocs() in Libzot::fetch_conversation() instead of custom queries
- Add the conversation endpoint
- Implement paginated fetch for zot requests in mod item
- Implement Zotconvo daemon to fetch conversations in the background
- Expose deleted channels to webfinger (otherwise we can not mark them deleted locally)
- Expire items in batches to prevent memory exhaustion
- Remove legacy zot compatibility tweaks
- Rewrite and simplify directory sync
- Improve potentially long running sql query finding the thread parent
- Implement option to override permissions for posts with mentions
Bugfixes
- Fix parent_mid and thr_parent not set correctly for response activities
- Fix query for postgres in attach_list_files()
- Fix item_url_replace() failing on arrays
- Fix OWA compatibility with friendica
- Fix regression in decoding the object type
- Fix xss vulnerability in justified gallery library
- Fix permissions not initialized after accepted follow request from AP
- Fix empty path passed to fopen()
- Fix % value in format_poll() not rounded
- Fix remove_all_xchan_resources() executed for local channels
- Fix likes not synced via libsync between clones
Addons
- Pubcrawl: fix xchan_url used as follow object instead of xchan_hash
- Channelreputation: moved to unmaintained repo due to duplication issues when storing data in pconfig
- Pubcrawl: add lemmy accept/reject follow quirks
- Diaspora: handle 4xx return codes in queue management
- Diaspora: fix fatal error in the case where parent_guid is set but empty
- Pubcrawl: if shared inbox delivery fails deliver to contacts instead of everybody we know from that site
- Articles: fix PHP error
- Diaspora: rewrite synced (from a clone) item author to primary
- Diaspora: improve reshare detection
- Diaspora: fix contact role not sets
- Pubcrawl: rewrite synced (from a clone) item author to primary
- Pubcrawl: if we receive a public message to the shared inbox deliver to following *and* directly addressed
Hubzilla 8.2 (2023-03-19)
- Remove redundant untranslated htconfig templates
- Implement workaround for friendica image/attachment construct
- Implement notification exception for forum posts repeated by group actors
- Updated es translations
- Rewrite totp multifactor auth and move it from addon to core (ported from streams)
- Implement page load progress indicator for pwa standalone mode
- Improved mod HQ logic to save some DB lookups
- Default owner_xchan to sender in Activity::store() except for fetched items
- Improved contact search
- Do not force new thread if announce comes from group actor
- Disable oembed in notes app
- Improved queue handling
- Slightly restructure conv item head
- Implemet author images in HQ widget
- Implement author filter in HQ widget
- Add config option db_skip_locked_supported which should be set if the DB backend supports skip locked
- Updated simple pie library
- Updated smarty library
- Updated forkawesome library
- Updated fullcalendar library
- Implement native dark/light mode in favour of dark/light schema
- Updated bootstrap library
Bugfixes
- Fix channel calendar location html not interpreted - issue #1728
- Fix max oembed size check if content length header is an array
- Fix group actor wall posts turned into direct messages when posting article or card
- Fix non zot profile mentions using zrl tag
- Fix message filter > and < not decoded
- Fix deleted hublocs included in author lookup
- Fix some more PHP warnings
- Fix syntax for get_compund_property()
- Fix xchan_pubforum not set on actor updates
- Fix duplicate directory entries for xchans with bogus second primary entry
- Fix missing created timestamp in like activity - issue #1729
- Fix messages not signed when posting from non primary locations
- Fix pinned post regression
- Fix autocomplete items not selectable on mobile
- Fix hubloc confusion in Libzot::fetch_conversation()
- Fix valid duplicate notification entries deduplicated
- Fix ics file import
- Fix recipients deduplication in some places
- Fix hashtag encoded with href instead of id
Addons
- Pubcrawl: re-implement encrypted content which got lost in transition
- Pubcrawl: flag fetched items
- Totp: removed from addons in favor of implementation in core
- Pubcrawl: fix delivery issues for relayed activities
- Cart: fix missing bootstrap namespace
- Gallery: do not inject gallery code in webpages
- Pubcrawl: fix sql error if mentions string is empty
- Cart: fix paypal order hash size
Hubzilla 8.0 (2023-01-13)
- Updated ru strings
- Implement ability to edit addon PDL with pdledit_gui and pdledit
- Implement queueworker auto sleep time
- Always add sys channel to receivers for public items
- Improved server sent events loop
- Exclude not tagable xchan networks handle_tag()
- Add mark html tag to the html2bbcode parser
- Embed or attach uploaded files depending on file type
- Changed logic to enable site only public stream - please revisit admin setting
- Updated nb-no strings
- Moved queueworker to core
- Provide a PDL file for mod invite and set the profile
- Disabled outdated context help
- Mark unseen items seen after a certain amount of time (default 90 days)
- Slightly restructure lib webfinger
- Improved redbasic dark schema
- Implement unseen thread and unseen items count in HQ widget
- In unseen items notifications just count the first 99 and display 99+ if there are more
Bugfixes
- Fix race conditions when processing multiple choice polls
- Fix affinity slider updates - issue #1714
- Fix issue where accounts created with a did2 could change their password
- Fix no message displayed if file not found in mod cloud
- Fix pubstream tagcloud unthreaded view
- Fix french invite template
- Fix comment permission issue in site only public stream
- Fix privacy tag not referring to latest hubloc entry
- Fix selected item not highlighted
- Fix poll issue when special chars and spaces are involved
- Fix prune_hub_reinstalls() to only care about zot6 hublocs
- Fix redis session PHP warnings
- Fix remote visitor photo uploads
- Fix mod shredwithme not showing any items
- Fix api_auth not referring to latest hubloc entry
- Fix category widget URLs
- Fix poller always polling broken feeds
- Fix sse event always triggered if public stream notification are off or the app is not installed
- Fix more PHP8 warnings
- Fix wrong variable in tag_deliver()
- Fix mod follow use trim() after punify() - issue #1698
Addons
- Cards: update widget info
- Articles: update widget info
- Wiki: update widget info
- Sse: filter apporvals
- Cards: use html_entity_decode before purify and html2plain for summary
- Articles: use html_entity_decode before purify and html2plain for summary
- Wiki: use html_entity_decode before purify and html2plain for summary
- Cards: fix comments not displayed if filter by category
- Articles: fix comments not displayed if filter by category
- Sse: respect the site public stream setting
- Queueworker: moved to core
- Pubcrawl: move db query out of foreach loop
- Pubcrawl: add mentions and thread owner to recipients for public items
Hubzilla 7.8.7 (2022-12-03)
- Fix regression when adding feed contacts
- Fix regression new channel calendar event not created
Hubzilla 7.8.6 (2022-11-14)
- Fix typo in boot.php
Hubzilla 7.8.5 (2022-11-13)
- Fix outbound edit activity not of type update
- Fix mod display not falling through to fetch public item
- Fix more PHP warnings
- Fix regression in items_fetch() which resulted in empty atom feed
- Pubcrawl: cleanup and slightly restructre mod inbox
Hubzilla 7.8.4 (2022-11-09)
- Fix new uuid created when editing a post
Hubzilla 7.8.3 (2022-11-07)
- Fix regression where auto created directories were not created with public permissions
- Fix regression where pinned/featured state of apps was not displayed correctly
Hubzilla 7.8.2 (2022-11-05)
- Pubcrawl: fix regression in inbox
- Fix display issue of shares coming from streams
- Throw a 404 if we could not determine which channel to load
- If we have a cached xchan/hubloc entry, make sure we fetch the latest
- Gallery: paint the background grid with css
Hubzilla 7.8.1 (2022-10-26)
- Silence tons of PHP warnings in core
- Catch decryption failure edgecase in receiver
- Deal with conversation privacy mismatches in Activity::store()
- Composer libs updates
- Fix timeago strings not always translated
- Fix edit link regression in cards addon
- Fix edit link regression in article addon
Hubzilla 7.8 (2022-10-10)
- Updated spanish translations
- Always update hubloc_updated timestamp if a hubloc is updated
- Do better with re-installs in various situations
- Update htconfig templates
- Emit an info if an item is deleted manually (issue #1691)
- Updated german translations
- Make Activity::actor_store() fetch the actor object if none is provided
- Check for various forms of as:Public for compatibility
- Cleanup dark schema
- Make use of CSS variables in redbasic
- Implement link hover color in redbasic
- Update to bootstrap version 5.2 which implements CSS variables
Bugfixes
- Fix stream filter for polls and events does not work anymore (issue #1694)
- Fix item menu display issue
- Fix HQ widget displaying superblocked items
- Fix mod poke
- Fix link to article or card not processed correctly if umlauts are involved (issue #1687)
- Fix mod siteinfo containing a dead link (issue #1690)
- Fix permission issue when displaying things (issue #1686).
- Fix check for existing profiles (issue #1688)
- Fix modal missing for conversation settings
- Fix missing closing div tag if there are no recent channel activities
- Fix issue where an unkown diaspora author was not imported if the comment arrived via a relayed activity
- Fix mangled xchan_url due to escape_tags()
- Fix the AP url not decode bin mod search
- Fix some php warnings
Addons
- Wiki: move create_missing_page() from widget to module
- Superblock: implement blocking for messages widget_item
- Diaspora: fix verification of relayed comments and likes
- Pubcrawl: make sure to store the attributedTo actor in announce activities
- Diaspora: fix issue where an unkown author was not imported if the comment arrived via a relayed activity
Hubzilla 7.6.1 (2022-08-07)
Bugfixes
- Fix attachments displayed in visible response activities
- Fix wrong attribution in unseen like notifications
Addons
- Cards: fix widget not implemented via pdl file (requires re-install)
- Articles: fix widget not implemented via pdl file (requires re-install)
- Wiki: fix widget not implemented via pdl file (requires re-install)
Hubzilla 7.6 (2022-07-26)
- Add filter rule to check for false condition
- Implement HQ dashboard to display recently created content for various modules
- Updated spanish translations
- Implement a max oembed size which defaults to 1MB
- Update composer libs
Addons
- Cart: do not attempt oembed
- Cards: implement channel_activities_widget for HQ dashboard
- Articles: implement channel_activities_widget for HQ dashboard
- Wiki: implement channel_activities_widget for HQ dashboard
Bugfixes
- Fix language filter filtering ambigous results
- Fix vcard-card background for dark schema
- Fix contact edit dialog not displayed in chrome browser
- Fix readability of category pills in dark schema
- Fix opengraph images inside zmg opening tag
- Fix oembed attempted for text previews
Hubzilla 7.4 (2022-06-01)
- Updated russian translations
- Raise min PHP version to 8.0
- Rewrite inbound attachment handling
- Move photo flag feature from addon to core
- Adjust default production php logging
- Update composer libs
- Add a hidden config to enable the hs2019 http signature algorithm
- Allow starring of pubstream items
- Update spanish translations
- Add the title in forum post reshares if applicable
- Implement inbound pleroma reactions
- Add real name info to the navbar template data
- Add the updated date to the icon url so that other platforms will pick it up on change
- Move wiki from core to addon
- Move articles from core to addon
- Move cards from core to addon
Addons
- Rendezvous: add missing default value to sql schema
- Wiki: moved from core to addons
- Articles: moved from core to addons
- Cards: moved from core to addons
- Photoflag: moved to core
- Sse: fix issue where notifications were emited for created tasks
Bugfixes
- Fix issue where inbound activitypub items lost image descriptions (issue 1679)
- Fix issue where observer tags were not rendered correctly in event items (issue 1674)
- Fix forum posts leaked into network stream
- Fix tags not found in search if not logged in (issue 1677)
- Fix dislikes causing stuck notifications (issue 1676)
Hubzilla 7.2.2 (2022-04-26)
- Fix item_verified not set due to data structure changes
Hubzilla 7.2.1 (2022-04-25)
- Fix changing profile image from new member widget - issue #1671
- Fix regression with incoming poll answers from activitypub introduced in 7.2
- Fix addons not removed from the DB when removed from the filesystem
- Fix regression in attaching images for activitypub introduced in 7.2
- Move activitypub addressing from core to the pubcrawl addon
- Fix hub re-install issues
- Fediwordle: slightly improved algorithm
Hubzilla 7.2 (2022-03-29)
- Streamline comment policy with downstream project
- Add new function is_local_url()
- Add helper function to escape URLs
- Add signing algorithm to zotinfo()
- Store signing algorithm in import_xchan()
- Use bootstrap-nightfall for redbasic:dark schema
- Add support for hs2019
- Remove unused function script_path()
- Move login and register button into the hamburger menu for small screens
- Collect accept headers in an array instead of a concatenated string
- Update composer libs
- Enhanced content filters
- Improve mod gprobe to also deal with URLs
- Adapt unseen forum posts query in mod network to new forum post style
- Remove deprecated widgets
- Add inbound support for quoteUrl to Lib/Activity
- Add widget descriptions
- Add a GUI for the PDL editor
Addons
- Pubcrawl: deprecate as.php in favor of core libs
- Pubcrawl: rewrite/modernize mod inbox
- Pubcrawl: reflect core enhanced content filter changes
- Diaspora: reflect core enhanced content filter changes
- Fediwordle: new addon - a distributed word game inspired by wordle
- Pubcrawl: streamline post_local hook with diaspora
Bugfixes
- Fix comments_closed date on posts where comments are disabled
- Fix open redirect via rpath query param (CVE-2022-27256)
- Fix cross-site scripting via rpath query param (CVE-2022-27258)
- Fix local file inclusion in redbasic theme (CVE-2022-27257)
- Fix baseurl for css and js
- Fix duplicate IDs in login form
- Fix unknown author not fetched if w2w comment arrives
- Fix thr_parent lost across edits
Hubzilla 7.0.3 (2022-02-10)
- Allow to override the charset for the PDO connection string via $db_charset in .htconfig.php
Hubzilla 7.0.2 (2022-02-09)
- Update french templates
- Add charset to the PDO connection strings
- Introduce delete keytype for get_activitystreams_key()
- Fix PHP error in Daemon/Externals
- Improved actor cache handling
- Implement manual fetch of packed local links
- Add JSalmon data to the meta field instead of data in Lib/ActivityStreams
- Fix some PHP8.1 deprecation warnings
- Fix delivery report for likes not found in some cases
- Allow zotfinger to recurse through all known hublocs if the one we got does not exist (404) or got removed (410)
- Diaspora: improve relaying of comments
- Fix regression in mod hcard
- Add the LD signature in Daemon/Notifier in case where there is no signed data available
- Prevent zot6 packet being saved as AP raw message
- Attach iconfig to the activity instead of the activity object
Addons
- Pubcrawl: make sure the sys channel falls through the app installed check
- Pubcrawl: improve local delivery of shared inbox items
Hubzilla 7.0.1 (2022-01-28)
- Fix removing contacts from privacy groups in the contact edit modal
- Fix escape_tags() messing with URLs in actor_store()
- Fix pagination in the cards module if a category is selected
- Remove unused entries in webfinger
- Remove deprecated mail app from apps
- Set item_hidden for forum comment announces
- Fix relaying of signed messages for activitypub
- Fix contact role permissions not re-assigned if the role permission has changed
- Fix default channel role not set in rare cases
Addons
- Pubcrawl: fix webfinger not returning the fetched URL
- Pubcrawl: improved queue handling for rejected deliveries
Hubzilla 7.0 (2022-01-21)
- Provide theme_color and background_color in App::$theme_info for usage in page meta and manifest
- PWA improvements according to lighthouse
- Refactor mod profile_photo
- Remove core legacy mail code
- Set session samesite cookie flag
- Improve toc bbcode for more flexible usecases
- Deprecate include/group in favor of Lib/AccessList
- Deprecate AccessList::widget()
- Mark forum channel profile images with a small icon in the timelines
- Improve privacy groups UI/UX
- Do not show connections widget if there are no connections
- Remove suggestions widget from various modules
- Provide guest access links for private resources in lockview
- Improve pconfig syncing
- deprecate include/group in favor of Lib/AccessList
- Implement background deleting of items in contact_remove()
- Refactor guest access tokens for better usability and provide quick access
- Refactor permissions handling
- Improved poll rendering
Bugfixes
- Fix items not deleted on remote channel purge
- Fix plink in post_activity_item()
- Fix multiple update_poll() calls dismissed in queueworker
- Fix blocked or ignored contacts displayed in connections
- Fix polls for forum channels
Addons:
- Legacy mail: remove
- Deprecate include/group in favor of Lib/AccessList
- Pubcrawl: support pleroma end time for polls
- Pubcrawl: slightly adjust the way we check mastodon direct messages
- Socialauth: scope support and improvements
Hubzilla 6.4.2 (2021-12-14)
- Fix issue in mod sse_bs where returning message id's were assumed to be base64 encoded
- Fix announce activity type not registered as response activity
Hubzilla 6.4.1 (2021-12-03)
- Fix hubloc_site_id in fix_system_urls() on detected site rename events
- Fix duplicate deliveries if duplicate hublocs available
- Redesign profile vcard for improved responsive handling
- Fix profile photos not stored in profile photo folder
- Maximum width of content region is now calculated in rem for improved responsive handling
- Fix likes notices emited allthough they are disabled
- Fix page not reloaded after comment/like in mod photos - issue #1651
- Port improved Lib/HttpMeta from zap
- Improved responsive aside
Hubzilla 6.4 (2021-11-09)
- Automatically connect the invitee with the inviting channel
- Use the composer version of urlify
- Implement zip file import of exported items from mod uexport
- Start sending supported protocols with the actor object
- Split up manual item export to separate sections
- Serve w3.org jsonld documents locally - issue #1637
- Support IDNA URL embedding
- Improve handling of re-installed hubs in lib HTTPSig
- BBcode support for notes widget/app
- Implement a force flag for HTTPSig::get_key()
- Update composer libs
- Use Libzot::fetch_conversation for manual content import
- Implement optional force argument in Libzot::process_delivery
- Improve german doco
- Move sync logic for apps to mod appman
- Provide sync for system apps
- Update certificates
- Return status code 410 if a channel is deleted
- Add optional argument to channelx_by_* functions to allow inclusion of removed channels
- Improve file upload performance
- Introduce progress tracking for channel cloning via network (not compatible with cloning from older versions)
- Improve channel delete performance by moving some actions to background tasks
- Introduce all in one channel cloning via network (not compatible with cloning from older versions)
- Rename zotfeed to outbox but keep an alias for compatibility
- Implement apps un-starring from the app bin via drag and drop
- Re-implement the externals daemon
- Add zot6 specific handling to onepoll
- Implement the top option in items_fetch() which will only return top level items
- Add notices tab to HQ widget
- Improve mod manage performance
- Add option to mark all notices of a thread read if a notice of the thread is clicked (default true)
- Provide a get_cached_actor_provider hook and improve the author/owner handling in Libzot::import()
Bugfixes
- Fix issue where remote channels could not create wiki pages due to wron permission check - issue #1640
- Fix dutch registration email template
- Fix selection of invite template
- Fix too restrictive email check in mod invite
- Fix photos and albums ActivityStreams 2 representation
- Fix keys always fetched from network in lib HTTPSig for some AP implementations
- Fix album display of root directory
- Fix onepoll importing to deleted channels
- Fix rendering of image tags in codeblocks
- Fix webfinger and xrd providing results for removed channels
- Fix alt_pager() providing too many arguments
- Fix drop_query_params() if no query params are provided
- Fix duplicate entries for dead hubs in delivery report
- Fix site lookup
- Fix mod locs displaying drop icons for local channels
- Fix multiple issues with propagating deletes of cloned channels
- Fix apps can be draged outsite of drop areas
- Fix removed channels counted in max id check
- Fix api_auth not fetching the id if it was not cached
- Fix public stream unseen notifications displayed allthough the app is not installed
- Fix possible storage conversion stuck on file save error
- Fix notification panel collapsed state not saved if closed manually
- Fix find_best_identity() dismissing AP hublocs
- Fix likes and commments on direct messages mixed up in notices
- Fix rewrite of links to resources in body fails if nicknames of clones differ - issue #1507
- Fix syncing outdated data due to profile sync done before the fields were updated
- Fix $desturl set to wrong value (null)
Addons
- Cart: add settings URL to the apd file
- Diaspora: remove deprecated included
- Cart: remove deprecated include
- Openid: remove library/urlify in favor of composer installed versions
- Pubcrawl: provide tags indicating the supported protocols
- Pubcrawl: if we do not get an uuid, create a v5 uuid from the mid
- Cart: fix rendering regressions from bootstrap5 upgrade
- Upgrade_info: fix dismiss button
- Pubcrawl: move fetch_provider from core to addon
- Diaspora: fix regression in fetch_provider
- Content_import: fix syntax error
- Queueworker: update priorities
- Pubcrawl: only lookup announce author if we actually deal with an announce
- Pubcrawl: make sure we have the best identity before we make the abook lookup
- Pubcrawl: outbox moved to core
- Diaspora: implement the get_cached_actor_provider hook
Hubzilla 6.2.2 (2021-10-03)
- Fix an issue which could lead to loss of photos under certain conditions
Hubzilla 6.2.1 (2021-09-16)
- Fix regression introduced in 6.2 where Diaspora comments on Hubzilla posts were not relayed
- Fix wrong variable used for refresh under certain conditions

19
SBOM.md
View File

@@ -2,20 +2,21 @@
|Name|Version|License|Source|
|----|-------|-------|------|
|blueimp/jquery-file-upload|10.31.0.0|MIT|https://github.com/vkhramtsov/jQuery-File-Upload.git|
|brick/math|0.9.2.0|MIT|https://github.com/brick/math.git|
|blueimp/jquery-file-upload|10.32.0.0|MIT|https://github.com/vkhramtsov/jQuery-File-Upload.git|
|brick/math|0.9.3.0|MIT|https://github.com/brick/math.git|
|bshaffer/oauth2-server-php|1.11.1.0|MIT|https://github.com/bshaffer/oauth2-server-php.git|
|commerceguys/intl|1.1.0.0|MIT|https://github.com/commerceguys/intl.git|
|desandro/imagesloaded|4.1.4.0|MIT|https://github.com/desandro/imagesloaded.git|
|ezyang/htmlpurifier|4.13.0.0|LGPL-2.1-or-later|https://github.com/ezyang/htmlpurifier.git|
|league/html-to-markdown|5.0.0.0|MIT|https://github.com/thephpleague/html-to-markdown.git|
|jbroadway/urlify|1.2.2.0|BSD-3-Clause-Clear|https://github.com/jbroadway/urlify.git|
|league/html-to-markdown|5.0.1.0|MIT|https://github.com/thephpleague/html-to-markdown.git|
|lukasreschke/id3parser|0.0.3.0|GPL|https://github.com/LukasReschke/ID3Parser.git|
|michelf/php-markdown|1.9.0.0|BSD-3-Clause|https://github.com/michelf/php-markdown.git|
|pear/text_languagedetect|1.0.1.0|BSD-2-Clause|https://github.com/pear/Text_LanguageDetect.git|
|phpseclib/phpseclib|2.0.30.0|MIT|https://github.com/phpseclib/phpseclib.git|
|phpseclib/phpseclib|2.0.33.0|MIT|https://github.com/phpseclib/phpseclib.git|
|psr/log|1.1.4.0|MIT|https://github.com/php-fig/log.git|
|ramsey/collection|1.1.3.0|MIT|https://github.com/ramsey/collection.git|
|ramsey/uuid|4.1.1.0|MIT|https://github.com/ramsey/uuid.git|
|ramsey/collection|1.2.2.0|MIT|https://github.com/ramsey/collection.git|
|ramsey/uuid|4.2.3.0|MIT|https://github.com/ramsey/uuid.git|
|sabre/dav|4.1.5.0|BSD-3-Clause|https://github.com/sabre-io/dav.git|
|sabre/event|5.1.2.0|BSD-3-Clause|https://github.com/sabre-io/event.git|
|sabre/http|5.1.1.0|BSD-3-Clause|https://github.com/sabre-io/http.git|
@@ -25,7 +26,11 @@
|simplepie/simplepie|1.5.6.0|BSD-3-Clause|https://github.com/simplepie/simplepie.git|
|smarty/smarty|3.1.39.0|LGPL-3.0|https://github.com/smarty-php/smarty.git|
|symfony/polyfill-ctype|1.23.0.0|MIT|https://github.com/symfony/polyfill-ctype.git|
|twbs/bootstrap|4.6.0.0|MIT|https://github.com/twbs/bootstrap.git|
|symfony/polyfill-php80|1.23.1.0|MIT|https://github.com/symfony/polyfill-php80.git|
|symfony/polyfill-php81|1.23.0.0|MIT|https://github.com/symfony/polyfill-php81.git|
|twbs/bootstrap|5.1.3.0|MIT|https://github.com/twbs/bootstrap.git|
|voku/portable-ascii|1.5.6.0|MIT|https://github.com/voku/portable-ascii.git|
|voku/stop-words|2.0.1.0|MIT|https://github.com/voku/stop-words.git|
|fullcalendar/fullcalendar|4.4.2.0|MIT|https://github.com/fullcalendar/fullcalendar.git|
|miromannino/Justified-Gallery|3.8.1.0|MIT|https://github.com/miromannino/Justified-Gallery.git|
|fengyuanchen/cropperjs|1.5.7.0|MIT|https://github.com/fengyuanchen/cropperjs.git|

View File

@@ -139,6 +139,11 @@ class AccessList {
* @param boolean $explicit (optional) default true
*/
function set_from_array($arr, $explicit = true) {
$arr['contact_allow'] = $arr['contact_allow'] ?? [];
$arr['group_allow'] = $arr['group_allow'] ?? [];
$arr['contact_deny'] = $arr['contact_deny'] ?? [];
$arr['group_deny'] = $arr['group_deny'] ?? [];
$this->allow_cid = perms2str((is_array($arr['contact_allow']))
? $arr['contact_allow'] : explode(',', $arr['contact_allow']));
$this->allow_gid = perms2str((is_array($arr['group_allow']))

View File

@@ -89,4 +89,4 @@ class PermissionLimits {
return false;
}
}
}

View File

@@ -17,7 +17,7 @@ class PermissionRoles {
* @return number
*/
static public function version() {
return 2;
return 3;
}
static function role_perms($role) {
@@ -27,6 +27,54 @@ class PermissionRoles {
$ret['role'] = $role;
switch($role) {
case 'public':
$ret['default_collection'] = false;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_pages', 'view_wiki',
'send_stream', 'post_comments', 'post_mail', 'post_wall', 'chat', 'post_like', 'republish'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['limits']['post_comments'] = PERMS_AUTHED;
$ret['limits']['post_mail'] = PERMS_AUTHED;
$ret['limits']['post_like'] = PERMS_AUTHED;
$ret['limits']['chat'] = PERMS_AUTHED;
break;
// Hubzilla default role
case 'personal':
$ret['default_collection'] = true;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_pages', 'view_wiki',
'send_stream', 'post_comments', 'post_mail', 'chat', 'post_like'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['limits']['view_contacts'] = PERMS_SPECIFIC;
break;
case 'group':
$ret['default_collection'] = false;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'view_wiki', 'post_wall', 'post_comments',
'post_mail', 'post_like', 'chat'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['channel_type'] = 'group';
break;
// Provide some defaults for the custom role so that we do not start
// with no permissions at all if we create a new channel with this role
case 'custom':
$ret['default_collection'] = true;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'view_pages', 'view_wiki',
'send_stream', 'post_comments', 'post_mail', 'chat', 'post_like'
];
$ret['limits'] = PermissionLimits::Std_Limits();
break;
/*
case 'social':
$ret['perms_auto'] = false;
$ret['default_collection'] = false;
@@ -193,13 +241,14 @@ class PermissionRoles {
$ret['channel_type'] = 'group';
break;
*/
case 'custom':
default:
break;
}
$x = get_config('system','role_perms');
// let system settings over-ride any or all
if($x && is_array($x) && array_key_exists($role,$x))
$ret = array_merge($ret,$x[$role]);
@@ -284,6 +333,7 @@ class PermissionRoles {
*/
static public function roles() {
$roles = [
t('Social Networking') => [
'social_federation' => t('Social - Federation'),
'social' => t('Social - Mostly Public'),
@@ -317,4 +367,29 @@ class PermissionRoles {
return $roles;
}
/**
* @brief Array with translated role names and grouping.
*
* Return an associative array with role names that can be used
* to create select groups like in \e field_select_grouped.tpl.
*
* @return array
*/
static public function channel_roles() {
$channel_roles = [
//'public' => [t('Public'), t('A very permissive role suited for participation in the fediverse')],
//'personal' => [t('Personal'), t('The $Projectname default role suited for a personal channel')],
//'forum' => [t('Community forum'), t('This role configures your channel to act as an community forum')],
//'custom' => [t('Custom'), t('This role comes with the presets of the personal role but allows you to configure it to your needs')]
'public' => t('Public'),
'personal' => t('Personal'),
'group' => t('Community forum'),
'custom' => t('Custom')
];
call_hooks('list_channel_roles', $channel_roles);
return $channel_roles;
}
}

View File

@@ -41,7 +41,7 @@ class Permissions {
* @return number
*/
static public function version() {
return 2;
return 3;
}
/**
@@ -67,9 +67,9 @@ class Permissions {
'post_comments' => t('Can comment on or like my posts'),
'post_mail' => t('Can send me direct messages'),
'post_like' => t('Can like/dislike profiles and profile things'),
'tag_deliver' => t('Can forward direct messages to all my channel connections (forum)'),
'chat' => t('Can chat with me'),
'republish' => t('Can source my public posts in derived channels'),
'republish' => t('Can source/mirror my public posts in derived channels'),
//'tag_deliver' => t('Can forward to my contacts via direct messages (forum)'),
'delegate' => t('Can administer my channel')
];
@@ -217,25 +217,23 @@ class Permissions {
$my_perms = [];
$permcat = null;
$automatic = 0;
$automatic = get_pconfig($channel_id, 'system', 'autoperms');
// If a default permcat exists, use that
$pc = ((feature_enabled($channel_id, 'permcats')) ? get_pconfig($channel_id, 'system', 'default_permcat') : 'default');
if (!in_array($pc, ['', 'default'])) {
$pcp = new Zlib\Permcat($channel_id);
$permcat = $pcp->fetch($pc);
if ($permcat && $permcat['perms']) {
foreach ($permcat['perms'] as $p) {
$my_perms[$p['name']] = $p['value'];
}
$pc = get_pconfig($channel_id, 'system', 'default_permcat', 'default');
$pcp = new Zlib\Permcat($channel_id);
$permcat = $pcp->fetch($pc);
if ($permcat && $permcat['perms']) {
foreach ($permcat['perms'] as $p) {
$my_perms[$p['name']] = $p['value'];
}
}
// look up the permission role to see if it specified auto-connect
// and if there was no permcat or a default permcat, set the perms
// from the role
/*
$role = get_pconfig($channel_id, 'system', 'permissions_role');
if ($role) {
$xx = PermissionRoles::role_perms($role);
@@ -247,11 +245,12 @@ class Permissions {
$my_perms = Permissions::FilledPerms($default_perms);
}
}
*/
// If we reached this point without having any permission information,
// it is likely a custom permissions role. First see if there are any
// automatic permissions.
/*
if (!$my_perms) {
$m = Permissions::FilledAutoperms($channel_id);
if ($m) {
@@ -259,11 +258,12 @@ class Permissions {
$my_perms = $m;
}
}
*/
// If we reached this point with no permissions, the channel is using
// custom perms but they are not automatic. They will be stored in abconfig with
// the channel's channel_hash (the 'self' connection).
/*
if (!$my_perms) {
$r = q("select channel_hash from channel where channel_id = %d",
intval($channel_id)
@@ -280,10 +280,10 @@ class Permissions {
}
}
}
return (['perms' => $my_perms, 'automatic' => $automatic]);
*/
return (['perms' => $my_perms, 'automatic' => $automatic, 'role' => $pc]);
}
/*
static public function serialise($p) {
$n = [];
if ($p) {
@@ -295,4 +295,5 @@ class Permissions {
}
return implode(',', $n);
}
*/
}

View File

@@ -7,6 +7,7 @@ class Addon {
static public function run($argc, $argv) {
call_hooks('daemon_addon', $argv);
return;
}

View File

@@ -19,8 +19,10 @@ class Cache_embeds {
$item = $c[0];
// bbcode conversion by default processes embeds that aren't already cached.
// Ignore the returned html output.
// Ignore the returned html output.
bbcode($item['body']);
return;
}
}

View File

@@ -24,7 +24,7 @@ class Cache_query {
array_shift($argv);
array_shift($argv);
$arr = json_decode(base64_decode($argv[0]), true);
$r = call_user_func_array('q', $arr);
@@ -32,5 +32,7 @@ class Cache_query {
Cache::set($key, serialize($r));
del_config('procid', $key);
return;
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Zotlabs\Daemon;
class Channel_purge {
static public function run($argc,$argv) {
cli_startup();
$channel_id = intval($argv[1]);
$channel = q("select * from channel where channel_id = %d and channel_removed = 1",
intval($channel_id)
);
if (! $channel) {
return;
}
do {
$r = q("select id from item where uid = %d and item_deleted = 0 limit 1000",
intval($channel_id)
);
if ($r) {
foreach ($r as $rv) {
drop_item($rv['id'], false);
}
}
} while ($r);
return;
}
}

View File

@@ -10,6 +10,9 @@ class Checksites {
logger('checksites: start');
$site_id = '';
$sql_options = '';
if (($argc > 1) && ($argv[1]))
$site_id = $argv[1];

View File

@@ -9,6 +9,7 @@ class Cli_suggest {
static public function run($argc,$argv) {
update_suggestions();
return;
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace Zotlabs\Daemon;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Lib\PConfig;
require_once('include/cli_startup.php');
require_once('include/attach.php');
require_once('include/import.php');
class Content_importer {
static public function run($argc,$argv) {
cli_startup();
$page = $argv[1];
$since = $argv[2];
$until = $argv[3];
$channel_address = $argv[4];
$hz_server = urldecode($argv[5]);
$m = parse_url($hz_server);
$channel = channelx_by_nick($channel_address);
if(! $channel) {
logger('channel not found');
return;
}
$headers = [
'X-API-Token' => random_string(),
'X-API-Request' => $hz_server . '/api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page ,
'Host' => $m['host'],
'(request-target)' => 'get /api/z/1.0/item/export_page?f=&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page ,
];
$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 ]);
// logger('item fetch: ' . print_r($x,true));
if(! $x['success']) {
logger('no API response',LOGGER_DEBUG);
killme();
}
$j = json_decode($x['body'],true);
if(! is_array($j['item']) || ! count($j['item'])) {
PConfig::Set($channel['channel_id'], 'import', 'content_completed', 1);
return;
}
$saved_notification_flags = notifications_off($channel['channel_id']);
import_items($channel,$j['item'],false,((array_key_exists('relocate',$j)) ? $j['relocate'] : null));
notifications_on($channel['channel_id'], $saved_notification_flags);
PConfig::Set($channel['channel_id'], 'import', 'content_progress', [
'items_total' => $j['items_total'],
'items_page' => $j['items_page'],
'items_current_page' => count($j['item']),
'last_page' => $page,
'next_cmd' => ['Content_importer', sprintf('%d',$page + 1), $since, $until, $channel['channel_address'], urlencode($hz_server)]
]);
$page++;
Master::Summon([ 'Content_importer', sprintf('%d',$page), $since, $until, $channel['channel_address'], urlencode($hz_server) ]);
return;
}
}

View File

@@ -30,6 +30,7 @@ class Convo {
intval($channel_id),
dbesc($contact_hash)
);
if (!$r) {
return;
}
@@ -40,19 +41,26 @@ class Convo {
$messages = $obj->get();
if ($messages) {
foreach ($messages as $message) {
if (is_string($message)) {
$message = Activity::fetch($message, $channel);
}
// set client flag because comments will probably just be objects and not full blown activities
// and that lets us use implied_create
$AS = new ActivityStreams($message);
if ($AS->is_valid() && is_array($AS->obj)) {
$item = Activity::decode_note($AS);
Activity::store($channel, $contact['abook_xchan'], $AS, $item);
}
if (!$messages) {
return;
}
foreach ($messages as $message) {
if (is_string($message)) {
$message = Activity::fetch($message, $channel);
}
// set client flag because comments will probably just be objects and not full blown activities
// and that lets us use implied_create
$AS = new ActivityStreams($message);
if ($AS->is_valid() && is_array($AS->obj)) {
$item = Activity::decode_note($AS);
$item['item_fetched'] = true;
Activity::store($channel, $contact['abook_xchan'], $AS, $item);
}
}
return;
}
}

View File

@@ -3,6 +3,7 @@
namespace Zotlabs\Daemon;
use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\Libzotdir;
class Cron {
@@ -19,6 +20,7 @@ class Cron {
}
}
/*
// Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it.
$lockfile = 'store/[data]/cron';
if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))
@@ -30,13 +32,24 @@ class Cron {
// Create a lockfile. Needs two vars, but $x doesn't need to contain anything.
$x = '';
file_put_contents($lockfile, $x);
*/
logger('cron: start');
// If this is a directory server, request a sync with an upstream
// directory at least once a day, up to once every poll interval.
// Pull remote changes and push local changes.
// potential issue: how do we keep from creating an endless update loop?
$dirmode = get_config('system', 'directory_mode');
if ($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) {
Libzotdir::sync_directories($dirmode);
}
// run queue delivery process in the background
Master::Summon(array('Queue'));
Master::Summon(array('Poller'));
/**
@@ -51,7 +64,7 @@ class Cron {
require_once('include/account.php');
remove_expired_registrations();
$interval = get_config('system', 'delivery_interval', 3);
$interval = get_config('queueworker', 'queue_interval', 500000);
// expire any expired items
@@ -66,8 +79,10 @@ class Cron {
if ($rr['item_wall']) {
// The notifier isn't normally invoked unless item_drop is interactive.
Master::Summon(['Notifier', 'drop', $rr['id']]);
if ($interval)
@time_sleep_until(microtime(true) + (float)$interval);
if ($interval) {
usleep($interval);
}
}
}
}
@@ -97,8 +112,10 @@ class Cron {
if ($r) {
foreach ($r as $rr) {
Master::Summon(array('Directory', $rr['channel_id'], 'force'));
if ($interval)
@time_sleep_until(microtime(true) + (float)$interval);
if ($interval) {
usleep($interval);
}
}
}
@@ -152,8 +169,10 @@ class Cron {
);
}
Master::Summon(array('Notifier', 'wall-new', $rr['id']));
if ($interval)
@time_sleep_until(microtime(true) + (float)$interval);
if ($interval) {
usleep($interval);
}
}
}
}
@@ -204,12 +223,11 @@ class Cron {
}
// pull in some public posts
// pull in some public posts if allowed
/* $disable_discover_tab = get_config('system', 'disable_discover_tab') || get_config('system', 'disable_discover_tab') === false;
if (!$disable_discover_tab)
Master::Summon(array('Externals'));
*/
$disable_externals = get_config('system', 'disable_discover_tab') || get_config('system', 'disable_discover_tab') === false || get_config('system', 'site_firehose');
if (!$disable_externals)
Master::Summon(['Externals']);
$restart = false;
@@ -230,7 +248,7 @@ class Cron {
set_config('system', 'lastcron', datetime_convert());
//All done - clear the lockfile
@unlink($lockfile);
//@unlink($lockfile);
return;
}

View File

@@ -49,6 +49,22 @@ class Cron_daily {
dbesc('sse_id.%')
);
// Mark items seen after X days (default 90)
$r = dbq("select channel_id from channel where channel_removed = 0");
if ($r) {
foreach ($r as $rr) {
$mark_seen_days = get_pconfig($rr['channel_id'], 'system', 'mark_seen_days', 90);
q("UPDATE item SET item_unseen = 0 WHERE
uid = %d AND item_unseen = 1
AND created < %s - INTERVAL %s",
intval($rr['channel_id']),
db_utcnow(),
db_quoteinterval($mark_seen_days . ' DAY')
);
}
}
// Clean up emdedded content cache
q("DELETE FROM cache WHERE updated < %s - INTERVAL %s",
db_utcnow(),
@@ -78,17 +94,6 @@ class Cron_daily {
// expire any expired accounts
downgrade_accounts();
// If this is a directory server, request a sync with an upstream
// directory at least once a day, up to once every poll interval.
// Pull remote changes and push local changes.
// potential issue: how do we keep from creating an endless update loop?
$dirmode = get_config('system', 'directory_mode');
if ($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) {
Libzotdir::sync_directories($dirmode);
}
Master::Summon(array('Expire'));
Master::Summon(array('Cli_suggest'));
@@ -103,5 +108,7 @@ class Cron_daily {
/**
* End Cron Daily
*/
return;
}
}

View File

@@ -22,12 +22,12 @@ class Cron_weekly {
mark_orphan_hubsxchans();
// Find channels that were removed in the last three weeks, but
// Find channels that were removed in the last three weeks, but
// haven't been finally cleaned up. These should be older than 10
// days to ensure that "purgeall" messages have gone out or bounced
// or timed out.
// days to ensure that "purgeall" messages have gone out or bounced
// or timed out.
$r = q("select channel_id from channel where channel_removed = 1 and
$r = q("select channel_id from channel where channel_removed = 1 and
channel_deleted > %s - INTERVAL %s and channel_deleted < %s - INTERVAL %s",
db_utcnow(), db_quoteinterval('21 DAY'),
db_utcnow(), db_quoteinterval('10 DAY')
@@ -59,5 +59,6 @@ class Cron_weekly {
* End Cron Weekly
*/
return;
}
}
}

View File

@@ -28,6 +28,8 @@ class Deliver {
}
return;
}
}

View File

@@ -12,8 +12,12 @@ class Deliver_hooks {
$r = q("select * from item where id = '%d'",
intval($argv[1])
);
if ($r)
if ($r) {
call_hooks('notifier_normal', $r[0]);
}
return;
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Zotlabs\Daemon;
require_once('include/connections.php');
/*
* Daemon to remove 'item' resources in the background from a removed connection
*/
class Delxitems {
static public function run($argc, $argv) {
cli_startup();
if($argc != 3) {
return;
}
remove_abook_items($argv[1], $argv[2]);
return;
}
}

View File

@@ -49,8 +49,9 @@ class Directory {
);
// Now update all the connections
if ($pushall)
if ($pushall) {
Master::Summon(array('Notifier', 'refresh_all', $channel['channel_id']));
}
return;
}
@@ -93,8 +94,10 @@ class Directory {
}
// Now update all the connections
if ($pushall)
if ($pushall) {
Master::Summon(array('Notifier', 'refresh_all', $channel['channel_id']));
}
return;
}
}

View File

@@ -32,7 +32,6 @@ class Expire {
}
// physically remove anything that has been deleted for more than two months
/** @FIXME - this is a wretchedly inefficient query */
q("delete from item where item_pending_remove = 1 and changed < %s - INTERVAL %s",
db_utcnow(),
@@ -59,8 +58,8 @@ class Expire {
continue;
// service class default (if non-zero) over-rides the site default
$service_class_expire = service_class_fetch($rr['channel_id'], 'expire_days');
if (intval($service_class_expire))
$channel_expire = $service_class_expire;
else
@@ -85,7 +84,6 @@ class Expire {
// this should probably just fetch the channel_expire_days from the sys channel,
// but there's no convenient way to set it.
$expire_days = get_config('system', 'sys_expire_days');
if ($expire_days === false)
$expire_days = 30;
@@ -96,12 +94,15 @@ class Expire {
logger('Expire: sys interval: ' . $expire_days, LOGGER_DEBUG);
if ($expire_days)
if ($expire_days) {
item_expire($x['channel_id'], $expire_days, $commented_days);
}
logger('Expire: sys: done', LOGGER_DEBUG);
}
del_config('procid', 'expire');
return;
}
}

View File

@@ -3,6 +3,7 @@
namespace Zotlabs\Daemon;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\ASCollection;
@@ -18,6 +19,7 @@ class Externals {
$importer = get_sys_channel();
$total = 0;
$attempts = 0;
$url = '';
logger('externals: startup', LOGGER_DEBUG);
@@ -31,25 +33,54 @@ class Externals {
$url = $arr['url'];
}
else {
$networks = ['zot6'];
if (plugin_is_installed('pubcrawl')) {
$networks[] = 'activitypub';
}
stringify_array_elms($networks);
$networks_str = implode(',', $networks);
$randfunc = db_getfunc('RAND');
// fixme this query does not deal with directory realms.
//$r = q("select site_url, site_pull from site where site_url != '%s'
//and site_flags != %d and site_type = %d
//and site_dead = 0 and site_project like '%s' and site_version > '5.3.1' order by $randfunc limit 1",
//dbesc(z_root()),
//intval(DIRECTORY_MODE_STANDALONE),
//intval(SITE_TYPE_ZOT),
//dbesc('hubzilla%')
//);
$r = q("select site_url, site_pull from site where site_url != '%s'
and site_flags != %d and site_type = %d
and site_dead = 0 and site_project like '%s' and site_version > '5.3.1' order by $randfunc limit 1",
$r = q("SELECT * FROM hubloc
LEFT JOIN abook ON abook_xchan = hubloc_hash
LEFT JOIN site ON site_url = hubloc_url WHERE
hubloc_network IN ( $networks_str ) AND
abook_xchan IS NULL AND
hubloc_url != '%s' AND
hubloc_updated > '%s' AND
hubloc_primary = 1 AND hubloc_deleted = 0 AND
site_dead = 0
ORDER BY $randfunc LIMIT 1",
dbesc(z_root()),
intval(DIRECTORY_MODE_STANDALONE),
intval(SITE_TYPE_ZOT),
dbesc('hubzilla%')
datetime_convert('UTC', 'UTC', 'now - 30 days')
);
if ($r)
$url = $r[0]['site_url'];
if ($r) {
$contact = $r[0];
$url = $contact['hubloc_id_url'];
}
}
if (!$url) {
continue;
}
$blacklisted = false;
if (!check_siteallowed($url)) {
if (!check_siteallowed($contact['hubloc_url'])) {
logger('blacklisted site: ' . $url);
$blacklisted = true;
}
@@ -59,123 +90,68 @@ class Externals {
// make sure we can eventually break out if somebody blacklists all known sites
if ($blacklisted) {
if ($attempts > 20)
if ($attempts > 5)
break;
$attempts--;
continue;
}
$cl = Activity::get_actor_collections($contact['hubloc_hash']);
if(empty($cl)) {
$cl = get_xconfig($contact['hubloc_hash'], 'activitypub', 'collections');
}
if (is_array($cl) && array_key_exists('outbox', $cl)) {
$url = $cl['outbox'];
}
else {
$url = str_replace('/channel/', '/outbox/', $contact['hubloc_id_url']);
if ($url) {
$url .= '?top=1';
}
}
if ($url) {
logger('fetching outbox: ' . $url);
$max = intval(get_config('system', 'max_imported_posts', 30));
if (intval($max)) {
logger('externals: fetching outbox');
$obj = new ASCollection($url, $importer, 0, 10);
$messages = $obj->get();
$feed_url = $url . '/zotfeed';
$obj = new ASCollection($feed_url, $importer, 0, $max);
$messages = $obj->get();
if ($messages) {
foreach ($messages as $message) {
if (is_string($message)) {
$message = Activity::fetch($message, $importer);
}
if ($messages) {
foreach ($messages as $message) {
if (is_string($message)) {
$message = Activity::fetch($message, $importer);
}
$AS = new ActivityStreams($message);
if ($AS->is_valid() && is_array($AS->obj)) {
$item = Activity::decode_note($AS);
Activity::store($importer, $importer['xchan_hash'], $AS, $item, true);
$total++;
if ($message['type'] !== 'Create') {
continue;
}
if ($contact['hubloc_network'] === 'zot6') {
// make sure we only fetch top level items
if (isset($message['object']['inReplyTo'])) {
continue;
}
$obj_id = $message['object']['id'] ?? $message['object'];
Libzot::fetch_conversation($importer, $obj_id);
$total++;
continue;
}
$AS = new ActivityStreams($message);
if ($AS->is_valid() && is_array($AS->obj)) {
$item = Activity::decode_note($AS);
$item['item_fetched'] = true;
Activity::store($importer, $contact['hubloc_hash'], $AS, $item);
$total++;
}
}
logger('externals: import_public_posts: ' . $total . ' messages imported', LOGGER_DEBUG);
}
logger('fetched messages count: ' . $total);
}
}
return;
/* $total = 0;
$attempts = 0;
logger('externals: startup', LOGGER_DEBUG);
// pull in some public posts
while ($total == 0 && $attempts < 3) {
$arr = ['url' => ''];
call_hooks('externals_url_select', $arr);
if ($arr['url']) {
$url = $arr['url'];
}
else {
$randfunc = db_getfunc('RAND');
// fixme this query does not deal with directory realms.
$r = q("select site_url, site_pull from site where site_url != '%s' and site_flags != %d and site_type = %d and site_dead = 0 order by $randfunc limit 1",
dbesc(z_root()),
intval(DIRECTORY_MODE_STANDALONE),
intval(SITE_TYPE_ZOT)
);
if ($r)
$url = $r[0]['site_url'];
}
$blacklisted = false;
if (!check_siteallowed($url)) {
logger('blacklisted site: ' . $url);
$blacklisted = true;
}
$attempts++;
// make sure we can eventually break out if somebody blacklists all known sites
if ($blacklisted) {
if ($attempts > 20)
break;
$attempts--;
continue;
}
if ($url) {
if ($r[0]['site_pull'] > NULL_DATE)
$mindate = urlencode(datetime_convert('', '', $r[0]['site_pull'] . ' - 1 day'));
else {
$days = get_config('externals', 'since_days');
if ($days === false)
$days = 15;
$mindate = urlencode(datetime_convert('', '', 'now - ' . intval($days) . ' days'));
}
$feedurl = $url . '/zotfeed?f=&mindate=' . $mindate;
logger('externals: pulling public content from ' . $feedurl, LOGGER_DEBUG);
$x = z_fetch_url($feedurl);
if (($x) && ($x['success'])) {
q("update site set site_pull = '%s' where site_url = '%s'",
dbesc(datetime_convert()),
dbesc($url)
);
$j = json_decode($x['body'], true);
if ($j['success'] && $j['messages']) {
$sys = get_sys_channel();
foreach ($j['messages'] as $message) {
// on these posts, clear any route info.
$message['route'] = '';
process_delivery(['hash' => 'undefined'], get_item_elements($message),
[['hash' => $sys['xchan_hash']]], false, true);
$total++;
}
logger('externals: import_public_posts: ' . $total . ' messages imported', LOGGER_DEBUG);
}
}
}
}*/
}
}

View File

@@ -0,0 +1,71 @@
<?php
namespace Zotlabs\Daemon;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Lib\PConfig;
require_once('include/cli_startup.php');
require_once('include/attach.php');
require_once('include/import.php');
class File_importer {
static public function run($argc,$argv) {
cli_startup();
$page = $argv[1];
$channel_address = $argv[2];
$hz_server = urldecode($argv[3]);
$m = parse_url($hz_server);
$channel = channelx_by_nick($channel_address);
if(! $channel) {
logger('channel not found');
return;
}
$headers = [
'X-API-Token' => random_string(),
'X-API-Request' => $hz_server . '/api/z/1.0/file/export_page?f=records=1&page=' . $page,
'Host' => $m['host'],
'(request-target)' => 'get /api/z/1.0/file/export_page?f=records=1&page=' . $page,
];
$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 ]);
// logger('file fetch: ' . print_r($x,true));
if(! $x['success']) {
logger('no API response',LOGGER_DEBUG);
killme();
}
$j = json_decode($x['body'],true);
if(! is_array($j['results'][0]['attach']) || ! count($j['results'][0]['attach'])) {
PConfig::Set($channel['channel_id'], 'import', 'files_completed', 1);
return;
}
$r = sync_files($channel, $j['results']);
PConfig::Set($channel['channel_id'], 'import', 'files_progress', [
'files_total' => $j['total'],
'files_page' => 1, // export page atm returns just one file
'last_page' => $page,
'next_cmd' => ['File_importer',sprintf('%d',$page + 1), $channel['channel_address'], urlencode($hz_server)]
]);
$page++;
Master::Summon([ 'File_importer',sprintf('%d',$page), $channel['channel_address'], urlencode($hz_server) ]);
return;
}
}

View File

@@ -15,21 +15,32 @@ class Gprobe {
return;
$url = hex2bin($argv[1]);
$is_webbie = false;
$r = null;
if (!strpos($url, '@'))
return;
if (filter_var($url, FILTER_VALIDATE_EMAIL)) {
$is_webbie = true;
$r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_network = 'zot6' limit 1",
dbesc($url)
);
$r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_network = 'zot6' limit 1",
dbesc($url)
);
}
elseif (filter_var($url, FILTER_VALIDATE_URL)) {
$r = q("select * from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
dbesc($url)
);
}
if (!$r) {
$href = Webfinger::zot_url(punify($url));
if ($href) {
$zf = Zotfinger::exec($href, null);
if ($is_webbie) {
$url = Webfinger::zot_url(punify($url));
}
if (is_array($zf) && array_path_exists('signature/signer', $zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) {
Libzot::import_xchan($zf['data']);
if ($url) {
$zf = Zotfinger::exec($url, null);
if (is_array($zf) && array_path_exists('signature/signer', $zf) && $zf['signature']['signer'] === $url && intval($zf['signature']['header_valid'])) {
Libzot::import_xchan($zf['data']);
}
}
}

View File

@@ -11,6 +11,8 @@ class Importdoc {
self::update_docs_dir('doc/*');
return;
}
static public function update_docs_dir($s) {

View File

@@ -2,6 +2,8 @@
namespace Zotlabs\Daemon;
use Zotlabs\Lib\QueueWorker;
if (array_search(__file__, get_included_files()) === 0) {
require_once('include/cli_startup.php');
array_shift($argv);
@@ -9,6 +11,7 @@ if (array_search(__file__, get_included_files()) === 0) {
if ($argc)
Master::Release($argc, $argv);
return;
}
@@ -16,6 +19,10 @@ if (array_search(__file__, get_included_files()) === 0) {
class Master {
static public function Summon($arr) {
QueueWorker::Summon($arr);
return;
/*
$hookinfo = [
'argv' => $arr
];
@@ -32,11 +39,15 @@ class Master {
$phpbin = get_config('system', 'phpbin', 'php');
proc_run($phpbin, 'Zotlabs/Daemon/Master.php', $arr);
*/
}
static public function Release($argc, $argv) {
cli_startup();
QueueWorker::Release($argv);
return;
/*
$hookinfo = [
'argv' => $argv
];
@@ -54,5 +65,6 @@ class Master {
logger('Master: release: ' . json_encode($argv), LOGGER_ALL, LOG_DEBUG);
$cls = '\\Zotlabs\\Daemon\\' . $argv[0];
$cls::run($argc, $argv);
*/
}
}

View File

@@ -5,6 +5,7 @@ namespace Zotlabs\Daemon;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\Queue;
use Zotlabs\Lib\LDSignatures;
require_once('include/html2plain.php');
require_once('include/conversation.php');
@@ -79,6 +80,7 @@ class Notifier {
static public $channel = null;
static public $private = false;
static public function run($argc, $argv) {
if ($argc < 3) {
@@ -88,14 +90,12 @@ class Notifier {
logger('notifier: invoked: ' . print_r($argv, true), LOGGER_DEBUG);
$cmd = $argv[1];
$item_id = $argv[2];
if (!$item_id) {
return;
}
self::$deliveries = [];
self::$recipients = [];
self::$env_recips = [];
@@ -107,6 +107,12 @@ class Notifier {
$sys = get_sys_channel();
$normal_mode = true;
$upstream = false;
$uplink = false;
$target_item = null;
$parent_item = null;
$top_level_post = false;
$relay_to_owner = false;
if ($cmd === 'keychange') {
self::$channel = channelx_by_n($item_id);
@@ -170,7 +176,7 @@ class Notifier {
elseif ($cmd === 'refresh_all') {
logger('notifier: refresh_all: ' . $item_id);
self::$channel = channelx_by_n($item_id);
self::$channel = channelx_by_n($item_id, true);
$r = q("select abook_xchan from abook where abook_channel = %d",
intval($item_id)
@@ -180,6 +186,11 @@ class Notifier {
self::$recipients[] = $rr['abook_xchan'];
}
}
// In case we deleted the channel, our abook entry has already vanished.
// In order to be able to update our clones we need to add ourself here.
self::$recipients[] = self::$channel['channel_hash'];
self::$private = false;
self::$packet_type = 'refresh';
}
@@ -190,14 +201,14 @@ class Notifier {
return;
}
self::$channel = channelx_by_n($item_id);
self::$channel = channelx_by_n($item_id, true);
self::$recipients = [$xchan];
self::$private = true;
self::$packet_type = 'purge';
}
elseif ($cmd === 'purge_all') {
logger('notifier: purge_all: ' . $item_id);
self::$channel = channelx_by_n($item_id);
self::$channel = channelx_by_n($item_id, true);
self::$recipients = [];
self::$private = false;
self::$packet_type = 'purge';
@@ -230,7 +241,7 @@ class Notifier {
$target_item = $r[0];
if (in_array($target_item['author']['xchan_network'], ['rss', 'anon'])) {
if (in_array($target_item['author']['xchan_network'], ['rss', 'anon', 'token'])) {
logger('notifier: target item author is not a fetchable actor', LOGGER_DEBUG);
return;
}
@@ -326,12 +337,14 @@ class Notifier {
self::$encoded_item = json_decode($m, true);
}
else {
self::$encoded_item = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], Activity::encode_activity($target_item)
);
self::$encoded_item['signature'] = LDSignatures::sign(self::$encoded_item, self::$channel);
}
logger('target_item: ' . print_r($target_item, true), LOGGER_DEBUG);
@@ -347,8 +360,6 @@ class Notifier {
// the hostname in the message_id and provides a second (fallback) opinion.
$relay_to_owner = (!$top_level_post && intval($target_item['item_origin']) && comment_local_origin($target_item));
$uplink = false;
$upstream = false;
// $cmd === 'relay' indicates the owner is sending it to the original recipients
// don't allow the item in the relay command to relay to owner under any circumstances, it will loop
@@ -398,8 +409,6 @@ class Notifier {
self::$private = false;
self::$recipients = collect_recipients($parent_item, self::$private);
// FIXME add any additional recipients such as mentions, etc.
if ($top_level_post) {
// remove clones who will receive the post via sync
self::$recipients = array_values(array_diff(self::$recipients, [$target_item['owner_xchan']]));
@@ -443,7 +452,6 @@ class Notifier {
}
}
$narr = [
'channel' => self::$channel,
'upstream' => $upstream,
@@ -485,7 +493,7 @@ class Notifier {
// Now we have collected recipients (except for external mentions, FIXME)
// Let's reduce this to a set of hubs; checking that the site is not dead.
$hubs = q("select hubloc.*, site.site_crypto, site.site_flags, site.site_dead from hubloc left join site on site_url = hubloc_url
$hubs = dbq("select hubloc.*, site.site_crypto, site.site_flags, site.site_dead from hubloc left join site on site_url = hubloc_url
where hubloc_hash in (" . protect_sprintf(implode(',', self::$recipients)) . ")
and hubloc_error = 0 and hubloc_deleted = 0"
);
@@ -493,6 +501,7 @@ class Notifier {
// public posts won't make it to the local public stream unless there's a recipient on this site.
// This code block sees if it's a public post and localhost is missing, and if so adds an entry for the local sys channel to the $hubs list
/* sys channel is now added in collect recipients
if (!self::$private) {
$found_localhost = false;
if ($hubs) {
@@ -513,6 +522,7 @@ class Notifier {
}
}
}
*/
if (!$hubs) {
logger('notifier: no hubs', LOGGER_NORMAL, LOG_NOTICE);
@@ -526,16 +536,18 @@ class Notifier {
*/
$hublist = []; // this provides an easily printable list for the logs
$dhubs = []; // delivery hubs where we store our resulting unique array
$keys = []; // array of keys to check uniquness for zot hubs
$urls = []; // array of urls to check uniqueness of hubs from other networks
$hub_env = []; // per-hub envelope so we don't broadcast the entire envelope to all
$dead = []; // known dead hubs - report them as undeliverable
$hublist = []; // this provides an easily printable list for the logs
$dhubs = []; // delivery hubs where we store our resulting unique array
$keys = []; // array of keys to check uniquness for zot hubs
$urls = []; // array of urls to check uniqueness of hubs from other networks
$hub_env = []; // per-hub envelope so we don't broadcast the entire envelope to all
$dead_hosts = []; // known dead hubs - report them as undeliverable
foreach ($hubs as $hub) {
if (isset($hub['site_dead']) && intval($hub['site_dead'])) {
$dead[] = $hub;
if(!in_array($hub['hubloc_host'], $dead_hosts)) {
$dead_hosts[] = $hub['hubloc_host'];
}
continue;
}
@@ -545,7 +557,9 @@ class Notifier {
if (!array_key_exists($hub['hubloc_site_id'], $hub_env)) {
$hub_env[$hub['hubloc_site_id']] = [];
}
$hub_env[$hub['hubloc_site_id']][] = $er;
if (!in_array($er, $hub_env[$hub['hubloc_site_id']])) {
$hub_env[$hub['hubloc_site_id']][] = $er;
}
}
}
}
@@ -623,9 +637,22 @@ class Notifier {
// default: zot protocol
// Prevent zot6 delivery of group comment boosts, which are not required for conversational platforms.
// ActivityPub conversational platforms may wish to filter these if they don't want or require them.
// We will assume here that if $target_item exists and has a verb that it is an actual item structure
// so we won't need to check the existence of the other item fields prior to evaluation.
// This shouldn't produce false positives on comment boosts that were generated on other platforms
// because we won't be delivering them.
if (isset($target_item['verb']) && $target_item['verb'] === 'Announce' && $target_item['author_xchan'] === $target_item['owner_xchan'] && ! intval($target_item['item_thread_top'])) {
continue;
}
$hash = new_uuid();
$env = (($hub_env && $hub_env[$hub['hubloc_site_id']]) ? $hub_env[$hub['hubloc_site_id']] : '');
$env = $hub_env[$hub['hubloc_site_id']] ?? '';
if ((self::$private) && (!$env)) {
continue;
}
@@ -662,7 +689,7 @@ class Notifier {
}
if ($normal_mode) {
if ($normal_mode && is_array($target_item)) {
// This wastes a process if there are no delivery hooks configured, so check this before launching the new process
$x = q("select * from hook where hook = 'notifier_normal'");
if ($x) {
@@ -674,21 +701,19 @@ class Notifier {
do_delivery(self::$deliveries);
}
if ($dead) {
foreach ($dead as $deceased) {
if (is_array($target_item) && (!$target_item['item_deleted']) && (!get_config('system', 'disable_dreport'))) {
q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan, dreport_queue )
values ( '%s', '%s','%s','%s','%s','%s','%s','%s' ) ",
dbesc($target_item['mid']),
dbesc($deceased['hubloc_host']),
dbesc($deceased['hubloc_host']),
dbesc($deceased['hubloc_host']),
dbesc('undeliverable/unresponsive site'),
dbesc(datetime_convert()),
dbesc(self::$channel['channel_hash']),
dbesc(new_uuid())
);
}
if ($dead_hosts && is_array($target_item) && (!$target_item['item_deleted']) && (!get_config('system', 'disable_dreport'))) {
foreach ($dead_hosts as $deceased_host) {
$r = q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan, dreport_queue )
values ( '%s', '%s','%s','%s','%s','%s','%s','%s' ) ",
dbesc($target_item['mid']),
dbesc($deceased_host),
dbesc($deceased_host),
dbesc($deceased_host),
dbesc('undeliverable/unresponsive site'),
dbesc(datetime_convert()),
dbesc(self::$channel['channel_hash']),
dbesc(new_uuid())
);
}
}

View File

@@ -15,61 +15,45 @@ class Onedirsync {
$update_id = intval($argv[1]);
if (!$update_id) {
logger('onedirsync: no update');
logger('onedirsync: no update id');
return;
}
$r = q("select * from updates where ud_id = %d limit 1",
$r = q("select * from updates where ud_id = %d",
intval($update_id)
);
if (!$r)
return;
if (($r[0]['ud_flags'] & UPDATE_FLAGS_UPDATED) || (!$r[0]['ud_addr']))
return;
// Have we probed this channel more recently than the other directory server
// (where we received this update from) ?
// If we have, we don't need to do anything except mark any older entries updated
$x = q("select * from updates where ud_addr = '%s' and ud_date > '%s' and ( ud_flags & %d )>0 order by ud_date desc limit 1",
dbesc($r[0]['ud_addr']),
dbesc($r[0]['ud_date']),
intval(UPDATE_FLAGS_UPDATED)
);
if ($x) {
q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 and ud_date != '%s'",
intval(UPDATE_FLAGS_UPDATED),
dbesc($r[0]['ud_addr']),
intval(UPDATE_FLAGS_UPDATED),
dbesc($x[0]['ud_date'])
);
if (!$r) {
logger('onedirsync: update id not found');
return;
}
// ignore doing an update if this ud_addr refers to a known dead hubloc
$h = q("select * from hubloc where hubloc_addr = '%s'",
$h = q("select * from hubloc where hubloc_id_url = '%s' order by hubloc_id desc",
dbesc($r[0]['ud_addr']),
);
$h = Libzot::zot_record_preferred($h);
if (($h) && (($h['hubloc_status'] & HUBLOC_OFFLINE) || $h['hubloc_deleted'] || $h['hubloc_error'])) {
q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 ",
intval(UPDATE_FLAGS_DELETED),
dbesc($r[0]['ud_addr']),
intval(UPDATE_FLAGS_UPDATED)
);
return;
// 2023-04-12: Try to update anyway since the info is not always correct
// This might change after all directory servers run the new code.
// q("update updates set ud_flags = 9 where ud_hash = '%s' and ud_flags != 9",
// dbesc($r[0]['ud_hash'])
//);
// return;
}
// we might have to pull this out some day, but for now update_directory_entry()
// runs zot_finger() and is kind of zot specific
if ($h && $h['hubloc_network'] !== 'zot6')
if ($h && $h['hubloc_network'] !== 'zot6') {
return;
}
Libzotdir::update_directory_entry($r[0]);

View File

@@ -30,14 +30,10 @@ class Onepoll {
$sql_extra = ' and abook_feed = 0 ';
}
$contacts = q("SELECT abook.*, xchan.*, account.*
FROM abook LEFT JOIN account on abook_account = account_id left join xchan on xchan_hash = abook_xchan
where abook_id = %d $sql_extra
and abook_pending = 0 and abook_archived = 0 and abook_blocked = 0 and abook_ignored = 0
AND (( account_flags = %d ) OR ( account_flags = %d )) limit 1",
intval($contact_id),
intval(ACCOUNT_OK),
intval(ACCOUNT_UNVERIFIED)
$contacts = q("SELECT abook.*, xchan.* FROM abook
LEFT JOIN xchan ON xchan_hash = abook_xchan
WHERE abook_id = %d",
intval($contact_id)
);
if (!$contacts) {
@@ -46,18 +42,15 @@ class Onepoll {
}
$contact = $contacts[0];
$importer_uid = $contact['abook_channel'];
$r = q("SELECT * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1",
intval($importer_uid)
);
$importer = channelx_by_n($importer_uid);
if (!$r)
if (!$importer)
return;
$importer = $r[0];
logger("onepoll: poll: ({$contact['id']}) IMPORTER: {$importer['xchan_name']}, CONTACT: {$contact['xchan_name']}");
logger("onepoll: poll: ($contact_id) IMPORTER: {$importer['xchan_name']}, CONTACT: {$contact['xchan_name']}");
$last_update = ((($contact['abook_updated'] === $contact['abook_created']) || ($contact['abook_updated'] <= NULL_DATE))
? datetime_convert('UTC', 'UTC', 'now - 7 days')
@@ -67,12 +60,21 @@ class Onepoll {
if ($contact['xchan_network'] === 'rss') {
logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG);
$alive = handle_feed($importer['channel_id'], $contact_id, $contact['xchan_hash']);
if ($alive) {
q("update abook set abook_connected = '%s' where abook_id = %d",
if (!$alive) {
q("update abook set abook_updated = '%s' where abook_id = %d",
dbesc(datetime_convert()),
intval($contact['abook_id'])
);
return;
}
q("update abook set abook_updated = '%s', abook_connected = '%s' where abook_id = %d",
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($contact['abook_id'])
);
return;
}
@@ -135,22 +137,38 @@ class Onepoll {
$url = $cl['outbox'];
}
else {
$url = str_replace('/poco/', '/zotfeed/', $contact['xchan_connurl']);
$url = str_replace('/poco/', '/outbox/', $contact['xchan_connurl']);
}
if ($url) {
logger('fetching outbox');
$url = $url . '?date_begin=' . urlencode($last_update);
$url = $url . '?date_begin=' . urlencode($last_update);
if($contact['xchan_network'] === 'zot6') {
$url = $url . '&top=1';
}
$obj = new ASCollection($url, $importer, 0, $max);
$messages = $obj->get();
if ($messages) {
foreach ($messages as $message) {
if (is_string($message)) {
$message = Activity::fetch($message, $importer);
}
if ($contact['xchan_network'] === 'zot6') {
// make sure we only fetch top level items
if ($message['type'] === 'Create' && !isset($message['object']['inReplyTo'])) {
Libzot::fetch_conversation($importer, $message['object']['id']);
}
continue;
}
$AS = new ActivityStreams($message);
if ($AS->is_valid() && is_array($AS->obj)) {
$item = Activity::decode_note($AS);
$item['item_fetched'] = true;
Activity::store($importer, $contact['abook_xchan'], $AS, $item);
}
}

View File

@@ -17,21 +17,7 @@ class Poller {
}
}
$interval = intval(get_config('system', 'poll_interval'));
if (!$interval)
$interval = ((get_config('system', 'delivery_interval') === false) ? 3 : intval(get_config('system', 'delivery_interval')));
// Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it.
$lockfile = 'store/[data]/poller';
if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))
&& (!get_config('system', 'override_poll_lockfile'))) {
logger("poller: Already running");
return;
}
// Create a lockfile. Needs two vars, but $x doesn't need to contain anything.
$x = '';
file_put_contents($lockfile, $x);
$interval = get_config('queueworker', 'queue_interval', 500000);
logger('poller: start');
@@ -63,6 +49,11 @@ class Poller {
: ''
);
$allow_feeds = get_config('system', 'feed_contacts');
if(!$allow_feeds) {
$sql_extra .= ' and abook_feed = 0 ';
}
$randfunc = db_getfunc('RAND');
$contacts = q("SELECT abook.abook_updated, abook.abook_connected, abook.abook_feed,
@@ -72,7 +63,7 @@ class Poller {
account.account_lastlog, account.account_flags
FROM abook LEFT JOIN xchan on abook_xchan = xchan_hash
LEFT JOIN account on abook_account = account_id
where abook_self = 0
where abook_self = 0 and abook_pending = 0 and abook_archived = 0 and abook_blocked = 0 and abook_ignored = 0
$sql_extra
AND (( account_flags = %d ) OR ( account_flags = %d )) $abandon_sql ORDER BY $randfunc",
intval(ACCOUNT_OK),
@@ -93,13 +84,24 @@ class Poller {
$min = intval(get_config('system', 'minimum_feedcheck_minutes'));
if (!$min)
$min = 60;
$x = datetime_convert('UTC', 'UTC', "now - $min minutes");
if ($c < $x) {
Master::Summon(['Onepoll', $contact['abook_id']]);
if ($interval)
@time_sleep_until(microtime(true) + (float)$interval);
if ($t !== $c) {
// if the last fetch failed only attempt fetch once a day
$min = 60 * 24;
}
$x = datetime_convert('UTC', 'UTC', "now - $min minutes");
if ($t < $x) {
Master::Summon(['Onepoll', $contact['abook_id']]);
if ($interval) {
usleep($interval);
}
}
continue;
}
if ($contact['xchan_network'] !== 'zot6')
@@ -158,20 +160,22 @@ class Poller {
continue;
Master::Summon(['Onepoll', $contact['abook_id']]);
if ($interval)
@time_sleep_until(microtime(true) + (float)$interval);
if ($interval) {
usleep($interval);
}
}
}
$dirmode = intval(get_config('system', 'directory_mode'));
if ($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) {
$r = q("SELECT u.ud_addr, u.ud_id, u.ud_last FROM updates AS u INNER JOIN (SELECT ud_addr, max(ud_id) AS ud_id FROM updates WHERE ( ud_flags & %d ) = 0 AND ud_addr != '' AND ( ud_last <= '%s' OR ud_last > %s - INTERVAL %s ) GROUP BY ud_addr) AS s ON s.ud_id = u.ud_id ",
intval(UPDATE_FLAGS_UPDATED),
$r = q("SELECT * FROM updates WHERE ud_update = 1 AND (ud_last = '%s' OR ud_last > %s - INTERVAL %s)",
dbesc(NULL_DATE),
db_utcnow(), db_quoteinterval('7 DAY')
db_utcnow(),
db_quoteinterval('7 DAY')
);
if ($r) {
foreach ($r as $rr) {
@@ -181,19 +185,18 @@ class Poller {
if ($rr['ud_last'] > NULL_DATE)
if ($rr['ud_last'] > datetime_convert('UTC', 'UTC', 'now - 1 day'))
continue;
Master::Summon(['Onedirsync', $rr['ud_id']]);
if ($interval)
@time_sleep_until(microtime(true) + (float)$interval);
if ($interval) {
usleep($interval);
}
}
}
}
set_config('system', 'lastpoll', datetime_convert());
//All done - clear the lockfile
@unlink($lockfile);
return;
}
}

View File

@@ -7,77 +7,57 @@ use Zotlabs\Lib\Queue as LibQueue;
class Queue {
static public function run($argc, $argv) {
require_once('include/items.php');
require_once('include/bbcode.php');
if ($argc > 1)
$queue_id = $argv[1];
else
$queue_id = EMPTY_STR;
$queue_id = ($argc > 1) ? $argv[1] : '';
logger('queue: start');
// delete all queue items more than 3 days old
// but first mark these sites dead if we haven't heard from them in a month
$r = q("select outq_posturl from outq where outq_created < %s - INTERVAL %s",
db_utcnow(), db_quoteinterval('3 DAY')
$oldqItems = q("select outq_posturl, outq_hash from outq where outq_created < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval('3 DAY')
);
if ($r) {
foreach ($r as $rr) {
$h = parse_url($rr['outq_posturl']);
$desturl = $h['scheme'] . '://' . $h['host'] . (isset($h['port']) ? ':' . $h['port'] : '');
if ($oldqItems) {
foreach ($oldqItems as $qItem) {
$h = parse_url($qItem['outq_posturl']);
$site_url = $h['scheme'] . '://' . $h['host'] . ((!empty($h['port'])) ? ':' . $h['port'] : '');
q("update site set site_dead = 1 where site_dead = 0 and site_url = '%s' and site_update < %s - INTERVAL %s",
dbesc($desturl),
db_utcnow(), db_quoteinterval('1 MONTH')
dbesc($site_url),
db_utcnow(),
db_quoteinterval('1 MONTH')
);
}
$old_hashes = ids_to_querystr($oldqItems, 'outq_hash', true);
logger('Removing ' . count($oldqItems) . ' old queue entries');
dbq("DELETE FROM outq WHERE outq_hash IN ($old_hashes)");
}
q("DELETE FROM outq WHERE outq_created < %s - INTERVAL %s",
db_utcnow(), db_quoteinterval('3 DAY')
);
$deliveries = [];
if ($queue_id) {
$r = q("SELECT * FROM outq WHERE outq_hash = '%s' LIMIT 1",
$qItems = q("SELECT * FROM outq WHERE outq_hash = '%s' LIMIT 1",
dbesc($queue_id)
);
logger('queue deliver: ' . $qItems[0]['outq_hash'] . ' to ' . $qItems[0]['outq_posturl'], LOGGER_DEBUG);
LibQueue::deliver($qItems[0]);
}
else {
// For the first 12 hours we'll try to deliver every 15 minutes
// After that, we'll only attempt delivery once per hour.
// This currently only handles the default queue drivers ('zot' or '') which we will group by posturl
// so that we don't start off a thousand deliveries for a couple of dead hubs.
// The zot driver will deliver everything destined for a single hub once contact is made (*if* contact is made).
// Other drivers will have to do something different here and may need their own query.
// Note: this requires some tweaking as new posts to long dead hubs once a day will keep them in the
// "every 15 minutes" category. We probably need to prioritise them when inserted into the queue
// or just prior to this query based on recent and long-term delivery history. If we have good reason to believe
// the site is permanently down, there's no reason to attempt delivery at all, or at most not more than once
// or twice a day.
$sqlrandfunc = db_getfunc('rand');
$r = q("SELECT *,$sqlrandfunc as rn FROM outq WHERE outq_delivered = 0 and outq_scheduled < %s order by rn limit 1",
$qItems = q("SELECT outq_hash FROM outq WHERE outq_scheduled < %s ",
db_utcnow()
);
while ($r) {
foreach ($r as $rv) {
LibQueue::deliver($rv);
}
$r = q("SELECT *,$sqlrandfunc as rn FROM outq WHERE outq_delivered = 0 and outq_scheduled < %s order by rn limit 1",
db_utcnow()
);
}
}
if (!$r)
return;
foreach ($r as $rv) {
LibQueue::deliver($rv);
}
if ($qItems) {
foreach ($qItems as $qItem) {
$deliveries[] = $qItem['outq_hash'];
}
do_delivery($deliveries, true);
}
}
}
}

View File

@@ -73,5 +73,7 @@ class Thumbnail {
|| (filectime(dbunescbin($attach['content']) . 'thumb') < (time() - 60)))) {
$default_controller->Thumb($attach, $preview_style, $preview_width, $preview_height);
}
return;
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace Zotlabs\Daemon;
use Zotlabs\Lib\Libzot;
class Zotconvo {
static public function run($argc, $argv) {
logger('Zotconvo invoked: ' . print_r($argv, true));
if ($argc != 3) {
return;
}
$mid = $argv[2];
if (!$mid) {
return;
}
$channel = channelx_by_n(intval($argv[1]));
if (!$channel) {
return;
}
Libzot::fetch_conversation($channel, $mid);
return;
}
}

View File

@@ -24,6 +24,8 @@ class ASCollection {
$this->direction = $direction;
$this->limit = $limit;
$data = null;
if (is_array($obj)) {
$data = $obj;
}
@@ -147,4 +149,4 @@ class ASCollection {
}
logger('nextpage: ' . $this->nextpage, LOGGER_DEBUG);
}
}
}

View File

@@ -6,12 +6,17 @@ namespace Zotlabs\Lib;
class AbConfig {
static public function Load($chan,$xhash,$family = '') {
if($family)
$where = '';
if($family) {
$where = sprintf(" and cat = '%s' ",dbesc($family));
}
$r = q("select * from abconfig where chan = %d and xchan = '%s' $where",
intval($chan),
dbesc($xhash)
);
return $r;
}
@@ -21,7 +26,7 @@ class AbConfig {
intval($chan),
dbesc($xhash),
dbesc($family),
dbesc($key)
dbesc($key)
);
if($r) {
return ((preg_match('|^a:[0-9]+:{.*}$|s', $r[0]['v'])) ? unserialize($r[0]['v']) : $r[0]['v']);
@@ -41,19 +46,19 @@ class AbConfig {
dbesc($xhash),
dbesc($family),
dbesc($key),
dbesc($dbvalue)
dbesc($dbvalue)
);
}
else {
$r = q("update abconfig set v = '%s' where chan = %d and xchan = '%s' and cat = '%s' and k = '%s' ",
dbesc($dbvalue),
dbesc($dbvalue),
dbesc($chan),
dbesc($xhash),
dbesc($family),
dbesc($key)
);
}
if($r)
return $value;
return false;

View File

@@ -1,38 +1,37 @@
<?php
<?php
namespace Zotlabs\Lib;
use Zotlabs\Lib\Libsync;
class AccessList {
static function add($uid,$name,$public = 0) {
$ret = false;
static function add($uid, $name, $public = 0) {
$ret = false;
$hash = '';
if ($uid && $name) {
$r = self::byname($uid,$name); // check for dups
$r = self::by_name($uid, $name); // check for dups
if ($r !== false) {
// This could be a problem.
// This could be a problem.
// Let's assume we've just created a list which we once deleted
// all the old members are gone, but the list remains so we don't break any security
// access lists. What we're doing here is reviving the dead list, but old content which
// was restricted to this list may now be seen by the new list members.
// was restricted to this list may now be seen by the new list members.
$z = q("SELECT * FROM pgrp WHERE id = %d LIMIT 1",
intval($r)
);
if(($z) && $z[0]['deleted']) {
if (($z) && $z[0]['deleted']) {
q('UPDATE pgrp SET deleted = 0 WHERE id = %d', intval($z[0]['id']));
notice( t('A deleted list with this name was revived. Existing item permissions <strong>may</strong> apply to this list and any future members. If this is not what you intended, please create another list with a different name.') . EOL);
notice(t('A deleted privacy group with this name was revived. Existing item permissions <strong>may</strong> apply to this privacy group and any future members. If this is not what you intended, please create another privacy group with a different name.') . EOL);
}
return true;
$hash = self::by_id($uid, $r);
return $hash;
}
$hash = new_uuid();
$r = q("INSERT INTO pgrp ( hash, uid, visible, gname )
$r = q("INSERT INTO pgrp ( hash, uid, visible, gname )
VALUES( '%s', %d, %d, '%s' ) ",
dbesc($hash),
intval($uid),
@@ -42,12 +41,12 @@ class AccessList {
$ret = $r;
}
Libsync::build_sync_packet($uid,null,true);
return $ret;
Libsync::build_sync_packet($uid, null, true);
return (($ret) ? $hash : $ret);
}
static function remove($uid,$name) {
static function remove($uid, $name) {
$ret = false;
if ($uid && $name) {
$r = q("SELECT id, hash FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1",
@@ -55,36 +54,36 @@ class AccessList {
dbesc($name)
);
if ($r) {
$group_id = $r[0]['id'];
$group_id = $r[0]['id'];
$group_hash = $r[0]['hash'];
}
else {
return false;
}
// remove group from default posting lists
$r = q("SELECT channel_default_group, channel_allow_gid, channel_deny_gid FROM channel WHERE channel_id = %d LIMIT 1",
intval($uid)
intval($uid)
);
if ($r) {
$user_info = array_shift($r);
$change = false;
$change = false;
if ($user_info['channel_default_group'] == $group_hash) {
$user_info['channel_default_group'] = '';
$change = true;
$change = true;
}
if (strpos($user_info['channel_allow_gid'], '<' . $group_hash . '>') !== false) {
$user_info['channel_allow_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_allow_gid']);
$change = true;
$change = true;
}
if (strpos($user_info['channel_deny_gid'], '<' . $group_hash . '>') !== false) {
$user_info['channel_deny_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_deny_gid']);
$change = true;
$change = true;
}
if ($change) {
q("UPDATE channel SET channel_default_group = '%s', channel_allow_gid = '%s', channel_deny_gid = '%s'
q("UPDATE channel SET channel_default_group = '%s', channel_allow_gid = '%s', channel_deny_gid = '%s'
WHERE channel_id = %d",
intval($user_info['channel_default_group']),
dbesc($user_info['channel_allow_gid']),
@@ -110,16 +109,16 @@ class AccessList {
}
Libsync::build_sync_packet($uid,null,true);
Libsync::build_sync_packet($uid, null, true);
return $ret;
}
// returns the integer id of an access group owned by $uid and named $name
// or false.
static function byname($uid,$name) {
if (! ($uid && $name)) {
static function by_name($uid, $name) {
if (!($uid && $name)) {
return false;
}
$r = q("SELECT id FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1",
@@ -132,11 +131,11 @@ class AccessList {
return false;
}
static function by_id($uid,$id) {
if (! ($uid && $id)) {
static function by_id($uid, $id) {
if (!($uid && $id)) {
return false;
}
$r = q("SELECT * FROM pgrp WHERE uid = %d AND id = %d and deleted = 0",
intval($uid),
intval($id)
@@ -147,10 +146,8 @@ class AccessList {
return false;
}
static function rec_byhash($uid,$hash) {
if (! ( $uid && $hash)) {
static function by_hash($uid, $hash) {
if (!($uid && $hash)) {
return false;
}
$r = q("SELECT * FROM pgrp WHERE uid = %d AND hash = '%s' LIMIT 1",
@@ -163,46 +160,46 @@ class AccessList {
return false;
}
static function member_remove($uid, $name, $member, $gid = 0) {
if (!$gid) {
$gid = self::by_name($uid, $name);
}
static function member_remove($uid,$name,$member) {
$gid = self::byname($uid,$name);
if (! $gid) {
return false;
}
if (! ($uid && $gid && $member)) {
if (!($uid && $gid && $member)) {
return false;
}
$r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' ",
intval($uid),
intval($gid),
dbesc($member)
);
Libsync::build_sync_packet($uid,null,true);
Libsync::build_sync_packet($uid, null, true);
return $r;
}
static function member_add($uid,$name,$member,$gid = 0) {
if (! $gid) {
$gid = self::byname($uid,$name);
static function member_add($uid, $name, $member, $gid = 0) {
if (!$gid) {
$gid = self::by_name($uid, $name);
}
if (! ($gid && $uid && $member)) {
if (!($gid && $uid && $member)) {
return false;
}
$r = q("SELECT * FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' LIMIT 1",
$r = q("SELECT * FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' LIMIT 1",
intval($uid),
intval($gid),
dbesc($member)
);
if ($r) {
return true; // You might question this, but
// we indicate success because the group member was in fact created
// -- It was just created at another time
return true;
// You might question this, but
// we indicate success because the group member was in fact created
// -- It was just created at another time
}
else {
else {
$r = q("INSERT INTO pgrp_member (uid, gid, xchan)
VALUES( %d, %d, '%s' ) ",
intval($uid),
@@ -210,15 +207,14 @@ class AccessList {
dbesc($member)
);
}
Libsync::build_sync_packet($uid,null,true);
Libsync::build_sync_packet($uid, null, true);
return $r;
}
static function members($uid, $gid) {
$ret = [];
if (intval($gid)) {
$r = q("SELECT * FROM pgrp_member
$r = q("SELECT * FROM pgrp_member
LEFT JOIN abook ON abook_xchan = pgrp_member.xchan left join xchan on xchan_hash = abook_xchan
WHERE gid = %d AND abook_channel = %d and pgrp_member.uid = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 ORDER BY xchan_name ASC ",
intval($gid),
@@ -232,7 +228,7 @@ class AccessList {
return $ret;
}
static function members_xchan($uid,$gid) {
static function members_xchan($uid, $gid) {
$ret = [];
if (intval($gid)) {
$r = q("SELECT xchan FROM pgrp_member WHERE gid = %d AND uid = %d",
@@ -248,99 +244,75 @@ class AccessList {
return $ret;
}
static function members_profile_xchan($uid,$gid) {
static function profile_members_xchan($uid,$gid) {
$ret = [];
if (intval($gid)) {
if(intval($gid)) {
$r = q("SELECT abook_xchan as xchan from abook left join profile on abook_profile = profile_guid where profile.id = %d and profile.uid = %d",
intval($gid),
intval($uid)
);
if ($r) {
foreach($r as $rv) {
$ret[] = $rv['xchan'];
if($r) {
foreach($r as $rr) {
$ret[] = $rr['xchan'];
}
}
}
return $ret;
}
static function select($uid, $options) {
$selected = $options['selected'] ?? '';
$form_id = $options['form_id'] ?? 'accesslist_select';
$label = $options['label'] ?? t('Select a privacy group');
$before = $options['before'] ?? [];
$after = $options['after'] ?? [];
static function select($uid,$group = '') {
$grps = [];
$o = '';
$grps[] = [
'name' => '',
'id' => '0',
'selected' => false
];
if ($before) {
$grps[] = $before;
}
$r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval($uid)
);
$grps[] = [ 'name' => '', 'hash' => '0', 'selected' => '' ];
if ($r) {
foreach ($r as $rr) {
$grps[] = [ 'name' => $rr['gname'], 'id' => $rr['hash'], 'selected' => (($group == $rr['hash']) ? 'true' : '') ];
}
}
return replace_macros(get_markup_template('group_selection.tpl'), [
'$label' => t('Add new connections to this access list'),
'$groups' => $grps
]);
}
static function widget($every="connections",$each="lists",$edit = false, $group_id = 0, $cid = '',$mode = 1) {
$o = '';
$groups = [];
$r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval($_SESSION['uid'])
);
$member_of = [];
if ($cid) {
$member_of = self::containing(local_channel(),$cid);
}
if ($r) {
foreach ($r as $rr) {
$selected = (($group_id == $rr['id']) ? ' group-selected' : '');
if ($edit) {
$groupedit = [ 'href' => "lists/".$rr['id'], 'title' => t('edit') ];
}
else {
$groupedit = null;
}
$groups[] = [
'id' => $rr['id'],
'enc_cid' => base64url_encode($cid),
'cid' => $cid,
'text' => $rr['gname'],
'selected' => $selected,
'href' => (($mode == 0) ? $each.'?f=&gid='.$rr['id'] : $each."/".$rr['id']) . ((x($_GET,'new')) ? '&new=' . $_GET['new'] : '') . ((x($_GET,'order')) ? '&order=' . $_GET['order'] : ''),
'edit' => $groupedit,
'ismember' => in_array($rr['id'],$member_of),
if($r) {
foreach($r as $rr) {
$grps[] = [
'name' => $rr['gname'],
'id' => $rr['hash'],
'selected' => ($selected == $rr['hash'])
];
}
}
return replace_macros(get_markup_template('group_side.tpl'), [
'$title' => t('Lists'),
'$edittext' => t('Edit list'),
'$createtext' => t('Create new list'),
'$ungrouped' => (($every === 'contacts') ? t('Channels not in any access list') : ''),
'$groups' => $groups,
'$add' => t('add'),
]);
if ($after) {
$grps[] = $after;
}
logger('select: ' . print_r($grps,true), LOGGER_DATA);
$o = replace_macros(get_markup_template('group_selection.tpl'), array(
'$label' => $label,
'$form_id' => $form_id,
'$groups' => $grps
));
return $o;
}
static function expand($g) {
if (! (is_array($g) && count($g))) {
if (!(is_array($g) && count($g))) {
return [];
}
@@ -350,8 +322,8 @@ class AccessList {
// private profile linked virtual groups
foreach ($g as $gv) {
if (substr($gv,0,3) === 'vp.') {
$profile_hash = substr($gv,3);
if (substr($gv, 0, 3) === 'vp.') {
$profile_hash = substr($gv, 3);
if ($profile_hash) {
$r = q("select abook_xchan from abook where abook_profile = '%s'",
dbesc($profile_hash)
@@ -366,10 +338,10 @@ class AccessList {
else {
$x[] = $gv;
}
}
}
if ($x) {
stringify_array_elms($x,true);
stringify_array_elms($x, true);
$groups = implode(',', $x);
if ($groups) {
$r = q("SELECT xchan FROM pgrp_member WHERE gid IN ( select id from pgrp where hash in ( $groups ))");
@@ -383,9 +355,8 @@ class AccessList {
return $ret;
}
static function member_of($c) {
$r = q("SELECT pgrp.gname, pgrp.id FROM pgrp LEFT JOIN pgrp_member ON pgrp_member.gid = pgrp.id
$r = q("SELECT pgrp.gname, pgrp.id FROM pgrp LEFT JOIN pgrp_member ON pgrp_member.gid = pgrp.id
WHERE pgrp_member.xchan = '%s' AND pgrp.deleted = 0 ORDER BY pgrp.gname ASC ",
dbesc($c)
);
@@ -393,7 +364,7 @@ class AccessList {
return $r;
}
static function containing($uid,$c) {
static function containing($uid, $c) {
$r = q("SELECT gid FROM pgrp_member WHERE uid = %d AND pgrp_member.xchan = '%s' ",
intval($uid),
@@ -405,7 +376,8 @@ class AccessList {
foreach ($r as $rv)
$ret[] = $rv['gid'];
}
return $ret;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,7 @@ class ActivityStreams {
public $raw = null;
public $data = null;
public $meta = null;
public $valid = false;
public $deleted = false;
public $id = '';
@@ -36,10 +37,14 @@ class ActivityStreams {
*/
function __construct($string) {
if(!$string)
return;
$this->raw = $string;
if (is_array($string)) {
$this->data = $string;
$this->raw = json_encode($string, JSON_UNESCAPED_SLASHES);
}
else {
$this->data = json_decode($string, true);
@@ -56,18 +61,21 @@ class ActivityStreams {
if ($ret['signer']) {
$saved = json_encode($this->data, JSON_UNESCAPED_SLASHES);
$this->data = $tmp;
$this->data['signer'] = $ret['signer'];
$this->data['signed_data'] = $saved;
$this->meta['signer'] = $ret['signer'];
$this->meta['signed_data'] = $saved;
if ($ret['hubloc']) {
$this->data['hubloc'] = $ret['hubloc'];
$this->meta['hubloc'] = $ret['hubloc'];
}
}
}
}
// This indicates only that we have sucessfully decoded JSON.
$this->valid = true;
if (array_key_exists('type', $this->data) && array_key_exists('actor', $this->data) && array_key_exists('object', $this->data)) {
// Special handling for Mastodon "delete actor" activities which will often fail to verify
// because the key cannot be fetched. We will catch this condition elsewhere.
if (is_array($this->data) && array_key_exists('type', $this->data) && array_key_exists('actor', $this->data) && array_key_exists('object', $this->data)) {
if ($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) {
$this->deleted = $this->data['actor'];
$this->valid = false;
@@ -76,6 +84,7 @@ class ActivityStreams {
}
// Attempt to assemble an Activity from what we were given.
if ($this->is_valid()) {
$this->id = $this->get_property_obj('id');
$this->type = $this->get_primary_type();
@@ -87,7 +96,7 @@ class ActivityStreams {
$this->ldsig = $this->get_compound_property('signature');
if ($this->ldsig) {
$this->signer = $this->get_compound_property('creator', $this->ldsig);
$this->signer = $this->get_actor('creator', $this->ldsig);
if ($this->signer && is_array($this->signer) && array_key_exists('publicKey', $this->signer) && is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) {
$this->sigok = LDSignatures::verify($this->data, $this->signer['publicKey']['publicKeyPem']);
}
@@ -104,20 +113,21 @@ class ActivityStreams {
// fetch recursive or embedded activities
if ($this->obj && is_array($this->obj) && array_key_exists('object', $this->obj)) {
$this->obj['object'] = $this->get_compound_property($this->obj['object']);
$this->obj['object'] = $this->get_compound_property('object', $this->obj);
}
if ($this->obj && is_array($this->obj) && $this->obj['actor'])
if ($this->obj && is_array($this->obj) && isset($this->obj['actor']))
$this->obj['actor'] = $this->get_actor('actor', $this->obj);
if ($this->tgt && is_array($this->tgt) && $this->tgt['actor'])
if ($this->tgt && is_array($this->tgt) && isset($this->tgt['actor']))
$this->tgt['actor'] = $this->get_actor('actor', $this->tgt);
$this->parent_id = $this->get_property_obj('inReplyTo');
if ((!$this->parent_id) && is_array($this->obj)) {
if ((!$this->parent_id) && is_array($this->obj) && isset($this->obj['inReplyTo'])) {
$this->parent_id = $this->obj['inReplyTo'];
}
if ((!$this->parent_id) && is_array($this->obj)) {
if ((!$this->parent_id) && is_array($this->obj) && isset($this->obj['id'])) {
$this->parent_id = $this->obj['id'];
}
}
@@ -136,36 +146,59 @@ class ActivityStreams {
$this->saved_recips = $arr;
}
/**
* @brief get single property from Activity object
*
* @param string $property
* @param mixed $default return value if property or object not set
* or object is a string id which could not be fetched.
* @return mixed
*/
public function objprop(string $property, mixed $default = false): mixed {
$x = $this->get_property_obj($property, $this->obj);
return (isset($x)) ? $x : $default;
}
/**
* @brief Collects all recipients.
*
* @param string $base
* @param mixed $base
* @param string $namespace (optional) default empty
* @return array
*/
function collect_recips($base = '', $namespace = '') {
$x = [];
public function collect_recips(mixed $base = '', string $namespace = ''): array {
$result = [];
$tmp = [];
$fields = ['to', 'cc', 'bto', 'bcc', 'audience'];
foreach ($fields as $f) {
$y = $this->get_compound_property($f, $base, $namespace);
if ($y) {
if (!is_array($this->raw_recips)) {
$this->raw_recips = [];
}
if (!is_array($y)) {
$y = [$y];
}
$this->raw_recips[$f] = $y;
$x = array_merge($x, $y);
foreach ($fields as $field) {
// don't expand these yet
$values = $this->get_property_obj($field, $base, $namespace);
if ($values) {
$values = force_array($values);
$tmp[$field] = $values;
$result = array_values(array_unique(array_merge($result, $values)));
}
// Merge the object recipients if they exist.
$values = $this->objprop($field);
if ($values) {
$values = force_array($values);
$tmp[$field] = ((isset($tmp[$field])) ? array_merge($tmp[$field], $values) : $values);
$result = array_values(array_unique(array_merge($result, $values)));
}
// remove duplicates
if (isset($tmp[$field])) {
$tmp[$field] = array_values(array_unique($tmp[$field]));
}
}
// not yet ready for prime time
// $x = $this->expand($x,$base,$namespace);
return $x;
$this->raw_recips = $tmp;
// not yet ready for prime time
// $result = $this->expand($result,$base,$namespace);
return $result;
}
function expand($arr, $base = '', $namespace = '') {
$ret = [];
@@ -299,20 +332,25 @@ class ActivityStreams {
function get_actor($property, $base = '', $namespace = '') {
$x = $this->get_property_obj($property, $base, $namespace);
if ($this->is_url($x)) {
$y = Activity::get_cached_actor($x);
if ($y) {
return $y;
}
}
$actor = $this->get_compound_property($property, $base, $namespace, true);
if (is_array($actor) && self::is_an_actor($actor['type'])) {
if (array_key_exists('id', $actor) && (!array_key_exists('inbox', $actor))) {
$actor = $this->fetch_property($actor['id']);
}
return $actor;
}
return null;
return Activity::get_unknown_actor($this->data);
}
@@ -327,6 +365,7 @@ class ActivityStreams {
*/
function get_compound_property($property, $base = '', $namespace = '', $first = false) {
$x = $this->get_property_obj($property, $base, $namespace);
if ($this->is_url($x)) {
$y = $this->fetch_property($x);
if (is_array($y)) {
@@ -343,10 +382,10 @@ class ActivityStreams {
if ($ret['signer']) {
$saved = json_encode($x, JSON_UNESCAPED_SLASHES);
$x = $tmp;
$x['signer'] = $ret['signer'];
$x['signed_data'] = $saved;
$x['meta']['signer'] = $ret['signer'];
$x['meta']['signed_data'] = $saved;
if ($ret['hubloc']) {
$x['hubloc'] = $ret['hubloc'];
$x['meta']['hubloc'] = $ret['hubloc'];
}
}
}
@@ -417,15 +456,19 @@ class ActivityStreams {
static function get_accept_header_string($channel = null) {
$ret = '';
$hookdata = [];
if ($channel)
$hookdata['channel'] = $channel;
$hookdata['data'] = 'application/x-zot-activity+json';
$hookdata['data'] = ['application/x-zot-activity+json'];
call_hooks('get_accept_header_string', $hookdata);
return $hookdata['data'];
$ret = implode(', ', $hookdata['data']);
return $ret;
}

View File

@@ -3,7 +3,6 @@
namespace Zotlabs\Lib;
use App;
use Zotlabs\Lib\Libsync;
require_once('include/plugin.php');
require_once('include/channel.php');
@@ -22,9 +21,10 @@ class Apps {
* @brief
*
* @param boolean $translate (optional) default true
* @param boolean $sync (optional) default false used if called from sync_sysapps()
* @return array
*/
static public function get_system_apps($translate = true) {
static public function get_system_apps($translate = true, $sync = false) {
$ret = [];
if(is_dir('apps'))
@@ -34,7 +34,7 @@ class Apps {
if($files) {
foreach($files as $f) {
$x = self::parse_app_description($f,$translate);
$x = self::parse_app_description($f, $translate, $sync);
if($x) {
$ret[] = $x;
}
@@ -46,7 +46,7 @@ class Apps {
$path = explode('/',$f);
$plugin = trim($path[1]);
if(plugin_is_installed($plugin)) {
$x = self::parse_app_description($f,$translate);
$x = self::parse_app_description($f, $translate, $sync);
if($x) {
$x['plugin'] = $plugin;
$ret[] = $x;
@@ -67,17 +67,15 @@ class Apps {
static public function get_base_apps() {
$x = get_config('system','base_apps',[
'Connections',
'Contact Roles',
'Network',
'Settings',
'Files',
'Channel Home',
'View Profile',
'Channel',
'Photos',
'Calendar',
'Directory',
'Search',
'Help',
'Profile Photo',
'HQ',
'Post'
]);
@@ -161,7 +159,7 @@ class Apps {
foreach(self::$available_apps as $iapp) {
if($iapp['app_id'] == hash('whirlpool',$app['name'])) {
$notfound = false;
if(($iapp['app_version'] !== $app['version'])
if((isset($app['version']) && $iapp['app_version'] !== $app['version'])
|| ($app['plugin'] && (! $iapp['app_plugin']))) {
return intval($iapp['app_id']);
}
@@ -210,9 +208,10 @@ class Apps {
*
* @param string $f filename
* @param boolean $translate (optional) default true
* @param boolean $sync (optional) default false
* @return boolean|array
*/
static public function parse_app_description($f, $translate = true) {
static public function parse_app_description($f, $translate = true, $sync = false) {
$ret = [];
$matches = [];
@@ -237,6 +236,7 @@ class Apps {
$ret['photo'] = $baseurl . '/' . get_default_profile_photo(80);
$ret['type'] = 'system';
$ret['plugin'] = '';
foreach($ret as $k => $v) {
if(strpos($v,'http') === 0) {
@@ -258,7 +258,7 @@ class Apps {
if(array_key_exists('categories',$ret))
$ret['categories'] = str_replace(array('\'','"'),array('&#39;','&dquot;'),$ret['categories']);
if(array_key_exists('requires',$ret)) {
if(array_key_exists('requires',$ret) && !$sync) {
$requires = explode(',',$ret['requires']);
foreach($requires as $require) {
$require = trim(strtolower($require));
@@ -310,14 +310,16 @@ class Apps {
}
}
}
if(isset($ret)) {
if($translate)
self::translate_system_apps($ret);
return $ret;
if(empty($ret)) {
return false;
}
return false;
if($translate) {
self::translate_system_apps($ret);
}
return $ret;
}
@@ -343,7 +345,7 @@ class Apps {
'Files' => t('Files'),
'Webpages' => t('Webpages'),
'Wiki' => t('Wiki'),
'Channel Home' => t('Channel Home'),
'Channel' => t('Channel'),
'View Profile' => t('View Profile'),
'Photos' => t('Photos'),
'Calendar' => t('Calendar'),
@@ -374,10 +376,10 @@ class Apps {
'OAuth Apps Manager' => t('OAuth Apps Manager'),
'OAuth2 Apps Manager' => t('OAuth2 Apps Manager'),
'PDL Editor' => t('PDL Editor'),
'Permission Categories' => t('Permission Categories'),
'Contact Roles' => t('Contact Roles'),
'Public Stream' => t('Public Stream'),
'My Chatrooms' => t('My Chatrooms'),
'Channel Export' => t('Channel Export'),
'Channel Export' => t('Channel Export')
);
if(array_key_exists('name',$arr)) {
@@ -425,7 +427,7 @@ class Apps {
self::translate_system_apps($papp);
if(trim($papp['plugin']) && (! plugin_is_installed(trim($papp['plugin']))))
if(isset($papp['plugin']) && trim($papp['plugin']) && (! plugin_is_installed(trim($papp['plugin']))))
return '';
$papp['papp'] = self::papp_encode($papp);
@@ -520,8 +522,13 @@ class Apps {
$hosturl = '';
if(local_channel()) {
if(self::app_installed(local_channel(),$papp) && !$papp['deleted'])
if(self::app_installed(local_channel(),$papp)) {
$installed = true;
}
if ($installed && isset($papp['deleted']) && $papp['deleted']) {
$installed = false;
}
$hosturl = z_root() . '/';
}
@@ -594,12 +601,12 @@ class Apps {
'$edit' => ((local_channel() && $installed && $mode == 'edit') ? t('Edit') : ''),
'$delete' => ((local_channel() && $mode == 'edit') ? t('Delete') : ''),
'$undelete' => ((local_channel() && $mode == 'edit') ? t('Undelete') : ''),
'$settings_url' => ((local_channel() && $installed && $mode == 'list') ? $papp['settings_url'] : ''),
'$deleted' => $papp['deleted'],
'$settings_url' => ((local_channel() && $installed && $mode == 'list' && isset($papp['settings_url'])) ? $papp['settings_url'] : ''),
'$deleted' => $papp['deleted'] ?? false,
'$feature' => ((isset($papp['embed']) || $mode == 'edit') ? false : true),
'$pin' => ((isset($papp['embed']) || $mode == 'edit') ? false : true),
'$featured' => ((strpos($papp['categories'], 'nav_featured_app') === false) ? false : true),
'$pinned' => ((strpos($papp['categories'], 'nav_pinned_app') === false) ? false : true),
'$featured' => ((isset($papp['categories']) && strpos($papp['categories'], 'nav_featured_app') !== false) ? true : false),
'$pinned' => ((isset($papp['categories']) && strpos($papp['categories'], 'nav_pinned_app') !== false) ? true : false),
'$mode' => $mode,
'$add' => t('Add to app-tray'),
'$remove' => t('Remove from app-tray'),
@@ -624,10 +631,12 @@ class Apps {
$app['uid'] = $uid;
if(self::app_installed($uid,$app,true))
if(self::app_installed($uid,$app,true)) {
$x = self::app_update($app);
else
}
else {
$x = self::app_store($app);
}
if($x['success']) {
$r = q("select * from app where app_id = '%s' and app_channel = %d limit 1",
@@ -635,13 +644,12 @@ class Apps {
intval($uid)
);
if($r) {
if(($app['uid']) && (! $r[0]['app_system'])) {
if($app['categories'] && (! $app['term'])) {
if($app['uid']) {
if((isset($app['categories']) && $app['categories']) && !(isset($app['term']) && $app['term'])) {
$r[0]['term'] = q("select * from term where otype = %d and oid = %d",
intval(TERM_OBJ_APP),
intval($r[0]['id'])
);
Libsync::build_sync_packet($uid,array('app' => $r[0]));
}
}
}
@@ -670,6 +678,7 @@ class Apps {
}
}
}
return true;
}
@@ -681,38 +690,35 @@ class Apps {
dbesc($app['guid']),
intval($uid)
);
if($x) {
if(! intval($x[0]['app_deleted'])) {
$x[0]['app_deleted'] = 1;
if(self::can_delete($uid,$app)) {
q("delete from app where app_id = '%s' and app_channel = %d",
dbesc($app['guid']),
intval($uid)
);
q("delete from term where otype = %d and oid = %d",
intval(TERM_OBJ_APP),
intval($x[0]['id'])
);
/**
* @hooks app_destroy
* Called after app entry got removed from database
* and provide app array from database.
*/
call_hooks('app_destroy', $x[0]);
}
else {
q("update app set app_deleted = 1 where app_id = '%s' and app_channel = %d",
dbesc($app['guid']),
intval($uid)
);
}
if(! intval($x[0]['app_system'])) {
Libsync::build_sync_packet($uid,array('app' => $x));
}
}
else {
self::app_undestroy($uid,$app);
}
if($x && intval($x[0]['app_deleted'])) {
self::app_undestroy($uid, $app);
return;
}
if(self::can_delete($uid,$app)) {
q("delete from app where app_id = '%s' and app_channel = %d",
dbesc($app['guid']),
intval($uid)
);
q("delete from term where otype = %d and oid = %d",
intval(TERM_OBJ_APP),
intval($x[0]['id'])
);
/**
* @hooks app_destroy
* Called after app entry got removed from database
* and provide app array from database.
*/
call_hooks('app_destroy', $x[0]);
}
else {
q("update app set app_deleted = 1 where app_id = '%s' and app_channel = %d",
dbesc($app['guid']),
intval($uid)
);
}
}
}
@@ -729,13 +735,11 @@ class Apps {
dbesc($app['guid']),
intval($uid)
);
if($x) {
if($x[0]['app_system']) {
q("update app set app_deleted = 0 where app_id = '%s' and app_channel = %d",
dbesc($app['guid']),
intval($uid)
);
}
if($x && intval($x[0]['app_deleted']) && $x[0]['app_system']) {
q("update app set app_deleted = 0 where app_id = '%s' and app_channel = %d",
dbesc($app['guid']),
intval($uid)
);
}
}
}
@@ -1186,7 +1190,7 @@ class Apps {
$ret['success'] = true;
$ret['app_id'] = $darray['app_id'];
}
if($arr['categories']) {
if(isset($arr['categories']) && $arr['categories']) {
$x = q("select id from app where app_id = '%s' and app_channel = %d limit 1",
dbesc($darray['app_id']),
intval($darray['app_channel'])
@@ -1194,9 +1198,9 @@ class Apps {
$y = explode(',',$arr['categories']);
if($y) {
foreach($y as $t) {
$t = trim($t);
$t = escape_tags(trim($t));
if($t) {
store_item_tag($darray['app_channel'],$x[0]['id'],TERM_OBJ_APP,TERM_CATEGORY,escape_tags($t),escape_tags(z_root() . '/apps/?f=&cat=' . escape_tags($t)));
store_item_tag($darray['app_channel'], $x[0]['id'], TERM_OBJ_APP, TERM_CATEGORY, $t, z_root() . '/apps/?f=&cat=' . $t);
}
}
}
@@ -1284,7 +1288,7 @@ class Apps {
intval(TERM_OBJ_APP),
intval($x[0]['id'])
);
if($arr['categories']) {
if(isset($arr['categories']) && $arr['categories']) {
$y = explode(',',$arr['categories']);
if($y) {
foreach($y as $t) {

View File

@@ -69,7 +69,8 @@ class Connect {
$xchan_hash = '';
$sql_options = (($protocol) ? " and xchan_network = '" . dbesc($protocol) . "' " : '');
$r = q("select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s') $sql_options ",
// We need both, the xchan and the hubloc here hence use JOIN instead of LEFT JOIN
$r = q("SELECT * FROM xchan JOIN hubloc ON xchan_hash = hubloc_hash WHERE ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s') $sql_options ORDER BY hubloc_id DESC",
dbesc($url),
dbesc($url),
dbesc($url)
@@ -80,12 +81,13 @@ class Connect {
// reset results to the best record or the first if we don't have the best
// note: this is a single record and not an array of results
$r = Libzot::zot_record_preferred($r,'xchan_network');
$r = Libzot::zot_record_preferred($r, 'xchan_network');
}
$singleton = false;
$d = false;
$wf = false;
if (! $r) {
@@ -108,10 +110,12 @@ class Connect {
if ($wf || $d) {
$xchan_hash = (($wf) ? $wf : $url);
// something was discovered - find the record which was just created.
$r = q("select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s' ) $sql_options",
dbesc(($wf) ? $wf : $url),
dbesc($xchan_hash),
dbesc($url),
dbesc($url)
);
@@ -119,7 +123,7 @@ class Connect {
// convert to a single record (once again preferring a zot solution in the case of multiples)
if ($r) {
$r = Libzot::zot_record_preferred($r,'xchan_network');
$r = Libzot::zot_record_preferred($r, 'xchan_network');
}
}
@@ -261,7 +265,8 @@ class Connect {
'abook_feed' => intval(($xchan['xchan_network'] === 'rss') ? 1 : 0),
'abook_created' => datetime_convert(),
'abook_updated' => datetime_convert(),
'abook_instance' => (($singleton) ? z_root() : '')
'abook_instance' => (($singleton) ? z_root() : ''),
'abook_role' => get_pconfig($uid, 'system', 'default_permcat', 'default')
]
);
}
@@ -300,7 +305,7 @@ class Connect {
/** If there is a default group for this channel, add this connection to it */
if ($default_group) {
$g = AccessList::rec_byhash($uid,$default_group);
$g = AccessList::by_hash($uid,$default_group);
if ($g) {
AccessList::member_add($uid,'',$xchan_hash,$g['id']);
}

View File

@@ -87,6 +87,10 @@ class Crypto {
return false;
}
if (!$alg) {
$alg = 'sha256';
}
try {
$verify = openssl_verify($data, $sig, $key, $alg);
} catch (Exception $e) {

View File

@@ -94,19 +94,6 @@ class DReport {
if(! $c)
return false;
// legacy zot recipients add a space and their name to the xchan. remove it if true.
$legacy_recipient = strpos($dr['recipient'], ' ');
if($legacy_recipient !== false) {
$legacy_recipient_parts = explode(' ', $dr['recipient'], 2);
$rxchan = $legacy_recipient_parts[0];
}
else {
$rxchan = $dr['recipient'];
}
// is the recipient one of our connections, or do we want to store every report?
$pcf = get_pconfig($c[0]['channel_id'],'system','dreport_store_all');
@@ -117,7 +104,7 @@ class DReport {
// So if a remote site says they can't find us, that's no big surprise
// and just creates a lot of extra report noise
if(($dr['location'] !== z_root()) && ($dr['sender'] === $rxchan) && ($dr['status'] === 'recipient not found'))
if(($dr['location'] !== z_root()) && ($dr['sender'] === $dr['recipient']) && ($dr['status'] === 'recipient not found'))
return false;
// If you have a private post with a recipient list, every single site is going to report
@@ -126,14 +113,14 @@ class DReport {
// have a channel on that site.
$r = q("select hubloc_id from hubloc where hubloc_hash = '%s' and hubloc_url = '%s'",
dbesc($rxchan),
dbesc($dr['recipient']),
dbesc($dr['location'])
);
if((! $r) && ($dr['status'] === 'recipient_not_found'))
return false;
$r = q("select abook_id from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc($rxchan),
dbesc($dr['recipient']),
intval($c[0]['channel_id'])
);
if($r)

View File

@@ -122,12 +122,15 @@ class Enotify {
// e.g. "your post", "David's photo", etc.
$possess_desc = t('%s <!item_type!>');
$parent_mid = '';
$parent_item = [];
// @@TODO: consider using switch instead of those elseif
if ($params['type'] == NOTIFY_MAIL) {
if (isset($params['type']) && $params['type'] == NOTIFY_MAIL) {
logger('notification: mail');
$subject = sprintf( t('[$Projectname:Notify] New direct message received at %s'), $sitename);
$preamble = sprintf( t('%1$s sent you a new direct message at %2$s.'), $sender['xchan_name'], $sitename);
$preamble = sprintf( t('%1$s sent you a new direct message at %2$s'), $sender['xchan_name'], $sitename);
$epreamble = sprintf( t('%1$s sent you %2$s.'), '[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]', '[zrl=$itemlink]' . t('a direct message') . '[/zrl]');
$sitelink = t('Please visit %s to view and/or reply to your direct messages.');
$tsitelink = sprintf( $sitelink, $siteurl . '/hq/' . gen_link_id($params['item']['mid']));
@@ -135,7 +138,7 @@ class Enotify {
$itemlink = $siteurl . '/hq/' . gen_link_id($params['item']['mid']);
}
elseif ($params['type'] === NOTIFY_COMMENT) {
elseif (isset($params['type']) && $params['type'] === NOTIFY_COMMENT) {
//logger("notification: params = " . print_r($params, true), LOGGER_DEBUG);
$moderated = (($params['item']['item_blocked'] == ITEM_MODERATED) ? true : false);
@@ -167,7 +170,7 @@ class Enotify {
}
$parent_mid = $params['parent_mid'];
$parent_mid = $params['parent_mid'] ?? '';
// Check to see if there was already a notify for this post.
// If so don't create a second notification
@@ -238,7 +241,7 @@ class Enotify {
$subject = sprintf( t('[$Projectname:Notify] Moderated Comment to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']);
else
$subject = sprintf( t('[$Projectname:Notify] Comment to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']);
$preamble = sprintf( t('%1$s commented on an item/conversation you have been following.'), $sender['xchan_name']);
$preamble = sprintf( t('%1$s commented on an item/conversation you have been following'), $sender['xchan_name']);
$epreamble = $dest_str;
$sitelink = t('Please visit %s to view and/or reply to the conversation.');
@@ -251,20 +254,20 @@ class Enotify {
}
elseif ($params['type'] === NOTIFY_LIKE) {
elseif (isset($params['type']) && $params['type'] === NOTIFY_LIKE) {
// logger("notification: params = " . print_r($params, true), LOGGER_DEBUG);
$itemlink = $params['link'];
if (array_key_exists('item',$params) && (! activity_match($params['item']['verb'],ACTIVITY_LIKE))) {
if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE)) {
if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ACTIVITY_LIKE) || activity_match($params['item']['verb'], ACTIVITY_DISLIKE))) {
if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE) || !feature_enabled($recip['channel_id'], 'dislike')) {
logger('notification: not a visible activity. Ignoring.');
pop_lang();
return;
}
}
$parent_mid = $params['parent_mid'];
$parent_mid = $params['parent_mid'] ?? '';
// Check to see if there was already a notify for this post.
// If so don't create a second notification
@@ -291,22 +294,29 @@ class Enotify {
);
}
if (!$p) {
pop_lang();
return;
}
xchan_query($p);
//@@FIXME $p can be null (line 285)
$item_post_type = item_post_type($p[0]);
// $private = $p[0]['item_private'];
$parent_id = $p[0]['id'];
$parent_item = $p[0];
$verb = ((activity_match($params['item']['verb'], ACTIVITY_DISLIKE)) ? t('disliked') : t('liked'));
// "your post"
if($p[0]['owner']['xchan_name'] === $p[0]['author']['xchan_name'] && intval($p[0]['item_wall']))
$dest_str = sprintf(t('%1$s liked [zrl=%2$s]your %3$s[/zrl]'),
$dest_str = sprintf(t('%1$s %2$s [zrl=%3$s]your %4$s[/zrl]'),
'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]',
$verb,
$itemlink,
$item_post_type);
$item_post_type
);
else {
pop_lang();
return;
@@ -318,7 +328,7 @@ class Enotify {
// differents subjects for messages on the same thread.
$subject = sprintf( t('[$Projectname:Notify] Like received to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']);
$preamble = sprintf( t('%1$s liked an item/conversation you created.'), $sender['xchan_name']);
$preamble = sprintf( t('%1$s liked an item/conversation you created'), $sender['xchan_name']);
$epreamble = $dest_str;
$sitelink = t('Please visit %s to view and/or reply to the conversation.');
@@ -328,7 +338,7 @@ class Enotify {
elseif($params['type'] === NOTIFY_WALL) {
elseif(isset($params['type']) && $params['type'] === NOTIFY_WALL) {
$subject = sprintf( t('[$Projectname:Notify] %s posted to your profile wall') , $sender['xchan_name']);
$preamble = sprintf( t('%1$s posted to your profile wall at %2$s') , $sender['xchan_name'], $sitename);
@@ -343,7 +353,7 @@ class Enotify {
$itemlink = $params['link'];
}
elseif ($params['type'] === NOTIFY_TAGSELF) {
elseif (isset($params['type']) && $params['type'] === NOTIFY_TAGSELF) {
$p = q("select id from notify where link = '%s' and uid = %d limit 1",
dbesc($params['link']),
@@ -367,7 +377,7 @@ class Enotify {
$itemlink = $params['link'];
}
elseif ($params['type'] === NOTIFY_POKE) {
elseif (isset($params['type']) && $params['type'] === NOTIFY_POKE) {
$subject = sprintf( t('[$Projectname:Notify] %1$s poked you') , $sender['xchan_name']);
$preamble = sprintf( t('%1$s poked you at %2$s') , $sender['xchan_name'], $sitename);
$epreamble = sprintf( t('%1$s [zrl=%2$s]poked you[/zrl].') ,
@@ -384,7 +394,7 @@ class Enotify {
$itemlink = $params['link'];
}
elseif ($params['type'] === NOTIFY_TAGSHARE) {
elseif (isset($params['type']) && $params['type'] === NOTIFY_TAGSHARE) {
$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]') ,
@@ -397,7 +407,7 @@ class Enotify {
$itemlink = $params['link'];
}
elseif ($params['type'] === NOTIFY_INTRO) {
elseif (isset($params['type']) && $params['type'] === NOTIFY_INTRO) {
$subject = sprintf( t('[$Projectname:Notify] Introduction received'));
$preamble = sprintf( t('You\'ve received an new connection request from \'%1$s\' at %2$s'), $sender['xchan_name'], $sitename);
$epreamble = sprintf( t('You\'ve received [zrl=%1$s]a new connection request[/zrl] from %2$s.'),
@@ -411,7 +421,7 @@ class Enotify {
$itemlink = $params['link'];
}
elseif ($params['type'] === NOTIFY_SUGGEST) {
elseif (isset($params['type']) && $params['type'] === NOTIFY_SUGGEST) {
$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.'),
@@ -429,11 +439,11 @@ class Enotify {
$itemlink = $params['link'];
}
elseif ($params['type'] === NOTIFY_CONFIRM) {
elseif (isset($params['type']) && $params['type'] === NOTIFY_CONFIRM) {
// ?
}
elseif ($params['type'] === NOTIFY_SYSTEM) {
elseif (isset($params['type']) && $params['type'] === NOTIFY_SYSTEM) {
// ?
}
@@ -488,12 +498,13 @@ class Enotify {
$datarray['link'] = $itemlink;
$datarray['parent'] = $parent_mid;
$datarray['parent_item'] = $parent_item;
$datarray['ntype'] = $params['type'];
$datarray['verb'] = $params['verb'];
$datarray['otype'] = $params['otype'];
$datarray['ntype'] = $params['type'] ?? '';
$datarray['verb'] = $params['verb'] ?? '';
$datarray['otype'] = $params['otype'] ?? '';
$datarray['abort'] = false;
$datarray['seen'] = 0;
$datarray['item'] = $params['item'];
$datarray['item'] = $params['item'] ?? [];
call_hooks('enotify_store', $datarray);
@@ -504,7 +515,6 @@ class Enotify {
// create notification entry in DB
$seen = 0;
// Mark some notifications as seen right away
// Note! The notification have to be created, because they are used to send emails
@@ -514,7 +524,7 @@ class Enotify {
if (!$always_show_in_notices) {
if (($params['type'] === NOTIFY_WALL) || ($params['type'] === NOTIFY_MAIL) || ($params['type'] === NOTIFY_INTRO)) {
$seen = 1;
$datarray['seen'] = 1;
}
}
@@ -530,7 +540,7 @@ class Enotify {
intval($datarray['uid']),
dbesc($datarray['link']),
dbesc($datarray['parent']),
intval($seen),
intval($datarray['seen']),
intval($datarray['ntype']),
dbesc($datarray['verb']),
dbesc($datarray['otype'])
@@ -606,8 +616,8 @@ class Enotify {
$datarray['preamble'] = $preamble;
$datarray['sitename'] = $sitename;
$datarray['siteurl'] = $siteurl;
$datarray['type'] = $params['type'];
$datarray['parent'] = $params['parent_mid'];
$datarray['type'] = $params['type'] ?? '';
$datarray['parent'] = $params['parent_mid'] ?? '';
$datarray['source_name'] = $sender['xchan_name'];
$datarray['source_link'] = $sender['xchan_url'];
$datarray['source_photo'] = $sender['xchan_photo_s'];
@@ -674,7 +684,6 @@ class Enotify {
'$source_name' => $datarray['source_name'],
'$source_link' => $datarray['source_link'],
'$source_photo' => $datarray['source_photo'],
'$username' => $datarray['to_name'],
'$hsitelink' => $datarray['hsitelink'],
'$hitemlink' => $datarray['hitemlink'],
'$thanks' => $datarray['thanks'],
@@ -696,7 +705,6 @@ class Enotify {
'$source_name' => $datarray['source_name'],
'$source_link' => $datarray['source_link'],
'$source_photo' => $datarray['source_photo'],
'$username' => $datarray['to_name'],
'$tsitelink' => $datarray['tsitelink'],
'$titemlink' => $datarray['titemlink'],
'$thanks' => $datarray['thanks'],
@@ -808,10 +816,10 @@ class Enotify {
localize_item($item);
if($item['shortlocalize']) {
if(isset($item['shortlocalize'])) {
$itemem_text = $item['shortlocalize'];
}
elseif($item['localize']) {
elseif(isset($item['localize'])) {
$itemem_text = $item['localize'];
}
else {
@@ -820,10 +828,18 @@ class Enotify {
: (($item['obj_type'] === 'Answer') ? sprintf( t('voted on %s\'s poll'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]') : sprintf( t('commented on %s\'s post'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]'))
);
if($item['verb'] === ACTIVITY_SHARE) {
if($item['verb'] === ACTIVITY_SHARE && empty($item['owner']['xchan_pubforum'])) {
$itemem_text = sprintf( t('repeated %s\'s post'), '[bdi]' . $item['author']['xchan_name'] . '[/bdi]');
}
if($item['verb'] === ACTIVITY_LIKE) {
$itemem_text = sprintf( t('liked %s\'s post'), '[bdi]' . $item['author']['xchan_name'] . '[/bdi]');
}
if($item['verb'] === ACTIVITY_DISLIKE) {
$itemem_text = sprintf( t('disliked %s\'s post'), '[bdi]' . $item['author']['xchan_name'] . '[/bdi]');
}
if(in_array($item['obj_type'], ['Document', 'Video', 'Audio', 'Image'])) {
$itemem_text = t('shared a file with you');
}
@@ -844,12 +860,16 @@ class Enotify {
// convert this logic into a json array just like the system notifications
$who = (($item['verb'] === ACTIVITY_SHARE) ? 'owner' : 'author');
$who = (($item['verb'] === ACTIVITY_SHARE && empty($item['owner']['xchan_pubforum'])) ? 'owner' : 'author');
$body = html2plain(bbcode($item['body'], ['drop_media' => true, 'tryoembed' => false]), 75, true);
if ($body) {
$body = htmlentities($body, ENT_QUOTES, 'UTF-8', false);
}
$x = array(
'notify_link' => $item['llink'],
'name' => $item[$who]['xchan_name'],
'addr' => (($item[$who]['xchan_addr']) ? $item[$who]['xchan_addr'] : $item[$who]['xchan_url']),
'addr' => $item[$who]['xchan_addr'] ? $item[$who]['xchan_addr'] : $item[$who]['xchan_url'],
'url' => $item[$who]['xchan_url'],
'photo' => $item[$who]['xchan_photo_s'],
'when' => (($edit) ? datetime_convert('UTC', date_default_timezone_get(), $item['edited']) : datetime_convert('UTC', date_default_timezone_get(), $item['created'])),
@@ -858,7 +878,7 @@ class Enotify {
//'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? gen_link_id($item['thr_parent']) : gen_link_id($item['mid'])),
'thread_top' => (($item['item_thread_top']) ? true : false),
'message' => bbcode(escape_tags($itemem_text)),
'body' => htmlentities(html2plain(bbcode($item['body'], ['drop_media', true]), 75, true), ENT_QUOTES, 'UTF-8', false),
'body' => $body,
// these are for the superblock addon
'hash' => $item[$who]['xchan_hash'],
'uid' => $item['uid'],
@@ -902,7 +922,7 @@ class Enotify {
static public function format_intros($rr) {
return [
'notify_link' => z_root() . '/connections/ifpending',
'notify_link' => z_root() . '/connections#' . $rr['abook_id'],
'name' => $rr['xchan_name'],
'addr' => $rr['xchan_addr'],
'url' => $rr['xchan_url'],

View File

@@ -1,405 +0,0 @@
<?php
namespace Zotlabs\Lib;
use Zotlabs\Lib\Libsync;
class Group {
static function add($uid,$name,$public = 0) {
$ret = false;
if(x($uid) && x($name)) {
$r = self::byname($uid,$name); // check for dups
if($r !== false) {
// This could be a problem.
// Let's assume we've just created a group which we once deleted
// all the old members are gone, but the group remains so we don't break any security
// access lists. What we're doing here is reviving the dead group, but old content which
// was restricted to this group may now be seen by the new group members.
$z = q("SELECT * FROM pgrp WHERE id = %d LIMIT 1",
intval($r)
);
if(($z) && $z[0]['deleted']) {
q('UPDATE pgrp SET deleted = 0 WHERE id = %d', intval($z[0]['id']));
notice( t('A deleted group with this name was revived. Existing item permissions <strong>may</strong> apply to this group and any future members. If this is not what you intended, please create another group with a different name.') . EOL);
}
return true;
}
do {
$dups = false;
$hash = random_string(32) . str_replace(['<','>'],['.','.'], $name);
$r = q("SELECT id FROM pgrp WHERE hash = '%s' LIMIT 1", dbesc($hash));
if($r)
$dups = true;
} while($dups == true);
$r = q("INSERT INTO pgrp ( hash, uid, visible, gname )
VALUES( '%s', %d, %d, '%s' ) ",
dbesc($hash),
intval($uid),
intval($public),
dbesc($name)
);
$ret = $r;
}
Libsync::build_sync_packet($uid,null,true);
return $ret;
}
static function remove($uid,$name) {
$ret = false;
if(x($uid) && x($name)) {
$r = q("SELECT id, hash FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1",
intval($uid),
dbesc($name)
);
if($r) {
$group_id = $r[0]['id'];
$group_hash = $r[0]['hash'];
}
if(! $group_id)
return false;
// remove group from default posting lists
$r = q("SELECT channel_default_group, channel_allow_gid, channel_deny_gid FROM channel WHERE channel_id = %d LIMIT 1",
intval($uid)
);
if($r) {
$user_info = $r[0];
$change = false;
if($user_info['channel_default_group'] == $group_hash) {
$user_info['channel_default_group'] = '';
$change = true;
}
if(strpos($user_info['channel_allow_gid'], '<' . $group_hash . '>') !== false) {
$user_info['channel_allow_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_allow_gid']);
$change = true;
}
if(strpos($user_info['channel_deny_gid'], '<' . $group_hash . '>') !== false) {
$user_info['channel_deny_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_deny_gid']);
$change = true;
}
if($change) {
q("UPDATE channel SET channel_default_group = '%s', channel_allow_gid = '%s', channel_deny_gid = '%s'
WHERE channel_id = %d",
intval($user_info['channel_default_group']),
dbesc($user_info['channel_allow_gid']),
dbesc($user_info['channel_deny_gid']),
intval($uid)
);
}
}
// remove all members
$r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d ",
intval($uid),
intval($group_id)
);
// remove group
$r = q("UPDATE pgrp SET deleted = 1 WHERE uid = %d AND gname = '%s'",
intval($uid),
dbesc($name)
);
$ret = $r;
}
Libsync::build_sync_packet($uid,null,true);
return $ret;
}
static function byname($uid,$name) {
if((! $uid) || (! strlen($name)))
return false;
$r = q("SELECT * FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1",
intval($uid),
dbesc($name)
);
if($r)
return $r[0]['id'];
return false;
}
static function rec_byhash($uid,$hash) {
if((! $uid) || (! strlen($hash)))
return false;
$r = q("SELECT * FROM pgrp WHERE uid = %d AND hash = '%s' LIMIT 1",
intval($uid),
dbesc($hash)
);
if($r)
return $r[0];
return false;
}
static function member_remove($uid,$name,$member) {
$gid = self::byname($uid,$name);
if(! $gid)
return false;
if(! ( $uid && $gid && $member))
return false;
$r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' ",
intval($uid),
intval($gid),
dbesc($member)
);
Libsync::build_sync_packet($uid,null,true);
return $r;
}
static function member_add($uid,$name,$member,$gid = 0) {
if(! $gid)
$gid = self::byname($uid,$name);
if((! $gid) || (! $uid) || (! $member))
return false;
$r = q("SELECT * FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' LIMIT 1",
intval($uid),
intval($gid),
dbesc($member)
);
if($r)
return true; // You might question this, but
// we indicate success because the group member was in fact created
// -- It was just created at another time
if(! $r)
$r = q("INSERT INTO pgrp_member (uid, gid, xchan)
VALUES( %d, %d, '%s' ) ",
intval($uid),
intval($gid),
dbesc($member)
);
Libsync::build_sync_packet($uid,null,true);
return $r;
}
static function members($gid) {
$ret = array();
if(intval($gid)) {
$r = q("SELECT * FROM pgrp_member
LEFT JOIN abook ON abook_xchan = pgrp_member.xchan left join xchan on xchan_hash = abook_xchan
WHERE gid = %d AND abook_channel = %d and pgrp_member.uid = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 ORDER BY xchan_name ASC ",
intval($gid),
intval(local_channel()),
intval(local_channel())
);
if($r)
$ret = $r;
}
return $ret;
}
static function members_xchan($gid) {
$ret = [];
if(intval($gid)) {
$r = q("SELECT xchan FROM pgrp_member WHERE gid = %d AND uid = %d",
intval($gid),
intval(local_channel())
);
if($r) {
foreach($r as $rr) {
$ret[] = $rr['xchan'];
}
}
}
return $ret;
}
static function members_profile_xchan($uid,$gid) {
$ret = [];
if(intval($gid)) {
$r = q("SELECT abook_xchan as xchan from abook left join profile on abook_profile = profile_guid where profile.id = %d and profile.uid = %d",
intval($gid),
intval($uid)
);
if($r) {
foreach($r as $rr) {
$ret[] = $rr['xchan'];
}
}
}
return $ret;
}
static function select($uid,$group = '') {
$grps = [];
$o = '';
$r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval($uid)
);
$grps[] = array('name' => '', 'hash' => '0', 'selected' => '');
if($r) {
foreach($r as $rr) {
$grps[] = array('name' => $rr['gname'], 'id' => $rr['hash'], 'selected' => (($group == $rr['hash']) ? 'true' : ''));
}
}
logger('select: ' . print_r($grps,true), LOGGER_DATA);
$o = replace_macros(get_markup_template('group_selection.tpl'), array(
'$label' => t('Add new connections to this privacy group'),
'$groups' => $grps
));
return $o;
}
static function widget($every="connections",$each="group",$edit = false, $group_id = 0, $cid = '',$mode = 1) {
$o = '';
if(! (local_channel() && feature_enabled(local_channel(),'groups'))) {
return '';
}
$groups = array();
$r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval($_SESSION['uid'])
);
$member_of = array();
if($cid) {
$member_of = self::containing(local_channel(),$cid);
}
if($r) {
foreach($r as $rr) {
$selected = (($group_id == $rr['id']) ? ' group-selected' : '');
if ($edit) {
$groupedit = [ 'href' => "group/".$rr['id'], 'title' => t('edit') ];
}
else {
$groupedit = null;
}
$groups[] = [
'id' => $rr['id'],
'enc_cid' => base64url_encode($cid),
'cid' => $cid,
'text' => $rr['gname'],
'selected' => $selected,
'href' => (($mode == 0) ? $each.'?f=&gid='.$rr['id'] : $each."/".$rr['id']) . ((x($_GET,'new')) ? '&new=' . $_GET['new'] : '') . ((x($_GET,'order')) ? '&order=' . $_GET['order'] : ''),
'edit' => $groupedit,
'ismember' => in_array($rr['id'],$member_of),
];
}
}
$tpl = get_markup_template("group_side.tpl");
$o = replace_macros($tpl, array(
'$title' => t('Privacy Groups'),
'$edittext' => t('Edit group'),
'$createtext' => t('Add privacy group'),
'$ungrouped' => (($every === 'contacts') ? t('Channels not in any privacy group') : ''),
'$groups' => $groups,
'$add' => t('add'),
));
return $o;
}
static function expand($g) {
if(! (is_array($g) && count($g)))
return array();
$ret = [];
$x = [];
// private profile linked virtual groups
foreach($g as $gv) {
if(substr($gv,0,3) === 'vp.') {
$profile_hash = substr($gv,3);
if($profile_hash) {
$r = q("select abook_xchan from abook where abook_profile = '%s'",
dbesc($profile_hash)
);
if($r) {
foreach($r as $rv) {
$ret[] = $rv['abook_xchan'];
}
}
}
}
else {
$x[] = $gv;
}
}
if($x) {
stringify_array_elms($x,true);
$groups = implode(',', $x);
if($groups) {
$r = q("SELECT xchan FROM pgrp_member WHERE gid IN ( select id from pgrp where hash in ( $groups ))");
if($r) {
foreach($r as $rr) {
$ret[] = $rr['xchan'];
}
}
}
}
return $ret;
}
static function member_of($c) {
$r = q("SELECT pgrp.gname, pgrp.id FROM pgrp LEFT JOIN pgrp_member ON pgrp_member.gid = pgrp.id WHERE pgrp_member.xchan = '%s' AND pgrp.deleted = 0 ORDER BY pgrp.gname ASC ",
dbesc($c)
);
return $r;
}
static function containing($uid,$c) {
$r = q("SELECT gid FROM pgrp_member WHERE uid = %d AND pgrp_member.xchan = '%s' ",
intval($uid),
dbesc($c)
);
$ret = array();
if($r) {
foreach($r as $rr)
$ret[] = $rr['gid'];
}
return $ret;
}
}

View File

@@ -75,22 +75,23 @@ class LDSignatures {
}
static function hash($obj) {
return hash('sha256',self::normalise($obj));
return hash('sha256', self::normalise($obj));
}
static function normalise($data) {
$ret = '';
if(is_string($data)) {
$data = json_decode($data);
}
if(! is_object($data))
return '';
return $ret;
jsonld_set_document_loader('jsonld_document_loader');
try {
$d = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]);
$ret = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]);
}
catch (\Exception $e) {
// Don't log the exception - this can exhaust memory
@@ -98,7 +99,7 @@ class LDSignatures {
logger('normalise error: ' . print_r($data,true));
}
return $d;
return $ret;
}
static function salmon_sign($data,$channel) {

View File

@@ -135,15 +135,13 @@ class Libsync {
$info['collection_members'] = $r;
}
$interval = ((get_config('system', 'delivery_interval') !== false)
? intval(get_config('system', 'delivery_interval')) : 2);
$interval = get_config('queueworker', 'queue_interval', 500000);
logger('Packet: ' . print_r($info, true), LOGGER_DATA, LOG_DEBUG);
$total = count($synchubs);
foreach ($synchubs as $hub) {
$hash = random_string();
$hash = new_uuid();
$n = Libzot::build_packet($channel, 'sync', $env_recips, json_encode($info), 'hz', $hub['hubloc_sitekey'], $hub['site_crypto']);
Queue::insert([
'hash' => $hash,
@@ -156,19 +154,26 @@ class Libsync {
]);
/*
$x = q("select count(outq_hash) as total from outq where outq_delivered = 0");
if (intval($x[0]['total']) > intval(get_config('system', 'force_queue_threshold', 3000))) {
logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO);
Queue::update($hash);
continue;
}
*/
Master::Summon(['Deliver', $hash]);
$total = $total - 1;
if ($interval && $total)
@time_sleep_until(microtime(true) + (float)$interval);
/*
$total = $total - 1;
*/
if ($interval) {
usleep($interval);
}
}
}
@@ -186,7 +191,6 @@ class Libsync {
require_once('include/import.php');
$result = [];
$keychange = ((array_key_exists('keychange', $arr)) ? true : false);
foreach ($deliveries as $d) {
@@ -194,7 +198,10 @@ class Libsync {
dbesc($sender)
);
$DR = new DReport(z_root(), $sender, $d, 'sync');
$mid = 'sync';
$DR = new DReport(z_root(), $sender, $d, $mid);
if (!$r) {
$DR->update('recipient not found');
@@ -204,6 +211,7 @@ class Libsync {
$channel = $r[0];
$DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
$max_friends = service_class_fetch($channel['channel_id'], 'total_channels');
@@ -232,8 +240,35 @@ class Libsync {
if (array_key_exists('config', $arr) && is_array($arr['config']) && count($arr['config'])) {
foreach ($arr['config'] as $cat => $k) {
foreach ($arr['config'][$cat] as $k => $v)
set_pconfig($channel['channel_id'], $cat, $k, $v);
$pconfig_updated = [];
foreach($arr['config'][$cat] as $k => $v) {
if ($cat === 'hz_delpconfig' && strpos($k, 'b64.') === 0) {
$delpconfig = explode(':', unpack_link_id($k));
// delete the provided pconfig
del_pconfig($channel['channel_id'], $delpconfig[0], $delpconfig[1], $v);
// delete the messenger pconfig
del_pconfig($channel['channel_id'], 'hz_delpconfig', $k);
}
if (strpos($k,'pcfgud:') === 0) {
$realk = substr($k,7);
$pconfig_updated[$realk] = $v;
unset($arr['config'][$cat][$k]);
}
}
foreach($arr['config'][$cat] as $k => $v) {
if (!isset($pconfig_updated[$k])) {
$pconfig_updated[$k] = NULL;
}
if ($cat !== 'hz_delpconfig') {
set_pconfig($channel['channel_id'],$cat,$k,$v,$pconfig_updated[$k]);
}
}
}
}
@@ -246,6 +281,10 @@ class Libsync {
if (array_key_exists('app', $arr) && $arr['app'])
sync_apps($channel, $arr['app']);
if (array_key_exists('sysapp',$arr) && $arr['sysapp']) {
sync_sysapps($channel, $arr['sysapp']);
}
if (array_key_exists('addressbook', $arr) && $arr['addressbook'])
sync_addressbook($channel, $arr['addressbook']);
@@ -255,8 +294,8 @@ class Libsync {
if (array_key_exists('chatroom', $arr) && $arr['chatroom'])
sync_chatrooms($channel, $arr['chatroom']);
if (array_key_exists('mail', $arr) && $arr['mail'])
sync_mail($channel, $arr['mail']);
//if (array_key_exists('mail', $arr) && $arr['mail'])
// sync_mail($channel, $arr['mail']);
if (array_key_exists('event', $arr) && $arr['event'])
sync_events($channel, $arr['event']);
@@ -264,14 +303,16 @@ class Libsync {
if (array_key_exists('event_item', $arr) && $arr['event_item'])
sync_items($channel, $arr['event_item'], ((array_key_exists('relocate', $arr)) ? $arr['relocate'] : null));
if (array_key_exists('item', $arr) && $arr['item'])
if (array_key_exists('item', $arr) && $arr['item']) {
sync_items($channel, $arr['item'], ((array_key_exists('relocate', $arr)) ? $arr['relocate'] : null));
$mid = $arr['item'][0]['message_id'] . '#sync';
}
// deprecated, maintaining for a few months for upward compatibility
// this should sync webpages, but the logic is a bit subtle
if (array_key_exists('item_id', $arr) && $arr['item_id'])
sync_items($channel, $arr['item_id']);
//if (array_key_exists('item_id', $arr) && $arr['item_id'])
// sync_items($channel, $arr['item_id']);
if (array_key_exists('menu', $arr) && $arr['menu'])
sync_menus($channel, $arr['menu']);
@@ -382,19 +423,42 @@ class Libsync {
// This relies on the undocumented behaviour that red sites send xchan info with the abook
// and import_author_xchan will look them up on all federated networks
if ($abook['abook_xchan'] && $abook['xchan_addr']) {
$found = false;
if ($abook['abook_xchan'] && $abook['xchan_addr'] && (! in_array($abook['xchan_network'], [ 'token', 'unknown' ]))) {
$h = Libzot::get_hublocs($abook['abook_xchan']);
if (!$h) {
if ($h) {
$found = true;
}
else {
$xhash = import_author_xchan(encode_item_xchan($abook));
if (!$xhash) {
if ($xhash) {
$found = true;
}
else {
logger('Import of ' . $abook['xchan_addr'] . ' failed.');
continue;
}
}
}
if (!$found && !in_array($abook['xchan_network'], ['zot6', 'activitypub', 'diaspora'])) {
// just import the record.
$xc = [];
foreach ($abook as $k => $v) {
if (strpos($k,'xchan_') === 0) {
$xc[$k] = $v;
}
}
$r = q("select * from xchan where xchan_hash = '%s'",
dbesc($xc['xchan_hash'])
);
if (! $r) {
xchan_store_lowlevel($xc);
}
}
foreach ($abook as $k => $v) {
if (in_array($k, $disallowed) || (strpos($k, 'abook') !== 0)) {
if (in_array($k, $disallowed) || (strpos($k, 'abook_') !== 0)) {
continue;
}
if (!in_array($k, $fields)) {
@@ -408,6 +472,13 @@ class Libsync {
if (array_key_exists('abook_instance', $clean) && $clean['abook_instance'] && strpos($clean['abook_instance'], z_root()) === false) {
$clean['abook_not_here'] = 1;
// guest pass or access token - don't try to probe since it is one-way
// we are relying on the undocumented behaviour that the abook record also contains the xchan
if ($abook['xchan_network'] === 'token') {
$clean['abook_instance'] .= ',';
$clean['abook_instance'] .= z_root();
}
}
@@ -681,13 +752,12 @@ class Libsync {
*/
call_hooks('process_channel_sync_delivery', $addon);
$DR = new DReport(z_root(), $d, $d, 'sync', 'channel sync delivered');
$DR = new DReport(z_root(), $d, $d, $mid, 'channel sync processed');
$DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
$result[] = $DR->get();
}
return $result;
}
@@ -696,20 +766,32 @@ class Libsync {
*
* @param array $sender
* @param array $arr
* @param boolean $absolute (optional) default false
* @return array
*/
static function sync_locations($sender, $arr, $absolute = false) {
static function sync_locations($sender, $arr) {
$ret = [];
$ret = [
'change_message' => '',
'changed' => false,
'message' => ''
];
if ($arr['locations']) {
$what = '';
$changed = false;
if ($absolute)
Libzot::check_location_move($sender['hash'], $arr['locations']);
// If a sender reports that the channel has been deleted, delete its hubloc
if (isset($arr['deleted_locally']) && intval($arr['deleted_locally'])) {
q("UPDATE hubloc SET hubloc_deleted = 1, hubloc_updated = '%s' WHERE hubloc_hash = '%s' AND hubloc_url = '%s'",
dbesc(datetime_convert()),
dbesc($sender['hash']),
dbesc($sender['site']['url'])
);
}
$xisting = q("select * from hubloc where hubloc_hash = '%s'",
if (isset($arr['locations']) && $arr['locations']) {
$xisting = q("select * from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0",
dbesc($sender['hash'])
);
@@ -757,14 +839,13 @@ class Libsync {
// match as many fields as possible in case anything at all changed.
$r = q("select * from hubloc where hubloc_hash = '%s' and hubloc_guid = '%s' and hubloc_guid_sig = '%s' and hubloc_id_url = '%s' and hubloc_url = '%s' and hubloc_url_sig = '%s' and hubloc_site_id = '%s' and hubloc_host = '%s' and hubloc_addr = '%s' and hubloc_callback = '%s' and hubloc_sitekey = '%s' ",
$r = q("select * from hubloc where hubloc_hash = '%s' and hubloc_guid = '%s' and hubloc_guid_sig = '%s' and hubloc_id_url = '%s' and hubloc_url = '%s' and hubloc_url_sig = '%s' and hubloc_host = '%s' and hubloc_addr = '%s' and hubloc_callback = '%s' and hubloc_sitekey = '%s' ",
dbesc($sender['hash']),
dbesc($sender['id']),
dbesc($sender['id_sig']),
dbesc($location['id_url']),
dbesc($location['url']),
dbesc($location['url_sig']),
dbesc($location['site_id']),
dbesc($location['host']),
dbesc($location['address']),
dbesc($location['callback']),
@@ -773,7 +854,18 @@ class Libsync {
if ($r) {
logger('Hub exists: ' . $location['url'], LOGGER_DEBUG);
// update connection timestamp if this is the site we're talking to
// generate a new hubloc_site_id if it's wrong due to historical bugs 2021-11-30
if ($r[0]['hubloc_site_id'] !== $location['site_id']) {
q("update hubloc set hubloc_site_id = '%s' where hubloc_id = %d",
dbesc(Libzot::make_xchan_hash($location['url'], $location['sitekey'])),
intval($r[0]['hubloc_id'])
);
}
// Update connection timestamp if this is the site we're talking to.
// Also mark all entries from the current site with different sitekeys
// deleted (the site has been re-installed)
// This only happens when called from import_xchan
$current_site = false;
@@ -787,6 +879,12 @@ class Libsync {
intval($r[0]['hubloc_id']),
dbesc($t)
);
q("update hubloc set hubloc_error = 1, hubloc_deleted = 1 where hubloc_url = '%s' and hubloc_sitekey != '%s'",
dbesc($r[0]['hubloc_url']),
dbesc($r[0]['hubloc_sitekey'])
);
$current_site = true;
}
@@ -836,14 +934,7 @@ class Libsync {
$what .= 'primary_hub ';
$changed = true;
}
elseif ($absolute) {
// Absolute sync - make sure the current primary is correctly reflected in the xchan
$pr = hubloc_change_primary($r[0]);
if ($pr) {
$what .= 'xchan_primary ';
$changed = true;
}
}
if (intval($r[0]['hubloc_deleted']) && (!intval($location['deleted']))) {
q("update hubloc set hubloc_deleted = 0, hubloc_updated = '%s' where hubloc_id_url = '%s'",
dbesc(datetime_convert()),
@@ -861,6 +952,7 @@ class Libsync {
$what .= 'delete_hub ';
$changed = true;
}
continue;
}
@@ -911,9 +1003,9 @@ class Libsync {
}
}
// get rid of any hubs we have for this channel which weren't reported.
// get rid of any hublocs we have for this channel which weren't reported.
if ($absolute && $xisting) {
if ($xisting) {
foreach ($xisting as $x) {
if (!array_key_exists('updated', $x)) {
logger('Deleting unreferenced hub location ' . $x['hubloc_addr']);

File diff suppressed because it is too large Load Diff

View File

@@ -145,8 +145,8 @@ class Libzotdir {
if(! $directory_sort_order)
$directory_sort_order = 'date';
$current_order = (($_REQUEST['order']) ? $_REQUEST['order'] : $directory_sort_order);
$suggest = (($_REQUEST['suggest']) ? '&suggest=' . $_REQUEST['suggest'] : '');
$current_order = $_REQUEST['order'] ?? $directory_sort_order;
$suggest = ((isset($_REQUEST['suggest'])) ? '&suggest=' . $_REQUEST['suggest'] : '');
$url = 'directory?f=';
@@ -172,13 +172,12 @@ class Libzotdir {
}
/**
* @brief Checks the directory mode of this hub.
* @brief fetches updates from known directories
*
* Checks the directory mode of this hub to see if it is some form of directory server. If it is,
* get the directory realm of this hub. Fetch a list of all other directory servers in this realm and request
* a directory sync packet. This will contain both directory updates and new ratings. Store these all in the DB.
* In the case of updates, we will query each of them asynchronously from a poller task. Ratings are stored
* directly if the rater's signature matches.
* a directory sync packet. Store these all in the DB.
* In the case of updates, we will query each of them asynchronously from a poller task.
*
* @param int $dirmode;
*/
@@ -233,6 +232,8 @@ class Libzotdir {
if (! $r)
return;
$dir_trusted_hosts = array_merge(get_directory_fallback_servers(), get_config('system', 'trusted_directory_servers', []));
foreach ($r as $rr) {
if (! $rr['site_directory'])
continue;
@@ -264,31 +265,65 @@ class Libzotdir {
if (is_array($j['transactions']) && count($j['transactions'])) {
foreach ($j['transactions'] as $t) {
if (empty($t['hash']) || empty($t['transaction_id']) || empty($t['address'])) {
if (empty($t['hash']) || empty($t['host']) || empty($t['address'])) {
continue;
}
$r = q("select * from updates where ud_guid = '%s' limit 1",
dbesc($t['transaction_id'])
$r = q("select * from updates where ud_hash = '%s' limit 1",
dbesc($t['hash'])
);
if($r)
continue;
$ud_flags = 0;
if (is_array($t['flags']) && in_array('deleted',$t['flags']))
$ud_flags |= UPDATE_FLAGS_DELETED;
if (is_array($t['flags']) && in_array('forced',$t['flags']))
$ud_flags |= UPDATE_FLAGS_FORCED;
if ($r) {
$update = 0;
$z = q("insert into updates ( ud_hash, ud_guid, ud_date, ud_flags, ud_addr )
values ( '%s', '%s', '%s', %d, '%s' ) ",
dbesc($t['hash']),
dbesc($t['transaction_id']),
dbesc($t['timestamp']),
intval($ud_flags),
dbesc($t['address'])
);
// no need to look at updates that originated from our own site
if ($t['host'] === z_root()) {
continue;
}
// there is more recent xchan information
if ($r[0]['ud_date'] <= $t['timestamp']) {
$update = 1;
}
// the host is trusted and flags have changed - update flags immediately
if (in_array($t['host'], $dir_trusted_hosts) &&
$rr['site_url'] === $t['host'] &&
intval($r[0]['ud_flags']) !== intval($t['flags'])) {
q("UPDATE updates SET ud_update = %d, ud_flags = %d WHERE ud_id = %d",
intval($update),
intval($t['flags']),
dbesc($r[0]['ud_id'])
);
q("UPDATE xchan SET xchan_censored = %d WHERE xchan_hash = '%s'",
intval($t['flags']),
dbesc($r[0]['ud_hash'])
);
continue;
}
if (!$update) {
continue;
}
q("UPDATE updates SET ud_update = %d WHERE ud_id = %d",
intval($update),
dbesc($r[0]['ud_id'])
);
}
else {
q("insert into updates ( ud_hash, ud_host, ud_date, ud_addr, ud_update, ud_flags )
values ( '%s', '%s', '%s', '%s', 1, %d) ",
dbesc($t['hash']),
dbesc($t['host']),
dbesc($t['timestamp']),
dbesc($t['address']),
dbesc(in_array($t['host'], $dir_trusted_hosts) ? $t['flags'] : 0)
);
}
}
}
}
@@ -303,8 +338,9 @@ class Libzotdir {
*
* Ignore updating records marked as deleted.
*
* If successful, sets ud_last in the DB to the current datetime for this
* If successful, sets ud_updated in the DB to the current datetime for this
* reddress/webbie.
* Else update ud_last so we can stop trying after 7 days (Daemon/Poller.php)
*
* @param array $ud Entry from update table
*/
@@ -313,32 +349,47 @@ class Libzotdir {
logger('update_directory_entry: ' . print_r($ud,true), LOGGER_DATA);
if ($ud['ud_addr'] && (! ($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) {
$success = false;
$zf = [];
// TODO: remove this check after all directory servers have version > 8.4
// ud_addr will always be the channel url at that time
$href = ((strpos($ud['ud_addr'], '://') === false) ? Webfinger::zot_url(punify($ud['ud_addr'])) : punify($ud['ud_addr']));
if($href) {
$zf = Zotfinger::exec($href);
if($zf && array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) {
$xc = Libzot::import_xchan($zf['data']);
// xchan_hash mismatch - this can happen after a site re-install at the same url
if ($xc['success'] && $xc['hash'] !== $ud['ud_hash']) {
self::delete_by_hash($ud['ud_hash']);
}
// backwards compatibility: Libzot::import_xchan(), where self::update() is called,
// will fail with versions < 8.4 if the channel has been locally deleted.
// In this case we will update the updates record here without bumping the date
// since we could not verify if anything changed.
if (!$xc['success'] && !empty($zf['data']['deleted_locally'])) {
self::update($ud['ud_hash'], $ud['ud_addr'], false);
}
$href = Webfinger::zot_url(punify($ud['ud_addr']));
if($href) {
$zf = Zotfinger::exec($href);
}
if(array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) {
$xc = Libzot::import_xchan($zf['data'], 0, $ud);
// This is a workaround for a missing xchan_updated column
// TODO: implement xchan_updated in the xchan table and update this column instead
if($zf['data']['primary_location']['address'] && $zf['data']['primary_location']['url']) {
if(!empty($zf['data']['primary_location']['url'])) {
q("UPDATE hubloc SET hubloc_updated = '%s' WHERE hubloc_id_url = '%s' AND hubloc_primary = 1",
dbesc(datetime_convert()),
dbesc($zf['data']['primary_location']['url'])
);
}
}
else {
q("update updates set ud_last = '%s' where ud_addr = '%s'",
dbesc(datetime_convert()),
dbesc($ud['ud_addr'])
);
return true;
}
}
q("UPDATE updates SET ud_addr = '%s', ud_last = '%s' WHERE ud_hash = '%s'",
dbesc($href ? $href : $ud['ud_addr']),
dbesc(datetime_convert()),
dbesc($ud['ud_hash'])
);
return false;
}
@@ -353,85 +404,78 @@ class Libzotdir {
*/
static function local_dir_update($uid, $force) {
logger('local_dir_update uid: ' . $uid, LOGGER_DEBUG);
logger('local_dir_update: uid: ' . $uid, LOGGER_DEBUG);
$p = q("select channel.channel_hash, channel_address, channel_timezone, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1",
$p = q("select channel.channel_hash, channel_address, channel_timezone, profile.*, xchan.xchan_hidden, xchan.xchan_url from profile left join channel on channel_id = uid left join xchan on channel_hash = xchan_hash where profile.uid = %d and profile.is_default = 1",
intval($uid)
);
$profile = array();
$profile['encoding'] = 'zot';
if ($p) {
$hash = $p[0]['channel_hash'];
$profile['description'] = $p[0]['pdesc'];
$profile['birthday'] = $p[0]['dob'];
if ($age = age($p[0]['dob'],$p[0]['channel_timezone'],''))
$profile['age'] = $age;
$profile['gender'] = $p[0]['gender'];
$profile['marital'] = $p[0]['marital'];
$profile['sexual'] = $p[0]['sexual'];
$profile['locale'] = $p[0]['locality'];
$profile['region'] = $p[0]['region'];
$profile['postcode'] = $p[0]['postal_code'];
$profile['country'] = $p[0]['country_name'];
$profile['about'] = $p[0]['about'];
$profile['homepage'] = $p[0]['homepage'];
$profile['hometown'] = $p[0]['hometown'];
if ($p[0]['keywords']) {
$tags = array();
$k = explode(' ', $p[0]['keywords']);
if ($k)
foreach ($k as $kk)
if (trim($kk))
$tags[] = trim($kk);
if ($tags)
$profile['keywords'] = $tags;
}
$hidden = (1 - intval($p[0]['publish']));
logger('hidden: ' . $hidden);
$r = q("select xchan_hidden from xchan where xchan_hash = '%s'",
dbesc($p[0]['channel_hash'])
);
if(intval($r[0]['xchan_hidden']) != $hidden) {
$r = q("update xchan set xchan_hidden = %d where xchan_hash = '%s'",
intval($hidden),
dbesc($hash)
);
}
$arr = [ 'channel_id' => $uid, 'hash' => $hash, 'profile' => $profile ];
call_hooks('local_dir_update', $arr);
$address = channel_reddress($p[0]);
if (perm_is_allowed($uid, '', 'view_profile')) {
self::import_directory_profile($hash, $arr['profile'], $address, 0);
}
else {
// they may have made it private
q("delete from xprof where xprof_hash = '%s'",
dbesc($hash)
);
q("delete from xtag where xtag_hash = '%s'",
dbesc($hash)
);
}
if (!$p) {
logger('profile not found');
return;
}
$ud_hash = random_string() . '@' . \App::get_hostname();
self::update_modtime($hash, $ud_hash, channel_reddress($p[0]),(($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED));
$profile = [];
$profile['encoding'] = 'zot';
$hash = $p[0]['channel_hash'];
$profile['description'] = $p[0]['pdesc'];
$profile['birthday'] = $p[0]['dob'];
if ($age = age($p[0]['dob'],$p[0]['channel_timezone'],''))
$profile['age'] = $age;
$profile['gender'] = $p[0]['gender'];
$profile['marital'] = $p[0]['marital'];
$profile['sexual'] = $p[0]['sexual'];
$profile['locale'] = $p[0]['locality'];
$profile['region'] = $p[0]['region'];
$profile['postcode'] = $p[0]['postal_code'];
$profile['country'] = $p[0]['country_name'];
$profile['about'] = $p[0]['about'];
$profile['homepage'] = $p[0]['homepage'];
$profile['hometown'] = $p[0]['hometown'];
if ($p[0]['keywords']) {
$tags = array();
$k = explode(' ', $p[0]['keywords']);
if ($k)
foreach ($k as $kk)
if (trim($kk))
$tags[] = trim($kk);
if ($tags)
$profile['keywords'] = $tags;
}
$hidden = (1 - intval($p[0]['publish']));
logger('hidden: ' . $hidden);
if(intval($p[0]['xchan_hidden']) !== $hidden) {
q("update xchan set xchan_hidden = %d where xchan_hash = '%s'",
intval($hidden),
dbesc($hash)
);
}
$arr = [ 'channel_id' => $uid, 'hash' => $hash, 'profile' => $profile ];
call_hooks('local_dir_update', $arr);
if (perm_is_allowed($uid, '', 'view_profile')) {
self::import_directory_profile($hash, $arr['profile']);
}
else {
// they may have made it private
q("delete from xprof where xprof_hash = '%s'",
dbesc($hash)
);
q("delete from xtag where xtag_hash = '%s'",
dbesc($hash)
);
}
self::update($hash, $p[0]['xchan_url']);
}
@@ -441,39 +485,48 @@ class Libzotdir {
*
* @param string $hash
* @param array $profile
* @param string $addr
* @param number $ud_flags (optional) UPDATE_FLAGS_UPDATED
* @param number $suppress_update (optional) default 0
* @return boolean $updated if something changed
*/
static function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLAGS_UPDATED, $suppress_update = 0) {
static function import_directory_profile($hash, $profile) {
logger('import_directory_profile', LOGGER_DEBUG);
if (! $hash)
return false;
$arr = array();
$arr = [];
$arr['xprof_hash'] = $hash;
$arr['xprof_dob'] = (($profile['birthday'] === '0000-00-00') ? $profile['birthday'] : datetime_convert('','',$profile['birthday'],'Y-m-d')); // !!!! check this for 0000 year
$arr['xprof_age'] = (($profile['age']) ? intval($profile['age']) : 0);
$arr['xprof_desc'] = (($profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_gender'] = (($profile['gender']) ? htmlspecialchars($profile['gender'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_marital'] = (($profile['marital']) ? htmlspecialchars($profile['marital'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_sexual'] = (($profile['sexual']) ? htmlspecialchars($profile['sexual'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_locale'] = (($profile['locale']) ? htmlspecialchars($profile['locale'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_region'] = (($profile['region']) ? htmlspecialchars($profile['region'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_postcode'] = (($profile['postcode']) ? htmlspecialchars($profile['postcode'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_country'] = (($profile['country']) ? htmlspecialchars($profile['country'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_about'] = (($profile['about']) ? htmlspecialchars($profile['about'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_homepage'] = (($profile['homepage']) ? htmlspecialchars($profile['homepage'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_hometown'] = (($profile['hometown']) ? htmlspecialchars($profile['hometown'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_hash'] = $hash;
$arr['xprof_dob'] = '0000-00-00';
if (isset($profile['birthday'])) {
$arr['xprof_dob'] = (($profile['birthday'] === '0000-00-00')
? $profile['birthday']
: datetime_convert('', '', $profile['birthday'], 'Y-m-d')); // !!!! check this for 0000 year
}
$arr['xprof_age'] = ((isset($profile['age']) && $profile['age']) ? intval($profile['age']) : 0);
$arr['xprof_desc'] = ((isset($profile['description']) && $profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_gender'] = ((isset($profile['gender']) && $profile['gender']) ? htmlspecialchars($profile['gender'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_marital'] = ((isset($profile['marital']) && $profile['marital']) ? htmlspecialchars($profile['marital'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_sexual'] = ((isset($profile['sexual']) && $profile['sexual']) ? htmlspecialchars($profile['sexual'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_locale'] = ((isset($profile['locale']) && $profile['locale']) ? htmlspecialchars($profile['locale'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_region'] = ((isset($profile['region']) && $profile['region']) ? htmlspecialchars($profile['region'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_postcode'] = ((isset($profile['postcode']) && $profile['postcode']) ? htmlspecialchars($profile['postcode'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_country'] = ((isset($profile['country']) && $profile['country']) ? htmlspecialchars($profile['country'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_about'] = ((isset($profile['about']) && $profile['about']) ? htmlspecialchars($profile['about'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_homepage'] = ((isset($profile['homepage']) && $profile['homepage']) ? htmlspecialchars($profile['homepage'], ENT_COMPAT,'UTF-8',false) : '');
$arr['xprof_hometown'] = ((isset($profile['hometown']) && $profile['hometown']) ? htmlspecialchars($profile['hometown'], ENT_COMPAT,'UTF-8',false) : '');
$clean = array();
if (array_key_exists('keywords', $profile) and is_array($profile['keywords'])) {
self::import_directory_keywords($hash,$profile['keywords']);
foreach ($profile['keywords'] as $kw) {
if (in_array($kw, $clean)) {
continue;
}
$kw = trim(htmlspecialchars($kw,ENT_COMPAT, 'UTF-8', false));
$kw = trim($kw, ',');
$clean[] = $kw;
@@ -580,9 +633,6 @@ class Libzotdir {
*/
call_hooks('import_directory_profile', $d);
if (($d['update']) && (! $suppress_update))
self::update_modtime($arr['xprof_hash'],random_string() . '@' . \App::get_hostname(), $addr, $ud_flags);
return $d['update'];
}
@@ -600,6 +650,10 @@ class Libzotdir {
dbesc($hash)
);
$xchan = q("select xchan_censored from xchan where xchan_hash = '%s'",
dbesc($hash)
);
if($r) {
foreach($r as $rr)
$existing[] = $rr['xtag_term'];
@@ -607,6 +661,10 @@ class Libzotdir {
$clean = array();
foreach($keywords as $kw) {
if (in_array($kw, $clean)) {
continue;
}
$kw = trim(htmlspecialchars($kw,ENT_COMPAT, 'UTF-8', false));
$kw = trim($kw, ',');
$clean[] = $kw;
@@ -621,9 +679,10 @@ class Libzotdir {
}
foreach($clean as $x) {
if(! in_array($x, $existing)) {
$r = q("insert into xtag ( xtag_hash, xtag_term, xtag_flags) values ( '%s' ,'%s', 0 )",
$r = q("insert into xtag ( xtag_hash, xtag_term, xtag_flags) values ( '%s' ,'%s', %d )",
dbesc($hash),
dbesc($x)
dbesc($x),
intval($xchan[0]['xchan_censored'])
);
}
}
@@ -633,13 +692,12 @@ class Libzotdir {
/**
* @brief
*
* @param string $hash
* @param string $guid
* @param string $addr
* @param int $flags (optional) default 0
* @param string $hash the channel hash
* @param string $addr the channel url
* @param bool $bump_date (optional) default true
*/
static function update_modtime($hash, $guid, $addr, $flags = 0) {
static function update($hash, $addr, $bump_date = true, $flag = null) {
$dirmode = intval(get_config('system', 'directory_mode'));
@@ -647,26 +705,70 @@ class Libzotdir {
return;
}
if (empty($hash) || empty($guid) || empty($addr)) {
if (empty($hash) || empty($addr)) {
return;
}
if($flags) {
q("insert into updates (ud_hash, ud_guid, ud_date, ud_flags, ud_addr ) values ( '%s', '%s', '%s', %d, '%s' )",
dbesc($hash),
dbesc($guid),
dbesc(datetime_convert()),
intval($flags),
dbesc($addr)
);
$u = q("SELECT * FROM updates WHERE ud_hash = '%s' LIMIT 1",
dbesc($hash)
);
$date_sql = '';
if ($bump_date) {
$date_sql = "ud_date = '" . dbesc(datetime_convert()) . "',";
}
else {
q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and not (ud_flags & %d)>0 ",
intval(UPDATE_FLAGS_UPDATED),
$flag_sql = '';
if ($flag !== null) {
$flag_sql = "ud_flags = '" . intval($flag) . "',";
}
if ($u) {
$x = q("UPDATE updates SET $date_sql $flag_sql ud_last = '%s', ud_host = '%s', ud_addr = '%s', ud_update = 0 WHERE ud_id = %d",
dbesc(NULL_DATE),
dbesc(z_root()),
dbesc($addr),
intval(UPDATE_FLAGS_UPDATED)
intval($u[0]['ud_id'])
);
return;
}
q("INSERT INTO updates (ud_hash, ud_host, ud_date, ud_addr, ud_flags) VALUES ( '%s', '%s', '%s', '%s', %d )",
dbesc($hash),
dbesc(z_root()),
dbesc(datetime_convert()),
dbesc($addr),
intval($flag)
);
return;
}
/**
* @brief deletes a entry in updates by hash
*
* @param string $hash the channel hash
* @return boolean
*/
static function delete_by_hash($hash) {
if (!$hash) {
return false;
}
$x = q("DELETE FROM updates WHERE ud_hash = '%s'",
dbesc($hash)
);
if ($x) {
return true;
}
return false;
}
}

View File

@@ -2,85 +2,120 @@
namespace Zotlabs\Lib;
require_once('include/html2plain.php');
class MessageFilter {
public static function evaluate($item, $incl, $excl) {
static public function evaluate($item,$incl,$excl) {
require_once('include/html2plain.php');
$text = prepare_text($item['body'],$item['mimetype']);
$text = prepare_text($item['body'],((isset($item['mimetype'])) ? $item['mimetype'] : 'text/bbcode'));
$text = html2plain(($item['title']) ? $item['title'] . ' ' . $text : $text);
$lang = null;
if((strpos($incl,'lang=') !== false) || (strpos($excl,'lang=') !== false) || (strpos($incl,'lang!=') !== false) || (strpos($excl,'lang!=') !== false)) {
if ((strpos($incl, 'lang=') !== false) || (strpos($excl, 'lang=') !== false) || (strpos($incl, 'lang!=') !== false) || (strpos($excl, 'lang!=') !== false)) {
$lang = detect_language($text);
}
$tags = ((is_array($item['term']) && count($item['term'])) ? $item['term'] : false);
$tags = ((isset($item['term']) && is_array($item['term']) && count($item['term'])) ? $item['term'] : false);
// exclude always has priority
$exclude = (($excl) ? explode("\n",$excl) : null);
$exclude = (($excl) ? explode("\n", $excl) : null);
if($exclude) {
foreach($exclude as $word) {
$word = trim($word);
if(! $word)
if ($exclude) {
foreach ($exclude as $word) {
$word = html_entity_decode(trim($word));
if (! $word) {
continue;
if(substr($word,0,1) === '#' && $tags) {
foreach($tags as $t)
if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
return false;
}
elseif(substr($word,0,1) === '$' && $tags) {
foreach($tags as $t)
if(($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
return false;
if (isset($lang) && ((strpos($word, 'lang=') === 0) || (strpos($word, 'lang!=') === 0))) {
if (!strlen($lang)) {
// Result is ambiguous. As we are matching deny rules only at this time, continue tests.
// Any matching deny rule concludes testing.
continue;
}
if (strpos($word, 'lang=') === 0 && strcasecmp($lang, trim(substr($word, 5))) == 0) {
return false;
} elseif (strpos($word, 'lang!=') === 0 && strcasecmp($lang, trim(substr($word, 6))) != 0) {
return false;
}
}
elseif((strpos($word,'/') === 0) && preg_match($word,$text))
elseif (substr($word, 0, 1) === '#' && $tags) {
foreach ($tags as $t) {
if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
return false;
}
}
} elseif (substr($word, 0, 1) === '$' && $tags) {
foreach ($tags as $t) {
if (($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
return false;
}
}
} elseif (substr($word, 0, 2) === '?+') {
if (self::test_condition(substr($word, 2), $item['obj'])) {
return false;
}
} elseif (substr($word, 0, 1) === '?') {
if (self::test_condition(substr($word, 1), $item)) {
return false;
}
} elseif ((strpos($word, '/') === 0) && preg_match($word, $text)) {
return false;
elseif((strpos($word,'lang=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,5))) == 0))
return false;
elseif((strpos($word,'lang!=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,6))) != 0))
return false;
elseif(stristr($text,$word) !== false)
} elseif (stristr($text, $word) !== false) {
return false;
}
}
}
$include = (($incl) ? explode("\n",$incl) : null);
$include = (($incl) ? explode("\n", $incl) : null);
if($include) {
foreach($include as $word) {
$word = trim($word);
if(! $word)
if ($include) {
foreach ($include as $word) {
$word = html_entity_decode(trim($word));
if (! $word) {
continue;
if(substr($word,0,1) === '#' && $tags) {
foreach($tags as $t)
if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
return true;
}
elseif(substr($word,0,1) === '$' && $tags) {
foreach($tags as $t)
if(($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
return true;
if (isset($lang) && ((strpos($word, 'lang=') === 0) || (strpos($word, 'lang!=') === 0))) {
if (!strlen($lang)) {
// Result is ambiguous. However we are checking allow rules
// and an ambiguous language is always permitted.
return true;
}
if (strpos($word, 'lang=') === 0 && strcasecmp($lang, trim(substr($word, 5))) == 0) {
return true;
} elseif (strpos($word, 'lang!=') === 0 && strcasecmp($lang, trim(substr($word, 6))) != 0) {
return true;
}
}
elseif((strpos($word,'/') === 0) && preg_match($word,$text))
elseif (substr($word, 0, 1) === '#' && $tags) {
foreach ($tags as $t) {
if ((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
return true;
}
}
} elseif (substr($word, 0, 1) === '$' && $tags) {
foreach ($tags as $t) {
if (($t['ttype'] == TERM_CATEGORY) && (($t['term'] === substr($word, 1)) || (substr($word, 1) === '*'))) {
return true;
}
}
} elseif (substr($word, 0, 2) === '?+') {
if (self::test_condition(substr($word, 2), $item['obj'])) {
return true;
}
} elseif (substr($word, 0, 1) === '?') {
if (self::test_condition(substr($word, 1), $item)) {
return true;
}
} elseif ((strpos($word, '/') === 0) && preg_match($word, $text)) {
return true;
elseif((strpos($word,'lang=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,5))) == 0))
return true;
elseif((strpos($word,'lang!=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,6))) != 0))
return true;
elseif(stristr($text,$word) !== false)
} elseif (stristr($text, $word) !== false) {
return true;
}
}
}
else {
} else {
return true;
}
@@ -88,4 +123,123 @@ class MessageFilter {
}
/**
* @brief Test for Conditional Execution conditions. Shamelessly ripped off from Code/Render/Comanche
*
* This is extensible. The first version of variable testing supports tests of the forms:
*
* - ?foo ~= baz which will check if item.foo contains the string 'baz';
* - ?foo == baz which will check if item.foo is the string 'baz';
* - ?foo != baz which will check if item.foo is not the string 'baz';
* - ?foo >= 3 which will check if item.foo is greater than or equal to 3;
* - ?foo > 3 which will check if item.foo is greater than 3;
* - ?foo <= 3 which will check if item.foo is less than or equal to 3;
* - ?foo < 3 which will check if item.foo is less than 3;
*
* - ?foo {} baz which will check if 'baz' is an array element in item.foo
* - ?foo {*} baz which will check if 'baz' is an array key in item.foo
* - ?foo which will check for a return of a true condition for item.foo;
* - ?!foo which will check for a return of a false condition for item.foo;
*
* The values 0, '', an empty array, and an unset value will all evaluate to false.
*
* @param string $s
* @param array $item
* @return bool
*/
public static function test_condition($s,$item) {
if (preg_match('/(.*?)\s\~\=\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if (stripos($x, trim($matches[2])) !== false) {
return true;
}
return false;
}
if (preg_match('/(.*?)\s\=\=\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x == trim($matches[2])) {
return true;
}
return false;
}
if (preg_match('/(.*?)\s\!\=\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x != trim($matches[2])) {
return true;
}
return false;
}
if (preg_match('/(.*?)\s\>\=\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x >= trim($matches[2])) {
return true;
}
return false;
}
if (preg_match('/(.*?)\s\<\=\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x <= trim($matches[2])) {
return true;
}
return false;
}
if (preg_match('/(.*?)\s\>\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x > trim($matches[2])) {
return true;
}
return false;
}
if (preg_match('/(.*?)\s\>\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x < trim($matches[2])) {
return true;
}
return false;
}
if (preg_match('/[\$](.*?)\s\{\}\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if (is_array($x) && in_array(trim($matches[2]), $x)) {
return true;
}
return false;
}
if (preg_match('/(.*?)\s\{\*\}\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if (is_array($x) && array_key_exists(trim($matches[2]), $x)) {
return true;
}
return false;
}
// Ordering of this check (for falsiness) with relation to the following one (check for truthiness) is important.
if (preg_match('/\!(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if (!$x) {
return true;
}
return false;
}
if (preg_match('/(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x) {
return true;
}
return false;
}
return false;
}
}

View File

@@ -1,324 +0,0 @@
<?php
namespace Zotlabs\Lib;
use Zotlabs\Lib\Libsync;
define ( 'NWIKI_ITEM_RESOURCE_TYPE', 'nwiki' );
class NativeWiki {
public static function listwikis($channel, $observer_hash) {
$sql_extra = item_permissions_sql($channel['channel_id'], $observer_hash);
$wikis = q("SELECT * FROM item
WHERE resource_type = '%s' AND mid = parent_mid AND uid = %d AND item_deleted = 0 $sql_extra",
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
intval($channel['channel_id'])
);
if($wikis) {
foreach($wikis as &$w) {
$w['json_allow_cid'] = acl2json($w['allow_cid']);
$w['json_allow_gid'] = acl2json($w['allow_gid']);
$w['json_deny_cid'] = acl2json($w['deny_cid']);
$w['json_deny_gid'] = acl2json($w['deny_gid']);
$w['rawName'] = get_iconfig($w, 'wiki', 'rawName');
$w['htmlName'] = escape_tags($w['rawName']);
//$w['urlName'] = urlencode(urlencode($w['rawName']));
$w['urlName'] = self::name_encode($w['rawName']);
$w['mimeType'] = get_iconfig($w, 'wiki', 'mimeType');
$w['typelock'] = get_iconfig($w, 'wiki', 'typelock');
$w['lockstate'] = (($w['allow_cid'] || $w['allow_gid'] || $w['deny_cid'] || $w['deny_gid']) ? 'lock' : 'unlock');
}
}
// TODO: query db for wikis the observer can access. Return with two lists, for read and write access
return array('wikis' => $wikis);
}
public static function create_wiki($channel, $observer_hash, $wiki, $acl) {
$resource_id = new_uuid();
$uuid = new_uuid();
$ac = $acl->get();
$mid = z_root() . '/item/' . $uuid;
$arr = array(); // Initialize the array of parameters for the post
$item_hidden = ((intval($wiki['postVisible']) === 0) ? 1 : 0);
$wiki_url = z_root() . '/wiki/' . $channel['channel_address'] . '/' . $wiki['urlName'];
$arr['aid'] = $channel['channel_account_id'];
$arr['uuid'] = $uuid;
$arr['uid'] = $channel['channel_id'];
$arr['mid'] = $mid;
$arr['parent_mid'] = $mid;
$arr['item_hidden'] = $item_hidden;
$arr['resource_type'] = NWIKI_ITEM_RESOURCE_TYPE;
$arr['resource_id'] = $resource_id;
$arr['owner_xchan'] = $channel['channel_hash'];
$arr['author_xchan'] = $observer_hash;
$arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']);
$arr['llink'] = $arr['plink'];
$arr['title'] = $wiki['htmlName']; // name of new wiki;
$arr['allow_cid'] = $ac['allow_cid'];
$arr['allow_gid'] = $ac['allow_gid'];
$arr['deny_cid'] = $ac['deny_cid'];
$arr['deny_gid'] = $ac['deny_gid'];
$arr['item_wall'] = 1;
$arr['item_origin'] = 1;
$arr['item_thread_top'] = 1;
$arr['item_private'] = intval($acl->is_private());
$arr['verb'] = ACTIVITY_CREATE;
$arr['obj_type'] = 'Document';
$arr['body'] = '[table][tr][td][h1]New Wiki[/h1][/td][/tr][tr][td][zrl=' . $wiki_url . ']' . $wiki['htmlName'] . '[/zrl][/td][/tr][/table]';
$arr['public_policy'] = map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_wiki'),true);
// Save the wiki name information using iconfig. This is shareable.
if(! set_iconfig($arr, 'wiki', 'rawName', $wiki['rawName'], true)) {
return array('item' => null, 'success' => false);
}
if(! set_iconfig($arr, 'wiki', 'mimeType', $wiki['mimeType'], true)) {
return array('item' => null, 'success' => false);
}
set_iconfig($arr,'wiki','typelock',$wiki['typelock'],true);
$post = item_store($arr);
$item_id = $post['item_id'];
if($item_id) {
\Zotlabs\Daemon\Master::Summon(array('Notifier', 'activity', $item_id));
return array('item' => $post['item'], 'item_id' => $item_id, 'success' => true);
}
else {
return array('item' => null, 'success' => false);
}
}
public static function update_wiki($channel_id, $observer_hash, $arr, $acl) {
$w = self::get_wiki($channel_id, $observer_hash, $arr['resource_id']);
$item = $w['wiki'];
if(! $item) {
return array('item' => null, 'success' => false);
}
$x = $acl->get();
$item['allow_cid'] = $x['allow_cid'];
$item['allow_gid'] = $x['allow_gid'];
$item['deny_cid'] = $x['deny_cid'];
$item['deny_gid'] = $x['deny_gid'];
$item['item_private'] = intval($acl->is_private());
$update_title = false;
if($item['title'] !== $arr['updateRawName']) {
$update_title = true;
$item['title'] = $arr['updateRawName'];
}
$update = item_store_update($item);
$item_id = $update['item_id'];
// update acl for any existing wiki pages
q("update item set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', item_private = %d where resource_type = 'nwikipage' and resource_id = '%s'",
dbesc($item['allow_cid']),
dbesc($item['allow_gid']),
dbesc($item['deny_cid']),
dbesc($item['deny_gid']),
dbesc($item['item_private']),
dbesc($arr['resource_id'])
);
if($update['item_id']) {
info( t('Wiki updated successfully'));
if($update_title) {
// Update the wiki name information using iconfig.
if(! set_iconfig($update['item_id'], 'wiki', 'rawName', $arr['updateRawName'], true)) {
return array('item' => null, 'success' => false);
}
}
return array('item' => $update['item'], 'item_id' => $update['item_id'], 'success' => $update['success']);
}
else {
return array('item' => null, 'success' => false);
}
}
public static function sync_a_wiki_item($uid,$id,$resource_id) {
$r = q("SELECT * from item WHERE uid = %d AND ( id = %d OR ( resource_type = '%s' and resource_id = '%s' )) ",
intval($uid),
intval($id),
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
dbesc($resource_id)
);
if($r) {
$q = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s'",
dbesc($r[0]['resource_id'])
);
if($q) {
$r = array_merge($r,$q);
}
xchan_query($r);
$sync_item = fetch_post_tags($r);
if($sync_item) {
$pkt = [];
foreach($sync_item as $w) {
$pkt[] = encode_item($w,true);
}
Libsync::build_sync_packet($uid,array('wiki' => $pkt));
}
}
}
public static function delete_wiki($channel_id,$observer_hash,$resource_id) {
$w = self::get_wiki($channel_id,$observer_hash,$resource_id);
if(! $w['wiki']) {
return [ 'success' => false ];
}
else {
$r = q("SELECT id FROM item WHERE uid = %s AND resource_id = '%s'",
intval($channel_id),
dbesc($resource_id)
);
$ids = array_column($r, 'id');
drop_items($ids, true, DROPITEM_PHASE1);
info(t('Wiki files deleted successfully'));
return [ 'success' => true ];
}
}
public static function get_wiki($channel_id, $observer_hash, $resource_id) {
$sql_extra = item_permissions_sql($channel_id,$observer_hash);
$item = q("SELECT * FROM item WHERE uid = %d AND resource_type = '%s' AND resource_id = '%s' AND item_deleted = 0
$sql_extra ORDER BY id LIMIT 1",
intval($channel_id),
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
dbesc($resource_id)
);
if(! $item) {
return [ 'wiki' => null ];
}
else {
$w = $item[0]; // wiki item table record
// Get wiki metadata
$rawName = get_iconfig($w, 'wiki', 'rawName');
$mimeType = get_iconfig($w, 'wiki', 'mimeType');
$typelock = get_iconfig($w, 'wiki', 'typelock');
return array(
'wiki' => $w,
'rawName' => $rawName,
'htmlName' => escape_tags($rawName),
//'urlName' => urlencode(urlencode($rawName)),
'urlName' => self::name_encode($rawName),
'mimeType' => $mimeType,
'typelock' => $typelock
);
}
}
public static function exists_by_name($uid, $urlName) {
$sql_extra = item_permissions_sql($uid);
$item = q("SELECT item.id, resource_id FROM item left join iconfig on iconfig.iid = item.id
WHERE resource_type = '%s' AND iconfig.v = '%s' AND uid = %d
AND item_deleted = 0 $sql_extra limit 1",
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
//dbesc(urldecode($urlName)),
dbesc(self::name_decode($urlName)),
intval($uid)
);
if($item) {
return array('id' => $item[0]['id'], 'resource_id' => $item[0]['resource_id']);
}
else {
return array('id' => null, 'resource_id' => null);
}
}
public static function get_permissions($resource_id, $owner_id, $observer_hash) {
// TODO: For now, only the owner can edit
$sql_extra = item_permissions_sql($owner_id, $observer_hash);
if(local_channel() && local_channel() == $owner_id) {
return [ 'read' => true, 'write' => true, 'success' => true ];
}
$r = q("SELECT * FROM item WHERE uid = %d and resource_type = '%s' AND resource_id = '%s' $sql_extra LIMIT 1",
intval($owner_id),
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
dbesc($resource_id)
);
if(! $r) {
return array('read' => false, 'write' => false, 'success' => true);
}
else {
// TODO: Create a new permission setting for wiki analogous to webpages. Until
// then, use webpage permissions
$write = perm_is_allowed($owner_id, $observer_hash,'write_wiki');
return array('read' => true, 'write' => $write, 'success' => true);
}
}
public static function name_encode ($string) {
$string = html_entity_decode($string);
$encoding = mb_internal_encoding();
mb_internal_encoding("UTF-8");
$ret = mb_ereg_replace_callback ('[^A-Za-z0-9\-\_\.\~]',function ($char) {
$charhex = unpack('H*',$char[0]);
$ret = '('.$charhex[1].')';
return $ret;
}
,$string);
mb_internal_encoding($encoding);
return $ret;
}
public static function name_decode ($string) {
$encoding = mb_internal_encoding();
mb_internal_encoding("UTF-8");
$ret = mb_ereg_replace_callback ('(\(([0-9a-f]+)\))',function ($chars) {
return pack('H*',$chars[2]);
}
,$string);
mb_internal_encoding($encoding);
return $ret;
}
}

View File

@@ -1,718 +0,0 @@
<?php
namespace Zotlabs\Lib;
use \Zotlabs\Lib as Zlib;
class NativeWikiPage {
static public function page_list($channel_id,$observer_hash, $resource_id) {
// TODO: Create item table records for pages so that metadata like title can be applied
$w = Zlib\NativeWiki::get_wiki($channel_id,$observer_hash,$resource_id);
$pages[] = [
'resource_id' => '',
'title' => 'Home',
'url' => 'Home',
'link_id' => 'id_wiki_home_0'
];
$sql_extra = item_permissions_sql($channel_id,$observer_hash);
$r = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s' and uid = %d and item_deleted = 0
$sql_extra order by title asc",
dbesc($resource_id),
intval($channel_id)
);
if($r) {
$x = [];
$y = [];
foreach($r as $rv) {
if(! in_array($rv['mid'],$x)) {
$y[] = $rv;
$x[] = $rv['mid'];
}
}
$items = fetch_post_tags($y,true);
foreach($items as $page_item) {
$title = get_iconfig($page_item['id'],'nwikipage','pagetitle',t('(No Title)'));
if(urldecode($title) !== 'Home') {
$pages[] = [
'resource_id' => $resource_id,
'title' => escape_tags($title),
//'url' => str_replace('%2F','/',urlencode(str_replace('%2F','/',urlencode($title)))),
'url' => Zlib\NativeWiki::name_encode($title),
'link_id' => 'id_' . substr($resource_id, 0, 10) . '_' . $page_item['id']
];
}
}
}
return array('pages' => $pages, 'wiki' => $w);
}
static public function create_page($channel_id, $observer_hash, $name, $resource_id, $mimetype = 'text/bbcode') {
logger('mimetype: ' . $mimetype);
if(! in_array($mimetype,[ 'text/markdown','text/bbcode','text/plain','text/html' ]))
$mimetype = 'text/markdown';
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
if (! $w['wiki']) {
return array('content' => null, 'message' => 'Error reading wiki', 'success' => false);
}
// backslashes won't work well in the javascript functions
$name = str_replace('\\','',$name);
// create an empty activity
$arr = [];
$arr['uid'] = $channel_id;
$arr['author_xchan'] = $observer_hash;
$arr['mimetype'] = $mimetype;
$arr['title'] = $name;
$arr['resource_type'] = 'nwikipage';
$arr['resource_id'] = $resource_id;
$arr['allow_cid'] = $w['wiki']['allow_cid'];
$arr['allow_gid'] = $w['wiki']['allow_gid'];
$arr['deny_cid'] = $w['wiki']['deny_cid'];
$arr['deny_gid'] = $w['wiki']['deny_gid'];
$arr['public_policy'] = map_scope(\Zotlabs\Access\PermissionLimits::Get($channel_id,'view_wiki'),true);
// We may wish to change this some day.
$arr['item_unpublished'] = 1;
set_iconfig($arr,'nwikipage','pagetitle',(($name) ? $name : t('(No Title)')),true);
$p = post_activity_item($arr, false, false);
if($p['item_id']) {
$page = [
'rawName' => $name,
'htmlName' => escape_tags($name),
//'urlName' => urlencode($name),
'urlName' => Zlib\NativeWiki::name_encode($name)
];
return array('page' => $page, 'item_id' => $p['item_id'], 'item' => $p['activity'], 'wiki' => $w, 'message' => '', 'success' => true);
}
return [ 'success' => false, 'message' => t('Wiki page create failed.') ];
}
static public function rename_page($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
$pageNewName = ((array_key_exists('pageNewName',$arr)) ? $arr['pageNewName'] : '');
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
if(! $w['wiki']) {
return array('message' => t('Wiki not found.'), 'success' => false);
}
$ic = q("select * from iconfig left join item on iconfig.iid = item.id
where uid = %d and cat = 'nwikipage' and k = 'pagetitle' and v = '%s'",
intval($channel_id),
dbesc($pageNewName)
);
if($ic) {
return [ 'success' => false, 'message' => t('Destination name already exists') ];
}
$ids = [];
$ic = q("select *, item.id as item_id from iconfig left join item on iconfig.iid = item.id
where uid = %d and cat = 'nwikipage' and k = 'pagetitle' and v = '%s'",
intval($channel_id),
dbesc($pageUrlName)
);
if($ic) {
foreach($ic as $c) {
set_iconfig($c['item_id'],'nwikipage','pagetitle',$pageNewName);
$ids[] = $c['item_id'];
}
$str_ids = implode(',', $ids);
q("update item set title = '%s' where id in ($str_ids)",
dbesc($pageNewName)
);
$page = [
'rawName' => $pageNewName,
'htmlName' => escape_tags($pageNewName),
//'urlName' => urlencode(escape_tags($pageNewName))
'urlName' => Zlib\NativeWiki::name_encode($pageNewName)
];
return [ 'success' => true, 'page' => $page ];
}
return [ 'success' => false, 'message' => t('Page not found') ];
}
static public function get_page_content($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
$channel_id = ((array_key_exists('channel_id',$arr)) ? intval($arr['channel_id']) : 0);
$revision = ((array_key_exists('revision',$arr)) ? intval($arr['revision']) : (-1));
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
if (! $w['wiki']) {
return array('content' => null, 'message' => 'Error reading wiki', 'success' => false);
}
$item = self::load_page($arr);
if($item) {
$content = $item['body'];
return [
'content' => $content,
'mimeType' => $w['mimeType'],
'pageMimeType' => $item['mimetype'],
'message' => '',
'success' => true
];
}
return array('content' => null, 'message' => t('Error reading page content'), 'success' => false);
}
static public function page_history($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
if (!$w['wiki']) {
return array('history' => null, 'message' => 'Error reading wiki', 'success' => false);
}
$items = self::load_page_history($arr);
$history = [];
if($items) {
$processed = 0;
foreach($items as $item) {
if($processed > 1000)
break;
$processed ++;
$history[] = [
'revision' => $item['revision'],
'date' => datetime_convert('UTC',date_default_timezone_get(),$item['edited']),
'name' => $item['author']['xchan_name'],
'title' => get_iconfig($item,'nwikipage','commit_msg')
];
}
return [ 'success' => true, 'history' => $history ];
}
return [ 'success' => false ];
}
static public function load_page($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
$revision = ((array_key_exists('revision',$arr)) ? $arr['revision'] : (-1));
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
if (! $w['wiki']) {
return array('content' => null, 'message' => 'Error reading wiki', 'success' => false);
}
$ids = '';
$ic = q("select * from iconfig left join item on iconfig.iid = item.id where uid = %d and cat = 'nwikipage' and k = 'pagetitle' and v = '%s'",
intval($channel_id),
dbesc($pageUrlName)
);
if($ic) {
foreach($ic as $c) {
if($ids)
$ids .= ',';
$ids .= intval($c['iid']);
}
}
$sql_extra = item_permissions_sql($channel_id,$observer_hash);
if($revision == (-1))
$sql_extra .= " order by revision desc ";
elseif($revision)
$sql_extra .= " and revision = " . intval($revision) . " ";
$r = null;
if($ids) {
$r = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s' and uid = %d and id in ( $ids ) $sql_extra limit 1",
dbesc($resource_id),
intval($channel_id)
);
if($r) {
$items = fetch_post_tags($r,true);
return $items[0];
}
}
return null;
}
static public function load_page_history($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
$revision = ((array_key_exists('revision',$arr)) ? $arr['revision'] : (-1));
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
if (! $w['wiki']) {
return array('content' => null, 'message' => 'Error reading wiki', 'success' => false);
}
$ids = '';
$ic = q("select * from iconfig left join item on iconfig.iid = item.id where uid = %d and cat = 'nwikipage' and k = 'pagetitle' and v = '%s'",
intval($channel_id),
dbesc($pageUrlName)
);
if($ic) {
foreach($ic as $c) {
if($ids)
$ids .= ',';
$ids .= intval($c['iid']);
}
}
$sql_extra = item_permissions_sql($channel_id,$observer_hash);
$sql_extra .= " order by revision desc ";
$r = null;
if($ids) {
$r = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s' and uid = %d and id in ( $ids ) and item_deleted = 0 $sql_extra",
dbesc($resource_id),
intval($channel_id)
);
if($r) {
xchan_query($r);
$items = fetch_post_tags($r,true);
return $items;
}
}
return null;
}
static public function save_page($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
$content = ((array_key_exists('content',$arr)) ? $arr['content'] : '');
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
$revision = ((array_key_exists('revision',$arr)) ? $arr['revision'] : 0);
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
if (!$w['wiki']) {
return array('message' => t('Error reading wiki'), 'success' => false);
}
// fetch the most recently saved revision.
$item = self::load_page($arr);
if(! $item) {
return array('message' => t('Page not found'), 'success' => false);
}
$mimetype = $item['mimetype'];
// change just the fields we need to change to create a revision;
unset($item['id']);
unset($item['author']);
$item['parent'] = 0;
$item['body'] = $content;
$item['author_xchan'] = $observer_hash;
$item['revision'] = (($arr['revision']) ? intval($arr['revision']) + 1 : intval($item['revision']) + 1);
$item['edited'] = datetime_convert();
$item['mimetype'] = $mimetype;
if($item['iconfig'] && is_array($item['iconfig']) && count($item['iconfig'])) {
for($x = 0; $x < count($item['iconfig']); $x ++) {
unset($item['iconfig'][$x]['id']);
unset($item['iconfig'][$x]['iid']);
}
}
$ret = item_store($item, false, false);
if($ret['item_id'])
return array('message' => '', 'item_id' => $ret['item_id'], 'filename' => $pageUrlName, 'success' => true);
else
return array('message' => t('Page update failed.'), 'success' => false);
}
static public function delete_page($arr) {
$pageUrlName = (array_key_exists('pageUrlName',$arr) ? $arr['pageUrlName'] : '');
$resource_id = (array_key_exists('resource_id',$arr) ? $arr['resource_id'] : '');
$observer_hash = (array_key_exists('observer_hash',$arr) ? $arr['observer_hash'] : '');
$channel_id = (array_key_exists('channel_id',$arr) ? $arr['channel_id'] : 0);
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
if(! $w['wiki']) {
return [ 'success' => false, 'message' => t('Error reading wiki') ];
}
$ids = [];
$ic = q("select * from iconfig left join item on iconfig.iid = item.id
where uid = %d and cat = 'nwikipage' and k = 'pagetitle' and v = '%s'",
intval($channel_id),
dbesc($pageUrlName)
);
if($ic) {
foreach($ic as $c) {
$ids[] = intval($c['iid']);
}
}
if($ids) {
drop_items($ids, true, DROPITEM_PHASE1);
return [ 'success' => true ];
}
return [ 'success' => false, 'message' => t('Nothing deleted') ];
}
static public function revert_page($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
$commitHash = ((array_key_exists('commitHash',$arr)) ? $arr['commitHash'] : null);
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
if (! $commitHash) {
return array('message' => 'No commit was provided', 'success' => false);
}
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
if (!$w['wiki']) {
return array('message' => 'Error reading wiki', 'success' => false);
}
$x = $arr;
if(intval($commitHash) > 0) {
unset($x['commitHash']);
$x['revision'] = intval($commitHash) - 1;
$loaded = self::load_page($x);
if($loaded) {
$content = $loaded['body'];
return [ 'content' => $content, 'success' => true ];
}
return [ 'success' => false ];
}
}
static public function compare_page($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
$currentCommit = ((array_key_exists('currentCommit',$arr)) ? $arr['currentCommit'] : (-1));
$compareCommit = ((array_key_exists('compareCommit',$arr)) ? $arr['compareCommit'] : 0);
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
if (!$w['wiki']) {
return array('message' => t('Error reading wiki'), 'success' => false);
}
$x = $arr;
$x['revision'] = (-1);
$currpage = self::load_page($x);
if($currpage)
$currentContent = $currpage['body'];
$x['revision'] = $compareCommit;
$comppage = self::load_page($x);
if($comppage)
$compareContent = $comppage['body'];
if($currpage && $comppage) {
require_once('library/class.Diff.php');
$diff = \Diff::toTable(\Diff::compare($currentContent, $compareContent));
return [ 'success' => true, 'diff' => $diff ];
}
return [ 'success' => false, 'message' => t('Compare: object not found.') ];
}
static public function commit($arr) {
$commit_msg = ((array_key_exists('commit_msg', $arr)) ? $arr['commit_msg'] : t('Page updated'));
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : t('Untitled'));
if(array_key_exists('resource_id', $arr)) {
$resource_id = $arr['resource_id'];
}
else {
return array('message' => t('Wiki resource_id required for git commit'), 'success' => false);
}
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
if (! $w['wiki']) {
return array('message' => t('Error reading wiki'), 'success' => false);
}
$page = self::load_page($arr);
if($page) {
set_iconfig($page['id'],'nwikipage','commit_msg',escape_tags($commit_msg),true);
return [ 'success' => true, 'item_id' => $page['id'], 'page' => $page ];
}
return [ 'success' => false, 'message' => t('Page not found.') ];
}
static public function convert_links($s, $wikiURL) {
if (strpos($s,'[[') !== false) {
preg_match_all("/\[\[(.*?)\]\]/", $s, $match);
$pages = $pageURLs = array();
foreach ($match[1] as $m) {
// TODO: Why do we need to double urlencode for this to work?
//$pageURLs[] = urlencode(urlencode(escape_tags($m)));
$titleUri = explode('|',$m);
$page = $titleUri[0] ?? '';
$title = $titleUri[1] ?? $page;
$pageURLs[] = Zlib\NativeWiki::name_encode(escape_tags($page));
$pages[] = $title;
}
$idx = 0;
while(strpos($s,'[[') !== false) {
$replace = '<a href="'.$wikiURL.'/'.$pageURLs[$idx].'">'.$pages[$idx].'</a>';
$s = preg_replace("/\[\[(.*?)\]\]/", $replace, $s, 1);
$idx++;
}
}
return $s;
}
static public function render_page_history($arr) {
$pageUrlName = ((array_key_exists('pageUrlName', $arr)) ? $arr['pageUrlName'] : '');
$resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : '');
$pageHistory = self::page_history([
'channel_id' => \App::$profile_uid,
'observer_hash' => get_observer_hash(),
'resource_id' => $resource_id,
'pageUrlName' => $pageUrlName
]);
return replace_macros(get_markup_template('nwiki_page_history.tpl'), array(
'$pageHistory' => $pageHistory['history'],
'$permsWrite' => $arr['permsWrite'],
'$name_lbl' => t('Name'),
'$msg_label' => t('Message','wiki_history'),
'$date_lbl' => t('Date'),
'$revert_btn' => t('Revert'),
'$compare_btn' => t('Compare')
));
}
/**
* Replace the instances of the string [toc] with a list element that will be populated by
* a table of contents by the JavaScript library
* @param string $s
* @return string
*/
static public function generate_toc($s) {
if (strpos($s,'[toc]') !== false) {
//$toc_md = wiki_toc($s); // Generate Markdown-formatted list prior to HTML render
$toc_md = '<ul id="wiki-toc"></ul>'; // use the available jQuery plugin http://ndabas.github.io/toc/
$s = preg_replace("/\[toc\]/", $toc_md, $s, -1);
}
return $s;
}
/**
* Converts a select set of bbcode tags. Much of the code is copied from include/bbcode.php
* @param string $s
* @return string
*/
static public function bbcode($s) {
$s = str_replace(array('[baseurl]', '[sitename]'), array(z_root(), get_config('system', 'sitename')), $s);
$s = preg_replace_callback("/\[observer\.language\=(.*?)\](.*?)\[\/observer\]/ism",'oblanguage_callback', $s);
$s = preg_replace_callback("/\[observer\.language\!\=(.*?)\](.*?)\[\/observer\]/ism",'oblanguage_necallback', $s);
$observer = \App::get_observer();
if ($observer) {
$s1 = '<span class="bb_observer" title="' . t('Different viewers will see this text differently') . '">';
$s2 = '</span>';
$obsBaseURL = $observer['xchan_connurl'];
$obsBaseURL = preg_replace("/\/poco\/.*$/", '', $obsBaseURL);
$s = str_replace('[observer.baseurl]', $obsBaseURL, $s);
$s = str_replace('[observer.url]', $observer['xchan_url'], $s);
$s = str_replace('[observer.name]', $s1 . $observer['xchan_name'] . $s2, $s);
$s = str_replace('[observer.address]', $s1 . $observer['xchan_addr'] . $s2, $s);
$s = str_replace('[observer.webname]', substr($observer['xchan_addr'], 0, strpos($observer['xchan_addr'], '@')), $s);
$s = str_replace('[observer.photo]', '', $s);
}
else {
$s = str_replace('[observer.baseurl]', '', $s);
$s = str_replace('[observer.url]', '', $s);
$s = str_replace('[observer.name]', '', $s);
$s = str_replace('[observer.address]', '', $s);
$s = str_replace('[observer.webname]', '', $s);
$s = str_replace('[observer.photo]', '', $s);
}
return $s;
}
static public function get_file_ext($arr) {
if($arr['mimetype'] === 'text/bbcode')
return '.bb';
elseif($arr['mimetype'] === 'text/markdown')
return '.md';
elseif($arr['mimetype'] === 'text/plain')
return '.txt';
}
// This function is derived from
// http://stackoverflow.com/questions/32068537/generate-table-of-contents-from-markdown-in-php
static public function toc($content) {
// ensure using only "\n" as line-break
$source = str_replace(["\r\n", "\r"], "\n", $content);
// look for markdown TOC items
preg_match_all(
'/^(?:=|-|#).*$/m',
$source,
$matches,
PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE
);
// preprocess: iterate matched lines to create an array of items
// where each item is an array(level, text)
$file_size = strlen($source);
foreach ($matches[0] as $item) {
$found_mark = substr($item[0], 0, 1);
if ($found_mark == '#') {
// text is the found item
$item_text = $item[0];
$item_level = strrpos($item_text, '#') + 1;
$item_text = substr($item_text, $item_level);
} else {
// text is the previous line (empty if <hr>)
$item_offset = $item[1];
$prev_line_offset = strrpos($source, "\n", -($file_size - $item_offset + 2));
$item_text =
substr($source, $prev_line_offset, $item_offset - $prev_line_offset - 1);
$item_text = trim($item_text);
$item_level = $found_mark == '=' ? 1 : 2;
}
if (!trim($item_text) OR strpos($item_text, '|') !== FALSE) {
// item is an horizontal separator or a table header, don't mind
continue;
}
$raw_toc[] = ['level' => $item_level, 'text' => trim($item_text)];
}
$o = '';
foreach($raw_toc as $t) {
$level = intval($t['level']);
$text = $t['text'];
switch ($level) {
case 1:
$li = '* ';
break;
case 2:
$li = ' * ';
break;
case 3:
$li = ' * ';
break;
case 4:
$li = ' * ';
break;
default:
$li = '* ';
break;
}
$o .= $li . $text . "\n";
}
return $o;
}
}

View File

@@ -2,6 +2,8 @@
namespace Zotlabs\Lib;
use App;
/**
* @brief Class for handling channel specific configurations.
*
@@ -32,15 +34,15 @@ class PConfig {
if(is_null($uid) || $uid === false)
return false;
if(! is_array(\App::$config)) {
if(! is_array(App::$config)) {
btlogger('App::$config not an array');
}
if(! array_key_exists($uid, \App::$config)) {
\App::$config[$uid] = array();
if(! array_key_exists($uid, App::$config)) {
App::$config[$uid] = array();
}
if(! is_array(\App::$config[$uid])) {
if(! is_array(App::$config[$uid])) {
btlogger('App::$config[$uid] not an array: ' . $uid);
}
@@ -52,12 +54,12 @@ class PConfig {
foreach($r as $rr) {
$k = $rr['k'];
$c = $rr['cat'];
if(! array_key_exists($c, \App::$config[$uid])) {
\App::$config[$uid][$c] = array();
\App::$config[$uid][$c]['config_loaded'] = true;
if(! array_key_exists($c, App::$config[$uid])) {
App::$config[$uid][$c] = array();
App::$config[$uid][$c]['config_loaded'] = true;
}
\App::$config[$uid][$c][$k] = $rr['v'];
\App::$config[$uid][$c]['pcfgud:'.$k] = $rr['updated'];
App::$config[$uid][$c][$k] = $rr['v'];
App::$config[$uid][$c]['pcfgud:'.$k] = $rr['updated'];
}
}
}
@@ -86,15 +88,15 @@ class PConfig {
if(is_null($uid) || $uid === false)
return $default;
if(! array_key_exists($uid, \App::$config))
if(! array_key_exists($uid, App::$config))
self::Load($uid);
if((! array_key_exists($family, \App::$config[$uid])) || (! array_key_exists($key, \App::$config[$uid][$family])))
if((! array_key_exists($family, App::$config[$uid])) || (! array_key_exists($key, App::$config[$uid][$family])))
return $default;
return ((! is_array(\App::$config[$uid][$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', \App::$config[$uid][$family][$key]))
? unserialize(\App::$config[$uid][$family][$key])
: \App::$config[$uid][$family][$key]
return ((! is_array(App::$config[$uid][$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', App::$config[$uid][$family][$key]))
? unserialize(App::$config[$uid][$family][$key])
: App::$config[$uid][$family][$key]
);
}
@@ -133,6 +135,7 @@ class PConfig {
$dbvalue = ((is_array($value)) ? serialize($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
$new = false;
$update = false;
$now = datetime_convert();
if (! $updated) {
@@ -143,23 +146,22 @@ class PConfig {
$updated = datetime_convert('UTC','UTC','-2 seconds');
}
$hash = hash('sha256',$family.':'.$key);
$hash = gen_link_id($family.':'.$key);
if (self::Get($uid, 'hz_delpconfig', $hash) !== false) {
if (self::Get($uid, 'hz_delpconfig', $hash) > $now) {
logger('Refusing to update pconfig with outdated info (Item deleted more recently).', LOGGER_NORMAL, LOG_ERR);
return self::Get($uid,$family,$key);
} else {
self::Delete($uid,'hz_delpconfig',$hash);
self::Delete($uid, 'hz_delpconfig', $hash);
}
}
if(self::Get($uid, $family, $key) === false) {
if(! array_key_exists($uid, \App::$config))
\App::$config[$uid] = array();
if(! array_key_exists($family, \App::$config[$uid]))
\App::$config[$uid][$family] = array();
if(! array_key_exists($uid, App::$config))
App::$config[$uid] = array();
if(! array_key_exists($family, App::$config[$uid]))
App::$config[$uid][$family] = array();
$ret = q("INSERT INTO pconfig ( uid, cat, k, v, updated ) VALUES ( %d, '%s', '%s', '%s', '%s' ) ",
intval($uid),
@@ -177,13 +179,14 @@ class PConfig {
logger("Error: Insert to pconfig failed.",LOGGER_NORMAL, LOG_ERR);
}
\App::$config[$uid][$family]['pcfgud:'.$key] = $updated;
$new = true;
App::$config[$uid][$family]['pcfgud:'.$key] = $updated;
}
else {
$new = (\App::$config[$uid][$family]['pcfgud:'.$key] < $now);
$update = (App::$config[$uid][$family]['pcfgud:'.$key] < $now);
if ($new) {
if ($update) {
// @NOTE There is still a possible race condition under limited circumstances
// where a value will be updated by another thread with more current data than
@@ -198,7 +201,7 @@ class PConfig {
dbesc($key)
);
\App::$config[$uid][$family]['pcfgud:'.$key] = $updated;
App::$config[$uid][$family]['pcfgud:'.$key] = $updated;
} else {
logger('Refusing to update pconfig with outdated info.', LOGGER_NORMAL, LOG_ERR);
@@ -211,16 +214,16 @@ class PConfig {
// set in the life of this page. We need this to
// synchronise channel clones.
if(! array_key_exists('transient', \App::$config[$uid]))
\App::$config[$uid]['transient'] = array();
if(! array_key_exists($family, \App::$config[$uid]['transient']))
\App::$config[$uid]['transient'][$family] = array();
if(! array_key_exists('transient', App::$config[$uid]))
App::$config[$uid]['transient'] = array();
if(! array_key_exists($family, App::$config[$uid]['transient']))
App::$config[$uid]['transient'][$family] = array();
\App::$config[$uid][$family][$key] = $value;
App::$config[$uid][$family][$key] = $value;
if ($new) {
\App::$config[$uid]['transient'][$family][$key] = $value;
\App::$config[$uid]['transient'][$family]['pcfgud:'.$key] = $updated;
if ($new || $update) {
App::$config[$uid]['transient'][$family][$key] = $value;
App::$config[$uid]['transient'][$family]['pcfgud:'.$key] = $updated;
}
if($ret)
@@ -253,7 +256,7 @@ class PConfig {
$updated = ($updated) ? $updated : datetime_convert('UTC','UTC','-2 seconds');
$now = datetime_convert();
$newer = (\App::$config[$uid][$family]['pcfgud:'.$key] < $now);
$newer = (App::$config[$uid][$family]['pcfgud:'.$key] < $now);
if (! $newer) {
logger('Refusing to delete pconfig with outdated delete request.', LOGGER_NORMAL, LOG_ERR);
@@ -262,12 +265,12 @@ class PConfig {
$ret = false;
if (isset(\App::$config[$uid][$family][$key])) {
unset(\App::$config[$uid][$family][$key]);
if (isset(App::$config[$uid][$family][$key])) {
unset(App::$config[$uid][$family][$key]);
}
if (isset(\App::$config[$uid][$family]['pcfgud:'.$key])) {
unset(\App::$config[$uid][$family]['pcfgud:'.$key]);
if (isset(App::$config[$uid][$family]['pcfgud:'.$key])) {
unset(App::$config[$uid][$family]['pcfgud:'.$key]);
}
$ret = q("DELETE FROM pconfig WHERE uid = %d AND cat = '%s' AND k = '%s'",
@@ -278,9 +281,9 @@ class PConfig {
// Synchronize delete with clones.
if ($family != 'hz_delpconfig') {
$hash = hash('sha256',$family.':'.$key);
set_pconfig($uid,'hz_delpconfig',$hash,$updated);
if ($family !== 'hz_delpconfig') {
$hash = gen_link_id($family.':'.$key);
set_pconfig($uid, 'hz_delpconfig', $hash, $updated);
}
return $ret;

View File

@@ -4,6 +4,7 @@ namespace Zotlabs\Lib;
use Zotlabs\Access\PermissionRoles;
use Zotlabs\Access\Permissions;
use Zotlabs\Daemon\Master;
/**
* @brief Permission Categories. Permission rules for various classes of connections.
@@ -38,33 +39,33 @@ class Permcat {
// first check role perms for a perms_connect setting
$role = get_pconfig($channel_id,'system','permissions_role');
if($role) {
$role = get_pconfig($channel_id, 'system', 'permissions_role');
if ($role) {
$x = PermissionRoles::role_perms($role);
if($x['perms_connect']) {
if ($x['perms_connect']) {
$perms = Permissions::FilledPerms($x['perms_connect']);
}
}
// if no role perms it may be a custom role, see if there any autoperms
if(! $perms) {
if (!$perms) {
$perms = Permissions::FilledAutoPerms($channel_id);
}
// if no autoperms it may be a custom role with manual perms
if(! $perms) {
if (!$perms) {
$r = q("select channel_hash from channel where channel_id = %d",
intval($channel_id)
);
if($r) {
if ($r) {
$x = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'my_perms'",
intval($channel_id),
dbesc($r[0]['channel_hash'])
);
if($x) {
foreach($x as $xv) {
if ($x) {
foreach ($x as $xv) {
$perms[$xv['k']] = intval($xv['v']);
}
}
@@ -73,25 +74,27 @@ class Permcat {
// nothing was found - create a filled permission array where all permissions are 0
if(! $perms) {
if (!$perms) {
$perms = Permissions::FilledPerms([]);
}
$this->permcats[] = [
'name' => 'default',
'localname' => t('default','permcat'),
'localname' => t('Default', 'permcat'),
'perms' => Permissions::Operms($perms),
'raw_perms' => $perms,
'system' => 1
];
$p = $this->load_permcats($channel_id);
if($p) {
for($x = 0; $x < count($p); $x++) {
if ($p) {
for ($x = 0; $x < count($p); $x++) {
$this->permcats[] = [
'name' => $p[$x][0],
'localname' => $p[$x][1],
'perms' => Permissions::Operms(Permissions::FilledPerms($p[$x][2])),
'raw_perms' => Permissions::FilledPerms($p[$x][2]),
'system' => intval($p[$x][3])
];
}
@@ -116,9 +119,9 @@ class Permcat {
* * \e bool \b error if $name not found in permcats true
*/
public function fetch($name) {
if($name && $this->permcats) {
foreach($this->permcats as $permcat) {
if(strcasecmp($permcat['name'], $name) === 0) {
if ($name && $this->permcats) {
foreach ($this->permcats as $permcat) {
if (strcasecmp($permcat['name'], $name) === 0) {
return $permcat;
}
}
@@ -128,31 +131,28 @@ class Permcat {
}
public function load_permcats($uid) {
/*
$permcats = [
[ 'follower', t('follower','permcat'),
[ 'view_stream','view_profile','view_contacts','view_storage','view_pages','view_wiki',
'post_like' ], 1
],
[ 'contributor', t('contributor','permcat'),
[ 'view_stream','view_profile','view_contacts','view_storage','view_pages','view_wiki',
'post_wall','post_comments','write_wiki','post_like','tag_deliver','chat' ], 1
],
[ 'publisher', t('publisher','permcat'),
[ 'contributor', t('Contributor','permcat'),
[ 'view_stream','view_profile','view_contacts','view_storage','view_pages',
'write_storage','post_wall','write_pages','write_wiki','post_comments','post_like','tag_deliver',
'chat', 'republish' ], 1
]
'write_storage','post_wall','write_pages','write_wiki','post_comments', 'post_mail', 'post_like',
'chat' ], 1
],
[ 'muted', t('Muted','permcat'),
[ 'view_stream','view_profile','view_contacts','view_storage','view_pages','view_wiki',
'post_comments','write_wiki','post_like' ], 1
],
];
if($uid) {
*/
if ($uid) {
$x = q("select * from pconfig where uid = %d and cat = 'permcat'",
intval($uid)
);
if($x) {
foreach($x as $xv) {
$value = ((preg_match('|^a:[0-9]+:{.*}$|s', $xv['v'])) ? unserialize($xv['v']) : $xv['v']);
$permcats[] = [ $xv['k'], $xv['k'], $value, 0 ];
if ($x) {
foreach ($x as $xv) {
$value = ((preg_match('|^a:[0-9]+:{.*}$|s', $xv['v'])) ? unserialize($xv['v']) : $xv['v']);
$permcats[] = [$xv['k'], $xv['k'], $value, 0];
}
}
}
@@ -167,11 +167,11 @@ class Permcat {
}
static public function find_permcat($arr, $name) {
if((! $arr) || (! $name))
if ((!$arr) || (!$name))
return false;
foreach($arr as $p)
if($p['name'] == $name)
foreach ($arr as $p)
if ($p['name'] == $name)
return $p['value'];
}
@@ -183,4 +183,105 @@ class Permcat {
PConfig::Delete($channel_id, 'permcat', $name);
}
}
/**
* @brief assign a contact role to contacts
*
* @param array $channel
* @param string $role the name of the role
* @param array $contacts an array of contact hashes
*/
public static function assign($channel, $role, $contacts) {
if (!isset($channel['channel_id'])) {
return;
}
if (!is_array($contacts) || empty($contacts)) {
return;
}
if (!$role) {
// lookup the default
$role = get_pconfig($channel['channel_id'], 'system', 'default_permcat', 'default');
}
// Doublecheck that we do not assign a role to ourself.
// It does not make a difference but could be confusing.
if (in_array($channel['channel_hash'], $contacts)) {
$contacts = array_diff($contacts, [$channel['channel_hash']]);
}
$all_perms = Permissions::Perms();
$permcats = new Permcat($channel['channel_id']);
$role_perms = $permcats->fetch($role);
if (isset($role_perms['error'])) {
return false;
}
$perms = $role_perms['raw_perms'];
$values_sql = '';
stringify_array_elms($contacts, true);
if ($all_perms && $perms) {
foreach ($contacts as $contact) {
foreach ($all_perms as $perm => $desc) {
if (array_key_exists($perm, $perms)) {
$values_sql .= " (" . intval($channel['channel_id']) . ", " . protect_sprintf($contact) . ", 'my_perms', '" . dbesc($perm) . "', " . intval($perms[$perm]) . "),";
}
else {
$values_sql .= " (" . intval($channel['channel_id']) . ", " . protect_sprintf($contact) . ", 'my_perms', '" . dbesc($perm) . "', 0), ";
}
}
}
}
$values_sql = rtrim($values_sql, ',');
dbq("DELETE FROM abconfig WHERE chan = " . intval($channel['channel_id']) . " AND cat = 'my_perms' AND xchan IN (" . protect_sprintf(implode(',', $contacts)) . ")");
dbq("INSERT INTO abconfig ( chan, xchan, cat, k, v ) VALUES $values_sql");
q("UPDATE abook SET abook_role = '%s'
WHERE abook_xchan IN (" . protect_sprintf(implode(',', $contacts)) . ") AND abook_channel = %d",
dbesc($role),
intval($channel['channel_id'])
);
$r = q("SELECT abook.*, xchan.* FROM abook LEFT JOIN xchan ON abook.abook_xchan = xchan.xchan_hash WHERE abook.abook_xchan IN (" . protect_sprintf(implode(',', $contacts)) . ") AND abook.abook_channel = %d AND abook_self = 0",
intval($channel['channel_id'])
);
foreach ($r as $rr) {
if (intval($rr['abook_self'])) {
continue;
}
Master::Summon([
'Notifier',
'permission_update',
$rr['abook_id']
]);
$clone = $rr;
unset($clone['abook_id']);
unset($clone['abook_account']);
unset($clone['abook_channel']);
$abconfig = load_abconfig($channel['channel_id'], $clone['abook_xchan']);
if ($abconfig)
$clone['abconfig'] = $abconfig;
Libsync::build_sync_packet(0 /* use the current local_channel */, ['abook' => [$clone]]);
}
return true;
}
}

View File

@@ -57,7 +57,6 @@ class Queue {
outq_priority = outq_priority + %d,
outq_scheduled = '%s'
WHERE outq_hash = '%s'",
dbesc(datetime_convert()),
intval($add_priority),
dbesc($next),
@@ -65,16 +64,38 @@ class Queue {
);
}
static function remove($id,$channel_id = 0) {
logger('queue: remove queue item ' . $id,LOGGER_DEBUG);
public static function remove($id, $channel_id = 0) {
logger('queue: remove queue item ' . $id, LOGGER_DEBUG);
$sql_extra = (($channel_id) ? " and outq_channel = " . intval($channel_id) . " " : '');
q("DELETE FROM outq WHERE outq_hash = '%s' $sql_extra",
// figure out what endpoint it is going to.
$record = q("select outq_posturl from outq where outq_hash = '%s' $sql_extra",
dbesc($id)
);
}
if ($record) {
q("DELETE FROM outq WHERE outq_hash = '%s' $sql_extra",
dbesc($id)
);
// If there's anything remaining in the queue for this site, move one of them to the next active
// queue run by setting outq_scheduled back to the present. We may be attempting to deliver it
// as a 'piled_up' delivery, but this ensures the site has an active queue entry as long as queued
// entries still exist for it. This fixes an issue where one immediate delivery left everything
// else for that site undeliverable since all the other entries had been pushed far into the future.
$r = q("SELECT outq_hash, outq_posturl FROM outq WHERE outq_posturl = '%s' LIMIT 1",
dbesc($record[0]['outq_posturl'])
);
if ($r) {
$hashes = ids_to_querystr($r, 'outq_hash', true);
$x = q("UPDATE outq SET outq_scheduled = '%s' WHERE outq_hash IN ($hashes)",
dbesc(datetime_convert())
);
}
}
}
static function remove_by_posturl($posturl) {
logger('queue: remove queue posturl ' . $posturl,LOGGER_DEBUG);
@@ -84,8 +105,6 @@ class Queue {
);
}
static function set_delivered($id,$channel = 0) {
logger('queue: set delivered ' . $id,LOGGER_DEBUG);
$sql_extra = (($channel['channel_id']) ? " and outq_channel = " . intval($channel['channel_id']) . " " : '');
@@ -110,21 +129,30 @@ class Queue {
return false;
}
$hash = $arr['hash'] ?? '';
$account_id = $arr['account_id'] ?? 0;
$channel_id = $arr['channel_id'] ?? 0;
$driver = $arr['driver'] ?? 'zot6';
$posturl = $arr['posturl'] ?? '';
$priority = $arr['priority'] ?? 0;
$notify = $arr['notify'] ?? '';
$msg = $arr['msg'] ?? '';
$x = q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_priority,
outq_created, outq_updated, outq_scheduled, outq_notify, outq_msg )
values ( '%s', %d, %d, '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s' )",
dbesc($arr['hash']),
intval($arr['account_id']),
intval($arr['channel_id']),
dbesc(($arr['driver']) ? $arr['driver'] : 'zot6'),
dbesc($arr['posturl']),
dbesc($hash),
intval($account_id),
intval($channel_id),
dbesc($driver),
dbesc($posturl),
intval(1),
intval(isset($arr['priority']) ? $arr['priority'] : 0),
intval($priority),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
dbesc($arr['notify']),
dbesc(($arr['msg']) ? $arr['msg'] : '')
dbesc($notify),
dbesc($msg)
);
return $x;
@@ -143,17 +171,19 @@ class Queue {
$y = q("select site_update, site_dead from site where site_url = '%s' ",
dbesc($base)
);
if($y) {
if(intval($y[0]['site_dead'])) {
if ($y) {
// Don't bother delivering if the site is dead.
// And if we haven't heard from the site in over a month - let them through but 3 strikes you're out.
if (intval($y[0]['site_dead']) || ($y[0]['site_update'] < datetime_convert('UTC', 'UTC', 'now - 1 month') && $outq['outq_priority'] > 20)) {
q("update dreport set dreport_result = '%s' where dreport_queue = '%s'",
dbesc('site dead'),
dbesc($outq['outq_hash'])
);
self::remove_by_posturl($outq['outq_posturl']);
logger('dead site ignored ' . $base);
return;
}
if($y[0]['site_update'] < datetime_convert('UTC','UTC','now - 1 month')) {
self::update($outq['outq_hash'], 10);
logger('immediate delivery deferred for site ' . $base);
return;
}
}
else {
@@ -195,14 +225,14 @@ class Queue {
$channel = null;
if($outq['outq_channel']) {
$channel = channelx_by_n($outq['outq_channel']);
$channel = channelx_by_n($outq['outq_channel'], true);
}
$host_crypto = null;
if($channel && $base) {
$h = q("SELECT hubloc_sitekey, site_crypto FROM hubloc LEFT JOIN site ON hubloc_url = site_url
WHERE site_url = '%s' AND hubloc_network = 'zot6' ORDER BY hubloc_id DESC LIMIT 1",
WHERE site_url = '%s' AND hubloc_network = 'zot6' AND hubloc_deleted = 0 ORDER BY hubloc_primary DESC, hubloc_id DESC LIMIT 1",
dbesc($base)
);
if($h) {
@@ -216,7 +246,7 @@ class Queue {
if($result['success']) {
logger('deliver: remote zot delivery succeeded to ' . $outq['outq_posturl']);
Libzot::process_response($outq['outq_posturl'],$result, $outq);
Libzot::process_response($outq['outq_posturl'], $result, $outq);
}
else {
logger('deliver: remote zot delivery failed to ' . $outq['outq_posturl']);

378
Zotlabs/Lib/QueueWorker.php Normal file
View File

@@ -0,0 +1,378 @@
<?php
namespace Zotlabs\Lib;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\Exception\UnableToBuildUuidException;
class QueueWorker {
public static $queueworker = null;
public static $maxworkers = 0;
public static $workermaxage = 0;
public static $workersleep = 100;
public static $default_priorities = [
'Notifier' => 10,
'Deliver' => 10,
'Cache_query' => 10,
'Content_importer' => 1,
'File_importer' => 1,
'Channel_purge' => 1,
'Directory' => 1
];
// Exceptions for processtimeout ($workermaxage) value.
// Currently the value is overriden with 3600 seconds (1h).
public static $long_running_cmd = [
'Queue',
'Expire'
];
private static function qstart() {
q('START TRANSACTION');
}
private static function qcommit() {
q("COMMIT");
}
private static function qrollback() {
q("ROLLBACK");
}
public static function Summon($argv) {
if ($argv[0] !== 'Queueworker') {
$priority = 0; // @TODO allow reprioritization
if (isset(self::$default_priorities[$argv[0]])) {
$priority = self::$default_priorities[$argv[0]];
}
$workinfo = ['argc' => count($argv), 'argv' => $argv];
$workinfo_json = json_encode($workinfo);
$uuid = self::getUuid($workinfo_json);
$r = q("SELECT * FROM workerq WHERE workerq_uuid = '%s'",
dbesc($uuid)
);
if ($r) {
logger("Summon: Ignoring duplicate workerq task", LOGGER_DEBUG);
logger(print_r($workinfo, true));
return;
}
self::qstart();
$r = q("INSERT INTO workerq (workerq_priority, workerq_data, workerq_uuid, workerq_cmd) VALUES (%d, '%s', '%s', '%s')",
intval($priority),
$workinfo_json,
dbesc($uuid),
dbesc($argv[0])
);
if (!$r) {
self::qrollback();
logger("INSERT FAILED", LOGGER_DEBUG);
return;
}
self::qcommit();
logger('INSERTED: ' . $workinfo_json, LOGGER_DEBUG);
}
$workers = self::GetWorkerCount();
if ($workers < self::$maxworkers) {
logger($workers . '/' . self::$maxworkers . ' workers active', LOGGER_DEBUG);
$phpbin = get_config('system', 'phpbin', 'php');
proc_run($phpbin, 'Zotlabs/Daemon/Master.php', ['Queueworker']);
}
}
public static function Release($argv) {
if ($argv[0] !== 'Queueworker') {
$priority = 0; // @TODO allow reprioritization
if (isset(self::$default_priorities[$argv[0]])) {
$priority = self::$default_priorities[$argv[0]];
}
$workinfo = ['argc' => count($argv), 'argv' => $argv];
$workinfo_json = json_encode($workinfo);
$uuid = self::getUuid($workinfo_json);
$r = q("SELECT * FROM workerq WHERE workerq_uuid = '%s'",
dbesc($uuid)
);
if ($r) {
logger("Release: Duplicate task - do not insert.", LOGGER_DEBUG);
logger(print_r($workinfo, true));
return;
}
self::qstart();
$r = q("INSERT INTO workerq (workerq_priority, workerq_data, workerq_uuid, workerq_cmd) VALUES (%d, '%s', '%s', '%s')",
intval($priority),
$workinfo_json,
dbesc($uuid),
dbesc($argv[0])
);
if (!$r) {
self::qrollback();
logger("Insert failed: " . $workinfo_json, LOGGER_DEBUG);
return;
}
self::qcommit();
logger('INSERTED: ' . $workinfo_json, LOGGER_DEBUG);
}
self::Process();
}
public static function GetWorkerCount() {
if (self::$maxworkers == 0) {
self::$maxworkers = get_config('queueworker', 'max_queueworkers', 4);
self::$maxworkers = self::$maxworkers > 3 ? self::$maxworkers : 4;
}
if (self::$workermaxage == 0) {
self::$workermaxage = get_config('queueworker', 'max_queueworker_age');
self::$workermaxage = self::$workermaxage > 120 ? self::$workermaxage : 300;
}
self::qstart();
// skip locked is preferred but is not supported by mariadb < 10.6 which is still used a lot - hence make it optional
$sql_quirks = ((get_config('system', 'db_skip_locked_supported')) ? 'SKIP LOCKED' : 'NOWAIT');
$r = q("SELECT workerq_id FROM workerq WHERE workerq_reservationid IS NOT NULL AND workerq_processtimeout < %s FOR UPDATE $sql_quirks",
db_utcnow()
);
if ($r) {
// TODO: some long running services store their pid in config.procid.daemon
// we could possibly check if a pid exist and check if the process is still alive
// prior to reseting workerq_reservationid
$ids = ids_to_querystr($r, 'workerq_id');
$u = dbq("update workerq set workerq_reservationid = null where workerq_id in ($ids)");
}
self::qcommit();
//q("update workerq set workerq_reservationid = null where workerq_reservationid is not null and workerq_processtimeout < %s",
//db_utcnow()
//);
//usleep(self::$workersleep);
$workers = dbq("select count(*) as total from workerq where workerq_reservationid is not null");
logger("WORKERCOUNT: " . $workers[0]['total'], LOGGER_DEBUG);
return intval($workers[0]['total']);
}
public static function GetWorkerID() {
if (self::$queueworker) {
return self::$queueworker;
}
$wid = uniqid('', true);
//usleep(mt_rand(300000, 1000000)); //Sleep .3 - 1 seconds before creating a new worker.
$workers = self::GetWorkerCount();
if ($workers >= self::$maxworkers) {
logger("Too many active workers ($workers) max = " . self::$maxworkers, LOGGER_DEBUG);
return false;
}
self::$queueworker = $wid;
return $wid;
}
private static function getWorkId() {
self::GetWorkerCount();
self::qstart();
// skip locked is preferred but is not supported by mariadb < 10.6 which is still used a lot - hence make it optional
$sql_quirks = ((get_config('system', 'db_skip_locked_supported')) ? 'SKIP LOCKED' : 'NOWAIT');
$work = dbq("SELECT workerq_id, workerq_cmd FROM workerq WHERE workerq_reservationid IS NULL ORDER BY workerq_priority DESC, workerq_id ASC LIMIT 1 FOR UPDATE $sql_quirks");
if (!$work) {
self::qrollback();
return false;
}
$id = $work[0]['workerq_id'];
$cmd = $work[0]['workerq_cmd'];
$age = self::$workermaxage;
if (in_array($cmd, self::$long_running_cmd)) {
$age = 3600; // 1h TODO: make this configurable
}
$work = q("UPDATE workerq SET workerq_reservationid = '%s', workerq_processtimeout = %s + INTERVAL %s WHERE workerq_id = %d",
self::$queueworker,
db_utcnow(),
db_quoteinterval($age . " SECOND"),
intval($id)
);
if (!$work) {
self::qrollback();
logger("Could not update workerq.", LOGGER_DEBUG);
return false;
}
logger("GOTWORK: " . json_encode($work), LOGGER_DEBUG);
self::qcommit();
return $id;
}
public static function Process() {
$sleep = intval(get_config('queueworker', 'queue_worker_sleep', 100));
$auto_queue_worker_sleep = get_config('queueworker', 'auto_queue_worker_sleep', 0);
if (!self::GetWorkerID()) {
if ($auto_queue_worker_sleep) {
set_config('queueworker', 'queue_worker_sleep', $sleep + 100);
}
logger('Unable to get worker ID. Exiting.', LOGGER_DEBUG);
killme();
}
if ($auto_queue_worker_sleep && $sleep > 100) {
$next_sleep = $sleep - 100;
set_config('queueworker', 'queue_worker_sleep', (($next_sleep < 100) ? 100 : $next_sleep));
}
$jobs = 0;
$workid = self::getWorkId();
$load_average_sleep = false;
self::$workersleep = $sleep;
self::$workersleep = ((intval(self::$workersleep) > 100) ? intval(self::$workersleep) : 100);
if (function_exists('sys_getloadavg') && get_config('queueworker', 'load_average_sleep')) {
// very experimental!
$load_average_sleep = true;
}
while ($workid) {
if ($load_average_sleep) {
$load_average = sys_getloadavg();
self::$workersleep = intval($load_average[0]) * 10000;
if (!self::$workersleep) {
self::$workersleep = 100;
}
}
logger('queue_worker_sleep: ' . self::$workersleep, LOGGER_DEBUG);
usleep(self::$workersleep);
$workitem = dbq("SELECT * FROM workerq WHERE workerq_id = $workid");
if ($workitem) {
// At least SOME work to do.... in case there's more, let's ramp up workers.
$workers = self::GetWorkerCount();
if ($workers < self::$maxworkers) {
logger($workers . '/' . self::$maxworkers . ' workers active', LOGGER_DEBUG);
$phpbin = get_config('system', 'phpbin', 'php');
proc_run($phpbin, 'Zotlabs/Daemon/Master.php', ['Queueworker']);
}
$jobs++;
logger("Workinfo: " . $workitem[0]['workerq_data'], LOGGER_DEBUG);
$workinfo = json_decode($workitem[0]['workerq_data'], true);
$argv = $workinfo['argv'];
$cls = '\\Zotlabs\\Daemon\\' . $argv[0];
$argv = flatten_array_recursive($argv);
$argc = count($argv);
$rnd = random_string();
logger('PROCESSING: ' . $rnd . ' ' . print_r($argv[0], true));
$cls::run($argc, $argv);
logger('COMPLETED: ' . $rnd);
// @FIXME: Right now we assume that if we get a return, everything is OK.
// At some point we may want to test whether the run returns true/false
// and requeue the work to be tried again if needed. But we probably want
// to implement some sort of "retry interval" first.
dbq("delete from workerq where workerq_id = $workid");
}
else {
logger("NO WORKITEM!", LOGGER_DEBUG);
}
$workid = self::getWorkId();
}
logger('Master: Worker Thread: queue items processed:' . $jobs, LOGGER_DEBUG);
}
public static function ClearQueue() {
$work = q("select * from workerq");
while ($work) {
foreach ($work as $workitem) {
$workinfo = json_decode($workitem['v'], true);
$argc = $workinfo['argc'];
$argv = $workinfo['argv'];
logger('Master: process: ' . print_r($argv, true), LOGGER_ALL, LOG_DEBUG);
if (!isset($argv[0])) {
q("delete from workerq where workerq_id = %d",
$work[0]['workerq_id']
);
continue;
}
$cls = '\\Zotlabs\\Daemon\\' . $argv[0];
$cls::run($argc, $argv);
q("delete from workerq where workerq_id = %d",
$work[0]['workerq_id']
);
//Give the server .3 seconds to catch its breath between tasks.
//This will hopefully keep it from crashing to it's knees entirely
//if the last task ended up initiating other parallel processes
//(eg. polling remotes)
usleep(300000);
}
//Make sure nothing new came in
$work = q("select * from workerq");
}
}
/**
* @brief Generate a name-based v5 UUID with custom namespace
*
* @param string $data
* @return string $uuid
*/
private static function getUuid(string $data) {
$namespace = '3a112e42-f147-4ccf-a78b-f6841339ea2a';
try {
$uuid = Uuid::uuid5($namespace, $data)->toString();
} catch (UnableToBuildUuidException $e) {
logger('UUID generation failed');
return '';
}
return $uuid;
}
}

View File

@@ -16,13 +16,13 @@ class System {
}
static public function get_site_name() {
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['sitename'])
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['sitename']))
return \App::$config['system']['sitename'];
return '';
}
static public function get_project_version() {
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['hide_version'])
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['hide_version']))
return '';
if(is_array(\App::$config) && is_array(\App::$config['system']) && array_key_exists('std_version',\App::$config['system']))
return \App::$config['system']['std_version'];
@@ -31,33 +31,33 @@ class System {
}
static public function get_update_version() {
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['hide_version'])
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['hide_version']))
return '';
return DB_UPDATE_VERSION;
}
static public function get_notify_icon() {
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['email_notify_icon_url'])
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['email_notify_icon_url']))
return \App::$config['system']['email_notify_icon_url'];
return z_root() . DEFAULT_NOTIFY_ICON;
}
static public function get_site_icon() {
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['site_icon_url'])
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['site_icon_url']))
return \App::$config['system']['site_icon_url'];
return z_root() . DEFAULT_PLATFORM_ICON ;
}
static public function get_project_link() {
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['project_link'])
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['project_link']))
return \App::$config['system']['project_link'];
return 'https://hubzilla.org';
}
static public function get_project_srclink() {
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['project_srclink'])
if(is_array(\App::$config) && is_array(\App::$config['system']) && isset(\App::$config['system']['project_srclink']))
return \App::$config['system']['project_srclink'];
return 'https://framagit.org/hubzilla/core.git';
}
@@ -68,7 +68,7 @@ class System {
static public function get_zot_revision() {
$x = [ 'revision' => ZOT_REVISION ];
$x = [ 'revision' => ZOT_REVISION ];
call_hooks('zot_revision',$x);
return $x['revision'];
}

View File

@@ -2,7 +2,9 @@
namespace Zotlabs\Lib;
use App;
use Zotlabs\Lib\Apps;
use Zotlabs\Access\AccessList;
require_once('include/text.php');
@@ -58,6 +60,9 @@ class ThreadItem {
$child = new ThreadItem($item);
$this->add_child($child);
}
// performance: we have already added the children
unset($this->data['children']);
}
// allow a site to configure the order and content of the reaction emoji list
@@ -79,10 +84,8 @@ class ThreadItem {
public function get_template_data($conv_responses, $thread_level=1, $conv_flags = []) {
$result = array();
$item = $this->get_data();
$result = [];
$item = $this->get_data();
$commentww = '';
$sparkle = '';
$buttons = '';
@@ -93,16 +96,30 @@ class ThreadItem {
$is_item = false;
$osparkle = '';
$total_children = $this->count_descendants();
$unseen_comments = (($item['real_uid']) ? 0 : $this->count_unseen_descendants());
$unseen_comments = ((isset($item['real_uid']) && $item['real_uid']) ? 0 : $this->count_unseen_descendants());
$conv = $this->get_conversation();
$observer = $conv->get_observer();
$lock = (((intval($item['item_private'])) || (($item['uid'] == local_channel()) && (strlen($item['allow_cid']) || strlen($item['allow_gid'])
|| strlen($item['deny_cid']) || strlen($item['deny_gid']))))
? t('Private Message')
$acl = new AccessList(false);
$acl->set($item);
$lock = ((intval($item['item_private']) || ($item['uid'] == local_channel() && $acl->is_private()))
? t('Restricted message')
: false);
$locktype = $item['item_private'];
// 1 = restricted message, 2 = direct message
$locktype = intval($item['item_private']);
if ($locktype === 2) {
$lock = t('Direct message');
}
// 0 = limited based on public policy
if ($item['uid'] == local_channel() && intval($item['item_private']) && !$acl->is_private() && strlen($item['public_policy'])) {
$lock = t('Public Policy');
$locktype = 0;
}
$shareable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && ($item['item_private'] != 1)) ? true : false);
@@ -110,16 +127,20 @@ class ThreadItem {
if($item['author']['xchan_network'] === 'rss')
$shareable = true;
$privacy_warning = false;
if(intval($item['item_private']) && ($item['owner']['xchan_network'] === 'activitypub')) {
$recips = get_iconfig($item['parent'], 'activitypub', 'recips');
// @fixme
// Have recently added code to properly handle polls in group reshares by redirecting all of the poll responses to the group.
// Sharing a poll using a regular embedded share is harder because the poll will need to fork. This is due to comment permissions.
// The original poll author may not accept responses from strangers. Forking the poll will receive responses from the sharer's
// followers, but there's no elegant way to merge these two sets of results together. For now, we'll disable sharing polls.
if(! is_array($recips['to']) || ! in_array($observer['xchan_url'], $recips['to']))
$privacy_warning = true;
if ($item['obj_type'] === 'Question') {
$shareable = false;
}
$privacy_warning = ($item['owner']['xchan_network'] === 'activitypub' && intval($item['item_private']) === 1);
if ($lock) {
if (($item['mid'] == $item['parent_mid']) && count(get_terms_oftype($item['term'],TERM_FORUM))) {
if (($item['mid'] == $item['parent_mid']) && isset($item['term']) && count(get_terms_oftype($item['term'], TERM_FORUM))) {
$privacy_warning = true;
$conv_flags['parent_privacy_warning'] = true;
}
@@ -133,24 +154,11 @@ class ThreadItem {
$mode = $conv->get_mode();
switch($item['item_type']) {
case ITEM_TYPE_CARD:
$edlink = 'card_edit';
break;
case ITEM_TYPE_ARTICLE:
$edlink = 'article_edit';
break;
default:
$edlink = 'editpost';
break;
}
if(local_channel() && $observer['xchan_hash'] === $item['author_xchan'])
$edpost = array(z_root() . '/' . $edlink . '/' . $item['id'], t('Edit'));
$edpost = array(z_root() . '/editpost/' . $item['id'], t('Edit'));
else
$edpost = false;
if($observer && $observer['xchan_hash']
&& ($observer['xchan_hash'] == $this->get_data_value('author_xchan')
|| $observer['xchan_hash'] == $this->get_data_value('owner_xchan')
@@ -164,7 +172,7 @@ class ThreadItem {
$dropping = false;
}
$drop = [];
if($dropping) {
$drop = array(
'dropping' => $dropping,
@@ -175,13 +183,6 @@ class ThreadItem {
$drop = [ 'dropping' => true, 'delete' => t('Admin Delete') ];
}
// FIXME
if($observer_is_pageowner) {
$multidrop = array(
'select' => t('Select'),
);
}
$filer = ((($conv->get_profile_owner() == local_channel()) && (! array_key_exists('real_uid',$item))) ? t("Save to Folder") : false);
$profile_avatar = $item['author']['xchan_photo_m'];
@@ -191,13 +192,12 @@ class ThreadItem {
$location = format_location($item);
$isevent = false;
$attend = null;
$canvote = false;
// process action responses - e.g. like/dislike/attend/agree/whatever
$response_verbs = array('like');
if(feature_enabled($conv->get_profile_owner(),'dislike'))
$response_verbs[] = 'dislike';
if($item['obj_type'] === ACTIVITY_OBJ_EVENT) {
if(in_array($item['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) {
$response_verbs[] = 'attendyes';
$response_verbs[] = 'attendno';
$response_verbs[] = 'attendmaybe';
@@ -211,17 +211,6 @@ class ThreadItem {
$response_verbs[] = 'answer';
}
$consensus = (intval($item['item_consensus']) ? true : false);
if($consensus) {
$response_verbs[] = 'agree';
$response_verbs[] = 'disagree';
$response_verbs[] = 'abstain';
if($this->is_commentable() && $observer) {
$conlabels = array( t('I agree'), t('I disagree'), t('I abstain'));
$canvote = true;
}
}
if(! feature_enabled($conv->get_profile_owner(),'dislike'))
unset($conv_responses['dislike']);
@@ -229,7 +218,8 @@ class ThreadItem {
$my_responses = [];
foreach($response_verbs as $v) {
$my_responses[$v] = (($conv_responses[$v][$item['mid'] . '-m']) ? 1 : 0);
$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']] : '');
@@ -242,6 +232,7 @@ class ThreadItem {
}
$like_button_label = tt('Like','Likes',$like_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'] : '');
@@ -252,11 +243,11 @@ class ThreadItem {
} 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']) : '');
$showdislike = ((x($conv_responses['dislike'],$item['mid']) && feature_enabled($conv->get_profile_owner(),'dislike'))
? format_like($conv_responses['dislike'][$item['mid']],$conv_responses['dislike'][$item['mid'] . '-l'],'dislike',$item['mid']) : '');
/*
* We should avoid doing this all the time, but it depends on the conversation mode
@@ -267,14 +258,11 @@ class ThreadItem {
$this->check_wall_to_wall();
if($this->is_toplevel()) {
// FIXME check this permission
if(($conv->get_profile_owner() == local_channel()) && (! array_key_exists('real_uid',$item))) {
$star = array(
if((local_channel() && $conv->get_profile_owner() === local_channel()) || (local_channel() && App::$module === 'pubstream')) {
$star = [
'toggle' => t("Toggle Star Status"),
'isstarred' => ((intval($item['item_starred'])) ? true : false),
);
];
}
}
else {
@@ -291,7 +279,7 @@ class ThreadItem {
$tagger = [];
// FIXME - check this permission
if($conv->get_profile_owner() == local_channel()) {
if(local_channel() && $conv->get_profile_owner() == local_channel()) {
/* disable until we agree on how to implemnt this in zot6/activitypub
$tagger = array(
'tagit' => t("Add Tag"),
@@ -303,7 +291,7 @@ class ThreadItem {
}
$has_bookmarks = false;
if(Apps::system_app_installed(local_channel(), 'Bookmarks') && is_array($item['term'])) {
if(Apps::system_app_installed(local_channel(), 'Bookmarks') && isset($item['term']) && is_array($item['term'])) {
foreach($item['term'] as $t) {
if(($t['ttype'] == TERM_BOOKMARK))
$has_bookmarks = true;
@@ -311,23 +299,29 @@ class ThreadItem {
}
$has_event = false;
if(($item['obj_type'] === ACTIVITY_OBJ_EVENT) && $conv->get_profile_owner() == local_channel())
if((in_array($item['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) && $conv->get_profile_owner() == local_channel())
$has_event = true;
$like = [];
$dislike = [];
$reply_to = [];
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"));
}
$share = [];
$embed = [];
if ($shareable) {
// This actually turns out not to be possible in some protocol stacks without opening up hundreds of new issues.
// Will allow it only for uri resolvable sources.
if(strpos($item['mid'],'http') === 0) {
$share = []; //Not yet ready for primetime
//Not yet ready for primetime
//$share = array( t('Repeat This'), t('repeat'));
}
$embed = array( t('Share This'), t('share'));
$embed = [t('Share This'), t('share')];
}
$dreport = '';
@@ -336,11 +330,13 @@ class ThreadItem {
if($keep_reports === 0)
$keep_reports = 10;
if((! get_config('system','disable_dreport')) && strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC',"now - $keep_reports days")) > 0) {
$dreport_link = '';
if((intval($item['item_type']) == ITEM_TYPE_POST) && (! get_config('system','disable_dreport')) && strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC',"now - $keep_reports days")) > 0) {
$dreport = t('Delivery Report');
$dreport_link = gen_link_id($item['mid']);
}
$is_new = false;
if(strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC','now - 12 hours')) > 0)
$is_new = true;
@@ -356,8 +352,8 @@ class ThreadItem {
if($conv->get_mode() === 'channel')
$viewthread = z_root() . '/channel/' . $owner_address . '?f=&mid=' . urlencode(gen_link_id($item['mid']));
$comment_count_txt = sprintf( tt('%d comment','%d comments',$total_children),$total_children );
$list_unseen_txt = (($unseen_comments) ? sprintf( t('%d unseen'),$unseen_comments) : '');
$comment_count_txt = sprintf(tt('%d Comment', '%d Comments', $total_children), $total_children);
$list_unseen_txt = (($unseen_comments) ? sprintf(t('%d unseen'), $unseen_comments) : '');
$children = $this->get_children();
@@ -384,6 +380,12 @@ class ThreadItem {
$pinned_items = ($allowed_type ? get_pconfig($item['uid'], 'pinned', $item['item_type'], []) : []);
$pinned = ((!empty($pinned_items) && in_array($midb64, $pinned_items)) ? true : false);
$contact = [];
if(App::$contacts && array_key_exists($item['author_xchan'], App::$contacts)) {
$contact = App::$contacts[$item['author_xchan']];
}
$tmp_item = array(
'template' => $this->get_template(),
'mode' => $mode,
@@ -401,11 +403,9 @@ class ThreadItem {
'mids' => $json_mids,
'parent' => $item['parent'],
'author_id' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
'author_is_group_actor' => (($item['author']['xchan_pubforum']) ? t('Forum') : ''),
'isevent' => $isevent,
'attend' => $attend,
'consensus' => $consensus,
'conlabels' => $conlabels,
'canvote' => $canvote,
'linktitle' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
'olinktitle' => (($item['owner']['xchan_addr']) ? $item['owner']['xchan_addr'] : $item['owner']['xchan_url']),
'llink' => $item['llink'],
@@ -474,7 +474,6 @@ class ThreadItem {
'bookmark' => (($conv->get_profile_owner() == local_channel() && local_channel() && $has_bookmarks) ? t('Save Bookmarks') : ''),
'addtocal' => (($has_event) ? t('Add to Calendar') : ''),
'drop' => $drop,
'multidrop' => ((feature_enabled($conv->get_profile_owner(),'multi_delete')) ? $multidrop : ''),
'dropdown_extras' => $dropdown_extras,
// end toolbar buttons
'unseen_comments' => $unseen_comments,
@@ -497,13 +496,15 @@ class ThreadItem {
'modal_dismiss' => t('Close'),
'showlike' => $showlike,
'showdislike' => $showdislike,
'comment' => ($item['item_delayed'] ? '' : $this->get_comment_box($indent)),
'comment' => ($item['item_delayed'] ? '' : $this->get_comment_box()),
'previewing' => ($conv->is_preview() ? true : false ),
'preview_lbl' => t('This is an unsaved preview'),
'wait' => t('Please wait'),
'thread_level' => $thread_level,
'settings' => $settings,
'thr_parent' => (($item['parent_mid'] != $item['thr_parent']) ? gen_link_id($item['thr_parent']) : '')
'thr_parent' => (($item['parent_mid'] != $item['thr_parent']) ? gen_link_id($item['thr_parent']) : ''),
'contact_id' => (($contact) ? $contact['abook_id'] : '')
);
$arr = array('item' => $item, 'output' => $tmp_item);
@@ -789,7 +790,7 @@ class ThreadItem {
* _ The comment box string (empty if no comment box)
* _ false on failure
*/
private function get_comment_box($indent) {
private function get_comment_box() {
if(!$this->is_toplevel() && !get_config('system','thread_allow')) {
return '';
@@ -835,7 +836,6 @@ class ThreadItem {
'$edurl' => t('Insert Link'),
'$edvideo' => t('Video'),
'$preview' => t('Preview'), // ((feature_enabled($conv->get_profile_owner(),'preview')) ? t('Preview') : ''),
'$indent' => $indent,
'$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'),

View File

@@ -4,18 +4,30 @@ namespace Zotlabs\Lib;
class ThreadListener {
public static function isEnabled() {
return Config::Get('system','enable_thread_listener');
}
static public function store($target_id,$portable_id,$ltype = 0) {
if (!self::isEnabled()) {
return true;
}
$x = self::fetch($target_id,$portable_id,$ltype = 0);
if(! $x) {
if(! $x) {
$r = q("insert into listeners ( target_id, portable_id, ltype ) values ( '%s', '%s' , %d ) ",
dbesc($target_id),
dbesc($portable_id),
intval($ltype)
);
}
}
}
static public function fetch($target_id,$portable_id,$ltype = 0) {
if (!self::isEnabled()) {
return false;
}
$x = q("select * from listeners where target_id = '%s' and portable_id = '%s' and ltype = %d limit 1",
dbesc($target_id),
dbesc($portable_id),
@@ -28,6 +40,10 @@ class ThreadListener {
}
static public function fetch_by_target($target_id,$ltype = 0) {
if (!self::isEnabled()) {
return [];
}
$x = q("select * from listeners where target_id = '%s' and ltype = %d",
dbesc($target_id),
intval($ltype)

View File

@@ -69,12 +69,12 @@ class ThreadStream {
case 'cards':
$this->profile_owner = \App::$profile['profile_uid'];
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
$this->reload = $_SESSION['return_url'];
//$this->reload = $_SESSION['return_url'];
break;
case 'articles':
$this->profile_owner = \App::$profile['profile_uid'];
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
$this->reload = $_SESSION['return_url'];
//$this->reload = $_SESSION['return_url'];
break;
case 'display':
// in this mode we set profile_owner after initialisation (from conversation()) and then

View File

@@ -52,15 +52,21 @@ class Webfinger {
if(strpos($resource,'http') === 0) {
$m = parse_url($resource);
if($m) {
if($m['scheme'] !== 'https') {
return false;
}
self::$server = $m['host'] . (($m['port']) ? ':' . $m['port'] : '');
}
else {
if (!$m) {
return false;
}
if(isset($m['scheme']) && $m['scheme'] !== 'https') {
return false;
}
if(!isset($m['host'])) {
return false;
}
self::$server = $m['host'] . ((isset($m['port'])) ? ':' . $m['port'] : '');
}
elseif(strpos($resource,'tag:') === 0) {
$arr = explode(':',$resource); // split the tag
@@ -86,7 +92,7 @@ class Webfinger {
/**
* @brief fetch a webfinger resource and return a zot6 discovery url if present
*
*/
*/
static function zot_url($resource) {

View File

@@ -162,7 +162,7 @@ class XConfig {
*/
static public function Delete($xchan, $family, $key) {
if(x(\App::$config[$xchan][$family], $key))
if(isset(\App::$config[$xchan][$family][$key]))
unset(\App::$config[$xchan][$family][$key]);
$ret = q("DELETE FROM xconfig WHERE xchan = '%s' AND cat = '%s' AND k = '%s'",

View File

@@ -87,4 +87,4 @@ class ZotURL {
return ids_to_array($r,'hubloc_url');
}
}
}

View File

@@ -6,7 +6,7 @@ use Zotlabs\Web\HTTPSig;
class Zotfinger {
static function exec($resource,$channel = null, $verify = true) {
static function exec($resource, $channel = null, $verify = true, $recurse = true) {
if(! $resource) {
return false;
@@ -39,6 +39,30 @@ class Zotfinger {
logger('fetch: ' . print_r($x,true));
if (in_array(intval($x['return_code']), [ 404, 410 ]) && $recurse) {
// The resource has been deleted or doesn't exist at this location.
// Try to find another nomadic resource for this channel and return that.
// First, see if there's a hubloc for this site. Fetch that record to
// obtain the nomadic identity hash. Then use that to find any additional
// nomadic locations.
$h = Activity::get_actor_hublocs($resource, 'zot6');
if ($h) {
// mark this location deleted
hubloc_delete($h[0]);
$hubs = Activity::get_actor_hublocs($h[0]['hubloc_hash']);
if ($hubs) {
foreach ($hubs as $hub) {
if ($hub['hubloc_id_url'] !== $resource && !$hub['hubloc_deleted']) {
return self::exec($hub['hubloc_id_url'], $channel, $verify);
}
}
}
}
}
if($x['success']) {
if ($verify) {
$result['signature'] = HTTPSig::verify($x, EMPTY_STR, 'zot6');

View File

@@ -3,9 +3,9 @@
namespace Zotlabs\Module;
use Zotlabs\Lib\Libzotdir;
use Zotlabs\Lib\AccessList;
require_once 'include/acl_selectors.php';
require_once 'include/group.php';
/**
* @brief ACL selector json backend.
@@ -66,6 +66,11 @@ class Acl extends \Zotlabs\Web\Controller {
killme();
$permitted = [];
$sql_extra = '';
$sql_extra2 = '';
$sql_extra3 = '';
$sql_extra2_xchan = '';
$order_extra2 = '';
if(in_array($type, [ 'm', 'a', 'c', 'f' ])) {
@@ -81,7 +86,6 @@ class Acl extends \Zotlabs\Web\Controller {
}
if($search) {
$sql_extra = " AND pgrp.gname LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ";
$sql_extra2 = "AND ( xchan_name LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR xchan_addr LIKE " . protect_sprintf( "'%" . dbesc(punify($search)) . ((strpos($search,'@') === false) ? "%@%'" : "%'")) . ") ";
@@ -100,10 +104,6 @@ class Acl extends \Zotlabs\Web\Controller {
$sql_extra3 = "AND ( xchan_addr like " . protect_sprintf( "'%" . dbesc(punify($search)) . "%'" ) . " OR xchan_name like " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ) ";
}
else {
$sql_extra = $sql_extra2 = $sql_extra3 = "";
}
$groups = array();
$contacts = array();
@@ -123,7 +123,7 @@ class Acl extends \Zotlabs\Web\Controller {
"name" => t('Profile','acl') . ' ' . $rv['profile_name'],
"id" => 'vp' . $rv['id'],
"xid" => 'vp.' . $rv['profile_guid'],
"uids" => group_get_profile_members_xchan(local_channel(), $rv['id']),
"uids" => AccessList::profile_members_xchan(local_channel(), $rv['id']),
"link" => ''
);
}
@@ -146,14 +146,14 @@ class Acl extends \Zotlabs\Web\Controller {
if($r) {
foreach($r as $g){
// logger('acl: group: ' . $g['gname'] . ' members: ' . group_get_members_xchan($g['id']));
// logger('acl: group: ' . $g['gname'] . ' members: ' . AccessList::members_xchan(local_channel(), $g['id']));
$groups[] = array(
"type" => "g",
"photo" => "images/twopeople.png",
"name" => $g['gname'],
"id" => $g['id'],
"xid" => $g['hash'],
"uids" => group_get_members_xchan($g['id']),
"uids" => AccessList::members_xchan(local_channel(), $g['id']),
"link" => ''
);
}
@@ -284,7 +284,7 @@ class Acl extends \Zotlabs\Web\Controller {
}
elseif($type == 'm') {
$r = array();
$z = q("SELECT xchan_hash as hash, xchan_name as name, xchan_network as net, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url
$z = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_network as net, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url, abook_self
FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel = %d
and xchan_deleted = 0
@@ -304,7 +304,7 @@ class Acl extends \Zotlabs\Web\Controller {
}
elseif($type == 'a') {
$r = q("SELECT abook_id as id, xchan_name as name, xchan_network as net, xchan_hash as hash, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url, xchan_addr as attag , abook_their_perms FROM abook left join xchan on abook_xchan = xchan_hash
$r = q("SELECT abook_id as id, xchan_name as name, xchan_network as net, xchan_hash as hash, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url, xchan_addr as attag, abook_their_perms, abook_self FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel = %d
and xchan_deleted = 0
$sql_extra3
@@ -342,7 +342,7 @@ class Acl extends \Zotlabs\Web\Controller {
$x = [];
foreach($r as $g) {
if(in_array($g['net'],['rss','anon','unknown']) && ($type != 'a'))
if(isset($g['net']) && in_array($g['net'], ['rss','anon','unknown']) && ($type != 'a'))
continue;
$g['hash'] = urlencode($g['hash']);
@@ -378,12 +378,13 @@ class Acl extends \Zotlabs\Web\Controller {
"name" => $g['name'],
"id" => urlencode($g['id']),
"xid" => $g['hash'],
"url" => $g['url'],
"link" => $clink,
"nick" => ((strpos($g['nick'],'@')) ? substr($g['nick'],0,strpos($g['nick'],'@')) : $g['nick']),
"self" => (intval($g['abook_self']) ? 'abook-self' : ''),
"taggable" => '',
"label" => '',
"net" => $g['net']
"net" => $g['net'] ?? ''
);
}
}

View File

@@ -182,7 +182,7 @@ class Activity extends Controller {
return;
}
$ob_authorise = false;
$ob_authorize = false;
$item_uid = 0;
$bear = ZlibActivity::token_from_request();

View File

@@ -77,6 +77,7 @@ class Addons {
} 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'];
@@ -111,6 +112,7 @@ class Addons {
} 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
@@ -172,6 +174,7 @@ class Addons {
$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

View File

@@ -5,11 +5,11 @@ namespace Zotlabs\Module\Admin;
class Dbsync {
function get() {
$o = '';
if(argc() > 3 && intval(argv(3)) && argv(2) === 'mark') {
// remove the old style config if it exists
del_config('database', 'update_r' . intval(argv(3)));
@@ -29,7 +29,7 @@ class Dbsync {
if(method_exists($c,'verify')) {
$retval = $c->verify();
if($retval === UPDATE_FAILED) {
$o .= sprintf( t('Verification of update %s failed. Check system logs.'), $s);
$o .= sprintf( t('Verification of update %s failed. Check system logs.'), $s);
}
elseif($retval === UPDATE_SUCCESS) {
$o .= sprintf( t('Update %s was successfully applied.'), $s);
@@ -44,20 +44,8 @@ class Dbsync {
}
else
$o .= sprintf( t('Update function %s could not be found.'), $s);
return $o;
// remove the old style config if it exists
del_config('database', 'update_r' . intval(argv(3)));
set_config('database', '_' . intval(argv(3)), 'success');
if(intval(get_config('system','db_version')) < intval(argv(3)))
set_config('system','db_version',intval(argv(3)));
info( t('Update has been marked successful') . EOL);
goaway(z_root() . '/admin/dbsync');
}
if(argc() > 2 && intval(argv(2))) {
@@ -68,7 +56,7 @@ class Dbsync {
$c = new $cls();
$retval = $c->run();
if($retval === UPDATE_FAILED) {
$o .= sprintf( t('Executing update procedure %s failed. Check system logs.'), $s);
$o .= sprintf( t('Executing update procedure %s failed. Check system logs.'), $s);
}
elseif($retval === UPDATE_SUCCESS) {
$o .= sprintf( t('Update %s was successfully applied.'), $s);
@@ -79,10 +67,10 @@ class Dbsync {
}
else
$o .= sprintf( t('Update function %s could not be found.'), $s);
return $o;
}
$failed = array();
$r = q("select * from config where cat = 'database' ");
if(count($r)) {
@@ -107,7 +95,7 @@ class Dbsync {
else {
return '<div class="generic-content-wrapper-styled"><h3>' . t('No failed updates.') . '</h3></div>';
}
return $o;
}
}
}

View File

@@ -12,23 +12,33 @@ class Queue {
$o = '';
$expert = ((array_key_exists('expert',$_REQUEST)) ? intval($_REQUEST['expert']) : 0);
$expert = $_REQUEST['expert'] ?? false;
if($_REQUEST['drophub']) {
if(isset($_REQUEST['drophub'])) {
hubloc_mark_as_down($_REQUEST['drophub']);
LibQueue::remove_by_posturl($_REQUEST['drophub']);
}
if($_REQUEST['emptyhub']) {
if(isset($_REQUEST['emptyhub'])) {
LibQueue::remove_by_posturl($_REQUEST['emptyhub']);
}
$r = q("select count(outq_posturl) as total, max(outq_priority) as priority, outq_posturl from outq
if(isset($_REQUEST['deliverhub'])) {
$hubq = q("SELECT * FROM outq WHERE outq_posturl = '%s'",
dbesc($_REQUEST['deliverhub'])
);
foreach ($hubq as $q) {
LibQueue::deliver($q, true);
}
}
$r = dbq("select count(outq_posturl) as total, max(outq_priority) as priority, outq_posturl from outq
where outq_delivered = 0 group by outq_posturl order by total desc");
for($x = 0; $x < count($r); $x ++) {
$r[$x]['eurl'] = urlencode($r[$x]['outq_posturl']);
$r[$x]['connected'] = datetime_convert('UTC',date_default_timezone_get(),$r[$x]['connected'],'Y-m-d');
}
$o = replace_macros(get_markup_template('admin_queue.tpl'), array(
@@ -37,6 +47,7 @@ class Queue {
'$priority' => t('Priority'),
'$desturl' => t('Destination URL'),
'$nukehub' => t('Mark hub permanently offline'),
'$deliverhub' => t('Retry delivery to this hub'),
'$empty' => t('Empty queue for this hub'),
'$lastconn' => t('Last known contact'),
'$hasentries' => ((count($r)) ? true : false),

View File

@@ -0,0 +1,121 @@
<?php
namespace Zotlabs\Module\Admin;
use App;
use Zotlabs\Web\Controller;
class Queueworker extends Controller {
function init() {
}
function post() {
check_form_security_token('form_security_token', 'queueworker');
$maxqueueworkers = intval($_POST['queueworker_maxworkers']);
$maxqueueworkers = ($maxqueueworkers > 3) ? $maxqueueworkers : 4;
set_config('queueworker', 'max_queueworkers', $maxqueueworkers);
$maxworkerage = intval($_POST['queueworker_max_age']);
$maxworkerage = ($maxworkerage >= 120) ? $maxworkerage : 300;
set_config('queueworker', 'queueworker_max_age', $maxworkerage);
$queueworkersleep = intval($_POST['queue_worker_sleep']);
$queueworkersleep = ($queueworkersleep > 100) ? $queueworkersleep : 100;
set_config('queueworker', 'queue_worker_sleep', $queueworkersleep);
$auto_queue_worker_sleep = intval($_POST['auto_queue_worker_sleep']);
set_config('queueworker', 'auto_queue_worker_sleep', $auto_queue_worker_sleep);
goaway(z_root() . '/admin/queueworker');
}
function get() {
$content = "<H1>Queue Status</H1>\n";
$r = q('select count(*) as total from workerq');
$content .= "<H4>There are " . $r[0]['total'] . " queue items to be processed.</H4>";
$r = dbq("select count(*) as qworkers from workerq where workerq_reservationid is not null");
$content .= "<H4>Active workers: " . $r[0]['qworkers'] . "</H4>";
$r = dbq("select workerq_cmd, count(*) as total from workerq where true group by workerq_cmd");
if ($r) {
$content .= "<H4>Work items</H4>";
foreach($r as $rr) {
$content .= $rr['workerq_cmd'] . ': ' . $rr['total'] . '<br>';
}
}
$maxqueueworkers = get_config('queueworker', 'max_queueworkers', 4);
$maxqueueworkers = ($maxqueueworkers > 3) ? $maxqueueworkers : 4;
$sc = '';
$sc .= replace_macros(get_markup_template('field_input.tpl'), [
'$field' => [
'queueworker_maxworkers',
t('Max queueworker threads'),
$maxqueueworkers,
t('Minimum 4, default 4')
]
]);
$workermaxage = get_config('queueworker', 'queueworker_max_age');
$workermaxage = ($workermaxage >= 120) ? $workermaxage : 300;
$sc .= replace_macros(get_markup_template('field_input.tpl'), [
'$field' => [
'queueworker_max_age',
t('Assume workers dead after'),
$workermaxage,
t('Minimum 120, default 300 seconds')
]
]);
$queueworkersleep = get_config('queueworker', 'queue_worker_sleep');
$queueworkersleep = ($queueworkersleep > 100) ? $queueworkersleep : 100;
$auto_queue_worker_sleep = get_config('queueworker', 'auto_queue_worker_sleep', 0);
$sc .= replace_macros(get_markup_template('field_input.tpl'), [
'$field' => [
'queue_worker_sleep',
t('Pause before starting next task'),
$queueworkersleep,
t('Minimum 100, default 100 microseconds'),
'',
(($auto_queue_worker_sleep) ? 'disabled' : '')
]
]);
$sc .= replace_macros(get_markup_template('field_checkbox.tpl'), [
'$field' => [
'auto_queue_worker_sleep',
t('Automatically adjust pause before starting next task'),
$auto_queue_worker_sleep,
]
]);
$tpl = get_markup_template('settings_addon.tpl');
$content .= replace_macros($tpl, [
'$action_url' => 'admin/queueworker',
'$form_security_token' => get_form_security_token('queueworker'),
'$title' => t('Queueworker Settings'),
'$content' => $sc,
'$baseurl' => z_root(),
'$submit' => t('Save')
]
);
return $content;
}
}

View File

@@ -7,12 +7,12 @@ class Security {
function post() {
check_form_security_token_redirectOnErr('/admin/security', 'admin_security');
$allowed_email = ((x($_POST,'allowed_email')) ? notags(trim($_POST['allowed_email'])) : '');
$not_allowed_email = ((x($_POST,'not_allowed_email')) ? notags(trim($_POST['not_allowed_email'])) : '');
set_config('system','allowed_email', $allowed_email);
set_config('system','not_allowed_email', $not_allowed_email);
set_config('system','not_allowed_email', $not_allowed_email);
$block_public = ((x($_POST,'block_public')) ? True : False);
set_config('system','block_public',$block_public);
@@ -25,22 +25,22 @@ class Security {
$ws = $this->trim_array_elems(explode("\n",$_POST['whitelisted_sites']));
set_config('system','whitelisted_sites',$ws);
$bs = $this->trim_array_elems(explode("\n",$_POST['blacklisted_sites']));
set_config('system','blacklisted_sites',$bs);
$wc = $this->trim_array_elems(explode("\n",$_POST['whitelisted_channels']));
set_config('system','whitelisted_channels',$wc);
$bc = $this->trim_array_elems(explode("\n",$_POST['blacklisted_channels']));
set_config('system','blacklisted_channels',$bc);
$embed_sslonly = ((x($_POST,'embed_sslonly')) ? True : False);
set_config('system','embed_sslonly',$embed_sslonly);
$we = $this->trim_array_elems(explode("\n",$_POST['embed_allow']));
set_config('system','embed_allow',$we);
$be = $this->trim_array_elems(explode("\n",$_POST['embed_deny']));
set_config('system','embed_deny',$be);
@@ -49,47 +49,54 @@ class Security {
$inline_pdf = ((x($_POST,'inline_pdf')) ? intval($_POST['inline_pdf']) : 0);
set_config('system', 'inline_pdf' , $inline_pdf);
$ts = ((x($_POST,'transport_security')) ? True : False);
set_config('system','transport_security_header',$ts);
$cs = ((x($_POST,'content_security')) ? True : False);
set_config('system','content_security_policy',$cs);
$trusted_directory_servers = $this->trim_array_elems(explode("\n", $_POST['trusted_directory_servers']));
set_config('system', 'trusted_directory_servers', $trusted_directory_servers);
goaway(z_root() . '/admin/security');
}
function get() {
$whitesites = get_config('system','whitelisted_sites');
$whitesites_str = ((is_array($whitesites)) ? implode("\n",$whitesites) : '');
$blacksites = get_config('system','blacklisted_sites');
$blacksites_str = ((is_array($blacksites)) ? implode("\n",$blacksites) : '');
$whitechannels = get_config('system','whitelisted_channels');
$whitechannels_str = ((is_array($whitechannels)) ? implode("\n",$whitechannels) : '');
$blackchannels = get_config('system','blacklisted_channels');
$blackchannels_str = ((is_array($blackchannels)) ? implode("\n",$blackchannels) : '');
$whiteembeds = get_config('system','embed_allow');
$whiteembeds_str = ((is_array($whiteembeds)) ? implode("\n",$whiteembeds) : '');
$blackembeds = get_config('system','embed_deny');
$blackembeds_str = ((is_array($blackembeds)) ? implode("\n",$blackembeds) : '');
$trusted_directory_servers = get_config('system', 'trusted_directory_servers');
$trusted_directory_servers_str = ((is_array($trusted_directory_servers)) ? implode("\n", $trusted_directory_servers) : '');
$is_dir = (intval(get_config('system', 'directory_mode', DIRECTORY_MODE_NORMAL)) !== DIRECTORY_MODE_NORMAL);
$embed_coop = intval(get_config('system','embed_coop'));
if((! $whiteembeds) && (! $blackembeds)) {
$embedhelp1 = t("By default, unfiltered HTML is allowed in embedded media. This is inherently insecure.");
}
$embedhelp2 = t("The recommended setting is to only allow unfiltered HTML from the following sites:");
$embedhelp2 = t("The recommended setting is to only allow unfiltered HTML from the following sites:");
$embedhelp3 = t("https://youtube.com/<br />https://www.youtube.com/<br />https://youtu.be/<br />https://vimeo.com/<br />https://soundcloud.com/<br />");
$embedhelp4 = t("All other embedded content will be filtered, <strong>unless</strong> embedded content from that site is explicitly blocked.");
@@ -99,7 +106,7 @@ class Security {
'$page' => t('Security'),
'$form_security_token' => get_form_security_token('admin_security'),
'$block_public' => array('block_public', t("Block public"), get_config('system','block_public'), t("Check to block public access to all otherwise public personal pages on this site unless you are currently authenticated.")),
'$cloud_noroot' => [ 'cloud_noroot', t('Provide a cloud root directory'), 1 - intval(get_config('system','cloud_disable_siteroot')), t('The cloud root directory lists all channel names which provide public files') ],
'$cloud_noroot' => [ 'cloud_noroot', t('Provide a cloud root directory'), 1 - intval(get_config('system','cloud_disable_siteroot')), t('The cloud root directory lists all channel names which provide public files') ],
'$cloud_disksize' => [ 'cloud_disksize', t('Show total disk space available to cloud uploads'), intval(get_config('system','cloud_report_disksize')), '' ],
'$transport_security' => array('transport_security', t('Set "Transport Security" HTTP header'),intval(get_config('system','transport_security_header')),''),
'$content_security' => array('content_security', t('Set "Content Security Policy" HTTP header'),intval(get_config('system','content_security_policy')),''),
@@ -115,6 +122,8 @@ class Security {
'$thumbnail_security' => [ 'thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.") ],
'$inline_pdf' => [ 'inline_pdf', t("Allow embedded (inline) PDF files"), get_config('system','inline_pdf',0), '' ],
'$trusted_directory_servers' => (($is_dir) ? ['trusted_directory_servers', t('Additional trusted directory server URLs'), $trusted_directory_servers_str, t('Accept directory flags (spam, nsfw) from those servers. One per line like https://example.tld')] : ''),
// '$embed_coop' => array('embed_coop', t('Cooperative embed security'), $embed_coop, t('Enable to share embed security with other compatible sites/hubs')),
'$submit' => t('Submit')
@@ -124,7 +133,7 @@ class Security {
function trim_array_elems($arr) {
$narr = array();
if($arr && is_array($arr)) {
for($x = 0; $x < count($arr); $x ++) {
$y = trim($arr[$x]);
@@ -134,6 +143,6 @@ class Security {
}
return $narr;
}
}

View File

@@ -67,7 +67,6 @@ class Site {
$open_pubstream = ((x($_POST,'open_pubstream')) ? True : False);
$login_on_homepage = ((x($_POST,'login_on_homepage')) ? True : False);
$enable_context_help = ((x($_POST,'enable_context_help')) ? True : False);
$global_directory = ((x($_POST,'directory_submit_url')) ? notags(trim($_POST['directory_submit_url'])) : '');
$no_community_page = !((x($_POST,'no_community_page')) ? True : False);
$default_expire_days = ((array_key_exists('default_expire_days',$_POST)) ? intval($_POST['default_expire_days']) : 0);
$active_expire_days = ((array_key_exists('active_expire_days',$_POST)) ? intval($_POST['active_expire_days']) : 7);
@@ -100,7 +99,7 @@ class Site {
$reg_expire = (preg_match('/^[a-z]{1,1}$/', $regexpireu) ? $regexpiren . $regexpireu : '');
$imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
$force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000);
//$force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000);
$pub_incl = escape_tags(trim($_POST['pub_incl']));
$pub_excl = escape_tags(trim($_POST['pub_excl']));
@@ -129,7 +128,7 @@ class Site {
set_config('system', 'register_duty', $this->register_duty);
set_config('system', 'register_duty_jso', $this->joo);
} else {
notice('ZAR0130E,'.t('Errors') . ': ' . $this->error) . EOL . $this->msgfg;
notice('ZAR0130E,' . t('Errors') . ': ' . $this->error . EOL . $this->msgfg . EOL);
}
}
}
@@ -181,7 +180,7 @@ class Site {
set_config('system', 'admininfo', $admininfo);
}
set_config('system','siteinfo',$siteinfo);
set_config('system', 'language', $language);
//set_config('system', 'language', $language);
set_config('system', 'theme', $theme);
// if ( $theme_mobile === '---' ) {
// del_config('system', 'mobile_theme');
@@ -205,12 +204,7 @@ class Site {
set_config('system','disable_discover_tab', $disable_discover_tab);
set_config('system','site_firehose', $site_firehose);
set_config('system','open_pubstream', $open_pubstream);
set_config('system','force_queue_threshold', $force_queue);
if ($global_directory == '') {
del_config('system', 'directory_submit_url');
} else {
set_config('system', 'directory_submit_url', $global_directory);
}
//set_config('system','force_queue_threshold', $force_queue);
set_config('system','no_community_page', $no_community_page);
set_config('system','no_utf', $no_utf);
@@ -283,7 +277,7 @@ class Site {
}
$dir_choices = null;
$dirmode = get_config('system','directory_mode');
$dirmode = get_config('system', 'directory_mode', DIRECTORY_MODE_NORMAL);
$realm = get_directory_realm();
// directory server should not be set or settable unless we are a directory client
@@ -301,6 +295,12 @@ class Site {
$dir_choices[$xx['site_url']] = $xx['site_url'];
}
}
if ($realm === DIRECTORY_REALM) {
$fallback_servers = get_directory_fallback_servers();
foreach ($fallback_servers as $fallback_server) {
$dir_choices[$fallback_server] = $fallback_server;
}
}
}
/* Banner */
@@ -339,12 +339,15 @@ class Site {
// now invert the logic for the setting.
$discover_tab = (1 - $discover_tab);
$perm_roles = \Zotlabs\Access\PermissionRoles::roles();
$default_role = get_config('system','default_permissions_role','social');
$perm_roles = \Zotlabs\Access\PermissionRoles::channel_roles();
$default_role = get_config('system', 'default_permissions_role', 'personal');
if (!in_array($default_role, array_keys($perm_roles))) {
$default_role = 'personal';
}
$role = array('permissions_role' , t('Default permission role for new accounts'), $default_role, t('This role will be used for the first channel created after registration.'),$perm_roles);
$homelogin = get_config('system','login_on_homepage');
$enable_context_help = get_config('system','enable_context_help');
@@ -422,7 +425,7 @@ class Site {
'$banner' => array('banner', t("Banner/Logo"), $banner, t('Unfiltered HTML/CSS/JS is allowed')),
'$admininfo' => array('admininfo', t("Administrator Information"), $admininfo, t("Contact information for site administrators. Displayed on siteinfo page. BBCode can be used here")),
'$siteinfo' => array('siteinfo', t('Site Information'), get_config('system','siteinfo'), t("Publicly visible description of this site. Displayed on siteinfo page. BBCode can be used here")),
'$language' => array('language', t("System language"), get_config('system','language'), "", $lang_choices),
//'$language' => array('language', t("System language"), get_config('system','language'), "", $lang_choices),
'$theme' => array('theme', t("System theme"), get_config('system','theme'), t("Default system theme - may be over-ridden by user profiles - <a href='#' id='cnftheme'>change theme settings</a>"), $theme_choices),
// '$theme_mobile' => array('theme_mobile', t("Mobile system theme"), get_config('system','mobile_theme'), t("Theme for mobile devices"), $theme_choices_mobile),
// '$site_channel' => array('site_channel', t("Channel to use for this website's static pages"), get_config('system','site_channel'), t("Site Channel")),
@@ -505,10 +508,10 @@ class Site {
'$frontpage' => array('frontpage', t("Site homepage to show visitors (default: login box)"), get_config('system','frontpage'), t("example: 'pubstream' to show public stream, 'page/sys/home' to show a system webpage called 'home' or 'include:home.html' to include a file.")),
'$mirror_frontpage' => array('mirror_frontpage', t("Preserve site homepage URL"), get_config('system','mirror_frontpage'), t('Present the site homepage in a frame at the original location instead of redirecting')),
'$allowed_sites' => array('allowed_sites', t("Allowed friend domains"), get_config('system','allowed_sites'), t("Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains")),
'$force_publish' => array('publish_all', t("Force publish"), get_config('system','publish_all'), t("Check to force all profiles on this site to be listed in the site directory.")),
'$disable_discover_tab' => array('disable_discover_tab', t('Import Public Streams'), $discover_tab, t('Import and allow access to public content pulled from other sites. Warning: this content is unmoderated.')),
'$site_firehose' => array('site_firehose', t('Site only Public Streams'), get_config('system','site_firehose'), t('Allow access to public content originating only from this site if Imported Public Streams are disabled.')),
'$open_pubstream' => array('open_pubstream', t('Allow anybody on the internet to access the Public streams'), get_config('system','open_pubstream',1), t('Disable to require authentication before viewing. Warning: this content is unmoderated.')),
'$force_publish' => array('publish_all', t("Force publish"), get_config('system','publish_all'), t("Check to force all profiles on this site to be listed in the site directory")),
'$disable_discover_tab' => array('disable_discover_tab', t('Enable public stream'), $discover_tab, t('Enable the public stream. Warning: this content is unmoderated')),
'$site_firehose' => array('site_firehose', t('Site only public stream'), get_config('system','site_firehose'), t('Restrict the public stream to content originating at this site')),
'$open_pubstream' => array('open_pubstream', t('Allow anybody on the internet to access the public streams'), get_config('system','open_pubstream',1), t('Disable to require authentication before viewing')),
'$incl' => array('pub_incl',t('Only import Public stream posts with this text'), get_config('system','pubstream_incl'),t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')),
'$excl' => array('pub_excl',t('Do not import Public stream posts with this text'), get_config('system','pubstream_excl'),t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')),
@@ -529,7 +532,7 @@ class Site {
'$timeout' => array('timeout', t("Network timeout"), (x(get_config('system','curl_timeout'))?get_config('system','curl_timeout'):60), t("Value is in seconds. Set to 0 for unlimited (not recommended).")),
'$delivery_interval' => array('delivery_interval', t("Delivery interval"), (x(get_config('system','delivery_interval'))?get_config('system','delivery_interval'):2), t("Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers.")),
'$delivery_batch_count' => array('delivery_batch_count', t('Deliveries per process'),(x(get_config('system','delivery_batch_count'))?get_config('system','delivery_batch_count'):1), t("Number of deliveries to attempt in a single operating system process. Adjust if necessary to tune system performance. Recommend: 1-5.")),
'$force_queue' => array('force_queue', t("Queue Threshold"), get_config('system','force_queue_threshold',3000), t("Always defer immediate delivery if queue contains more than this number of entries.")),
//'$force_queue' => array('force_queue', t("Queue Threshold"), get_config('system','force_queue_threshold',3000), t("Always defer immediate delivery if queue contains more than this number of entries.")),
'$poll_interval' => array('poll_interval', t("Poll interval"), (x(get_config('system','poll_interval'))?get_config('system','poll_interval'):2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.")),
'$imagick_path' => array('imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert")),
'$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")),

103
Zotlabs/Module/Album.php Normal file
View File

@@ -0,0 +1,103 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Config;
use Zotlabs\Web\HTTPSig;
require_once('include/security.php');
require_once('include/attach.php');
require_once('include/photo/photo_driver.php');
require_once('include/photos.php');
class Album extends Controller {
function init() {
if (ActivityStreams::is_as_request()) {
$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);
}
elseif (Config::get('system', 'require_authenticated_fetch', false)) {
http_status_exit(403, 'Permission denied');
}
$observer_xchan = get_observer_hash();
$allowed = false;
$bear = Activity::token_from_request();
if ($bear) {
logger('bear: ' . $bear, LOGGER_DEBUG);
}
$channel = null;
if (argc() > 1) {
$channel = channelx_by_nick(argv(1));
}
if (!$channel) {
http_status_exit(404, 'Not found.');
}
$sql_extra = permissions_sql($channel['channel_id'], $observer_xchan);
if (argc() > 2) {
$folder = argv(2);
$r = q("select * from attach where is_dir = 1 and hash = '%s' and uid = %d $sql_extra limit 1",
dbesc($folder),
intval($channel['channel_id'])
);
$allowed = (($r) ? attach_can_view($channel['channel_id'], $observer_xchan, $r[0]['hash'] /*,$bear */) : false);
}
else {
$folder = EMPTY_STR;
$allowed = perm_is_allowed($channel['channel_id'], $observer_xchan, 'view_storage');
}
if (!$allowed) {
http_status_exit(403, 'Permission denied.');
}
$x = q("select * from attach where folder = '%s' and uid = %d $sql_extra",
dbesc($folder),
intval($channel['channel_id'])
);
$contents = [];
if ($x) {
foreach ($x as $xv) {
if (intval($xv['is_dir'])) {
continue;
}
if (!attach_can_view($channel['channel_id'], $observer_xchan, $xv['hash'] /*,$bear*/)) {
continue;
}
if (intval($xv['is_photo'])) {
$contents[] = z_root() . '/photo/' . $xv['hash'];
}
}
}
$obj = Activity::encode_simple_collection($contents, App::$query_string, 'OrderedCollection', count($contents));
as_return_and_die($obj, $channel);
}
}
}

View File

@@ -2,9 +2,9 @@
namespace Zotlabs\Module;
//require_once('include/apps.php');
use \Zotlabs\Lib as Zlib;
use App;
use Zotlabs\Lib\Apps;
use Zotlabs\Lib\Libsync;
class Appman extends \Zotlabs\Web\Controller {
@@ -13,7 +13,7 @@ class Appman extends \Zotlabs\Web\Controller {
if(! local_channel())
return;
if($_POST['url']) {
if(isset($_POST['url']) && $_POST['url']) {
$arr = array(
'uid' => intval($_REQUEST['uid']),
'url' => escape_tags($_REQUEST['url']),
@@ -33,9 +33,9 @@ class Appman extends \Zotlabs\Web\Controller {
'categories' => escape_tags($_REQUEST['categories'])
);
$_REQUEST['appid'] = Zlib\Apps::app_install(local_channel(),$arr);
$_REQUEST['appid'] = Apps::app_install(local_channel(),$arr);
if(Zlib\Apps::app_installed(local_channel(),$arr))
if(Apps::app_installed(local_channel(),$arr))
info( t('App installed.') . EOL);
goaway(z_root() . '/apps');
@@ -43,36 +43,98 @@ class Appman extends \Zotlabs\Web\Controller {
}
$papp = Zlib\Apps::app_decode($_POST['papp']);
$papp = Apps::app_decode($_POST['papp']);
if(! is_array($papp)) {
notice( t('Malformed app.') . EOL);
return;
}
if($_POST['install']) {
Zlib\Apps::app_install(local_channel(),$papp);
if(Zlib\Apps::app_installed(local_channel(),$papp))
if(isset($_POST['install']) && $_POST['install']) {
Apps::app_install(local_channel(),$papp);
if(Apps::app_installed(local_channel(),$papp))
info( t('App installed.') . EOL);
$sync = q("SELECT * FROM app WHERE app_channel = %d AND app_id = '%s' LIMIT 1",
intval(local_channel()),
dbesc($papp['guid'])
);
if (!$sync) {
return;
}
if (intval($sync[0]['app_system'])) {
Libsync::build_sync_packet(local_channel(), ['sysapp' => $sync]);
}
else {
Libsync::build_sync_packet(local_channel(), ['app' => $sync]);
}
}
if($_POST['delete']) {
Zlib\Apps::app_destroy(local_channel(),$papp);
if(isset($_POST['delete']) && $_POST['delete']) {
// Fetch the app for sync before it is deleted (if it is deletable))
$sync = q("SELECT * FROM app WHERE app_channel = %d AND app_id = '%s' LIMIT 1",
intval(local_channel()),
dbesc($papp['guid'])
);
if (!$sync) {
return;
}
Apps::app_destroy(local_channel(), $papp);
// Now flag it deleted
$sync[0]['app_deleted'] = 1;
if (intval($sync[0]['app_system'])) {
Libsync::build_sync_packet(local_channel(), ['sysapp' => $sync]);
}
else {
Libsync::build_sync_packet(local_channel(), ['app' => $sync]);
}
}
if($_POST['edit']) {
if(isset($_POST['edit']) && $_POST['edit']) {
return;
}
if($_POST['feature']) {
Zlib\Apps::app_feature(local_channel(), $papp, $_POST['feature']);
if(isset($_POST['feature']) && $_POST['feature']) {
Apps::app_feature(local_channel(), $papp, $_POST['feature']);
$sync = q("SELECT * FROM app WHERE app_channel = %d AND app_id = '%s' LIMIT 1",
intval(local_channel()),
dbesc($papp['guid'])
);
if (intval($sync[0]['app_system'])) {
Libsync::build_sync_packet(local_channel(), ['sysapp' => $sync]);
}
else {
Libsync::build_sync_packet(local_channel(), ['app' => $sync]);
}
}
if($_POST['pin']) {
Zlib\Apps::app_feature(local_channel(), $papp, $_POST['pin']);
if(isset($_POST['pin']) && $_POST['pin']) {
Apps::app_feature(local_channel(), $papp, $_POST['pin']);
$sync = q("SELECT * FROM app WHERE app_channel = %d AND app_id = '%s' LIMIT 1",
intval(local_channel()),
dbesc($papp['guid'])
);
if (intval($sync[0]['app_system'])) {
Libsync::build_sync_packet(local_channel(), ['sysapp' => $sync]);
}
else {
Libsync::build_sync_packet(local_channel(), ['app' => $sync]);
}
}
if($_POST['aj']) {
if(isset($_POST['aj']) && $_POST['aj']) {
killme();
}
@@ -92,14 +154,14 @@ class Appman extends \Zotlabs\Web\Controller {
return;
}
$channel = \App::get_channel();
$channel = App::get_channel();
if(argc() > 3) {
if(argv(2) === 'moveup') {
Zlib\Apps::moveup(local_channel(),argv(1),argv(3));
Apps::moveup(local_channel(),argv(1),argv(3));
}
if(argv(2) === 'movedown') {
Zlib\Apps::movedown(local_channel(),argv(1),argv(3));
Apps::movedown(local_channel(),argv(1),argv(3));
}
goaway(z_root() . '/apporder');
}
@@ -109,7 +171,7 @@ class Appman extends \Zotlabs\Web\Controller {
$app = null;
$embed = null;
if($_REQUEST['appid']) {
if(isset($_REQUEST['appid']) && $_REQUEST['appid']) {
$r = q("select * from app where app_id = '%s' and app_channel = %d limit 1",
dbesc($_REQUEST['appid']),
dbesc(local_channel())
@@ -133,32 +195,30 @@ class Appman extends \Zotlabs\Web\Controller {
}
}
$embed = array('embed', t('Embed code'), Zlib\Apps::app_encode($app,true),'', 'onclick="this.select();"');
$embed = array('embed', t('Embed code'), Apps::app_encode($app,true),'', 'onclick="this.select();"');
}
return replace_macros(get_markup_template('app_create.tpl'), array(
'$banner' => (($app) ? t('Edit App') : t('Create App')),
'$app' => $app,
'$guid' => (($app) ? $app['app_id'] : ''),
'$author' => (($app) ? $app['app_author'] : $channel['channel_hash']),
'$addr' => (($app) ? $app['app_addr'] : $channel['xchan_addr']),
'$name' => array('name', t('Name of app'),(($app) ? $app['app_name'] : ''), t('Required')),
'$url' => array('url', t('Location (URL) of app'),(($app) ? $app['app_url'] : ''), t('Required')),
'$desc' => array('desc', t('Description'),(($app) ? $app['app_desc'] : ''), ''),
'$photo' => array('photo', t('Photo icon URL'),(($app) ? $app['app_photo'] : ''), t('80 x 80 pixels - optional')),
'$categories' => array('categories',t('Categories (optional, comma separated list)'),(($app) ? $app['categories'] : ''),''),
'$version' => array('version', t('Version ID'),(($app) ? $app['app_version'] : ''), ''),
'$price' => array('price', t('Price of app'),(($app) ? $app['app_price'] : ''), ''),
'$page' => array('page', t('Location (URL) to purchase app'),(($app) ? $app['app_page'] : ''), ''),
'$system' => (($app) ? intval($app['app_system']) : 0),
'$plugin' => (($app) ? $app['app_plugin'] : ''),
'$requires' => (($app) ? $app['app_requires'] : ''),
'$guid' => $app['app_id'] ?? '',
'$author' => $app['app_author'] ?? $channel['channel_hash'],
'$addr' => $app['app_addr'] ?? $channel['xchan_addr'],
'$name' => array('name', t('Name of app'), $app['app_name'] ?? '', t('Required')),
'$url' => array('url', t('Location (URL) of app'), $app['app_url'] ?? '', t('Required')),
'$desc' => array('desc', t('Description'), $app['app_desc'] ?? '', ''),
'$photo' => array('photo', t('Photo icon URL'),$app['app_photo'] ?? '', t('80 x 80 pixels - optional')),
'$categories' => array('categories',t('Categories (optional, comma separated list)'), $app['categories'] ?? '',''),
'$version' => array('version', t('Version ID'), $app['app_version'] ?? '', ''),
'$price' => array('price', t('Price of app'), $app['app_price'] ?? '', ''),
'$page' => array('page', t('Location (URL) to purchase app'), $app['app_page'] ?? '', ''),
'$system' => $app['app_system'] ?? 0,
'$plugin' => $app['app_plugin'] ?? '',
'$requires' => $app['app_requires'] ?? '',
'$embed' => $embed,
'$submit' => t('Submit')
));
}
}

View File

@@ -19,7 +19,8 @@ class Apps extends \Zotlabs\Web\Controller {
$_SESSION['return_url'] = \App::$query_string;
$apps = array();
$apps = [];
$cat = [];
if(local_channel()) {
Zlib\Apps::import_system_apps();

View File

@@ -14,7 +14,7 @@ class Apschema extends \Zotlabs\Web\Controller {
'zot' => z_root() . '/apschema#',
'id' => '@id',
'type' => '@type',
'commentPolicy' => 'as:commentPolicy',
'commentPolicy' => 'zot:commentPolicy',
'meData' => 'zot:meData',
'meDataType' => 'zot:meDataType',
'meEncoding' => 'zot:meEncoding',
@@ -33,6 +33,9 @@ class Apschema extends \Zotlabs\Web\Controller {
'PropertyValue' => 'schema:PropertyValue',
'value' => 'schema:value',
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
'magicEnv' => [
'@id' => 'zot:magicEnv',
'@type' => '@id'
@@ -50,7 +53,7 @@ class Apschema extends \Zotlabs\Web\Controller {
'guid' => 'diaspora:guid',
'Hashtag' => 'as:Hashtag'
]
];

View File

@@ -1,138 +0,0 @@
<?php
namespace Zotlabs\Module;
require_once('include/channel.php');
require_once('include/acl_selectors.php');
require_once('include/conversation.php');
class Article_edit extends \Zotlabs\Web\Controller {
function get() {
// Figure out which post we're editing
$post_id = ((argc() > 1) ? intval(argv(1)) : 0);
if(! $post_id) {
notice( t('Item not found') . EOL);
return;
}
$itm = q("SELECT * FROM item WHERE id = %d and item_type = %d LIMIT 1",
intval($post_id),
intval(ITEM_TYPE_ARTICLE)
);
if($itm) {
$item_id = q("select * from iconfig where cat = 'system' and k = 'ARTICLE' and iid = %d limit 1",
intval($itm[0]['id'])
);
if($item_id)
$card_title = $item_id[0]['v'];
}
else {
notice( t('Item not found') . EOL);
return;
}
$owner = $itm[0]['uid'];
$uid = local_channel();
$observer = \App::get_observer();
$channel = channelx_by_n($owner);
if(! $channel) {
notice( t('Channel not found.') . EOL);
return;
}
$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
if(! perm_is_allowed($owner,$ob_hash,'write_pages')) {
notice( t('Permission denied.') . EOL);
return;
}
$is_owner = (($uid && $uid == $owner) ? true : false);
$o = '';
$category = '';
$catsenabled = ((feature_enabled($owner,'categories')) ? 'categories' : '');
if ($catsenabled){
$itm = fetch_post_tags($itm);
$cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY);
foreach ($cats as $cat) {
if (strlen($category))
$category .= ', ';
$category .= $cat['term'];
}
}
if($itm[0]['attach']) {
$j = json_decode($itm[0]['attach'],true);
if($j) {
foreach($j as $jj) {
$itm[0]['body'] .= "\n" . '[attachment]' . basename($jj['href']) . ',' . $jj['revision'] . '[/attachment]' . "\n";
}
}
}
$mimetype = $itm[0]['mimetype'];
$content = $itm[0]['body'];
$rp = 'articles/' . $channel['channel_address'];
$x = array(
'nickname' => $channel['channel_address'],
'bbco_autocomplete'=> 'bbcode',
'return_path' => $rp,
'webpage' => ITEM_TYPE_ARTICLE,
'button' => t('Edit'),
'writefiles' => perm_is_allowed($owner, get_observer_hash(), 'write_pages'),
'weblink' => t('Insert web link'),
'hide_voting' => false,
'hide_future' => false,
'hide_location' => false,
'hide_expire' => false,
'showacl' => true,
'acl' => populate_acl($itm[0],false,\Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')),
'permissions' => $itm[0],
'lockstate' => (($itm[0]['allow_cid'] || $itm[0]['allow_gid'] || $itm[0]['deny_cid'] || $itm[0]['deny_gid']) ? 'lock' : 'unlock'),
'ptyp' => $itm[0]['type'],
'mimeselect' => false,
'mimetype' => $itm[0]['mimetype'],
'body' => undo_post_tagging($content),
'post_id' => $post_id,
'visitor' => true,
'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
'summary' => htmlspecialchars($itm[0]['summary'],ENT_COMPAT,'UTF-8'),
'placeholdertitle' => t('Title (optional)'),
'pagetitle' => $card_title,
'profile_uid' => (intval($channel['channel_id'])),
'catsenabled' => $catsenabled,
'category' => $category,
'bbcode' => (($mimetype == 'text/bbcode') ? true : false)
);
$editor = status_editor($a, $x, false, 'Article_edit');
$o .= replace_macros(get_markup_template('edpost_head.tpl'), array(
'$title' => t('Edit Article'),
'$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false),
'$id' => $itm[0]['id'],
'$cancel' => t('Cancel'),
'$editor' => $editor
));
return $o;
}
}

View File

@@ -1,232 +0,0 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Lib\Apps;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\PermissionDescription;
require_once('include/channel.php');
require_once('include/conversation.php');
require_once('include/acl_selectors.php');
require_once('include/opengraph.php');
class Articles extends Controller {
function init() {
if(argc() > 1)
$which = argv(1);
if(! $which) {
if(local_channel()) {
$channel = App::get_channel();
if($channel && $channel['channel_address'])
$which = $channel['channel_address'];
} else {
return;
}
}
profile_load($which);
}
function get($update = 0, $load = false) {
if(observer_prohibited(true)) {
return login();
}
if(! App::$profile) {
notice( t('Requested profile is not available.') . EOL );
App::$error = 404;
return;
}
if(! Apps::system_app_installed(App::$profile_uid, 'Articles')) {
//Do not display any associated widgets at this point
App::$pdl = '';
$papp = Apps::get_papp('Articles');
return Apps::app_render($papp, 'module');
}
nav_set_selected('Articles');
head_add_link([
'rel' => 'alternate',
'type' => 'application/json+oembed',
'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string),
'title' => 'oembed'
]);
$category = (($_REQUEST['cat']) ? escape_tags(trim($_REQUEST['cat'])) : '');
if($category) {
$sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'],'item', $category, TERM_CATEGORY));
}
$datequery = ((x($_GET,'dend') && is_a_date_arg($_GET['dend'])) ? notags($_GET['dend']) : '');
$datequery2 = ((x($_GET,'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : '');
$which = argv(1);
$selected_card = ((argc() > 2) ? argv(2) : '');
$_SESSION['return_url'] = App::$query_string;
$uid = local_channel();
$owner = App::$profile_uid;
$observer = App::get_observer();
$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
if(! perm_is_allowed($owner,$ob_hash,'view_pages')) {
notice( t('Permission denied.') . EOL);
return;
}
$is_owner = ($uid && $uid == $owner);
$channel = channelx_by_n($owner);
if($channel) {
$channel_acl = array(
'allow_cid' => $channel['channel_allow_cid'],
'allow_gid' => $channel['channel_allow_gid'],
'deny_cid' => $channel['channel_deny_cid'],
'deny_gid' => $channel['channel_deny_gid']
);
}
else {
$channel_acl = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ];
}
if(perm_is_allowed($owner,$ob_hash,'write_pages')) {
$x = [
'webpage' => ITEM_TYPE_ARTICLE,
'is_owner' => true,
'content_label' => t('Add Article'),
'button' => t('Save'),
'nickname' => $channel['channel_address'],
'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
|| $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
'acl' => (($is_owner) ? populate_acl($channel_acl, false,
PermissionDescription::fromGlobalPermission('view_pages')) : ''),
'permissions' => $channel_acl,
'showacl' => (($is_owner) ? true : false),
'visitor' => true,
'hide_location' => false,
'hide_voting' => false,
'profile_uid' => intval($owner),
'mimetype' => 'text/bbcode',
'mimeselect' => false,
'layoutselect' => false,
'expanded' => false,
'novoting' => false,
'catsenabled' => feature_enabled($owner,'categories'),
'bbco_autocomplete' => 'bbcode',
'bbcode' => true
];
if($_REQUEST['title'])
$x['title'] = $_REQUEST['title'];
if($_REQUEST['body'])
$x['body'] = $_REQUEST['body'];
$editor = status_editor($a,$x,false,'Articles');
}
else {
$editor = '';
}
$itemspage = get_pconfig(local_channel(),'system','itemspage');
App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 10));
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start']));
$sql_extra = item_permissions_sql($owner);
$sql_item = '';
if($selected_card) {
$r = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = 'ARTICLE' and iconfig.v = '%s' limit 1",
dbesc($selected_card)
);
if($r) {
$sql_item = "and item.id = " . intval($r[0]['iid']) . " ";
}
}
if($datequery) {
$sql_extra2 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery))));
$order = 'post';
}
if($datequery2) {
$sql_extra2 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery2))));
}
if($datequery || $datequery2) {
$sql_extra2 .= " and item.item_thread_top != 0 ";
}
$r = q("select * from item
where item.uid = %d and item_type = %d
$sql_extra $sql_extra2 $sql_item order by item.created desc $pager_sql",
intval($owner),
intval(ITEM_TYPE_ARTICLE)
);
$item_normal = " and item.item_hidden = 0 and item.item_type in (0,7) and item.item_deleted = 0
and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
and item.item_blocked = 0 ";
if($r) {
$pager_total = count($r);
$parents_str = ids_to_querystr($r,'id');
$r = q("SELECT item.*, item.id AS item_id
FROM item
WHERE item.uid = %d $item_normal
AND item.parent IN ( %s )
$sql_extra $sql_extra2 ",
intval(App::$profile['profile_uid']),
dbesc($parents_str)
);
if($r) {
xchan_query($r);
$items = fetch_post_tags($r, true);
$items = conv_sort($items,'updated');
}
else
$items = [];
}
// Add Opengraph markup
opengraph_add_meta((! empty($items) ? $r[0] : []), $channel);
$mode = 'articles';
if(get_pconfig(local_channel(),'system','articles_list_mode') && (! $selected_card))
$page_mode = 'pager_list';
else
$page_mode = 'traditional';
$content = conversation($items,$mode,false,$page_mode);
$o = replace_macros(get_markup_template('cards.tpl'), [
'$title' => t('Articles'),
'$editor' => $editor,
'$content' => $content,
'$pager' => alt_pager($pager_total)
]);
return $o;
}
}

View File

@@ -9,43 +9,43 @@ require_once('include/acl_selectors.php');
class Blocks extends \Zotlabs\Web\Controller {
function init() {
if(argc() > 1 && argv(1) === 'sys' && is_site_admin()) {
$sys = get_sys_channel();
if($sys && intval($sys['channel_id'])) {
\App::$is_sys = true;
}
}
if(argc() > 1)
$which = argv(1);
else
return;
profile_load($which);
}
function get() {
if(! \App::$profile) {
notice( t('Requested profile is not available.') . EOL );
\App::$error = 404;
return;
}
$which = argv(1);
$_SESSION['return_url'] = \App::$query_string;
$uid = local_channel();
$owner = 0;
$channel = null;
$observer = \App::get_observer();
$channel = \App::get_channel();
if(\App::$is_sys && is_site_admin()) {
$sys = get_sys_channel();
if($sys && intval($sys['channel_id'])) {
@@ -54,7 +54,7 @@ class Blocks extends \Zotlabs\Web\Controller {
$observer = $sys;
}
}
if(! $owner) {
// Figure out who the page owner is.
$r = q("select channel_id from channel where channel_address = '%s'",
@@ -64,24 +64,24 @@ class Blocks extends \Zotlabs\Web\Controller {
$owner = intval($r[0]['channel_id']);
}
}
$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
$perms = get_all_perms($owner,$ob_hash);
if(! $perms['write_pages']) {
notice( t('Permission denied.') . EOL);
return;
}
// Block design features from visitors
// Block design features from visitors
if((! $uid) || ($uid != $owner)) {
notice( t('Permission denied.') . EOL);
return;
}
$mimetype = (($_REQUEST['mimetype']) ? $_REQUEST['mimetype'] : get_pconfig($owner,'system','page_mimetype'));
$mimetype = ((isset($_REQUEST['mimetype']) && $_REQUEST['mimetype']) ? $_REQUEST['mimetype'] : get_pconfig($owner,'system','page_mimetype'));
$x = array(
'webpage' => ITEM_TYPE_BLOCK,
@@ -101,27 +101,25 @@ class Blocks extends \Zotlabs\Web\Controller {
'bbco_autocomplete' => 'bbcode',
'bbcode' => true
);
if($_REQUEST['title'])
$x['title'] = $_REQUEST['title'];
if($_REQUEST['body'])
$x['body'] = $_REQUEST['body'];
if($_REQUEST['pagetitle'])
$x['pagetitle'] = $_REQUEST['pagetitle'];
$editor = status_editor($a,$x,false,'Blocks');
$r = q("select iconfig.iid, iconfig.k, iconfig.v, mid, title, body, mimetype, created, edited from iconfig
$x['title'] = $_REQUEST['title'] ?? '';
$x['body'] = $_REQUEST['body'] ?? '';
$x['pagetitle'] = $_REQUEST['pagetitle'] ?? '';
$a = '';
$editor = status_editor($a,$x,false,'Blocks');
$r = q("select iconfig.iid, iconfig.k, iconfig.v, mid, title, body, mimetype, created, edited from iconfig
left join item on iconfig.iid = item.id
where uid = %d and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK'
where uid = %d and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK'
and item_type = %d order by item.created desc",
intval($owner),
intval(ITEM_TYPE_BLOCK)
);
$pages = null;
if($r) {
$pages = array();
foreach($r as $rr) {
@@ -143,13 +141,13 @@ class Blocks extends \Zotlabs\Web\Controller {
'edited' => $rr['edited'],
'bb_element' => '[element]' . base64url_encode(json_encode($element_arr)) . '[/element]'
);
}
}
}
//Build the base URL for edit links
$url = z_root() . '/editblock/' . $which;
$o .= replace_macros(get_markup_template('blocklist.tpl'), array(
$url = z_root() . '/editblock/' . $which;
$o = replace_macros(get_markup_template('blocklist.tpl'), array(
'$baseurl' => $url,
'$title' => t('Blocks'),
'$name' => t('Block Name'),
@@ -166,8 +164,8 @@ class Blocks extends \Zotlabs\Web\Controller {
'$view' => t('View'),
'$preview' => '1',
));
return $o;
}
}

View File

@@ -39,7 +39,7 @@ class Cal extends Controller {
head_set_icon(App::$data['channel']['xchan_photo_s']);
App::$page['htmlhead'] .= "<script> var profile_uid = " . ((App::$data['channel']) ? App::$data['channel']['channel_id'] : 0) . "; </script>" ;
App::$page['htmlhead'] = "<script> var profile_uid = " . ((App::$data['channel']) ? App::$data['channel']['channel_id'] : 0) . "; </script>" ;
}
@@ -65,13 +65,9 @@ class Cal extends Controller {
nav_set_selected('Calendar');
head_add_css('/library/fullcalendar/packages/core/main.min.css');
head_add_css('/library/fullcalendar/packages/daygrid/main.min.css');
head_add_js('/library/fullcalendar/dist/index.global.js');
head_add_css('cdav_calendar.css');
head_add_js('/library/fullcalendar/packages/core/main.min.js');
head_add_js('/library/fullcalendar/packages/daygrid/main.min.js');
$sql_extra = permissions_sql($channel['channel_id'], get_observer_hash(), 'event');
if(! perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_contacts') || App::$profile['hide_friends'])

View File

@@ -1,140 +0,0 @@
<?php
namespace Zotlabs\Module;
require_once('include/channel.php');
require_once('include/acl_selectors.php');
require_once('include/conversation.php');
class Card_edit extends \Zotlabs\Web\Controller {
function get() {
// Figure out which post we're editing
$post_id = ((argc() > 1) ? intval(argv(1)) : 0);
if(! $post_id) {
notice( t('Item not found') . EOL);
return;
}
$itm = q("SELECT * FROM item WHERE id = %d and item_type = %d LIMIT 1",
intval($post_id),
intval(ITEM_TYPE_CARD)
);
if($itm) {
$item_id = q("select * from iconfig where cat = 'system' and k = 'CARD' and iid = %d limit 1",
intval($itm[0]['id'])
);
if($item_id)
$card_title = $item_id[0]['v'];
}
else {
notice( t('Item not found') . EOL);
return;
}
$owner = $itm[0]['uid'];
$uid = local_channel();
$observer = \App::get_observer();
$channel = channelx_by_n($owner);
if(! $channel) {
notice( t('Channel not found.') . EOL);
return;
}
$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
if(! perm_is_allowed($owner,$ob_hash,'write_pages')) {
notice( t('Permission denied.') . EOL);
return;
}
$is_owner = (($uid && $uid == $owner) ? true : false);
$o = '';
$category = '';
$catsenabled = ((feature_enabled($owner,'categories')) ? 'categories' : '');
if ($catsenabled){
$itm = fetch_post_tags($itm);
$cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY);
foreach ($cats as $cat) {
if (strlen($category))
$category .= ', ';
$category .= $cat['term'];
}
}
if($itm[0]['attach']) {
$j = json_decode($itm[0]['attach'],true);
if($j) {
foreach($j as $jj) {
$itm[0]['body'] .= "\n" . '[attachment]' . basename($jj['href']) . ',' . $jj['revision'] . '[/attachment]' . "\n";
}
}
}
$mimetype = $itm[0]['mimetype'];
$content = $itm[0]['body'];
$rp = 'cards/' . $channel['channel_address'];
$x = array(
'nickname' => $channel['channel_address'],
'bbco_autocomplete'=> 'bbcode',
'return_path' => $rp,
'webpage' => ITEM_TYPE_CARD,
'button' => t('Edit'),
'writefiles' => perm_is_allowed($owner, get_observer_hash(), 'write_pages'),
'weblink' => t('Insert web link'),
'hide_voting' => false,
'hide_future' => false,
'hide_location' => false,
'hide_expire' => false,
'showacl' => true,
'acl' => populate_acl($itm[0],false,\Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')),
'permissions' => $itm[0],
'lockstate' => (($itm[0]['allow_cid'] || $itm[0]['allow_gid'] || $itm[0]['deny_cid'] || $itm[0]['deny_gid']) ? 'lock' : 'unlock'),
'ptyp' => $itm[0]['type'],
'mimeselect' => false,
'mimetype' => $itm[0]['mimetype'],
'body' => undo_post_tagging($content),
'post_id' => $post_id,
'visitor' => true,
'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
'summary' => htmlspecialchars($itm[0]['summary'],ENT_COMPAT,'UTF-8'),
'placeholdertitle' => t('Title (optional)'),
'pagetitle' => $card_title,
'profile_uid' => (intval($channel['channel_id'])),
'catsenabled' => $catsenabled,
'category' => $category,
'bbcode' => (($mimetype == 'text/bbcode') ? true : false)
);
$editor = status_editor($a, $x, false, 'Card_edit');
$o .= replace_macros(get_markup_template('edpost_head.tpl'), array(
'$title' => t('Edit Card'),
'$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false),
'$id' => $itm[0]['id'],
'$cancel' => t('Cancel'),
'$editor' => $editor
));
return $o;
}
}

View File

@@ -1,214 +0,0 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Lib\Apps;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\PermissionDescription;
require_once('include/channel.php');
require_once('include/conversation.php');
require_once('include/acl_selectors.php');
/**
* @brief Provides the Cards module.
*
*/
class Cards extends Controller {
public function init() {
if(argc() > 1)
$which = argv(1);
else
return;
profile_load($which);
}
/**
* {@inheritDoc}
* @see \\Zotlabs\\Web\\Controller::get()
*
* @return string Parsed HTML from template 'cards.tpl'
*/
public function get($update = 0, $load = false) {
if(observer_prohibited(true)) {
return login();
}
if(! App::$profile) {
notice( t('Requested profile is not available.') . EOL );
App::$error = 404;
return;
}
if(! Apps::system_app_installed(App::$profile_uid, 'Cards')) {
//Do not display any associated widgets at this point
App::$pdl = '';
$papp = Apps::get_papp('Cards');
return Apps::app_render($papp, 'module');
}
nav_set_selected('Cards');
head_add_link([
'rel' => 'alternate',
'type' => 'application/json+oembed',
'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string),
'title' => 'oembed'
]);
$category = (($_REQUEST['cat']) ? escape_tags(trim($_REQUEST['cat'])) : '');
if($category) {
$sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'], 'item', $category, TERM_CATEGORY));
}
$which = argv(1);
$selected_card = ((argc() > 2) ? argv(2) : '');
$_SESSION['return_url'] = App::$query_string;
$uid = local_channel();
$owner = App::$profile_uid;
$observer = App::get_observer();
$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
if(! perm_is_allowed($owner, $ob_hash, 'view_pages')) {
notice( t('Permission denied.') . EOL);
return;
}
$is_owner = ($uid && $uid == $owner);
$channel = channelx_by_n($owner);
if($channel) {
$channel_acl = [
'allow_cid' => $channel['channel_allow_cid'],
'allow_gid' => $channel['channel_allow_gid'],
'deny_cid' => $channel['channel_deny_cid'],
'deny_gid' => $channel['channel_deny_gid']
];
}
else {
$channel_acl = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ];
}
if(perm_is_allowed($owner, $ob_hash, 'write_pages')) {
$x = [
'webpage' => ITEM_TYPE_CARD,
'is_owner' => true,
'content_label' => t('Add Card'),
'button' => t('Save'),
'nickname' => $channel['channel_address'],
'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
|| $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
'acl' => (($is_owner) ? populate_acl($channel_acl, false,
PermissionDescription::fromGlobalPermission('view_pages')) : ''),
'permissions' => $channel_acl,
'showacl' => (($is_owner) ? true : false),
'visitor' => true,
'hide_location' => false,
'hide_voting' => false,
'profile_uid' => intval($owner),
'mimetype' => 'text/bbcode',
'mimeselect' => false,
'layoutselect' => false,
'expanded' => false,
'novoting' => false,
'catsenabled' => feature_enabled($owner, 'categories'),
'bbco_autocomplete' => 'bbcode',
'bbcode' => true
];
if($_REQUEST['title'])
$x['title'] = $_REQUEST['title'];
if($_REQUEST['body'])
$x['body'] = $_REQUEST['body'];
$editor = status_editor($a, $x, false, 'Cards');
}
else {
$editor = '';
}
$itemspage = get_pconfig(local_channel(),'system','itemspage');
App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 10));
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start']));
$sql_extra = item_permissions_sql($owner);
$sql_item = '';
if($selected_card) {
$r = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = 'CARD' and iconfig.v = '%s' limit 1",
dbesc($selected_card)
);
if($r) {
$sql_item = "and item.id = " . intval($r[0]['iid']) . " ";
}
}
$r = q("select * from item
where uid = %d and item_type = %d
$sql_extra $sql_item order by item.created desc $pager_sql",
intval($owner),
intval(ITEM_TYPE_CARD)
);
$item_normal = " and item.item_hidden = 0 and item.item_type in (0,6) and item.item_deleted = 0
and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
and item.item_blocked = 0 ";
$items_result = [];
if($r) {
$pager_total = count($r);
$parents_str = ids_to_querystr($r, 'id');
$items = q("SELECT item.*, item.id AS item_id
FROM item
WHERE item.uid = %d $item_normal
AND item.parent IN ( %s )
$sql_extra $sql_extra2 ",
intval(App::$profile['profile_uid']),
dbesc($parents_str)
);
if($items) {
xchan_query($items);
$items = fetch_post_tags($items, true);
$items_result = conv_sort($items, 'updated');
}
}
$mode = 'cards';
if(get_pconfig(local_channel(),'system','articles_list_mode') && (! $selected_card))
$page_mode = 'pager_list';
else
$page_mode = 'traditional';
$content = conversation($items_result, $mode, false, $page_mode);
$o = replace_macros(get_markup_template('cards.tpl'), [
'$title' => t('Cards'),
'$editor' => $editor,
'$content' => $content,
'$pager' => alt_pager($pager_total)
]);
return $o;
}
}

View File

@@ -200,7 +200,7 @@ class Cdav extends Controller {
$etag = (isset($_SERVER['HTTP_IF_MATCH']) ? $_SERVER['HTTP_IF_MATCH'] : false);
// delete
if($httpmethod === 'DELETE' && $cdavdata['etag'] == $etag) {
if($httpmethod === 'DELETE' && $etag && isset($cdavdata['etag']) && $cdavdata['etag'] == $etag) {
Libsync::build_sync_packet($channel['channel_id'], [
$sync => [
'action' => 'delete_card',
@@ -210,7 +210,7 @@ class Cdav extends Controller {
]);
}
else {
if($etag && $cdavdata['etag'] !== $etag) {
if($etag && isset($cdavdata['etag']) && $cdavdata['etag'] !== $etag) {
// update
Libsync::build_sync_packet($channel['channel_id'], [
$sync => [
@@ -317,7 +317,7 @@ class Cdav extends Controller {
$calendars = $caldavBackend->getCalendarsForUser($principalUri);
//create new calendar
if($_REQUEST['{DAV:}displayname'] && $_REQUEST['create']) {
if((isset($_REQUEST['{DAV:}displayname']) && $_REQUEST['{DAV:}displayname']) && (isset($_REQUEST['create']) && $_REQUEST['create'])) {
do {
$duplicate = false;
$calendarUri = random_string(40);
@@ -332,9 +332,9 @@ class Cdav extends Controller {
} while ($duplicate == true);
$properties = [
'{DAV:}displayname' => $_REQUEST['{DAV:}displayname'],
'{http://apple.com/ns/ical/}calendar-color' => $_REQUEST['color'],
'{urn:ietf:params:xml:ns:caldav}calendar-description' => $channel['channel_name']
'{DAV:}displayname' => escape_tags($_REQUEST['{DAV:}displayname']),
'{http://apple.com/ns/ical/}calendar-color' => escape_tags($_REQUEST['color']),
'{urn:ietf:params:xml:ns:caldav}calendar-description' => escape_tags($channel['channel_name'])
];
$id = $caldavBackend->createCalendar($principalUri, $calendarUri, $properties);
@@ -352,7 +352,7 @@ class Cdav extends Controller {
}
//create new calendar object via ajax request
if($_REQUEST['submit'] === 'create_event' && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) {
if((isset($_REQUEST['submit']) && $_REQUEST['submit'] === 'create_event') && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) {
$id = explode(':', $_REQUEST['target']);
@@ -366,7 +366,7 @@ class Cdav extends Controller {
$allday = $_REQUEST['allday'];
$title = $_REQUEST['title'];
$title = escape_tags($_REQUEST['title']);
$start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']);
$dtstart = new \DateTime($start);
@@ -374,8 +374,8 @@ class Cdav extends Controller {
$end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']);
$dtend = new \DateTime($end);
}
$description = $_REQUEST['description'];
$location = $_REQUEST['location'];
$description = escape_tags($_REQUEST['description']);
$location = escape_tags($_REQUEST['location']);
do {
$duplicate = false;
@@ -431,7 +431,7 @@ class Cdav extends Controller {
}
//edit calendar name and color
if($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && $_REQUEST['id']) {
if((isset($_REQUEST['{DAV:}displayname']) && $_REQUEST['{DAV:}displayname']) && $_REQUEST['edit'] && $_REQUEST['id']) {
$id = explode(':', $_REQUEST['id']);
@@ -441,8 +441,8 @@ class Cdav extends Controller {
$cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
$mutations = [
'{DAV:}displayname' => $_REQUEST['{DAV:}displayname'],
'{http://apple.com/ns/ical/}calendar-color' => $_REQUEST['color']
'{DAV:}displayname' => escape_tags($_REQUEST['{DAV:}displayname']),
'{http://apple.com/ns/ical/}calendar-color' => escape_tags($_REQUEST['color'])
];
$patch = new \Sabre\DAV\PropPatch($mutations);
@@ -459,7 +459,7 @@ class Cdav extends Controller {
}
//edit calendar object via ajax request
if($_REQUEST['submit'] === 'update_event' && $_REQUEST['uri'] && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) {
if((isset($_REQUEST['submit']) && $_REQUEST['submit'] === 'update_event') && $_REQUEST['uri'] && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) {
$id = explode(':', $_REQUEST['target']);
@@ -471,18 +471,18 @@ class Cdav extends Controller {
$timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
$tz = (($timezone) ? $timezone : date_default_timezone_get());
$allday = $_REQUEST['allday'];
$allday = intval($_REQUEST['allday']);
$uri = $_REQUEST['uri'];
$title = $_REQUEST['title'];
$uri = escape_tags($_REQUEST['uri']);
$title = escape_tags($_REQUEST['title']);
$start = datetime_convert('UTC', 'UTC', $_REQUEST['dtstart']);
$dtstart = new \DateTime($start);
if($_REQUEST['dtend']) {
$end = datetime_convert('UTC', 'UTC', $_REQUEST['dtend']);
$dtend = new \DateTime($end);
}
$description = $_REQUEST['description'];
$location = $_REQUEST['location'];
$description = escape_tags($_REQUEST['description']);
$location = escape_tags($_REQUEST['location']);
$object = $caldavBackend->getCalendarObject($id, $uri);
@@ -654,7 +654,7 @@ class Cdav extends Controller {
$duplicate = true;
} while ($duplicate == true);
$properties = ['{DAV:}displayname' => $_REQUEST['{DAV:}displayname']];
$properties = ['{DAV:}displayname' => escape_tags($_REQUEST['{DAV:}displayname'])];
$carddavBackend->createAddressBook($principalUri, $addressbookUri, $properties);
@@ -668,9 +668,9 @@ class Cdav extends Controller {
}
//edit addressbook
if($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && intval($_REQUEST['id'])) {
if($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && $_REQUEST['id']) {
$id = $_REQUEST['id'];
$id = intval($_REQUEST['id']);
if(! cdav_perms($id,$addressbooks))
return;
@@ -678,7 +678,7 @@ class Cdav extends Controller {
$cdavdata = $this->get_cdav_data($id, 'addressbooks');
$mutations = [
'{DAV:}displayname' => $_REQUEST['{DAV:}displayname']
'{DAV:}displayname' => escape_tags($_REQUEST['{DAV:}displayname'])
];
$patch = new \Sabre\DAV\PropPatch($mutations);
@@ -901,19 +901,10 @@ class Cdav extends Controller {
//Display calendar(s) here
if(argc() <= 3 && argv(1) === 'calendar') {
head_add_css('/library/fullcalendar/packages/core/main.min.css');
head_add_css('/library/fullcalendar/packages/daygrid/main.min.css');
head_add_css('/library/fullcalendar/packages/timegrid/main.min.css');
head_add_css('/library/fullcalendar/packages/list/main.min.css');
head_add_js('/library/fullcalendar/dist/index.global.js');
head_add_css('cdav_calendar.css');
head_add_js('/library/fullcalendar/packages/core/main.min.js');
head_add_js('/library/fullcalendar/packages/interaction/main.min.js');
head_add_js('/library/fullcalendar/packages/daygrid/main.min.js');
head_add_js('/library/fullcalendar/packages/timegrid/main.min.js');
head_add_js('/library/fullcalendar/packages/list/main.min.js');
$o = '';
$sources = '';
$resource_id = '';
$resource = null;
@@ -921,6 +912,8 @@ class Cdav extends Controller {
if(argc() == 3)
$resource_id = argv(2);
$categories = '';
if($resource_id) {
$r = q("SELECT event.*, item.author_xchan, item.owner_xchan, item.plink, item.id as item_id FROM event LEFT JOIN item ON event.event_hash = item.resource_id
WHERE event.uid = %d AND event.event_hash = '%s' LIMIT 1",
@@ -944,7 +937,6 @@ class Cdav extends Controller {
$resource = $r[0];
$catsenabled = feature_enabled(local_channel(),'categories');
$categories = '';
if($catsenabled){
if($r[0]['term']) {
$cats = get_terms_oftype($r[0]['term'], TERM_CATEGORY);

View File

@@ -31,8 +31,10 @@ class Channel extends Controller {
goaway(z_root() . '/search?f=&search=' . $_GET['search']);
$which = null;
if (argc() > 1)
if (argc() > 1) {
$which = argv(1);
}
if (!$which) {
if (local_channel()) {
$channel = App::get_channel();
@@ -40,9 +42,9 @@ class Channel extends Controller {
$which = $channel['channel_address'];
}
}
if (!$which) {
notice(t('You must be logged in to see this page.') . EOL);
return;
http_status_exit(404, 'Not found');
}
$profile = 0;
@@ -53,14 +55,7 @@ class Channel extends Controller {
$profile = argv(1);
}
// Do not use channelx_by_nick() here since it will dismiss deleted channels.
// We need to provide zotinfo for deleted channels so that directories can pick up the info.
$r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_address = '%s' LIMIT 1",
dbesc($which)
);
$channel = $r[0];
$channel = channelx_by_nick($which, true);
if (!$channel) {
http_status_exit(404, 'Not found');
@@ -73,9 +68,8 @@ class Channel extends Controller {
$sigdata = HTTPSig::verify(file_get_contents('php://input'), EMPTY_STR, 'zot6');
if ($sigdata && $sigdata['signer'] && $sigdata['header_valid']) {
$data = json_encode(Libzot::zotinfo(['address' => $channel['channel_address'], 'target_url' => $sigdata['signer']]));
$s = q("select site_crypto, hubloc_sitekey from site left join hubloc on hubloc_url = site_url where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
$data = json_encode(Libzot::zotinfo(['guid_hash' => $channel['channel_hash'], 'target_url' => $sigdata['signer']]));
$s = q("select site_crypto, hubloc_sitekey from site left join hubloc on hubloc_url = site_url where hubloc_id_url = '%s' and hubloc_network = 'zot6' order by hubloc_id desc limit 1",
dbesc($sigdata['signer'])
);
@@ -100,7 +94,11 @@ class Channel extends Controller {
}
if ($channel['channel_removed']) {
http_status_exit(404, 'Not found');
http_status_exit(410, 'Gone');
}
if (get_pconfig($channel['channel_id'], 'system', 'index_opt_out')) {
App::$meta->set('robots', 'noindex, noarchive');
}
if (ActivityStreams::is_as_request($channel)) {
@@ -249,9 +247,7 @@ class Channel extends Controller {
$channel_acl = ['allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => ''];
}
if ($perms['post_wall']) {
$x = [
'is_owner' => $is_owner,
'allow_location' => ((($is_owner || $observer) && (intval(get_pconfig(App::$profile['profile_uid'], 'system', 'use_browser_location')))) ? true : false),
@@ -271,9 +267,16 @@ class Channel extends Controller {
'reset' => t('Reset form')
];
$a = '';
$o .= status_editor($a, $x, false, 'Channel');
}
// Add pinned content
if (!x($_REQUEST, 'mid') && !$search) {
$pinned = new \Zotlabs\Widget\Pinned;
$r = $pinned->widget(intval(App::$profile['profile_uid']), [ITEM_TYPE_POST]);
$o .= $r['html'];
}
}
@@ -297,7 +300,7 @@ class Channel extends Controller {
$abook_uids = " and abook.abook_channel = " . intval(App::$profile['profile_uid']) . " ";
$simple_update = '';
if ($update && $_SESSION['loadtime'])
if ($update && isset($_SESSION['loadtime']))
$simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC', 'UTC', $_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC', 'UTC', $_SESSION['loadtime']) . "' ) ";
if ($search) {
@@ -424,17 +427,14 @@ class Channel extends Controller {
$items = [];
}
// Add pinned content
if (!x($_REQUEST, 'mid') && !$search) {
$pinned = new \Zotlabs\Widget\Pinned;
$r = $pinned->widget(intval(App::$profile['profile_uid']), [ITEM_TYPE_POST]);
$o .= $r['html'];
}
$mode = (($search) ? 'search' : 'channel');
if ((!$update) && (!$load)) {
//if we got a decoded hash we must encode it again before handing to javascript
$mid = gen_link_id($mid);

View File

@@ -30,7 +30,7 @@ class Channel_calendar extends Controller {
$xchan = ((x($_POST, 'xchan')) ? dbesc($_POST['xchan']) : '');
// only allow editing your own events.
// only allow editing your own events.
if (($xchan) && ($xchan !== get_observer_hash()))
return;
@@ -55,8 +55,8 @@ class Channel_calendar extends Controller {
// Don't allow the event to finish before it begins.
// It won't hurt anything, but somebody will file a bug report
// and we'll waste a bunch of time responding to it. Time that
// could've been spent doing something else.
// and we'll waste a bunch of time responding to it. Time that
// could've been spent doing something else.
if (strcmp($finish, $start) < 0) {
notice(t('Event can not end before it has started.') . EOL);
@@ -319,12 +319,12 @@ class Channel_calendar extends Controller {
// fixed an issue with "nofinish" events not showing up in the calendar.
// There's still an issue if the finish date crosses the end of month.
// Noting this for now - it will need to be fixed here and in Friendica.
// Ultimately the finish date shouldn't be involved in the query.
// Ultimately the finish date shouldn't be involved in the query.
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
from event left join item on event.event_hash = item.resource_id
where item.resource_type = 'event' and event.uid = %d and event.uid = item.uid $ignored
AND (( event.adjust = 0 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' )
from event left join item on event.event_hash = item.resource_id
where item.resource_type = 'event' and event.uid = %d and event.uid = item.uid $ignored
AND (( event.adjust = 0 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' )
OR ( event.adjust = 1 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' )) ",
intval(local_channel()),
dbesc($start),
@@ -357,7 +357,7 @@ class Channel_calendar extends Controller {
$catsenabled = feature_enabled(local_channel(), 'categories');
$categories = '';
if ($catsenabled) {
if ($rr['term']) {
if (isset($rr['term']) && $rr['term']) {
$cats = get_terms_oftype($rr['term'], TERM_CATEGORY);
foreach ($cats as $cat) {
if (strlen($categories))
@@ -449,7 +449,7 @@ class Channel_calendar extends Controller {
}
// The site admin can delete any post/item on the site.
// If the item originated on this site+channel the deletion will propagate downstream.
// If the item originated on this site+channel the deletion will propagate downstream.
// Otherwise just the local copy is removed.
if (is_site_admin()) {

View File

@@ -16,17 +16,17 @@ class Chanview extends \Zotlabs\Web\Controller {
$r = null;
if($_REQUEST['hash']) {
if(!empty($_REQUEST['hash'])) {
$r = q("select * from xchan where xchan_hash = '%s' and xchan_deleted = 0",
dbesc($_REQUEST['hash'])
);
}
if($_REQUEST['address']) {
if(!empty($_REQUEST['address'])) {
$r = q("select * from xchan where xchan_addr = '%s' and xchan_deleted = 0",
dbesc(punify($_REQUEST['address']))
);
}
elseif(local_channel() && intval($_REQUEST['cid'])) {
elseif(local_channel() && !empty($_REQUEST['cid'])) {
$r = q("SELECT abook.*, xchan.*
FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel = %d and abook_id = %d and xchan_deleted = 0",
@@ -34,8 +34,7 @@ class Chanview extends \Zotlabs\Web\Controller {
intval($_REQUEST['cid'])
);
}
elseif($_REQUEST['url']) {
elseif(!empty($_REQUEST['url'])) {
// if somebody re-installed they will have more than one xchan, use the most recent name date as this is
// the most useful consistently ascending table item we have.
@@ -56,7 +55,7 @@ class Chanview extends \Zotlabs\Web\Controller {
if(! App::$poi) {
logger('mod_chanview: fallback');
if($_REQUEST['address']) {
if(!empty($_REQUEST['address'])) {
$href = Webfinger::zot_url(punify($_REQUEST['address']));
if($href) {
$_REQUEST['url'] = $href;
@@ -65,9 +64,9 @@ class Chanview extends \Zotlabs\Web\Controller {
$r = null;
if($_REQUEST['url']) {
if(!empty($_REQUEST['url'])) {
$zf = Zotfinger::exec($_REQUEST['url'], null);
$zf = Zotfinger::exec($_REQUEST['url']);
if(array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $_REQUEST['url'] && intval($zf['signature']['header_valid'])) {
Libzot::import_xchan($zf['data']);
@@ -79,6 +78,7 @@ class Chanview extends \Zotlabs\Web\Controller {
}
}
if(! $r) {
if(discover_by_webbie($_REQUEST['url'])) {
$r = q("select * from xchan where xchan_url = '%s' and xchan_deleted = 0",
dbesc($_REQUEST['url'])

View File

@@ -174,7 +174,8 @@ class Chat extends Controller {
$x = Chatroom::enter($observer,$room_id,'online',$_SERVER['REMOTE_ADDR']);
if(! $x)
return;
$x = q("select * from chatroom where cr_id = %d and cr_uid = %d $sql_extra limit 1",
$x = q("select * from chatroom where cr_id = %d and cr_uid = %d limit 1",
intval($room_id),
intval(App::$profile['profile_uid'])
);

View File

@@ -1,6 +1,6 @@
<?php /** @file */
namespace Zotlabs\Module;
namespace Zotlabs\Module;
require_once('include/security.php');
@@ -9,76 +9,76 @@ use \Zotlabs\Lib as Zlib;
class Chatsvc extends \Zotlabs\Web\Controller {
function init() {
//logger('chatsvc');
$ret = array('success' => false);
\App::$data['chat']['room_id'] = intval($_REQUEST['room_id']);
$x = q("select cr_uid from chatroom where cr_id = %d and cr_id != 0 limit 1",
intval(\App::$data['chat']['room_id'])
);
if(! $x)
json_return_and_die($ret);
\App::$data['chat']['uid'] = $x[0]['cr_uid'];
if(! perm_is_allowed(\App::$data['chat']['uid'],get_observer_hash(),'chat')) {
json_return_and_die($ret);
}
}
function post() {
$ret = array('success' => false);
$room_id = \App::$data['chat']['room_id'];
$text = escape_tags($_REQUEST['chat_text']);
if(! $text)
return;
$sql_extra = permissions_sql(\App::$data['chat']['uid']);
$r = q("select * from chatroom where cr_uid = %d and cr_id = %d $sql_extra",
intval(\App::$data['chat']['uid']),
intval(\App::$data['chat']['room_id'])
);
if(! $r)
json_return_and_die($ret);
$arr = array(
'chat_room' => \App::$data['chat']['room_id'],
'chat_xchan' => get_observer_hash(),
'chat_text' => $text
);
call_hooks('chat_post',$arr);
$x = q("insert into chat ( chat_room, chat_xchan, created, chat_text )
values( %d, '%s', '%s', '%s' )",
intval(\App::$data['chat']['room_id']),
dbesc(get_observer_hash()),
dbesc(datetime_convert()),
dbesc(str_rot47(base64url_encode($arr['chat_text'])))
dbesc(str_rot47(base64url_encode($arr['chat_text'])))
);
$ret['success'] = true;
json_return_and_die($ret);
}
function get() {
$status = strip_tags($_REQUEST['status']);
$status = ((isset($_REQUEST['status'])) ? strip_tags($_REQUEST['status']) : '');
$room_id = intval(\App::$data['chat']['room_id']);
$stopped = ((x($_REQUEST,'stopped') && intval($_REQUEST['stopped'])) ? true : false);
if($status && $room_id) {
$x = q("select channel_address from channel where channel_id = %d limit 1",
intval(\App::$data['chat']['uid'])
);
);
$r = q("update chatpresence set cp_status = '%s', cp_last = '%s' where cp_room = %d and cp_xchan = '%s' and cp_client = '%s'",
dbesc($status),
dbesc(datetime_convert()),
@@ -86,27 +86,27 @@ class Chatsvc extends \Zotlabs\Web\Controller {
dbesc(get_observer_hash()),
dbesc($_SERVER['REMOTE_ADDR'])
);
goaway(z_root() . '/chat/' . $x[0]['channel_address'] . '/' . $room_id);
goaway(z_root() . '/chat/' . $x[0]['channel_address'] . '/' . $room_id);
}
if(! $stopped) {
$lastseen = intval($_REQUEST['last']);
$ret = array('success' => false);
$sql_extra = permissions_sql(\App::$data['chat']['uid']);
$r = q("select * from chatroom where cr_uid = %d and cr_id = %d $sql_extra",
intval(\App::$data['chat']['uid']),
intval(\App::$data['chat']['room_id'])
);
if(! $r)
json_return_and_die($ret);
$inroom = array();
$r = q("select * from chatpresence left join xchan on xchan_hash = cp_xchan where cp_room = %d order by xchan_name",
intval(\App::$data['chat']['room_id'])
);
@@ -120,9 +120,9 @@ class Chatsvc extends \Zotlabs\Web\Controller {
$rv['xchan_url'] = z_root();
$rv['xchan_hidden'] = 1;
$rv['xchan_photo_mimetype'] = 'image/png';
$rv['xchan_photo_l'] = z_root() . '/' . get_default_profile_photo(300);
$rv['xchan_photo_m'] = z_root() . '/' . get_default_profile_photo(80);
$rv['xchan_photo_s'] = z_root() . '/' . get_default_profile_photo(48);
$rv['xchan_photo_l'] = z_root() . '/' . get_default_profile_photo(300);
$rv['xchan_photo_m'] = z_root() . '/' . get_default_profile_photo(80);
$rv['xchan_photo_s'] = z_root() . '/' . get_default_profile_photo(48);
}
@@ -137,13 +137,13 @@ class Chatsvc extends \Zotlabs\Web\Controller {
$status_class = 'online';
break;
}
$inroom[] = array('img' => zid($rv['xchan_photo_m']), 'img_type' => $rv['xchan_photo_mimetype'],'name' => $rv['xchan_name'], 'status' => $status, 'status_class' => $status_class);
}
}
$chats = array();
$r = q("select * from chat left join xchan on chat_xchan = xchan_hash where chat_room = %d and chat_id > %d order by created",
intval(\App::$data['chat']['room_id']),
intval($lastseen)
@@ -152,7 +152,7 @@ class Chatsvc extends \Zotlabs\Web\Controller {
foreach($r as $rr) {
$chats[] = array(
'id' => $rr['chat_id'],
'img' => zid($rr['xchan_photo_m']),
'img' => zid($rr['xchan_photo_m']),
'img_type' => $rr['xchan_photo_mimetype'],
'name' => $rr['xchan_name'],
'isotime' => datetime_convert('UTC', date_default_timezone_get(), $rr['created'], 'c'),
@@ -163,22 +163,22 @@ class Chatsvc extends \Zotlabs\Web\Controller {
}
}
}
$r = q("update chatpresence set cp_last = '%s' where cp_room = %d and cp_xchan = '%s' and cp_client = '%s'",
dbesc(datetime_convert()),
intval(\App::$data['chat']['room_id']),
dbesc(get_observer_hash()),
dbesc($_SERVER['REMOTE_ADDR'])
);
$ret['success'] = true;
if(! $stopped) {
$ret['inroom'] = $inroom;
$ret['chats'] = $chats;
}
json_return_and_die($ret);
}
}

View File

@@ -70,7 +70,7 @@ class Cloud extends Controller {
$_SESSION['cloud_sort'] = 'name';
}
$_SESSION['cloud_sort'] = (($_REQUEST['sort']) ? trim(notags($_REQUEST['sort'])) : $_SESSION['cloud_sort']);
$_SESSION['cloud_sort'] = ((isset($_REQUEST['sort']) && $_REQUEST['sort']) ? trim(notags($_REQUEST['sort'])) : $_SESSION['cloud_sort']);
$x = clean_query_string();
if($x !== \App::$query_string)
@@ -100,7 +100,6 @@ class Cloud extends Controller {
// over-ride the default XML output on thrown exceptions
$server->on('exception', [ $this, 'DAVException' ]);
// All we need to do now, is to fire up the server
@@ -117,21 +116,19 @@ class Cloud extends Controller {
function DAVException($err) {
if($err instanceof \Sabre\DAV\Exception\NotFound) {
notice( t('Not found') . EOL);
\App::$page['content'] = '<h2>404 Not found</h2>';
}
elseif($err instanceof \Sabre\DAV\Exception\Forbidden) {
notice( t('Permission denied') . EOL);
\App::$page['content'] = '<h2>403 Forbidden</h2>';
}
elseif($err instanceof \Sabre\DAV\Exception\NotImplemented) {
// notice( t('Please refresh page') . EOL);
goaway(z_root() . '/' . \App::$query_string);
}
else {
notice( t('Unknown error') . EOL);
\App::$page['content'] = '<h2>Unknown error</h2>';
}
construct_page();
killme();
}

View File

@@ -6,7 +6,7 @@ class Cloud_tiles extends \Zotlabs\Web\Controller {
function init() {
if(intval($_SESSION['cloud_tiles']))
if(isset($_SESSION['cloud_tiles']) && intval($_SESSION['cloud_tiles']))
$_SESSION['cloud_tiles'] = 0;
else
$_SESSION['cloud_tiles'] = 1;
@@ -18,4 +18,4 @@ class Cloud_tiles extends \Zotlabs\Web\Controller {
goaway(z_root() . '/' . hex2bin(argv(1)));
}
}
}

View File

@@ -2,32 +2,32 @@
namespace Zotlabs\Module;
use App;
use Zotlabs\Lib\Permcat;
require_once('include/socgraph.php');
require_once('include/selectors.php');
require_once('include/group.php');
class Connections extends \Zotlabs\Web\Controller {
function init() {
if(! local_channel())
return;
App::$profile_uid = local_channel();
$channel = App::get_channel();
if($channel)
head_set_icon($channel['xchan_photo_s']);
}
function get() {
$sort_type = 0;
$o = '';
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
return login();
@@ -44,13 +44,13 @@ class Connections extends \Zotlabs\Web\Controller {
$pending = false;
$unconnected = false;
$all = false;
if(! $_REQUEST['aj'])
if(!(isset($_REQUEST['aj']) && $_REQUEST['aj']))
$_SESSION['return_url'] = App::$query_string;
$search_flags = "";
$head = '';
if(argc() == 2) {
switch(argv(1)) {
case 'active':
@@ -106,7 +106,7 @@ class Connections extends \Zotlabs\Web\Controller {
// $head = t('Unconnected');
// $unconnected = true;
// break;
case 'all':
$head = t('All');
break;
@@ -115,20 +115,22 @@ class Connections extends \Zotlabs\Web\Controller {
$active = true;
$head = t('Active');
break;
}
$sql_extra = $search_flags;
if(argv(1) === 'pending')
$sql_extra .= " and abook_ignored = 0 ";
}
else {
$sql_extra = " and abook_blocked = 0 ";
$unblocked = true;
}
switch($_REQUEST['order']) {
$order = $_REQUEST['order'] ?? '';
switch($order) {
case 'name_desc':
$sql_order = 'xchan_name DESC';
break;
@@ -143,32 +145,33 @@ class Connections extends \Zotlabs\Web\Controller {
}
$search = ((x($_REQUEST,'search')) ? notags(trim($_REQUEST['search'])) : '');
$search_xchan = ((x($_REQUEST,'search_xchan')) ? notags(trim($_REQUEST['search_xchan'])) : '');
$tabs = array(
/*
array(
'label' => t('Suggestions'),
'url' => z_root() . '/suggest',
'url' => z_root() . '/suggest',
'sel' => '',
'title' => t('Suggest new connections'),
),
*/
'active' => array(
'label' => t('Active Connections'),
'url' => z_root() . '/connections/active',
'url' => z_root() . '/connections/active',
'sel' => ($active) ? 'active' : '',
'title' => t('Show active connections'),
),
'pending' => array(
'label' => t('New Connections'),
'url' => z_root() . '/connections/pending',
'url' => z_root() . '/connections/pending',
'sel' => ($pending) ? 'active' : '',
'title' => t('Show pending (new) connections'),
),
/*
array(
'label' => t('Unblocked'),
@@ -177,68 +180,75 @@ class Connections extends \Zotlabs\Web\Controller {
'title' => t('Only show unblocked connections'),
),
*/
'blocked' => array(
'label' => t('Blocked'),
'url' => z_root() . '/connections/blocked',
'sel' => ($blocked) ? 'active' : '',
'title' => t('Only show blocked connections'),
),
'ignored' => array(
'label' => t('Ignored'),
'url' => z_root() . '/connections/ignored',
'sel' => ($ignored) ? 'active' : '',
'title' => t('Only show ignored connections'),
),
'archived' => array(
'label' => t('Archived/Unreachable'),
'url' => z_root() . '/connections/archived',
'sel' => ($archived) ? 'active' : '',
'title' => t('Only show archived/unreachable connections'),
),
'hidden' => array(
'label' => t('Hidden'),
'url' => z_root() . '/connections/hidden',
'sel' => ($hidden) ? 'active' : '',
'title' => t('Only show hidden connections'),
),
// array(
// 'label' => t('Unconnected'),
// 'url' => z_root() . '/connections/unconnected',
// 'sel' => ($unconnected) ? 'active' : '',
// 'title' => t('Only show one-way connections'),
// ),
'all' => array(
'label' => t('All Connections'),
'url' => z_root() . '/connections',
'url' => z_root() . '/connections',
'sel' => ($all) ? 'active' : '',
'title' => t('Show all connections'),
),
);
//$tab_tpl = get_markup_template('common_tabs.tpl');
//$t = replace_macros($tab_tpl, array('$tabs'=>$tabs));
$searching = false;
$search_hdr = '';
if($search) {
$search_hdr = $search;
$search_txt = dbesc(protect_sprintf(preg_quote($search)));
$searching = true;
$search_txt = (($search_xchan) ? urldecode($search_xchan) : preg_quote($search));
if ($search_xchan) {
$sql_extra .= " AND xchan_hash = '" . protect_sprintf(dbesc($search_txt)) . "' ";
}
else {
$sql_extra .= " AND xchan_name LIKE '%%" . protect_sprintf(dbesc($search_txt)) . "%%' ";
}
}
$sql_extra .= (($searching) ? protect_sprintf(" AND xchan_name like '%$search_txt%' ") : "");
if($_REQUEST['gid']) {
if(isset($_REQUEST['gid']) && $_REQUEST['gid']) {
$sql_extra .= " and xchan_hash in ( select xchan from pgrp_member where gid = " . intval($_REQUEST['gid']) . " and uid = " . intval(local_channel()) . " ) ";
}
$r = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash
$r = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash
where abook_channel = %d and abook_self = 0 and xchan_deleted = 0 and xchan_orphan = 0 $sql_extra ",
intval(local_channel())
);
@@ -246,32 +256,39 @@ class Connections extends \Zotlabs\Web\Controller {
App::set_pager_total($r[0]['total']);
$total = $r[0]['total'];
}
$r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash
WHERE abook_channel = %d and abook_self = 0 and xchan_deleted = 0 and xchan_orphan = 0 $sql_extra ORDER BY $sql_order LIMIT %d OFFSET %d ",
intval(local_channel()),
intval(App::$pager['itemspage']),
intval(App::$pager['start'])
);
$roles = new Permcat(local_channel());
$roles_list = $roles->listing();
$roles_dict = [];
foreach ($roles_list as $role) {
$roles_dict[$role['name']] = $role['localname'];
}
$contacts = array();
if($r) {
vcard_query($r);
//vcard_query($r);
foreach($r as $rr) {
if($rr['xchan_url']) {
if(($rr['vcard']) && is_array($rr['vcard']['tels']) && $rr['vcard']['tels'][0]['nr'])
if((isset($rr['vcard'])) && is_array($rr['vcard']['tels']) && $rr['vcard']['tels'][0]['nr'])
$phone = $rr['vcard']['tels'][0]['nr'];
else
$phone = '';
$status_str = '';
$status = array(
((intval($rr['abook_active'])) ? t('Active') : ''),
((intval($rr['abook_pending'])) ? t('Pending approval') : ''),
((intval($rr['abook_archived'])) ? t('Archived') : ''),
((intval($rr['abook_hidden'])) ? t('Hidden') : ''),
@@ -306,7 +323,7 @@ class Connections extends \Zotlabs\Web\Controller {
$perminfo['connperms'] .= t('Nothing');
}
foreach($status as $str) {
if(!$str)
continue;
@@ -314,19 +331,16 @@ class Connections extends \Zotlabs\Web\Controller {
$status_str .= ', ';
}
$status_str = rtrim($status_str, ', ');
$contacts[] = array(
'img_hover' => sprintf( t('%1$s [%2$s]'),$rr['xchan_name'],$rr['xchan_url']),
'edit_hover' => t('Edit connection'),
'edit' => t('Edit'),
'delete_hover' => t('Delete connection'),
'id' => $rr['abook_id'],
'thumb' => $rr['xchan_photo_m'],
'thumb' => $rr['xchan_photo_m'],
'name' => $rr['xchan_name'],
'classes' => ((intval($rr['abook_archived']) || intval($rr['abook_not_here'])) ? 'archived' : ''),
'link' => z_root() . '/connedit/' . $rr['abook_id'],
'deletelink' => z_root() . '/connedit/' . intval($rr['abook_id']) . '/drop',
'delete' => t('Delete'),
'url' => chanlink_hash($rr['xchan_hash']),
'webbie_label' => t('Channel address'),
'webbie' => $rr['xchan_addr'],
@@ -337,6 +351,7 @@ class Connections extends \Zotlabs\Web\Controller {
'phone' => $phone,
'status_label' => t('Status'),
'status' => $status_str,
'states' => $status,
'connected_label' => t('Connected'),
'connected' => datetime_convert('UTC',date_default_timezone_get(),$rr['abook_created'], 'c'),
'approve_hover' => t('Approve connection'),
@@ -348,15 +363,24 @@ class Connections extends \Zotlabs\Web\Controller {
'oneway' => $oneway,
'perminfo' => $perminfo,
'connect' => (intval($rr['abook_not_here']) ? t('Connect') : ''),
'follow' => z_root() . '/follow/?f=&url=' . urlencode($rr['xchan_hash']) . '&interactive=0',
'connect_hover' => t('Connect at this location')
'follow' => z_root() . '/follow/?f=&url=' . urlencode($rr['xchan_hash']) . '&interactive=1',
'connect_hover' => t('Connect at this location'),
'role' => $roles_dict[$rr['abook_role']] ?? '',
'pending' => intval($rr['abook_pending'])
);
}
}
}
if($_REQUEST['aj']) {
$limit = service_class_fetch(local_channel(),'total_channels');
if($limit !== false) {
$abook_usage_message = sprintf( t("You have %1$.0f of %2$.0f allowed connections."), $total, $limit);
}
else {
$abook_usage_message = '';
}
if(isset($_REQUEST['aj']) && $_REQUEST['aj']) {
if($contacts) {
$o = replace_macros(get_markup_template('contactsajax.tpl'),array(
'$contacts' => $contacts,
@@ -371,27 +395,30 @@ class Connections extends \Zotlabs\Web\Controller {
}
else {
$o .= "<script> var page_query = '" . escape_tags(urlencode($_GET['q'])) . "'; var extra_args = '" . extra_query_args() . "' ; </script>";
$o .= replace_macros(get_markup_template('connections.tpl'),array(
$o .= replace_macros(get_markup_template('connections.tpl'), [
'$header' => t('Connections') . (($head) ? ': ' . $head : ''),
'$tabs' => $tabs,
'$total' => $total,
'$search' => $search_hdr,
'$label' => t('Search'),
'$desc' => t('Search your connections'),
'$finding' => (($searching) ? t('Connections search') . ": '" . $search . "'" : ""),
'$role_label' => t('Contact role'),
'$desc' => $search ?? t('Search your connections'),
'$finding' => (($searching) ? t('Contact search') . ": '" . $search . "'" : ""),
'$submit' => t('Find'),
'$edit' => t('Edit'),
'$approve' => t('Approve'),
'$cmd' => App::$cmd,
'$contacts' => $contacts,
'$paginate' => paginate($a),
));
'$abook_usage_message' => $abook_usage_message,
'$group_label' => t('This is a group/forum channel')
]);
}
if(! $contacts)
$o .= '<div id="content-complete"></div>';
return $o;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,675 @@
<?php
namespace Zotlabs\Module;
/* @file Cobtactedit.php
* @brief In this file the connection-editor form is generated and evaluated.
*
*
*/
use App;
use Sabre\VObject\Reader;
use Zotlabs\Lib\Apps;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Libsync;
use Zotlabs\Daemon\Master;
use Zotlabs\Web\Controller;
use Zotlabs\Access\Permissions;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Web\HTTPHeaders;
use Zotlabs\Lib\Permcat;
use Zotlabs\Lib\AccessList;
require_once('include/socgraph.php');
require_once('include/selectors.php');
require_once('include/group.php');
require_once('include/photos.php');
class Contactedit extends Controller {
/* @brief Initialize the connection-editor
*
*
*/
function init() {
if (!local_channel())
return;
if ((argc() >= 2) && intval(argv(1))) {
$r = q("SELECT abook.*, xchan.* FROM abook LEFT JOIN xchan ON abook_xchan = xchan_hash
WHERE abook_channel = %d AND abook_id = %d AND abook_self = 0 AND xchan_deleted = 0",
intval(local_channel()),
intval(argv(1))
);
if (!$r) {
json_return_and_die([
'success' => false,
'message' => t('Invalid abook_id')
]);
}
App::$poi = $r[0];
}
}
/* @brief Evaluate posted values and set changes
*
*/
function post() {
if (!local_channel())
return;
$contact_id = intval(argv(1));
if (!$contact_id)
return;
$channel = App::get_channel();
$contact = App::$poi;
if (!$contact) {
notice(t('Could not access contact record.') . EOL);
killme();
}
call_hooks('contact_edit_post', $_REQUEST);
if (Apps::system_app_installed(local_channel(), 'Privacy Groups')) {
$pgrp_ids = q("SELECT id FROM pgrp WHERE deleted = 0 AND uid = %d",
intval(local_channel())
);
foreach($pgrp_ids as $pgrp) {
if (array_key_exists('pgrp_id_' . $pgrp['id'], $_REQUEST)) {
AccessList::member_add(local_channel(), '', $contact['abook_xchan'], $pgrp['id']);
}
else {
AccessList::member_remove(local_channel(), '', $contact['abook_xchan'], $pgrp['id']);
}
}
}
$profile_id = ((array_key_exists('profile_assign', $_REQUEST)) ? $_REQUEST['profile_assign'] : $contact['abook_profile']);
if ($profile_id) {
$r = q("SELECT profile_guid FROM profile WHERE profile_guid = '%s' AND uid = %d LIMIT 1",
dbesc($profile_id),
intval(local_channel())
);
if (!$r) {
notice(t('Could not locate selected profile.') . EOL);
return;
}
}
$abook_incl = ((array_key_exists('abook_incl', $_REQUEST)) ? escape_tags($_REQUEST['abook_incl']) : $contact['abook_incl']);
$abook_excl = ((array_key_exists('abook_excl', $_REQUEST)) ? escape_tags($_REQUEST['abook_excl']) : $contact['abook_excl']);
$abook_role = ((array_key_exists('permcat', $_REQUEST)) ? escape_tags($_REQUEST['permcat']) : $contact['abook_role']);
if (!array_key_exists('closeness', $_REQUEST)) {
$_REQUEST['closeness'] = 80;
}
$closeness = intval($_REQUEST['closeness']);
if ($closeness < 0 || $closeness > 99) {
$closeness = 80;
}
$new_friend = ((intval($contact['abook_pending'])) ? true : false);
\Zotlabs\Lib\Permcat::assign($channel, $abook_role, [$contact['abook_xchan']]);
$abook_pending = (($new_friend) ? 0 : $contact['abook_pending']);
$r = q("UPDATE abook SET abook_profile = '%s', abook_closeness = %d, abook_pending = %d,
abook_incl = '%s', abook_excl = '%s'
where abook_id = %d AND abook_channel = %d",
dbesc($profile_id),
intval($closeness),
intval($abook_pending),
dbesc($abook_incl),
dbesc($abook_excl),
intval($contact_id),
intval(local_channel())
);
$_REQUEST['success'] = false;
if ($r) {
$_REQUEST['success'] = true;
}
if (!intval($contact['abook_self'])) {
if ($new_friend) {
Master::Summon(['Notifier', 'permission_accept', $contact_id]);
}
Master::Summon([
'Notifier',
(($new_friend) ? 'permission_create' : 'permission_update'),
$contact_id
]);
}
if ($new_friend) {
$default_group = $channel['channel_default_group'];
if ($default_group) {
$g = AccessList::by_hash(local_channel(), $default_group);
if ($g) {
AccessList::member_add(local_channel(), '', $contact['abook_xchan'], $g['id']);
}
}
// Check if settings permit ("post new friend activity" is allowed, and
// friends in general or this friend in particular aren't hidden)
// and send out a new friend activity
$pr = q("select * from profile where uid = %d and is_default = 1 and hide_friends = 0",
intval($channel['channel_id'])
);
if (($pr) && (!intval($contact['abook_hidden'])) && (intval(get_pconfig($channel['channel_id'], 'system', 'post_newfriend')))) {
$xarr = [];
$xarr['item_wall'] = 1;
$xarr['item_origin'] = 1;
$xarr['item_thread_top'] = 1;
$xarr['owner_xchan'] = $xarr['author_xchan'] = $channel['channel_hash'];
$xarr['allow_cid'] = $channel['channel_allow_cid'];
$xarr['allow_gid'] = $channel['channel_allow_gid'];
$xarr['deny_cid'] = $channel['channel_deny_cid'];
$xarr['deny_gid'] = $channel['channel_deny_gid'];
$xarr['item_private'] = (($xarr['allow_cid'] || $xarr['allow_gid'] || $xarr['deny_cid'] || $xarr['deny_gid']) ? 1 : 0);
$xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . $contact['xchan_url'] . ']' . $contact['xchan_name'] . '[/zrl]';
$xarr['body'] .= "\n\n\n" . '[zrl=' . $contact['xchan_url'] . '][zmg=80x80]' . $contact['xchan_photo_m'] . '[/zmg][/zrl]';
post_activity_item($xarr);
}
// pull in a bit of content if there is any to pull in
Master::Summon(['Onepoll', $contact_id]);
}
// Refresh the structure in memory with the new data
$this->init();
if ($new_friend) {
$arr = ['channel_id' => local_channel(), 'abook' => App::$poi];
call_hooks('accept_follow', $arr);
}
$this->contactedit_clone();
$this->get();
killme();
return;
}
/* @brief Generate content of contact edit page
*
*
*/
function get() {
if (!local_channel()) {
killme();
}
if (!App::$poi) {
killme();
}
$channel = App::get_channel();
$contact_id = App::$poi['abook_id'];
$contact = App::$poi;
$section = ((array_key_exists('section', $_REQUEST)) ? $_REQUEST['section'] : 'roles');
$sub_section = ((array_key_exists('sub_section', $_REQUEST)) ? $_REQUEST['sub_section'] : '');
if (argc() == 3) {
$cmd = argv(2);
$ret = $this->do_action($contact, $cmd);
$contact = App::$poi;
$tools_html = replace_macros(get_markup_template("contact_edit_tools.tpl"), [
'$tools_label' => t('Contact Tools'),
'$tools' => $this->get_tools($contact),
]);
$ret['tools'] = $tools_html;
json_return_and_die($ret);
}
$groups = [];
if (Apps::system_app_installed(local_channel(), 'Privacy Groups')) {
$r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval(local_channel())
);
$member_of = AccessList::containing(local_channel(), $contact['xchan_hash']);
if ($r) {
foreach ($r as $rr) {
$default_group = false;
if ($rr['hash'] === $channel['channel_default_group']) {
$default_group = true;
}
$groups[] = [
'pgrp_id_' . $rr['id'],
$rr['gname'],
// if it's a new contact preset the default group if we have one
(($default_group && $contact['abook_pending']) ? 1 : in_array($rr['id'], $member_of)),
'',
[t('No'), t('Yes')]
];
}
}
}
$slide = '';
if (Apps::system_app_installed(local_channel(), 'Affinity Tool')) {
$labels = [
t('Me'),
t('Family'),
t('Friends'),
t('Acquaintances'),
t('All')
];
call_hooks('affinity_labels', $labels);
$label_str = '';
if ($labels) {
foreach ($labels as $l) {
if ($label_str) {
$label_str .= ", '|'";
$label_str .= ", '" . $l . "'";
}
else
$label_str .= "'" . $l . "'";
}
}
$slider_tpl = get_markup_template('contact_slider.tpl');
$slideval = intval($contact['abook_closeness']);
$slide = replace_macros($slider_tpl, [
'$min' => 1,
'$val' => $slideval,
'$labels' => $label_str,
]);
}
$perms = [];
$global_perms = Permissions::Perms();
$existing = get_all_perms(local_channel(), $contact['abook_xchan'], false);
$unapproved = ['pending', t('Approve this contact'), '', t('Accept contact to allow communication'), [t('No'), ('Yes')]];
$multiprofs = ((feature_enabled(local_channel(), 'multi_profiles')) ? true : false);
$theirs = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'their_perms'",
intval(local_channel()),
dbesc($contact['abook_xchan'])
);
$their_perms = [];
if ($theirs) {
foreach ($theirs as $t) {
$their_perms[$t['k']] = $t['v'];
}
}
foreach ($global_perms as $k => $v) {
$thisperm = $existing[$k];
$checkinherited = PermissionLimits::Get(local_channel(), $k);
$perms[] = ['perms_' . $k, $v, ((array_key_exists($k, $their_perms)) ? intval($their_perms[$k]) : ''), $thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '0' : '1'), '', $checkinherited];
}
$pcat = new Permcat(local_channel());
$pcatlist = $pcat->listing();
$default_role = get_pconfig(local_channel(), 'system', 'default_permcat');
$current_permcat = (($contact['abook_pending']) ? $default_role : $contact['abook_role']);
$roles_dict = [];
foreach ($pcatlist as $role) {
$roles_dict[$role['name']] = $role['localname'];
}
if (!$current_permcat) {
notice(t('Please select a role for this contact!') . EOL);
$permcats[] = '';
}
if ($pcatlist) {
foreach ($pcatlist as $pc) {
$permcats[$pc['name']] = $pc['localname'];
}
}
$locstr = locations_by_netid($contact['xchan_hash']);
if (!$locstr) {
$locstr = unpunify($contact['xchan_url']);
}
$clone_warn = '';
$clonable = in_array($contact['xchan_network'], ['zot6', 'rss']);
if (!$clonable) {
$clone_warn = '<strong>';
$clone_warn .= ((intval($contact['abook_not_here']))
? t('This contact is unreachable from this location.')
: t('This contact may be unreachable from other channel locations.')
);
$clone_warn .= '</strong><br>' . t('Location independence is not supported by their network.');
}
$header_card = '<img src="' . $contact['xchan_photo_s'] . '" class="rounded" style="width: 3rem; height: 3rem;">&nbsp; ' . $contact['xchan_name'];
$header_html = replace_macros(get_markup_template("contact_edit_header.tpl"), [
'$img_src' => $contact['xchan_photo_s'],
'$name' => $contact['xchan_name'],
'$addr' => (($contact['xchan_addr']) ? $contact['xchan_addr'] : $contact['xchan_url']),
'$href' => ((is_matrix_url($contact['xchan_url'])) ? zid($contact['xchan_url']) : $contact['xchan_url']),
'$link_label' => t('View profile'),
'$is_group' => $contact['xchan_pubforum'],
'$group_label' => t('This is a group/forum channel')
]);
$tools_html = replace_macros(get_markup_template("contact_edit_tools.tpl"), [
'$tools_label' => t('Contact Tools'),
'$tools' => $this->get_tools($contact),
]);
$tpl = get_markup_template("contact_edit.tpl");
$o = replace_macros($tpl, [
'$permcat' => ['permcat', t('Select a role for this contact'), $current_permcat, '', $permcats],
'$permcat_new' => t('Contact roles'),
'$permcat_value' => bin2hex($current_permcat),
// '$addr' => unpunify($contact['xchan_addr']),
// '$primeurl' => unpunify($contact['xchan_url']),
'$section' => $section,
'$sub_section' => $sub_section,
'$groups' => $groups,
// '$addr_text' => t('This contacts\'s primary address is'),
// '$loc_text' => t('Available locations:'),
// '$locstr' => $locstr,
// '$unclonable' => $clone_warn,
'$lbl_slider' => t('Slide to adjust your degree of friendship'),
'$connfilter' => feature_enabled(local_channel(), 'connfilter'),
'$connfilter_label' => t('Custom Filter'),
'$incl' => ['abook_incl', t('Only import posts with this text'), $contact['abook_incl'], t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')],
'$excl' => ['abook_excl', t('Do not import posts with this text'), $contact['abook_excl'], t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')],
'$slide' => $slide,
// '$pending_label' => t('Contact Pending Approval'),
// '$is_pending' => (intval($contact['abook_pending']) ? 1 : ''),
// '$unapproved' => $unapproved,
'$submit' => ((intval($contact['abook_pending'])) ? t('Approve contact') : t('Submit')),
'$close' => (($contact['abook_closeness']) ? $contact['abook_closeness'] : 80),
'$them' => t('Their'),
'$me' => t('My'),
'$perms' => $perms,
// '$lastupdtext' => t('Last update:'),
// '$last_update' => relative_date($contact['abook_connected']),
'$profile_select' => contact_profile_assign($contact['abook_profile']),
'$multiprofs' => $multiprofs,
'$contact_id' => $contact['abook_id'],
// '$name' => $contact['xchan_name'],
'$roles_label' => t('Roles'),
'$compare_label' => t('Compare permissions'),
'$permission_label' => t('Permission'),
'$pgroups_label' => t('Privacy groups'),
'$profiles_label' => t('Profiles'),
'$affinity_label' => t('Affinity'),
'$filter_label' => t('Content filter')
]);
$arr = ['contact' => $contact, 'output' => $o];
call_hooks('contact_edit', $arr);
if (is_ajax()) {
json_return_and_die([
'success' => ((isset($_REQUEST['success'])) ? intval($_REQUEST['success']) : 1),
'message' => ((isset($_REQUEST['success'])) ? t('Contact updated') : t('Contact update failed')),
'id' => $contact_id,
'title' => $header_html,
'role' => ((intval($contact['abook_pending'])) ? '' : $roles_dict[$current_permcat]),
'body' => $arr['output'],
'tools' => $tools_html,
'submit' => ((intval($contact['abook_pending'])) ? t('Approve connection') : t('Submit')),
'pending' => intval($contact['abook_pending'])
]);
}
return $arr['output'];
}
function contactedit_clone() {
if (!App::$poi)
return;
$channel = App::get_channel();
$clone = App::$poi;
unset($clone['abook_id']);
unset($clone['abook_account']);
unset($clone['abook_channel']);
$abconfig = load_abconfig($channel['channel_id'], $clone['abook_xchan']);
if ($abconfig)
$clone['abconfig'] = $abconfig;
Libsync::build_sync_packet(0 /* use the current local_channel */, ['abook' => [$clone]]);
}
function do_action($contact, $cmd) {
$ret = [
'sucess' => false,
'message' => ''
];
if ($cmd === 'resetphoto') {
q("update xchan set xchan_photo_date = '2001-01-01 00:00:00' where xchan_hash = '%s'",
dbesc($contact['xchan_hash'])
);
$cmd = 'refresh';
}
if ($cmd === 'refresh') {
if ($contact['xchan_network'] === 'zot6') {
if (Libzot::refresh($contact, App::get_channel())) {
$ret['success'] = true;
$ret['message'] = t('Refresh succeeded');
}
else {
$ret['message'] = t('Refresh failed - channel is currently unavailable');
}
}
else {
// if you are on a different network we'll force a refresh of the connection basic info
Master::Summon(['Notifier', 'permission_update', $contact['abook_id']]);
$ret['success'] = true;
$ret['message'] = t('Refresh succeeded');
}
return $ret;
}
if ($cmd === 'block') {
if (abook_toggle_flag($contact, ABOOK_FLAG_BLOCKED)) {
$this->init(); // refresh data
$this->contactedit_clone();
$ret['success'] = true;
$ret['message'] = t('Block status updated');
}
else {
$ret['success'] = false;
$ret['message'] = t('Block failed');
}
return $ret;
}
if ($cmd === 'ignore') {
if (abook_toggle_flag($contact, ABOOK_FLAG_IGNORED)) {
$this->init(); // refresh data
$this->contactedit_clone();
$ret['success'] = true;
$ret['message'] = t('Ignore status updated');
}
else {
$ret['success'] = false;
$ret['message'] = t('Ignore failed');
}
return $ret;
}
if ($cmd === 'archive') {
if (abook_toggle_flag($contact, ABOOK_FLAG_ARCHIVED)) {
$this->init(); // refresh data
$this->contactedit_clone();
$ret['success'] = true;
$ret['message'] = t('Archive status updated');
}
else {
$ret['success'] = false;
$ret['message'] = t('Archive failed');
}
return $ret;
}
if ($cmd === 'hide') {
if (abook_toggle_flag($contact, ABOOK_FLAG_HIDDEN)) {
$this->init(); // refresh data
$this->contactedit_clone();
$ret['success'] = true;
$ret['message'] = t('Hide status updated');
}
else {
$ret['success'] = false;
$ret['message'] = t('Hide failed');
}
return $ret;
}
// We'll prevent somebody from unapproving an already approved contact.
// Though maybe somebody will want this eventually (??)
//if ($cmd === 'approve') {
//if (intval($contact['abook_pending'])) {
//if (abook_toggle_flag($contact, ABOOK_FLAG_PENDING)) {
//$this->contactedit_clone();
//}
//else
//notice(t('Unable to set address book parameters.') . EOL);
//}
//goaway(z_root() . '/connedit/' . $contact_id);
//}
if ($cmd === 'drop') {
if (contact_remove(local_channel(), $contact['abook_id'])) {
Master::Summon(['Notifier', 'purge', local_channel(), $contact['xchan_hash']]);
Libsync::build_sync_packet(0 /* use the current local_channel */,
['abook' => [
[
'abook_xchan' => $contact['abook_xchan'],
'entry_deleted' => true
]
]
]);
$ret['success'] = true;
$ret['message'] = t('Contact removed');
}
else {
$ret['success'] = false;
$ret['message'] = t('Delete failed');
}
return $ret;
}
}
function get_tools($contact) {
return [
'refresh' => [
'label' => t('Refresh Permissions'),
'title' => t('Fetch updated permissions'),
],
'rephoto' => [
'label' => t('Refresh Photo'),
'title' => t('Fetch updated photo'),
],
'block' => [
'label' => (intval($contact['abook_blocked']) ? t('Unblock') : t('Block')),
'sel' => (intval($contact['abook_blocked']) ? 'active' : ''),
'title' => t('Block (or Unblock) all communications with this connection'),
'info' => (intval($contact['abook_blocked']) ? t('This connection is blocked!') : ''),
],
'ignore' => [
'label' => (intval($contact['abook_ignored']) ? t('Unignore') : t('Ignore')),
'sel' => (intval($contact['abook_ignored']) ? 'active' : ''),
'title' => t('Ignore (or Unignore) all inbound communications from this connection'),
'info' => (intval($contact['abook_ignored']) ? t('This connection is ignored!') : ''),
],
'archive' => [
'label' => (intval($contact['abook_archived']) ? t('Unarchive') : t('Archive')),
'sel' => (intval($contact['abook_archived']) ? 'active' : ''),
'title' => t('Archive (or Unarchive) this connection - mark channel dead but keep content'),
'info' => (intval($contact['abook_archived']) ? t('This connection is archived!') : ''),
],
'hide' => [
'label' => (intval($contact['abook_hidden']) ? t('Unhide') : t('Hide')),
'sel' => (intval($contact['abook_hidden']) ? 'active' : ''),
'title' => t('Hide or Unhide this connection from your other connections'),
'info' => (intval($contact['abook_hidden']) ? t('This connection is hidden!') : ''),
],
'delete' => [
'label' => t('Delete'),
'sel' => '',
'title' => t('Delete this connection'),
],
];
}
}

View File

@@ -1,17 +1,17 @@
<?php
namespace Zotlabs\Module;
require_once('include/group.php');
use Zotlabs\Lib\AccessList;
use Zotlabs\Web\Controller;
class Contactgroup extends \Zotlabs\Web\Controller {
class Contactgroup extends Controller {
function get() {
if(! local_channel()) {
killme();
}
if((argc() > 2) && (intval(argv(1))) && (argv(2))) {
$r = q("SELECT abook_xchan from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1",
dbesc(base64url_decode(argv(2))),
@@ -20,9 +20,9 @@ class Contactgroup extends \Zotlabs\Web\Controller {
if($r)
$change = $r[0]['abook_xchan'];
}
if((argc() > 1) && (intval(argv(1)))) {
$r = q("SELECT * FROM pgrp WHERE id = %d AND uid = %d AND deleted = 0 LIMIT 1",
intval(argv(1)),
intval(local_channel())
@@ -30,25 +30,25 @@ class Contactgroup extends \Zotlabs\Web\Controller {
if(! $r) {
killme();
}
$group = $r[0];
$members = group_get_members($group['id']);
$members = AccessList::members(local_channel(), $group['id']);
$preselected = array();
if(count($members)) {
foreach($members as $member)
$preselected[] = $member['xchan_hash'];
}
if($change) {
if(in_array($change,$preselected)) {
group_rmv_member(local_channel(),$group['gname'],$change);
AccessList::member_remove(local_channel(),$group['gname'],$change);
}
else {
group_add_member(local_channel(),$group['gname'],$change);
AccessList::member_add(local_channel(),$group['gname'],$change);
}
}
}
killme();
}
}

View File

@@ -0,0 +1,188 @@
<?php
namespace Zotlabs\Module;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\Libzot;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Lib\LDSignatures;
use Zotlabs\Lib\ThreadListener;
use Zotlabs\Lib\Config;
use App;
class Conversation extends Controller {
public function init() {
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 ('%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 mid = '%s' or uuid = '%s' $item_normal order by item_wall desc limit 1",
dbesc(z_root() . '/item/' . $item_id),
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'];
observer_auth($portable_id);
// first see if we have a copy of this item's parent owned by the current signer
// include xchans for all zot-like networks - these will have the same guid and public key
$x = q(
"select * from xchan where xchan_hash = '%s'",
dbesc($sigdata['portable_id'])
);
if ($x) {
$xchans = q(
"select xchan_hash from xchan where xchan_hash = '%s' OR ( xchan_guid = '%s' AND xchan_pubkey = '%s' ) ",
dbesc($sigdata['portable_id']),
dbesc($x[0]['xchan_guid']),
dbesc($x[0]['xchan_pubkey'])
);
if ($xchans) {
$hashes = ids_to_querystr($xchans, 'xchan_hash', true);
$i = q(
"select id as item_id from item where mid = '%s' $item_normal and owner_xchan in ( " . protect_sprintf($hashes) . " ) limit 1",
dbesc($r[0]['parent_mid'])
);
}
}
}
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'])
);
}
if (!$i) {
http_status_exit(403, 'Forbidden');
}
$parents_str = ids_to_querystr($i, 'item_id');
$itemspage = 30;
$page = $_REQUEST['page'] ?? 1;
$offset = (intval($page) - 1) * $itemspage;
$items = dbq("SELECT item.*,
item.id AS item_id,
(SELECT count(*) FROM item WHERE item.parent IN ( $parents_str ) $item_normal) AS total
FROM item WHERE item.parent IN ( $parents_str ) $item_normal order by item.id LIMIT $itemspage OFFSET $offset"
);
if (!$items) {
http_status_exit(404, 'Not found');
}
xchan_query($items, true);
$items = fetch_post_tags($items);
$observer = App::get_observer();
$parent = $items[0];
$recips = (($parent['owner']['xchan_network'] === 'activitypub') ? get_iconfig($parent['id'], 'activitypub', 'recips', []) : []);
$to = (($recips && array_key_exists('to', $recips) && is_array($recips['to'])) ? $recips['to'] : null);
$nitems = [];
foreach ($items as $i) {
$mids = [];
if (intval($i['item_private'])) {
if (!$observer) {
continue;
}
/*
// ignore private reshare, possibly from hubzilla
if ($i['verb'] === 'Announce') {
if (!in_array($i['thr_parent'], $mids)) {
$mids[] = $i['thr_parent'];
}
continue;
}
// also ignore any children of the private reshares
if (in_array($i['thr_parent'], $mids)) {
continue;
}
*/
if ((!$to) || (!in_array($observer['xchan_url'], $to))) {
continue;
}
}
$nitems[] = $i;
}
if (!$nitems) {
http_status_exit(404, 'Not found');
}
App::set_pager_total($nitems[0]['total']);
App::set_pager_itemspage($itemspage);
$channel = channelx_by_n($nitems[0]['uid']);
if (!$channel) {
http_status_exit(404, 'Not found');
}
if (!perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_stream')) {
http_status_exit(403, 'Forbidden');
}
$i = Activity::encode_item_collection($nitems, App::$query_string, 'OrderedCollection', $nitems[0]['total']);
if (!$i) {
http_status_exit(404, 'Not found');
}
if ($portable_id && (!intval($nitems[0]['item_private']))) {
$c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'",
intval($nitems[0]['uid']),
dbesc($portable_id)
);
if (!$c) {
ThreadListener::store(z_root() . '/item/' . $item_id, $portable_id);
}
}
as_return_and_die($i, $channel);
}
goaway(z_root() . '/item/' . argv(1));
}
}

View File

@@ -3,7 +3,7 @@ namespace Zotlabs\Module;
use Zotlabs\Lib\Libsync;
/*
/*
@file cover_photo.php
@brief Module-file with functions for handling of cover-photos
@@ -29,43 +29,43 @@ class Cover_photo extends \Zotlabs\Web\Controller {
if(! local_channel()) {
return;
}
$channel = \App::get_channel();
profile_load($channel['channel_address']);
profile_load($channel['channel_address']);
}
/**
* @brief Evaluate posted values
*
* @return void
*
*/
function post() {
if(! local_channel()) {
return;
}
$channel = \App::get_channel();
check_form_security_token_redirectOnErr('/cover_photo', 'cover_photo');
// Remove cover photo
if(isset($_POST['remove'])) {
$r = q("SELECT resource_id FROM photo WHERE photo_usage = %d AND uid = %d LIMIT 1",
intval(PHOTO_COVER),
intval(local_channel())
);
if($r) {
q("update photo set photo_usage = %d where photo_usage = %d and uid = %d",
intval(PHOTO_NORMAL),
intval(PHOTO_COVER),
intval(local_channel())
);
$sync = attach_export_data($channel,$r[0]['resource_id']);
if($sync)
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
@@ -76,47 +76,47 @@ class Cover_photo extends \Zotlabs\Web\Controller {
goaway(z_root() . '/cover_photo');
}
if((array_key_exists('cropfinal',$_POST)) && ($_POST['cropfinal'] == 1)) {
// phase 2 - we have finished cropping
if(argc() != 2) {
notice( t('Image uploaded but image cropping failed.') . EOL );
return;
}
$image_id = argv(1);
if(substr($image_id,-2,1) == '-') {
$scale = substr($image_id,-1,1);
$image_id = substr($image_id,0,-2);
}
$srcX = intval($_POST['xstart']);
$srcY = intval($_POST['ystart']);
$srcW = intval($_POST['xfinal']) - $srcX;
$srcH = intval($_POST['yfinal']) - $srcY;
$r = q("select gender from profile where uid = %d and is_default = 1 limit 1",
intval(local_channel())
);
if($r) {
$profile = $r[0];
}
$r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale = 0 LIMIT 1",
dbesc($image_id),
intval(local_channel())
);
if($r) {
$max_thumb = intval(get_config('system','max_thumbnail',1600));
$iscaled = false;
if(intval($r[0]['height']) > $max_thumb || intval($r[0]['width']) > $max_thumb) {
if(intval($r[0]['height']) > $max_thumb || intval($r[0]['width']) > $max_thumb) {
$imagick_path = get_config('system','imagick_convert_path');
if($imagick_path && @file_exists($imagick_path) && intval($r[0]['os_storage'])) {
@@ -150,63 +150,63 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$im = photo_factory($base_image['content'], $base_image['mimetype']);
if($im->is_valid()) {
// We are scaling and cropping the relative pixel locations to the original photo instead of the
// We are scaling and cropping the relative pixel locations to the original photo instead of the
// scaled photo we operated on.
// First load the scaled photo to check its size. (Should probably pass this in the post form and save
// a query.)
$g = q("select width, height from photo where resource_id = '%s' and uid = %d and imgscale = 3",
dbesc($image_id),
intval(local_channel())
);
$scaled_width = $g[0]['width'];
$scaled_height = $g[0]['height'];
if((! $scaled_width) || (! $scaled_height)) {
logger('potential divide by zero scaling cover photo');
return;
}
// unset all other cover photos
q("update photo set photo_usage = %d where photo_usage = %d and uid = %d",
intval(PHOTO_NORMAL),
intval(PHOTO_COVER),
intval(local_channel())
);
$orig_srcx = ( $base_image['width'] / $scaled_width ) * $srcX;
$orig_srcy = ( $base_image['height'] / $scaled_height ) * $srcY;
$orig_srcw = ( $srcW / $scaled_width ) * $base_image['width'];
$orig_srch = ( $srcH / $scaled_height ) * $base_image['height'];
$im->cropImageRect(1200,435,$orig_srcx, $orig_srcy, $orig_srcw, $orig_srch);
$aid = get_account_id();
$p = [
'aid' => $aid,
'uid' => local_channel(),
$p = [
'aid' => $aid,
'uid' => local_channel(),
'resource_id' => $base_image['resource_id'],
'filename' => $base_image['filename'],
'filename' => $base_image['filename'],
'album' => t('Cover Photos'),
'os_path' => $base_image['os_path'],
'display_path' => $base_image['display_path'],
'photo_usage' => PHOTO_COVER
];
$r1 = $im->storeThumbnail($p, PHOTO_RES_COVER_1200);
$im->doScaleImage(850,310);
$r2 = $im->storeThumbnail($p, PHOTO_RES_COVER_850);
$im->doScaleImage(425,160);
$r3 = $im->storeThumbnail($p, PHOTO_RES_COVER_425);
if($r1 === false || $r2 === false || $r3 === false) {
// if one failed, delete them all so we can start over.
notice( t('Image resize failed.') . EOL );
@@ -214,7 +214,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
dbesc($base_image['resource_id']),
local_channel()
);
$x = q("SELECT content FROM photo WHERE resource_id = '%s' AND uid = %d AND os_storage = 1 AND imgscale >= 7",
dbesc($base_image['resource_id']),
local_channel()
@@ -229,7 +229,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
}
$this->send_cover_photo_activity($channel,$base_image,$profile);
$sync = attach_export_data($channel,$base_image['resource_id']);
if($sync)
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
@@ -240,33 +240,33 @@ class Cover_photo extends \Zotlabs\Web\Controller {
else
notice( t('Unable to process image') . EOL);
}
goaway(z_root() . '/channel/' . $channel['channel_address']);
}
$hash = photo_new_resource();
$smallest = 0;
require_once('include/attach.php');
$res = attach_store(\App::get_channel(), get_observer_hash(), '', array('album' => t('Cover Photos'), 'hash' => $hash, 'nosync' => true));
logger('attach_store: ' . print_r($res,true));
if($res && intval($res['data']['is_photo'])) {
$i = q("select * from photo where resource_id = '%s' and uid = %d and imgscale = 0",
dbesc($hash),
intval(local_channel())
);
if(! $i) {
notice( t('Image upload failed.') . EOL );
return;
}
$os_storage = false;
foreach($i as $ii) {
$smallest = intval($ii['imgscale']);
$os_storage = intval($ii['os_storage']);
@@ -274,91 +274,91 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$filetype = $ii['mimetype'];
}
}
$imagedata = (($os_storage) ? @file_get_contents(dbunescbin($imagedata)) : dbunescbin($imagedata));
$ph = photo_factory($imagedata, $filetype);
if(! $ph->is_valid()) {
notice( t('Unable to process image.') . EOL );
return;
}
return $this->cover_photo_crop_ui_head($a, $ph, $hash, $smallest);
}
function send_cover_photo_activity($channel,$photo,$profile) {
$arr = array();
$arr['item_thread_top'] = 1;
$arr['item_origin'] = 1;
$arr['item_wall'] = 1;
if($profile && stripos($profile['gender'],t('female')) !== false)
$t = t('%1$s updated her %2$s');
elseif($profile && stripos($profile['gender'],t('male')) !== false)
$t = t('%1$s updated his %2$s');
else
$t = t('%1$s updated their %2$s');
$ptext = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo['resource_id'] . ']' . t('cover photo') . '[/zrl]';
$ltext = '[zrl=' . z_root() . '/profile/' . $channel['channel_address'] . ']' . '[zmg]' . z_root() . '/photo/' . $photo['resource_id'] . '-8[/zmg][/zrl]';
$ltext = '[zrl=' . z_root() . '/profile/' . $channel['channel_address'] . ']' . '[zmg]' . z_root() . '/photo/' . $photo['resource_id'] . '-8[/zmg][/zrl]';
$arr['body'] = sprintf($t,$channel['channel_name'],$ptext) . "\n\n" . $ltext;
$acl = new \Zotlabs\Access\AccessList($channel);
$x = $acl->get();
$arr['allow_cid'] = $x['allow_cid'];
$arr['allow_gid'] = $x['allow_gid'];
$arr['deny_cid'] = $x['deny_cid'];
$arr['deny_gid'] = $x['deny_gid'];
$arr['uid'] = $channel['channel_id'];
$arr['aid'] = $channel['channel_account_id'];
$arr['owner_xchan'] = $channel['channel_hash'];
$arr['author_xchan'] = $channel['channel_hash'];
post_activity_item($arr);
}
/**
* @brief Generate content of profile-photo view
*
* @return string
*
*/
function get() {
if(! local_channel()) {
notice( t('Permission denied.') . EOL );
return;
}
$channel = \App::get_channel();
$newuser = false;
if(argc() == 2 && argv(1) === 'new')
$newuser = true;
if(argv(1) === 'use') {
if (argc() < 3) {
notice( t('Permission denied.') . EOL );
return;
};
// check_form_security_token_redirectOnErr('/cover_photo', 'cover_photo');
$resource_id = argv(2);
$r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' ORDER BY imgscale ASC",
intval(local_channel()),
dbesc($resource_id)
@@ -372,22 +372,22 @@ class Cover_photo extends \Zotlabs\Web\Controller {
if($rr['imgscale'] == 7)
$havescale = true;
}
$r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1",
intval($r[0]['id']),
intval(local_channel())
);
if(! $r) {
notice( t('Photo not available.') . EOL );
return;
}
if(intval($r[0]['os_storage']))
$data = @file_get_contents(dbunescbin($r[0]['content']));
else
$data = dbunescbin($r[0]['content']);
$data = dbunescbin($r[0]['content']);
$ph = photo_factory($data, $r[0]['mimetype']);
$smallest = 0;
if($ph->is_valid()) {
@@ -396,7 +396,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
dbesc($r[0]['resource_id']),
intval(local_channel())
);
if($i) {
$hash = $i[0]['resource_id'];
foreach($i as $ii) {
@@ -404,15 +404,15 @@ class Cover_photo extends \Zotlabs\Web\Controller {
}
}
}
$this->cover_photo_crop_ui_head($a, $ph, $hash, $smallest);
}
if(! x(\App::$data,'imagecrop')) {
$tpl = get_markup_template('cover_photo.tpl');
$o .= replace_macros($tpl,array(
'$user' => \App::$channel['channel_address'],
'$info' => t('Your cover photo may be visible to anybody on the internet'),
@@ -422,7 +422,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
'$title' => t('Change Cover Photo'),
'$submit' => t('Upload'),
'$remove' => t('Remove'),
'$profiles' => $profiles,
'$profiles' => false,
'$embedPhotos' => t('Use a photo from your albums'),
'$embedPhotosModalTitle' => t('Use a photo from your albums'),
'$embedPhotosModalCancel' => t('Cancel'),
@@ -434,13 +434,13 @@ class Cover_photo extends \Zotlabs\Web\Controller {
'$modalerrorlink' => t('Error getting photo link'),
'$modalerroralbum' => t('Error getting album'),
'$form_security_token' => get_form_security_token("cover_photo"),
/// @FIXME - yuk
/// @FIXME - yuk
'$select' => t('Select existing photo'),
));
call_hooks('cover_photo_content_end', $o);
return $o;
}
else {
@@ -459,10 +459,8 @@ class Cover_photo extends \Zotlabs\Web\Controller {
));
return $o;
}
return; // NOTREACHED
}
/* @brief Generate the UI for photo-cropping
*
* @param $a Current application
@@ -470,30 +468,30 @@ class Cover_photo extends \Zotlabs\Web\Controller {
* @return void
*
*/
function cover_photo_crop_ui_head(&$a, $ph, $hash, $smallest){
$max_length = get_config('system','max_image_length');
if(! $max_length)
$max_length = MAX_IMAGE_LENGTH;
if($max_length > 0)
$ph->scaleImage($max_length);
$width = $ph->getWidth();
$height = $ph->getHeight();
if($width < 300 || $height < 300) {
$ph->scaleImageUp(240);
$width = $ph->getWidth();
$height = $ph->getHeight();
}
\App::$data['imagecrop'] = $hash;
\App::$data['imagecrop_resolution'] = $smallest;
\App::$page['htmlhead'] .= replace_macros(get_markup_template("crophead.tpl"), array());
return;
}
}

View File

@@ -8,7 +8,6 @@ use Zotlabs\Lib\Libsync;
require_once('include/socgraph.php');
require_once('include/selectors.php');
require_once('include/group.php');
require_once('include/photos.php');
class Defperms extends Controller {
@@ -23,8 +22,8 @@ class Defperms extends Controller {
if(! local_channel())
return;
if(! Apps::system_app_installed(local_channel(), 'Default Permissions'))
return;
//if(! Apps::system_app_installed(local_channel(), 'Default Permissions'))
// return;
$r = q("SELECT abook.*, xchan.*
FROM abook left join xchan on abook_xchan = xchan_hash
@@ -50,8 +49,8 @@ class Defperms extends Controller {
if(! local_channel())
return;
if(! Apps::system_app_installed(local_channel(), 'Default Permissions'))
return;
//if(! Apps::system_app_installed(local_channel(), 'Default Permissions'))
// return;
$contact_id = intval(argv(1));
if(! $contact_id)
@@ -183,12 +182,12 @@ class Defperms extends Controller {
return login();
}
if(! Apps::system_app_installed(local_channel(), 'Default Permissions')) {
//Do not display any associated widgets at this point
App::$pdl = '';
$papp = Apps::get_papp('Default Permissions');
return Apps::app_render($papp, 'module');
}
//~ if(! Apps::system_app_installed(local_channel(), 'Default Permissions')) {
//~ //Do not display any associated widgets at this point
//~ App::$pdl = '';
//~ $papp = Apps::get_papp('Default Permissions');
//~ return Apps::app_render($papp, 'module');
//~ }
$section = ((array_key_exists('section',$_REQUEST)) ? $_REQUEST['section'] : '');
$channel = App::get_channel();
@@ -259,7 +258,6 @@ class Defperms extends Controller {
'$sections' => $sections,
'$autolbl' => t('The permissions indicated on this page will be applied to all new connections.'),
'$autoapprove' => t('Automatic approval settings'),
'$unapproved' => $unapproved,
'$inherited' => t('inherited'),
'$submit' => t('Submit'),
'$me' => t('My Settings'),

View File

@@ -4,6 +4,7 @@ namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Libzotdir;
class Dircensor extends Controller {
@@ -15,11 +16,12 @@ class Dircensor extends Controller {
$dirmode = intval(get_config('system','directory_mode'));
if (! ($dirmode == DIRECTORY_MODE_PRIMARY || $dirmode == DIRECTORY_MODE_STANDALONE)) {
if(!in_array($dirmode, [DIRECTORY_MODE_PRIMARY, DIRECTORY_MODE_SECONDARY, DIRECTORY_MODE_STANDALONE])) {
return;
}
$xchan = argv(1);
if(! $xchan) {
return;
}
@@ -32,19 +34,43 @@ class Dircensor extends Controller {
return;
}
$val = (($r[0]['xchan_censored']) ? 0 : 1);
$severity = intval($_REQUEST['severity'] ?? 0);
$flag = DIRECTORY_FLAG_OK;
q("update xchan set xchan_censored = $val where xchan_hash = '%s'",
if ($severity === 1) {
$flag = DIRECTORY_FLAG_UNSAFE;
}
if ($severity === 2) {
$flag = DIRECTORY_FLAG_HIDDEN;
}
Libzotdir::update($xchan, $r[0]['xchan_url'], true, $flag);
q("UPDATE xchan SET xchan_censored = %d WHERE xchan_hash = '%s'",
intval($flag),
dbesc($xchan)
);
if($val) {
q("UPDATE xtag SET xtag_flags = %d WHERE xtag_hash = '%s'",
intval($flag),
dbesc($xchan)
);
if($flag) {
info( t('Entry censored') . EOL);
}
else {
info( t('Entry uncensored') . EOL);
info( t('Entry OK') . EOL);
}
if (isset($_REQUEST['aj'])) {
json_return_and_die([
'success' => 1,
'flag' => $flag
]);
}
goaway(z_root() . '/directory');
}

View File

@@ -83,7 +83,7 @@ class Directory extends Controller {
$globaldir = Libzotdir::get_directory_setting($observer, 'globaldir');
// override your personal global search pref if we're doing a navbar search of the directory
if(intval($_REQUEST['navsearch']))
if(isset($_REQUEST['navsearch']) && intval($_REQUEST['navsearch']))
$globaldir = 1;
$safe_mode = Libzotdir::get_directory_setting($observer, 'safemode');
@@ -98,15 +98,18 @@ class Directory extends Controller {
else
$search = ((x($_GET,'search')) ? notags(trim(rawurldecode($_GET['search']))) : '');
$advanced = '';
if(strpos($search,'=') && local_channel() && feature_enabled(local_channel(), 'advanced_dirsearch'))
$advanced = $search;
$keywords = (($_GET['keywords']) ? $_GET['keywords'] : '');
$keywords = $_GET['keywords'] ?? '';
// Suggest channels if no search terms or keywords are given
$suggest = (local_channel() && x($_REQUEST,'suggest')) ? $_REQUEST['suggest'] : '';
$addresses = [];
$common = [];
if($suggest) {
// the directory options have no effect in suggestion mode
@@ -123,8 +126,7 @@ class Directory extends Controller {
}
// Remember in which order the suggestions were
$addresses = array();
$common = array();
$index = 0;
foreach($r as $rr) {
$common[$rr['xchan_addr']] = ((intval($rr['total']) > 0) ? intval($rr['total']) - 1 : 0);
@@ -132,7 +134,7 @@ class Directory extends Controller {
}
// Build query to get info about suggested people
$advanced = '';
foreach(array_keys($addresses) as $address) {
$advanced .= "address=\"$address\" ";
}
@@ -147,7 +149,9 @@ class Directory extends Controller {
$directory_admin = false;
if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) {
$url = '';
if(in_array($dirmode, [DIRECTORY_MODE_PRIMARY, DIRECTORY_MODE_SECONDARY, DIRECTORY_MODE_STANDALONE])) {
$url = z_root() . '/dirsearch';
if (is_site_admin()) {
$directory_admin = true;
@@ -187,7 +191,10 @@ class Directory extends Controller {
if(get_config('system','disable_directory_keywords'))
$kw = 0;
$query = $url . '?f=&kw=' . $kw . (($safe_mode != 1) ? '&safe=' . $safe_mode : '');
if (intval($safe_mode) === 0 && $directory_admin)
$safe_mode = -1;
$query = $url . '?f=&kw=' . $kw . (($safe_mode < 1) ? '&safe=' . $safe_mode : '');
if($token)
$query .= '&t=' . $token;
@@ -228,7 +235,7 @@ class Directory extends Controller {
$j = json_decode($x['body'],true);
if($j) {
if($j['results']) {
if(isset($j['results']) && $j['results']) {
$results = $j['results'];
if($suggest) {
@@ -254,40 +261,33 @@ class Directory extends Controller {
$connect_link = '';
$location = '';
if(strlen($rr['locale']))
if(isset($rr['locale']))
$location .= $rr['locale'];
if(strlen($rr['region'])) {
if(strlen($rr['locale']))
if(isset($rr['region'])) {
if($location)
$location .= ', ';
$location .= $rr['region'];
}
if(strlen($rr['country'])) {
if(strlen($location))
if(isset($rr['country'])) {
if($location)
$location .= ', ';
$location .= $rr['country'];
}
$age = '';
if(strlen($rr['birthday'])) {
if(isset($rr['birthday'])) {
if(($years = age($rr['birthday'],'UTC','')) > 0)
$age = $years;
}
$page_type = '';
$rating_enabled = get_config('system','rating_enabled');
if($rr['total_ratings'] && $rating_enabled)
$total_ratings = sprintf( tt("%d rating", "%d ratings", $rr['total_ratings']), $rr['total_ratings']);
else
$total_ratings = '';
$profile = $rr;
if ((x($profile,'locale') == 1)
|| (x($profile,'region') == 1)
|| (x($profile,'postcode') == 1)
|| (x($profile,'country') == 1))
// if ((x($profile,'locale') == 1)
// || (x($profile,'region') == 1)
// || (x($profile,'postcode') == 1)
// || (x($profile,'country') == 1))
$gender = ((x($profile,'gender') == 1) ? t('Gender: ') . $profile['gender']: False);
@@ -299,10 +299,11 @@ class Directory extends Controller {
$hometown = ((x($profile,'hometown') == 1) ? html2plain($profile['hometown']) : False);
$about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'], ['tryoembed' => false])) : False);
if ($about && $safe_mode) {
$about = html2plain($about);
if ($about && $safe_mode > 0) {
$about = strip_tags($about, '<br>');
}
$keywords = ((x($profile,'keywords')) ? $profile['keywords'] : '');
@@ -312,7 +313,7 @@ class Directory extends Controller {
$keywords = str_replace(',',' ', $keywords);
$keywords = str_replace(' ',' ', $keywords);
$karr = explode(' ', $keywords);
$marr = [];
if($karr) {
if(local_channel()) {
$r = q("select keywords from profile where uid = %d and is_default = 1 limit 1",
@@ -352,16 +353,17 @@ class Directory extends Controller {
'location' => $location,
'location_label' => t('Location:'),
'gender' => $gender,
'total_ratings' => $total_ratings,
'viewrate' => true,
'canrate' => (($rating_enabled && local_channel()) ? true : false),
'pdesc' => $pdesc,
'pdesc_label' => t('Description:'),
'censor' => (($directory_admin) ? 'dircensor/' . $rr['hash'] : ''),
'censor_label' => (($rr['censored']) ? t('Uncensor') : t('Censor')),
'censor' => (($directory_admin) ? 'dircensor/' . $rr['hash'] . '?severity=' . ((intval($rr['censored']) > 0) ? 0 : 1) : ''),
'censor_label' => t('Unsafe'),
'censor_class' => ((intval($rr['censored']) === 1) ? 'active' : ''),
'censor_2' => (($directory_admin) ? 'dircensor/' . $rr['hash'] . '?severity=' . ((intval($rr['censored']) > 1) ? 0 : 2) : ''),
'censor_2_label' => t('Spam'),
'censor_2_class' => ((intval($rr['censored']) > 1) ? 'active' : ''),
'marital' => $marital,
'homepage' => $homepage,
'homepageurl' => (($safe_mode) ? $homepageurl : linkify($homepageurl)),
'homepageurl' => (($safe_mode > 0) ? $homepageurl : linkify($homepageurl)),
'hometown' => $hometown,
'hometown_label' => t('Hometown:'),
'about' => $about,
@@ -374,9 +376,9 @@ class Directory extends Controller {
'keywords' => $out,
'ignlink' => $suggest ? z_root() . '/directory?ignore=' . $rr['hash'] : '',
'ignore_label' => t('Don\'t suggest'),
'common_friends' => (($common[$rr['address']]) ? intval($common[$rr['address']]) : ''),
'common_friends' => $common[$rr['address']] ?? '',
'common_label' => t('Common connections (estimated):'),
'common_count' => intval($common[$rr['address']]),
'common_count' => $common[$rr['address']] ?? '',
'safe' => $safe_mode
);
@@ -402,14 +404,15 @@ class Directory extends Controller {
ksort($entries); // Sort array by key so that foreach-constructs work as expected
if($j['keywords']) {
if(isset($j['keywords']) && $j['keywords']) {
App::$data['directory_keywords'] = $j['keywords'];
}
logger('mod_directory: entries: ' . print_r($entries,true), LOGGER_DATA);
$aj = $_REQUEST['aj'] ?? '';
if($_REQUEST['aj']) {
if($aj) {
if($entries) {
$o = replace_macros(get_markup_template('directajax.tpl'),array(
'$entries' => $entries
@@ -441,7 +444,8 @@ class Directory extends Controller {
'$reverse' => t('Reverse Alphabetic'),
'$date' => t('Newest to Oldest'),
'$reversedate' => t('Oldest to Newest'),
'$suggest' => $suggest ? '&suggest=1' : ''
'$suggest' => $suggest ? '&suggest=1' : '',
'$directory_admin' => $directory_admin
));
@@ -449,12 +453,12 @@ class Directory extends Controller {
}
else {
if($_REQUEST['aj']) {
if(isset($_REQUEST['aj']) && $_REQUEST['aj']) {
$o = '<div id="content-complete"></div>';
echo $o;
killme();
}
if(App::$pager['page'] == 1 && $j['records'] == 0 && strpos($search,'@')) {
if(App::$pager['page'] == 1 && (isset($j['records']) && $j['records'] == 0) && strpos($search,'@')) {
goaway(z_root() . '/chanview/?f=&address=' . $search);
}
info( t("No entries (some entries may be hidden).") . EOL);

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