Compare commits

..

261 Commits
4.6 ... 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
Max Kostikov
ec68ede79f Merge branch 'dev' into 'dev'
Dev sync

See merge request kostikov/core!4
2019-11-08 23:39:04 +01:00
1013 changed files with 47403 additions and 28744 deletions

View File

@@ -66,7 +66,6 @@ Hubzilla 4.6 (2019-12-04)
- 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

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

View File

@@ -44,6 +44,12 @@ 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(),

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

@@ -168,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]);
}
}
@@ -220,7 +224,7 @@ class Activity {
'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']) {
@@ -321,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'])
@@ -572,8 +592,15 @@ class Activity {
}
}
$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 ]));
@@ -611,10 +638,10 @@ class Activity {
if($i['id'] != $i['parent']) {
$reply = true;
// inReplyTo needs to be set in the activity for followup actiions (Like, Dislike, Attend, Announce, etc.),
// but *not* for comments, where it should only be present in the object
if (! in_array($ret['type'],[ 'Create','Update' ])) {
// 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']));
}
@@ -672,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'])) {
@@ -822,7 +852,8 @@ 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);
@@ -868,7 +899,8 @@ 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);
@@ -902,7 +934,8 @@ 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);
@@ -922,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',
@@ -941,11 +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];
}
@@ -1596,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;
@@ -1634,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;
@@ -1664,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']);
}
@@ -1693,38 +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['name'];
$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 {
@@ -1766,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
@@ -1957,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);
@@ -2048,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'])
);
@@ -2078,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'];
}

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,14 +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' AND updated > %s - INTERVAL %s LIMIT 1",
dbesc($hash),
db_utcnow(),
db_quoteinterval(get_config('system','object_cache_days', '30') . ' DAY')
db_quoteinterval(($age ? $age : get_config('system','object_cache_days', '30') . ' DAY'))
);
if ($r)
@@ -43,4 +52,3 @@ class Cache {
}
}
}

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

@@ -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,8 +1220,8 @@ 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']) {
@@ -1277,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) {
@@ -1608,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();
@@ -1634,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

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);
@@ -863,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

@@ -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);
}
@@ -1190,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();
}
@@ -1201,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();
}
@@ -1408,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();
}
@@ -1460,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

@@ -419,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,
@@ -468,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

@@ -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)
@@ -323,6 +345,7 @@ class Connections extends \Zotlabs\Web\Controller {
'recent_label' => t('Recent activity'),
'recentlink' => z_root() . '/network/?f=&cid=' . intval($rr['abook_id']) . '&name=' . $rr['xchan_name'],
'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

@@ -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, true),
'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 = '';
@@ -924,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;
}
@@ -972,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;
@@ -1389,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

@@ -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 = '';

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

@@ -65,11 +65,6 @@ class Well_known extends \Zotlabs\Web\Controller {
killme();
case 'caldav':
if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
http_status('301', 'moved permanently');
goaway(z_root() . '/cdav');
};
case 'carddav':
if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
http_status('301', 'moved permanently');

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

@@ -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

