Compare commits

..

452 Commits
4.4 ... 4.7.2

Author SHA1 Message Date
Mario
e7e79f7423 bump version 2020-02-27 08:38:01 +00:00
Mario
589af1f9ee Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2020-02-26 09:51:56 +00:00
Mario
e7f25b8466 implement poll UI in jot 2020-02-26 09:51:40 +00:00
Max Kostikov
2100441b54 Merge branch 'dev' into 'dev'
Update Russian translation

See merge request hubzilla/core!1839
2020-02-26 00:17:58 +01:00
Max Kostikov
082826ee44 Update hstrings.php 2020-02-26 00:12:57 +01:00
Max Kostikov
93ad3eb6f1 Update hmessages.po 2020-02-26 00:12:23 +01:00
Max Kostikov
177209b5e9 Merge branch 'dev' into 'dev'
Fix missprint in Russian translation

See merge request hubzilla/core!1838
2020-02-25 21:43:48 +01:00
Max Kostikov
47d80df81c Update hmessages.po 2020-02-25 21:38:33 +01:00
Max Kostikov
3d6fa049da Update hstrings.php 2020-02-25 21:37:49 +01:00
Max Kostikov
16738dfe7f Merge branch 'dev' into 'dev'
Minor cdav related changes

See merge request hubzilla/core!1836
2020-02-24 12:10:00 +01:00
Max Kostikov
c28ba4be37 Update cdav import parameters comment 2020-02-24 11:39:26 +01:00
Max Kostikov
8bcdc24fcb Code reuse 2020-02-24 11:38:23 +01:00
Mario
b36eb9a91c Merge branch 'dev' into 'dev'
Implement DAV calendars sync with clones

See merge request hubzilla/core!1834
2020-02-24 10:02:09 +01:00
Max Kostikov
989fbe70cd Implement DAV calendars sync with clones 2020-02-24 10:02:09 +01:00
Mario
7bb94f9993 Merge branch 'patch-20200221a' into 'dev'
Fix: hang on too few items

See merge request hubzilla/core!1832
2020-02-23 14:40:18 +01:00
M. Dent
1297c8d2ae Fix: hang on too few items 2020-02-23 14:40:18 +01:00
Mario
ed28ef185e polls can also appear in shares 2020-02-23 08:45:39 +00:00
Mario
9d97cc2a1d implement optional events and polls filter 2020-02-21 10:44:26 +00:00
Mario
23acf02d58 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2020-02-20 21:25:52 +00:00
Mario
60311eb04b fix warning 2020-02-20 21:25:41 +00:00
Mario
b9a8b9e47b Merge branch 'dev' into 'dev'
Implement CardDAV address book sync with clones

See merge request hubzilla/core!1829
2020-02-20 20:03:50 +01:00
Max Kostikov
b7bac45427 Revert "Use argv() instead URI parsing"
This reverts commit bcfb69eeeef6a0506a0ec0574a03b673df84a55a
2020-02-20 20:03:50 +01:00
Mario
7d05b8e5fd vote issue 2020-02-20 17:16:14 +00:00
Mario
d5ae9aedc4 remove unused images 2020-02-13 10:38:47 +01:00
Max Kostikov
1b216e6019 Merge branch 'dev' into 'dev'
issue with multi-line poll elements

See merge request hubzilla/core!1831
2020-02-13 08:33:20 +01:00
zotlabs
83256c9ccd issue with multi-line poll elements 2020-02-12 14:17:28 -08:00
Mario
9f029336ca fix notifications for polls 2020-02-11 09:20:32 +00:00
Mario
95476cf33c Merge branch 'dev' into 'dev'
this allows polls to federate from hubzilla to zap, though still a remaining issue with voting

See merge request hubzilla/core!1830
2020-02-11 07:55:34 +01:00
zotlabs
bf7c96807a fix poll responses 2020-02-10 18:17:41 -08:00
zotlabs
d4a6aa7801 this allows polls to federate from hubzilla to zap, though still a remaining issue with voting 2020-02-10 15:34:33 -08:00
zotlabs
b767bda410 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2020-02-10 14:38:28 -08:00
Mario
a39d436f9f poll fixes 2020-02-10 20:37:35 +00:00
Mario
50dbe1e62d Merge branch 'dev' into 'dev'
poll updates

See merge request hubzilla/core!1828
2020-02-10 12:25:11 +01:00
zotlabs
be81a40b2b Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2020-02-09 16:33:12 -08:00
zotlabs
bbcb237f5b poll updates 2020-02-09 16:32:18 -08:00
Mario
33be244d8a Merge branch 'patch-1' into 'dev'
Add 'hook call' to be used for new addon 'NavBanner_options'

See merge request hubzilla/core!1827
2020-02-07 11:24:01 +01:00
Voryzen
ca75619518 Add 'hook call' to be used for new addon 'NavBanner_options' 2020-02-07 11:24:01 +01:00
Max Kostikov
82acfb75a1 Merge branch 'dev' into 'dev'
missing piece of poll code

See merge request hubzilla/core!1826
2020-02-05 14:28:27 +01:00
zotlabs
fc9e6d289a missing piece of poll code 2020-01-31 12:51:23 -08:00
Mario
6838342d62 fix php warningà 2020-01-31 10:29:20 +00:00
Mario
69b25e490e Merge branch 'dev' into 'dev'
polls and other backend z6 compat work

See merge request hubzilla/core!1825
2020-01-31 10:34:55 +01:00
zotlabs
b8d7647c48 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2020-01-30 15:58:36 -08:00
zotlabs
989443a569 basic poll support and patch to not call System::get_platform_name() within t() unless needed. Polls probably need refining and have not yet been fully tested after porting 2020-01-30 15:56:33 -08:00
Max Kostikov
c50a311ff3 Merge branch 'dev' into 'dev'
Prevent multiple database requests on name platform check

See merge request hubzilla/core!1824
2020-01-30 20:39:13 +01:00
Max Kostikov
b37e5a426a Update System.php 2020-01-30 20:36:00 +01:00
Max Kostikov
5e76318e44 Update System.php 2020-01-30 20:28:55 +01:00
Max Kostikov
8ed3971ef0 Prevent multiple database requests on name platform check 2020-01-30 20:18:25 +01:00
Mario
c2b6f0bc28 Merge branch 'dev' into 'dev'
z6 compat work

See merge request hubzilla/core!1822
2020-01-30 20:06:15 +01:00
Zot
2c42daf609 z6 compat work 2020-01-30 20:06:15 +01:00
Mario
8e2446a2fc provide img and zmg tags with image description 2020-01-30 17:24:08 +00:00
zotlabs
e9b2dacb61 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2020-01-29 14:33:43 -08:00
zotlabs
3df5d854b8 z6 transition work - prevent z6 sync packets from being unpacked into an incompatible schema 2020-01-29 14:29:06 -08:00
Mario
7d8c6cb9ed Merge branch 'dev' into 'dev'
bugfix: event_addtocal not preserving original privacy expectation

See merge request hubzilla/core!1820
2020-01-26 13:54:00 +01:00
zotlabs
f123809d29 more work on zap export 2020-01-25 16:24:14 -08:00
Mario
7abcdd34af minor private forum notifications fixes 2020-01-25 14:32:35 +00:00
zotlabs
ead56c59e2 bugfix: event_addtocal not preserving original privacy expectation 2020-01-24 19:38:52 -08:00
zotlabs
19a8dfaa5c Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2020-01-24 19:38:21 -08:00
Mario
fa45ea1d84 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2020-01-23 14:25:01 +00:00
Mario
8789edb65d make sure we import the zot6 xchan if we do not have it yet 2020-01-23 14:24:46 +00:00
Max Kostikov
b6abc034cf Merge branch 'dev' into 'dev'
Update Russian translation

See merge request hubzilla/core!1819
2020-01-22 21:11:27 +01:00
Max Kostikov
c92ea70453 Update hstrings.php 2020-01-22 21:02:46 +01:00
Max Kostikov
07eee20525 Update hmessages.po 2020-01-22 21:02:33 +01:00
Mario
6c9130be46 Merge branch 'dev' into 'dev'
Don't validate domain with PTR record; remove uneccessary CNAME check; add IPv6 check

See merge request hubzilla/core!1818
2020-01-22 20:26:10 +01:00
Mario
51f00cda92 fix typo 2020-01-21 08:55:11 +00:00
Mario
7973567a7c more shortlocalize and bdi tags 2020-01-20 09:30:24 +00:00
Max Kostikov
b81b18814e Don't validate domain with PTR record; remove uneccessary CNAME check; add IPv6 check 2020-01-19 21:55:15 +01:00
Mario
bbfe71b0c6 the address or URL as linktitle should be sufficient 2020-01-18 20:46:52 +00:00
Mario
7404183830 missing update file 2020-01-18 20:13:09 +00:00
Mario
43aea3ce38 we need 24h format 2020-01-18 20:05:05 +00:00
Mario
cbaf4b7536 introduce db_str_to_date() 2020-01-18 20:00:37 +00:00
Mario
570d84c031 fix shortlocalize 2020-01-18 16:04:40 +00:00
Mario
9eeccc087d move mail frontend to addons and remove mail app from system apps 2020-01-18 14:23:23 +00:00
Mario
7404a8ec1a implement bdi tags via bbcode where possible 2020-01-18 14:19:31 +00:00
Mario
bfae86bdb6 more bdi tags 2020-01-18 13:17:37 +00:00
Mario
66f6a1d186 wrap profile names in bdi tags to prevent mastodon-kiddies to mess with the layout 2020-01-18 10:54:53 +00:00
Mario
17a4aa983e $owner in get_feed_for() is the atom rendered channel, for atom_entry we need the owners channel_id though. 2020-01-17 21:31:37 +00:00
Mario
2a0a06d74a some work on zot6 DMs 2020-01-15 21:43:47 +00:00
Mario
ccaa93655a fix typo 2020-01-15 09:48:10 +00:00
Mario
65bc363685 Merge branch 'dev' into 'dev'
event compatibility work

See merge request hubzilla/core!1817
2020-01-15 10:30:02 +01:00
zotlabs
293d411efb Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2020-01-14 13:34:56 -08:00
zotlabs
2a287e6def event compatibility work 2020-01-14 13:29:45 -08:00
Mario
d96f4340e8 Merge branch 'dev' into 'dev'
Fix wrong URL detection with Markdown support enabled

See merge request hubzilla/core!1816
2020-01-14 10:38:06 +01:00
zotlabs
d3cbbe029c rework activitystreams events - send invite/event activities instead of create/event. Also a first pass at creating a Zap export file from Hubzilla. Much more work is needed before this is functional. 2020-01-12 22:41:28 -08:00
Max Kostikov
a1ccacb825 Fix wrong URL detection with Markdown support enabled 2020-01-12 18:24:59 +01:00
Mario
b04915161b composer update symfony/polyfill-ctype 2020-01-12 09:51:21 +00:00
Mario
8cb968c4b0 composer update sabre/dav 2020-01-12 09:18:07 +00:00
Mario
f645c6f3a5 update cropperjs to the recent version 2020-01-11 10:30:12 +00:00
Mario
4c1c690816 fix markdown test 2020-01-09 14:33:00 +00:00
Mario
537a7cf03d composer updates 2020-01-09 13:34:37 +00:00
Mario
662e8f8a4c Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2020-01-09 08:38:48 +00:00
Mario
7397348b9c Merge branch 'dev' into 'dev'
Add age choice on cached item retrieve

See merge request hubzilla/core!1813
2020-01-09 09:30:36 +01:00
Mario
5c43013692 deal with situations where we do not have an xchan_addr but only an xchan_url 2020-01-09 08:20:01 +00:00
Max Kostikov
908875a052 Update Cache.php 2020-01-06 20:40:18 +01:00
Max Kostikov
41ce2da080 Add age choice on cached item retrieve 2020-01-05 11:49:36 +01:00
Max Kostikov
6add6ce79b Merge branch 'dev' into 'dev'
Fixed es-es/hmessages.po

See merge request hubzilla/core!1812
2019-12-28 22:23:57 +01:00
mjfriaza
0fe9c029ab Fixed es-es/hmessages.po 2019-12-28 19:04:58 +01:00
Max Kostikov
a6522b34c7 Merge branch 'dev' into 'dev'
Update Spanish

See merge request hubzilla/core!1811
2019-12-28 18:47:08 +01:00
mjfriaza
229f99fe6b Update Spanish 2019-12-28 18:17:42 +01:00
Mario
bdc269d445 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-12-28 14:38:06 +00:00
Mario
ff63132a32 pubstream: use search mode for tag filter view and add a title 2019-12-28 14:37:52 +00:00
Max Kostikov
e7fb22edc1 Merge branch 'dev' into 'dev'
Update Russian translation