@@ -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.6' );
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();
@@ -1812,6 +1819,8 @@ function can_view_public_stream() {
* @param string $s Text to display
*/
function notice($s) {
/*
if(! session_id())
return;
@@ -1827,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);
}
}
/**
@@ -1840,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();
@@ -1850,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);
}
}
/**

165
composer.lock generated
View File

@@ -8,16 +8,16 @@
"packages": [
{
"name": "blueimp/jquery-file-upload",
"version": "v10.3.0",
"version": "v10.7.0",
"source": {
"type": "git",
"url": "https://github.com/vkhramtsov/jQuery-File-Upload.git",
"reference": "63cb566b29a5407cfbfbda8a5154e10b6e098678"
"reference": "4677050d31be2da817e1d23d0bacb81fb4b37cb3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vkhramtsov/jQuery-File-Upload/zipball/63cb566b29a5407cfbfbda8a5154e10b6e098678",
"reference": "63cb566b29a5407cfbfbda8a5154e10b6e098678",
"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-11-04T09:18:09+00:00"
"time": "2020-01-04T05:46:30+00:00"
},
{
"name": "bshaffer/oauth2-server-php",
@@ -251,16 +251,16 @@
},
{
"name": "league/html-to-markdown",
"version": "4.9.0",
"version": "4.9.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/html-to-markdown.git",
"reference": "71319108e3db506250b8987721b13568fd9fa446"
"reference": "1dcd0f85de786f46a7f224a27cc3d709ddd2a68c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/71319108e3db506250b8987721b13568fd9fa446",
"reference": "71319108e3db506250b8987721b13568fd9fa446",
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/1dcd0f85de786f46a7f224a27cc3d709ddd2a68c",
"reference": "1dcd0f85de786f46a7f224a27cc3d709ddd2a68c",
"shasum": ""
},
"require": {
@@ -311,7 +311,7 @@
"html",
"markdown"
],
"time": "2019-11-02T14:54:14+00:00"
"time": "2019-12-28T01:32:28+00:00"
},
{
"name": "lukasreschke/id3parser",
@@ -350,21 +350,24 @@
},
{
"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",
@@ -532,44 +535,46 @@
},
{
"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": "4.0.2",
"version": "4.0.3",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/dav.git",
"reference": "fd0234d46c045fc9b35ec06bd2e7b490240e6ade"
"reference": "b793fb4ce27cf0f981b540ad771281c430ffe818"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/dav/zipball/fd0234d46c045fc9b35ec06bd2e7b490240e6ade",
"reference": "fd0234d46c045fc9b35ec06bd2e7b490240e6ade",
"url": "https://api.github.com/repos/sabre-io/dav/zipball/b793fb4ce27cf0f981b540ad771281c430ffe818",
"reference": "b793fb4ce27cf0f981b540ad771281c430ffe818",
"shasum": ""
},
"require": {
@@ -689,7 +697,7 @@
"framework",
"iCalendar"
],
"time": "2019-10-19T07:17:49+00:00"
"time": "2020-01-10T07:52:45+00:00"
},
{
"name": "sabre/event",
@@ -753,16 +761,16 @@
},
{
"name": "sabre/http",
"version": "5.0.4",
"version": "5.0.5",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/http.git",
"reference": "73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72"
"reference": "85962a2ed867e7e5beb9f9d3a15cd53cd521a09b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/http/zipball/73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72",
"reference": "73e2fa1ef894eddff145b698b6b0e2e2c5bf1d72",
"url": "https://api.github.com/repos/sabre-io/http/zipball/85962a2ed867e7e5beb9f9d3a15cd53cd521a09b",
"reference": "85962a2ed867e7e5beb9f9d3a15cd53cd521a09b",
"shasum": ""
},
"require": {
@@ -805,7 +813,7 @@
"keywords": [
"http"
],
"time": "2019-10-09T20:27:43+00:00"
"time": "2019-11-28T19:35:25+00:00"
},
{
"name": "sabre/uri",
@@ -859,16 +867,16 @@
},
{
"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": {
@@ -951,7 +959,7 @@
"xCal",
"xCard"
],
"time": "2019-02-19T13:05:37+00:00"
"time": "2019-12-18T19:29:43+00:00"
},
{
"name": "sabre/xml",
@@ -1017,16 +1025,16 @@
},
{
"name": "simplepie/simplepie",
"version": "1.5.3",
"version": "1.5.4",
"source": {
"type": "git",
"url": "https://github.com/simplepie/simplepie.git",
"reference": "173663382a9346acd53df60c7ffb20689c9cf1f6"
"reference": "f4c8246511a38fc9d99a59fb42f61eeeafb31663"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/simplepie/simplepie/zipball/173663382a9346acd53df60c7ffb20689c9cf1f6",
"reference": "173663382a9346acd53df60c7ffb20689c9cf1f6",
"url": "https://api.github.com/repos/simplepie/simplepie/zipball/f4c8246511a38fc9d99a59fb42f61eeeafb31663",
"reference": "f4c8246511a38fc9d99a59fb42f61eeeafb31663",
"shasum": ""
},
"require": {
@@ -1085,10 +1093,10 @@
"rss"
],
"support": {
"source": "https://github.com/simplepie/simplepie/tree/1.5.3",
"source": "https://github.com/simplepie/simplepie/tree/master",
"issues": "https://github.com/simplepie/simplepie/issues"
},
"time": "2019-09-22T23:21:30+00:00"
"time": "2019-11-23T07:05:15+00:00"
},
{
"name": "smarty/smarty",
@@ -1148,16 +1156,16 @@
},
{
"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

@@ -79,6 +79,7 @@ Options are:
[*= 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.

View File

@@ -259,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

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 853 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1015 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1004 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 999 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 612 B

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