See merge request hubzilla/core!1810
2019-12-27 19:38:17 +01:00
Max Kostikov
3c59303b68 Update hstrings.php 2019-12-27 19:25:36 +01:00
Max Kostikov
fb4504c5a3 Update hmessages.po 2019-12-27 19:25:05 +01:00
Mario
db22578c16 re-add german translations for x minutes etc. which were removed in rkor's merge request 2019-12-21 09:49:24 +00:00
Mario
300727b8cf german translation fixes 2019-12-21 09:40:57 +00:00
Mario
448fb14fc4 Merge branch 'dev' into 'dev'
Some translations to German (#1418)

See merge request hubzilla/core!1809
2019-12-21 10:35:32 +01:00
Mario
c42e8613e5 sse: fix new posts only filter broken after aditional results loaded 2019-12-20 09:53:05 +00:00
Robert Kormann
12de30a2b1 German translations related to settings and apps, German context help 2019-12-18 18:27:00 +01:00
Mario
3d019fa2dd Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-12-17 09:33:08 +00:00
Max Kostikov
d5aeb13601 Merge branch 'dev' into 'dev'
Fix possibly unknown author

See merge request hubzilla/core!1808
2019-12-16 21:51:40 +01:00
Mario
230f7ab6d4 sse: remove redundant code 2019-12-16 13:50:43 +00:00
Max Kostikov
d71dd21abc Fix possibly unknown author 2019-12-16 10:23:33 +01:00
Robert Kormann
0d00b72569 Merge branch 'dev' into RKor.Info 2019-12-15 18:11:47 +01:00
Mario
00f6deb9bd remove redundant css 2019-12-15 09:14:51 +00:00
Robert Kormann
cce5054aec German translations of settings and apps elements 2019-12-14 16:46:26 +01:00
Mario
544ef3bc58 update composer libs and minor notifications display fixes 2019-12-12 14:51:10 +00:00
Mario
124cc43962 when ajax loading new posts, always scroll to top first 2019-12-12 09:09:31 +00:00
Max Kostikov
4237dd457e Merge branch 'dev' into 'dev'
missing translation "%d unseen"

See merge request hubzilla/core!1806
2019-12-10 12:34:45 +01:00
zotlabs
88ebbd90d8 missing translation "%d unseen" 2019-12-09 19:43:01 -08:00
Max Kostikov
298acb9645 Merge branch 'dev' into 'dev'
directory: port censoring from zap and disable oembed in profile about

See merge request hubzilla/core!1805
2019-12-09 18:47:55 +01:00
Mario
c4f4edd743 directory: port censoring from zap and disable oembed in profile about 2019-12-09 10:44:44 +00:00
Max Kostikov
258a4e5627 Merge branch 'dev' into 'dev'
Don't show pinned post on single post displaying

See merge request hubzilla/core!1804
2019-12-08 00:22:46 +01:00
Max Kostikov
e1400e5745 Don't show pinned post on single post displaying 2019-12-08 00:18:51 +01:00
Mario
593688d539 Merge branch 'dev' into 'dev'
Add .webp image format support

See merge request hubzilla/core!1802
2019-12-07 20:14:18 +01:00
Max Kostikov
aed6823051 Add .webp image format support 2019-12-07 20:14:17 +01:00
Mario
96f9e51546 sse: encode string instead of replacing quotes in the template, use decodeURIComponent() instead of unescape() which is marked deprecated. 2019-12-07 19:09:19 +00:00
Mario
161ea6d51f sse: initial commit to deal with forum notifications 2019-12-07 13:05:07 +00:00
Max Kostikov
88e755037b Merge branch 'dev' into 'dev'
Unpin pinned item on site admin deletion

See merge request hubzilla/core!1801
2019-12-05 12:43:00 +01:00
Max Kostikov
cde706748a Unpin pinned item on site admin deletion 2019-12-05 12:37:54 +01:00
Max Kostikov
3e833a5bcd Merge branch 'dev' into 'dev'
Add missed break

See merge request hubzilla/core!1800
2019-12-04 21:00:20 +01:00
Max Kostikov
475a39ff90 Add missed break 2019-12-04 20:57:35 +01:00
Max Kostikov
2dd2b755f1 Merge branch 'dev' into 'dev'
Show unpin button in pinned post for owner only

See merge request hubzilla/core!1799
2019-12-04 15:42:48 +01:00
Max Kostikov
a6516341c5 Show unpin button for pinned post for owner only 2019-12-04 15:35:46 +01:00
Max Kostikov
9a70c3c275 Show unpin button for pinned post for owner only 2019-12-04 15:33:53 +01:00
Max Kostikov
5998445841 Merge branch 'dev' into 'dev'
Remove pinned item on every change

See merge request hubzilla/core!1798
2019-12-04 12:01:24 +01:00
Max Kostikov
d9c39d0c41 Remove pinned item on every change 2019-12-04 11:58:42 +01:00
Max Kostikov
4038b78377 Merge branch 'dev' into 'dev'
More pinned items frontend processing fixes

See merge request hubzilla/core!1797
2019-12-04 11:53:37 +01:00
Max Kostikov
dce8516da4 More pinned items frontend processing fixes 2019-12-04 11:50:56 +01:00
Max Kostikov
d439dee736 Merge branch 'dev' into 'dev'
Fix switching pinned items

See merge request hubzilla/core!1796
2019-12-04 11:16:36 +01:00
Mario
295c08fcf3 update changelog 2019-12-04 10:14:28 +00:00
Max Kostikov
efa11cbc74 Update pinned item markup 2019-12-04 11:13:33 +01:00
Max Kostikov
4a8e222763 Fix update pin / unpin button text on pinned item replace 2019-12-04 11:11:39 +01:00
Max Kostikov
75b9c7d6b8 Fix variables for unpin button 2019-12-04 10:21:03 +01:00
Max Kostikov
d1648fb258 Remove square 2019-12-04 10:12:29 +01:00
Max Kostikov
34cda095fe Remove square 2019-12-04 10:10:39 +01:00
Max Kostikov
dad7bc82c3 Merge branch 'dev' into 'dev'
Ad unpin button for pinned content and fix unpin on unpinned item drop

See merge request hubzilla/core!1795
2019-12-04 10:07:09 +01:00
Max Kostikov
0ee65ee954 Merge branch 'dev' into 'dev'
# Conflicts:
#   Zotlabs/Widget/Pinned.php
#   view/js/main.js
#   view/tpl/conv_item.tpl
#   view/tpl/pinned_item.tpl
2019-12-04 10:03:55 +01:00
Max Kostikov
ae0780fe3f Unpin only pinned items on item drop 2019-12-04 09:58:16 +01:00
Max Kostikov
d2a65ab1be Remove hint for pin button 2019-12-04 09:50:31 +01:00
Max Kostikov
f4516826ef Add unpin button for pinned item 2019-12-04 09:49:32 +01:00
Max Kostikov
b894380f86 Add unpin button for pinned item 2019-12-04 09:49:05 +01:00
M. Dent
b48a9d3f75 Merge branch 'dev' into 'dev'
Add content pinning support

See merge request hubzilla/core!1794
2019-12-04 03:44:25 +01:00
Max Kostikov
21b398252a Add content pinning support 2019-12-04 03:44:24 +01:00
Max Kostikov
80e03268fd Fix show share menu option for pinned post 2019-12-03 23:35:19 +01:00
Max Kostikov
135b3cf1ef Fix hide pinned post button for unauthenticated viewer 2019-12-03 17:17:06 +01:00
Max Kostikov
b9e083da61 Add layout for hiding pinned content and its processing 2019-12-03 16:58:46 +01:00
Max Kostikov
74aa446190 Add hiding pinned content 2019-12-03 16:56:24 +01:00
Max Kostikov
0d7548a381 Add hiding pinned content 2019-12-03 16:55:32 +01:00
Max Kostikov
428b2cca21 Minor pinned content processing fixes 2019-12-03 16:44:27 +01:00
Max Kostikov
28a316f73f Normalize SQL query 2019-12-03 10:33:46 +01:00
Max Kostikov
0532d639c2 Optimize pinned item verbs based activity processing 2019-12-03 10:26:49 +01:00
Max Kostikov
c17717c5db Remove debug logging 2019-12-03 10:14:49 +01:00
Max Kostikov
8b00913579 Show poll results in pinned items 2019-12-03 00:24:04 +01:00
Max Kostikov
cf95c4878d Add poll results in pinned item layout 2019-12-03 00:23:02 +01:00
Max Kostikov
4958e3b42c Unpin item on drop 2019-12-02 17:07:12 +01:00
Max Kostikov
cc3edeb6f5 Fix unique HTML elements id 2019-12-02 15:09:15 +01:00
Max Kostikov
20c296ce53 Add scroll to pinned item before removal 2019-12-01 16:30:16 +01:00
Max Kostikov
5ccbcb44f7 Add pinned content on channel page 2019-12-01 15:52:57 +01:00
Max Kostikov
adcf28af7c Add Russian strings for pinned content 2019-12-01 15:41:28 +01:00
Max Kostikov
5b206cd4a7 Add Russian strings for pinned content 2019-12-01 15:41:10 +01:00
Max Kostikov
1eb70b66d8 Add missed semicolon 2019-12-01 15:37:06 +01:00
Max Kostikov
3c1ff1fc63 Add base64 mids array 2019-12-01 15:22:38 +01:00
Max Kostikov
d711f2ad4c Add b64mids to support current JS 2019-12-01 15:21:32 +01:00
Max Kostikov
ae8a1c992a Formatting 2019-12-01 14:28:26 +01:00
Max Kostikov
580d3db5a8 Add pinned content widget 2019-12-01 14:26:18 +01:00
Max Kostikov
042cc96968 Add pinning processing module 2019-12-01 14:21:08 +01:00
Max Kostikov
d177043c9f Add pinned item layout 2019-12-01 14:17:32 +01:00
Max Kostikov
4c1e2c2dd8 Fix missprint 2019-12-01 14:12:52 +01:00
Max Kostikov
7dcb0cc11b Add pinning processing 2019-12-01 14:10:47 +01:00
Max Kostikov
837d9a4df0 Add pinnig controls to item layout 2019-12-01 14:08:19 +01:00
Max Kostikov
ec1d5ead93 Add description for system.pin_types variable 2019-12-01 14:06:14 +01:00
Max Kostikov
f485ed174d Add pinned items controls 2019-12-01 14:00:10 +01:00
Max Kostikov
e8560d56f5 Add pinned items strings 2019-12-01 13:56:52 +01:00
Max Kostikov
3a937fb969 Add pinned items JS strings 2019-12-01 13:55:51 +01:00
Mario
c1aa96ebf7 sse: template fixes, fix missing forum notifications and minor impovements 2019-11-29 19:46:13 +00:00
Mario
17e012afc6 remove logging 2019-11-29 15:31:46 +00:00
Mario
1c6796f907 sse: possible fix for race condition and fix notification count if we loaded unseen items but their notifications were not yet loaded 2019-11-29 15:30:58 +00:00
Mario
f2c73c0f45 Merge branch 'fix-listmode-spinner' into 'dev'
Move auto_save_draft to header from thread comment

See merge request hubzilla/core!1793
2019-11-28 09:30:57 +01:00
Mario
78492d0037 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-11-28 08:23:13 +00:00
Mario
2b08519f5a sse: improve caching fix an issue with removing notifications and move chatpresence expiration to cron 2019-11-28 08:22:53 +00:00
DM42.Net Hubzilla Development
c86b35da70 Move auto_save_draft to header from thread comment 2019-11-28 00:27:12 -05:00
Max Kostikov
b2003e2c3c Merge branch 'dev' into 'dev'
Update Russian translation

See merge request hubzilla/core!1791
2019-11-25 22:32:53 +01:00
Max Kostikov
8a08cceccb Update CHANGELOG 2019-11-25 22:32:39 +01:00
Max Kostikov
9284b60a79 Update CHANGELOG 2019-11-25 22:25:44 +01:00
Max Kostikov
b69f8a3f29 Update Russian hstrings.php 2019-11-25 22:22:37 +01:00
Max Kostikov
8ea7c08f43 Update Russian hmessages.po 2019-11-25 22:22:17 +01:00
Max Kostikov
78197aa625 Merge branch 'dev' into 'dev'
Dev sync

See merge request kostikov/core!6
2019-11-25 22:20:49 +01:00
Mario
fcb065bcb2 update changelog 2019-11-25 21:06:12 +00:00
Mario
3940fa5659 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-11-25 21:00:24 +00:00
Mario
697fbf33c5 Merge branch 'dev' into 'dev'
Fix once cached embedded content is used and stored forever

See merge request hubzilla/core!1790
2019-11-25 21:50:03 +01:00
Max Kostikov
901785663e Fix once cached embedded content is used and stored forever 2019-11-25 21:50:02 +01:00
Max Kostikov
9e4ff8ce25 Update system.object_cache_days default value 2019-11-25 17:52:21 +01:00
Max Kostikov
5f1b2b4bf7 Use cached embedded content use up to 30 days by default 2019-11-25 17:51:28 +01:00
Max Kostikov
271d280c91 Fix orthography 2019-11-25 14:37:45 +01:00
Max Kostikov
8f708fef9c Add daily expired cached embedded content cleanup 2019-11-25 14:35:03 +01:00
Max Kostikov
38de059156 Revert "Add daily cached embedded content cleanup"
This reverts commit 5c47c9ed95
2019-11-25 14:32:58 +01:00
Max Kostikov
f0b40ac15e Add system.object_cache_days variable description 2019-11-25 14:27:36 +01:00
Max Kostikov
5c47c9ed95 Add daily cached embedded content cleanup 2019-11-25 14:16:07 +01:00
Max Kostikov
dafac11aaa Remove move unused cache cleanup to cron 2019-11-25 14:08:29 +01:00
Max Kostikov
1fc81457a1 Use cached embeds for a week by default 2019-11-25 14:07:39 +01:00
Mario
0d47bb6878 remove sysmsg and sysmsg_info from session - those are now stored in xconfig (sse) 2019-11-25 12:59:16 +00:00
Mario
f6f7e7e8d2 changelog 2019-11-25 11:32:22 +00:00
Mario
483d450af4 sse: use fadeOut() to be consistent 2019-11-23 20:47:34 +00:00
Mario
decc14c324 sse: more cleanup 2019-11-23 20:41:20 +00:00
Mario
1134be8d30 sse: improve handling of notification status and major cleanup 2019-11-23 20:20:13 +00:00
Mario
fb65c54123 sse: minor improvements 2019-11-23 13:33:46 +00:00
Mario
fe803135d8 sse: fix another regression 2019-11-22 21:01:54 +00:00
Mario
908ebed9fd sse: remove some logging 2019-11-22 20:55:52 +00:00
Mario
bdb6b0d237 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-11-22 20:52:55 +00:00
Mario
73a0866ac4 sse: fix a regression where not all appearances of an notification were looped through and fix format_notify() to not look for the parent item anymore 2019-11-22 20:52:22 +00:00
Max Kostikov
e6b1b20565 Add space after comma in connection accepted interactions list 2019-11-22 19:28:37 +01:00
Max Kostikov
e40ea62c7c Add space after comma in connection accepted interactions list 2019-11-22 19:24:40 +01:00
Max Kostikov
7864579b1e Add space after comma in connection accepted interactions list 2019-11-22 19:20:02 +01:00
Mario
b62eb665c5 sse: store the item mid plus reactions mids in data-mids and change functions accordingly 2019-11-22 14:11:26 +00:00
Mario
c72716eca7 missing closing tags 2019-11-22 14:08:53 +00:00
Mario
530d816df6 Merge branch 'better-conn-status' into 'dev'
More descriptive connection status icons

See merge request hubzilla/core!1789
2019-11-22 14:59:46 +01:00
M. Dent
23c47f78ea More descriptive connection status icons 2019-11-22 14:59:45 +01:00
Mario
4a4c43bb2c Merge branch 'cherry-pick-cc1cca5e' into 'dev'
Cherry pick cc1cca5e

See merge request hubzilla/core!1788
2019-11-21 14:47:20 +01:00
Manuel Jiménez Friaza
0159b631fc no mention notifications from mastodon (and pleroma)
(cherry picked from commit ea235c0c67)
2019-11-21 14:47:20 +01:00
Mario
e74361c4db sse: introduce sse_updateNotifications() to be able to update the notifications from different places 2019-11-20 18:38:25 +00:00
Mario
21299c6fc1 sse: defins sse_mids as array and comment out logging of dismissed notifications 2019-11-19 09:39:09 +00:00
Mario
eec42d3bb3 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-11-19 09:33:13 +00:00
Mario
bd049eddd4 sse: fix notifications visible for loaded items when the items were loaded before the notifications 2019-11-19 09:33:00 +00:00
Max Kostikov
e762347080 Merge branch 'dev' into 'dev'
Remove duplicate Opengraph creation

See merge request hubzilla/core!1786
2019-11-18 20:36:46 +01:00
Max Kostikov
53ad04cdc4 Remove duplicate Opengraph creation 2019-11-18 20:33:55 +01:00
Max Kostikov
148c3f9dc5 Merge branch 'dev' into 'dev'
Better Opengraph markup for posts

See merge request hubzilla/core!1785
2019-11-18 15:58:35 +01:00
Max Kostikov
6f1188f44f Update Articles.php 2019-11-18 15:52:59 +01:00
Max Kostikov
78868314a7 Use channelx array on Opengraph markup procedure 2019-11-18 15:47:03 +01:00
Max Kostikov
dc2f293089 Update opengraph.php 2019-11-18 15:42:14 +01:00
Max Kostikov
c7a0526428 Move back Opengraph markup creation to init stage 2019-11-18 15:40:51 +01:00
Max Kostikov
498c021aec Merge branch 'dev' into 'dev'
Dev sync

See merge request kostikov/core!5
2019-11-18 13:00:43 +01:00
Max Kostikov
5ee133843f Remove base64 decode check on Opengraph tags create 2019-11-18 12:55:09 +01:00
Max Kostikov
9ad2902add Remove unnecessary brackets 2019-11-18 12:55:02 +01:00
Mario
ef75d27afb cleanup local and session storage on channel change or logout 2019-11-15 21:12:40 +00:00
Mario
965c51c2d4 sse: implement notifications for anonymous visitors (info, notice and pubs) and fix a potential memory leak 2019-11-15 20:29:58 +00:00
Mario
5a6b14f878 onepoll: do not update dead feeds 2019-11-15 10:01:21 +00:00
Mario
de9a7f0fa9 make inline pdf a security option, move thumbnail security to security options from admin/site 2019-11-15 09:55:44 +00:00
Mario
3009c88d24 AP fixes 2019-11-15 09:43:39 +00:00
Mario
f3fa2d853a sse: make sure we have an observer 2019-11-13 14:30:54 +00:00
Mario
a982aecd5b sse: revert to reset to array 2019-11-13 13:51:00 +00:00
Mario
52bd27a028 check if file exists 2019-11-13 13:40:40 +00:00
Mario
e5e16da8cb sse: reset to empty string instead of empty array 2019-11-13 13:26:28 +00:00
Mario
b0adb70ffc Merge branch 'dev' into 'dev'
wildcard tag issue

See merge request hubzilla/core!1784
2019-11-13 08:56:27 +01:00
zotlabs
2f4c619d51 wildcard tag issue 2019-11-12 20:25:25 -08:00
Mario
6e36820b1b sse: do not delete xconfig - reset it 2019-11-12 21:15:01 +00:00
Mario
209d06a8f7 better detection for who to send sys notifications (needs addons update) 2019-11-12 10:11:58 +00:00
Max Kostikov
4a6d050e22 Merge branch 'sse_merge_core' into 'dev'
sse notifications

See merge request hubzilla/core!1783
2019-11-11 21:30:38 +01:00
Mario
b033597ada sse notifications 2019-11-11 21:30:38 +01:00
Mario
89342ca9fb use minified version of jquery 2019-11-11 10:17:03 +00:00
Mario
892f4b4182 bump version 2019-11-11 08:20:30 +00:00
Mario
de7891771d update strings 2019-11-11 08:14:42 +00:00
Mario
602768209b bump version 2019-11-11 08:06:44 +00:00
Mario
73b1f8fcdd Merge branch 'cherry-pick-1affcb80' into 'dev'
fix language tests

See merge request hubzilla/core!1782
2019-11-10 14:21:13 +01:00
Mario
e1b923ab7d Merge branch 'cherry-pick-6685381f' into 'dev'
another bulk of composer updates

See merge request hubzilla/core!1781
2019-11-10 14:18:18 +01:00
Mario
bed9876d68 Merge branch 'cherry-pick-9ad4c652' into 'dev'
hopefully fix query for postgres

See merge request hubzilla/core!1780
2019-11-10 14:17:58 +01:00
Mario
d184e2708f fix language tests
(cherry picked from commit 1affcb80172576dc46e4434cd10e1a534a9bb6c2)
2019-11-10 14:10:51 +01:00
Mario
580c3f4ffe another bulk of composer updates
(cherry picked from commit 6685381fd8db507493c3d7c1793f8c05c681bbce)
2019-11-10 14:10:03 +01:00
Mario
158b8aea38 hopefully fix query for postgres
(cherry picked from commit 9ad4c6528cc3ee4e34d2b5d77027a1c33cbadf5c)
2019-11-10 12:02:12 +01:00
Max Kostikov
d22766f458 Merge branch 'cherry-pick-971e7eef' into 'dev'
remove some old unused javascript libraries

See merge request hubzilla/core!1779
2019-11-10 11:55:05 +01:00
Max Kostikov
70391243dc Merge branch 'cherry-pick-b444bf59' into 'dev'
update jquery to version 3.4.1

See merge request hubzilla/core!1778
2019-11-10 11:54:43 +01:00
Mario
61eef68ff3 Ãremove some old unused javascript libraries
(cherry picked from commit 971e7eef9c415a2ce82eb0cd22eaabee12ae719c)
2019-11-10 09:59:22 +01:00
Mario
41cc2854c5 update jquery to version 3.4.1
(cherry picked from commit b444bf59560b3d918aa13b52035c602b03e8d013)
2019-11-10 09:58:18 +01:00
Max Kostikov
ec68ede79f Merge branch 'dev' into 'dev'
Dev sync

See merge request kostikov/core!4
2019-11-08 23:39:04 +01:00
Max Kostikov
478014f02a Better BBcode to Markdown conversion 2019-11-08 23:35:05 +01:00
M. Dent
aff7c2d771 Merge branch 'dev' into 'dev'
exempt svg from tag completion

See merge request hubzilla/core!1777
2019-11-08 23:30:30 +01:00
zotlabs
00dd52317a Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-11-08 13:10:24 -08:00
zotlabs
17522b31e9 exempt svg from tag completion 2019-11-08 13:07:42 -08:00
Max Kostikov
163b1ee9f8 Merge branch 'cherry-pick-fa437b79' into 'dev'
more fix date header format

See merge request hubzilla/core!1776
2019-11-08 21:35:06 +01:00
Mario
7b9a992f83 more fix date header format
(cherry picked from commit fa437b7977ba7fffd7368fa5c75e3d57fbf75424)
2019-11-08 21:27:43 +01:00
Max Kostikov
4efb258671 Merge branch 'cherry-pick-bb11cd15' into 'dev'
fix date header format

See merge request hubzilla/core!1775
2019-11-08 21:26:54 +01:00
Mario
7532358806 fix date header format
(cherry picked from commit bb11cd15d147ebbcc90b544788c9c2ef4925daa5)
2019-11-08 21:13:58 +01:00
Max Kostikov
13c05e7937 Merge branch 'dev' into 'dev'
Do not trim a sufficiently shortened Opengraph description

See merge request hubzilla/core!1774
2019-11-08 18:13:52 +01:00
Max Kostikov
c6e9bca76c Merge branch 'cherry-pick-2df15f35' into 'dev'
update composer libs

See merge request hubzilla/core!1773
2019-11-08 18:13:27 +01:00
Max Kostikov
3706afbd01 Do not trim a sufficiently shortened Opengraph description 2019-11-08 16:19:08 +01:00
Mario
bcd0802ea4 update composr libs
(cherry picked from commit 2df15f35d706d4608ff723ce6288391ca774f7ba)
2019-11-08 10:47:28 +01:00
Mario
9360148829 Merge branch 'dev' into 'dev'
svg stuff

See merge request hubzilla/core!1772
2019-11-08 10:47:00 +01:00
Zot
a6165c00ce svg stuff 2019-11-08 10:47:00 +01:00
zotlabs
a5826fec25 svg stuff 2019-11-07 14:51:29 -08:00
zotlabs
839c6668cf Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-11-07 14:48:44 -08:00
Max Kostikov
e9a9fc5050 Merge branch 'dev' into 'dev'
Update Russian translation

See merge request hubzilla/core!1771
2019-11-07 14:24:19 +01:00
Max Kostikov
426668cd2e Update hstrings.php 2019-11-07 14:14:41 +01:00
Max Kostikov
926d7c56a6 Update hmessages.po 2019-11-07 14:13:29 +01:00
Mario
9934dbfe69 Merge branch 'dev' into 'dev'
Sanitize title on Atom/RSS feed import

See merge request hubzilla/core!1770
2019-11-07 09:14:51 +01:00
Max Kostikov
b6314c109d Sanitize title on Atom/RSS feed import 2019-11-07 09:14:51 +01:00
Max Kostikov
f8955f90b8 Move title sanitizer code in the right place 2019-11-06 16:14:57 +01:00
Max Kostikov
9248fc96b3 Formatting 2019-11-06 16:11:10 +01:00
Max Kostikov
2875ee2423 Update feedutils.php 2019-11-06 16:08:36 +01:00
Max Kostikov
36f707b25e Sanitize title on Atom/RSS feed import 2019-11-06 16:07:04 +01:00
M. Dent
2a05bd9ed6 Merge branch 'cherry-pick-7cc8c2d1' into 'dev'
port fixes from zap to check for arrays

See merge request hubzilla/core!1767
2019-11-06 04:13:57 +01:00
M. Dent
b7db9944ec Merge branch 'cherry-pick-3604220c' into 'dev'
add date and request target headers to make pixelfed happy

See merge request hubzilla/core!1768
2019-11-06 04:11:12 +01:00
M. Dent
86f7d08483 Merge branch 'dev' into 'dev'
Prefer use Etag on photo modification validation

See merge request hubzilla/core!1769
2019-11-06 04:10:16 +01:00
zotlabs
1358a81c32 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-11-04 14:26:12 -08:00
Max Kostikov
09ad48c12b Prefer use Etag on photo modification validation 2019-11-04 21:44:42 +01:00
M. Dent
aa137fb2d2 Merge branch 'cherry-pick-4cfb9658' into 'dev'
fix duplicate attachment and regression with audio file upload

See merge request hubzilla/core!1766
2019-11-04 20:01:14 +01:00
M. Dent
09284d512d Merge branch 'cherry-pick-03317b98' into 'dev'
fix query with protocol prefix not always picking the right xchan

See merge request hubzilla/core!1765
2019-11-04 19:58:01 +01:00
Mario
02fd7e51ff add date and request target headers to make pixelfed happy
(cherry picked from commit 3604220c2a5aedddf25143cc5fd87ed576d34702)
2019-11-04 13:04:28 +01:00
Mario
b359b89aa1 port fixes from zap to check for arrays
(cherry picked from commit 7cc8c2d127b09b7e53c7916c6ea104fa566971db)
2019-11-04 13:03:00 +01:00
Mario
873b20677e fix duplicate attachment and regression with audio file upload
(cherry picked from commit 4cfb965881df2be181aab6020c9df78c0a86fd9f)
2019-11-04 10:34:24 +01:00
Mario
a049664219 fix query with protocol prefix not always picking the right xchan
(cherry picked from commit 03317b9864c0d7c99e144404c647b9923d8d29ea)
2019-11-04 09:39:56 +01:00
Max Kostikov
64c6e25896 Merge branch 'cherry-pick-4a1c2208' into 'dev'
fix issue #1402

See merge request hubzilla/core!1764
2019-11-03 14:03:00 +01:00
Mario
9f9122ab8e fix issue #1402
(cherry picked from commit 4a1c2208866360b5fe54eea71ff8e62bd6d63045)
2019-11-03 11:15:12 +01:00
Mario
d0661cd4a3 Merge branch 'commentsclosed-hook' into 'dev'
Add hook to comments_are_now_closed()

See merge request hubzilla/core!1763
2019-11-03 10:12:12 +01:00
M. Dent
707b19dc35 Add hook to comments_are_now_closed() 2019-11-03 10:12:11 +01:00
Max Kostikov
6fd15d66a7 Merge branch 'dev' into 'dev'
Change llink type in default SQL schema

See merge request hubzilla/core!1761
2019-11-02 10:42:02 +01:00
Max Kostikov
8c9a814e18 Merge branch 'homeinstall_fix_addons' into 'dev'
homeinstall fix addons

See merge request hubzilla/core!1762
2019-11-02 10:37:59 +01:00
Max Kostikov
74ef5f38e9 Fix start time to sync queries on photo cache purge 2019-11-02 10:36:04 +01:00
root
624a3ee1a7 homeinstall fix addons 2019-11-01 23:01:42 +01:00
Max Kostikov
fc658a25d7 Update schema_mysql.sql 2019-11-01 19:37:46 +01:00
Max Kostikov
308619a726 Drop llink index 2019-11-01 17:47:16 +01:00
Max Kostikov
e87d8d9856 Change llink column type and drop index 2019-11-01 17:46:28 +01:00
Max Kostikov
7594264725 Merge branch 'dev' into 'dev'
Better photo cache expiry processing

See merge request hubzilla/core!1760
2019-11-01 10:49:19 +01:00
Max Kostikov
69533ce8f5 Add missed interval in SQL query 2019-11-01 10:46:49 +01:00
Max Kostikov
9fac43a3a3 Better photo cache expiry processing 2019-11-01 10:34:02 +01:00
Max Kostikov
b00db39739 Merge branch 'dev' into 'dev'
Better cached photos processing

See merge request hubzilla/core!1759
2019-10-26 12:30:41 +02:00
Max Kostikov
6f2a584279 Update Photo.php 2019-10-26 12:24:23 +02:00
Max Kostikov
de717268f7 Better cached photos processing 2019-10-26 12:22:09 +02:00
Mario
e27b19c756 fix hardcoded code/pre css in mod admin
(cherry picked from commit cddf6c4ff51580f3dec5d32eef06a40a473a9202)
2019-10-22 13:29:52 +02:00
Mario
045cb461f1 fix encoding issue
(cherry picked from commit 067010fc0a5a6c10825b869b822c9cfbb3d4516b)
2019-10-22 10:39:54 +02:00
Max Kostikov
088c0eedc6 Merge branch 'patch-1' into 'dev'
add japanese translation

See merge request hubzilla/core!1752
2019-10-19 23:28:58 +02:00
harukin
e5137b03fc Update view/ja/hstrings.php 2019-10-19 18:41:58 +02:00
harukin
76d34a4d74 Update view/ja/hmessages.po, view/ja/hstrings.php files 2019-10-17 17:57:23 +02:00
Max Kostikov
ae4f0e5728 Merge branch 'dev' into 'dev'
Fix channel address in follow link

See merge request hubzilla/core!1757
2019-10-15 22:39:18 +02:00
Max Kostikov
5df59027ad Fix channel address in follow link 2019-10-15 22:37:03 +02:00
Max Kostikov
c888e33f04 Merge branch 'dev' into 'dev'
Better Opengraph image type detection

See merge request hubzilla/core!1756
2019-10-15 14:11:21 +02:00
Max Kostikov
1a56ecaa39 Update opengraph.php 2019-10-15 14:04:24 +02:00
Max Kostikov
d778c3cf19 Better Opengraph image type detection 2019-10-15 14:03:41 +02:00
Max Kostikov
8bf57c6226 Merge branch 'dev' into 'dev'
Dev

See merge request hubzilla/core!1755
2019-10-15 14:00:21 +02:00
Max Kostikov
3c762b8809 Fix cache-control syntax for photos 2019-10-15 13:49:46 +02:00
Max Kostikov
3561fd7c43 Merge branch 'dev' into 'dev'
Sync dev

See merge request kostikov/core!3
2019-10-15 13:48:07 +02:00
Max Kostikov
66bfc0ec64 Merge branch 'patch-20191014' into 'dev'
Updates to zcard/profile images and other public images to account for infrastructure caches (CDN)

See merge request hubzilla/core!1754
2019-10-14 22:28:48 +02:00
M. Dent
7d0e576e3b Updates to zcard/profile images and other public images to account for infrastructure caches (CDN) 2019-10-14 22:28:48 +02:00
Max Kostikov
aa330bc8c7 Merge branch 'dev' into 'dev'
Better plural function detection

See merge request hubzilla/core!1753
2019-10-14 11:16:12 +02:00
Max Kostikov
b4de492e0d Merge branch 'dev' into 'dev'
Dev

See merge request kostikov/core!2
2019-10-14 11:11:48 +02:00
Max Kostikov
5bf3114e6f Better plural function detection 2019-10-14 11:09:53 +02:00
harukin
d2b1a2e5a3 Upload .php file 2019-10-14 03:39:43 +02:00
harukin
4b01f6359b Upload .po file 2019-10-14 03:39:05 +02:00
harukin
bcfa62f45a japanese translation directory 2019-10-14 03:34:24 +02:00
Mario
e7e8a2ca5f Merge branch 'dev' into 'dev'
Better Opengraph markup

See merge request hubzilla/core!1751
2019-10-13 14:27:54 +02:00
Max Kostikov
5edeb0250b Revert "Remove visible channels list from pubstream tags cloud creation procedure"
This reverts commit 5c4c6e68f6
2019-10-13 14:27:54 +02:00
Max Kostikov
0c2657df78 Add Opengraph image type detection 2019-10-12 23:42:35 +02:00
Max Kostikov
e4c57e8031 Update opengraph.php 2019-10-12 21:22:42 +02:00
Max Kostikov
6a25548097 Update Channel.php 2019-10-12 19:26:17 +02:00
Max Kostikov
db7cbdfc44 Add Opengraph markup for articles 2019-10-12 19:23:14 +02:00
Max Kostikov
2f26badb84 Move Opengraph functions to common libraries 2019-10-12 19:05:20 +02:00
Max Kostikov
f7e665c42f Add Opengraph function 2019-10-12 19:03:21 +02:00
Max Kostikov
3bc44ee451 Minor Opengraph improvements 2019-10-11 19:29:40 +02:00
Max Kostikov
125de855ef Add Opengraph og:type object 2019-10-11 09:55:06 +02:00
Max Kostikov
3881ebcce0 Better Opengraph markup for channel 2019-10-11 00:46:02 +02:00
M. Dent
bef5324fea Merge branch 'cherry-pick-cac0672a' into 'dev'
issue #1401

See merge request hubzilla/core!1750
2019-10-08 14:26:17 +02:00
Mario Vavti
c2655370e0 issue #1401
(cherry picked from commit cac0672a49cd710b3eced1d66f1bfb18747ddbf8)
2019-10-08 11:28:36 +02:00
Max Kostikov
d017e34795 Merge branch 'dev' into 'dev'
Dev sync

See merge request kostikov/core!1
2019-10-06 19:26:23 +02:00
Max Kostikov
aa44da35ba Revert "Remove visible channels list from pubstream tags cloud creation procedure"
This reverts commit 5c4c6e68f6
2019-10-06 19:24:28 +02:00
Max Kostikov
5c4c6e68f6 Remove visible channels list from pubstream tags cloud creation procedure 2019-10-06 12:02:45 +02:00
Max Kostikov
a435363b94 Merge branch 'cherry-pick-d8b8d8ce' into 'dev'
fix zap->hubzlla event title compatibility

See merge request hubzilla/core!1749
2019-10-06 11:18:35 +02:00
Mario Vavti
d6634eb14e fix zap->hubzlla event title compatibility
(cherry picked from commit d8b8d8ceb5cc9d701f91dac26834af15f3257cce)
2019-10-05 22:04:23 +02:00
Mario
afee2cf71a Merge branch 'dev' into 'dev'
Allow addons to process forum posts published through mentions

See merge request hubzilla/core!1745
2019-10-05 10:31:47 +02:00
Max Kostikov
79b0a6ba9c Allow addons to process forum posts published through mentions 2019-10-05 10:31:47 +02:00
Mario
0c2438b36a Merge branch 'cherry-pick-79bcc157' into 'dev'
fix bbcode event reshare timezone issue

See merge request hubzilla/core!1747
2019-10-05 10:31:26 +02:00
Mario
d6da46f94b Merge branch 'dev' into 'dev'
another timezone fix

See merge request hubzilla/core!1748
2019-10-05 10:31:11 +02:00
Zot
562e39c9c5 another timezone fix 2019-10-05 10:31:11 +02:00
zotlabs
2d08e0955a Merge branch 'dev' of https://framagit.org/zot/core into dev 2019-10-04 14:31:21 -07:00
zotlabs
baffa969d3 another timezone fix 2019-10-04 14:28:31 -07:00
Mario Vavti
1fbc8739b9 fix bbcode event reshare timezone issue
(cherry picked from commit 79bcc157bf8f0c67a8ee41ae9c53a9dec969f8d1)
2019-10-04 09:25:39 +02:00
zotlabs
b9dec84489 fix event timezones for zot6 2019-10-03 22:16:11 -07:00
Max Kostikov
6feb864c38 Allow processing of forum posts through mentions in addons 2019-10-03 18:28:29 +02:00
Max Kostikov
b6db1898b1 Get extended channel info using channelx_by_hash() 2019-10-03 18:27:25 +02:00
Max Kostikov
de902d179e Allow processing of forum posts through mentions in addons 2019-10-03 18:25:57 +02:00
Max Kostikov
58b77e3427 Merge branch 'cherry-pick-2c7ed093' into 'dev'
fix missing summary in mod article_edit

See merge request hubzilla/core!1744
2019-10-02 11:43:41 +02:00
Mario Vavti
cdcac86256 fix missing summary in mod article_edit
(cherry picked from commit 2c7ed093699ea0c0f68068fdd8a035454b9a76a3)
2019-10-02 11:05:24 +02:00
Mario
79b05e48e8 Merge branch 'dev' into 'dev'
Add 'Connect' button for not connected at this location channels

See merge request hubzilla/core!1743
2019-10-01 11:15:29 +02:00
Max Kostikov
541146e8ce Add 'Connect' button for not connected at this location channels 2019-10-01 11:15:29 +02:00
Max Kostikov
97b161c536 Merge branch 'dev' into 'dev'
Fix empty string quotation; remove trailing spaces

See merge request hubzilla/core!1742
2019-09-30 16:54:35 +02:00
Max Kostikov
ba3a6ecb52 Fix empty string quotation; remove trailing spaces 2019-09-30 16:50:24 +02:00
Mario
cf27b7440d Merge branch 'dev' into 'dev'
Sync private items with clones; avoid sync if no local connection with thread owner

See merge request hubzilla/core!1739
2019-09-30 16:19:39 +02:00
Max Kostikov
407b9c9cd7 Sync private items with clones; avoid sync if no local connection with thread owner 2019-09-30 16:19:39 +02:00
Mario
d0055310ba Merge branch 'dev' into 'dev'
issue with bearcap tests

See merge request hubzilla/core!1738
2019-09-28 10:36:38 +02:00
zotlabs
02f5fa32af Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-09-26 18:36:06 -07:00
zotlabs
b6590e95b5 issue with bearcap tests 2019-09-26 18:34:08 -07:00
M. Dent
ec65211d54 Merge branch 'admindoc' into 'dev'
Improve admin documentation

See merge request hubzilla/core!1737
2019-09-24 23:36:32 +02:00
Ale Abdo
8dfa08f146 Improve admin documentation 2019-09-24 15:37:47 +02:00
M. Dent
daef2d0546 Merge branch 'dev' into 'dev'
Update plink type for MySQL schema

See merge request hubzilla/core!1736
2019-09-23 19:21:27 +02:00
M. Dent
15eaa80301 Merge branch 'cherry-pick-9aa928ec' into 'dev'
composer update simplepie/simplepie

See merge request hubzilla/core!1735
2019-09-23 19:20:45 +02:00
M. Dent
1e924a8530 Merge branch 'cherry-pick-e4336578' into 'dev'
composer update vendor/league/html-to-markdown/.github/

See merge request hubzilla/core!1734
2019-09-23 19:18:53 +02:00
M. Dent
23995ccb07 Merge branch 'cherry-pick-38cb094e' into 'dev'
composer update ezyang/htmlpurifier

See merge request hubzilla/core!1733
2019-09-23 19:16:59 +02:00
M. Dent
a4f2603454 Merge branch 'cherry-pick-a34ce790' into 'dev'
composer update ezyang/htmlpurifier

See merge request hubzilla/core!1732
2019-09-23 19:16:38 +02:00
M. Dent
cc860b4a76 Merge branch 'cherry-pick-53b8ee78' into 'dev'
composer update blueimp/jquery-file-upload

See merge request hubzilla/core!1731
2019-09-23 19:08:47 +02:00
Max Kostikov
0be82602ce Update schema_mysql.sql 2019-09-23 14:23:47 +02:00
Max Kostikov
b42c42692e Update plink type for MySQL 2019-09-23 14:14:02 +02:00
Mario Vavti
7fcbff3ceb composer update simplepie/simplepie
(cherry picked from commit 9aa928ec8f378c6df2a0c8bbe892ff971c3bc672)
2019-09-23 12:22:35 +02:00
Mario Vavti
efec0af394 composer update vendor/league/html-to-markdown/.github/
(cherry picked from commit e4336578388b3e59ba8130123649ccdc9b8487d0)
2019-09-23 12:22:08 +02:00
Mario Vavti
aafecd9d1e composer update ezyang/htmlpurifier
(cherry picked from commit 38cb094ede8a389ef0b8bb331c1e6a3befd666a8)
2019-09-23 12:21:04 +02:00
Mario Vavti
e37c43ea06 composer update ezyang/htmlpurifier
(cherry picked from commit a34ce790129bdd729a5019895ea6cd4c59f08ba4)
2019-09-23 12:20:28 +02:00
Mario Vavti
3fac7b5bb7 composer update blueimp/jquery-file-upload
(cherry picked from commit 53b8ee7866eb1394980b08b90153a63563832391)
2019-09-23 12:19:33 +02:00
Mario
9b90114d03 Merge branch 'customitem-delivery' into 'dev'
Notify on custom items - rework hooks

See merge request hubzilla/core!1730
2019-09-23 10:11:27 +02:00
M. Dent
7c5cfe6697 Notify on custom items - rework hooks 2019-09-23 10:11:27 +02:00
Mario
d1fd69337f Merge branch 'encode-comment-policy' into 'dev'
Encode comment policy into AS(Z6) packets.

See merge request hubzilla/core!1729
2019-09-23 10:10:56 +02:00
DM42.Net Zap Dev
3fc218111a Add dependency 2019-09-21 23:03:42 -04:00
DM42.Net Zap Dev
c63fb0fc6b comment policy default for ordered items 2019-09-21 13:37:20 -04:00
DM42.Net Zap Dev
6fe4ac241d encode/decode comment_policy for Z6 2019-09-21 13:30:42 -04:00
Max Kostikov
c385b80807 Merge branch 'cherry-pick-394f263d' into 'dev'
fix issue #1331

See merge request hubzilla/core!1728
2019-09-19 12:41:47 +02:00
Mario Vavti
97f36fa46f fix issue #1331
(cherry picked from commit 394f263ddd648e25ff3967bfbe3b0e25dccf89a0)
2019-09-19 12:34:01 +02:00
Mario
856d4b39d1 Merge branch 'dev' into 'dev'
change event formatting slightly for Zot6 and ActivityStreams.

See merge request hubzilla/core!1727
2019-09-18 12:43:45 +02:00
Mario
01abd73a2a Merge branch 'fix_homeinstall_for_Debian_10' into 'dev'
Fix homeinstall for debian 10

See merge request hubzilla/core!1725
2019-09-18 12:42:56 +02:00
zotlabs
375c2a87c7 change event formatting slightly for Zot6 and ActivityStreams. 2019-09-16 23:27:41 -07:00
Max Kostikov
6ca507f8dd Merge branch 'dev' into 'dev'
Prevent image blurring

See merge request hubzilla/core!1726
2019-09-15 09:23:22 +02:00
Max Kostikov
86b4a53858 Prevent image blurring 2019-09-15 09:18:42 +02:00
OJ Random
8959ba9b82 hominstall - readme 2019-09-14 19:14:31 +02:00
OJ Random
a62a230d3d hominstall - fix url rewriting and minor changes. 2019-09-14 19:09:26 +02:00
Max Kostikov
cc45129e9f Merge branch 'dev' into 'dev'
Add selected text quote on comment reply

See merge request hubzilla/core!1724
2019-09-10 10:41:53 +02:00
Max Kostikov
bffc9d5aba Merge branch 'daemon-qwfix' into 'dev'
Return in the case of further processing

See merge request hubzilla/core!1711
2019-09-10 10:41:34 +02:00
Max Kostikov
f2b121cd58 Merge branch 'dev' into 'dev'
Zot -> Zot6 translation issue, liking a "new friend" activity

See merge request hubzilla/core!1723
2019-09-10 10:40:53 +02:00
Max Kostikov
fd30be7644 Add selected text quote on comment reply 2019-09-09 12:35:47 +02:00
zotlabs
d9052c7e3c Zot -> Zot6 translation issue, liking a "new friend" activity 2019-09-03 17:00:10 -07:00
Max Kostikov
dcfe10b691 Merge branch 'dev' into 'dev'
Add CalDAV / CardDAV autodiscovery

See merge request hubzilla/core!1719
2019-09-03 14:33:37 +02:00
Max Kostikov
914a096b42 Merge branch 'dev' into 'dev'
improved conversion of emoji reactions from zot to zot6

See merge request hubzilla/core!1720
2019-09-03 14:33:09 +02:00
Max Kostikov
5fa9dcbc7e Merge branch 'dev' into 'dev'
More nofollow tags to discourage backlink farmers

See merge request hubzilla/core!1722
2019-09-03 14:32:52 +02:00
Terrox
93ec01e0a1 More nofollow tags to discourage backlink farmers 2019-09-03 14:32:52 +02:00
zotlabs
bbc98db6b4 Clarify private mail deletion policy. Related to issue #1391. 2019-08-31 14:43:08 -07:00
zotlabs
1f8d29a221 improved conversion of emoji reactions from zot to zot6 2019-08-31 14:04:10 -07:00
Max Kostikov
d267dd2515 Update Well_known.php 2019-08-30 00:55:36 +02:00
Max Kostikov
51954c7f3d Add CalDAV / CardDAV autodiscovery 2019-08-30 00:51:46 +02:00
Max Kostikov
df842a8e8d Merge branch 'dev' into 'dev'
Better spoiler BBcode tag conversion to Markdown

See merge request hubzilla/core!1718
2019-08-24 00:00:58 +02:00
Max Kostikov
60919488f1 Better spoiler BBcode tag conversion to Markdown 2019-08-23 23:58:07 +02:00
Max Kostikov
4dbaaa63bb Merge branch 'dev' into 'dev'
issues with image import to zot6 - wrong mid. Also label source project of...

See merge request hubzilla/core!1717
2019-08-23 23:09:14 +02:00
zotlabs
8cc4003837 issues with image import to zot6 - wrong mid. Also label source project of zotfeed since it is not completely compatible across projects. 2019-08-22 19:39:11 -07:00
Max Kostikov
35790c584b Merge branch 'dev' into 'dev'
possible for DB to return hublocs with no sitekey

See merge request hubzilla/core!1713
2019-08-22 20:29:53 +02:00
Max Kostikov
09d7cf2cc1 Merge branch 'dev' into 'dev'
Fix attach permissions sync for clonned channel

See merge request hubzilla/core!1716
2019-08-22 20:25:57 +02:00
Max Kostikov
58d7c7f6ae Fix attach permissions sync for clonned channel 2019-08-22 20:20:54 +02:00
Max Kostikov
cab24836d8 Merge branch 'dev' into 'dev'
Fix spoiler displaying while convert BBcode to markdown

See merge request hubzilla/core!1715
2019-08-22 20:20:44 +02:00
Max Kostikov
cf9ef615c9 Fix spoiler displaying while convert BBcode to markdown 2019-08-22 20:17:22 +02:00
zotlabs
8c96032b2b Merge branch 'dev' of https://framagit.org/zot/core into dev 2019-08-21 18:51:25 -07:00
zotlabs
d256551907 possible for DB to return hublocs with no sitekey 2019-08-21 18:50:38 -07:00
DM42.Net Zap Dev
e800e2db2b Return in the case of further processing 2019-08-19 23:13:19 -04:00
Mario Vavti
e5539c0d01 update changelog 2019-08-16 20:19:49 +02:00
Mario
ea8621d6ec Merge branch 'dev' into 'dev'
zot6 compatibility: when posting from a non-primary clone the actor->id is...

See merge request hubzilla/core!1710
2019-08-16 19:32:08 +02:00
zotlabs
ac05a2ede7 support "bearcaps" in Activity library 2019-08-15 21:30:47 -07:00
zotlabs
808baf203d show correct profile photo when previewing and editing profiles 2019-08-15 19:18:46 -07:00
zotlabs
beeafc6bc5 fix bitrot in util/zotsh 2019-08-15 16:28:06 -07:00
zotlabs
6f8c977e73 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2019-08-15 13:49:02 -07:00
zotlabs
9a2fbdde20 zot6 compatibility: when posting from a non-primary clone the actor->id is that of the primary, resulting in an author/owner identity mismatch. Solution is to always post with the actor->id set to the sender if it is a local channel. 2019-08-14 17:55:56 -07:00
Max Kostikov
b325b2c003 Merge branch 'dev' into 'dev'
illegal offset warning (prevents encrypted signatures from being used for...

See merge request hubzilla/core!1709
2019-08-14 16:35:55 +02:00
zotlabs
feda23587c illegal offset warning (prevents encrypted signatures from being used for encrypted messages). Not fatal but can leak metadata. 2019-08-13 16:53:04 -07:00
2705 changed files with 228432 additions and 519750 deletions

View File

@@ -1,10 +1,65 @@
# Hubzilla at Home next to your Router
# How to use
This readme will show you how to install and run Hubzilla (or Zap) at home.
## Disclaimers
The installation is done by a script.
- This script does work with Debian 10 only.
- This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation).
What the script will do for you...
## Preconditions
Hardware
+ Internet connection and router at home
+ Mini-pc connected to your router (a Raspberry 3 will do for very small Hubs)
+ USB drive for backups
Software
+ Fresh installation of Debian 10 (Stretch)
+ Router with open ports 80 and 443 for your web server
## How to run the script
+ Register your own domain (for example at selfHOST) or a free subdomain (for example at freeDNS)
+ Log on to your fresh Debian
- apt-get install git
- mkdir -p /var/www
- cd /var/www
- git clone https://framagit.org/hubzilla/core.git html
- cd html/.homeinstall
- cp hubzilla-config.txt.template hubzilla-config.txt
- nano hubzilla-config.txt
- Read the comments carefully
- Enter your values: db pass, domain, values for dyn DNS
- Prepare your external disk for backups
- hubzilla-setup.sh as root
- ... wait, wait, wait until the script is finised
+ Open your domain with a browser and step throught the initial configuration of hubzilla.
## Optional - Set path to imagemagick
In Admin settings of hubzilla or via terminal
cd /var/www/html
util/config system.imagick_convert_path /usr/bin/convert
## Optional - Switch verification of email on/off
Do this just befor you register the user.
In Admin settings of hubzilla or via terminal
cd /var/www/html
Check the current setting
util/config system verify_email
Switch the verification on/off (1/0)
util/config system verify_email 0
## What the script will do for you...
+ install everything required by Hubzilla, basically a web server (Apache), PHP, a database (MySQL), certbot,...
+ create a database
@@ -38,69 +93,11 @@ The script can install both [Hubzilla](https://zotlabs.org/page/hubzilla/hubzill
- core: git clone https://framagit.org/zot/zap.git html (in this readme)
- addons: util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons (in hubzilla-setup.sh)
## Disclaimers
- This script does work with Debian 10 only.
- This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation).
# Step-by-Step Overwiew
# Step-by-Step - some Details
## Preconditions
Hardware
+ Internet connection and router at home
+ Mini-pc connected to your router (a Raspberry 3 will do for very small Hubs)
+ USB drive for backups
Software
+ Fresh installation of Debian 10 (Stretch)
+ Router with open ports 80 and 443 for your web server
## The basic steps (quick overview)
+ Register your own domain (for example at selfHOST) or a free subdomain (for example at freeDNS)
+ Log on to your fresh Debian
- apt-get install git
- mkdir -p /var/www
- cd /var/www
- git clone https://framagit.org/hubzilla/core.git html
- cd html/.homeinstall
- cp hubzilla-config.txt.template hubzilla-config.txt
- nano hubzilla-config.txt
- Read the comments carefully
- Enter your values: db pass, domain, values for dyn DNS
- Prepare your external disk for backups
- hubzilla-setup.sh as root
- ... wait, wait, wait until the script is finised
+ Open your domain with a browser and step throught the initial configuration of hubzilla.
## Troubleshooting
If the check of the mail address fails when you try to register the very first user in the browser. Do...
cd /var/www/html
util/config system.do_not_check_dns 1
## Optional - Set path to imagemagick
In Admin settings of hubzilla or via terminal
cd /var/www/html
util/config system.imagick_convert_path /usr/bin/convert
# Step-by-Step in Detail
## Preparations Software
## Install Debian 9
Provided you use a Raspberry Pi 3...
Download the OS Raspbian from https://www.raspberrypi.org/downloads/raspbian/
Follow the installation instruction there.
## Preparations
## Configure your Router
@@ -146,12 +143,5 @@ to boot the Rapsi to the client console.
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
On a Raspian Stretch (Debian 10) the validation of the mail address fails for the very first user.
This used to happen on some *bsd distros but there was some work to fix that a year ago (2017).
So if your system isn't registered in DNS or DNS isn't active do
cd /var/www/html
util/config system.do_not_check_dns 1

View File

@@ -28,14 +28,13 @@
# * php,
# * mariadb - the database for hubzilla,
# * adminer,
# * git to download and update hubzilla addon
# - download hubzilla core and addons
# * git to download and update addons
# - configure cron
# * "Master.php" for regular background prozesses of hubzilla
# * "apt-get update" and "apt-get dist-upgrade" and "apt-get autoremove" to keep linux up-to-date
# * run command to keep the IP up-to-date > DynDNS provided by selfHOST.de or freedns.afraid.org
# * backup hubzillas database and files (rsync)
# - letsencrypt
# - run letsencrypt to create, register and use a certifacte for https
#
#
# Discussion
@@ -56,7 +55,7 @@
# - creates a daily cron that runs the hubzilla-daily.sh
#
# hubzilla-daily.sh makes a (daily) backup of all relevant files
# - /var/lib/mysql/ > hubzilla database
# - /var/lib/mysql/ > database
# - /var/www/ > hubzilla/zap from github
# - /etc/letsencrypt/ > certificates
#
@@ -223,6 +222,11 @@ function install_curl {
nocheck_install "curl"
}
function install_wget {
print_info "installing wget..."
nocheck_install "wget"
}
function install_sendmail {
print_info "installing sendmail..."
nocheck_install "sendmail sendmail-bin"
@@ -269,7 +273,19 @@ function install_adminer {
else
print_info "file /etc/adminer/adminer.conf exists already"
fi
a2enmod rewrite
if [ ! -f /etc/apache2/apache2.conf ]
then
die "could not find file /etc/apache2/apache2.conf"
fi
sed -i \
"s/AllowOverride None/AllowOverride all/" \
/etc/apache2/apache2.conf
a2enconf adminer
systemctl restart mariadb
systemctl reload apache2
}
@@ -407,10 +423,9 @@ function install_letsencrypt {
then
die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
fi
# check if user gave mail address
if [ -z "$le_email" ]
then
die "Failed to install let's encrypt: 'le_domain' is empty in $configfile"
die "Failed to install let's encrypt: 'le_email' is empty in $configfile"
fi
nocheck_install "certbot python-certbot-apache"
print_info "run certbot ..."
@@ -431,12 +446,19 @@ function check_https {
}
function install_hubzilla {
print_info "installing hubzilla addons..."
print_info "installing addons..."
cd /var/www/html/
# if you install Hubzilla
# util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
# if you install ZAP
util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons
if git remote -v | grep -i "origin.*hubzilla.*core"
then
print_info "hubzilla"
util/add_addon_repo https://framagit.org/hubzilla/addons hzaddons
elif git remote -v | grep -i "origin.*zap.*core"
then
print_info "zap"
util/add_addon_repo https://framagit.org/zot/zap-addons.git zaddons
else
die "neither zap nor hubzilla repository > did not install addons or zap/hubzilla"
fi
mkdir -p "store/[data]/smarty3"
chmod -R 777 store
touch .htconfig.php
@@ -446,7 +468,7 @@ function install_hubzilla {
chown root:www-data /var/www/html/
chown root:www-data /var/www/html/.htaccess
chmod 0644 /var/www/html/.htaccess
print_info "installed hubzilla"
print_info "installed addons"
}
function install_rsync {
@@ -585,6 +607,7 @@ check_config
stop_hubzilla
update_upgrade
install_curl
install_wget
install_sendmail
install_apache
install_imagemagick
@@ -600,23 +623,34 @@ configure_cron_selfhost
if [ "$le_domain" != "localhost" ]
then
install_letsencrypt
check_https
install_letsencrypt
configure_apache_for_https
check_https
else
print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https"
print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https"
fi
install_hubzilla
if [ "$le_domain" != "localhost" ]
then
rewrite_to_https
install_rsnapshot
else
print_info "is localhost - skipped rewrite to https and installation of rsnapshot"
fi
configure_cron_daily
if [ "$le_domain" != "localhost" ]
then
install_rsync
install_cryptosetup
install_cryptosetup
write_uninstall_script
else
print_info "is localhost - skipped installation of cryptosetup"
print_info "is localhost - skipped installation of cryptosetup"
fi
#set +x # stop debugging from here

View File

@@ -1,3 +1,77 @@
Hubzilla 4.6 (2019-12-04)
- Improve opengraph support for channels
- Add opengraph support for articles
- Update abook_connected for RSS feeds only if handle_feed() returned success
- Do not embed PDF files by default but allow to enabled this feature in security options
- Check if file exists before we include it in the router
- Update jquery to version 3.4.1
- Update composer libraries
- Remove old and unused javascript libraries
- Improved BBcode to Markdown conversion
- Introduce inline SVG support via BBcode
- Sanitize title on Atom/RSS feed import
- Improved HTTP headers cache support for photos
- Add date headers to signed headers
- Add check if item['tag'] is an array
- Add hook comments_are_now_closed for addons to override date based comment closure
- Change mysql schema for item.llink and item.plink for new installs from char(191) to text
- Improved photo cache expiration
- Improved plural function processing on translation strings creation from .po file with util/po2php utlility
- Improved support for CDN/Infrastructure caching (especially profile images)
- New japanese translation
- Add connect button for non-zot networks not connected in current location
- Allow to send forum channels wall2wall or sent by mentions post to external sites via addons
- Allow addons to process forum posts published through mentions
- Improved internal routing for ActivityPub messages
- Improved admin documentation
- Add ITEM_TYPE_CUSTOM and hooks to permit addons to create and distribute custom item types
- Support "comment policy" in Zot6 communications
- Add selected text as quote on reply if comment button is used
- Add more nofollow tags to links to discourage backlink farmers
- Improved conversion of emoji reactions from zot to zot6
- Add CardDAV/CalDAV autodiscovery
- Label source project of zotfeed since it is not completely compatible across projects
- Update homeinstall script
Bugfixes
- Fix once cached embedded content is used and stored forever
- Fix wildcard tag issue
- Fix duplicate attachment in jot fileupload
- Fix regression with audio file upload
- Fix can not edit menu name or title (#1402)
- Fix pagination encoding issue for some server setups
- Fix Zap->Hubzilla event title compatibility
- Fix event timezones for Zot6
- Fix missing summary in mod article_edit
- Fix PHP warning failed to write session data using user defined save handler
- Fix possible thumbnails distortion on rebuild with util/thumbrepair utility
- Fix issues with image import to zot6
- Fix attachment permissions on clonned channels sync
- Fix entries without sitekey returned from DB in queue_deliver() and Lib/Queue
Addons
- Twitter: send tweet even if attached image uploading was unsuccessful
- Livejournal: add link to original post option
- Flashcards: update to version 2.08
- Pubcrawl: compatibility changes to support pixelfed
- Cart: update paypal button to API v2
- Photocache: rework for speed and lower memory consumption
- Photocache: etag support for cached photos
- Photocache: purge cache on addon uninstall
- Openstreetmap: fix regression if no default values set
- Livejournal: allow send posts from non channel owner
- Pubcrawl: fix event timezones
- Pubcrawl: better ActivityPub channel URL detection
- Pubcrawl: fix comments delivery for other channels on the same hub
- New addon "workflow" with initial basic "issue tracker" capability
Hubzilla 4.4.1 (2019-08-16)
- Fix wrong profile photo displayed when previewing and editing profiles
- Fix regression from 4.4 which prevented encrypted signatures from being used for encrypted messages
- Fix typo in queueworker addon which broke filtering of duplicate work
Hubzilla 4.4 (2019-08-13)
- Change primary directory from zotadel.net to hub.netzgemeinde.eu (requested by zotadel admin)
- Add Russian context help files

View File

@@ -40,6 +40,15 @@ class Cron {
require_once('include/sharedwithme.php');
apply_updates();
/**
* Chatpresence: if somebody hasn't pinged recently, they've most likely left the page
* and shouldn't count as online anymore. We allow an expection for bots.
*/
q("delete from chatpresence where cp_last < %s - INTERVAL %s and cp_client != 'auto' ",
db_utcnow(),
db_quoteinterval('3 MINUTE')
);
// expire any expired mail
@@ -97,13 +106,17 @@ class Cron {
// Clean expired photos from cache
$age = get_config('system','active_expire_days', '30');
$r = q("SELECT DISTINCT xchan, content FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
intval(PHOTO_CACHE),
db_utcnow(),
db_quoteinterval($age . ' DAY')
db_utcnow(),
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
);
if($r) {
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
intval(PHOTO_CACHE),
db_utcnow(),
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
);
foreach($r as $rr) {
$file = dbunescbin($rr['content']);
if(is_file($file)) {
@@ -113,11 +126,6 @@ class Cron {
}
}
}
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
intval(PHOTO_CACHE),
db_utcnow(),
db_quoteinterval($age . ' DAY')
);
// publish any applicable items that were set to be published in the future
// (time travel posts). Restrict to items that have come of age in the last
@@ -215,7 +223,7 @@ class Cron {
$restart = true;
$generation = intval($argv[2]);
if(! $generation)
killme();
return;
}
reload_plugins();

View File

@@ -44,6 +44,17 @@ class Cron_daily {
db_utcnow(), db_quoteinterval('1 YEAR')
);
// expire anonymous sse notification entries once a day
q("delete from xconfig where xchan like '%s'",
dbesc('sse_id.%')
);
// Clean up emdedded content cache
q("DELETE FROM cache WHERE updated < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval(get_config('system','active_expire_days', '30') . ' DAY')
);
//update statistics in config
require_once('include/statistics_fns.php');

View File

@@ -13,7 +13,7 @@ class CurlAuth {
static public function run($argc,$argv) {
if($argc != 2)
killme();
return;
\App::$session->start();
@@ -50,6 +50,6 @@ class CurlAuth {
file_put_contents($c,$x);
killme();
return;
}
}
}

View File

@@ -9,7 +9,7 @@ if(array_search( __file__ , get_included_files()) === 0) {
if($argc)
Master::Release($argc,$argv);
killme();
return;
}

View File

@@ -3,6 +3,7 @@
namespace Zotlabs\Daemon;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Activity;
require_once('include/queue_fn.php');
require_once('include/html2plain.php');
@@ -285,8 +286,21 @@ class Notifier {
}
if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST ] )) {
logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
return;
$hookinfo=[
'targetitem'=>$target_item,
'deliver'=>false
];
if (intval($target_item['item_type'] == ITEM_TYPE_CUSTOM)) {
call_hooks('customitem_deliver',$hookinfo);
}
if (!$hookinfo['deliver']) {
logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
return;
}
$target_item = $hookinfo['targetitem'];
}
// Check for non published items, but allow an exclusion for transmitting hidden file activities
@@ -353,9 +367,18 @@ class Notifier {
$activity = json_decode($m,true);
}
else {
$activity = \Zotlabs\Lib\Activity::encode_activity($target_item);
$activity = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], Activity::encode_activity($target_item)
);
}
logger('target_item: ' . print_r($target_item,true), LOGGER_DEBUG);
logger('encoded: ' . print_r($activity,true), LOGGER_DEBUG);
// Send comments to the owner to re-deliver to everybody in the conversation
// We only do this if the item in question originated on this site. This prevents looping.
// To clarify, a site accepting a new comment is responsible for sending it to the owner for relay.

View File

@@ -61,11 +61,13 @@ class Onepoll {
if($contact['xchan_network'] === 'rss') {
logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG);
handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
q("update abook set abook_connected = '%s' where abook_id = %d",
dbesc(datetime_convert()),
intval($contact['abook_id'])
);
$alive = handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
if ($alive) {
q("update abook set abook_connected = '%s' where abook_id = %d",
dbesc(datetime_convert()),
intval($contact['abook_id'])
);
}
return;
}

View File

@@ -47,7 +47,7 @@ class Poller {
$restart = true;
$generation = intval($argv[2]);
if(! $generation)
killme();
return;
}
if(($argc > 1) && intval($argv[1])) {

View File

@@ -2,10 +2,12 @@
namespace Zotlabs\Lib;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Daemon\Master;
use Zotlabs\Web\HTTPSig;
require_once('include/event.php');
require_once('include/html2plain.php');
class Activity {
@@ -40,6 +42,8 @@ class Activity {
if($x['type'] === ACTIVITY_OBJ_PHOTO) {
return self::fetch_image($x);
}
call_hooks('encode_object',$x);
}
return $x;
@@ -63,12 +67,32 @@ class Activity {
}
else {
$m = parse_url($url);
// handle bearcaps
if ($m['scheme'] === 'bear') {
$params = explode('&',$m['query']);
if ($params) {
foreach ($params as $p) {
if (substr($p,0,2) === 'u=') {
$url = substr($p,2);
}
if (substr($p,0,2) === 't=') {
$token = substr($p,2);
}
}
$m = parse_url($url);
}
}
$headers = [
'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'Host' => $m['host'],
'(request-target)' => 'get ' . get_request_string($url),
'Date' => datetime_convert('UTC','UTC','now','D, d M Y H:i:s') . ' UTC'
'Date' => datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'),
'(request-target)' => 'get ' . get_request_string($url)
];
if (isset($token)) {
$headers['Authorization'] = 'Bearer ' . $token;
}
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false);
$x = z_fetch_url($url, true, $redirects, [ 'headers' => $h ] );
}
@@ -144,6 +168,10 @@ class Activity {
if($r) {
xchan_query($r,true);
$r = fetch_post_tags($r,true);
if ($r[0]['verb'] === 'Create' && $r[0]['obj_type'] === ACTIVITY_OBJ_EVENT) {
$r[0]['verb'] = 'Invite';
return self::encode_activity($r[0]);
}
return self::encode_item($r[0]);
}
}
@@ -178,6 +206,11 @@ class Activity {
$ev = bbtoevent($x['content']);
if($ev) {
if (! $ev['timezone']) {
$ev['timezone'] = 'UTC';
}
$actor = null;
if(array_key_exists('author',$x) && array_key_exists('link',$x['author'])) {
$actor = $x['author']['link'][0]['href'];
@@ -185,16 +218,17 @@ class Activity {
$y = [
'type' => 'Event',
'id' => z_root() . '/event/' . $ev['event_hash'],
'summary' => bbcode($ev['summary'], [ 'cache' => true ]),
'name' => $ev['summary'],
// 'summary' => bbcode($ev['summary'], [ 'cache' => true ]),
// RFC3339 Section 4.3
'startTime' => (($ev['adjust']) ? datetime_convert('UTC','UTC',$ev['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtstart'],'Y-m-d\\TH:i:s-00:00')),
'startTime' => (($ev['adjust']) ? datetime_convert($ev['timezone'],'UTC',$ev['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtstart'],'Y-m-d\\TH:i:s-00:00')),
'content' => bbcode($ev['description'], [ 'cache' => true ]),
'location' => [ 'type' => 'Place', 'content' => bbcode($ev['location'], [ 'cache' => true ]) ],
'source' => [ 'content' => format_event_bbcode($ev), 'mediaType' => 'text/bbcode' ],
'source' => [ 'content' => format_event_bbcode($ev,true), 'mediaType' => 'text/bbcode' ],
'actor' => $actor,
];
if(! $ev['nofinish']) {
$y['endTime'] = (($ev['adjust']) ? datetime_convert('UTC','UTC',$ev['dtend'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtend'],'Y-m-d\\TH:i:s-00:00'));
$y['endTime'] = (($ev['adjust']) ? datetime_convert($ev['timezone'],'UTC',$ev['dtend'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtend'],'Y-m-d\\TH:i:s-00:00'));
}
// copy attachments from the passed object - these are already formatted for ActivityStreams
@@ -274,8 +308,14 @@ class Activity {
$ret = [];
$objtype = self::activity_obj_mapper($i['obj_type']);
if($i['verb'] === ACTIVITY_FRIEND) {
// Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
$objtype = 'Note';
}
else {
$objtype = self::activity_obj_mapper($i['obj_type']);
}
if(intval($i['item_deleted'])) {
$ret['type'] = 'Tombstone';
$ret['formerType'] = $objtype;
@@ -285,6 +325,22 @@ class Activity {
$ret['type'] = $objtype;
if ($objtype === 'Question') {
if ($i['obj']) {
if (is_array($i['obj'])) {
$ret = $i['obj'];
}
else {
$ret = json_decode($i['obj'],true);
}
if(array_path_exists('actor/id',$ret)) {
$ret['actor'] = $ret['actor']['id'];
}
}
}
$ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/item/' . urlencode($i['mid']));
if($i['title'])
@@ -312,10 +368,21 @@ class Activity {
}
}
if (intval($i['item_wall']) && $i['mid'] === $i['parent_mid']) {
$ret['commentPolicy'] = map_scope(PermissionLimits::Get($i['uid'],'post_comments'));
}
if (intval($i['item_private']) === 2) {
$ret['directMessage'] = true;
}
if (array_key_exists('comments_closed',$i) && $i['comments_closed'] !== EMPTY_STR && $i['comments_closed'] !== NULL_DATE) {
if($ret['commentPolicy']) {
$ret['commentPolicy'] .= ' ';
}
$ret['commentPolicy'] .= 'until=' . datetime_convert('UTC','UTC',$i['comments_closed'],ATOM_TIME);
}
$ret['attributedTo'] = $i['author']['xchan_url'];
if($i['id'] != $i['parent']) {
@@ -354,26 +421,30 @@ class Activity {
$ret = [];
if($item['tag']) {
foreach($item['tag'] as $t) {
if(! array_key_exists('type',$t))
if ($item['tag'] && is_array($item['tag'])) {
$ptr = $item['tag'];
if (! array_key_exists(0,$ptr)) {
$ptr = [ $ptr ];
}
foreach ($ptr as $t) {
if (! array_key_exists('type',$t))
$t['type'] = 'Hashtag';
switch($t['type']) {
case 'Hashtag':
$ret[] = [ 'ttype' => TERM_HASHTAG, 'url' => ((isset($t['href'])) ? $t['href'] : $t['id']), 'term' => escape_tags((substr($t['name'],0,1) === '#') ? substr($t['name'],1) : $t['name']) ];
$ret[] = [ 'ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'],0,1) === '#') ? substr($t['name'],1) : $t['name']) ];
break;
case 'Mention':
$mention_type = substr($t['name'],0,1);
if($mention_type === '!') {
if ($mention_type === '!') {
$ret[] = [ 'ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'],1)) ];
}
else {
$ret[] = [ 'ttype' => TERM_MENTION, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'],0,1) === '@') ? substr($t['name'],1) : $t['name']) ];
}
break;
default:
break;
}
@@ -384,6 +455,7 @@ class Activity {
}
static function encode_taxonomy($item) {
$ret = [];
@@ -467,6 +539,12 @@ class Activity {
$ret = [];
$reply = false;
if($i['verb'] === ACTIVITY_FRIEND) {
// Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
$ret['obj'] = [];
}
if(intval($i['item_deleted'])) {
$ret['type'] = 'Tombstone';
$ret['formerType'] = self::activity_obj_mapper($i['obj_type']);
@@ -479,11 +557,6 @@ class Activity {
return $ret;
}
if($i['verb'] === ACTIVITY_FRIEND) {
// Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
$ret['obj_type'] = ACTIVITY_OBJ_NOTE;
$ret['obj'] = [];
}
$ret['type'] = self::activity_mapper($i['verb']);
@@ -497,11 +570,37 @@ class Activity {
xchan_query($p,true);
$p = fetch_post_tags($p,true);
$i['obj'] = self::encode_item($p[0]);
// convert to zot6 emoji reaction encoding which uses the target object to indicate the
// specific emoji instead of overloading the verb or type.
$im = explode('#',$i['verb']);
if($im && count($im) > 1)
$emoji = $im[1];
if(preg_match("/\[img(.*?)\](.*?)\[\/img\]/ism", $i['body'], $match)) {
$ln = $match[2];
}
$i['tgt_type'] = 'Image';
$i['target'] = [
'type' => 'Image',
'name' => $emoji,
'url' => (($ln) ? $ln : z_root() . '/images/emoji/' . $emoji . '.png')
];
}
}
$ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/activity/' . urlencode($i['mid']));
if (strpos($i['mid'],z_root() . '/item/') !== false) {
$ret['id'] = str_replace('/item/','/activity/',$i['mid']);
}
elseif (strpos($i['mid'],z_root() . '/event/') !== false) {
$ret['id'] = str_replace('/event/','/activity/',$i['mid']);
}
else {
$ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/activity/' . urlencode($i['mid']));
}
if($i['title'])
$ret['name'] = html2plain(bbcode($i['title'], [ 'cache' => true ]));
@@ -537,9 +636,15 @@ class Activity {
}
if($i['id'] != $i['parent']) {
$ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
$reply = true;
// inReplyTo needs to be set in the activity for followup actions (Like, Dislike, Announce, etc.),
// but *not* for comments and RSVPs, where it should only be present in the object
if (! in_array($ret['type'],[ 'Create','Update','Accept','Reject','TentativeAccept','TentativeReject' ])) {
$ret['inReplyTo'] = ((strpos($i['thr_parent'],'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent']));
}
if($i['item_private']) {
$d = q("select xchan_url, xchan_addr, xchan_name from item left join xchan on xchan_hash = author_xchan where id = %d limit 1",
intval($i['parent'])
@@ -577,7 +682,7 @@ class Activity {
$i['obj'] = json_decode($i['obj'],true);
}
if($i['obj']['type'] === ACTIVITY_OBJ_PHOTO) {
$i['obj']['id'] = $i['id'];
$i['obj']['id'] = $i['mid'];
}
$obj = self::encode_object($i['obj']);
@@ -594,6 +699,9 @@ class Activity {
return [];
}
if(array_path_exists('object/type',$ret) && $ret['object']['type'] === 'Event' && $ret['type'] === 'Create') {
$ret['type'] = 'Invite';
}
if($i['target']) {
if(! is_array($i['target'])) {
@@ -668,8 +776,24 @@ class Activity {
}
$ret = [];
$c = ((array_key_exists('channel_id',$p)) ? $p : channelx_by_hash($p['xchan_hash']));
$ret['type'] = 'Person';
$ret['id'] = $p['xchan_url'];
if ($c) {
$role = get_pconfig($c['channel_id'],'system','permissions_role');
if (strpos($role,'forum') !== false) {
$ret['type'] = 'Group';
}
}
if ($c) {
$ret['id'] = channel_url($c);
}
else {
$ret['id'] = ((strpos($p['xchan_hash'],'http') === 0) ? $p['xchan_hash'] : $p['xchan_url']);
}
if($p['xchan_addr'] && strpos($p['xchan_addr'],'@'))
$ret['preferredUsername'] = substr($p['xchan_addr'],0,strpos($p['xchan_addr'],'@'));
$ret['name'] = $p['xchan_name'];
@@ -728,9 +852,11 @@ class Activity {
'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow',
'http://purl.org/zot/activity/attendyes' => 'Accept',
'http://purl.org/zot/activity/attendno' => 'Reject',
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept',
'Invite' => 'Invite',
];
call_hooks('activity_mapper',$acts);
if(array_key_exists($verb,$acts) && $acts[$verb]) {
return $acts[$verb];
@@ -743,6 +869,9 @@ class Activity {
if(strpos($verb,ACTIVITY_MOOD) !== false)
return 'Create';
if(strpos($verb,ACTIVITY_FRIEND) !== false)
return 'Create';
if(strpos($verb,ACTIVITY_POKE) !== false)
return 'Activity';
@@ -770,9 +899,11 @@ class Activity {
'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow',
'http://purl.org/zot/activity/attendyes' => 'Accept',
'http://purl.org/zot/activity/attendno' => 'Reject',
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept',
'Invite' => 'Invite',
];
call_hooks('activity_decode_mapper',$acts);
foreach($acts as $k => $v) {
if($verb === $v) {
@@ -803,9 +934,12 @@ class Activity {
'http://purl.org/zot/activity/thing' => 'Object',
'http://purl.org/zot/activity/file' => 'zot:File',
'http://purl.org/zot/activity/mood' => 'zot:Mood',
'Invite' => 'Invite',
'Question' => 'Question'
];
call_hooks('activity_obj_decode_mapper',$objs);
foreach($objs as $k => $v) {
if($obj === $v) {
return $k;
@@ -821,10 +955,6 @@ class Activity {
static function activity_obj_mapper($obj) {
if(strpos($obj,'/') === false) {
return $obj;
}
$objs = [
'http://activitystrea.ms/schema/1.0/note' => 'Note',
'http://activitystrea.ms/schema/1.0/comment' => 'Note',
@@ -840,9 +970,21 @@ class Activity {
'http://purl.org/zot/activity/thing' => 'Object',
'http://purl.org/zot/activity/file' => 'zot:File',
'http://purl.org/zot/activity/mood' => 'zot:Mood',
'Invite' => 'Invite',
'Question' => 'Question'
];
call_hooks('activity_obj_mapper',$objs);
if ($obj === 'Answer') {
return 'Note';
}
if (strpos($obj,'/') === false) {
return $obj;
}
if(array_key_exists($obj,$objs)) {
return $objs[$obj];
}
@@ -1493,6 +1635,73 @@ class Activity {
}
static function update_poll($item,$mid,$content) {
$multi = false;
if (! $item) {
return false;
}
$o = json_decode($item['obj'],true);
if ($o && array_key_exists('anyOf',$o)) {
$multi = true;
}
$answer_found = false;
$found = false;
if ($multi) {
for ($c = 0; $c < count($o['anyOf']); $c ++) {
if ($o['anyOf'][$c]['name'] === $content) {
$answer_found = true;
if (is_array($o['anyOf'][$c]['replies'])) {
foreach($o['anyOf'][$c]['replies'] as $reply) {
if(is_array($reply) && array_key_exists('id',$reply) && $reply['id'] === $mid) {
$found = true;
}
}
}
if (! $found) {
$o['anyOf'][$c]['replies']['totalItems'] ++;
$o['anyOf'][$c]['replies']['items'][] = [ 'id' => $mid, 'type' => 'Note' ];
}
}
}
}
else {
for ($c = 0; $c < count($o['oneOf']); $c ++) {
if ($o['oneOf'][$c]['name'] === $content) {
$answer_found = true;
if (is_array($o['oneOf'][$c]['replies'])) {
foreach($o['oneOf'][$c]['replies'] as $reply) {
if(is_array($reply) && array_key_exists('id',$reply) && $reply['id'] === $mid) {
$found = true;
}
}
}
if (! $found) {
$o['oneOf'][$c]['replies']['totalItems'] ++;
$o['oneOf'][$c]['replies']['items'][] = [ 'id' => $mid, 'type' => 'Note' ];
}
}
}
}
logger('updated_poll: ' . print_r($o,true),LOGGER_DATA);
if ($answer_found && ! $found) {
$x = q("update item set obj = '%s', edited = '%s' where id = %d",
dbesc(json_encode($o)),
dbesc(datetime_convert()),
intval($item['id'])
);
Master::Summon( [ 'Notifier', 'wall-new', $item['id'] ] );
return true;
}
return false;
}
static function decode_note($act) {
$response_activity = false;
@@ -1531,7 +1740,6 @@ class Activity {
$s['expires'] = datetime_convert('UTC','UTC',$act->obj['expires']);
}
if(in_array($act->type, [ 'Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'emojiReaction' ])) {
$response_activity = true;
@@ -1561,15 +1769,23 @@ class Activity {
if($act->type === 'Dislike') {
$content['content'] = sprintf( t('Doesn\'t like %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content'];
}
if($act->type === 'Accept' && $act->obj['type'] === 'Event' ) {
$content['content'] = sprintf( t('Will attend %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content'];
}
if($act->type === 'Reject' && $act->obj['type'] === 'Event' ) {
$content['content'] = sprintf( t('Will not attend %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content'];
}
if($act->type === 'TentativeAccept' && $act->obj['type'] === 'Event' ) {
$content['content'] = sprintf( t('May attend %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content'];
// handle event RSVPs
if (($act->obj['type'] === 'Event') || ($act->obj['type'] === 'Invite' && array_path_exists('object/type',$act->obj) && $act->obj['object']['type'] === 'Event')) {
if ($act->type === 'Accept') {
$content['content'] = sprintf( t('Will attend %s\'s event'),$mention) . EOL . EOL . $content['content'];
}
if ($act->type === 'Reject') {
$content['content'] = sprintf( t('Will not attend %s\'s event'),$mention) . EOL . EOL . $content['content'];
}
if ($act->type === 'TentativeAccept') {
$content['content'] = sprintf( t('May attend %s\'s event'),$mention) . EOL . EOL . $content['content'];
}
if ($act->type === 'TentativeReject') {
$content['content'] = sprintf( t('May not attend %s\'s event'),$mention) . EOL . EOL . $content['content'];
}
}
if($act->type === 'Announce') {
$content['content'] = sprintf( t('&#x1f501; Repeated %1$s\'s %2$s'), $mention, $act->obj['type']);
}
@@ -1590,37 +1806,58 @@ class Activity {
$s['verb'] = self::activity_decode_mapper($act->type);
// Mastodon does not provide update timestamps when updating poll tallies which means race conditions may occur here.
if ($act->type === 'Update' && $act->obj['type'] === 'Question' && $s['edited'] === $s['created']) {
$s['edited'] = datetime_convert();
}
if($act->type === 'Tombstone' || $act->type === 'Delete' || ($act->type === 'Create' && $act->obj['type'] === 'Tombstone')) {
$s['item_deleted'] = 1;
}
$s['obj_type'] = self::activity_obj_decode_mapper($act->obj['type']);
if($s['obj_type'] === ACTIVITY_OBJ_NOTE && $s['mid'] !== $s['parent_mid']) {
$s['obj_type'] = ACTIVITY_OBJ_COMMENT;
}
$eventptr = null;
if ($act->obj['type'] === 'Invite' && array_path_exists('object/type',$act->obj) && $act->obj['object']['type'] === 'Event') {
$eventptr = $act->obj['object'];
$s['mid'] = $s['parent_mid'] = $act->obj['id'];
}
if($act->obj['type'] === 'Event') {
if ($act->type === 'Invite') {
$s['mid'] = $s['parent_mid'] = $act->id;
}
$eventptr = $act->obj;
}
if ($eventptr) {
$s['obj'] = [];
$s['obj']['asld'] = $act->obj;
$s['obj']['asld'] = $eventptr;
$s['obj']['type'] = ACTIVITY_OBJ_EVENT;
$s['obj']['id'] = $act->obj['id'];
$s['obj']['title'] = $act->obj['summary'];
$s['obj']['id'] = $eventptr['id'];
$s['obj']['title'] = $eventptr['name'];
if(strpos($act->obj['startTime'],'Z'))
$s['obj']['adjust'] = true;
else
$s['obj']['adjust'] = false;
$s['obj']['dtstart'] = datetime_convert('UTC','UTC',$act->obj['startTime']);
$s['obj']['dtstart'] = datetime_convert('UTC','UTC',$eventptr['startTime']);
if($act->obj['endTime'])
$s['obj']['dtend'] = datetime_convert('UTC','UTC',$act->obj['endTime']);
$s['obj']['dtend'] = datetime_convert('UTC','UTC',$eventptr['endTime']);
else
$s['obj']['nofinish'] = true;
$s['obj']['description'] = $act->obj['content'];
$s['obj']['description'] = $eventptr['content'];
if(array_path_exists('location/content',$act->obj))
$s['obj']['location'] = $act->obj['location']['content'];
if(array_path_exists('location/content',$eventptr))
$s['obj']['location'] = $eventptr['location']['content'];
}
else {
@@ -1662,6 +1899,18 @@ class Activity {
}
if ($act->obj['type'] === 'Question' && in_array($act->type,['Create','Update'])) {
if ($act->obj['endTime']) {
$s['comments_closed'] = datetime_convert('UTC','UTC', $act->obj['endTime']);
}
}
if ($act->obj['closed']) {
$s['comments_closed'] = datetime_convert('UTC','UTC', $act->obj['closed']);
}
// we will need a hook here to extract magnet links e.g. peertube
// right now just link to the largest mp4 we find that will fit in our
// standard content region
@@ -1853,9 +2102,15 @@ class Activity {
$s['plink'] = $s['mid'];
}
if($act->recips && (! in_array(ACTIVITY_PUBLIC_INBOX,$act->recips)))
if ($act->recips && (! in_array(ACTIVITY_PUBLIC_INBOX,$act->recips)))
$s['item_private'] = 1;
if (is_array($act->obj)) {
if (array_key_exists('directMessage',$act->obj) && intval($act->obj['directMessage'])) {
$s['item_private'] = 2;
}
}
set_iconfig($s,'activitypub','recips',$act->raw_recips);
$parent = (($s['parent_mid'] && $s['parent_mid'] === $s['mid']) ? true : false);
@@ -1863,6 +2118,15 @@ class Activity {
set_iconfig($s,'activitypub','rawmsg',$act->raw,1);
}
$hookinfo = [
'act' => $act,
's' => $s
];
call_hooks('decode_note',$hookinfo);
$s = $hookinfo['s'];
return $s;
}
@@ -1935,7 +2199,7 @@ class Activity {
set_iconfig($item,'activitypub','recips',$act->raw_recips);
if(! $is_parent) {
$p = q("select parent_mid from item where mid = '%s' and uid = %d limit 1",
$p = q("select parent_mid, id, obj_type from item where mid = '%s' and uid = %d limit 1",
dbesc($item['parent_mid']),
intval($item['uid'])
);
@@ -1965,6 +2229,15 @@ class Activity {
// $s['thr_parent'] = $s['mid'];
}
}
if ($p[0]['obj_type'] === 'Question') {
if ($item['obj_type'] === ACTIVITY_OBJ_NOTE && $item['title'] && (! $item['content'])) {
$item['obj_type'] = 'Answer';
}
}
if($p[0]['parent_mid'] !== $item['parent_mid']) {
$item['thr_parent'] = $item['parent_mid'];
}
@@ -2052,16 +2325,25 @@ class Activity {
break;
}
if(! $item) {
break;
$hookinfo = [
'a' => $a,
'item' => $item
];
call_hooks('fetch_and_store',$hookinfo);
$item = $hookinfo['item'];
if($item) {
array_unshift($p,[ $a, $item, $replies]);
if($item['parent_mid'] === $item['mid'] || count($p) > 20) {
break;
}
}
array_unshift($p,[ $a, $item, $replies]);
if($item['parent_mid'] === $item['mid'] || count($p) > 20) {
break;
}
$current_act = $a;
$current_item = $item;
}
@@ -2110,11 +2392,19 @@ class Activity {
default:
break;
}
if(! $item) {
break;
}
array_unshift($p,[ $a, $item ]);
$hookinfo = [
'a' => $a,
'item' => $item
];
call_hooks('fetch_and_store',$hookinfo);
$item = $hookinfo['item'];
if($item) {
array_unshift($p,[ $a, $item ]);
}
}
@@ -2495,7 +2785,12 @@ class Activity {
}
if($event) {
$event['summary'] = html2bbcode($content['summary']);
$event['summary'] = $content['name'];
if(! $event['summary']) {
if($content['summary']) {
$event['summary'] = html2plain($content['summary']);
}
}
$event['description'] = html2bbcode($content['content']);
if($event['summary'] && $event['dtstart']) {
$content['event'] = $event;

View File

@@ -101,7 +101,13 @@ class ActivityStreams {
$this->actor = $this->get_actor('attributedTo',$this->obj);
}
}
// 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']);
}
if($this->obj && is_array($this->obj) && $this->obj['actor'])
$this->obj['actor'] = $this->get_actor('actor',$this->obj);
if($this->tgt && is_array($this->tgt) && $this->tgt['actor'])

View File

@@ -74,7 +74,6 @@ class Apps {
'Directory',
'Search',
'Help',
'Mail',
'Profile Photo'
]);

View File

@@ -7,12 +7,23 @@ namespace Zotlabs\Lib;
*/
class Cache {
public static function get($key) {
/**
* @brief Returns cached content
*
* @param string $key
* @param string $age in SQL format, default is '30 DAY'
* @return string
*/
public static function get($key, $age = '') {
$hash = hash('whirlpool',$key);
$r = q("SELECT v FROM cache WHERE k = '%s' limit 1",
dbesc($hash)
$r = q("SELECT v FROM cache WHERE k = '%s' AND updated > %s - INTERVAL %s LIMIT 1",
dbesc($hash),
db_utcnow(),
db_quoteinterval(($age ? $age : get_config('system','object_cache_days', '30') . ' DAY'))
);
if ($r)
@@ -40,12 +51,4 @@ class Cache {
dbesc(datetime_convert()));
}
}
public static function clear() {
q("DELETE FROM cache WHERE updated < '%s'",
dbesc(datetime_convert('UTC','UTC',"now - 30 days")));
}
}

View File

@@ -550,6 +550,11 @@ class Enotify {
if ((\App::$language === 'en' || (! \App::$language)) && strpos($msg,', '))
$msg = substr($msg,strpos($msg,', ')+1);
$datarray['id'] = $notify_id;
$datarray['msg'] = $msg;
call_hooks('enotify_store_end', $datarray);
$r = q("update notify set msg = '%s' where id = %d and uid = %d",
dbesc($msg),
intval($notify_id),
@@ -805,11 +810,12 @@ class Enotify {
}
else {
$itemem_text = (($item['item_thread_top'])
? t('created a new post')
: sprintf( t('commented on %s\'s post'), $item['owner']['xchan_name']));
? (($item['obj_type'] === 'Question') ? t('created a new poll') : t('created a new post'))
: (($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) {
$itemem_text = sprintf( t('repeated %s\'s post'), $item['author']['xchan_name']);
$itemem_text = sprintf( t('repeated %s\'s post'), '[bdi]' . $item['author']['xchan_name'] . '[/bdi]');
}
}
@@ -838,15 +844,16 @@ class Enotify {
'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' => relative_date(($edit)? $item['edited'] : $item['created']),
'when' => (($edit) ? datetime_convert('UTC', date_default_timezone_get(), $item['edited']) : datetime_convert('UTC', date_default_timezone_get(), $item['created'])),
'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'),
'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])),
'b64mid' => 'b64.' . base64url_encode($item['mid']),
//'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])),
'notify_id' => 'undefined',
'thread_top' => (($item['item_thread_top']) ? true : false),
'message' => strip_tags(bbcode($itemem_text)),
'message' => bbcode(escape_tags($itemem_text)),
// these are for the superblock addon
'hash' => $item[$who]['xchan_hash'],
'uid' => local_channel(),
'uid' => $item['uid'],
'display' => true
);
@@ -858,4 +865,120 @@ class Enotify {
return $x;
}
static public function format_notify($tt) {
$message = trim(strip_tags(bbcode($tt['msg'])));
if(strpos($message, $tt['xname']) === 0)
$message = substr($message, strlen($tt['xname']) + 1);
$mid = basename($tt['link']);
$b64mid = ((strpos($mid, 'b64.') === 0) ? $mid : 'b64.' . base64url_encode($mid));
$x = [
'notify_link' => z_root() . '/notify/view/' . $tt['id'],
'name' => $tt['xname'],
'url' => $tt['url'],
'photo' => $tt['photo'],
'when' => datetime_convert('UTC', date_default_timezone_get(), $tt['created']),
'hclass' => (($tt['seen']) ? 'notify-seen' : 'notify-unseen'),
'b64mid' => (($tt['otype'] == 'item') ? $b64mid : 'undefined'),
'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : 'undefined'),
'message' => $message
];
return $x;
}
static public function format_intros($rr) {
$x = [
'notify_link' => z_root() . '/connections/ifpending',
'name' => $rr['xchan_name'],
'addr' => $rr['xchan_addr'],
'url' => $rr['xchan_url'],
'photo' => $rr['xchan_photo_s'],
'when' => datetime_convert('UTC', date_default_timezone_get(), $rr['abook_created']),
'hclass' => ('notify-unseen'),
'message' => t('added your channel')
];
return $x;
}
static public function format_files($rr) {
$x = [
'notify_link' => z_root() . '/sharedwithme',
'name' => $rr['author']['xchan_name'],
'addr' => $rr['author']['xchan_addr'],
'url' => $rr['author']['xchan_url'],
'photo' => $rr['author']['xchan_photo_s'],
'when' => datetime_convert('UTC', date_default_timezone_get(), $rr['created']),
'hclass' => ('notify-unseen'),
'message' => t('shared a file with you')
];
return $x;
}
static public function format_mail($rr) {
$x = [
'notify_link' => z_root() . '/mail/' . $rr['id'],
'name' => $rr['xchan_name'],
'addr' => $rr['xchan_addr'],
'url' => $rr['xchan_url'],
'photo' => $rr['xchan_photo_s'],
'when' => datetime_convert('UTC', date_default_timezone_get(), $rr['created']),
'hclass' => (intval($rr['mail_seen']) ? 'notify-seen' : 'notify-unseen'),
'message' => t('sent you a private message'),
];
return $x;
}
static public function format_all_events($rr) {
$bd_format = t('g A l F d') ; // 8 AM Friday January 18
$strt = datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['dtstart']);
$today = ((substr($strt, 0, 10) === datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d')) ? true : false);
$when = day_translate(datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['dtstart'], $bd_format)) . (($today) ? ' ' . t('[today]') : '');
$x = [
'notify_link' => z_root() . '/cdav/calendar/' . $rr['event_hash'],
'name' => $rr['xchan_name'],
'addr' => $rr['xchan_addr'],
'url' => $rr['xchan_url'],
'photo' => $rr['xchan_photo_s'],
'when' => $when,
'hclass' => ('notify-unseen'),
'message' => t('posted an event')
];
return $x;
}
static public function format_register($rr) {
$x = [
'notify_link' => z_root() . '/admin/accounts',
'name' => $rr['account_email'],
'addr' => $rr['account_email'],
'url' => '',
'photo' => z_root() . '/' . get_default_profile_photo(48),
'when' => datetime_convert('UTC', date_default_timezone_get(),$rr['account_created']),
'hclass' => ('notify-unseen'),
'message' => t('requires approval')
];
return $x;
}
}

View File

@@ -30,7 +30,7 @@ class LDSignatures {
'type' => 'RsaSignature2017',
'nonce' => random_string(64),
'creator' => z_root() . '/channel/' . $channel['channel_address'],
'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\Th:i:s\Z')
'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\TH:i:s\Z')
];
$ohash = self::hash(self::signable_options($options));

View File

@@ -83,7 +83,7 @@ class Libsync {
$info = (($packet) ? $packet : array());
$info['type'] = 'sync';
$info['encoding'] = 'red'; // note: not zot, this packet is very platform specific
$info['encoding'] = 'hz'; // note: not zot, this packet is very platform specific
$info['relocate'] = ['channel_address' => $channel['channel_address'], 'url' => z_root() ];
if(array_key_exists($uid,\App::$config) && array_key_exists('transient',\App::$config[$uid])) {
@@ -144,7 +144,7 @@ class Libsync {
foreach($synchubs as $hub) {
$hash = random_string();
$n = Libzot::build_packet($channel,'sync',$env_recips,json_encode($info),'red',$hub['hubloc_sitekey'],$hub['site_crypto']);
$n = Libzot::build_packet($channel,'sync',$env_recips,json_encode($info),'hz',$hub['hubloc_sitekey'],$hub['site_crypto']);
Queue::insert(array(
'hash' => $hash,
'account_id' => $channel['channel_account_id'],
@@ -244,7 +244,13 @@ class Libsync {
if(array_key_exists('app',$arr) && $arr['app'])
sync_apps($channel,$arr['app']);
if(array_key_exists('addressbook',$arr) && $arr['addressbook'])
sync_addressbook($channel,$arr['addressbook']);
if(array_key_exists('calendar',$arr) && $arr['calendar'])
sync_calendar($channel,$arr['calendar']);
if(array_key_exists('chatroom',$arr) && $arr['chatroom'])
sync_chatrooms($channel,$arr['chatroom']);

View File

@@ -1220,12 +1220,42 @@ class Libzot {
$arr['owner_xchan'] = $env['sender'];
}
if($private) {
$arr['item_private'] = true;
if ($private && (! intval($arr['item_private']))) {
$arr['item_private'] = 1;
}
if ($arr['mid'] === $arr['parent_mid']) {
if (is_array($AS->obj) && array_key_exists('commentPolicy',$AS->obj)) {
$p = strstr($AS->obj['commentPolicy'],'until=');
if($p !== false) {
$arr['comments_closed'] = datetime_convert('UTC','UTC', substr($p,6));
$arr['comment_policy'] = trim(str_replace($p,'',$AS->obj['commentPolicy']));
}
else {
$arr['comment_policy'] = $AS->obj['commentPolicy'];
}
}
}
/// @FIXME - spoofable
if($AS->data['hubloc']) {
$arr['item_verified'] = true;
if (! array_key_exists('comment_policy',$arr)) {
// set comment policy depending on source hub. Unknown or osada is ActivityPub.
// Anything else we'll say is zot - which could have a range of project names
$s = q("select site_project from site where site_url = '%s' limit 1",
dbesc($r[0]['hubloc_url'])
);
if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) {
$arr['comment_policy'] = 'authenticated';
}
else {
$arr['comment_policy'] = 'contacts';
}
}
}
if($AS->data['signed_data']) {
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
@@ -1247,7 +1277,12 @@ class Libzot {
logger('Channel sync received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
logger('Channel sync recipients: ' . print_r($deliveries,true), LOGGER_DATA, LOG_DEBUG);
$result = Libsync::process_channel_sync_delivery($env['sender'],$arr,$deliveries);
if ($env['encoding'] === 'hz') {
$result = Libsync::process_channel_sync_delivery($env['sender'],$arr,$deliveries);
}
else {
logger('sync packet type not supported.');
}
}
}
if ($result) {
@@ -1578,10 +1613,11 @@ class Libzot {
// As a side effect we will also do a preliminary check that we have the top-level-post, otherwise
// processing it is pointless.
$r = q("select route, id, owner_xchan, item_private from item where mid = '%s' and uid = %d limit 1",
$r = q("select route, id, parent_mid, mid, owner_xchan, item_private, obj_type from item where mid = '%s' and uid = %d limit 1",
dbesc($arr['parent_mid']),
intval($channel['channel_id'])
);
if(! $r) {
$DR->update('comment parent not found');
$result[] = $DR->get();
@@ -1604,6 +1640,16 @@ class Libzot {
continue;
}
if ($r[0]['obj_type'] === 'Question') {
// route checking doesn't work correctly here because we've changed the privacy
$r[0]['route'] = EMPTY_STR;
// If this is a poll response, convert the obj_type to our (internal-only) "Answer" type
if ($arr['obj_type'] === ACTIVITY_OBJ_COMMENT && $arr['title'] && (! $arr['body'])) {
$arr['obj_type'] = 'Answer';
}
}
if($relay || $friendofriend || (intval($r[0]['item_private']) === 0 && intval($arr['item_private']) === 0)) {
// reset the route in case it travelled a great distance upstream
// use our parent's route so when we go back downstream we'll match
@@ -1734,7 +1780,7 @@ class Libzot {
// if it's a sourced post, call the post_local hooks as if it were
// posted locally so that crosspost connectors will be triggered.
if(check_item_source($arr['uid'], $arr)) {
if(check_item_source($arr['uid'], $arr) || ($channel['xchan_pubforum'] == 1)) {
/**
* @hooks post_local
* Called when an item has been posted on this machine via mod/item.php (also via API).
@@ -1819,6 +1865,10 @@ class Libzot {
$ret = [];
$signer = q("select hubloc_hash, hubloc_url from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
dbesc($a['signature']['signer'])
);
foreach($a['data']['orderedItems'] as $activity) {
$AS = new ActivityStreams($activity);
@@ -1877,6 +1927,23 @@ class Libzot {
if($AS->data['hubloc']) {
$arr['item_verified'] = true;
}
// set comment policy depending on source hub. Unknown or osada is ActivityPub.
// Anything else we'll say is zot - which could have a range of project names
if ($signer) {
$s = q("select site_project from site where site_url = '%s' limit 1",
dbesc($signer[0]['hubloc_url'])
);
if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) {
$arr['comment_policy'] = 'authenticated';
}
else {
$arr['comment_policy'] = 'contacts';
}
}
if($AS->data['signed_data']) {
IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false);
}

View File

@@ -250,7 +250,7 @@ class Queue {
$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' order by hubloc_id desc limit 1",
$h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' and hubloc_sitekey != '' order by hubloc_id desc limit 1",
dbesc($base)
);
if($h) {

View File

@@ -0,0 +1,150 @@
<?php
namespace Zotlabs\Lib;
use DomDocument;
/**
* SVGSantiizer
*
* Whitelist-based PHP SVG sanitizer.
*
* @link https://github.com/alister-/SVG-Sanitizer}
* @author Alister Norris
* @copyright Copyright (c) 2013 Alister Norris
* @license http://opensource.org/licenses/mit-license.php The MIT License
* @package svgsanitizer
*/
class SvgSanitizer {
private $xmlDoc; // PHP XML DOMDocument
private $removedattrs = [];
private static $allowed_functions = [ 'matrix', 'url', 'translate', 'rgb' ];
// defines the whitelist of elements and attributes allowed.
private static $whitelist = [
'a' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'href', 'xlink:href', 'xlink:title' ],
'circle' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
'clipPath' => [ 'class', 'clipPathUnits', 'id' ],
'defs' => [ ],
'style' => [ 'type' ],
'desc' => [ ],
'ellipse' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
'feGaussianBlur' => [ 'class', 'color-interpolation-filters', 'id', 'requiredFeatures', 'stdDeviation' ],
'filter' => [ 'class', 'color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'id', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y' ],
'foreignObject' => [ 'class', 'font-size', 'height', 'id', 'opacity', 'requiredFeatures', 'style', 'transform', 'width', 'x', 'y' ],
'g' => [ 'class', 'clip-path', 'clip-rule', 'id', 'display', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor' ],
'image' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'style', 'systemLanguage', 'transform', 'width', 'x', 'xlink:href', 'xlink:title', 'y' ],
'line' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'x1', 'x2', 'y1', 'y2' ],
'linearGradient' => [ 'class', 'id', 'gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2' ],
'marker' => [ 'id', 'class', 'markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'systemLanguage', 'viewBox' ],
'mask' => [ 'class', 'height', 'id', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y' ],
'metadata' => [ 'class', 'id' ],
'path' => [ 'class', 'clip-path', 'clip-rule', 'd', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
'pattern' => [ 'class', 'height', 'id', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y' ],
'polygon' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'class', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
'polyline' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ],
'radialGradient' => [ 'class', 'cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'id', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href' ],
'rect' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'width', 'x', 'y' ],
'stop' => [ 'class', 'id', 'offset', 'requiredFeatures', 'stop-color', 'stop-opacity', 'style', 'systemLanguage' ],
'svg' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'id', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'y' ],
'switch' => [ 'class', 'id', 'requiredFeatures', 'systemLanguage' ],
'symbol' => [ 'class', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'opacity', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'viewBox' ],
'text' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'transform', 'x', 'xml:space', 'y' ],
'textPath' => [ 'class', 'id', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'style', 'systemLanguage', 'transform', 'xlink:href' ],
'title' => [ ],
'tspan' => [ 'class', 'clip-path', 'clip-rule', 'dx', 'dy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'rotate', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'textLength', 'transform', 'x', 'xml:space', 'y' ],
'use' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'transform', 'width', 'x', 'xlink:href', 'y' ],
];
function __construct() {
$this->xmlDoc = new DOMDocument('1.0','UTF-8');
$this->xmlDoc->preserveWhiteSpace = false;
libxml_use_internal_errors(true);
}
// load XML SVG
function load($file) {
$this->xmlDoc->load($file);
}
function loadXML($str) {
if (! $this->xmlDoc->loadXML($str)) {
logger('loadxml: ' . print_r(libxml_get_errors(),true), LOGGER_DEBUG);
return false;
}
return true;
}
function sanitize()
{
// all elements in xml doc
$allElements = $this->xmlDoc->getElementsByTagName('*');
// loop through all elements
for($i = 0; $i < $allElements->length; $i++)
{
$this->removedattrs = [];
$currentNode = $allElements->item($i);
// logger('current_node: ' . print_r($currentNode,true));
// array of allowed attributes in specific element
$whitelist_attr_arr = self::$whitelist[$currentNode->tagName];
// does element exist in whitelist?
if(isset($whitelist_attr_arr)) {
$total = $currentNode->attributes->length;
for($x = 0; $x < $total; $x++) {
// get attributes name
$attrName = $currentNode->attributes->item($x)->nodeName;
// logger('checking: ' . print_r($currentNode->attributes->item($x),true));
$matches = false;
// check if attribute isn't in whitelist
if(! in_array($attrName, $whitelist_attr_arr)) {
$this->removedattrs[] = $attrName;
}
// check for disallowed functions
elseif (preg_match_all('/([a-zA-Z0-9]+)[\s]*\(/',
$currentNode->attributes->item($x)->textContent,$matches,PREG_SET_ORDER)) {
if ($attrName === 'text') {
continue;
}
foreach ($matches as $match) {
if(! in_array($match[1],self::$allowed_functions)) {
logger('queue_remove_function: ' . $match[1],LOGGER_DEBUG);
$this->removedattrs[] = $attrName;
}
}
}
}
if ($this->removedattrs) {
foreach ($this->removedattrs as $attr) {
$currentNode->removeAttribute($attr);
logger('removed: ' . $attr, LOGGER_DEBUG);
}
}
}
// else remove element
else {
logger('remove_node: ' . print_r($currentNode,true));
$currentNode->parentNode->removeChild($currentNode);
}
}
return true;
}
function saveSVG() {
$this->xmlDoc->formatOutput = true;
return($this->xmlDoc->saveXML());
}
}

View File

@@ -5,9 +5,14 @@ namespace Zotlabs\Lib;
class System {
static public function get_platform_name() {
if(is_array(\App::$config) && is_array(\App::$config['system']) && array_key_exists('platform_name',\App::$config['system']))
return \App::$config['system']['platform_name'];
return PLATFORM_NAME;
static $platform_name = '';
if(empty($platform_name)) {
if(is_array(\App::$config) && is_array(\App::$config['system']) && array_key_exists('platform_name',\App::$config['system']))
$platform_name = \App::$config['system']['platform_name'];
else
$platform_name = PLATFORM_NAME;
}
return $platform_name;
}
static public function get_site_name() {

View File

@@ -78,7 +78,7 @@ class ThreadItem {
*/
public function get_template_data($conv_responses, $thread_level=1, $conv_flags = []) {
$result = array();
$item = $this->get_data();
@@ -95,7 +95,7 @@ class ThreadItem {
$total_children = $this->count_descendants();
$unseen_comments = (($item['real_uid']) ? 0 : $this->count_unseen_descendants());
$conv = $this->get_conversation();
$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'])
@@ -204,6 +204,10 @@ class ThreadItem {
}
}
if($item['obj_type'] === 'Question') {
$response_verbs[] = 'answer';
}
$consensus = (intval($item['item_consensus']) ? true : false);
if($consensus) {
$response_verbs[] = 'agree';
@@ -346,7 +350,7 @@ class ThreadItem {
$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('%d unseen',$unseen_comments) : '');
$list_unseen_txt = (($unseen_comments) ? sprintf( t('%d unseen'),$unseen_comments) : '');
$children = $this->get_children();
@@ -356,11 +360,28 @@ class ThreadItem {
call_hooks('dropdown_extras',$dropdown_extras_arr);
$dropdown_extras = $dropdown_extras_arr['dropdown_extras'];
$midb64 = 'b64.' . base64url_encode($item['mid']);
$mids = [ $midb64 ];
$response_mids = [];
foreach($response_verbs as $v) {
if(isset($conv_responses[$v]['mids'][$item['mid']])) {
$response_mids = array_merge($response_mids, $conv_responses[$v]['mids'][$item['mid']]);
}
}
$mids = array_merge($mids, $response_mids);
$json_mids = json_encode($mids);
// Pinned item processing
$allowed_type = (in_array($item['item_type'], get_config('system', 'pin_types', [ ITEM_TYPE_POST ])) ? true : false);
$pinned_items = ($allowed_type ? get_pconfig($item['uid'], 'pinned', $item['item_type'], []) : []);
$pinned = ((!empty($pinned_items) && in_array($midb64, $pinned_items)) ? true : false);
$tmp_item = array(
'template' => $this->get_template(),
'mode' => $mode,
'item_type' => intval($item['item_type']),
'type' => implode("",array_slice(explode("/",$item['verb']),-1)),
//'type' => implode("",array_slice(explode("/",$item['verb']),-1)),
'body' => $body['html'],
'tags' => $body['tags'],
'categories' => $body['categories'],
@@ -369,7 +390,8 @@ class ThreadItem {
'folders' => $body['folders'],
'text' => strip_tags($body['html']),
'id' => $this->get_id(),
'mid' => $item['mid'],
'mid' => $midb64,
'mids' => $json_mids,
'parent' => $item['parent'],
'author_id' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
'isevent' => $isevent,
@@ -377,8 +399,8 @@ class ThreadItem {
'consensus' => $consensus,
'conlabels' => $conlabels,
'canvote' => $canvote,
'linktitle' => sprintf( t('View %s\'s profile - %s'), $profile_name, (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url'])),
'olinktitle' => sprintf( t('View %s\'s profile - %s'), $this->get_owner_name(), (($item['owner']['xchan_addr']) ? $item['owner']['xchan_addr'] : $item['owner']['xchan_url'])),
'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'],
'viewthread' => $viewthread,
'to' => t('to'),
@@ -396,7 +418,7 @@ class ThreadItem {
'sparkle' => $sparkle,
'title' => $item['title'],
'title_tosource' => get_pconfig($conv->get_profile_owner(),'system','title_tosource'),
'ago' => relative_date($item['created']),
//'ago' => relative_date($item['created']),
'app' => $item['app'],
'str_app' => sprintf( t('from %s'), $item['app']),
'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'),
@@ -437,6 +459,9 @@ class ThreadItem {
'star' => ((feature_enabled($conv->get_profile_owner(),'star_posts') && ($item['item_type'] == ITEM_TYPE_POST)) ? $star : ''),
'tagger' => ((feature_enabled($conv->get_profile_owner(),'commtag')) ? $tagger : ''),
'filer' => ((feature_enabled($conv->get_profile_owner(),'filing') && ($item['item_type'] == ITEM_TYPE_POST)) ? $filer : ''),
'pinned' => ($pinned ? t('Pinned post') : ''),
'pinnable' => (($this->is_toplevel() && local_channel() && $item['owner_xchan'] == $observer['xchan_hash'] && $allowed_type && $item['item_private'] == 0) ? '1' : ''),
'pinme' => ($pinned ? t('Unpin from the top') : t('Pin to the top')),
'bookmark' => (($conv->get_profile_owner() == local_channel() && local_channel() && $has_bookmarks) ? t('Save Bookmarks') : ''),
'addtocal' => (($has_event) ? t('Add to Calendar') : ''),
'drop' => $drop,
@@ -467,10 +492,9 @@ class ThreadItem {
'previewing' => ($conv->is_preview() ? true : false ),
'preview_lbl' => t('This is an unsaved preview'),
'wait' => t('Please wait'),
'submid' => str_replace(['+','='], ['',''], base64_encode($item['mid'])),
'thread_level' => $thread_level,
'settings' => $settings,
'thr_parent' => (($item['parent_mid'] != $item['thr_parent']) ? $item['thr_parent'] : '')
'thr_parent' => (($item['parent_mid'] != $item['thr_parent']) ? 'b64.' . base64url_encode($item['thr_parent']) : '')
);
$arr = array('item' => $item, 'output' => $tmp_item);
@@ -778,8 +802,6 @@ class ThreadItem {
call_hooks('comment_buttons',$arr);
$comment_buttons = $arr['comment_buttons'];
$feature_auto_save_draft = ((feature_enabled($conv->get_profile_owner(), 'auto_save_draft')) ? "true" : "false");
$comment_box = replace_macros($template,array(
'$return_path' => '',
'$threaded' => $this->is_threaded(),
@@ -814,8 +836,7 @@ class ThreadItem {
'$anoncomments' => ((($conv->get_mode() === 'channel' || $conv->get_mode() === 'display') && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false),
'$anonname' => [ 'anonname', t('Your full name (required)') ],
'$anonmail' => [ 'anonmail', t('Your email address (required)') ],
'$anonurl' => [ 'anonurl', t('Your website URL (optional)') ],
'$auto_save_draft' => $feature_auto_save_draft
'$anonurl' => [ 'anonurl', t('Your website URL (optional)') ]
));
return $comment_box;
@@ -866,7 +887,4 @@ class ThreadItem {
return $this->visiting;
}
}

View File

@@ -42,7 +42,7 @@ class Acl extends \Zotlabs\Web\Controller {
// $type =
// 'm' => autocomplete private mail recipient (checks post_mail permission)
// 'm' => autocomplete private mail recipient (checks post_mail permission and displays only zot, diaspora, friendica-over-diaspora xchan_network xchan's)
// 'a' => autocomplete connections (mod_connections, mod_poke, mod_sources, mod_photos)
// 'x' => nav search bar autocomplete (match any xchan)
// $_REQUEST['query'] contains autocomplete search text.
@@ -286,6 +286,7 @@ class Acl extends \Zotlabs\Web\Controller {
FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel = %d
and xchan_deleted = 0
and xchan_network IN ('zot', 'diaspora', 'friendica-over-diaspora')
$sql_extra3
ORDER BY xchan_name ASC ",
intval(local_channel())

175
Zotlabs/Module/Activity.php Normal file
View File

@@ -0,0 +1,175 @@
<?php
namespace Zotlabs\Module;
use Zotlabs\Lib\IConfig;
use Zotlabs\Lib\Enotify;
use Zotlabs\Web\Controller;
use Zotlabs\Daemon\Master;
use Zotlabs\Lib\Activity as ZlibActivity;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\LDSignatures;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\ThreadListener;
use App;
class Activity extends Controller {
function init() {
if (Libzot::is_zot_request()) {
$item_id = argv(1);
if (! $item_id)
http_status_exit(404, 'Not found');
$portable_id = EMPTY_STR;
$item_normal = " 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 ";
$i = null;
// do we have the item (at all)?
$r = q("select * from item where mid = '%s' $item_normal limit 1",
dbesc(z_root() . '/activity/' . $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'])
);
}
}
}
// 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');
$items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent IN ( %s ) $item_normal ",
dbesc($parents_str)
);
if(! $items) {
http_status_exit(404, 'Not found');
}
xchan_query($items,true);
$items = fetch_post_tags($items,true);
$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');
$chan = channelx_by_n($nitems[0]['uid']);
if(! $chan)
http_status_exit(404, 'Not found');
if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream'))
http_status_exit(403, 'Forbidden');
$i = ZlibActivity::encode_item_collection($nitems,'conversation/' . $item_id,'OrderedCollection');
if($portable_id) {
ThreadListener::store(z_root() . '/activity/' . $item_id,$portable_id);
}
if(! $i)
http_status_exit(404, 'Not found');
$x = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], $i);
$headers = [];
$headers['Content-Type'] = 'application/x-zot+json' ;
$x['signature'] = LDSignatures::sign($x,$chan);
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan));
HTTPSig::set_headers($h);
echo $ret;
killme();
}
}
}

View File

@@ -2,6 +2,7 @@
namespace Zotlabs\Module\Admin;
use App;
use \Zotlabs\Storage\GitRepo;
use \Michelf\MarkdownExtra;
@@ -253,14 +254,14 @@ class Addons {
* Single plugin
*/
if (\App::$argc == 3){
$plugin = \App::$argv[2];
if (App::$argc == 3){
$plugin = App::$argv[2];
if (!is_file("addon/$plugin/$plugin.php")){
notice( t("Item not found.") );
return '';
}
$enabled = in_array($plugin,\App::$plugins);
$enabled = in_array($plugin,App::$plugins);
$info = get_plugin_info($plugin);
$x = check_plugin_versions($info);
@@ -268,11 +269,11 @@ class Addons {
if($enabled && ! $x) {
$enabled = false;
$idz = array_search($plugin, \App::$plugins);
$idz = array_search($plugin, App::$plugins);
if ($idz !== false) {
unset(\App::$plugins[$idz]);
unset(App::$plugins[$idz]);
uninstall_plugin($plugin);
set_config("system","addon", implode(", ",\App::$plugins));
set_config("system","addon", implode(", ",App::$plugins));
}
}
$info['disabled'] = 1-intval($x);
@@ -281,19 +282,19 @@ class Addons {
check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't');
$pinstalled = false;
// Toggle plugin status
$idx = array_search($plugin, \App::$plugins);
$idx = array_search($plugin, App::$plugins);
if ($idx !== false){
unset(\App::$plugins[$idx]);
unset(App::$plugins[$idx]);
uninstall_plugin($plugin);
$pinstalled = false;
info( sprintf( t("Plugin %s disabled."), $plugin ) );
} else {
\App::$plugins[] = $plugin;
App::$plugins[] = $plugin;
install_plugin($plugin);
$pinstalled = true;
info( sprintf( t("Plugin %s enabled."), $plugin ) );
}
set_config("system","addon", implode(", ",\App::$plugins));
set_config("system","addon", implode(", ",App::$plugins));
if($pinstalled) {
@require_once("addon/$plugin/$plugin.php");
@@ -305,7 +306,7 @@ class Addons {
// display plugin details
if (in_array($plugin, \App::$plugins)){
if (in_array($plugin, App::$plugins)){
$status = 'on';
$action = t('Disable');
} else {
@@ -380,18 +381,18 @@ class Addons {
list($tmp, $id) = array_map('trim', explode('/', $file));
$info = get_plugin_info($id);
$enabled = in_array($id,\App::$plugins);
$enabled = in_array($id,App::$plugins);
$x = check_plugin_versions($info);
// disable plugins which are installed but incompatible versions
if($enabled && ! $x) {
$enabled = false;
$idz = array_search($id, \App::$plugins);
$idz = array_search($id, App::$plugins);
if ($idz !== false) {
unset(\App::$plugins[$idz]);
unset(App::$plugins[$idz]);
uninstall_plugin($id);
set_config("system","addon", implode(", ",\App::$plugins));
set_config("system","addon", implode(", ",App::$plugins));
}
}
$info['disabled'] = 1-intval($x);

View File

@@ -43,6 +43,12 @@ class Security {
$be = $this->trim_array_elems(explode("\n",$_POST['embed_deny']));
set_config('system','embed_deny',$be);
$thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
set_config('system', 'thumbnail_security' , $thumbnail_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);
@@ -86,7 +92,7 @@ class Security {
$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.");
$t = get_markup_template('admin_security.tpl');
return replace_macros($t, array(
'$title' => t('Administration'),
@@ -106,7 +112,9 @@ class Security {
'$embed_sslonly' => array('embed_sslonly',t('Only allow embeds from secure (SSL) websites and links.'), intval(get_config('system','embed_sslonly')),''),
'$embed_allow' => array('embed_allow', t('Allow unfiltered embedded HTML content only from these domains'), $whiteembeds_str, t('One site per line. By default embedded content is filtered.')),
'$embed_deny' => array('embed_deny', t('Block embedded HTML from these domains'), $blackembeds_str, ''),
'$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), '' ],
// '$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')
@@ -128,4 +136,4 @@ class Security {
}
}
}

View File

@@ -73,7 +73,6 @@ class Site {
$feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
$imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
$thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
$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']));
@@ -100,7 +99,6 @@ class Site {
set_config('system', 'from_email', $from_email);
set_config('system', 'from_email_name' , $from_email_name);
set_config('system', 'imagick_convert_path' , $imagick_path);
set_config('system', 'thumbnail_security' , $thumbnail_security);
set_config('system', 'default_permissions_role', $permissions_role);
set_config('system', 'pubstream_incl',$pub_incl);
set_config('system', 'pubstream_excl',$pub_excl);
@@ -341,7 +339,6 @@ class Site {
'$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")),
'$thumbnail_security' => array('thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.")),
'$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.")),
'$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content')),
'$active_expire_days' => array('active_expire_days', t('Do not expire any posts which have comments less than this many days ago'), intval(get_config('system','active_expire_days',7)), ''),

View File

@@ -85,10 +85,9 @@ class Article_edit extends \Zotlabs\Web\Controller {
$mimetype = $itm[0]['mimetype'];
$summary = (($itm[0]['summary']) ? '[summary]' . $itm[0]['summary'] . '[/summary]' . "\r\n" : '');
$content = $itm[0]['body'];
$rp = 'articles/' . $channel['channel_address'];
$x = array(
@@ -110,7 +109,7 @@ class Article_edit extends \Zotlabs\Web\Controller {
'ptyp' => $itm[0]['type'],
'mimeselect' => false,
'mimetype' => $itm[0]['mimetype'],
'body' => undo_post_tagging($content),
'body' => $summary . undo_post_tagging($content),
'post_id' => $post_id,
'visitor' => true,
'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),

View File

@@ -9,6 +9,7 @@ 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 {
@@ -192,7 +193,7 @@ class Articles extends Controller {
$parents_str = ids_to_querystr($r,'id');
$items = q("SELECT item.*, item.id AS item_id
$r = q("SELECT item.*, item.id AS item_id
FROM item
WHERE item.uid = %d $item_normal
AND item.parent IN ( %s )
@@ -200,15 +201,18 @@ class Articles extends Controller {
intval(App::$profile['profile_uid']),
dbesc($parents_str)
);
if($items) {
xchan_query($items);
$items = fetch_post_tags($items, true);
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))

View File

@@ -10,6 +10,7 @@ require_once('include/event.php');
require_once('include/auth.php');
require_once('include/security.php');
require_once('include/cdav.php');
class Cdav extends Controller {
@@ -156,6 +157,79 @@ class Cdav extends Controller {
}
}
// Track CDAV updates from remote clients
$httpmethod = $_SERVER['REQUEST_METHOD'];
if($httpmethod === 'PUT' || $httpmethod === 'DELETE') {
$httpuri = $_SERVER['REQUEST_URI'];
logger("debug: method: " . $httpmethod, LOGGER_DEBUG);
logger("debug: uri: " . $httpuri, LOGGER_DEBUG);
if(strpos($httpuri, 'cdav/addressbooks')) {
$sync = 'addressbook';
$cdavtable = 'addressbooks';
}
elseif(strpos($httpuri, 'cdav/calendars')) {
$sync = 'calendar';
$cdavtable = 'calendarinstances';
}
else
$sync = false;
if($sync) {
$uri = basename($httpuri);
$httpbody = file_get_contents('php://input');
logger("debug: body: " . $httpbody, LOGGER_DEBUG);
if($x = get_cdav_id($principalUri, explode("/", $httpuri)[4], $cdavtable)) {
$cdavdata = $this->get_cdav_data($x['id'], $cdavtable);
$etag = (isset($_SERVER['HTTP_IF_MATCH']) ? $_SERVER['HTTP_IF_MATCH'] : false);
// delete
if($httpmethod === 'DELETE' && $cdavdata['etag'] == $etag)
build_sync_packet($channel['channel_id'], [
$sync => [
'action' => 'delete_card',
'uri' => $cdavdata['uri'],
'carduri' => $uri
]
]);
else {
if($etag) {
// update
if($cdavdata['etag'] !== $etag)
build_sync_packet($channel['channel_id'], [
$sync => [
'action' => 'update_card',
'uri' => $cdavdata['uri'],
'carduri' => $uri,
'card' => $httpbody
]
]);
}
else {
// new
build_sync_packet($channel['channel_id'], [
$sync => [
'action' => 'import',
'uri' => $cdavdata['uri'],
'ids' => [ $uri ],
'card' => $httpbody
]
]);
}
}
}
}
}
$principalBackend = new \Sabre\DAVACL\PrincipalBackend\PDO($pdo);
@@ -262,6 +336,14 @@ class Cdav extends Controller {
// set new calendar to be visible
set_pconfig(local_channel(), 'cdav_calendar' , $id[0], 1);
build_sync_packet($channel['channel_id'], [
'calendar' => [
'action' => 'create',
'uri' => $calendarUri,
'properties' => $properties
]
]);
}
//create new calendar object via ajax request
@@ -272,6 +354,8 @@ class Cdav extends Controller {
if(!cdav_perms($id[0],$calendars,true))
return;
$cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
$timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
$tz = (($timezone) ? $timezone : date_default_timezone_get());
@@ -327,9 +411,17 @@ class Cdav extends Controller {
$vcalendar->VEVENT->DTSTART['TZID'] = $tz;
$calendarData = $vcalendar->serialize();
$caldavBackend->createCalendarObject($id, $objectUri, $calendarData);
build_sync_packet($channel['channel_id'], [
'calendar' => [
'action' => 'import',
'uri' => $cdavdata['uri'],
'ids' => [ $objectUri ],
'card' => $calendarData
]
]);
killme();
}
@@ -341,17 +433,24 @@ class Cdav extends Controller {
if(! cdav_perms($id[0],$calendars))
return;
$cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
$mutations = [
'{DAV:}displayname' => $_REQUEST['{DAV:}displayname'],
'{http://apple.com/ns/ical/}calendar-color' => $_REQUEST['color']
];
$patch = new \Sabre\DAV\PropPatch($mutations);
$caldavBackend->updateCalendar($id, $patch);
$patch->commit();
build_sync_packet($channel['channel_id'], [
'calendar' => [
'action' => 'edit',
'uri' => $cdavdata['uri'],
'mutations' => $mutations,
]
]);
}
//edit calendar object via ajax request
@@ -359,9 +458,11 @@ class Cdav extends Controller {
$id = explode(':', $_REQUEST['target']);
if(!cdav_perms($id[0],$calendars,true))
if(! cdav_perms($id[0],$calendars,true))
return;
$cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
$timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
$tz = (($timezone) ? $timezone : date_default_timezone_get());
@@ -407,9 +508,17 @@ class Cdav extends Controller {
$vcalendar->VEVENT->LOCATION = $location;
$calendarData = $vcalendar->serialize();
$caldavBackend->updateCalendarObject($id, $uri, $calendarData);
build_sync_packet($channel['channel_id'], [
'calendar' => [
'action' => 'update_card',
'uri' => $cdavdata['uri'],
'carduri' => $uri,
'card' => $calendarData
]
]);
killme();
}
@@ -418,13 +527,23 @@ class Cdav extends Controller {
$id = explode(':', $_REQUEST['target']);
if(!cdav_perms($id[0],$calendars,true))
if(! cdav_perms($id[0],$calendars,true))
return;
$cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
$uri = $_REQUEST['uri'];
$caldavBackend->deleteCalendarObject($id, $uri);
build_sync_packet($channel['channel_id'], [
'calendar' => [
'action' => 'delete_card',
'uri' => $cdavdata['uri'],
'carduri' => $uri
]
]);
killme();
}
@@ -433,9 +552,11 @@ class Cdav extends Controller {
$id = [$_REQUEST['id'][0], $_REQUEST['id'][1]];
if(!cdav_perms($id[0],$calendars,true))
if(! cdav_perms($id[0],$calendars,true))
return;
$cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
$timezone = ((x($_POST,'timezone_select')) ? escape_tags(trim($_POST['timezone_select'])) : '');
$tz = (($timezone) ? $timezone : date_default_timezone_get());
@@ -471,9 +592,17 @@ class Cdav extends Controller {
unset($vcalendar->VEVENT->DTEND);
$calendarData = $vcalendar->serialize();
$caldavBackend->updateCalendarObject($id, $uri, $calendarData);
build_sync_packet($channel['channel_id'], [
'calendar' => [
'action' => 'update_card',
'uri' => $cdavdata['uri'],
'carduri' => $uri,
'card' => $calendarData
]
]);
killme();
}
@@ -523,6 +652,14 @@ class Cdav extends Controller {
$properties = ['{DAV:}displayname' => $_REQUEST['{DAV:}displayname']];
$carddavBackend->createAddressBook($principalUri, $addressbookUri, $properties);
build_sync_packet($channel['channel_id'], [
'addressbook' => [
'action' => 'create',
'uri' => $addressbookUri,
'properties' => $properties
]
]);
}
//edit addressbook
@@ -533,21 +670,32 @@ class Cdav extends Controller {
if(! cdav_perms($id,$addressbooks))
return;
$cdavdata = $this->get_cdav_data($id, 'addressbooks');
$mutations = [
'{DAV:}displayname' => $_REQUEST['{DAV:}displayname']
];
$patch = new \Sabre\DAV\PropPatch($mutations);
$carddavBackend->updateAddressBook($id, $patch);
$patch->commit();
build_sync_packet($channel['channel_id'], [
'addressbook' => [
'action' => 'edit',
'uri' => $cdavdata['uri'],
'mutations' => $mutations,
]
]);
}
//create addressbook card
if($_REQUEST['create'] && $_REQUEST['target'] && $_REQUEST['fn']) {
$id = $_REQUEST['target'];
$cdavdata = $this->get_cdav_data($id, 'addressbooks');
do {
$duplicate = false;
$uri = random_string(40) . '.vcf';
@@ -569,86 +717,21 @@ class Cdav extends Controller {
'N' => array_reverse(explode(' ', $fn))
]);
$org = $_REQUEST['org'];
if($org) {
$vcard->ORG = $org;
}
$fields = $this->request_to_array($_REQUEST);
$title = $_REQUEST['title'];
if($title) {
$vcard->TITLE = $title;
}
$tel = $_REQUEST['tel'];
$tel_type = $_REQUEST['tel_type'];
if($tel) {
$i = 0;
foreach($tel as $item) {
if($item) {
$vcard->add('TEL', $item, ['type' => $tel_type[$i]]);
}
$i++;
}
}
$email = $_REQUEST['email'];
$email_type = $_REQUEST['email_type'];
if($email) {
$i = 0;
foreach($email as $item) {
if($item) {
$vcard->add('EMAIL', $item, ['type' => $email_type[$i]]);
}
$i++;
}
}
$impp = $_REQUEST['impp'];
$impp_type = $_REQUEST['impp_type'];
if($impp) {
$i = 0;
foreach($impp as $item) {
if($item) {
$vcard->add('IMPP', $item, ['type' => $impp_type[$i]]);
}
$i++;
}
}
$url = $_REQUEST['url'];
$url_type = $_REQUEST['url_type'];
if($url) {
$i = 0;
foreach($url as $item) {
if($item) {
$vcard->add('URL', $item, ['type' => $url_type[$i]]);
}
$i++;
}
}
$adr = $_REQUEST['adr'];
$adr_type = $_REQUEST['adr_type'];
if($adr) {
$i = 0;
foreach($adr as $item) {
if($item) {
$vcard->add('ADR', $item, ['type' => $adr_type[$i]]);
}
$i++;
}
}
$note = $_REQUEST['note'];
if($note) {
$vcard->NOTE = $note;
}
process_cdav_card($fields, $vcard);
$cardData = $vcard->serialize();
$carddavBackend->createCard($id, $uri, $cardData);
build_sync_packet($channel['channel_id'], [
'addressbook' => [
'action' => 'import',
'uri' => $cdavdata['uri'],
'ids' => [ $uri ],
'card' => $cardData
]
]);
}
//edit addressbook card
@@ -656,9 +739,11 @@ class Cdav extends Controller {
$id = $_REQUEST['target'];
if(!cdav_perms($id,$addressbooks))
if(! cdav_perms($id,$addressbooks))
return;
$cdavdata = $this->get_cdav_data($id, 'addressbooks');
$uri = $_REQUEST['uri'];
$object = $carddavBackend->getCard($id, $uri);
@@ -670,113 +755,23 @@ class Cdav extends Controller {
$vcard->N = array_reverse(explode(' ', $fn));
}
$org = $_REQUEST['org'];
if($org) {
$vcard->ORG = $org;
}
else {
unset($vcard->ORG);
}
$fields = $this->request_to_array($_REQUEST);
$title = $_REQUEST['title'];
if($title) {
$vcard->TITLE = $title;
}
else {
unset($vcard->TITLE);
}
$tel = $_REQUEST['tel'];
$tel_type = $_REQUEST['tel_type'];
if($tel) {
$i = 0;
unset($vcard->TEL);
foreach($tel as $item) {
if($item) {
$vcard->add('TEL', $item, ['type' => $tel_type[$i]]);
}
$i++;
}
}
else {
unset($vcard->TEL);
}
$email = $_REQUEST['email'];
$email_type = $_REQUEST['email_type'];
if($email) {
$i = 0;
unset($vcard->EMAIL);
foreach($email as $item) {
if($item) {
$vcard->add('EMAIL', $item, ['type' => $email_type[$i]]);
}
$i++;
}
}
else {
unset($vcard->EMAIL);
}
$impp = $_REQUEST['impp'];
$impp_type = $_REQUEST['impp_type'];
if($impp) {
$i = 0;
unset($vcard->IMPP);
foreach($impp as $item) {
if($item) {
$vcard->add('IMPP', $item, ['type' => $impp_type[$i]]);
}
$i++;
}
}
else {
unset($vcard->IMPP);
}
$url = $_REQUEST['url'];
$url_type = $_REQUEST['url_type'];
if($url) {
$i = 0;
unset($vcard->URL);
foreach($url as $item) {
if($item) {
$vcard->add('URL', $item, ['type' => $url_type[$i]]);
}
$i++;
}
}
else {
unset($vcard->URL);
}
$adr = $_REQUEST['adr'];
$adr_type = $_REQUEST['adr_type'];
if($adr) {
$i = 0;
unset($vcard->ADR);
foreach($adr as $item) {
if($item) {
$vcard->add('ADR', $item, ['type' => $adr_type[$i]]);
}
$i++;
}
}
else {
unset($vcard->ADR);
}
$note = $_REQUEST['note'];
if($note) {
$vcard->NOTE = $note;
}
else {
unset($vcard->NOTE);
}
process_cdav_card($fields, $vcard, true);
$cardData = $vcard->serialize();
$carddavBackend->updateCard($id, $uri, $cardData);
build_sync_packet($channel['channel_id'], [
'addressbook' => [
'action' => 'update_card',
'uri' => $cdavdata['uri'],
'carduri' => $uri,
'card' => $cardData
]
]);
}
//delete addressbook card
@@ -784,12 +779,22 @@ class Cdav extends Controller {
$id = $_REQUEST['target'];
if(!cdav_perms($id,$addressbooks))
if(! cdav_perms($id,$addressbooks))
return;
$cdavdata = $this->get_cdav_data($id, 'addressbooks');
$uri = $_REQUEST['uri'];
$carddavBackend->deleteCard($id, $uri);
build_sync_packet($channel['channel_id'], [
'addressbook' => [
'action' => 'delete_card',
'uri' => $cdavdata['uri'],
'carduri' => $uri
]
]);
}
}
@@ -799,6 +804,8 @@ class Cdav extends Controller {
$src = $_FILES['userfile']['tmp_name'];
if($src) {
$carddata = @file_get_contents($src);
if($_REQUEST['c_upload']) {
if($_REQUEST['target'] == 'channel_calendar') {
@@ -812,76 +819,42 @@ class Cdav extends Controller {
return;
}
$id = explode(':', $_REQUEST['target']);
$id = explode(':', $_REQUEST['target'])[0];
$ext = 'ics';
$table = 'calendarobjects';
$column = 'calendarid';
$objects = new \Sabre\VObject\Splitter\ICalendar(@file_get_contents($src));
$sync = 'calendar';
$objects = new \Sabre\VObject\Splitter\ICalendar($carddata);
$profile = \Sabre\VObject\Node::PROFILE_CALDAV;
$backend = new \Sabre\CalDAV\Backend\PDO($pdo);
$cdavdata = $this->get_cdav_data($id, 'calendarinstances');
}
if($_REQUEST['a_upload']) {
$id[] = intval($_REQUEST['target']);
$id = intval($_REQUEST['target']);
$ext = 'vcf';
$table = 'cards';
$column = 'addressbookid';
$objects = new \Sabre\VObject\Splitter\VCard(@file_get_contents($src));
$sync = 'addressbook';
$objects = new \Sabre\VObject\Splitter\VCard($carddata);
$profile = \Sabre\VObject\Node::PROFILE_CARDDAV;
$backend = new \Sabre\CardDAV\Backend\PDO($pdo);
$cdavdata = $this->get_cdav_data($id, 'addressbooks');
}
while ($object = $objects->getNext()) {
if($_REQUEST['a_upload']) {
$object = $object->convert(\Sabre\VObject\Document::VCARD40);
}
$ret = $object->validate($profile & \Sabre\VObject\Node::REPAIR);
//level 3 Means that the document is invalid,
//level 2 means a warning. A warning means it's valid but it could cause interopability issues,
//level 1 means that there was a problem earlier, but the problem was automatically repaired.
if($ret[0]['level'] < 3) {
do {
$duplicate = false;
$objectUri = random_string(40) . '.' . $ext;
$r = q("SELECT uri FROM $table WHERE $column = %d AND uri = '%s' LIMIT 1",
dbesc($id[0]),
dbesc($objectUri)
);
if (count($r))
$duplicate = true;
} while ($duplicate == true);
if($_REQUEST['c_upload']) {
$backend->createCalendarObject($id, $objectUri, $object->serialize());
}
if($_REQUEST['a_upload']) {
$backend->createCard($id[0], $objectUri, $object->serialize());
}
}
else {
if($_REQUEST['c_upload']) {
notice( '<strong>' . t('INVALID EVENT DISMISSED!') . '</strong>' . EOL .
'<strong>' . t('Summary: ') . '</strong>' . (($object->VEVENT->SUMMARY) ? $object->VEVENT->SUMMARY : t('Unknown')) . EOL .
'<strong>' . t('Date: ') . '</strong>' . (($object->VEVENT->DTSTART) ? $object->VEVENT->DTSTART : t('Unknown')) . EOL .
'<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL
);
}
if($_REQUEST['a_upload']) {
notice( '<strong>' . t('INVALID CARD DISMISSED!') . '</strong>' . EOL .
'<strong>' . t('Name: ') . '</strong>' . (($object->FN) ? $object->FN : t('Unknown')) . EOL .
'<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL
);
}
}
}
$ids = [];
import_cdav_card($id, $ext, $table, $column, $objects, $profile, $backend, $ids, true);
build_sync_packet($channel['channel_id'], [
$sync => [
'action' => 'import',
'uri' => $cdavdata['uri'],
'ids' => $ids,
'card' => $carddata
]
]);
}
@unlink($src);
}
@@ -910,8 +883,6 @@ class Cdav extends Controller {
require_once 'vendor/autoload.php';
head_add_css('cdav.css');
if(!cdav_principal($principalUri)) {
$this->activate($pdo, $channel);
if(!cdav_principal($principalUri)) {
@@ -1192,7 +1163,18 @@ class Cdav extends Controller {
if(! cdav_perms($id,$calendars))
killme();
set_pconfig(local_channel(), 'cdav_calendar' , argv(3), argv(4));
$cdavdata = $this->get_cdav_data($id, 'calendarinstances');
set_pconfig(local_channel(), 'cdav_calendar', $id, argv(4));
build_sync_packet(local_channel(), [
'calendar' => [
'action' => 'switch',
'uri' => $cdavdata['uri'],
'switch' => intval(argv(4))
]
]);
killme();
}
@@ -1203,7 +1185,18 @@ class Cdav extends Controller {
if(! cdav_perms($id[0],$calendars))
killme();
// get metadata before we delete it
$cdavdata = $this->get_cdav_data($id[0], 'calendarinstances');
$caldavBackend->deleteCalendar($id);
build_sync_packet($channel['channel_id'], [
'calendar' => [
'action' => 'drop',
'uri' => $cdavdata['uri']
]
]);
killme();
}
@@ -1410,7 +1403,19 @@ class Cdav extends Controller {
if(! cdav_perms($id,$addressbooks))
return;
// get metadata before we delete it
$cdavdata = $this->get_cdav_data($id, 'addressbooks');
$carddavBackend->deleteAddressBook($id);
if($cdavdata)
build_sync_packet($channel['channel_id'], [
'addressbook' => [
'action' => 'drop',
'uri' => $cdavdata['uri']
]
]);
killme();
}
@@ -1462,4 +1467,36 @@ class Cdav extends Controller {
}
function get_cdav_data($id, $table) {
$r = q("SELECT * FROM $table WHERE id = %d LIMIT 1",
intval($id)
);
if(! $r)
return false;
return $r[0];
}
function request_to_array($req) {
$f = [];
$f['org'] = $req['org'];
$f['title'] = $req['title'];
$f['tel'] = $req['tel'];
$f['tel_type'] = $req['tel_type'];
$f['email'] = $req['email'];
$f['email_type'] = $req['email_type'];
$f['impp'] = $req['impp'];
$f['impp_type'] = $req['impp_type'];
$f['url'] = $req['url'];
$f['url_type'] = $req['url_type'];
$f['adr'] = $req['adr'];
$f['adr_type'] = $req['adr_type'];
$f['note'] = $req['note'];
return $f;
}
}

View File

@@ -13,6 +13,7 @@ require_once('include/items.php');
require_once('include/security.php');
require_once('include/conversation.php');
require_once('include/acl_selectors.php');
require_once('include/opengraph.php');
/**
@@ -109,19 +110,20 @@ class Channel extends Controller {
// Run profile_load() here to make sure the theme is set before
// we start loading content
profile_load($which,$profile);
App::$page['htmlhead'] .= '<meta property="og:title" content="' . htmlspecialchars($channel['channel_name']) . '">' . "\r\n";
App::$page['htmlhead'] .= '<meta property="og:image" content="' . $channel['xchan_photo_l'] . '">' . "\r\n";
if(App::$profile['about'] && perm_is_allowed($channel['channel_id'],get_observer_hash(),'view_profile')) {
App::$page['htmlhead'] .= '<meta property="og:description" content="' . htmlspecialchars(App::$profile['about']) . '">' . "\r\n";
}
else {
App::$page['htmlhead'] .= '<meta property="og:description" content="' . htmlspecialchars(sprintf( t('This is the home page of %s.'), $channel['channel_name'])) . '">' . "\r\n";
}
// Add Opengraph markup
$mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : '');
if(strpos($mid,'b64.') === 0)
$mid = @base64url_decode(substr($mid,4));
if($mid)
$r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d AND item_private = 0 LIMIT 1",
dbesc($mid),
intval($channel['channel_id'])
);
opengraph_add_meta($r ? $r[0] : [], $channel);
}
function get($update = 0, $load = false) {
@@ -362,7 +364,7 @@ class Channel extends Controller {
$parents_str = ids_to_querystr($r,'item_id');
$items = q("SELECT item.*, item.id AS item_id
$r = q("SELECT item.*, item.id AS item_id
FROM item
WHERE item.uid = %d $item_normal
AND item.parent IN ( %s )
@@ -371,8 +373,8 @@ class Channel extends Controller {
dbesc($parents_str)
);
xchan_query($items);
$items = fetch_post_tags($items, true);
xchan_query($r);
$items = fetch_post_tags($r, true);
$items = conv_sort($items,$ordering);
if($load && $mid && (! count($items))) {
@@ -417,6 +419,7 @@ class Channel extends Controller {
'$nouveau' => '0',
'$wall' => '1',
'$fh' => '0',
'$dm' => '0',
'$static' => $static,
'$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1),
'$search' => $search,
@@ -466,6 +469,13 @@ class Channel extends Controller {
);
}
}
// 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');

View File

@@ -35,13 +35,6 @@ class Cloud extends \Zotlabs\Web\Controller {
if (argc() > 1)
$which = argv(1);
if (argc() < 2 && intval(get_config('system','cloud_disable_siteroot'))) {
notice( t('Permission denied.') . EOL);
construct_page();
killme();
}
$profile = 0;
if ($which)

View File

@@ -283,6 +283,28 @@ class Connections extends \Zotlabs\Web\Controller {
if(! intval(get_abconfig(local_channel(),$rr['xchan_hash'],'their_perms','post_comments'))) {
$oneway = true;
}
$perminfo['connpermcount']=0;
$perminfo['connperms']=t('Accepts').': ';
if(intval(get_abconfig(local_channel(),$rr['xchan_hash'],'their_perms','post_comments'))) {
$perminfo['connpermcount']++;
$perminfo['connperms'] .= t('Comments');
}
if(intval(get_abconfig(local_channel(),$rr['xchan_hash'],'their_perms','send_stream'))) {
$perminfo['connpermcount']++;
$perminfo['connperms'] = ($perminfo['connperms']) ? $perminfo['connperms'] . ', ' : $perminfo['connperms'] ;
$perminfo['connperms'] .= t('Stream items');
}
if(intval(get_abconfig(local_channel(),$rr['xchan_hash'],'their_perms','post_wall'))) {
$perminfo['connpermcount']++;
$perminfo['connperms'] = ($perminfo['connperms']) ? $perminfo['connperms'] . ', ' : $perminfo['connperms'] ;
$perminfo['connperms'] .= t('Wall posts');
}
if ($perminfo['connpermcount'] == 0) {
$perminfo['connperms'] .= t('Nothing');
}
foreach($status as $str) {
if(!$str)
@@ -322,7 +344,11 @@ class Connections extends \Zotlabs\Web\Controller {
'ignore' => ((! $rr['abook_ignored']) ? t('Ignore') : false),
'recent_label' => t('Recent activity'),
'recentlink' => z_root() . '/network/?f=&cid=' . intval($rr['abook_id']) . '&name=' . $rr['xchan_name'],
'oneway' => $oneway
'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')
);
}
}

View File

@@ -95,6 +95,8 @@ class Dav extends \Zotlabs\Web\Controller {
$auth = new \Zotlabs\Storage\BasicAuth();
$auth->observer = get_observer_hash();
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV');
$rootDirectory = new \Zotlabs\Storage\Directory('/', $auth);

View File

@@ -0,0 +1,52 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
class Dircensor extends Controller {
function get() {
if(! is_site_admin()) {
return;
}
$dirmode = intval(get_config('system','directory_mode'));
if (! ($dirmode == DIRECTORY_MODE_PRIMARY || $dirmode == DIRECTORY_MODE_STANDALONE)) {
return;
}
$xchan = argv(1);
if(! $xchan) {
return;
}
$r = q("select * from xchan where xchan_hash = '%s'",
dbesc($xchan)
);
if(! $r) {
return;
}
$val = (($r[0]['xchan_censored']) ? 0 : 1);
q("update xchan set xchan_censored = $val where xchan_hash = '%s'",
dbesc($xchan)
);
if($val) {
info( t('Entry censored') . EOL);
}
else {
info( t('Entry uncensored') . EOL);
}
goaway(z_root() . '/directory');
}
}

View File

@@ -2,15 +2,19 @@
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
require_once('include/socgraph.php');
require_once('include/dir_fns.php');
require_once('include/bbcode.php');
require_once('include/html2plain.php');
class Directory extends \Zotlabs\Web\Controller {
class Directory extends Controller {
function init() {
\App::set_pager_itemspage(60);
App::set_pager_itemspage(60);
if(local_channel() && x($_GET,'ignore')) {
q("insert into xign ( uid, xchan ) values ( %d, '%s' ) ",
@@ -21,7 +25,7 @@ class Directory extends \Zotlabs\Web\Controller {
}
if(local_channel())
\App::$profile_uid = local_channel();
App::$profile_uid = local_channel();
$observer = get_observer_hash();
$global_changed = false;
@@ -140,9 +144,15 @@ class Directory extends \Zotlabs\Web\Controller {
$dirmode = intval(get_config('system','directory_mode'));
$directory_admin = false;
if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) {
$url = z_root() . '/dirsearch';
}
if (is_site_admin()) {
$directory_admin = true;
}
}
if(! $url) {
$directory = find_upstream_directory($dirmode);
if((! $directory) || (! array_key_exists('url',$directory)) || (! $directory['url']))
@@ -182,7 +192,7 @@ class Directory extends \Zotlabs\Web\Controller {
$query .= '&t=' . $token;
if(! $globaldir)
$query .= '&hub=' . \App::get_hostname();
$query .= '&hub=' . App::get_hostname();
if($search)
$query .= '&name=' . urlencode($search) . '&keywords=' . urlencode($search);
@@ -204,8 +214,8 @@ class Directory extends \Zotlabs\Web\Controller {
if($sort_order)
$query .= '&order=' . urlencode($sort_order);
if(\App::$pager['page'] != 1)
$query .= '&p=' . \App::$pager['page'];
if(App::$pager['page'] != 1)
$query .= '&p=' . App::$pager['page'];
logger('mod_directory: query: ' . $query);
@@ -283,12 +293,15 @@ class Directory extends \Zotlabs\Web\Controller {
$marital = ((x($profile,'marital') == 1) ? t('Status: ') . $profile['marital']: False);
$homepage = ((x($profile,'homepage') == 1) ? t('Homepage: ') : False);
$homepageurl = ((x($profile,'homepage') == 1) ? $profile['homepage'] : '');
$homepageurl = ((x($profile,'homepage') == 1) ? html2plain($profile['homepage']) : '');
$hometown = ((x($profile,'hometown') == 1) ? $profile['hometown'] : False);
$about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'])) : False);
$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);
}
$keywords = ((x($profile,'keywords')) ? $profile['keywords'] : '');
@@ -343,9 +356,11 @@ class Directory extends \Zotlabs\Web\Controller {
'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')),
'marital' => $marital,
'homepage' => $homepage,
'homepageurl' => linkify($homepageurl),
'homepageurl' => (($safe_mode) ? $homepageurl : linkify($homepageurl)),
'hometown' => $hometown,
'hometown_label' => t('Hometown:'),
'about' => $about,
@@ -387,7 +402,7 @@ class Directory extends \Zotlabs\Web\Controller {
ksort($entries); // Sort array by key so that foreach-constructs work as expected
if($j['keywords']) {
\App::$data['directory_keywords'] = $j['keywords'];
App::$data['directory_keywords'] = $j['keywords'];
}
logger('mod_directory: entries: ' . print_r($entries,true), LOGGER_DATA);
@@ -438,7 +453,7 @@ class Directory extends \Zotlabs\Web\Controller {
echo $o;
killme();
}
if(\App::$pager['page'] == 1 && $j['records'] == 0 && strpos($search,'@')) {
if(App::$pager['page'] == 1 && $j['records'] == 0 && strpos($search,'@')) {
goaway(z_root() . '/chanview/?f=&address=' . $search);
}
info( t("No entries (some entries may be hidden).") . EOL);

View File

@@ -1,14 +1,17 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
require_once('include/dir_fns.php');
class Dirsearch extends \Zotlabs\Web\Controller {
class Dirsearch extends Controller {
function init() {
\App::set_pager_itemspage(60);
App::set_pager_itemspage(60);
}
@@ -25,7 +28,8 @@ class Dirsearch extends \Zotlabs\Web\Controller {
$ret['message'] = t('This site is not a directory server');
json_return_and_die($ret);
}
$access_token = $_REQUEST['t'];
$token = get_config('system','realm_token');
@@ -286,29 +290,29 @@ class Dirsearch extends \Zotlabs\Web\Controller {
else
$entry['total_ratings'] = 0;
$entry['name'] = $rr['xchan_name'];
$entry['hash'] = $rr['xchan_hash'];
$entry['name'] = $rr['xchan_name'];
$entry['hash'] = $rr['xchan_hash'];
$entry['censored'] = $rr['xchan_censored'];
$entry['selfcensored'] = $rr['xchan_selfcensored'];
$entry['public_forum'] = (intval($rr['xchan_pubforum']) ? true : false);
$entry['url'] = $rr['xchan_url'];
$entry['photo_l'] = $rr['xchan_photo_l'];
$entry['photo'] = $rr['xchan_photo_m'];
$entry['address'] = $rr['xchan_addr'];
$entry['description'] = $rr['xprof_desc'];
$entry['locale'] = $rr['xprof_locale'];
$entry['region'] = $rr['xprof_region'];
$entry['postcode'] = $rr['xprof_postcode'];
$entry['country'] = $rr['xprof_country'];
$entry['birthday'] = $rr['xprof_dob'];
$entry['age'] = $rr['xprof_age'];
$entry['gender'] = $rr['xprof_gender'];
$entry['marital'] = $rr['xprof_marital'];
$entry['sexual'] = $rr['xprof_sexual'];
$entry['about'] = $rr['xprof_about'];
$entry['homepage'] = $rr['xprof_homepage'];
$entry['hometown'] = $rr['xprof_hometown'];
$entry['keywords'] = $rr['xprof_keywords'];
$entry['url'] = $rr['xchan_url'];
$entry['photo_l'] = $rr['xchan_photo_l'];
$entry['photo'] = $rr['xchan_photo_m'];
$entry['address'] = $rr['xchan_addr'];
$entry['description'] = $rr['xprof_desc'];
$entry['locale'] = $rr['xprof_locale'];
$entry['region'] = $rr['xprof_region'];
$entry['postcode'] = $rr['xprof_postcode'];
$entry['country'] = $rr['xprof_country'];
$entry['birthday'] = $rr['xprof_dob'];
$entry['age'] = $rr['xprof_age'];
$entry['gender'] = $rr['xprof_gender'];
$entry['marital'] = $rr['xprof_marital'];
$entry['sexual'] = $rr['xprof_sexual'];
$entry['about'] = $rr['xprof_about'];
$entry['homepage'] = $rr['xprof_homepage'];
$entry['hometown'] = $rr['xprof_hometown'];
$entry['keywords'] = $rr['xprof_keywords'];
$entries[] = $entry;

View File

@@ -200,7 +200,8 @@ class Display extends \Zotlabs\Web\Controller {
// if the target item is not a post (eg a like) we want to address its thread parent
$mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
//$mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
$mid = $target_item['mid'];
// if we got a decoded hash we must encode it again before handing to javascript
if($decoded)
@@ -223,6 +224,7 @@ class Display extends \Zotlabs\Web\Controller {
'$conv' => '0',
'$spam' => '0',
'$fh' => '0',
'$dm' => '0',
'$nouveau' => '0',
'$wall' => '0',
'$static' => $static,

View File

@@ -68,6 +68,8 @@ class Embedphotos extends \Zotlabs\Web\Controller {
$ext = '.png';
elseif($r[0]['mimetype'] === 'image/gif')
$ext = '.gif';
elseif($r[0]['mimetype'] === 'image/webp')
$exp = '.webp';
else
$ext = EMPTY_STR;

76
Zotlabs/Module/Event.php Normal file
View File

@@ -0,0 +1,76 @@
<?php
namespace Zotlabs\Module;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\LDSignatures;
use Zotlabs\Web\HTTPSig;
class Event extends Controller {
function init() {
if(ActivityStreams::is_as_request()) {
$item_id = argv(1);
if(! $item_id)
return;
$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 ";
$sql_extra = item_permissions_sql(0);
$r = q("select * from item where mid like '%s' $item_normal $sql_extra limit 1",
dbesc(z_root() . '/activity/' . $item_id . '%')
);
if(! $r) {
$r = q("select * from item where mid like '%s' $item_normal limit 1",
dbesc(z_root() . '/activity/' . $item_id . '%')
);
if($r) {
http_status_exit(403, 'Forbidden');
}
http_status_exit(404, 'Not found');
}
xchan_query($r,true);
$items = fetch_post_tags($r,true);
$channel = channelx_by_n($items[0]['uid']);
if(! is_array($items[0]['obj'])) {
$obj = json_decode($items[0]['obj'],true);
}
else {
$obj = $items[0]['obj'];
}
$x = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], $obj );
$headers = [];
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
$x['signature'] = LDSignatures::sign($x,$channel);
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
$headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T');
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel));
HTTPSig::set_headers($h);
echo $ret;
killme();
}
}
}

View File

@@ -66,7 +66,10 @@ class Help extends \Zotlabs\Web\Controller {
case IMAGETYPE_PNG:
header("Content-Type: image/png");
break;
default:
case IMAGETYPE_WEBP:
header("Content-Type: image/webp");
break;
default:
break;
}
header("Content-Length: " . filesize($realpath));

View File

@@ -152,8 +152,8 @@ class Hq extends \Zotlabs\Web\Controller {
if($target_item) {
// if the target item is not a post (eg a like) we want to address its thread parent
$mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
//$mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
$mid = $target_item['mid'];
// if we got a decoded hash we must encode it again before handing to javascript
if($decoded)
$mid = 'b64.' . base64url_encode($mid);
@@ -179,6 +179,7 @@ class Hq extends \Zotlabs\Web\Controller {
'$conv' => '0',
'$spam' => '0',
'$fh' => '0',
'$dm' => '0',
'$nouveau' => '0',
'$wall' => '0',
'$static' => $static,

View File

@@ -42,8 +42,6 @@ class Item extends Controller {
if (Libzot::is_zot_request()) {
$conversation = false;
$item_id = argv(1);
if (! $item_id)
@@ -273,7 +271,9 @@ class Item extends Controller {
$consensus = intval($_REQUEST['consensus']);
$nocomment = intval($_REQUEST['nocomment']);
$is_poll = ((trim($_REQUEST['poll_answers'][0]) != '' && trim($_REQUEST['poll_answers'][1]) != '') ? true : false);
// 'origin' (if non-zero) indicates that this network is where the message originated,
// for the purpose of relaying comments to other conversation members.
// If using the API from a device (leaf node) you must set origin to 1 (default) or leave unset.
@@ -720,7 +720,6 @@ class Item extends Controller {
// BBCODE alert: the following functions assume bbcode input
// and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.)
// we may need virtual or template classes to implement the possible alternatives
if(strpos($body,'[/summary]') !== false) {
$match = '';
@@ -817,11 +816,6 @@ class Item extends Controller {
'revision' => $r['data']['revision']
);
}
$ext = substr($r['data']['filename'],strrpos($r['data']['filename'],'.'));
if(strpos($r['data']['filetype'],'audio/') !== false)
$attach_link = '[audio]' . z_root() . '/attach/' . $r['data']['hash'] . '/' . $r['data']['revision'] . (($ext) ? $ext : '') . '[/audio]';
elseif(strpos($r['data']['filetype'],'video/') !== false)
$attach_link = '[video]' . z_root() . '/attach/' . $r['data']['hash'] . '/' . $r['data']['revision'] . (($ext) ? $ext : '') . '[/video]';
$body = str_replace($match[1][$i],$attach_link,$body);
$i++;
}
@@ -929,6 +923,27 @@ class Item extends Controller {
}
if($is_poll) {
$poll = [
'question' => $body,
'answers' => $_REQUEST['poll_answers'],
'multiple_answers' => $_REQUEST['poll_multiple_answers'],
'expire_value' => $_REQUEST['poll_expire_value'],
'expire_unit' => $_REQUEST['poll_expire_unit']
];
$obj = $this->extract_poll_data($poll, [ 'item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny ]);
}
else {
$obj = $this->extract_bb_poll_data($body,[ 'item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny ]);
}
if ($obj) {
$obj['url'] = $mid;
$obj['attributedTo'] = channel_url($channel);
$datarray['obj'] = $obj;
$obj_type = 'Question';
}
if(! $parent_mid) {
$parent_mid = $mid;
}
@@ -977,7 +992,11 @@ class Item extends Controller {
$plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . gen_link_id($mid);
$plink = substr($plink,0,190);
}
if ($datarray['obj']) {
$datarray['obj']['id'] = $mid;
}
$datarray['aid'] = $channel['channel_account_id'];
$datarray['uid'] = $profile_uid;
$datarray['uuid'] = $uuid;
@@ -1232,13 +1251,7 @@ class Item extends Controller {
killme();
}
if(($parent) && ($parent != $post_id)) {
// Store the comment signature information in case we need to relay to Diaspora
//$ditem = $datarray;
//$ditem['author'] = $observer;
//store_diaspora_comment_sig($ditem,$channel,$parent_item, $post_id, (($walltowall_comment) ? 1 : 0));
}
else {
if(($parent == $post_id) || ($datarray['item_private'] == 1)) {
$r = q("select * from item where id = %d",
intval($post_id)
);
@@ -1400,5 +1413,104 @@ class Item extends Controller {
return $ret;
}
function extract_bb_poll_data(&$body,$item) {
$multiple = false;
if (strpos($body,'[/question]') === false && strpos($body,'[/answer]') === false) {
return false;
}
if (strpos($body,'[nobb]') !== false) {
return false;
}
$obj = [];
$ptr = [];
$matches = null;
$obj['type'] = 'Question';
if (preg_match_all('/\[answer\](.*?)\[\/answer\]/ism',$body,$matches,PREG_SET_ORDER)) {
foreach ($matches as $match) {
$ptr[] = [ 'name' => $match[1], 'type' => 'Note', 'replies' => [ 'type' => 'Collection', 'totalItems' => 0 ]];
$body = str_replace('[answer]' . $match[1] . '[/answer]', EMPTY_STR, $body);
}
}
$matches = null;
if (preg_match('/\[question\](.*?)\[\/question\]/ism',$body,$matches)) {
$obj['content'] = bbcode($matches[1]);
$body = str_replace('[question]' . $matches[1] . '[/question]', $matches[1], $body);
$obj['oneOf'] = $ptr;
}
$matches = null;
if (preg_match('/\[question=multiple\](.*?)\[\/question\]/ism',$body,$matches)) {
$obj['content'] = bbcode($matches[1]);
$body = str_replace('[question=multiple]' . $matches[1] . '[/question]', $matches[1], $body);
$obj['anyOf'] = $ptr;
}
$matches = null;
if (preg_match('/\[ends\](.*?)\[\/ends\]/ism',$body,$matches)) {
$obj['endTime'] = datetime_convert(date_default_timezone_get(),'UTC', $matches[1],ATOM_TIME);
$body = str_replace('[ends]' . $matches[1] . '[/ends]', EMPTY_STR, $body);
}
if ($item['item_private']) {
$obj['to'] = Activity::map_acl($item);
}
else {
$obj['to'] = [ ACTIVITY_PUBLIC_INBOX ];
}
return $obj;
}
function extract_poll_data($poll, $item) {
$multiple = intval($poll['multiple_answers']);
$expire_value = intval($poll['expire_value']);
$expire_unit = $poll['expire_unit'];
$question = $poll['question'];
$answers = $poll['answers'];
$obj = [];
$ptr = [];
$obj['type'] = 'Question';
$obj['content'] = bbcode($question);
foreach($answers as $answer) {
if(trim($answer))
$ptr[] = [ 'name' => escape_tags($answer), 'type' => 'Note', 'replies' => [ 'type' => 'Collection', 'totalItems' => 0 ]];
}
if($multiple) {
$obj['anyOf'] = $ptr;
}
else {
$obj['oneOf'] = $ptr;
}
$obj['endTime'] = datetime_convert(date_default_timezone_get(), 'UTC', 'now + ' . $expire_value . ' ' . $expire_unit, ATOM_TIME);
if ($item['item_private']) {
$obj['to'] = Activity::map_acl($item);
}
else {
$obj['to'] = [ ACTIVITY_PUBLIC_INBOX ];
}
return $obj;
}
}

View File

@@ -75,7 +75,12 @@ class Like extends \Zotlabs\Web\Controller {
return EMPTY_STR;
}
$is_rsvp = false;
if (in_array($activity, [ ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE ])) {
$is_rsvp = true;
}
$extended_like = false;
$object = $target = null;
$post_type = EMPTY_STR;
@@ -381,7 +386,7 @@ class Like extends \Zotlabs\Web\Controller {
$arr = array();
$arr['uuid'] = $uuid;
$arr['mid'] = z_root() . '/item/' . $uuid;
$arr['mid'] = z_root() . (($is_rsvp) ? '/activity/' : '/item/') . $uuid;
if($extended_like) {
$arr['item_thread_top'] = 1;

View File

@@ -1,449 +0,0 @@
<?php
namespace Zotlabs\Module;
require_once('include/acl_selectors.php');
require_once('include/message.php');
require_once('include/zot.php');
require_once("include/bbcode.php");
class Mail extends \Zotlabs\Web\Controller {
function post() {
if(! local_channel())
return;
$replyto = ((x($_REQUEST,'replyto')) ? notags(trim($_REQUEST['replyto'])) : '');
$subject = ((x($_REQUEST,'subject')) ? notags(trim($_REQUEST['subject'])) : '');
$body = ((x($_REQUEST,'body')) ? escape_tags(trim($_REQUEST['body'])) : '');
$recipient = ((x($_REQUEST,'messageto')) ? notags(trim(urldecode($_REQUEST['messageto']))) : '');
$rstr = ((x($_REQUEST,'messagerecip')) ? notags(trim($_REQUEST['messagerecip'])) : '');
$preview = ((x($_REQUEST,'preview')) ? intval($_REQUEST['preview']) : 0);
$expires = ((x($_REQUEST,'expires')) ? datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['expires']) : NULL_DATE);
$raw = ((x($_REQUEST,'raw')) ? intval($_REQUEST['raw']) : 0);
$mimetype = ((x($_REQUEST,'mimetype')) ? notags(trim($_REQUEST['mimetype'])) : 'text/bbcode');
$sig = ((x($_REQUEST,'signature')) ? trim($_REQUEST['signature']) : '');
if(strpos($sig,'b64.') === 0)
$sig = base64_decode(str_replace('b64.', '', $sig));
if($preview) {
if($raw) {
$body = mail_prepare_binary(['id' => 'M0']);
echo json_encode(['preview' => $body]);
}
else {
$body = cleanup_bbcode($body);
$results = linkify_tags($body, local_channel());
if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) {
$attachments = array();
foreach($match[2] as $mtch) {
$hash = substr($mtch,0,strpos($mtch,','));
$rev = intval(substr($mtch,strpos($mtch,',')));
$r = attach_by_hash_nodata($hash,get_observer_hash(),$rev);
if($r['success']) {
$attachments[] = array(
'href' => z_root() . '/attach/' . $r['data']['hash'],
'length' => $r['data']['filesize'],
'type' => $r['data']['filetype'],
'title' => urlencode($r['data']['filename']),
'revision' => $r['data']['revision']
);
}
$body = trim(str_replace($match[1],'',$body));
}
}
echo json_encode(['preview' => zidify_links(smilies(bbcode($body)))]);
}
killme();
}
// If we have a raw string for a recipient which hasn't been auto-filled,
// it means they probably aren't in our address book, hence we don't know
// if we have permission to send them private messages.
// finger them and find out before we try and send it.
if(! $recipient) {
$channel = \App::get_channel();
$j = \Zotlabs\Zot\Finger::run(punify($rstr),$channel);
if(! $j['success']) {
notice( t('Unable to lookup recipient.') . EOL);
return;
}
logger('message_post: lookup: ' . $rstr . ' ' . print_r($j,true));
if(! $j['guid']) {
notice( t('Unable to communicate with requested channel.'));
return;
}
$x = import_xchan($j);
if(! $x['success']) {
notice( t('Cannot verify requested channel.'));
return;
}
$recipient = $x['hash'];
$their_perms = 0;
if($j['permissions']['data']) {
$permissions = crypto_unencapsulate($j['permissions'],$channel['channel_prvkey']);
if($permissions)
$permissions = json_decode($permissions, true);
logger('decrypted permissions: ' . print_r($permissions,true), LOGGER_DATA);
}
else
$permissions = $j['permissions'];
if(! ($permissions['post_mail'])) {
notice( t('Selected channel has private message restrictions. Send failed.'));
// reported issue: let's still save the message and continue. We'll just tell them
// that nothing useful is likely to happen. They might have spent hours on it.
// return;
}
}
require_once('include/text.php');
linkify_tags($body, local_channel());
if(! $recipient) {
notice('No recipient found.');
\App::$argc = 2;
\App::$argv[1] = 'new';
return;
}
// We have a local_channel, let send_message use the session channel and save a lookup
$ret = send_message(0, $recipient, $body, $subject, $replyto, $expires, $mimetype, $raw, $sig);
if($ret['success']) {
xchan_mail_query($ret['mail']);
build_sync_packet(0,array('conv' => array($ret['conv']),'mail' => array(encode_mail($ret['mail'],true))));
}
else {
notice($ret['message']);
}
goaway(z_root() . '/mail/combined');
}
function get() {
$o = '';
nav_set_selected('Mail');
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
return login();
}
$channel = \App::get_channel();
head_set_icon($channel['xchan_photo_s']);
$cipher = get_pconfig(local_channel(),'system','default_cipher');
if(! $cipher)
$cipher = 'aes256';
$tpl = get_markup_template('mail_head.tpl');
$header = replace_macros($tpl, array(
'$header' => t('Messages'),
));
if(argc() == 3 && intval(argv(1)) && argv(2) === 'download') {
$r = q("select * from mail where id = %d and channel_id = %d",
intval(argv(1)),
intval(local_channel())
);
if($r) {
header('Content-type: ' . $r[0]['mail_mimetype']);
header('Content-disposition: attachment; filename="' . t('message') . '-' . $r[0]['id'] . '"' );
$body = (($r[0]['mail_obscured']) ? base64url_decode(str_rot47($r[0]['body'])) : $r[0]['body']);
echo $body;
killme();
}
}
if((argc() == 4) && (argv(2) === 'drop')) {
if(! intval(argv(3)))
return;
$cmd = argv(2);
$mailbox = argv(1);
$r = private_messages_drop(local_channel(), argv(3));
if($r) {
//info( t('Message deleted.') . EOL );
}
goaway(z_root() . '/mail/' . $mailbox);
}
if((argc() == 4) && (argv(2) === 'recall')) {
if(! intval(argv(3)))
return;
$cmd = argv(2);
$mailbox = argv(1);
$r = q("update mail set mail_recalled = 1 where id = %d and channel_id = %d",
intval(argv(3)),
intval(local_channel())
);
$x = q("select * from mail where id = %d and channel_id = %d",
intval(argv(3)),
intval(local_channel())
);
if($x) {
build_sync_packet(local_channel(),array('mail' => encode_mail($x[0],true)));
}
\Zotlabs\Daemon\Master::Summon(array('Notifier','mail',intval(argv(3))));
if($r) {
info( t('Message recalled.') . EOL );
}
goaway(z_root() . '/mail/' . $mailbox . '/' . argv(3));
}
if((argc() == 4) && (argv(2) === 'dropconv')) {
if(! intval(argv(3)))
return;
$cmd = argv(2);
$mailbox = argv(1);
$r = private_messages_drop(local_channel(), argv(3), true);
if($r)
info( t('Conversation removed.') . EOL );
goaway(z_root() . '/mail/' . $mailbox);
}
if((argc() > 1) && (argv(1) === 'new')) {
$plaintext = true;
$tpl = get_markup_template('msg-header.tpl');
$header = replace_macros($tpl, array(
'$baseurl' => z_root(),
'$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'),
'$nickname' => $channel['channel_address'],
'$linkurl' => t('Please enter a link URL:'),
'$expireswhen' => t('Expires YYYY-MM-DD HH:MM')
));
\App::$page['htmlhead'] .= $header;
$prename = '';
$preid = '';
if(x($_REQUEST,'hash')) {
$r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash
where abook_channel = %d and abook_xchan = '%s' limit 1",
intval(local_channel()),
dbesc($_REQUEST['hash'])
);
if(!$r) {
$r = q("select * from xchan where xchan_hash = '%s' and xchan_network = 'zot' limit 1",
dbesc($_REQUEST['hash'])
);
}
if($r) {
$prename = (($r[0]['abook_id']) ? $r[0]['xchan_name'] : $r[0]['xchan_addr']);
$preurl = $r[0]['xchan_url'];
$preid = (($r[0]['abook_id']) ? ($r[0]['xchan_hash']) : '');
}
else {
notice( t('Requested channel is not in this network') . EOL );
}
}
$tpl = get_markup_template('prv_message.tpl');
$o .= replace_macros($tpl,array(
'$new' => true,
'$header' => t('Send Private Message'),
'$to' => t('To:'),
'$prefill' => $prename,
'$preid' => $preid,
'$subject' => t('Subject:'),
'$subjtxt' => ((x($_REQUEST,'subject')) ? strip_tags($_REQUEST['subject']) : ''),
'$text' => ((x($_REQUEST,'body')) ? htmlspecialchars($_REQUEST['body'], ENT_COMPAT, 'UTF-8') : ''),
'$yourmessage' => t('Your message:'),
'$parent' => '',
'$attach' => t('Attach file'),
'$insert' => t('Insert web link'),
'$submit' => t('Send'),
'$defexpire' => '',
'$feature_expire' => ((feature_enabled(local_channel(),'content_expire')) ? true : false),
'$expires' => t('Set expiration date'),
'$feature_encrypt' => ((feature_enabled(local_channel(),'content_encrypt')) ? true : false),
'$encrypt' => t('Encrypt text'),
'$cipher' => $cipher,
));
return $o;
}
$direct_mid = 0;
switch(argv(1)) {
case 'combined':
$mailbox = 'combined';
break;
case 'inbox':
$mailbox = 'inbox';
break;
case 'outbox':
$mailbox = 'outbox';
break;
default:
$mailbox = 'combined';
// notifications direct to mail/nn
if(intval(argv(1)))
$direct_mid = intval(argv(1));
break;
}
$last_message = private_messages_list(local_channel(), $mailbox, 0, 1);
$mid = ((argc() > 2) && (intval(argv(2)))) ? argv(2) : $last_message[0]['id'];
if($direct_mid)
$mid = $direct_mid;
$plaintext = true;
// if( local_channel() && feature_enabled(local_channel(),'richtext') )
// $plaintext = false;
if($mailbox == 'combined') {
$messages = private_messages_fetch_conversation(local_channel(), $mid, true);
}
else {
$messages = private_messages_fetch_message(local_channel(), $mid, true);
}
if(! $messages) {
//info( t('Message not found.') . EOL);
return;
}
if($messages[0]['to_xchan'] === $channel['channel_hash'])
\App::$poi = $messages[0]['from'];
else
\App::$poi = $messages[0]['to'];
$tpl = get_markup_template('msg-header.tpl');
\App::$page['htmlhead'] .= replace_macros($tpl, array(
'$nickname' => $channel['channel_address'],
'$baseurl' => z_root(),
'$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'),
'$linkurl' => t('Please enter a link URL:'),
'$expireswhen' => t('Expires YYYY-MM-DD HH:MM')
));
$mails = array();
$seen = 0;
$unknown = false;
foreach($messages as $message) {
$s = theme_attachments($message);
if($message['mail_raw'])
$message['body'] = mail_prepare_binary([ 'id' => $message['id'] ]);
else
$message['body'] = zidify_links(smilies(bbcode($message['body'])));
$mails[] = array(
'mailbox' => $mailbox,
'id' => $message['id'],
'mid' => $message['mid'],
'from_name' => $message['from']['xchan_name'],
'from_url' => chanlink_hash($message['from_xchan']),
'from_photo' => $message['from']['xchan_photo_s'],
'to_name' => $message['to']['xchan_name'],
'to_url' => chanlink_hash($message['to_xchan']),
'to_photo' => $message['to']['xchan_photo_s'],
'subject' => $message['title'],
'body' => $message['body'],
'attachments' => $s,
'delete' => t('Delete message'),
'dreport' => t('Delivery report'),
'recall' => t('Recall message'),
'can_recall' => ($channel['channel_hash'] == $message['from_xchan']),
'is_recalled' => (intval($message['mail_recalled']) ? t('Message has been recalled.') : ''),
'date' => datetime_convert('UTC',date_default_timezone_get(),$message['created'], 'c'),
'sig' => base64_encode($message['sig'])
);
$seen = $message['seen'];
}
$recp = (($message['from_xchan'] === $channel['channel_hash']) ? 'to' : 'from');
$tpl = get_markup_template('mail_display.tpl');
$o = replace_macros($tpl, array(
'$mailbox' => $mailbox,
'$prvmsg_header' => $message['title'],
'$thread_id' => $mid,
'$thread_subject' => $message['title'],
'$thread_seen' => $seen,
'$delete' => t('Delete Conversation'),
'$canreply' => (($unknown) ? false : '1'),
'$unknown_text' => t("No secure communications available. You <strong>may</strong> be able to respond from the sender's profile page."),
'$mails' => $mails,
// reply
'$header' => t('Send Reply'),
'$to' => t('To:'),
'$reply' => true,
'$subject' => t('Subject:'),
'$subjtxt' => $message['title'],
'$yourmessage' => sprintf(t('Your message for %s (%s):'), $message[$recp]['xchan_name'], $message[$recp]['xchan_addr']),
'$text' => '',
'$parent' => $message['parent_mid'],
'$recphash' => $message[$recp]['xchan_hash'],
'$attach' => t('Attach file'),
'$insert' => t('Insert web link'),
'$submit' => t('Submit'),
'$defexpire' => '',
'$feature_expire' => ((feature_enabled(local_channel(),'content_expire')) ? true : false),
'$expires' => t('Set expiration date'),
'$feature_encrypt' => ((feature_enabled(local_channel(),'content_encrypt')) ? true : false),
'$encrypt' => t('Encrypt text'),
'$cipher' => $cipher,
));
return $o;
}
}

View File

@@ -54,9 +54,10 @@ class Menu extends \Zotlabs\Web\Controller {
if($_REQUEST['menu_system'])
$_REQUEST['menu_flags'] |= MENU_SYSTEM;
$menu_id = ((argc() > 1) ? intval(argv(1)) : 0);
$menu_id = ((argc() > 2) ? intval(argv(2)) : 0);
if($menu_id) {
$_REQUEST['menu_id'] = intval(argv(1));
$_REQUEST['menu_id'] = $menu_id;
$r = menu_edit($_REQUEST);
if($r) {
menu_sync_packet($uid,get_observer_hash(),$menu_id);

View File

@@ -69,6 +69,7 @@ class Network extends \Zotlabs\Web\Controller {
$category = ((x($_REQUEST,'cat')) ? $_REQUEST['cat'] : '');
$hashtags = ((x($_REQUEST,'tag')) ? $_REQUEST['tag'] : '');
$verb = ((x($_REQUEST,'verb')) ? $_REQUEST['verb'] : '');
$dm = ((x($_REQUEST,'dm')) ? $_REQUEST['dm'] : 0);
$order = get_pconfig(local_channel(), 'mod_network', 'order', 0);
@@ -339,7 +340,7 @@ class Network extends \Zotlabs\Web\Controller {
// The special div is needed for liveUpdate to kick in for this page.
// We only launch liveUpdate if you aren't filtering in some incompatible
// way and also you aren't writing a comment (discovered in javascript).
$maxheight = get_pconfig(local_channel(),'system','network_divmore_height');
if(! $maxheight)
$maxheight = 400;
@@ -363,6 +364,7 @@ class Network extends \Zotlabs\Web\Controller {
'$conv' => (($conv) ? $conv : '0'),
'$spam' => (($spam) ? $spam : '0'),
'$fh' => '0',
'$dm' => (($dm) ? $dm : '0'),
'$nouveau' => (($nouveau) ? $nouveau : '0'),
'$wall' => '0',
'$static' => $static,
@@ -409,15 +411,33 @@ class Network extends \Zotlabs\Web\Controller {
}
}
if($verb) {
$sql_extra .= sprintf(" AND item.verb like '%s' ",
dbesc(protect_sprintf('%' . $verb . '%'))
);
if ($verb) {
// the presence of a leading dot in the verb determines
// whether to match the type of activity or the child object.
// The name 'verb' is a holdover from the earlier XML
// ActivityStreams specification.
if (substr($verb,0,1) === '.') {
$verb = substr($verb,1);
$sql_extra .= sprintf(" AND item.obj_type like '%s' ",
dbesc(protect_sprintf('%' . $verb . '%'))
);
}
else {
$sql_extra .= sprintf(" AND item.verb like '%s' ",
dbesc(protect_sprintf('%' . $verb . '%'))
);
}
}
if(strlen($file)) {
$sql_extra .= term_query('item',$file,TERM_FILE);
}
if ($dm) {
$sql_extra .= " AND item_private = 2 ";
}
if($conv) {
$item_thread_top = '';

View File

@@ -31,12 +31,7 @@ class Photo extends \Zotlabs\Web\Controller {
// NOTREACHED
}
$cache_mode = array(
'on' => false,
'age' => 86400,
'exp' => true,
'leak' => false
);
$cache_mode = [ 'on' => false, 'age' => 86400, 'exp' => true, 'leak' => false ];
call_hooks('cache_mode_hook', $cache_mode);
$observer_xchan = get_observer_hash();
@@ -144,7 +139,7 @@ class Photo extends \Zotlabs\Web\Controller {
$resolution = 1;
}
$r = q("SELECT uid, photo_usage, display_path FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
$r = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
dbesc($photo),
intval($resolution)
);
@@ -163,13 +158,10 @@ class Photo extends \Zotlabs\Web\Controller {
if($u === PHOTO_CACHE) {
// Validate cache
if($cache_mode['on']) {
$cache = array(
'resid' => $photo,
'status' => false
);
$cache = [ 'status' => false, 'item' => $r[0] ];
call_hooks('cache_url_hook', $cache);
if(! $cache['status']) {
$url = html_entity_decode($r[0]['display_path'], ENT_QUOTES);
$url = html_entity_decode($cache['item']['display_path'], ENT_QUOTES);
// SSLify if needed
if(strpos(z_root(),'https:') !== false && strpos($url,'https:') === false)
$url = z_root() . '/sslify/' . $filename . '?f=&url=' . urlencode($url);
@@ -229,7 +221,7 @@ class Photo extends \Zotlabs\Web\Controller {
header_remove('Pragma');
if($_SERVER['HTTP_IF_NONE_MATCH'] === $etag || $_SERVER['HTTP_IF_MODIFIED_SINCE'] === gmdate("D, d M Y H:i:s", $modified) . " GMT") {
if((isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $etag) || (!isset($_SERVER['HTTP_IF_NONE_MATCH']) && isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $_SERVER['HTTP_IF_MODIFIED_SINCE'] === gmdate("D, d M Y H:i:s", $modified) . " GMT")) {
header_remove('Expires');
header_remove('Cache-Control');
header_remove('Set-Cookie');
@@ -272,7 +264,12 @@ class Photo extends \Zotlabs\Web\Controller {
$maxage = $expires - time();
header("Expires: " . gmdate("D, d M Y H:i:s", $expires) . " GMT");
header("Cache-Control: max-age=" . $maxage . $cachecontrol);
// set CDN/Infrastructure caching much lower than maxage
// in the event that infrastructure caching is present.
$smaxage = intval($maxage/12);
header("Cache-Control: s-maxage=" . $smaxage . ", max-age=" . $maxage . $cachecontrol);
}

View File

@@ -1080,7 +1080,6 @@ class Photos extends \Zotlabs\Web\Controller {
$comments = '';
if(! $r) {
if($observer && ($can_post || $can_comment)) {
$feature_auto_save_draft = ((feature_enabled($owner_uid, 'auto_save_draft')) ? "true" : "false");
$commentbox = replace_macros($cmnt_tpl,array(
'$return_path' => '',
'$mode' => 'photos',
@@ -1096,8 +1095,7 @@ class Photos extends \Zotlabs\Web\Controller {
'$submit' => t('Submit'),
'$preview' => t('Preview'),
'$ww' => '',
'$feature_encrypt' => false,
'$auto_save_draft' => $feature_auto_save_draft
'$feature_encrypt' => false
));
}
}

69
Zotlabs/Module/Pin.php Normal file
View File

@@ -0,0 +1,69 @@
<?php
namespace Zotlabs\Module;
/*
* Pinned post processing
*/
use App;
class Pin extends \Zotlabs\Web\Controller {
function init() {
if(argc() !== 2)
http_status_exit(400, 'Bad request');
}
function post() {
$item_id = intval($_POST['id']);
if ($item_id <= 0)
http_status_exit(404, 'Not found');
$observer = \App::get_observer();
if(! $observer)
http_status_exit(403, 'Forbidden');
$r = q("SELECT * FROM item WHERE id = %d AND id = parent AND item_private = 0 LIMIT 1",
$item_id
);
if(! $r) {
notice(t('Unable to locate original post.'));
http_status_exit(404, 'Not found');
}
$midb64 = 'b64.' . base64url_encode($r[0]['mid']);
$pinned = (in_array($midb64, get_pconfig($r[0]['uid'], 'pinned', $r[0]['item_type'], [])) ? true : false);
switch(argv(1)) {
case 'pin':
if(! local_channel() || (local_channel() != $r[0]['uid'] && local_channel() != is_site_admin()))
http_status_exit(403, 'Forbidden');
// Currently allow only one pinned item for each type
set_pconfig($r[0]['uid'], 'pinned', $r[0]['item_type'], ($pinned ? [] : [ $midb64 ]));
if($pinned)
del_pconfig($r[0]['uid'], 'pinned_hide', $midb64);
break;
case 'hide':
if($pinned) {
$hidden = get_pconfig($r[0]['uid'], 'pinned_hide', $midb64, []);
if(! in_array($observer['xchan_hash'], $hidden)) {
$hidden[] = $observer['xchan_hash'];
set_pconfig($r[0]['uid'], 'pinned_hide', $midb64, $hidden);
}
}
break;
default:
http_status_exit(404, 'Not found');
}
build_sync_packet($r[0]['uid'], [ 'config' ]);
}
}

View File

@@ -62,6 +62,11 @@ class Pubstream extends \Zotlabs\Web\Controller {
$static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0);
$net = ((array_key_exists('net',$_REQUEST)) ? escape_tags($_REQUEST['net']) : '');
$title = replace_macros(get_markup_template("section_title.tpl"),array(
'$title' => (($hashtags) ? '#' . htmlspecialchars($hashtags, ENT_COMPAT,'UTF-8') : '')
));
$o = (($hashtags) ? $title : '');
if(local_channel() && (! $update)) {
@@ -94,7 +99,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
'reset' => t('Reset form')
);
$o = '<div id="jot-popup">';
$o .= '<div id="jot-popup">';
$o .= status_editor($a,$x,false,'Pubstream');
$o .= '</div>';
}
@@ -139,6 +144,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
'$conv' => '0',
'$spam' => '0',
'$fh' => '1',
'$dm' => '0',
'$nouveau' => '0',
'$wall' => '0',
'$list' => '0',
@@ -285,7 +291,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
}
// fake it
$mode = ('pubstream');
$mode = (($hashtags) ? 'search' : 'pubstream');
$o .= conversation($items,$mode,$update,$page_mode);

View File

@@ -128,6 +128,7 @@ class Search extends \Zotlabs\Web\Controller {
'$conv' => '0',
'$spam' => '0',
'$fh' => '0',
'$dm' => '0',
'$nouveau' => '0',
'$wall' => '0',
'$static' => $static,

121
Zotlabs/Module/Sse.php Normal file
View File

@@ -0,0 +1,121 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Lib\Apps;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Enotify;
use Zotlabs\Lib\XConfig;
class Sse extends Controller {
public static $uid;
public static $ob_hash;
public static $sse_id;
public static $vnotify;
function init() {
if((observer_prohibited(true))) {
killme();
}
if(! intval(get_config('system','open_pubstream',1))) {
if(! get_observer_hash()) {
killme();
}
}
// this is important!
session_write_close();
self::$uid = local_channel();
self::$ob_hash = get_observer_hash();
self::$sse_id = false;
if(! self::$ob_hash) {
if(session_id()) {
self::$sse_id = true;
self::$ob_hash = 'sse_id.' . session_id();
}
else {
return;
}
}
self::$vnotify = get_pconfig(self::$uid, 'system', 'vnotify');
$sys = get_sys_channel();
$sleep_seconds = 3;
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
header("Connection: keep-alive");
header("X-Accel-Buffering: no");
while(true) {
/**
* Update chat presence indication (if applicable)
*/
if(! self::$sse_id) {
$r = q("select cp_id, cp_room from chatpresence where cp_xchan = '%s' and cp_client = '%s' and cp_room = 0 limit 1",
dbesc(self::$ob_hash),
dbesc($_SERVER['REMOTE_ADDR'])
);
$basic_presence = false;
if($r) {
$basic_presence = true;
q("update chatpresence set cp_last = '%s' where cp_id = %d",
dbesc(datetime_convert()),
intval($r[0]['cp_id'])
);
}
if(! $basic_presence) {
q("insert into chatpresence ( cp_xchan, cp_last, cp_status, cp_client)
values( '%s', '%s', '%s', '%s' ) ",
dbesc(self::$ob_hash),
dbesc(datetime_convert()),
dbesc('online'),
dbesc($_SERVER['REMOTE_ADDR'])
);
}
}
XConfig::Load(self::$ob_hash);
$result = XConfig::Get(self::$ob_hash, 'sse', 'notifications', []);
$lock = XConfig::Get(self::$ob_hash, 'sse', 'lock');
if($result && !$lock) {
echo "event: notifications\n";
echo 'data: ' . json_encode($result);
echo "\n\n";
XConfig::Set(self::$ob_hash, 'sse', 'notifications', []);
unset($result);
}
// always send heartbeat to detect disconnected clients
echo "event: heartbeat\n";
echo 'data: {}';
echo "\n\n";
ob_end_flush();
flush();
if(connection_status() != CONNECTION_NORMAL || connection_aborted()) {
//TODO: this does not seem to be triggered
XConfig::Set(self::$ob_hash, 'sse', 'timestamp', NULL_DATE);
break;
}
sleep($sleep_seconds);
}
}
}

550
Zotlabs/Module/Sse_bs.php Normal file
View File

@@ -0,0 +1,550 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Lib\Apps;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Enotify;
class Sse_bs extends Controller {
public static $uid;
public static $ob_hash;
public static $sse_id;
public static $vnotify;
public static $evdays;
public static $limit;
public static $offset;
public static $xchans;
function init() {
self::$uid = local_channel();
self::$ob_hash = get_observer_hash();
self::$sse_id = false;
if(! self::$ob_hash) {
if(session_id()) {
self::$sse_id = true;
self::$ob_hash = 'sse_id.' . session_id();
}
else {
return;
}
}
self::$vnotify = get_pconfig(self::$uid, 'system', 'vnotify');
self::$evdays = intval(get_pconfig(self::$uid, 'system', 'evdays'));
self::$limit = 100;
self::$offset = 0;
self::$xchans = '';
if(!empty($_GET['nquery']) && $_GET['nquery'] !== '%') {
$nquery = $_GET['nquery'];
$x = q("SELECT xchan_hash FROM xchan WHERE xchan_name LIKE '%s' OR xchan_addr LIKE '%s'",
dbesc($nquery . '%'),
dbesc($nquery . '%')
);
self::$xchans = ids_to_querystr($x, 'xchan_hash', true);
}
if(intval(argv(2)) > 0)
self::$offset = argv(2);
else
$_SESSION['sse_loadtime'] = datetime_convert();
$network = false;
$home = false;
$pubs = false;
$f = '';
switch (argv(1)) {
case 'network':
$network = true;
$f = 'bs_network';
break;
case 'home':
$home = true;
$f = 'bs_home';
break;
case 'pubs':
$pubs = true;
$f = 'bs_pubs';
break;
default:
}
if(self::$offset && $f) {
$result = self::$f(true);
json_return_and_die($result);
}
$result = array_merge(
self::bs_network($network),
self::bs_home($home),
self::bs_notify(),
self::bs_intros(),
self::bs_forums(),
self::bs_pubs($pubs),
self::bs_files(),
self::bs_mail(),
self::bs_all_events(),
self::bs_register()
);
set_xconfig(self::$ob_hash, 'sse', 'timestamp', datetime_convert());
set_xconfig(self::$ob_hash, 'sse', 'notifications', []); // reset the cache
set_xconfig(self::$ob_hash, 'sse', 'language', App::$language);
json_return_and_die($result);
}
function bs_network($notifications) {
$result['network']['notifications'] = [];
$result['network']['count'] = 0;
if(! self::$uid)
return $result;
$limit = intval(self::$limit);
$offset = self::$offset;
$sql_extra = '';
if(! (self::$vnotify & VNOTIFY_LIKE))
$sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
$sql_extra2 = '';
if(self::$xchans)
$sql_extra2 = " AND (author_xchan IN (" . self::$xchans . ") OR owner_xchan IN (" . self::$xchans . ")) ";
$item_normal = item_normal();
if ($notifications) {
$items = q("SELECT * FROM item
WHERE uid = %d
AND created <= '%s'
AND item_unseen = 1 AND item_wall = 0
AND author_xchan != '%s'
$item_normal
$sql_extra
$sql_extra2
ORDER BY created DESC LIMIT $limit OFFSET $offset",
intval(self::$uid),
dbescdate($_SESSION['sse_loadtime']),
dbesc(self::$ob_hash)
);
if($items) {
$result['network']['offset'] = ((count($items) == $limit) ? intval($offset + $limit) : -1);
xchan_query($items);
foreach($items as $item) {
$result['network']['notifications'][] = Enotify::format($item);
}
}
else {
$result['network']['offset'] = -1;
}
}
$r = q("SELECT count(id) as total FROM item
WHERE uid = %d and item_unseen = 1 AND item_wall = 0
$item_normal
$sql_extra
AND author_xchan != '%s'",
intval(self::$uid),
dbesc(self::$ob_hash)
);
if($r)
$result['network']['count'] = intval($r[0]['total']);
return $result;
}
function bs_home($notifications) {
$result['home']['notifications'] = [];
$result['home']['count'] = 0;
if(! self::$uid)
return $result;
$limit = intval(self::$limit);
$offset = self::$offset;
$sql_extra = '';
if(! (self::$vnotify & VNOTIFY_LIKE))
$sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
$sql_extra2 = '';
if(self::$xchans)
$sql_extra2 = " AND (author_xchan IN (" . self::$xchans . ") OR owner_xchan IN (" . self::$xchans . ")) ";
$item_normal = item_normal();
if ($notifications) {
$items = q("SELECT * FROM item
WHERE uid = %d
AND created <= '%s'
AND item_unseen = 1 AND item_wall = 1
AND author_xchan != '%s'
$item_normal
$sql_extra
$sql_extra2
ORDER BY created DESC LIMIT $limit OFFSET $offset",
intval(self::$uid),
dbescdate($_SESSION['sse_loadtime']),
dbesc(self::$ob_hash)
);
if($items) {
$result['home']['offset'] = ((count($items) == $limit) ? intval($offset + $limit) : -1);
xchan_query($items);
foreach($items as $item) {
$result['home']['notifications'][] = Enotify::format($item);
}
}
else {
$result['home']['offset'] = -1;
}
}
$r = q("SELECT count(id) as total FROM item
WHERE uid = %d and item_unseen = 1 AND item_wall = 1
$item_normal
$sql_extra
AND author_xchan != '%s'",
intval(self::$uid),
dbesc(self::$ob_hash)
);
if($r)
$result['home']['count'] = intval($r[0]['total']);
return $result;
}
function bs_pubs($notifications) {
$result['pubs']['notifications'] = [];
$result['pubs']['count'] = 0;
if((observer_prohibited(true))) {
return $result;
}
if(! intval(get_config('system','open_pubstream',1))) {
if(! get_observer_hash()) {
return $result;
}
}
if(! isset($_SESSION['static_loadtime']))
$_SESSION['static_loadtime'] = datetime_convert();
$limit = intval(self::$limit);
$offset = self::$offset;
$sys = get_sys_channel();
$sql_extra = '';
if(! (self::$vnotify & VNOTIFY_LIKE))
$sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
$sql_extra2 = '';
if(self::$xchans)
$sql_extra2 = " AND (author_xchan IN (" . self::$xchans . ") OR owner_xchan IN (" . self::$xchans . ")) ";
$item_normal = item_normal();
if ($notifications) {
$items = q("SELECT * FROM item
WHERE uid = %d
AND created <= '%s'
AND item_unseen = 1
AND author_xchan != '%s'
AND created > '%s'
$item_normal
$sql_extra
$sql_extra2
ORDER BY created DESC LIMIT $limit OFFSET $offset",
intval($sys['channel_id']),
dbescdate($_SESSION['sse_loadtime']),
dbesc(self::$ob_hash),
dbescdate($_SESSION['static_loadtime'])
);
if($items) {
$result['pubs']['offset'] = ((count($items) == $limit) ? intval($offset + $limit) : -1);
xchan_query($items);
foreach($items as $item) {
$result['pubs']['notifications'][] = Enotify::format($item);
}
}
else {
$result['pubs']['offset'] = -1;
}
}
$r = q("SELECT count(id) as total FROM item
WHERE uid = %d AND item_unseen = 1
AND created > '%s'
$item_normal
$sql_extra
AND author_xchan != '%s'",
intval($sys['channel_id']),
dbescdate($_SESSION['static_loadtime']),
dbesc(self::$ob_hash)
);
if($r)
$result['pubs']['count'] = intval($r[0]['total']);
return $result;
}
function bs_notify() {
$result['notify']['notifications'] = [];
$result['notify']['count'] = 0;
$result['notify']['offset'] = -1;
if(! self::$uid)
return $result;
$r = q("SELECT * FROM notify WHERE uid = %d AND seen = 0 ORDER BY created DESC",
intval(self::$uid)
);
if($r) {
foreach($r as $rr) {
$result['notify']['notifications'][] = Enotify::format_notify($rr);
}
$result['notify']['count'] = count($r);
}
return $result;
}
function bs_intros() {
$result['intros']['notifications'] = [];
$result['intros']['count'] = 0;
$result['intros']['offset'] = -1;
if(! self::$uid)
return $result;
$r = q("SELECT * FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ORDER BY abook_created DESC LIMIT 50",
intval(self::$uid)
);
if($r) {
foreach($r as $rr) {
$result['intros']['notifications'][] = Enotify::format_intros($rr);
}
$result['intros']['count'] = count($r);
}
return $result;
}
function bs_forums() {
$result['forums']['notifications'] = [];
$result['forums']['count'] = 0;
$result['forums']['offset'] = -1;
if(! self::$uid)
return $result;
$forums = get_forum_channels(self::$uid);
if($forums) {
$item_normal = item_normal();
$sql_extra = '';
if(! (self::$vnotify & VNOTIFY_LIKE))
$sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') ";
$fcount = count($forums);
$i = 0;
for($x = 0; $x < $fcount; $x ++) {
$p = q("SELECT oid AS parent FROM term WHERE uid = %d AND ttype = %d AND term = '%s'",
intval(self::$uid),
intval(TERM_FORUM),
dbesc($forums[$x]['xchan_name'])
);
$p_str = ids_to_querystr($p, 'parent');
$p_sql = (($p_str) ? "OR parent IN ( $p_str )" : '');
$r = q("select mid from item
where uid = %d and ( owner_xchan = '%s' OR author_xchan = '%s' $p_sql ) and item_unseen = 1 $sql_extra $item_normal",
intval(self::$uid),
dbesc($forums[$x]['xchan_hash']),
dbesc($forums[$x]['xchan_hash'])
);
if($r) {
$mids = flatten_array_recursive($r);
foreach($mids as $mid)
$b64mids[] = 'b64.' . base64url_encode($mid);
$forums[$x]['notify_link'] = z_root() . '/network/?f=&pf=1&unseen=1&cid=' . $forums[$x]['abook_id'];
$forums[$x]['name'] = $forums[$x]['xchan_name'];
$forums[$x]['addr'] = $forums[$x]['xchan_addr'];
$forums[$x]['url'] = $forums[$x]['xchan_url'];
$forums[$x]['photo'] = $forums[$x]['xchan_photo_s'];
$forums[$x]['unseen'] = count($b64mids);
$forums[$x]['private_forum'] = (($forums[$x]['private_forum']) ? 'lock' : '');
$forums[$x]['message'] = (($forums[$x]['private_forum']) ? t('Private forum') : t('Public forum'));
$forums[$x]['mids'] = json_encode($b64mids);
unset($forums[$x]['abook_id']);
unset($forums[$x]['xchan_hash']);
unset($forums[$x]['xchan_name']);
unset($forums[$x]['xchan_url']);
unset($forums[$x]['xchan_photo_s']);
$i = $i + count($mids);
}
else {
unset($forums[$x]);
}
}
$result['forums']['count'] = $i;
$result['forums']['notifications'] = array_values($forums);
}
return $result;
}
function bs_files() {
$result['files']['notifications'] = [];
$result['files']['count'] = 0;
$result['files']['offset'] = -1;
if(! self::$uid)
return $result;
$r = q("SELECT * FROM item
WHERE verb = '%s'
AND obj_type = '%s'
AND uid = %d
AND owner_xchan != '%s'
AND item_unseen = 1",
dbesc(ACTIVITY_POST),
dbesc(ACTIVITY_OBJ_FILE),
intval(self::$uid),
dbesc(self::$ob_hash)
);
if($r) {
xchan_query($r);
foreach($r as $rr) {
$result['files']['notifications'][] = Enotify::format_files($rr);
}
$result['files']['count'] = count($r);
}
return $result;
}
function bs_mail() {
$result['mail']['notifications'] = [];
$result['mail']['count'] = 0;
$result['mail']['offset'] = -1;
if(! self::$uid)
return $result;
$r = q("select mail.*, xchan.* from mail left join xchan on xchan_hash = from_xchan
where channel_id = %d and mail_seen = 0 and mail_deleted = 0
and from_xchan != '%s' order by created desc",
intval(self::$uid),
dbesc(self::$ob_hash)
);
if($r) {
foreach($r as $rr) {
$result['mail']['notifications'][] = Enotify::format_mail($rr);
}
$result['mail']['count'] = count($r);
}
return $result;
}
function bs_all_events() {
$result['all_events']['notifications'] = [];
$result['all_events']['count'] = 0;
$result['all_events']['offset'] = -1;
if(! self::$uid)
return $result;
$r = q("SELECT * FROM event left join xchan on event_xchan = xchan_hash
WHERE event.uid = %d AND dtstart < '%s' AND dtstart > '%s' and dismissed = 0
and etype in ( 'event', 'birthday' )
ORDER BY dtstart DESC",
intval(self::$uid),
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval(self::$evdays) . ' days')),
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))
);
if($r) {
foreach($r as $rr) {
$result['all_events']['notifications'][] = Enotify::format_all_events($rr);
}
$result['all_events']['count'] = count($r);
}
return $result;
}
function bs_register() {
$result['register']['notifications'] = [];
$result['register']['count'] = 0;
$result['register']['offset'] = -1;
if(! self::$uid && ! is_site_admin())
return $result;
$r = q("SELECT account_email, account_created from account where (account_flags & %d) > 0",
intval(ACCOUNT_PENDING)
);
if($r) {
foreach($r as $rr) {
$result['register']['notifications'][] = Enotify::format_register($rr);
}
$result['register']['count'] = count($r);
}
return $result;
}
}

View File

@@ -74,6 +74,29 @@ class Viewconnections extends \Zotlabs\Web\Controller {
if(! intval(get_abconfig(\App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_comments'))) {
$oneway = true;
}
$perminfo=[];
$perminfo['connpermcount']=0;
$perminfo['connperms']=t('Accepts').': ';
if(intval(get_abconfig(\App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_comments'))) {
$perminfo['connpermcount']++;
$perminfo['connperms'] .= t('Comments');
}
if(intval(get_abconfig(\App::$profile['uid'],$rr['xchan_hash'],'their_perms','send_stream'))) {
$perminfo['connpermcount']++;
$perminfo['connperms'] = ($perminfo['connperms']) ? $perminfo['connperms'] . ', ' : $perminfo['connperms'] ;
$perminfo['connperms'] .= t('Stream items');
}
if(intval(get_abconfig(\App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_wall'))) {
$perminfo['connpermcount']++;
$perminfo['connperms'] = ($perminfo['connperms']) ? $perminfo['connperms'] . ', ' : $perminfo['connperms'] ;
$perminfo['connperms'] .= t('Wall posts');
}
if ($perminfo['connpermcount'] == 0) {
$perminfo['connperms'] .= t('Nothing');
}
$url = chanlink_hash($rr['xchan_hash']);
if($url) {
@@ -88,6 +111,7 @@ class Viewconnections extends \Zotlabs\Web\Controller {
'sparkle' => '',
'itemurl' => $rr['url'],
'network' => '',
'perminfo' => $perminfo,
'oneway' => $oneway
);
}

143
Zotlabs/Module/Vote.php Normal file
View File

@@ -0,0 +1,143 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Activity;
use Zotlabs\Daemon\Master;
use Zotlabs\Lib\Libsync;
class Vote extends Controller {
function init() {
$ret = [ 'success' => false, 'message' => EMPTY_STR ];
$channel = App::get_channel();
if (! $channel) {
$ret['message'] = t('Permission denied.');
json_return_and_die($ret);
}
$fetch = null;
$id = argv(1);
$response = $_REQUEST['answer'];
if ($id) {
$fetch = q("select * from item where id = %d limit 1",
intval($id)
);
}
if ($fetch && $fetch[0]['obj_type'] === 'Question') {
$obj = json_decode($fetch[0]['obj'],true);
}
else {
$ret['message'] = t('Poll not found.');
json_return_and_die($ret);
}
$valid = false;
if ($obj['oneOf']) {
foreach($obj['oneOf'] as $selection) {
// logger('selection: ' . $selection);
// logger('response: ' . $response);
if($selection['name'] && $selection['name'] === $response) {
$valid = true;
}
}
}
$choices = [];
if ($obj['anyOf']) {
foreach ($obj['anyOf'] as $selection) {
$choices[] = $selection['name'];
}
foreach ($response as $res) {
if (! in_array($res,$choices)) {
$valid = false;
break;
}
$valid = true;
}
}
if (! $valid) {
$ret['message'] = t('Invalid response.');
json_return_and_die($ret);
}
if (! is_array($response)) {
$response = [ $response ];
}
foreach ($response as $res) {
$item = [];
$item['aid'] = $channel['channel_account_id'];
$item['uid'] = $channel['channel_id'];
$item['item_origin'] = 1;
$item['parent'] = $fetch[0]['id'];
$item['parent_mid'] = $fetch[0]['mid'];
$item['thr_parent'] = $fetch[0]['mid'];
$item['uuid'] = new_uuid();
$item['mid'] = z_root() . '/item/' . $item['uuid'];
$item['verb'] = 'Create';
$item['title'] = $res;
$item['author_xchan'] = $channel['channel_hash'];
$item['owner_xchan'] = $fetch[0]['author_xchan'];
$item['allow_cid'] = '<' . $fetch[0]['author_xchan'] . '>';
$item['item_private'] = 1;
$item['obj_type'] = 'Note';
$item['author'] = channelx_by_n($channel['channel_id']);
$item['obj'] = Activity::encode_item($item);
// now reset the placeholders
$item['verb'] = ACTIVITY_POST;
$item['obj_type'] = 'Answer';
unset($item['author']);
$x = item_store($item);
retain_item($fetch[0]['id']);
if($x['success']) {
$itemid = $x['item_id'];
Master::Summon( [ 'Notifier', 'like', $itemid ] );
}
$r = q("select * from item where id = %d",
intval($itemid)
);
if ($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
Libsync::build_sync_packet($channel['channel_id'], [ 'item' => [ encode_item($sync_item[0],true) ] ]);
}
}
$ret['success'] = true;
$ret['message'] = t('Response submitted. Updates may not appear instantly.');
json_return_and_die($ret);
}
}

View File

@@ -86,7 +86,7 @@ class Wall_attach extends \Zotlabs\Web\Controller {
$def_attach = get_pconfig($channel['channel_id'],'system','attach_path');
$r = attach_store($channel,(($observer) ? $observer['xchan_hash'] : ''),'', array('source' => 'editor', 'visible' => 0, 'album' => $def_album, 'directory' => $def_attach, 'allow_cid' => '<' . $channel['channel_hash'] . '>'));
if(! $r['success']) {
notice( $r['message'] . EOL);
killme();
@@ -111,9 +111,24 @@ class Wall_attach extends \Zotlabs\Web\Controller {
}
if(strpos($r['data']['filetype'],'audio') === 0) {
$url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path'];
echo "\n\n" . '[zaudio]' . $url . '[/zaudio]' . "\n\n";
$s = "\n\n" . '[zaudio]' . $url . '[/zaudio]' . "\n\n";
}
if ($r['data']['filetype'] === 'image/svg+xml') {
$x = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']);
if ($x) {
$bb = svg2bb($x);
if ($bb) {
$s .= "\n\n" . $bb;
}
else {
logger('empty return from svgbb');
}
}
else {
logger('unable to read svg data file: ' . 'store/' . $channel['channel_address'] . '/' . $r['data']['os_path']);
}
}
$s .= "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n";
}

View File

@@ -63,6 +63,13 @@ class Well_known extends \Zotlabs\Web\Controller {
case 'dnt-policy.txt':
echo file_get_contents('doc/dnt-policy.txt');
killme();
case 'caldav':
case 'carddav':
if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
http_status('301', 'moved permanently');
goaway(z_root() . '/cdav');
};
default:
if(file_exists(\App::$cmd)) {

View File

@@ -42,7 +42,7 @@ class Zotfeed extends \Zotlabs\Web\Controller {
}
logger('zotfeed request: ' . $r[0]['channel_name'], LOGGER_DEBUG);
$result['project'] = 'Hubzilla';
$result['messages'] = zot_feed($r[0]['channel_id'],$observer['xchan_hash'],array('mindate' => $mindate));
$result['success'] = true;
json_return_and_die($result);

View File

@@ -13,12 +13,16 @@ class PhotoGd extends PhotoDriver {
* @see \Zotlabs\Photo\PhotoDriver::supportedTypes()
*/
public function supportedTypes() {
$t = [];
$t['image/jpeg'] = 'jpg';
if(imagetypes() & IMG_PNG)
$t['image/png'] = 'png';
if(imagetypes() & IMG_GIF)
$t['image/gif'] = 'gif';
if(imagetypes() & IMG_WEBP)
$t['image/webp'] = 'webp';
return $t;
}
@@ -142,6 +146,7 @@ class PhotoGd extends PhotoDriver {
* @see \Zotlabs\Photo\PhotoDriver::imageString()
*/
public function imageString() {
if(! $this->is_valid())
return false;
@@ -150,23 +155,32 @@ class PhotoGd extends PhotoDriver {
ob_start();
switch($this->getType()){
case 'image/png':
$quality = get_config('system', 'png_quality');
if((! $quality) || ($quality > 9))
$quality = PNG_QUALITY;
\imagepng($this->image, NULL, $quality);
break;
case 'image/webp':
$quality = get_config('system', 'webp_quality');
if((! $quality) || ($quality > 100))
$quality = WEBP_QUALITY;
\imagewebp($this->image, NULL, $quality);
break;
case 'image/jpeg':
// gd can lack imagejpeg(), but we verify during installation it is available
default:
$quality = get_config('system', 'jpeg_quality');
if((! $quality) || ($quality > 100))
$quality = JPEG_QUALITY;
\imagejpeg($this->image, NULL, $quality);
break;
}
$string = ob_get_contents();
ob_end_clean();

View File

@@ -8,19 +8,16 @@ namespace Zotlabs\Photo;
class PhotoImagick extends PhotoDriver {
public function supportedTypes() {
return [
$ret = [
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/gif' => 'gif',
'image/gif' => 'gif'
];
}
if(\Imagick::queryFormats("WEBP"))
$ret['image/webp'] = 'webp';
private function get_FormatsMap() {
return [
'image/jpeg' => 'JPG',
'image/png' => 'PNG',
'image/gif' => 'GIF',
];
return $ret;
}
@@ -42,8 +39,8 @@ class PhotoImagick extends PhotoDriver {
* Setup the image to the format it will be saved to
*/
$map = $this->get_FormatsMap();
$format = $map[$type];
$map = $this->supportedTypes();
$format = strtoupper($map[$type]);
if($this->image) {
$this->image->setFormat($format);
@@ -58,6 +55,7 @@ class PhotoImagick extends PhotoDriver {
* setup the compression here, so we'll do it only once
*/
switch($this->getType()) {
case 'image/png':
$quality = get_config('system', 'png_quality');
if((! $quality) || ($quality > 9))
@@ -73,11 +71,21 @@ class PhotoImagick extends PhotoDriver {
$quality = $quality * 10;
$this->image->setCompressionQuality($quality);
break;
case 'image/jpeg':
$quality = get_config('system', 'jpeg_quality');
if((! $quality) || ($quality > 100))
$quality = JPEG_QUALITY;
$this->image->setCompressionQuality($quality);
break;
case 'image/webp':
$quality = get_config('system', 'webp_quality');
if((! $quality) || ($quality > 100))
$quality = WEBP_QUALITY;
$this->image->setCompressionQuality($quality);
break;
default:
break;
}

View File

@@ -720,7 +720,11 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
* @return array Directory[]
*/
function ChannelList(&$auth) {
$ret = array();
$ret = [];
if (intval(get_config('system','cloud_disable_siteroot'))) {
return $ret;
}
$r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0",
intval(PAGE_HIDDEN)
@@ -730,8 +734,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
foreach ($r as $rr) {
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) {
logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA);
// @todo can't we drop '/cloud'? It gets stripped off anyway in RedDirectory
$ret[] = new Directory('/cloud/' . $rr['channel_address'], $auth);
$ret[] = new Directory($rr['channel_address'], $auth);
}
}
}

View File

@@ -169,7 +169,7 @@ class File extends DAV\Node implements DAV\IFile {
}
$gis = @getimagesize($f);
logger('getimagesize: ' . print_r($gis,true), LOGGER_DATA);
if(($gis) && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG)) {
if(($gis) && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG || $gis[2] === IMAGETYPE_WEBP)) {
$is_photo = 1;
}

25
Zotlabs/Update/_1235.php Normal file
View File

@@ -0,0 +1,25 @@
<?php
namespace Zotlabs\Update;
class _1235 {
function run() {
q("START TRANSACTION");
$r = q("DELETE FROM app WHERE app_name = '%s' AND app_system = 1",
dbesc('Mail')
);
if($r) {
q("COMMIT");
return UPDATE_SUCCESS;
}
q("ROLLBACK");
return UPDATE_FAILED;
}
}

View File

@@ -56,7 +56,7 @@ class Router {
$routes = Route::get();
if($routes) {
foreach($routes as $route) {
if(is_array($route) && strtolower($route[1]) === $module) {
if(is_array($route) && file_exists($route[0]) && strtolower($route[1]) === $module) {
include_once($route[0]);
if(class_exists($modname)) {
$this->controller = new $modname;

View File

@@ -38,10 +38,15 @@ class SessionHandler implements \SessionHandlerInterface {
function write ($id, $data) {
// Pretend everything is hunky-dory, even though it isn't.
// There probably isn't anything we can do about it in any event.
// See: https://stackoverflow.com/a/43636110
if(! $id || ! $data) {
return false;
return true;
}
// Unless we authenticate somehow, only keep a session for 5 minutes
// The viewer can extend this by performing any web action using the
// original cookie, but this allows us to cleanup the hundreds or

View File

@@ -82,14 +82,6 @@ class WebServer {
if((x($_SESSION, 'authenticated')) || (x($_POST, 'auth-params')) || (\App::$module === 'login'))
require('include/auth.php');
if(! x($_SESSION, 'sysmsg'))
$_SESSION['sysmsg'] = array();
if(! x($_SESSION, 'sysmsg_info'))
$_SESSION['sysmsg_info'] = array();
if(\App::$install) {
/* Allow an exception for the view module so that pcss will be interpreted during installation */
if(\App::$module != 'view')

View File

@@ -2,6 +2,7 @@
namespace Zotlabs\Widget;
use App;
use Zotlabs\Lib\Apps;
class Activity_filter {
@@ -16,6 +17,46 @@ class Activity_filter {
$tabs = [];
if(x($_GET,'dm')) {
$dm_active = (($_GET['dm'] == 1) ? 'active' : '');
$filter_active = 'dm';
}
if(x($_GET,'verb')) {
$events_active = (($_GET['verb'] == '.Event') ? 'active' : '');
$polls_active = (($_GET['verb'] == '.Question') ? 'active' : '');
$filter_active = (($events_active) ? 'events' : 'polls');
}
$tabs[] = [
'label' => t('Direct Messages'),
'icon' => 'envelope-o',
'url' => z_root() . '/' . $cmd . '/?f=&dm=1',
'sel' => $dm_active,
'title' => t('Show direct (private) messages')
];
if(feature_enabled(local_channel(),'events_tab')) {
$tabs[] = [
'label' => t('Events'),
'icon' => 'calendar',
'url' => z_root() . '/' . $cmd . '/?verb=%2EEvent',
'sel' => $events_active,
'title' => t('Show posts that include events')
];
}
if(feature_enabled(local_channel(),'polls_tab')) {
$tabs[] = [
'label' => t('Polls'),
'icon' => 'bar-chart',
'url' => z_root() . '/' . $cmd . '/?verb=%2EQuestion',
'sel' => $polls_active,
'title' => t('Show posts that include polls')
];
}
if(Apps::system_app_installed(local_channel(), 'Privacy Groups')) {
$groups = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
@@ -51,6 +92,7 @@ class Activity_filter {
if(feature_enabled(local_channel(),'forums_tab')) {
$forums = get_forum_channels(local_channel());
$channel = App::get_channel();
if($forums) {
foreach($forums as $f) {
@@ -61,7 +103,7 @@ class Activity_filter {
$fsub[] = [
'label' => $f['xchan_name'],
'img' => $f['xchan_photo_s'],
'url' => (($f['private_forum']) ? $f['xchan_url'] : z_root() . '/' . $cmd . '/?f=&pf=1&cid=' . $f['abook_id']),
'url' => (($f['private_forum']) ? $f['xchan_url'] . '/?f=&zid=' . $channel['xchan_addr'] : z_root() . '/' . $cmd . '/?f=&pf=1&cid=' . $f['abook_id']),
'sel' => $forum_active,
'title' => t('Show posts to this forum'),
'lock' => (($f['private_forum']) ? 'lock' : '')

280
Zotlabs/Widget/Pinned.php Normal file
View File

@@ -0,0 +1,280 @@
<?php
namespace Zotlabs\Widget;
/*
* Show pinned content
*
*/
class Pinned {
private $allowed_types = 0;
private $uid = 0;
/*
* @brief Displays pinned items
*
* @param $uid
* @param $types
* @return array of results: 'html' string, 'ids' array
*
*/
function widget($uid, $types) {
$ret = [ 'html' => EMPTY_STR, 'ids' => [] ];
$this->uid = intval($uid);
if(! $this->uid)
return $ret;
$this->allowed_types = get_config('system', 'pin_types', [ ITEM_TYPE_POST ]);
$items = $this->list($types);
if(empty($items))
return $ret;
$ret['ids'] = array_column($items, 'id');
$observer = \App::get_observer();
foreach($items as $item) {
$midb64 = 'b64.' . base64url_encode($item['mid']);
if(in_array($observer['xchan_hash'], get_pconfig($item['uid'], 'pinned_hide', $midb64, [])))
continue;
$author = channelx_by_hash($item['author_xchan']);
$owner = channelx_by_hash($item['owner_xchan']);
$profile_avatar = $author['xchan_photo_m'];
$profile_link = chanlink_hash($item['author_xchan']);
$profile_name = $author['xchan_name'];
$commentable = ($item['item_nocomment'] == 0 && $item['comments_closed'] == NULL_DATE ? true : false);
$location = format_location($item);
$isevent = false;
$attend = null;
$canvote = false;
$conv_responses = [];
if($item['obj_type'] === ACTIVITY_OBJ_EVENT) {
$conv_responses['attendyes'] = [ 'title' => t('Attending','title') ];
$conv_responses['attendno'] = [ 'title' => t('Not attending','title') ];
$conv_responses['attendmaybe'] = [ 'title' => t('Might attend','title') ];
if($commentable && $observer) {
$attend = array( t('I will attend'), t('I will not attend'), t('I might attend'));
$isevent = true;
}
}
$consensus = (intval($item['item_consensus']) ? true : false);
if($consensus) {
$conv_responses['agree'] = [ 'title' => t('Agree','title') ];
$conv_responses['disagree'] = [ 'title' => t('Disagree','title') ];
$conv_responses['abstain'] = [ 'title' => t('Abstain','title') ];
if($commentable && $observer) {
$conlabels = array( t('I agree'), t('I disagree'), t('I abstain'));
$canvote = true;
}
}
$this->activity($item, $conv_responses);
$verified = (intval($item['item_verified']) ? t('Message signature validated') : '');
$forged = ((! intval($item['item_verified']) && $item['sig']) ? t('Message signature incorrect') : '');
$shareable = ((local_channel() && \App::$profile_uid == local_channel() && $item['item_private'] != 1) ? true : false);
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
//$share = array( t('Repeat This'), t('repeat'));
}
$embed = array( t('Share This'), t('share'));
}
if(strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC','now - 12 hours')) > 0)
$is_new = true;
$body = prepare_body($item,true);
$str = [
'item_type' => intval($item['item_type']),
'body' => $body['html'],
'tags' => $body['tags'],
'categories' => $body['categories'],
'mentions' => $body['mentions'],
'attachments' => $body['attachments'],
'folders' => $body['folders'],
'text' => strip_tags($body['html']),
'id' => $item['id'],
'mids' => json_encode([ $midb64 ]),
'isevent' => $isevent,
'attend' => $attend,
'consensus' => $consensus,
'conlabels' => $conlabels,
'canvote' => $canvote,
'linktitle' => sprintf( t('View %s\'s profile - %s'), $profile_name, ($author['xchan_addr'] ? $author['xchan_addr'] : $author['xchan_url']) ),
'olinktitle' => sprintf( t('View %s\'s profile - %s'), $owner['xchan_name'], ($owner['xchan_addr'] ? $owner['xchan_addr'] : $owner['xchan_url']) ),
'profile_url' => $profile_link,
'name' => $profile_name,
'thumb' => $profile_avatar,
'via' => t('via'),
'title' => $item['title'],
'title_tosource' => get_pconfig($item['uid'],'system','title_tosource'),
'ago' => relative_date($item['created']),
'app' => $item['app'],
'str_app' => sprintf( t('from %s'), $item['app'] ),
'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'),
'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'),
'editedtime' => (($item['edited'] != $item['created']) ? sprintf( t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r') ) : ''),
'expiretime' => ($item['expires'] > NULL_DATE ? sprintf( t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r') ) : ''),
'lock' => $lock,
'verified' => $verified,
'forged' => $forged,
'location' => $location,
'divider' => get_pconfig($item['uid'],'system','item_divider'),
'attend_title' => t('Attendance Options'),
'vote_title' => t('Voting Options'),
'is_new' => $is_new,
'owner_url' => ($owner['xchan_addr'] != $author['xchan_addr'] ? chanlink_hash($owner['xchan_hash']) : ''),
'owner_photo'=> $owner['xchan_photo_m'],
'owner_name' => $owner['xchan_name'],
'photo' => $body['photo'],
'event' => $body['event'],
'has_tags' => (($body['tags'] || $body['categories'] || $body['mentions'] || $body['attachments'] || $body['folders']) ? true : false),
// Item toolbar buttons
'share' => $share,
'embed' => $embed,
'plink' => get_plink($item),
'pinned' => t('Pinned post'),
'pinme' => (($observer['xchan_hash'] == $owner['xchan_hash']) ? t('Unpin from the top') : ''),
'hide' => (! $is_new && $observer && ($observer['xchan_hash'] != $owner['xchan_hash']) ? t("Don't show") : ''),
// end toolbar buttons
'modal_dismiss' => t('Close'),
'responses' => $conv_responses
];
$tpl = get_markup_template('pinned_item.tpl');
$ret['html'] .= replace_macros($tpl, $str);
}
return $ret;
}
/*
* @brief List pinned items depend on type
*
* @param $types
* @return array of pinned items
*
*/
private function list($types) {
if(empty($types) || (! is_array($types)))
return [];
$item_types = array_intersect($this->allowed_types, $types);
if(empty($item_types))
return [];
$mids_list = [];
foreach($item_types as $type) {
$mids = get_pconfig($this->uid, 'pinned', $type, []);
foreach($mids as $mid) {
if(! empty($mid) && strpos($mid,'b64.') === 0)
$mids_list[] = @base64url_decode(substr($mid,4));
}
}
if(empty($mids_list))
return [];
$r = q("SELECT * FROM item WHERE mid IN ( '%s' ) AND uid = %d AND id = parent AND item_private = 0 ORDER BY created DESC",
dbesc(implode(",", $mids_list)),
intval($this->uid)
);
if($r)
return $r;
return [];
}
/*
* @brief List activities on item
*
* @param array $item
* @param array $conv_responses
* @return array
*
*/
private function activity($item, &$conv_responses) {
foreach(array_keys($conv_responses) as $verb) {
switch($verb) {
case 'like':
$v = ACTIVITY_LIKE;
break;
case 'dislike':
$v = ACTIVITY_DISLIKE;
break;
case 'agree':
$v = ACTIVITY_AGREE;
break;
case 'disagree':
$v = ACTIVITY_DISAGREE;
break;
case 'abstain':
$v = ACTIVITY_ABSTAIN;
break;
case 'attendyes':
$v = ACTIVITY_ATTEND;
break;
case 'attendno':
$v = ACTIVITY_ATTENDNO;
break;
case 'attendmaybe':
$v = ACTIVITY_ATTENDMAYBE;
break;
default:
break;
}
$r = q("SELECT * FROM item WHERE parent = %d AND id <> parent AND verb = '%s' AND item_deleted = 0",
intval($item['id']),
dbesc($v)
);
if(! $r) {
unset($conv_responses[$verb]);
continue;
}
$conv_responses[$verb]['count'] = count($r);
$conv_responses[$verb]['button'] = get_response_button_text($verb, $conv_responses[$verb]['count']);
foreach($r as $rr) {
$author = q("SELECT * FROM xchan WHERE xchan_hash = '%s' LIMIT 1",
dbesc($rr['author_xchan'])
);
$name = (($author && $author[0]['xchan_name']) ? $author[0]['xchan_name'] : t('Unknown'));
$conv_responses[$verb]['list'][] = (($rr['author_xchan'] && $author && $author[0]['xchan_photo_s']) ?
'<a class="dropdown-item" href="' . chanlink_hash($rr['author_xchan']) . '">' . '<img class="menu-img-1" src="' . zid($author[0]['xchan_photo_s']) . '" alt="' . urlencode($name) . '" /> ' . $name . '</a>' :
'<a class="dropdown-item" href="#" class="disabled">' . $name . '</a>'
);
}
}
$conv_responses['count'] = count($conv_responses);
}
}

View File

@@ -50,10 +50,10 @@ require_once('include/attach.php');
require_once('include/bbcode.php');
define ( 'PLATFORM_NAME', 'hubzilla' );
define ( 'STD_VERSION', '4.4' );
define ( 'STD_VERSION', '4.7.2' );
define ( 'ZOT_REVISION', '6.0a' );
define ( 'DB_UPDATE_VERSION', 1234 );
define ( 'DB_UPDATE_VERSION', 1235 );
define ( 'PROJECT_BASE', __DIR__ );
@@ -104,6 +104,11 @@ define ( 'JPEG_QUALITY', 100 );
*/
define ( 'PNG_QUALITY', 8 );
/**
* App::$config['system']['webp_quality'] from 1 (maximum compressed) to 100 (uncompressed)
*/
define ( 'WEBP_QUALITY', 80 );
/**
* Language detection parameters
*/
@@ -899,11 +904,12 @@ class App {
// Serve raw files from the file system in certain cases.
$filext = pathinfo(self::$cmd, PATHINFO_EXTENSION);
$serve_rawfiles=[
$serve_rawfiles = [
'jpg'=>'image/jpeg',
'jpeg'=>'image/jpeg',
'gif'=>'image/gif',
'png'=>'image/png',
'webp'=>'image/webp',
'ico'=>'image/vnd.microsoft.icon',
'css'=>'text/css',
'js'=>'text/javascript',
@@ -913,7 +919,8 @@ class App {
'ttf'=>'font/ttf',
'woff'=>'font/woff',
'woff2'=>'font/woff2',
'svg'=>'image/svg+xml'];
'svg'=>'image/svg+xml'
];
if (array_key_exists($filext, $serve_rawfiles) && file_exists(self::$cmd)) {
$staticfilecwd = getcwd();
@@ -1205,7 +1212,8 @@ class App {
'$linkrel' => head_get_links(),
'$js_strings' => js_strings(),
'$zid' => get_my_address(),
'$channel_id' => self::$profile['uid']
'$channel_id' => self::$profile['uid'],
'$auto_save_draft' => ((feature_enabled(self::$profile['uid'], 'auto_save_draft')) ? "true" : "false")
]
) . self::$page['htmlhead'];
@@ -1811,6 +1819,8 @@ function can_view_public_stream() {
* @param string $s Text to display
*/
function notice($s) {
/*
if(! session_id())
return;
@@ -1826,6 +1836,40 @@ function notice($s) {
if(App::$interactive) {
$_SESSION['sysmsg'][] = $s;
}
*/
$hash = get_observer_hash();
$sse_id = false;
if(! $hash) {
if(session_id()) {
$sse_id = true;
$hash = 'sse_id.' . session_id();
}
else {
return;
}
}
$t = get_xconfig($hash, 'sse', 'timestamp', NULL_DATE);
if(datetime_convert('UTC', 'UTC', $t) < datetime_convert('UTC', 'UTC', '- 30 seconds')) {
set_xconfig($hash, 'sse', 'notifications', []);
}
$x = get_xconfig($hash, 'sse', 'notifications');
if ($x === false)
$x = [];
if (isset($x['notice']) && in_array($s, $x['notice']['notifications']))
return;
if (App::$interactive) {
$x['notice']['notifications'][] = $s;
set_xconfig($hash, 'sse', 'notifications', $x);
}
}
/**
@@ -1839,8 +1883,11 @@ function notice($s) {
* @param string $s Text to display
*/
function info($s) {
/*
if(! session_id())
return;
if(! x($_SESSION, 'sysmsg_info'))
$_SESSION['sysmsg_info'] = array();
@@ -1849,6 +1896,40 @@ function info($s) {
if(App::$interactive)
$_SESSION['sysmsg_info'][] = $s;
*/
$hash = get_observer_hash();
$sse_id = false;
if(! $hash) {
if(session_id()) {
$sse_id = true;
$hash = 'sse_id.' . session_id();
}
else {
return;
}
}
$t = get_xconfig($hash, 'sse', 'timestamp', NULL_DATE);
if(datetime_convert('UTC', 'UTC', $t) < datetime_convert('UTC', 'UTC', '- 30 seconds')) {
set_xconfig($hash, 'sse', 'notifications', []);
}
$x = get_xconfig($hash, 'sse', 'notifications');
if($x === false)
$x = [];
if(isset($x['info']) && in_array($s, $x['info']['notifications']))
return;
if(App::$interactive) {
$x['info']['notifications'][] = $s;
set_xconfig($hash, 'sse', 'notifications', $x);
}
}
/**

View File

@@ -28,19 +28,19 @@
"ext-mbstring" : "*",
"ext-xml" : "*",
"ext-openssl" : "*",
"sabre/dav" : "~3.2",
"sabre/dav" : "^4.0",
"michelf/php-markdown" : "^1.7",
"bshaffer/oauth2-server-php": "^1.9",
"ezyang/htmlpurifier": "^4.9",
"simplepie/simplepie": "~1.5",
"league/html-to-markdown": "^4.4",
"pear/text_languagedetect": "^1.0",
"commerceguys/intl": "~0.7",
"lukasreschke/id3parser": "^0.0.1",
"commerceguys/intl": "~1.0.5",
"lukasreschke/id3parser": "^0.0.3",
"smarty/smarty": "~3.1",
"ramsey/uuid": "^3.8",
"twbs/bootstrap": "^4.3.1",
"blueimp/jquery-file-upload": "^9.25",
"blueimp/jquery-file-upload": "^10.3",
"desandro/imagesloaded": "^4.1"
},
"require-dev" : {

331
composer.lock generated
View File

@@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f4dce457cd65f92a26d8197617f2f560",
"content-hash": "1869554b567d2e0c8d16978035b7197e",
"packages": [
{
"name": "blueimp/jquery-file-upload",
"version": "v9.31.0",
"version": "v10.7.0",
"source": {
"type": "git",
"url": "https://github.com/vkhramtsov/jQuery-File-Upload.git",
"reference": "2485bf016e1085f0cd8308723064458cb0af5729"
"reference": "4677050d31be2da817e1d23d0bacb81fb4b37cb3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vkhramtsov/jQuery-File-Upload/zipball/2485bf016e1085f0cd8308723064458cb0af5729",
"reference": "2485bf016e1085f0cd8308723064458cb0af5729",
"url": "https://api.github.com/repos/vkhramtsov/jQuery-File-Upload/zipball/4677050d31be2da817e1d23d0bacb81fb4b37cb3",
"reference": "4677050d31be2da817e1d23d0bacb81fb4b37cb3",
"shasum": ""
},
"type": "library",
@@ -59,7 +59,7 @@
"upload",
"widget"
],
"time": "2019-05-24T07:59:46+00:00"
"time": "2020-01-04T05:46:30+00:00"
},
{
"name": "bshaffer/oauth2-server-php",
@@ -121,20 +121,20 @@
},
{
"name": "commerceguys/intl",
"version": "v0.7.5",
"version": "v1.0.5",
"source": {
"type": "git",
"url": "https://github.com/commerceguys/intl.git",
"reference": "de1435502068393fae4061818e194e4ea61b98d6"
"reference": "6a8c7a8da189d51856b642a61aeb8ae5114fec6c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/commerceguys/intl/zipball/de1435502068393fae4061818e194e4ea61b98d6",
"reference": "de1435502068393fae4061818e194e4ea61b98d6",
"url": "https://api.github.com/repos/commerceguys/intl/zipball/6a8c7a8da189d51856b642a61aeb8ae5114fec6c",
"reference": "6a8c7a8da189d51856b642a61aeb8ae5114fec6c",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
"php": ">=5.5.0"
},
"require-dev": {
"mikey179/vfsstream": "1.*",
@@ -143,7 +143,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.x-dev"
"dev-master": "1.x-dev"
}
},
"autoload": {
@@ -161,7 +161,7 @@
}
],
"description": "Internationalization library powered by CLDR data.",
"time": "2017-12-29T00:13:05+00:00"
"time": "2019-10-22T10:40:46+00:00"
},
{
"name": "desandro/imagesloaded",
@@ -204,23 +204,23 @@
},
{
"name": "ezyang/htmlpurifier",
"version": "v4.10.0",
"version": "v4.12.0",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "d85d39da4576a6934b72480be6978fb10c860021"
"reference": "a617e55bc62a87eec73bd456d146d134ad716f03"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/d85d39da4576a6934b72480be6978fb10c860021",
"reference": "d85d39da4576a6934b72480be6978fb10c860021",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/a617e55bc62a87eec73bd456d146d134ad716f03",
"reference": "a617e55bc62a87eec73bd456d146d134ad716f03",
"shasum": ""
},
"require": {
"php": ">=5.2"
},
"require-dev": {
"simpletest/simpletest": "^1.1"
"simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd"
},
"type": "library",
"autoload": {
@@ -233,7 +233,7 @@
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL"
"LGPL-2.1-or-later"
],
"authors": [
{
@@ -247,20 +247,20 @@
"keywords": [
"html"
],
"time": "2018-02-23T01:58:20+00:00"
"time": "2019-10-28T03:44:26+00:00"
},
{
"name": "league/html-to-markdown",
"version": "4.8.1",
"version": "4.9.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/html-to-markdown.git",
"reference": "250d1bf45f80d15594fb6b316df777d6d4c97ad1"
"reference": "1dcd0f85de786f46a7f224a27cc3d709ddd2a68c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/250d1bf45f80d15594fb6b316df777d6d4c97ad1",
"reference": "250d1bf45f80d15594fb6b316df777d6d4c97ad1",
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/1dcd0f85de786f46a7f224a27cc3d709ddd2a68c",
"reference": "1dcd0f85de786f46a7f224a27cc3d709ddd2a68c",
"shasum": ""
},
"require": {
@@ -270,7 +270,7 @@
},
"require-dev": {
"mikehaertl/php-shellcommand": "~1.1.0",
"phpunit/phpunit": "4.*",
"phpunit/phpunit": "^4.8|^5.7",
"scrutinizer/ocular": "~1.1"
},
"bin": [
@@ -279,7 +279,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.9-dev"
"dev-master": "4.10-dev"
}
},
"autoload": {
@@ -292,17 +292,17 @@
"MIT"
],
"authors": [
{
"name": "Nick Cernis",
"email": "nick@cern.is",
"homepage": "http://modernnerd.net",
"role": "Original Author"
},
{
"name": "Colin O'Dell",
"email": "colinodell@gmail.com",
"homepage": "https://www.colinodell.com",
"role": "Lead Developer"
},
{
"name": "Nick Cernis",
"email": "nick@cern.is",
"homepage": "http://modernnerd.net",
"role": "Original Author"
}
],
"description": "An HTML-to-markdown conversion helper for PHP",
@@ -311,20 +311,20 @@
"html",
"markdown"
],
"time": "2018-12-24T17:21:44+00:00"
"time": "2019-12-28T01:32:28+00:00"
},
{
"name": "lukasreschke/id3parser",
"version": "v0.0.1",
"version": "v0.0.3",
"source": {
"type": "git",
"url": "https://github.com/LukasReschke/ID3Parser.git",
"reference": "cd3ba6e8918cc30883f01a3c24281cfe23b8877a"
"reference": "62f4de76d4eaa9ea13c66dacc1f22977dace6638"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/LukasReschke/ID3Parser/zipball/cd3ba6e8918cc30883f01a3c24281cfe23b8877a",
"reference": "cd3ba6e8918cc30883f01a3c24281cfe23b8877a",
"url": "https://api.github.com/repos/LukasReschke/ID3Parser/zipball/62f4de76d4eaa9ea13c66dacc1f22977dace6638",
"reference": "62f4de76d4eaa9ea13c66dacc1f22977dace6638",
"shasum": ""
},
"require": {
@@ -346,25 +346,28 @@
"php",
"tags"
],
"time": "2016-04-04T09:34:50+00:00"
"time": "2016-09-22T15:10:54+00:00"
},
{
"name": "michelf/php-markdown",
"version": "1.8.0",
"version": "1.9.0",
"source": {
"type": "git",
"url": "https://github.com/michelf/php-markdown.git",
"reference": "01ab082b355bf188d907b9929cd99b2923053495"
"reference": "c83178d49e372ca967d1a8c77ae4e051b3a3c75c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/michelf/php-markdown/zipball/01ab082b355bf188d907b9929cd99b2923053495",
"reference": "01ab082b355bf188d907b9929cd99b2923053495",
"url": "https://api.github.com/repos/michelf/php-markdown/zipball/c83178d49e372ca967d1a8c77ae4e051b3a3c75c",
"reference": "c83178d49e372ca967d1a8c77ae4e051b3a3c75c",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": ">=4.3 <5.8"
},
"type": "library",
"autoload": {
"psr-4": {
@@ -392,7 +395,7 @@
"keywords": [
"markdown"
],
"time": "2018-01-15T00:49:33+00:00"
"time": "2019-12-02T02:32:27+00:00"
},
{
"name": "paragonie/random_compat",
@@ -485,16 +488,16 @@
},
{
"name": "psr/log",
"version": "1.1.0",
"version": "1.1.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd"
"reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
"url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801",
"reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801",
"shasum": ""
},
"require": {
@@ -503,7 +506,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
"dev-master": "1.1.x-dev"
}
},
"autoload": {
@@ -528,48 +531,50 @@
"psr",
"psr-3"
],
"time": "2018-11-20T15:27:04+00:00"
"time": "2019-11-01T11:05:21+00:00"
},
{
"name": "ramsey/uuid",
"version": "3.8.0",
"version": "3.9.2",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
"reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3"
"reference": "7779489a47d443f845271badbdcedfe4df8e06fb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/d09ea80159c1929d75b3f9c60504d613aeb4a1e3",
"reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/7779489a47d443f845271badbdcedfe4df8e06fb",
"reference": "7779489a47d443f845271badbdcedfe4df8e06fb",
"shasum": ""
},
"require": {
"paragonie/random_compat": "^1.0|^2.0|9.99.99",
"php": "^5.4 || ^7.0",
"ext-json": "*",
"paragonie/random_compat": "^1 | ^2 | 9.99.99",
"php": "^5.4 | ^7 | ^8",
"symfony/polyfill-ctype": "^1.8"
},
"replace": {
"rhumsaa/uuid": "self.version"
},
"require-dev": {
"codeception/aspect-mock": "^1.0 | ~2.0.0",
"doctrine/annotations": "~1.2.0",
"goaop/framework": "1.0.0-alpha.2 | ^1.0 | ~2.1.0",
"ircmaxell/random-lib": "^1.1",
"jakub-onderka/php-parallel-lint": "^0.9.0",
"mockery/mockery": "^0.9.9",
"codeception/aspect-mock": "^1 | ^2",
"doctrine/annotations": "^1.2",
"goaop/framework": "1.0.0-alpha.2 | ^1 | ^2.1",
"jakub-onderka/php-parallel-lint": "^1",
"mockery/mockery": "^0.9.11 | ^1",
"moontoast/math": "^1.1",
"php-mock/php-mock-phpunit": "^0.3|^1.1",
"phpunit/phpunit": "^4.7|^5.0|^6.5",
"squizlabs/php_codesniffer": "^2.3"
"paragonie/random-lib": "^2",
"php-mock/php-mock-phpunit": "^0.3 | ^1.1",
"phpunit/phpunit": "^4.8 | ^5.4 | ^6.5",
"squizlabs/php_codesniffer": "^3.5"
},
"suggest": {
"ext-ctype": "Provides support for PHP Ctype functions",
"ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator",
"ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator",
"ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator",
"ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
"moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).",
"paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
"ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid",
"ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
},
@@ -582,13 +587,21 @@
"autoload": {
"psr-4": {
"Ramsey\\Uuid\\": "src/"
}
},
"files": [
"src/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ben Ramsey",
"email": "ben@benramsey.com",
"homepage": "https://benramsey.com"
},
{
"name": "Marijn Huizendveld",
"email": "marijn.huizendveld@gmail.com"
@@ -596,11 +609,6 @@
{
"name": "Thibaud Fabre",
"email": "thibaud@aztech.io"
},
{
"name": "Ben Ramsey",
"email": "ben@benramsey.com",
"homepage": "https://benramsey.com"
}
],
"description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).",
@@ -610,20 +618,20 @@
"identifier",
"uuid"
],
"time": "2018-07-19T23:38:55+00:00"
"time": "2019-12-17T08:18:51+00:00"
},
{
"name": "sabre/dav",
"version": "3.2.3",
"version": "4.0.3",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/dav.git",
"reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80"
"reference": "b793fb4ce27cf0f981b540ad771281c430ffe818"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/dav/zipball/a9780ce4f35560ecbd0af524ad32d9d2c8954b80",
"reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80",
"url": "https://api.github.com/repos/sabre-io/dav/zipball/b793fb4ce27cf0f981b540ad771281c430ffe818",
"reference": "b793fb4ce27cf0f981b540ad771281c430ffe818",
"shasum": ""
},
"require": {
@@ -631,27 +639,28 @@
"ext-date": "*",
"ext-dom": "*",
"ext-iconv": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-pcre": "*",
"ext-simplexml": "*",
"ext-spl": "*",
"lib-libxml": ">=2.7.0",
"php": ">=5.5.0",
"php": ">=7.0.0",
"psr/log": "^1.0",
"sabre/event": ">=2.0.0, <4.0.0",
"sabre/http": "^4.2.1",
"sabre/uri": "^1.0.1",
"sabre/vobject": "^4.1.0",
"sabre/xml": "^1.4.0"
"sabre/event": "^5.0",
"sabre/http": "^5.0",
"sabre/uri": "^2.0",
"sabre/vobject": "^4.2.0-alpha1",
"sabre/xml": "^2.0.1"
},
"require-dev": {
"evert/phpdoc-md": "~0.1.0",
"monolog/monolog": "^1.18",
"phpunit/phpunit": "> 4.8, <6.0.0",
"sabre/cs": "^1.0.0"
"phpunit/phpunit": "^6"
},
"suggest": {
"ext-curl": "*",
"ext-imap": "*",
"ext-pdo": "*"
},
"bin": [
@@ -659,11 +668,6 @@
"bin/naturalselection"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1.0-dev"
}
},
"autoload": {
"psr-4": {
"Sabre\\DAV\\": "lib/DAV/",
@@ -693,28 +697,28 @@
"framework",
"iCalendar"
],
"time": "2018-10-19T09:58:27+00:00"
"time": "2020-01-10T07:52:45+00:00"
},
{
"name": "sabre/event",
"version": "3.0.0",
"version": "5.0.3",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/event.git",
"reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534"
"reference": "f5cf802d240df1257866d8813282b98aee3bc548"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/event/zipball/831d586f5a442dceacdcf5e9c4c36a4db99a3534",
"reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534",
"url": "https://api.github.com/repos/sabre-io/event/zipball/f5cf802d240df1257866d8813282b98aee3bc548",
"reference": "f5cf802d240df1257866d8813282b98aee3bc548",
"shasum": ""
},
"require": {
"php": ">=5.5"
"php": ">=7.0"
},
"require-dev": {
"phpunit/phpunit": "*",
"sabre/cs": "~0.0.4"
"phpunit/phpunit": ">=6",
"sabre/cs": "~1.0.0"
},
"type": "library",
"autoload": {
@@ -744,38 +748,41 @@
"keywords": [
"EventEmitter",
"async",
"coroutine",
"eventloop",
"events",
"hooks",
"plugin",
"promise",
"reactor",
"signal"
],
"time": "2015-11-05T20:14:39+00:00"
"time": "2018-03-05T13:55:47+00:00"
},
{
"name": "sabre/http",
"version": "v4.2.4",
"version": "5.0.5",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/http.git",
"reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956"
"reference": "85962a2ed867e7e5beb9f9d3a15cd53cd521a09b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/http/zipball/acccec4ba863959b2d10c1fa0fb902736c5c8956",
"reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956",
"url": "https://api.github.com/repos/sabre-io/http/zipball/85962a2ed867e7e5beb9f9d3a15cd53cd521a09b",
"reference": "85962a2ed867e7e5beb9f9d3a15cd53cd521a09b",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-curl": "*",
"ext-mbstring": "*",
"php": ">=5.4",
"sabre/event": ">=1.0.0,<4.0.0",
"sabre/uri": "~1.0"
"php": "^7.0",
"sabre/event": ">=4.0 <6.0",
"sabre/uri": "^2.0"
},
"require-dev": {
"phpunit/phpunit": "~4.3",
"sabre/cs": "~0.0.1"
"phpunit/phpunit": "^6.0 || ^7.0"
},
"suggest": {
"ext-curl": " to make http requests with the Client class"
@@ -806,28 +813,27 @@
"keywords": [
"http"
],
"time": "2018-02-23T11:10:29+00:00"
"time": "2019-11-28T19:35:25+00:00"
},
{
"name": "sabre/uri",
"version": "1.2.1",
"version": "2.1.3",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/uri.git",
"reference": "ada354d83579565949d80b2e15593c2371225e61"
"reference": "18f454324f371cbcabdad3d0d3755b4b0182095d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/uri/zipball/ada354d83579565949d80b2e15593c2371225e61",
"reference": "ada354d83579565949d80b2e15593c2371225e61",
"url": "https://api.github.com/repos/sabre-io/uri/zipball/18f454324f371cbcabdad3d0d3755b4b0182095d",
"reference": "18f454324f371cbcabdad3d0d3755b4b0182095d",
"shasum": ""
},
"require": {
"php": ">=5.4.7"
"php": ">=7"
},
"require-dev": {
"phpunit/phpunit": ">=4.0,<6.0",
"sabre/cs": "~1.0.0"
"phpunit/phpunit": "^6"
},
"type": "library",
"autoload": {
@@ -857,20 +863,20 @@
"uri",
"url"
],
"time": "2017-02-20T19:59:28+00:00"
"time": "2019-09-09T23:00:25+00:00"
},
{
"name": "sabre/vobject",
"version": "4.2.0",
"version": "4.2.1",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/vobject.git",
"reference": "bd500019764e434ff65872d426f523e7882a0739"
"reference": "6d7476fbd227ae285029c19ad518cd451336038c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/vobject/zipball/bd500019764e434ff65872d426f523e7882a0739",
"reference": "bd500019764e434ff65872d426f523e7882a0739",
"url": "https://api.github.com/repos/sabre-io/vobject/zipball/6d7476fbd227ae285029c19ad518cd451336038c",
"reference": "6d7476fbd227ae285029c19ad518cd451336038c",
"shasum": ""
},
"require": {
@@ -953,20 +959,20 @@
"xCal",
"xCard"
],
"time": "2019-02-19T13:05:37+00:00"
"time": "2019-12-18T19:29:43+00:00"
},
{
"name": "sabre/xml",
"version": "1.5.1",
"version": "2.1.3",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/xml.git",
"reference": "a367665f1df614c3b8fefc30a54de7cd295e444e"
"reference": "f08a58f57e2b0d7df769a432756aa371417ab9eb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/xml/zipball/a367665f1df614c3b8fefc30a54de7cd295e444e",
"reference": "a367665f1df614c3b8fefc30a54de7cd295e444e",
"url": "https://api.github.com/repos/sabre-io/xml/zipball/f08a58f57e2b0d7df769a432756aa371417ab9eb",
"reference": "f08a58f57e2b0d7df769a432756aa371417ab9eb",
"shasum": ""
},
"require": {
@@ -974,12 +980,11 @@
"ext-xmlreader": "*",
"ext-xmlwriter": "*",
"lib-libxml": ">=2.6.20",
"php": ">=5.5.5",
"php": ">=7.0",
"sabre/uri": ">=1.0,<3.0.0"
},
"require-dev": {
"phpunit/phpunit": "~4.8|~5.7",
"sabre/cs": "~1.0.0"
"phpunit/phpunit": "^6"
},
"type": "library",
"autoload": {
@@ -1016,20 +1021,20 @@
"dom",
"xml"
],
"time": "2019-01-09T13:51:57+00:00"
"time": "2019-08-14T15:41:34+00:00"
},
{
"name": "simplepie/simplepie",
"version": "1.5.2",
"version": "1.5.4",
"source": {
"type": "git",
"url": "https://github.com/simplepie/simplepie.git",
"reference": "0e8fe72132dad765d25db4cabc69a91139af1263"
"reference": "f4c8246511a38fc9d99a59fb42f61eeeafb31663"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/simplepie/simplepie/zipball/0e8fe72132dad765d25db4cabc69a91139af1263",
"reference": "0e8fe72132dad765d25db4cabc69a91139af1263",
"url": "https://api.github.com/repos/simplepie/simplepie/zipball/f4c8246511a38fc9d99a59fb42f61eeeafb31663",
"reference": "f4c8246511a38fc9d99a59fb42f61eeeafb31663",
"shasum": ""
},
"require": {
@@ -1088,28 +1093,31 @@
"rss"
],
"support": {
"source": "https://github.com/simplepie/simplepie/tree/1.5.2",
"source": "https://github.com/simplepie/simplepie/tree/master",
"issues": "https://github.com/simplepie/simplepie/issues"
},
"time": "2018-08-02T05:43:58+00:00"
"time": "2019-11-23T07:05:15+00:00"
},
{
"name": "smarty/smarty",
"version": "v3.1.33",
"version": "v3.1.34",
"source": {
"type": "git",
"url": "https://github.com/smarty-php/smarty.git",
"reference": "dd55b23121e55a3b4f1af90a707a6c4e5969530f"
"reference": "c9f0de05f41b9e52798b268ab1e625fac3b8578c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/dd55b23121e55a3b4f1af90a707a6c4e5969530f",
"reference": "dd55b23121e55a3b4f1af90a707a6c4e5969530f",
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/c9f0de05f41b9e52798b268ab1e625fac3b8578c",
"reference": "c9f0de05f41b9e52798b268ab1e625fac3b8578c",
"shasum": ""
},
"require": {
"php": ">=5.2"
},
"require-dev": {
"phpunit/phpunit": "6.4.1"
},
"type": "library",
"extra": {
"branch-alias": {
@@ -1117,8 +1125,8 @@
}
},
"autoload": {
"files": [
"libs/bootstrap.php"
"classmap": [
"libs/"
]
},
"notification-url": "https://packagist.org/downloads/",
@@ -1144,20 +1152,20 @@
"keywords": [
"templating"
],
"time": "2018-09-12T20:54:16+00:00"
"time": "2019-02-28T06:42:20+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.10.0",
"version": "v1.13.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "e3d826245268269cd66f8326bd8bc066687b4a19"
"reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19",
"reference": "e3d826245268269cd66f8326bd8bc066687b4a19",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3",
"reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3",
"shasum": ""
},
"require": {
@@ -1169,7 +1177,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.9-dev"
"dev-master": "1.13-dev"
}
},
"autoload": {
@@ -1185,13 +1193,13 @@
"MIT"
],
"authors": [
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
},
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
@@ -1202,20 +1210,20 @@
"polyfill",
"portable"
],
"time": "2018-08-06T14:22:27+00:00"
"time": "2019-11-27T13:56:44+00:00"
},
{
"name": "twbs/bootstrap",
"version": "v4.3.1",
"version": "v4.4.1",
"source": {
"type": "git",
"url": "https://github.com/twbs/bootstrap.git",
"reference": "8fa0d3010112dca5dd6dd501173415856001ba8b"
"reference": "dca1ab7d877bc4b664b43604657a2b5fbe2b4ecb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twbs/bootstrap/zipball/8fa0d3010112dca5dd6dd501173415856001ba8b",
"reference": "8fa0d3010112dca5dd6dd501173415856001ba8b",
"url": "https://api.github.com/repos/twbs/bootstrap/zipball/dca1ab7d877bc4b664b43604657a2b5fbe2b4ecb",
"reference": "dca1ab7d877bc4b664b43604657a2b5fbe2b4ecb",
"shasum": ""
},
"replace": {
@@ -1232,13 +1240,13 @@
"MIT"
],
"authors": [
{
"name": "Jacob Thornton",
"email": "jacobthornton@gmail.com"
},
{
"name": "Mark Otto",
"email": "markdotto@gmail.com"
},
{
"name": "Jacob Thornton",
"email": "jacobthornton@gmail.com"
}
],
"description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
@@ -1253,7 +1261,7 @@
"sass",
"web"
],
"time": "2019-02-13T16:01:40+00:00"
"time": "2019-11-28T12:59:49+00:00"
}
],
"packages-dev": [
@@ -1695,6 +1703,7 @@
],
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
"homepage": "https://github.com/container-interop/container-interop",
"abandoned": "psr/container",
"time": "2017-02-14T19:40:03+00:00"
},
{

View File

@@ -0,0 +1,4 @@
<dl class="dl-horizontal">
<dt>Allgemein</dt>
<dd>Ändere die individuellen Eigenschaften der ausgewählten App. Kategorien erlauben dir das Einsortieren der Apps um sie in der Liste leichter zu finden. Kundenspezifische Apps, die du oder dein Administrator erstellt haben, können weitere Felder enthalten wie "Preis der App" oder "Ort (URL), um die App zu kaufen". Dies gilt nicht für Hubzilla Core Apps.</dd>
</dl>

View File

@@ -0,0 +1,4 @@
<dl class="dl-horizontal">
<dt>Allgemein</dt>
<dd>Ändere oder lösche deine Apps mit Hilfe der Steuerknöpfe neben jedem App-Icon in der Liste.</dd>
</dl>

View File

@@ -0,0 +1,6 @@
<dl class="dl-horizontal">
<dt>Allgemein</dt>
<dd>Diese Seite listet alle verfügbaren Apps für Deinen Kanal. Sie enthält die Core Apps wie auch die von Addons. Wenn eine App im <a href='#' onclick='contextualHelpFocus("#app-menu", 1); return false;' title="Klicke zum Öffnen...">App Menü</a> erscheinen soll, dann markiere die App in der Liste mit dem Stern.</dd>
<dt>Apps verwalten</dt>
<dd>Der Knopf "Apps verwalten" öffnet eine Seite, mit der Du den Namen, die Kategorie und andere Eigenschaften deiner Apps ändern kannst.</dd>
</dl>

View File

@@ -0,0 +1,19 @@
<dl class="dl-horizontal">
<dt>Allgemein</dt>
<dd>
Wenn du dich registriert und dir damit einen <i>Zugang</i> zum Grid verschafft hast, hast du ein <i>Profil</i> und einen <i>Kanal</i> erzeugt.
</dd>
<dt>Zugang</dt>
<dd>
Du hast <i>einen</i> Zugang, der sich aus deiner Emailadresse mit deinem Passwort zusammen setzt. Damit greifst du auf dein Profil und deinen Kanal zu.
<i>Du authetifizierst dich also einmal auf einem Hub von Hubzilla, und es erlaubt dir beliebig Profile und Kanäle anzulegen und dich mit anderen Leuten zu verbinden.</i>
</dd>
<dt>Profil</dt>
<dd>
Du bist sicherlich bei anderen Services im Internet registriert, wie irgendwelchen Foren oder anderen Online Communities. Überall hinterläßt du Informationen über dich wie deinen Geburtstag, dein Alter, dein Land und Ähnliches. Im Gegensatz zu anderen Services erlaubt dir Hubzilla das Anlegen <i>vieler verschiedener Profile</i>. So kannst du ein öffentliches Profil anlegen, das zur allgemeinen Verwendung gedacht ist, ein Profil für deine Arbeitskollegen, deine Familie oder deinen Lebenspartner. <i>Deine Profile sind die grundlegende Information, die du anderen Leuten je nach Beziehung zur Verfügung stellen willst</i>.
</dd>
<dt>Kanal</dt>
<dd>
Während der Registrierung hast du deinen ersten <i>Kanal</i> erzeugt. In der Tat, neben verschiedenen Profilen kannst du auch verschiedene Kanäle haben. Das könnte etwas verwirrend sein am Anfang, aber lass uns die Dinge besser verstehen. Du hast also bereits einen Kanal erstellt, den du zum Beispiel für die breite Öffentlichkeit und für den Alltag verwenden kannst. Aber vielleicht bist du ein Bücherwurm, und viele deiner Leser langweilt das. Also eröffnest Du einen <i>zweiten Kanal</i> für Bücherfreunde, in dem ihr euch ungezwungen über Bücher austauschen könnt. Offensichtlich ergibt sich daraus ein neuer Stream von Beiträgen, womöglich mit einem neuen Profil oder neuen Profilen und komplett eigenen Verbindungen oder Kontakten. Einige finden sich in beiden Kanälen, aber die meisten werden wohl nur in einem der Kanäle mitlesen. Du wechselst zwischen den Kanälen wie im richtigen Leben je nachdem, ob du dich auf der Straße mit Leuten triffst oder mit Bücherfreunden sprichst. Im Prinzip können sich deine Kanäle auch untereinander verbinden, du also mit dir selbst sprechen, wenn du das möchtest. <i>Deine Kanäle sind also wie Räume für unterschiedliche Themen, in denen du auf verschiedene Leute triffst</i>.
</dd>
</dl>

View File

@@ -0,0 +1,19 @@
<dl class="dl-horizontal">
<dt>Allgemein</dt>
<dd>
Wenn du dich registriert und dir damit einen <i>Zugang</i> zum Grid verschafft hast, hast du ein <i>Profil</i> und einen <i>Kanal</i> erzeugt.
</dd>
<dt>Zugang</dt>
<dd>
Du hast <i>einen</i> Zugang, der sich aus deiner Emailadresse mit deinem Passwort zusammensetzt. Damit greifst du auf dein Profil und deinen Kanal zu.
<i>Du authetifizierst dich also einmal auf einem Hub von Hubzilla, und es erlaubt dir beliebig Profile und Kanäle anzulegen und dich mit anderen Leuten zu verbinden.</i>
</dd>
<dt>Profil</dt>
<dd>
Du bist sicherlich bei anderen Services im Internet registriert, wie irgendwelchen Foren oder anderen Online Communities. Überall hinterläßt du Informationen über dich wie deinen Geburtstag, dein Alter, dein Land und Ähnliches. Im Gegensatz zu anderen Services erlaubt dir Hubzilla das Anlegen <i>vieler verschiedener Profile</i>. So kannst du ein öffentliches Profil anlegen, das zur allgemeinen Verwendung gedacht ist, ein Profil für deine Arbeitskollegen, deine Familie oder deinen Lebenspartner. <i>Deine Profile sind die grundlegende Information, die du anderen Leuten je nach Beziehung zur Verfügung stellen willst</i>.
</dd>
<dt>Kanal</dt>
<dd>
Während der Registrierung hast du deinen ersten <i>Kanal</i> erzeugt. In der Tat, neben verschiedenen Profilen kannst du auch verschiedene Kanäle haben. Das könnte etwas verwirrend sein am Anfang, aber lass uns die Dinge besser verstehen. Du hast also bereits einen Kanal erstellt, den du zum Beispiel für die breite Öffentlichkeit und für den Alltag verwenden kannst. Aber vielleicht bist du ein Bücherwurm und viele deiner Leser langweilt das. Also eröffnest Du einen <i>zweiten Kanal</i> für Bücherfreunde, in dem ihr euch ungezwungen über Bücher austauschen könnt. Offensichtlich ergibt sich daraus ein neuer Stream von Beiträgen, womöglich mit einem neuen Profil oder neuen Profilen und komplett eigenen Verbindungen oder Kontakten. Einige finden sich in beiden Kanälen, aber die meisten werden wohl nur in einem der Kanäle mitlesen. Du wechselst zwischen den Kanälen wie im richtigen Leben je nachdem, ob du dich auf der Straße mit Leuten triffst oder mit Bücherfreunden sprichst. Im Prinzip können sich deine Kanäle auch untereinander verbinden, du also mit dir selbst sprechen, wenn du das möchtest. <i>Deine Kanäle sind also wie Räume für unterschiedliche Themen, in denen du auf verschiedene Leute triffst</i>.
</dd>
</dl>

View File

@@ -0,0 +1,12 @@
<dl class="dl-horizontal">
<dt>Allgemein</dt>
<dd>Diese Seite ermöglicht dir viele zusätzliche Funktionen von Hubzilla einzustellen.</dd>
<dt><a href='#' onclick='$("#general-settings-title h3 a").click(); setTimeout((function() {contextualHelpFocus("#general-settings-title", 0)}), 1000); return false;' title="Klicken um das Element anzuzeigen...">Allgemeine Funktionen</a></dt>
<dd>Die Einstellungen für allgemeine Funktionen beinhalten Optionen, die relevant sind für deinen Kanal, zum Beispiel bei Webseiten oder Wikis.</dd>
<dt><a href='#' onclick='$("#composition-settings-title h3 a").click(); setTimeout((function() {contextualHelpFocus("#composition-settings-title", 0)}), 1000); return false;' title="Klicken um das Element anzuzeigen...">Funktionen für die Beitragserstellung</a></dt>
<dd>Diese Funktionen bieten weitere Optionen und Möglichkeiten für die Erstellung neuer Beiträge.</dd>
<dt><a href='#' onclick='$("#net_module-settings-title h3 a").click(); setTimeout((function() {contextualHelpFocus("#net_module-settings-title", 0)}), 1000); return false;' title="Klicken um das Element anzuzeigen...">Filterung von Streams</a></dt>
<dd>Diese Einstellungen verändern Funktionen, die mit der Filterung und der Ansichtskontrolle enkommender Beiträge verbunden sind.</dd>
<dt><a href='#' onclick='$("#tools-settings-title h3 a").click(); setTimeout((function() {contextualHelpFocus("#tools-settings-title", 0)}), 1000); return false;' title="Klicken um das Element anzuzeigen...">Werkzeuge für Beiträge und Kommentare</a></dt>
<dd>Hier findest du zusätzliche Werkzeuge um Beiträge zu kategorisieren, und erweiterte Methoden der Kommentierung wie Emojis und Community Tagging.</dd>
</dl>

View File

@@ -0,0 +1,20 @@
<dl class="dl-horizontal">
<dt><a href="/help/member/member_guide#Guest_Access_Tokens">Gastzugangs-Token</a></dt>
<dd>
Hubzilla verwendet befristete "Wegwerf"-Logins oder "Zot Access Tokens", um das Teilen privater Informationen mit Nichtmitgliedern oder Mitgliedern im Fediverse zu ermöglichen, deren Knoten nur eingeschränkte Möglichkeiten zur Identifizierung bieten. Diese Token können zur Authentifizierung an einem Hub für den Zweck verwendet werden privilegierte oder zugangskontrollierte Ressourcen (Dateien, Fotos, Beiträge, Webseiten, Chaträume, usw.) zugänglich zu machen.
</dd>
<dt>Einen Token erzeugen</dt>
<dd>
Das Formular zur Erzeugung von Token benötigt drei Parameter: einen lesbaren Zugangsnamen, ein Passwort oder Zugangs-Token, und optional ein Verfallsdatum. Ein verfallenes Token kann nicht länger verwendet werden und wird von der Liste befristeter Zugänge entfernt. <i>Hinweis</i> Das Passwort-Feld zeigt das Token oder Passwort im Klartext.
</dd>
<dt>Einen Token teilen</dt>
<dd>
Wir geben keine Mechanismen für das Teilen der Zugangs-Token vor, jede Kommunikationsmethode ist recht. Alle Token, die du erzeugt hast, werden zu den Listen für die Zugangskontrolle hinzugefügt und können von überall verwendet werden, wo anhand dieser Listen authentifiziert werden kann.
<b>Ein Beispiel:</b> Ein Besucher trifft auf deine Seite. Er hat ein von dir zur Verfügung gestelltes Zugangs-Token für eines Deiner Fotoalben, das nur von Dir und eben diesem befristeten Zugangsnamen betrachtet werden darf. Der Besucher erhält zunächst keinen Zugang.
Nun wählt er "Login" aus der Navigation und erhält die Loginseite angezeigt, in die er seine Zugangsdaten eingibt. Ab sofort erhält er Zugang zum Fotoalbum.
Alternativ kannst du einen Link mit deinem Besucher teilen, dessen URL um den Parameter "&zat=abc123" erweitert ist, wobei "abc123" das Zugangs-Token oder das Passwort für den befristeten Login ist. Mit dieser Erweiterung ist kein Login erforderlich, der Besucher erhält sofort den Zugang.
</dd>
</dl>

View File

@@ -1,3 +1,12 @@
[h2]Database updates[/h2]
In the [observer.baseurl]/admin/dbsync page the administrator can check if any update was not successful and, if so, retry it.
If an update has failed but doesn't register as failed for some reason, the administrator can attempt to re-execute the update. For example for DB update #1999, by visiting the webpage:
https://hubzilla.com.bradmin/dbsync/1999
[h2]Database Tables[/h2][table border=1][tr][th]Table[/th][th]Description[/th][/tr]
[tr][td][zrl=[baseurl]/help/database/db_abconfig]abconfig[/zrl][/td][td]arbitrary storage for connections of local channels[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_abook]abook[/zrl][/td][td]connections of local channels[/td][/tr]

View File

@@ -1,7 +1,10 @@
[h1]Advanced Configurations for Administrators[/h1]
$Projectname contains many configuration options hidden from the main admin panel.
These are generally options considered too niche, confusing, or advanced for the average member. These settings can be activated from the the top level web directory with the syntax
[i]This document assumes you're an administrator.[/i]
$Projectname contains many configuration options hidden from the main admin panel. These are generally options considered too niche, advanced or prone do confusion.
These settings can be modified through the shell, from the the top level web directory, with the syntax:
[code]util/config cat key value[/code]
for a site configuration, or
@@ -9,8 +12,13 @@ for a site configuration, or
[code]util/pconfig channel_id cat key value[/code]
for a member configuration.
This document assumes you're an administrator.
[h2]pconfig[/h2][dl terms="mb"]
For a site configuration, another option is to add a line to .htconfig.php, with the syntax:
[code]App::$config['cat']['key'] = 'value';[/code]
[h2]Member configuration (pconfig)[/h2]
[dl terms="mb"]
[*= system.always_my_theme ] Always use your own theme when viewing channels on the same hub. This will break in some quite imaginative ways when viewing channels with theme dependent Comanche.
[*= system.blocked ] An array of xchans blocked by this channel. Technically, this is a hidden config and does belong here, however, addons (notably superblock) have made this available in the UI.
[*= system.default_cipher ] Set the default cipher used for E2EE items.
@@ -31,7 +39,10 @@ Options are:
[*= system.anonymous_comments ] By default or if set to 1, custom permissions can be set to allow anonymous (moderated) comments like WordPress, moderated by the channel owner. If set to 0, no member of your site can select or enable this.
[*= system.user_scalable ] Determine if the app is scalable on touch screens. Defaults to on, to disable, set to zero - real zero, not just false.
[/dl]
[h2]Site config[/h2][dl terms="mb"]
[h2]Site configuration[/h2]
[dl terms="mb"]
[*= randprofile.check ] When requesting a random profile, check that it actually exists first
[*= randprofile.retry ] Number of times to retry getting a random profile
[*= system.admin_email ] Specifies the administrator's email for this site. This is initially set during install.
@@ -62,11 +73,13 @@ Options are:
[*= system.max_tagged_forums ] Spam prevention. Limits the number of tagged forums which are recognised in any post. Default is 2. Only the first 'n' tags will be delivered as forums, the others will not cause any delivery.
[*= system.minimum_feedcheck_minutes ] The minimum interval between polling RSS feeds. If this is lower than the cron interval, feeds will be polled with each cronjob. Defaults to 60 if not set. The site setting can also be over-ridden on a channel by channel basis by a service class setting aptly named 'minimum_feedcheck_minutes'.
[*= system.no_age_restriction ] Do not restrict registration to people over the age of 13. This carries legal responsibilities in many countries to require that age be provided and to block all personal information from minors, so please check your local laws before changing.
[*= system.object_cache_days] Set how long is cached embedded content can be used without refetching. Default is 30 days.
[*= system.openssl_conf_file ] Specify a file containing OpenSSL configuration. Needed in some Windows installations to locate the openssl configuration file on the system. Read the code first. If you can't read the code, don't play with it.
[*= system.openssl_encrypt ] Use openssl encryption engine, default is false (uses mcrypt for AES encryption)
[*= system.optimize_items ] Runs optimise_table during some tasks to keep your database nice and defragmented. This comes at a performance cost while the operations are running, but also keeps things a bit faster while it's not. There also exist CLI utilities for performing this operation, which you may prefer, especially if you're a large site.
[*= system.override_poll_lockfile ] Ignore the lock file in the poller process to allow more than one process to run at a time.
[*= system.paranoia ] As the pconfig, but on a site-wide basis. Can be overwritten by member settings.
[*= system.pin_types ] Array of allowed item types for pinning. Defaults depend on module but can be redifined here.
[*= system.photo_cache_time ] How long to cache photos, in seconds. Default is 86400 (1 day). Longer time increases performance, but it also means it takes longer for changed permissions to apply.
[*= system.platform_name ] What to report as the platform name in webpages and statistics. (*) Must be set in .htconfig.php
[*= system.rating_enabled ] Distributed reputation reporting and data collection. This feature is currently being re-worked.
@@ -87,13 +100,19 @@ Options are:
[*= system.workflow_channel_next ] The page to direct new members to immediately after creating a channel.
[*= system.workflow_register_next ] The page to direct members to immediately after creating an account (only when auto_channel_create or UNO is enabled).
[/dl]
[h2]Directory config[/h2]
[h3]Directory search defaults[/h3][dl terms="mb"]
[h3]Directory config[/h3]
[h4]Directory search defaults[/h4]
[dl terms="mb"]
[*= directory.globaldir ] 0 or 1. Default 0. If you visit the directory on a site you'll just see the members of that site by default. You have to go through an extra step to see the people in the rest of the network; and by doing so there's a clear delineation that these people *aren't* members of that site but of a larger network.
[*= directory.pubforums ] 0 or 1. Public forums [i]should[/i] be default 0.
[*= directory.safemode ] 0 or 1.
[/dl]
[h3]Directory server configuration[/h3][i](see [zrl=[baseurl]/help/directories]help/directories[/zrl])[/i]
[h4]Directory server configuration[/h4][i](see [zrl=[baseurl]/help/directories]help/directories[/zrl])[/i]
[dl terms="mb"]
[*= system.directory_mode ]

View File

@@ -0,0 +1 @@
[h2]activity_decode_mapper[/h2]

View File

@@ -0,0 +1 @@
[h2]activity_mapper[/h2]

View File

@@ -0,0 +1 @@
[h2]activity_obj_decode_mapper[/h2]

View File

@@ -0,0 +1 @@
[h2]activity_obj_mapper[/h2]

View File

@@ -0,0 +1,11 @@
[h3]comments_are_now_closed[/h3]
Called when deciding whether or not commenting is closed for an item.
Hook data (array):
item => posted item
closed => 'unset'
To over-ride the default behaviour, change closed to true or false

View File

@@ -0,0 +1 @@
[h2]encode_object[/h2]

View File

@@ -0,0 +1 @@
[h2]fetch_and_store[/h2]

View File

@@ -34,6 +34,18 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
[zrl=[baseurl]/help/hook/activity_filter]activity_filter[/zrl]
Called when generating the list of filters for the network page
[zrl=[baseurl]/help/hook/activity_filter]activity_mapper[/zrl]
Called when determining the activity type for transmission.
[zrl=[baseurl]/help/hook/activity_filter]activity_decode_mapper[/zrl]
Called when determining the activity type for transmission.
[zrl=[baseurl]/help/hook/activity_filter]activity_obj_mapper[/zrl]
Called when determining the object type for transmission.
[zrl=[baseurl]/help/hook/activity_filter]activity_obj_decode_mapper[/zrl]
Called when determining the object type for transmission.
[zrl=[baseurl]/help/hook/activity_order]activity_order[/zrl]
Called when generating the list of order options for the network page
@@ -142,6 +154,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
[zrl=[baseurl]/help/hook/comment_buttons]comment_buttons[/zrl]
Called when rendering the edit buttons for comments
[zrl=[baseurl]/help/hook/comments_are_now_closed]comments_are_now_closed[/zrl]
Called when deciding whether or not to present a comment box for a post
[zrl=[baseurl]/help/hook/connect_premium]connect_premium[/zrl]
Called when connecting to a premium channel
@@ -232,6 +247,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
[zrl=[baseurl]/help/hook/drop_item]drop_item[/zrl]
called when an 'item' is removed
[zrl=[baseurl]/help/hook/encode_object]encode_object[/zrl]
called when encoding an object for transmission.
[zrl=[baseurl]/help/hook/enotify]enotify[/zrl]
called before any notification
@@ -241,6 +259,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
[zrl=[baseurl]/help/hook/enotify_store]enotify_store[/zrl]
called when storing a notification record
[zrl=[baseurl]/help/hook/enotify_store_end]enotify_store_end[/zrl]
called after a notification record has been stored
[zrl=[baseurl]/help/hook/event_created]event_created[/zrl]
called when an event record is created
@@ -262,6 +283,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
[zrl=[baseurl]/help/hook/feature_settings_post]feature_settings_post[/zrl]
called from settings page when posting from 'addon/feature settings'
[zrl=[baseurl]/help/hook/fetch_and_store]fetch_and_store[/zrl]
called to allow filtering of 'decoded' items before storage.
[zrl=[baseurl]/help/hook/file_thumbnail]file_thumbnail[/zrl]
called when generating thumbnail images for cloud page in 'view tiles' mode

View File

@@ -37,7 +37,8 @@
<div class="flex-column">
<a class="nav-link" href="/help/admin/administrator_guide">Guide</a>
<a class="nav-link" href="/help/admin/hub_snapshots">Hub Snapshots</a>
<a class="nav-link" href="/help/database">Database Tables</a>
<a class="nav-link" href="/help/database">Database</a>
<a class="nav-link" href="/help/hidden_configs">Extra configs</a>
</div>
</div>
</div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 559 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 B

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