Compare commits

...

200 Commits
6.4.2 ... 7.0.3

Author SHA1 Message Date
Mario
53c842c614 Merge branch 'dev' 2022-02-10 19:50:28 +00:00
Mario
23ececeb34 changelog and version 2022-02-10 19:48:52 +00:00
Mario
521c9eb566 Merge branch 'dev' 2022-02-10 19:45:08 +00:00
Mario
35877b1382 allow to override the DB charset via the $db_charset variable in .htconfig.php 2022-02-10 18:57:44 +00:00
Mario
c531287170 fix php8.1 deprecation warning 2022-02-09 19:25:55 +00:00
Mario
8e79a81b88 Merge branch 'dev' 2022-02-09 12:10:04 +00:00
Mario
b95ceb301f gc() returns bool 2022-02-09 12:09:33 +00:00
Mario
76a94495c4 Merge branch 'dev' 2022-02-09 12:02:00 +00:00
Mario
b6b2299b4e revert: union types are only possible from php version 8 and higher 2022-02-09 12:01:16 +00:00
Mario
34ddea87d3 version 2022-02-09 09:54:02 +00:00
Mario
3d318542cb Merge branch 'dev' 2022-02-09 09:50:08 +00:00
Mario
4a8c3cdc61 changelog 2022-02-09 09:49:46 +00:00
Mario
c0b6f2d95f fix missing asterisk 2022-02-09 09:23:12 +00:00
Mario
9ca7fccab8 Merge branch 'dandauge-dev-patch-55065' into 'dev'
Update register_verify_eml.tpl

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

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

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

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

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

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

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

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

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

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

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

See merge request hubzilla/core!1995
2021-12-17 22:42:36 +00:00
Max Kostikov
9c790e5a90 Update Russian translation 2021-12-18 00:39:47 +02:00
Mario
9c79b5be77 version 2021-12-17 21:10:00 +00:00
Mario
2d9a4f4e42 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-12-17 21:08:54 +00:00
Mario
565602538c main.js simplify notify_id checks 2021-12-17 21:08:20 +00:00
Mario Vavti
78972725ae mod tokens cleanup and fixes 2021-12-17 22:05:45 +01:00
Mario
5ab90f7791 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-12-17 20:29:06 +01:00
Mario
b90d98fc2b implement background deleting of items in contact_remove() 2021-12-17 20:26:36 +01:00
Mario
eca3ae393b daemon to delete abbok items in the background 2021-12-17 19:25:28 +00:00
Mario
2bd69495d2 missing file 2021-12-17 19:52:54 +01:00
Mario
bfd3da43ac access token refactor 2021-12-17 19:48:09 +01:00
Mario
32a9eaf3b6 update db schemas 2021-12-17 15:30:26 +01:00
Mario
91cea1f28a add template 2021-12-17 15:01:25 +01:00
Mario
220ed35f58 implement contact role deletion 2021-12-17 14:59:25 +01:00
Mario
b1cf5d4e44 nag channel owners to select achannel role if they have not yet done so yet 2021-12-15 12:58:33 +00:00
Mario
fe330ec1bb bump version 2021-12-15 12:18:07 +00:00
Mario
2968bf8241 merge branch perms_ng into dev 2021-12-15 12:17:19 +00:00
177 changed files with 25189 additions and 23319 deletions

View File

@@ -1,3 +1,81 @@
Hubzilla 7.0.3 (2022-02-10)
- Allow to override the charset for the PDO connection string via $db_charset in .htconfig.php
Hubzilla 7.0.2 (2022-02-09)
- Update french templates
- Add charset to the PDO connection strings
- Introduce delete keytype for get_activitystreams_key()
- Fix PHP error in Daemon/Externals
- Improved actor cache handling
- Implement manual fetch of packed local links
- Add JSalmon data to the meta field instead of data in Lib/ActivityStreams
- Fix some PHP8.1 deprecation warnings
- Fix delivery report for likes not found in some cases
- Allow zotfinger to recurse through all known hublocs if the one we got does not exist (404) or got removed (410)
- Diaspora: improve relaying of comments
- Fix regression in mod hcard
- Add the LD signature in Daemon/Notifier in case where there is no signed data available
- Prevent zot6 packet being saved as AP raw message
- Attach iconfig to the activity instead of the activity object
Addons
- Pubcrawl: make sure the sys channel falls through the app installed check
- Pubcrawl: improve local delivery of shared inbox items
Hubzilla 7.0.1 (2022-01-28)
- Fix removing contacts from privacy groups in the contact edit modal
- Fix escape_tags() messing with URLs in actor_store()
- Fix pagination in the cards module if a category is selected
- Remove unused entries in webfinger
- Remove deprecated mail app from apps
- Set item_hidden for forum comment announces
- Fix relaying of signed messages for activitypub
- Fix contact role permissions not re-assigned if the role permission has changed
- Fix default channel role not set in rare cases
Addons
- Pubcrawl: fix webfinger not returning the fetched URL
- Pubcrawl: improved queue handling for rejected deliveries
Hubzilla 7.0 (2022-01-21)
- Provide theme_color and background_color in App::$theme_info for usage in page meta and manifest
- PWA improvements according to lighthouse
- Refactor mod profile_photo
- Remove core legacy mail code
- Set session samesite cookie flag
- Improve toc bbcode for more flexible usecases
- Deprecate include/group in favor of Lib/AccessList
- Deprecate AccessList::widget()
- Mark forum channel profile images with a small icon in the timelines
- Improve privacy groups UI/UX
- Do not show connections widget if there are no connections
- Remove suggestions widget from various modules
- Provide guest access links for private resources in lockview
- Improve pconfig syncing
- deprecate include/group in favor of Lib/AccessList
- Implement background deleting of items in contact_remove()
- Refactor guest access tokens for better usability and provide quick access
- Refactor permissions handling
- Improved poll rendering
Bugfixes
- Fix items not deleted on remote channel purge
- Fix plink in post_activity_item()
- Fix multiple update_poll() calls dismissed in queueworker
- Fix blocked or ignored contacts displayed in connections
- Fix polls for forum channels
Addons:
- Legacy mail: remove
- Deprecate include/group in favor of Lib/AccessList
- Pubcrawl: support pleroma end time for polls
- Pubcrawl: slightly adjust the way we check mastodon direct messages
- Socialauth: scope support and improvements
Hubzilla 6.4.2 (2021-12-14)
- Fix issue in mod sse_bs where returning message id's were assumed to be base64 encoded
- Fix announce activity type not registered as response activity

View File

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

View File

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

View File

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

View File

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

View File

@@ -133,7 +133,9 @@ class Externals {
continue;
}
Libzot::fetch_conversation($importer, $message['object']['id']);
$obj_id = isset($message['object']['id']) ?? $message['object'];
Libzot::fetch_conversation($importer, $obj_id);
$total++;
continue;
}

View File

@@ -5,6 +5,7 @@ namespace Zotlabs\Daemon;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\Queue;
use Zotlabs\Lib\LDSignatures;
require_once('include/html2plain.php');
require_once('include/conversation.php');
@@ -78,6 +79,10 @@ class Notifier {
static public $encoded_item = null;
static public $channel = null;
static public $private = false;
// $fragment can contain additional info to omit de-duplication in the queueworker.
// E.g. if an item is updated many times in a row from different sources (multiple vote updates) the
// update source mid or a timestamp or random string can be added.
static public $fragment = null;
static public function run($argc, $argv) {
@@ -88,7 +93,6 @@ class Notifier {
logger('notifier: invoked: ' . print_r($argv, true), LOGGER_DEBUG);
$cmd = $argv[1];
$item_id = $argv[2];
if (!$item_id) {
@@ -103,6 +107,7 @@ class Notifier {
self::$encoded_item = null;
self::$channel = null;
self::$private = false;
self::$fragment = null;
$sys = get_sys_channel();
$normal_mode = true;
@@ -222,6 +227,8 @@ class Notifier {
// Fetch the target item
self::$fragment = $argv[3] ?? '';
$r = q("SELECT * FROM item WHERE id = %d AND parent != 0",
intval($item_id)
);
@@ -234,7 +241,7 @@ class Notifier {
$target_item = $r[0];
if (in_array($target_item['author']['xchan_network'], ['rss', 'anon'])) {
if (in_array($target_item['author']['xchan_network'], ['rss', 'anon', 'token'])) {
logger('notifier: target item author is not a fetchable actor', LOGGER_DEBUG);
return;
}
@@ -330,12 +337,14 @@ class Notifier {
self::$encoded_item = json_decode($m, true);
}
else {
self::$encoded_item = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], Activity::encode_activity($target_item)
);
self::$encoded_item['signature'] = LDSignatures::sign(self::$encoded_item, self::$channel);
}
logger('target_item: ' . print_r($target_item, true), LOGGER_DEBUG);
@@ -630,6 +639,18 @@ class Notifier {
// default: zot protocol
// Prevent zot6 delivery of group comment boosts, which are not required for conversational platforms.
// ActivityPub conversational platforms may wish to filter these if they don't want or require them.
// We will assume here that if $target_item exists and has a verb that it is an actual item structure
// so we won't need to check the existence of the other item fields prior to evaluation.
// This shouldn't produce false positives on comment boosts that were generated on other platforms
// because we won't be delivering them.
if (isset($target_item) && isset($target_item['verb']) && $target_item['verb'] === 'Announce' && $target_item['author_xchan'] === $target_item['owner_xchan'] && ! intval($target_item['item_thread_top'])) {
continue;
}
$hash = new_uuid();
$env = (($hub_env && $hub_env[$hub['hubloc_site_id']]) ? $hub_env[$hub['hubloc_site_id']] : '');
@@ -673,7 +694,7 @@ class Notifier {
// This wastes a process if there are no delivery hooks configured, so check this before launching the new process
$x = q("select * from hook where hook = 'notifier_normal'");
if ($x) {
Master::Summon(['Deliver_hooks', $target_item['id']]);
Master::Summon(['Deliver_hooks', $target_item['id'], self::$fragment]);
}
}

View File

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

View File

@@ -116,6 +116,11 @@ class Activity {
$y = json_decode($x['body'], true);
logger('returned: ' . json_encode($y, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), LOGGER_DEBUG);
if (ActivityStreams::is_an_actor($y['type'])) {
XConfig::Set($y['id'], 'system', 'actor_record', $y);
}
return json_decode($x['body'], true);
}
else {
@@ -529,6 +534,7 @@ class Activity {
$top_level = (($i['mid'] === $i['parent_mid']) ? true : false);
if ($public) {
$ret['to'] = [ACTIVITY_PUBLIC_INBOX];
$ret['cc'] = [z_root() . '/followers/' . substr($i['author']['xchan_addr'], 0, strpos($i['author']['xchan_addr'], '@'))];
}
@@ -660,11 +666,11 @@ class Activity {
return $ret;
}
static function encode_attachment($item) {
static function encode_attachment($item, $iconfig = false) {
$ret = [];
if (array_key_exists('attach', $item)) {
if (!$iconfig && array_key_exists('attach', $item)) {
$atts = ((is_array($item['attach'])) ? $item['attach'] : json_decode($item['attach'], true));
if ($atts) {
foreach ($atts as $att) {
@@ -677,7 +683,7 @@ class Activity {
}
}
}
if (array_key_exists('iconfig', $item) && is_array($item['iconfig'])) {
if ($iconfig && array_key_exists('iconfig', $item) && is_array($item['iconfig'])) {
foreach ($item['iconfig'] as $att) {
if ($att['sharing']) {
$value = ((is_string($att['v']) && preg_match('|^a:[0-9]+:{.*}$|s', $att['v'])) ? unserialize($att['v']) : $att['v']);
@@ -886,10 +892,6 @@ class Activity {
else
return [];
if (strpos($i['body'], '[/share]') !== false) {
$i['obj'] = null;
}
if ($i['obj']) {
if (!is_array($i['obj'])) {
$i['obj'] = json_decode($i['obj'], true);
@@ -899,8 +901,10 @@ class Activity {
}
$obj = self::encode_object($i['obj']);
if ($obj)
if ($obj) {
$ret['object'] = $obj;
}
else
return [];
}
@@ -932,6 +936,11 @@ class Activity {
$ret['tag'] = $t;
}
$a = self::encode_attachment($i, true);
if ($a) {
$ret['attachment'] = $a;
}
// addressing madness
$public = (($i['item_private']) ? false : true);
@@ -1042,7 +1051,7 @@ class Activity {
$tmp = expand_acl($i['allow_cid']);
$list = stringify_array($tmp, true);
if ($list) {
$details = q("select hubloc_id_url from hubloc where hubloc_hash in (" . $list . ") and hubloc_id_url != ''");
$details = q("select hubloc_id_url from hubloc where hubloc_hash in (" . $list . ") and hubloc_id_url != '' and hubloc_deleted = 0");
if ($details) {
foreach ($details as $d) {
$ret[] = $d['hubloc_id_url'];
@@ -1089,10 +1098,11 @@ class Activity {
$ret['type'] = 'Person';
if ($c) {
$role = get_pconfig($c['channel_id'], 'system', 'permissions_role');
if (strpos($role, 'forum') !== false) {
if (get_pconfig($c['channel_id'], 'system', 'group_actor')) {
$ret['type'] = 'Group';
}
$ret['manuallyApprovesFollowers'] = ((get_pconfig($c['channel_id'], 'system', 'autoperms')) ? false : true);
}
if ($c) {
@@ -1403,7 +1413,7 @@ class Activity {
}
}
$x = PermissionRoles::role_perms('social');
$x = PermissionRoles::role_perms('personal');
$their_perms = Permissions::FilledPerms($x['perms_connect']);
if ($contact && $contact['abook_id']) {
@@ -1520,7 +1530,7 @@ class Activity {
'type' => NOTIFY_INTRO,
'from_xchan' => $ret['xchan_hash'],
'to_xchan' => $channel['channel_hash'],
'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'],
'link' => z_root() . '/connections#' . $new_connection[0]['abook_id'],
]
);
@@ -1554,9 +1564,9 @@ class Activity {
/* If there is a default group for this channel and permissions are automatic, add this member to it */
if ($channel['channel_default_group'] && $automatic) {
$g = Group::rec_byhash($channel['channel_id'], $channel['channel_default_group']);
$g = AccessList::by_hash($channel['channel_id'], $channel['channel_default_group']);
if ($g)
Group::member_add($channel['channel_id'], '', $ret['xchan_hash'], $g['id']);
AccessList::member_add($channel['channel_id'], '', $ret['xchan_hash'], $g['id']);
}
@@ -1704,7 +1714,7 @@ class Activity {
if ($links) {
foreach ($links as $link) {
if (array_key_exists('mediaType', $link) && $link['mediaType'] === 'text/html') {
if (is_array($link) && array_key_exists('mediaType', $link) && $link['mediaType'] === 'text/html') {
$profile = $link['href'];
}
}
@@ -1749,7 +1759,7 @@ class Activity {
// update existing xchan record
q("update xchan set xchan_name = '%s', xchan_guid = '%s', xchan_pubkey = '%s', xchan_addr = '%s', xchan_network = 'activitypub', xchan_name_date = '%s' where xchan_hash = '%s'",
dbesc(escape_tags($name)),
dbesc(escape_tags($url)),
dbesc($url),
dbesc(escape_tags($pubkey)),
dbesc(escape_tags($webfinger_addr)),
dbescdate(datetime_convert()),
@@ -1758,13 +1768,13 @@ class Activity {
// update existing hubloc record
q("update hubloc set hubloc_guid = '%s', hubloc_addr = '%s', hubloc_network = 'activitypub', hubloc_url = '%s', hubloc_host = '%s', hubloc_callback = '%s', hubloc_updated = '%s', hubloc_id_url = '%s' where hubloc_hash = '%s'",
dbesc(escape_tags($url)),
dbesc($url),
dbesc(escape_tags($webfinger_addr)),
dbesc(escape_tags($baseurl)),
dbesc(escape_tags($hostname)),
dbesc(escape_tags($inbox)),
dbesc($baseurl),
dbesc($hostname),
dbesc($inbox),
dbescdate(datetime_convert()),
dbesc(escape_tags($profile)),
dbesc($profile),
dbesc($url)
);
}
@@ -1773,8 +1783,8 @@ class Activity {
xchan_store_lowlevel(
[
'xchan_hash' => escape_tags($url),
'xchan_guid' => escape_tags($url),
'xchan_hash' => $url,
'xchan_guid' => $url,
'xchan_pubkey' => escape_tags($pubkey),
'xchan_addr' => $webfinger_addr,
'xchan_url' => escape_tags($profile),
@@ -1786,16 +1796,16 @@ class Activity {
hubloc_store_lowlevel(
[
'hubloc_guid' => escape_tags($url),
'hubloc_hash' => escape_tags($url),
'hubloc_guid' => $url,
'hubloc_hash' => $url,
'hubloc_addr' => $webfinger_addr,
'hubloc_network' => 'activitypub',
'hubloc_url' => escape_tags($baseurl),
'hubloc_host' => escape_tags($hostname),
'hubloc_callback' => escape_tags($inbox),
'hubloc_url' => $baseurl,
'hubloc_host' => $hostname,
'hubloc_callback' => $inbox,
'hubloc_updated' => datetime_convert(),
'hubloc_primary' => 1,
'hubloc_id_url' => escape_tags($profile)
'hubloc_id_url' => $profile
]
);
}
@@ -2116,6 +2126,7 @@ class Activity {
}
static function update_poll($item, $post) {
$multi = false;
$mid = $post['mid'];
$content = $post['title'];
@@ -2200,7 +2211,8 @@ class Activity {
dbesc(datetime_convert()),
intval($item['id'])
);
Master::Summon(['Notifier', 'wall-new', $item['id']]);
Master::Summon(['Notifier', 'wall-new', $item['id'], $post['mid'] /* trick queueworker de-duplication */ ]);
return true;
}
@@ -2637,13 +2649,78 @@ class Activity {
}
}
set_iconfig($s, 'activitypub', 'recips', $act->raw_recips);
$ap_rawmsg = '';
$diaspora_rawmsg = '';
$raw_arr = [];
$parent = (($s['parent_mid'] && $s['parent_mid'] === $s['mid']) ? true : false);
if ($parent) {
$raw_arr = json_decode($act->raw, true);
// This is a zot6 packet and the raw activitypub or diaspora message json
// is possibly available in the attachement.
if (array_key_exists('signed', $raw_arr) && is_array($act->data['attachment'])) {
foreach($act->data['attachment'] as $a) {
if (
isset($a['type']) && $a['type'] === 'PropertyValue' &&
isset($a['name']) && $a['name'] === 'zot.activitypub.rawmsg' &&
isset($a['value'])
) {
$ap_rawmsg = $a['value'];
}
if (
isset($a['type']) && $a['type'] === 'PropertyValue' &&
isset($a['name']) && $a['name'] === 'zot.diaspora.fields' &&
isset($a['value'])
) {
$diaspora_rawmsg = $a['value'];
}
}
}
// old style: can be removed after most hubs are on 7.0.2
elseif (array_key_exists('signed', $raw_arr) && is_array($act->obj) && is_array($act->obj['attachment'])) {
foreach($act->obj['attachment'] as $a) {
if (
isset($a['type']) && $a['type'] === 'PropertyValue' &&
isset($a['name']) && $a['name'] === 'zot.activitypub.rawmsg' &&
isset($a['value'])
) {
$ap_rawmsg = $a['value'];
}
if (
isset($a['type']) && $a['type'] === 'PropertyValue' &&
isset($a['name']) && $a['name'] === 'zot.diaspora.fields' &&
isset($a['value'])
) {
$diaspora_rawmsg = $a['value'];
}
}
}
// catch the likes
if (!$ap_rawmsg && $response_activity) {
$ap_rawmsg = json_encode($act->data, JSON_UNESCAPED_SLASHES);
}
// end old style
if (!$ap_rawmsg && array_key_exists('signed', $raw_arr)) {
// zap
$ap_rawmsg = json_encode($act->data, JSON_UNESCAPED_SLASHES);
}
if ($ap_rawmsg) {
set_iconfig($s, 'activitypub', 'rawmsg', $ap_rawmsg, 1);
}
elseif (!array_key_exists('signed', $raw_arr)) {
set_iconfig($s, 'activitypub', 'rawmsg', $act->raw, 1);
}
if ($diaspora_rawmsg) {
set_iconfig($s, 'diaspora', 'fields', $diaspora_rawmsg, 1);
}
set_iconfig($s, 'activitypub', 'recips', $act->raw_recips);
$hookinfo = [
'act' => $act,
's' => $s
@@ -2692,6 +2769,17 @@ class Activity {
// set the owner to the owner of the parent
$item['owner_xchan'] = $p[0]['owner_xchan'];
// quietly reject group comment boosts by group owner
// (usually only sent via ActivityPub so groups will work on microblog platforms)
// This catches those activities if they slipped in via a conversation fetch
if ($p[0]['parent_mid'] !== $item['parent_mid']) {
if ($item['verb'] === 'Announce' && $item['author_xchan'] === $item['owner_xchan']) {
logger('group boost activity by group owner rejected');
return;
}
}
// check permissions against the author, not the sender
$allowed = perm_is_allowed($channel['channel_id'], $item['author_xchan'], 'post_comments');
if ((!$allowed)/* && $permit_mentions*/) {
@@ -3626,7 +3714,10 @@ class Activity {
}
static function get_cached_actor($id) {
$actor = XConfig::Get($id, 'system', 'actor_record');
// remove any fragments like #main-key since these won't be present in our cached data
$cache_url = ((strpos($id, '#')) ? substr($id, 0, strpos($id, '#')) : $id);
$actor = XConfig::Get($cache_url, 'system', 'actor_record');
if ($actor) {
return $actor;
@@ -3635,7 +3726,7 @@ class Activity {
// try other get_cached_actor providers (e.g. diaspora)
$hookdata = [
'id' => $id,
'actor' => false
'actor' => null
];
call_hooks('get_cached_actor_provider', $hookdata);

View File

@@ -11,6 +11,7 @@ class ActivityStreams {
public $raw = null;
public $data = null;
public $meta = null;
public $valid = false;
public $deleted = false;
public $id = '';
@@ -36,10 +37,14 @@ class ActivityStreams {
*/
function __construct($string) {
if(!$string)
return;
$this->raw = $string;
if (is_array($string)) {
$this->data = $string;
$this->raw = json_encode($string, JSON_UNESCAPED_SLASHES);
}
else {
$this->data = json_decode($string, true);
@@ -56,10 +61,10 @@ class ActivityStreams {
if ($ret['signer']) {
$saved = json_encode($this->data, JSON_UNESCAPED_SLASHES);
$this->data = $tmp;
$this->data['signer'] = $ret['signer'];
$this->data['signed_data'] = $saved;
$this->meta['signer'] = $ret['signer'];
$this->meta['signed_data'] = $saved;
if ($ret['hubloc']) {
$this->data['hubloc'] = $ret['hubloc'];
$this->meta['hubloc'] = $ret['hubloc'];
}
}
}
@@ -87,7 +92,7 @@ class ActivityStreams {
$this->ldsig = $this->get_compound_property('signature');
if ($this->ldsig) {
$this->signer = $this->get_compound_property('creator', $this->ldsig);
$this->signer = $this->get_actor('creator', $this->ldsig);
if ($this->signer && is_array($this->signer) && array_key_exists('publicKey', $this->signer) && is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) {
$this->sigok = LDSignatures::verify($this->data, $this->signer['publicKey']['publicKeyPem']);
}
@@ -343,10 +348,10 @@ class ActivityStreams {
if ($ret['signer']) {
$saved = json_encode($x, JSON_UNESCAPED_SLASHES);
$x = $tmp;
$x['signer'] = $ret['signer'];
$x['signed_data'] = $saved;
$x['meta']['signer'] = $ret['signer'];
$x['meta']['signed_data'] = $saved;
if ($ret['hubloc']) {
$x['hubloc'] = $ret['hubloc'];
$x['meta']['hubloc'] = $ret['hubloc'];
}
}
}

View File

@@ -67,17 +67,15 @@ class Apps {
static public function get_base_apps() {
$x = get_config('system','base_apps',[
'Connections',
'Contact Roles',
'Network',
'Settings',
'Files',
'Channel Home',
'View Profile',
'Channel',
'Photos',
'Calendar',
'Directory',
'Search',
'Help',
'Profile Photo',
'HQ',
'Post'
]);
@@ -346,7 +344,7 @@ class Apps {
'Files' => t('Files'),
'Webpages' => t('Webpages'),
'Wiki' => t('Wiki'),
'Channel Home' => t('Channel Home'),
'Channel' => t('Channel'),
'View Profile' => t('View Profile'),
'Photos' => t('Photos'),
'Calendar' => t('Calendar'),
@@ -377,10 +375,10 @@ class Apps {
'OAuth Apps Manager' => t('OAuth Apps Manager'),
'OAuth2 Apps Manager' => t('OAuth2 Apps Manager'),
'PDL Editor' => t('PDL Editor'),
'Permission Categories' => t('Permission Categories'),
'Contact Roles' => t('Contact Roles'),
'Public Stream' => t('Public Stream'),
'My Chatrooms' => t('My Chatrooms'),
'Channel Export' => t('Channel Export'),
'Channel Export' => t('Channel Export')
);
if(array_key_exists('name',$arr)) {
@@ -428,7 +426,7 @@ class Apps {
self::translate_system_apps($papp);
if(trim($papp['plugin']) && (! plugin_is_installed(trim($papp['plugin']))))
if(isset($papp['plugin']) && trim($papp['plugin']) && (! plugin_is_installed(trim($papp['plugin']))))
return '';
$papp['papp'] = self::papp_encode($papp);

View File

@@ -261,7 +261,8 @@ class Connect {
'abook_feed' => intval(($xchan['xchan_network'] === 'rss') ? 1 : 0),
'abook_created' => datetime_convert(),
'abook_updated' => datetime_convert(),
'abook_instance' => (($singleton) ? z_root() : '')
'abook_instance' => (($singleton) ? z_root() : ''),
'abook_role' => get_pconfig($uid, 'system', 'default_permcat', 'default')
]
);
}
@@ -300,7 +301,7 @@ class Connect {
/** If there is a default group for this channel, add this connection to it */
if ($default_group) {
$g = AccessList::rec_byhash($uid,$default_group);
$g = AccessList::by_hash($uid,$default_group);
if ($g) {
AccessList::member_add($uid,'',$xchan_hash,$g['id']);
}

View File

@@ -902,7 +902,7 @@ class Enotify {
static public function format_intros($rr) {
return [
'notify_link' => z_root() . '/connections/ifpending',
'notify_link' => z_root() . '/connections#' . $rr['abook_id'],
'name' => $rr['xchan_name'],
'addr' => $rr['xchan_addr'],
'url' => $rr['xchan_url'],

View File

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

View File

@@ -230,8 +230,35 @@ class Libsync {
if (array_key_exists('config', $arr) && is_array($arr['config']) && count($arr['config'])) {
foreach ($arr['config'] as $cat => $k) {
foreach ($arr['config'][$cat] as $k => $v)
set_pconfig($channel['channel_id'], $cat, $k, $v);
$pconfig_updated = [];
foreach($arr['config'][$cat] as $k => $v) {
if ($cat === 'hz_delpconfig' && strpos($k, 'b64.') === 0) {
$delpconfig = explode(':', unpack_link_id($k));
// delete the provided pconfig
del_pconfig($channel['channel_id'], $delpconfig[0], $delpconfig[1], $v);
// delete the messenger pconfig
del_pconfig($channel['channel_id'], 'hz_delpconfig', $k);
}
if (strpos($k,'pcfgud:') === 0) {
$realk = substr($k,7);
$pconfig_updated[$realk] = $v;
unset($arr['config'][$cat][$k]);
}
}
foreach($arr['config'][$cat] as $k => $v) {
if (!isset($pconfig_updated[$k])) {
$pconfig_updated[$k] = NULL;
}
if ($cat !== 'hz_delpconfig') {
set_pconfig($channel['channel_id'],$cat,$k,$v,$pconfig_updated[$k]);
}
}
}
}
@@ -384,19 +411,42 @@ class Libsync {
// This relies on the undocumented behaviour that red sites send xchan info with the abook
// and import_author_xchan will look them up on all federated networks
if ($abook['abook_xchan'] && $abook['xchan_addr']) {
$found = false;
if ($abook['abook_xchan'] && $abook['xchan_addr'] && (! in_array($abook['xchan_network'], [ 'token', 'unknown' ]))) {
$h = Libzot::get_hublocs($abook['abook_xchan']);
if (!$h) {
if ($h) {
$found = true;
}
else {
$xhash = import_author_xchan(encode_item_xchan($abook));
if (!$xhash) {
if ($xhash) {
$found = true;
}
else {
logger('Import of ' . $abook['xchan_addr'] . ' failed.');
continue;
}
}
}
if (!$found && !in_array($abook['xchan_network'], ['zot6', 'activitypub', 'diaspora'])) {
// just import the record.
$xc = [];
foreach ($abook as $k => $v) {
if (strpos($k,'xchan_') === 0) {
$xc[$k] = $v;
}
}
$r = q("select * from xchan where xchan_hash = '%s'",
dbesc($xc['xchan_hash'])
);
if (! $r) {
xchan_store_lowlevel($xc);
}
}
foreach ($abook as $k => $v) {
if (in_array($k, $disallowed) || (strpos($k, 'abook') !== 0)) {
if (in_array($k, $disallowed) || (strpos($k, 'abook_') !== 0)) {
continue;
}
if (!in_array($k, $fields)) {
@@ -410,6 +460,13 @@ class Libsync {
if (array_key_exists('abook_instance', $clean) && $clean['abook_instance'] && strpos($clean['abook_instance'], z_root()) === false) {
$clean['abook_not_here'] = 1;
// guest pass or access token - don't try to probe since it is one-way
// we are relying on the undocumented behaviour that the abook record also contains the xchan
if ($abook['xchan_network'] === 'token') {
$clean['abook_instance'] .= ',';
$clean['abook_instance'] .= z_root();
}
}

View File

@@ -386,9 +386,10 @@ class Libzot {
else {
$p = Permissions::connect_perms($channel['channel_id']);
$my_perms = $p['perms'];
$my_perms = $p['perms'];
$automatic = $p['automatic'];
$role = (($automatic) ? $p['role'] : '');
// new connection
@@ -410,7 +411,8 @@ class Libzot {
'abook_created' => datetime_convert(),
'abook_updated' => datetime_convert(),
'abook_dob' => $next_birthday,
'abook_pending' => intval(($automatic) ? 0 : 1)
'abook_pending' => intval(($automatic) ? 0 : 1),
'abook_role' => $role
]
);
@@ -435,7 +437,7 @@ class Libzot {
'type' => NOTIFY_INTRO,
'from_xchan' => $x['hash'],
'to_xchan' => $channel['channel_hash'],
'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id']
'link' => z_root() . '/connections#' . $new_connection[0]['abook_id']
]
);
@@ -453,10 +455,10 @@ class Libzot {
$default_group = $channel['channel_default_group'];
if ($default_group) {
$g = Group::rec_byhash($channel['channel_id'], $default_group);
$g = AccessList::by_hash($channel['channel_id'], $default_group);
if ($g) {
Group::member_add($channel['channel_id'], '', $x['hash'], $g['id']);
AccessList::member_add($channel['channel_id'], '', $x['hash'], $g['id']);
}
}
}
@@ -1143,6 +1145,7 @@ class Libzot {
if ($env['encoding'] === 'activitystreams') {
$AS = new ActivityStreams($data);
if (!$AS->is_valid()) {
logger('Activity rejected: ' . print_r($data, true));
return;
@@ -1158,8 +1161,6 @@ class Libzot {
}
$deliveries = null;
if (array_key_exists('recipients', $env) && count($env['recipients'])) {
@@ -1217,7 +1218,7 @@ class Libzot {
if (in_array($env['type'], ['activity', 'response'])) {
if(!isset($AS->actor['id'])) {
if(empty($AS->actor['id'])) {
logger('No actor id!');
return;
}
@@ -1295,9 +1296,8 @@ class Libzot {
}
}
}
if ($AS->data['signed_data']) {
IConfig::Set($arr, 'activitypub', 'signed_data', $AS->data['signed_data'], false);
if ($AS->meta['signed_data']) {
IConfig::Set($arr, 'activitypub', 'signed_data', $AS->meta['signed_data'], false);
}
logger('Activity received: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG);
@@ -1592,6 +1592,7 @@ class Libzot {
if ((!$tag_delivery) && (!$local_public)) {
$allowed = (perm_is_allowed($channel['channel_id'], $sender, $perm));
if ((!$allowed) && $perm === 'post_comments') {
$parent = q("select * from item where mid = '%s' and uid = %d limit 1",
dbesc($arr['parent_mid']),
@@ -1925,6 +1926,7 @@ class Libzot {
dbesc($a['signature']['signer'])
);
foreach ($items as $activity) {
$AS = new ActivityStreams($activity);
@@ -1986,9 +1988,9 @@ class Libzot {
$arr['item_verified'] = true;
}
if ($AS->data['signed_data']) {
IConfig::Set($arr, 'activitypub', 'signed_data', $AS->data['signed_data'], false);
$j = json_decode($AS->data['signed_data'], true);
if ($AS->meta['signed_data']) {
IConfig::Set($arr, 'activitypub', 'signed_data', $AS->meta['signed_data'], false);
$j = json_decode($AS->meta['signed_data'], true);
if ($j) {
IConfig::Set($arr, 'activitypub', 'rawmsg', json_encode(JSalmon::unpack($j['data'])), true);
}
@@ -2480,14 +2482,14 @@ class Libzot {
$access_policy = ACCESS_PRIVATE;
}
$directory_url = htmlspecialchars($arr['directory_url'], ENT_COMPAT, 'UTF-8', false);
$url = htmlspecialchars(strtolower($arr['url']), ENT_COMPAT, 'UTF-8', false);
$sellpage = htmlspecialchars($arr['sellpage'], ENT_COMPAT, 'UTF-8', false);
$site_location = htmlspecialchars($arr['location'], ENT_COMPAT, 'UTF-8', false);
$site_realm = htmlspecialchars($arr['realm'], ENT_COMPAT, 'UTF-8', false);
$site_project = htmlspecialchars($arr['project'], ENT_COMPAT, 'UTF-8', false);
$site_crypto = ((array_key_exists('encryption', $arr) && is_array($arr['encryption'])) ? htmlspecialchars(implode(',', $arr['encryption']), ENT_COMPAT, 'UTF-8', false) : '');
$site_version = ((array_key_exists('version', $arr)) ? htmlspecialchars($arr['version'], ENT_COMPAT, 'UTF-8', false) : '');
$directory_url = htmlspecialchars((string)$arr['directory_url'], ENT_COMPAT, 'UTF-8', false);
$url = htmlspecialchars((string)strtolower($arr['url']), ENT_COMPAT, 'UTF-8', false);
$sellpage = htmlspecialchars((string)$arr['sellpage'], ENT_COMPAT, 'UTF-8', false);
$site_location = htmlspecialchars((string)$arr['location'], ENT_COMPAT, 'UTF-8', false);
$site_realm = htmlspecialchars((string)$arr['realm'], ENT_COMPAT, 'UTF-8', false);
$site_project = htmlspecialchars((string)$arr['project'], ENT_COMPAT, 'UTF-8', false);
$site_crypto = ((array_key_exists('encryption', $arr) && is_array($arr['encryption'])) ? htmlspecialchars((string)implode(',', $arr['encryption']), ENT_COMPAT, 'UTF-8', false) : '');
$site_version = ((array_key_exists('version', $arr)) ? htmlspecialchars((string)$arr['version'], ENT_COMPAT, 'UTF-8', false) : '');
// You can have one and only one primary directory per realm.
// Downgrade any others claiming to be primary. As they have
@@ -2785,28 +2787,6 @@ class Libzot {
if ($deleted || $censored || $sys_channel)
$searchable = false;
$public_forum = false;
$role = get_pconfig($e['channel_id'], 'system', 'permissions_role');
if ($role === 'forum' || $role === 'repository') {
$public_forum = true;
}
else {
// check if it has characteristics of a public forum based on custom permissions.
$m = Permissions::FilledAutoperms($e['channel_id']);
if ($m) {
foreach ($m as $k => $v) {
if ($k == 'tag_deliver' && intval($v) == 1)
$ch++;
if ($k == 'send_stream' && intval($v) == 0)
$ch++;
}
if ($ch == 2)
$public_forum = true;
}
}
// This is for birthdays and keywords, but must check access permissions
$p = q("select * from profile where uid = %d and is_default = 1",
intval($e['channel_id'])
@@ -2875,6 +2855,7 @@ class Libzot {
];
$ret['channel_role'] = get_pconfig($e['channel_id'], 'system', 'permissions_role', 'custom');
$ret['channel_type'] = ((get_pconfig($e['channel_id'], 'system', 'group_actor')) ? 'group' : 'normal');
$hookinfo = [
'channel_id' => $id,
@@ -2890,8 +2871,10 @@ class Libzot {
$ret['protocols'] = $hookinfo['protocols'];
$ret['searchable'] = $searchable;
$ret['adult_content'] = $adult_channel;
$ret['public_forum'] = $public_forum;
// now all forums (public, restricted, and private) set the public_forum flag. So it really means "is a group"
// and has nothing to do with accessibility.
$ret['public_forum'] = get_pconfig($e['channel_id'], 'system', 'group_actor');
$ret['comments'] = map_scope(PermissionLimits::Get($e['channel_id'], 'post_comments'));
$ret['mail'] = map_scope(PermissionLimits::Get($e['channel_id'], 'post_mail'));
@@ -3189,7 +3172,7 @@ class Libzot {
}
static function update_cached_hubloc($hubloc) {
if ($hubloc['hubloc_updated'] > datetime_convert('UTC','UTC','now - 1 week') || $hubloc['hubloc_url'] === z_root()) {
if ($hubloc['hubloc_updated'] > datetime_convert('UTC','UTC','now - 3 days') || $hubloc['hubloc_url'] === z_root()) {
return;
}
self::refresh( [ 'hubloc_id_url' => $hubloc['hubloc_id_url'] ] );

View File

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

View File

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

View File

@@ -2,7 +2,9 @@
namespace Zotlabs\Lib;
use App;
use Zotlabs\Lib\Apps;
use Zotlabs\Access\AccessList;
require_once('include/text.php');
@@ -58,6 +60,9 @@ class ThreadItem {
$child = new ThreadItem($item);
$this->add_child($child);
}
// performance: we have already added the children
unset($this->data['children']);
}
// allow a site to configure the order and content of the reaction emoji list
@@ -98,11 +103,25 @@ class ThreadItem {
$conv = $this->get_conversation();
$observer = $conv->get_observer();
$lock = (((intval($item['item_private'])) || (($item['uid'] == local_channel()) && (strlen($item['allow_cid']) || strlen($item['allow_gid'])
|| strlen($item['deny_cid']) || strlen($item['deny_gid']))))
? t('Private Message')
$acl = new AccessList(false);
$acl->set($item);
$lock = ((intval($item['item_private']) || ($item['uid'] == local_channel() && $acl->is_private()))
? t('Restricted message')
: false);
$locktype = $item['item_private'];
// 1 = restricted message, 2 = direct message
$locktype = intval($item['item_private']);
if ($locktype === 2) {
$lock = t('Direct message');
}
// 0 = limited based on public policy
if ($item['uid'] == local_channel() && intval($item['item_private']) && !$acl->is_private() && strlen($item['public_policy'])) {
$lock = t('Public Policy');
$locktype = 0;
}
$shareable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && ($item['item_private'] != 1)) ? true : false);
@@ -110,6 +129,16 @@ class ThreadItem {
if($item['author']['xchan_network'] === 'rss')
$shareable = true;
// @fixme
// Have recently added code to properly handle polls in group reshares by redirecting all of the poll responses to the group.
// Sharing a poll using a regular embedded share is harder because the poll will need to fork. This is due to comment permissions.
// The original poll author may not accept responses from strangers. Forking the poll will receive responses from the sharer's
// followers, but there's no elegant way to merge these two sets of results together. For now, we'll disable sharing polls.
if ($item['obj_type'] === 'Question') {
$shareable = false;
}
$privacy_warning = false;
if(intval($item['item_private']) && ($item['owner']['xchan_network'] === 'activitypub')) {
$recips = get_iconfig($item['parent'], 'activitypub', 'recips');
@@ -384,6 +413,12 @@ class ThreadItem {
$pinned_items = ($allowed_type ? get_pconfig($item['uid'], 'pinned', $item['item_type'], []) : []);
$pinned = ((!empty($pinned_items) && in_array($midb64, $pinned_items)) ? true : false);
$contact = [];
if(App::$contacts && array_key_exists($item['author_xchan'], App::$contacts)) {
$contact = App::$contacts[$item['author_xchan']];
}
$tmp_item = array(
'template' => $this->get_template(),
'mode' => $mode,
@@ -401,6 +436,7 @@ class ThreadItem {
'mids' => $json_mids,
'parent' => $item['parent'],
'author_id' => (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']),
'author_is_group_actor' => (($item['author']['xchan_pubforum']) ? t('Forum') : ''),
'isevent' => $isevent,
'attend' => $attend,
'consensus' => $consensus,
@@ -503,7 +539,9 @@ class ThreadItem {
'wait' => t('Please wait'),
'thread_level' => $thread_level,
'settings' => $settings,
'thr_parent' => (($item['parent_mid'] != $item['thr_parent']) ? gen_link_id($item['thr_parent']) : '')
'thr_parent' => (($item['parent_mid'] != $item['thr_parent']) ? gen_link_id($item['thr_parent']) : ''),
'contact_id' => (($contact) ? $contact['abook_id'] : '')
);
$arr = array('item' => $item, 'output' => $tmp_item);

View File

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

View File

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

View File

@@ -3,9 +3,9 @@
namespace Zotlabs\Module;
use Zotlabs\Lib\Libzotdir;
use Zotlabs\Lib\AccessList;
require_once 'include/acl_selectors.php';
require_once 'include/group.php';
/**
* @brief ACL selector json backend.
@@ -123,7 +123,7 @@ class Acl extends \Zotlabs\Web\Controller {
"name" => t('Profile','acl') . ' ' . $rv['profile_name'],
"id" => 'vp' . $rv['id'],
"xid" => 'vp.' . $rv['profile_guid'],
"uids" => group_get_profile_members_xchan(local_channel(), $rv['id']),
"uids" => AccessList::profile_members_xchan(local_channel(), $rv['id']),
"link" => ''
);
}
@@ -146,14 +146,14 @@ class Acl extends \Zotlabs\Web\Controller {
if($r) {
foreach($r as $g){
// logger('acl: group: ' . $g['gname'] . ' members: ' . group_get_members_xchan($g['id']));
// logger('acl: group: ' . $g['gname'] . ' members: ' . AccessList::members_xchan(local_channel(), $g['id']));
$groups[] = array(
"type" => "g",
"photo" => "images/twopeople.png",
"name" => $g['gname'],
"id" => $g['id'],
"xid" => $g['hash'],
"uids" => group_get_members_xchan($g['id']),
"uids" => AccessList::members_xchan(local_channel(), $g['id']),
"link" => ''
);
}

View File

@@ -23,7 +23,18 @@ class Queue {
LibQueue::remove_by_posturl($_REQUEST['emptyhub']);
}
$r = q("select count(outq_posturl) as total, max(outq_priority) as priority, outq_posturl from outq
if($_REQUEST['deliverhub']) {
$hubq = q("SELECT * FROM outq WHERE outq_posturl = '%s'",
dbesc($_REQUEST['deliverhub'])
);
foreach ($hubq as $q) {
LibQueue::deliver($q, true);
}
}
$r = dbq("select count(outq_posturl) as total, max(outq_priority) as priority, outq_posturl from outq
where outq_delivered = 0 group by outq_posturl order by total desc");
for($x = 0; $x < count($r); $x ++) {
@@ -37,6 +48,7 @@ class Queue {
'$priority' => t('Priority'),
'$desturl' => t('Destination URL'),
'$nukehub' => t('Mark hub permanently offline'),
'$deliverhub' => t('Retry delivery to this hub'),
'$empty' => t('Empty queue for this hub'),
'$lastconn' => t('Last known contact'),
'$hasentries' => ((count($r)) ? true : false),

View File

@@ -339,12 +339,15 @@ class Site {
// now invert the logic for the setting.
$discover_tab = (1 - $discover_tab);
$perm_roles = \Zotlabs\Access\PermissionRoles::roles();
$default_role = get_config('system','default_permissions_role','social');
$perm_roles = \Zotlabs\Access\PermissionRoles::channel_roles();
$default_role = get_config('system', 'default_permissions_role', 'personal');
if (!in_array($default_role, array_keys($perm_roles))) {
$default_role = 'personal';
}
$role = array('permissions_role' , t('Default permission role for new accounts'), $default_role, t('This role will be used for the first channel created after registration.'),$perm_roles);
$homelogin = get_config('system','login_on_homepage');
$enable_context_help = get_config('system','enable_context_help');

View File

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

View File

@@ -95,6 +95,10 @@ class Channel extends Controller {
http_status_exit(410, 'Gone');
}
if (get_pconfig($channel['channel_id'], 'system', 'index_opt_out')) {
App::$meta->set('robots', 'noindex, noarchive');
}
if (ActivityStreams::is_as_request($channel)) {
// Somebody may attempt an ActivityStreams fetch on one of our message permalinks

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -8,7 +8,6 @@ use Zotlabs\Lib\Libsync;
require_once('include/socgraph.php');
require_once('include/selectors.php');
require_once('include/group.php');
require_once('include/photos.php');
class Defperms extends Controller {
@@ -23,8 +22,8 @@ class Defperms extends Controller {
if(! local_channel())
return;
if(! Apps::system_app_installed(local_channel(), 'Default Permissions'))
return;
//if(! Apps::system_app_installed(local_channel(), 'Default Permissions'))
// return;
$r = q("SELECT abook.*, xchan.*
FROM abook left join xchan on abook_xchan = xchan_hash
@@ -50,8 +49,8 @@ class Defperms extends Controller {
if(! local_channel())
return;
if(! Apps::system_app_installed(local_channel(), 'Default Permissions'))
return;
//if(! Apps::system_app_installed(local_channel(), 'Default Permissions'))
// return;
$contact_id = intval(argv(1));
if(! $contact_id)
@@ -183,12 +182,12 @@ class Defperms extends Controller {
return login();
}
if(! Apps::system_app_installed(local_channel(), 'Default Permissions')) {
//Do not display any associated widgets at this point
App::$pdl = '';
$papp = Apps::get_papp('Default Permissions');
return Apps::app_render($papp, 'module');
}
//~ if(! Apps::system_app_installed(local_channel(), 'Default Permissions')) {
//~ //Do not display any associated widgets at this point
//~ App::$pdl = '';
//~ $papp = Apps::get_papp('Default Permissions');
//~ return Apps::app_render($papp, 'module');
//~ }
$section = ((array_key_exists('section',$_REQUEST)) ? $_REQUEST['section'] : '');
$channel = App::get_channel();

View File

@@ -56,9 +56,10 @@ class Dreport extends \Zotlabs\Web\Controller {
return;
}
$r = q("select * from dreport where dreport_xchan = '%s' and dreport_mid = '%s'",
$r = q("select * from dreport where dreport_xchan = '%s' and (dreport_mid = '%s' or dreport_mid = '%s')",
dbesc($channel['channel_hash']),
dbesc($mid)
dbesc($mid),
dbesc(str_replace('/item/', '/activity/', $mid))
);
if(! $r) {

View File

@@ -108,7 +108,7 @@ class Follow extends Controller {
}
Libsync::build_sync_packet(0, [ 'abook' => [ $clone ] ], true);
$can_view_stream = their_perms_contains($channel['channel_id'],$clone['abook_xchan'],'view_stream');
$can_view_stream = intval(get_abconfig($channel['channel_id'], $clone['abook_xchan'], 'their_perms', 'view_stream'));
// If we can view their stream, pull in some posts
@@ -117,7 +117,7 @@ class Follow extends Controller {
}
if ($interactive) {
goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?follow=1');
goaway(z_root() . '/connections#' . $result['abook']['abook_id']);
}
else {
json_return_and_die([ 'success' => true ]);

View File

@@ -5,8 +5,7 @@ use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Apps;
use Zotlabs\Lib\Libsync;
require_once('include/group.php');
use Zotlabs\Lib\AccessList;
class Group extends Controller {
@@ -41,16 +40,17 @@ class Group extends Controller {
$name = notags(trim($_POST['groupname']));
$public = intval($_POST['public']);
$r = group_add(local_channel(),$name,$public);
$r = AccessList::add(local_channel(),$name,$public);
$group_hash = $r;
if($r) {
info( t('Privacy group created.') . EOL );
}
else {
notice( t('Could not create privacy group.') . EOL );
}
goaway(z_root() . '/group');
}
if((argc() == 2) && (intval(argv(1)))) {
check_form_security_token_redirectOnErr('/group', 'group_edit');
@@ -65,10 +65,11 @@ class Group extends Controller {
}
$group = $r[0];
$groupname = notags(trim($_POST['groupname']));
$group_hash = $group['hash'];
$public = intval($_POST['public']);
$hookinfo = [ 'pgrp_extras' => '', 'group'=>$group['id'] ];
call_hooks ('privacygroup_extras_post',$hookinfo);
call_hooks('privacygroup_extras_post',$hookinfo);
if((strlen($groupname)) && (($groupname != $group['gname']) || ($public != $group['visible']))) {
$r = q("UPDATE pgrp SET gname = '%s', visible = %d WHERE uid = %d AND id = %d",
@@ -79,13 +80,25 @@ class Group extends Controller {
);
if($r)
info( t('Privacy group updated.') . EOL );
Libsync::build_sync_packet(local_channel(),null,true);
}
goaway(z_root() . '/group/' . argv(1) . '/' . argv(2));
}
$channel = App::get_channel();
$default_group = ((isset($_POST['set_default_group'])) ? $group_hash : (($channel['channel_default_group'] === $group_hash) ? '' : $channel['channel_default_group']));
$default_acl = ((isset($_POST['set_default_acl'])) ? '<' . $group_hash . '>' : (($channel['channel_allow_gid'] === '<' . $group_hash . '>') ? '' : $channel['channel_allow_gid']));
q("update channel set channel_default_group = '%s', channel_allow_gid = '%s'
where channel_id = %d",
dbesc($default_group),
dbesc($default_acl),
intval(local_channel())
);
Libsync::build_sync_packet(local_channel(),null,true);
goaway(z_root() . '/group/' . argv(1) . ((argv(2)) ? '/' . argv(2) : ''));
return;
}
@@ -117,51 +130,32 @@ class Group extends Controller {
if((argc() == 1) || ((argc() == 2) && (argv(1) === 'new'))) {
$new = (((argc() == 2) && (argv(1) === 'new')) ? true : false);
$groups = q("SELECT id, gname FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval(local_channel())
);
$i = 0;
foreach($groups as $group) {
$entries[$i]['name'] = $group['gname'];
$entries[$i]['id'] = $group['id'];
$entries[$i]['count'] = count(group_get_members($group['id']));
$i++;
}
$hookinfo = [ 'pgrp_extras' => '', 'group'=>argv(1) ];
call_hooks ('privacygroup_extras',$hookinfo);
$pgrp_extras = $hookinfo['pgrp_extras'];
$is_default_acl = ['set_default_acl', t('Post to this group by default'), 0, '', [t('No'), t('Yes')]];
$is_default_group = ['set_default_group', t('Add new contacts to this group by default'), 0, '', [t('No'), t('Yes')]];
$tpl = get_markup_template('privacy_groups.tpl');
$o = replace_macros($tpl, [
'$title' => t('Privacy Groups'),
'$add_new_label' => t('Add Group'),
'$new' => $new,
// new group form
'$gname' => array('groupname',t('Privacy group name')),
'$public' => array('public',t('Members are visible to other channels'), false),
'$public' => array('public',t('Members are visible to other channels'), 0, '', [t('No'), t('Yes')]),
'$pgrp_extras' => $pgrp_extras,
'$form_security_token' => get_form_security_token("group_edit"),
'$submit' => t('Submit'),
// groups list
'$title' => t('Privacy Groups'),
'$name_label' => t('Name'),
'$count_label' => t('Members'),
'$entries' => $entries
'$is_default_acl' => $is_default_acl,
'$is_default_group' => $is_default_group,
]);
return $o;
}
$context = array('$submit' => t('Submit'));
$tpl = get_markup_template('group_edit.tpl');
@@ -174,7 +168,7 @@ class Group extends Controller {
intval(local_channel())
);
if($r)
$result = group_rmv(local_channel(),$r[0]['gname']);
$result = AccessList::remove(local_channel(),$r[0]['gname']);
if($result) {
$hookinfo = [ 'pgrp_extras' => '', 'group' => argv(2) ];
call_hooks ('privacygroup_extras_drop',$hookinfo);
@@ -215,7 +209,7 @@ class Group extends Controller {
$group = $r[0];
$members = group_get_members($group['id']);
$members = AccessList::members(local_channel(), $group['id']);
$preselected = array();
if(count($members)) {
@@ -227,13 +221,13 @@ class Group extends Controller {
if($change) {
if(in_array($change,$preselected)) {
group_rmv_member(local_channel(),$group['gname'],$change);
AccessList::member_remove(local_channel(),$group['gname'],$change);
}
else {
group_add_member(local_channel(),$group['gname'],$change);
AccessList::member_add(local_channel(),$group['gname'],$change);
}
$members = group_get_members($group['id']);
$members = AccessList::members(local_channel(), $group['id']);
$preselected = array();
if(count($members)) {
@@ -252,9 +246,9 @@ class Group extends Controller {
'$gname' => array('groupname',t('Privacy group name: '),$group['gname'], ''),
'$gid' => $group['id'],
'$drop' => $drop_txt,
'$public' => array('public',t('Members are visible to other channels'), $group['visible'], ''),
'$public' => array('public',t('Members are visible to other channels'), $group['visible'], '', [t('No'), t('Yes')]),
'$form_security_token_edit' => get_form_security_token('group_edit'),
'$delete' => t('Delete Group'),
'$delete' => t('Delete'),
'$form_security_token_drop' => get_form_security_token("group_drop"),
'$pgrp_extras' => $pgrp_extras,
);
@@ -280,7 +274,7 @@ class Group extends Controller {
$groupeditor['members'][] = micropro($member,true,'mpgroup', $textmode);
}
else
group_rmv_member(local_channel(),$group['gname'],$member['xchan_hash']);
AccessList::member_remove(local_channel(),$group['gname'],$member['xchan_hash']);
}
$r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d AND abook_self = 0 and abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 order by xchan_name asc",
@@ -302,6 +296,12 @@ class Group extends Controller {
$context['$desc'] = t('Click a channel to toggle membership');
$context['$pgrp_extras'] = $pgrp_extras;
$channel = App::get_channel();
$context['$is_default_acl'] = ['set_default_acl', t('Post to this group by default'), intval($group['hash'] === trim($channel['channel_allow_gid'], '<>')), '', [t('No'), t('Yes')]];
$context['$is_default_group'] = ['set_default_group', t('Add new contacts to this group by default'), intval($group['hash'] === $channel['channel_default_group']), '', [t('No'), t('Yes')]];
if($change) {
$tpl = get_markup_template('groupeditor.tpl');
echo replace_macros($tpl, $context);

View File

@@ -5,7 +5,7 @@ namespace Zotlabs\Module;
class Hcard extends \Zotlabs\Web\Controller {
function init() {
if(argc() > 1)
$which = argv(1);
else {
@@ -13,12 +13,12 @@ class Hcard extends \Zotlabs\Web\Controller {
\App::$error = 404;
return;
}
logger('hcard_request: ' . $which, LOGGER_DEBUG);
$profile = '';
$channel = \App::get_channel();
if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
$which = $channel['channel_address'];
$profile = argv(1);
@@ -30,22 +30,22 @@ class Hcard extends \Zotlabs\Web\Controller {
$profile = '';
$profile = $r[0]['profile_guid'];
}
head_add_link( [
'rel' => 'alternate',
head_add_link( [
'rel' => 'alternate',
'type' => 'application/atom+xml',
'title' => t('Posts and comments'),
'href' => z_root() . '/feed/' . $which
]);
head_add_link( [
'rel' => 'alternate',
head_add_link( [
'rel' => 'alternate',
'type' => 'application/atom+xml',
'title' => t('Only posts'),
'href' => z_root() . '/feed/' . $which . '?f=&top=1'
]);
if(! $profile) {
$x = q("select channel_id as profile_uid from channel where channel_address = '%s' limit 1",
dbesc(argv(1))
@@ -54,20 +54,20 @@ class Hcard extends \Zotlabs\Web\Controller {
\App::$profile = $x[0];
}
}
profile_load($which,$profile);
}
function get() {
$x = new \Zotlabs\Widget\Profile();
$x = new \Zotlabs\Widget\Fullprofile();
return $x->widget(array());
}
}

View File

@@ -42,6 +42,9 @@ class Hq extends \Zotlabs\Web\Controller {
$item_normal = item_normal();
$item_normal_update = item_normal_update();
$sys = get_sys_channel();
$sys_item = false;
$sql_extra = '';
if(! $item_hash) {
$r = q("SELECT mid FROM item
@@ -77,11 +80,6 @@ class Hq extends \Zotlabs\Web\Controller {
if($update && $_SESSION['loadtime'])
$simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) ";
$sys = get_sys_channel();
$sql_extra = item_permissions_sql($sys['channel_id']);
$sys_item = false;
}
if(! $update) {
@@ -183,6 +181,7 @@ class Hq extends \Zotlabs\Web\Controller {
if(!$r) {
$sys_item = true;
$sql_extra = item_permissions_sql($sys['channel_id']);
$r = q("SELECT item.id AS item_id FROM item
LEFT JOIN abook ON item.author_xchan = abook.abook_xchan
@@ -209,6 +208,7 @@ class Hq extends \Zotlabs\Web\Controller {
if(!$r) {
$sys_item = true;
$sql_extra = item_permissions_sql($sys['channel_id']);
$r = q("SELECT item.parent AS item_id FROM item
LEFT JOIN abook ON item.author_xchan = abook.abook_xchan
@@ -227,7 +227,7 @@ class Hq extends \Zotlabs\Web\Controller {
if($r) {
$items = q("SELECT item.*, item.id AS item_id
FROM item
WHERE parent = '%s' $item_normal ",
WHERE parent = '%s' $item_normal $sql_extra",
dbesc($r[0]['item_id'])
);

View File

@@ -358,7 +358,7 @@ 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);
$is_poll = ((trim((string)$_REQUEST['poll_answers'][0]) != '' && trim((string)$_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.
@@ -416,6 +416,7 @@ class Item extends Controller {
$expires = NULL_DATE;
$comments_closed = NULL_DATE;
$route = '';
$parent_item = null;
@@ -692,6 +693,7 @@ class Item extends Controller {
$postopts = $orig_post['postopts'];
$created = $orig_post['created'];
$expires = $orig_post['expires'];
$comments_closed = $orig_post['comments_closed'];
$mid = $orig_post['mid'];
$parent_mid = $orig_post['parent_mid'];
$plink = $orig_post['plink'];
@@ -717,13 +719,13 @@ class Item extends Controller {
}
$location = notags(trim($_REQUEST['location']));
$coord = notags(trim($_REQUEST['coord']));
$verb = notags(trim($_REQUEST['verb']));
$title = escape_tags(trim($_REQUEST['title']));
$summary = trim($_REQUEST['summary']);
$body = trim($_REQUEST['body']);
$body .= trim($_REQUEST['attachment']);
$location = notags(trim((string)$_REQUEST['location']));
$coord = notags(trim((string)$_REQUEST['coord']));
$verb = notags(trim((string)$_REQUEST['verb']));
$title = escape_tags(trim((string)$_REQUEST['title']));
$summary = trim((string)$_REQUEST['summary']);
$body = trim((string)$_REQUEST['body']);
$body .= trim((string)$_REQUEST['attachment']);
$postopts = '';
$allow_empty = ((array_key_exists('allow_empty', $_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0);
@@ -762,7 +764,7 @@ class Item extends Controller {
}
$mimetype = notags(trim($_REQUEST['mimetype']));
$mimetype = notags(trim((string)$_REQUEST['mimetype']));
if (!$mimetype)
$mimetype = 'text/bbcode';
@@ -794,13 +796,7 @@ class Item extends Controller {
// if this is a wall-to-wall post to a group, turn it into a direct message
$role = get_pconfig($profile_uid, 'system', 'permissions_role');
$rolesettings = PermissionRoles::role_perms($role);
$channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal';
$is_group = (($channel_type === 'group') ? true : false);
$is_group = get_pconfig($profile_uid, 'system', 'group_actor');
if (($is_group) && ($walltowall) && (!$walltowall_comment)) {
$groupww = true;
@@ -994,8 +990,9 @@ class Item extends Controller {
$notify_type = (($parent) ? 'comment-new' : 'wall-new');
$uuid = (($message_id) ? $message_id : item_message_id());
if (!$mid) {
$uuid = (($message_id) ? $message_id : item_message_id());
$mid = z_root() . '/item/' . $uuid;
}
@@ -1015,10 +1012,23 @@ class Item extends Controller {
}
if ($obj) {
$obj['url'] = $mid;
$obj['attributedTo'] = channel_url($channel);
$datarray['obj'] = $obj;
$obj_type = 'Question';
$obj['url'] = $mid;
$obj['id'] = $mid;
$obj['diaspora:guid'] = $uuid;
$obj['attributedTo'] = channel_url($channel);
$obj['published'] = $created;
$obj['name'] = $title;
$datarray['obj'] = $obj;
if ($obj['endTime']) {
$d = datetime_convert('UTC','UTC', $obj['endTime']);
if ($d > NULL_DATE) {
$comments_closed = $d;
}
}
$obj_type = 'Question';
}
if (!$parent_mid) {
@@ -1082,6 +1092,7 @@ class Item extends Controller {
$datarray['created'] = $created;
$datarray['edited'] = (($orig_post) ? datetime_convert() : $created);
$datarray['expires'] = $expires;
$datarray['comments_closed'] = $comments_closed;
$datarray['commented'] = (($orig_post) ? datetime_convert() : $created);
$datarray['received'] = (($orig_post) ? datetime_convert() : $created);
$datarray['changed'] = (($orig_post) ? datetime_convert() : $created);
@@ -1594,6 +1605,8 @@ class Item extends Controller {
$obj['endTime'] = datetime_convert(date_default_timezone_get(), 'UTC', 'now + ' . $expire_value . ' ' . $expire_unit, ATOM_TIME);
$obj['directMessage'] = (intval($item['item_private']) === 2);
if ($item['item_private']) {
$obj['to'] = Activity::map_acl($item);
}

View File

@@ -1,21 +1,30 @@
<?php
namespace Zotlabs\Module;
use Zotlabs\Lib\AccessList;
use Zotlabs\Web\Controller;
require_once('include/security.php');
class Lockview extends \Zotlabs\Web\Controller {
class Lockview extends Controller {
function get() {
$atokens = array();
$atokens = [];
$atoken_xchans = [];
$access_list = [];
$guest_access_list = [];
if(local_channel()) {
if (local_channel()) {
$at = q("select * from atoken where atoken_uid = %d",
intval(local_channel())
);
if($at) {
foreach($at as $t) {
$atokens[] = atoken_xchan($t);
if ($at) {
foreach ($at as $t) {
$atoken_xchan = atoken_xchan($t);
$atokens[] = array_merge($t, $atoken_xchan);
$atoken_xchans[] = $atoken_xchan['xchan_hash'];
}
}
}
@@ -23,20 +32,20 @@ class Lockview extends \Zotlabs\Web\Controller {
$type = ((argc() > 1) ? argv(1) : 0);
if (is_numeric($type)) {
$item_id = intval($type);
$type='item';
$type = 'item';
}
else {
$item_id = ((argc() > 2) ? intval(argv(2)) : 0);
}
if(! $item_id)
if (!$item_id)
killme();
if (! in_array($type, array('item', 'photo', 'attach', 'event', 'menu_item', 'chatroom')))
if (!in_array($type, ['item', 'photo', 'attach', 'menu_item', 'chatroom']))
killme();
// we have different naming in in menu_item table and chatroom table
switch($type) {
switch ($type) {
case 'menu_item':
$id = 'mitem_id';
break;
@@ -53,134 +62,177 @@ class Lockview extends \Zotlabs\Web\Controller {
intval($item_id)
);
if(! $r)
if (!$r)
killme();
$item = $r[0];
$uid = null;
$url = '';
//we have different naming in in menu_item table and chatroom table
switch($type) {
switch ($type) {
case 'menu_item':
$uid = $item['mitem_channel_id'];
break;
case 'chatroom':
$uid = $item['cr_uid'];
$uid = $item['cr_uid'];
$channel = channelx_by_n($uid);
$url = z_root() . '/chat/' . $channel['channel_address'] . '/' . $item['cr_id'];
break;
case 'item':
$uid = $item['uid'];
$url = $item['plink'];
break;
case 'photo':
$uid = $item['uid'];
$channel = channelx_by_n($uid);
$url = z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $item['resource_id'];
break;
case 'attach':
$uid = $item['uid'];
$channel = channelx_by_n($uid);
$url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $item['display_path'];
break;
default:
$uid = $item['uid'];
break;
}
if($uid != local_channel()) {
echo '<div class="dropdown-item">' . t('Remote privacy information not available.') . '</div>';
if (intval($uid) !== local_channel()) {
echo '<div class="dropdown-item-text">' . t('Remote privacy information not available') . '</div>';
killme();
}
if(intval($item['item_private']) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid']))
&& (! strlen($item['deny_cid'])) && (! strlen($item['deny_gid']))) {
if (intval($item['item_private']) && (!strlen($item['allow_cid'])) && (!strlen($item['allow_gid']))
&& (!strlen($item['deny_cid'])) && (!strlen($item['deny_gid']))) {
// if the post is private, but public_policy is blank ("visible to the internet"), and there aren't any
// specific recipients, we're the recipient of a post with "bcc" or targeted recipients; so we'll just show it
// as unknown specific recipients. The sender will have the visibility list and will fall through to the
// next section.
echo '<div class="dropdown-item">' . translate_scope((! $item['public_policy']) ? 'specific' : $item['public_policy']) . '</div>';
echo '<div class="dropdown-item-text">' . translate_scope((!$item['public_policy']) ? 'specific' : $item['public_policy']) . '</div>';
killme();
}
$allowed_users = expand_acl($item['allow_cid']);
$allowed_users = expand_acl($item['allow_cid']);
$allowed_groups = expand_acl($item['allow_gid']);
$deny_users = expand_acl($item['deny_cid']);
$deny_groups = expand_acl($item['deny_gid']);
$deny_users = expand_acl($item['deny_cid']);
$deny_groups = expand_acl($item['deny_gid']);
$o = '<div class="dropdown-item">' . t('Visible to:') . '</div>';
$l = array();
stringify_array_elms($allowed_groups,true);
stringify_array_elms($allowed_users,true);
stringify_array_elms($deny_groups,true);
stringify_array_elms($deny_users,true);
stringify_array_elms($allowed_groups, true);
stringify_array_elms($allowed_users, true);
stringify_array_elms($deny_groups, true);
stringify_array_elms($deny_users, true);
$allowed_xchans = [];
$profile_groups = [];
if($allowed_groups) {
foreach($allowed_groups as $g) {
if(substr($g,0,4) === '\'vp.') {
$profile_groups[] = '\'' . substr($g,4);
if ($allowed_groups) {
foreach ($allowed_groups as $g) {
if (substr($g, 0, 4) === '\'vp.') {
$profile_groups[] = '\'' . substr($g, 4);
}
}
}
if(count($profile_groups)) {
$r = q("SELECT profile_name FROM profile WHERE profile_guid IN ( " . implode(', ', $profile_groups) . " )");
if($r)
foreach($r as $rr)
$l[] = '<div class="dropdown-item"><b>' . t('Profile','acl') . ' ' . $rr['profile_name'] . '</b></div>';
if ($profile_groups) {
$r = q("SELECT id, profile_name FROM profile WHERE profile_guid IN ( " . implode(', ', $profile_groups) . " )");
if ($r) {
foreach ($r as $rr) {
$pgrp_members = AccessList::profile_members_xchan($uid, $rr['id']);
$allowed_xchans = array_merge($allowed_xchans, $pgrp_members);
$access_list[] = '<div class="dropdown-item-text" title="' . t('Profile', 'acl') . '">' . $rr['profile_name'] . '</div>';
}
}
}
if(count($allowed_groups)) {
$r = q("SELECT gname FROM pgrp WHERE hash IN ( " . implode(', ', $allowed_groups) . " )");
if($r)
foreach($r as $rr)
$l[] = '<div class="dropdown-item"><b>' . $rr['gname'] . '</b></div>';
if ($allowed_groups) {
$r = q("SELECT id, gname FROM pgrp WHERE hash IN ( " . implode(', ', $allowed_groups) . " )");
if ($r) {
foreach ($r as $rr) {
$pgrp_members = AccessList::members_xchan($uid, $rr['id']);
$allowed_xchans = array_merge($allowed_xchans, $pgrp_members);
$access_list[] = '<div class="dropdown-item-text" title="' . t('Privacy group') . '">' . $rr['gname'] . '</div>';
}
}
}
if(count($allowed_users)) {
$r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ',$allowed_users) . " )");
if($r)
foreach($r as $rr)
$l[] = '<div class="dropdown-item">' . $rr['xchan_name'] . '</div>';
if($atokens) {
foreach($atokens as $at) {
if(in_array("'" . $at['xchan_hash'] . "'",$allowed_users)) {
$l[] = '<div class="dropdown-item">' . $at['xchan_name'] . '</div>';
if ($allowed_users) {
$r = q("SELECT xchan_name, xchan_hash FROM xchan WHERE xchan_hash IN ( " . implode(', ', $allowed_users) . " )");
if ($r) {
foreach ($r as $rr) {
$allowed_xchans[] = $rr['xchan_hash'];
if (!in_array($rr['xchan_hash'], $atoken_xchans)) {
$access_list[] = '<div class="dropdown-item-text">' . $rr['xchan_name'] . '</div>';
}
}
}
}
$profile_groups = [];
if($deny_groups) {
foreach($deny_groups as $g) {
if(substr($g,0,4) === '\'vp.') {
$profile_groups[] = '\'' . substr($g,4);
if ($deny_groups) {
foreach ($deny_groups as $g) {
if (substr($g, 0, 4) === '\'vp.') {
$profile_groups[] = '\'' . substr($g, 4);
}
}
}
if(count($profile_groups)) {
if ($profile_groups) {
$r = q("SELECT profile_name FROM profile WHERE profile_guid IN ( " . implode(', ', $profile_groups) . " )");
if($r)
foreach($r as $rr)
$l[] = '<div class="dropdown-item"><b><strike>' . t('Profile','acl') . ' ' . $rr['profile_name'] . '</strike></b></div>';
if ($r) {
foreach ($r as $rr) {
$access_list[] = '<div class="dropdown-item-text" title="' . t('Profile', 'acl') . '"><strike>' . $rr['profile_name'] . '</strike></b></div>';
}
}
}
if(count($deny_groups)) {
if ($deny_groups) {
$r = q("SELECT gname FROM pgrp WHERE hash IN ( " . implode(', ', $deny_groups) . " )");
if($r)
foreach($r as $rr)
$l[] = '<div class="dropdown-item"><b><strike>' . $rr['gname'] . '</strike></b></div>';
}
if(count($deny_users)) {
$r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ', $deny_users) . " )");
if($r)
foreach($r as $rr)
$l[] = '<div class="dropdown-item"><strike>' . $rr['xchan_name'] . '</strike></div>';
if($atokens) {
foreach($atokens as $at) {
if(in_array("'" . $at['xchan_hash'] . "'",$deny_users)) {
$l[] = '<div class="dropdown-item"><strike>' . $at['xchan_name'] . '</strike></div>';
}
if ($r) {
foreach ($r as $rr) {
$access_list[] = '<div class="dropdown-item-text" title="' . t('Privacy group') . '"><strike>' . $rr['gname'] . '</strike></b></div>';
}
}
}
echo $o . implode($l);
killme();
if ($deny_users) {
$r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ', $deny_users) . " )");
if ($r) {
foreach ($r as $rr) {
$access_list[] = '<div class="dropdown-item-text"><strike>' . $rr['xchan_name'] . '</strike></div>';
}
}
}
if ($atokens && $allowed_xchans && $url) {
$guest_access_list = [];
$allowed_xchans = array_unique($allowed_xchans);
foreach ($atokens as $atoken) {
if (in_array($atoken['xchan_hash'], $allowed_xchans)) {
$guest_access_list[] = '<div class="dropdown-item d-flex justify-content-between cursor-pointer" title="' . sprintf(t('Click to copy link to this ressource for guest %s to clipboard'), $atoken['xchan_name']) . '" data-token="' . $url . '?zat=' . $atoken['atoken_token'] . '" onclick="navigator.clipboard.writeText(this.dataset.token); $.jGrowl(\'' . t('Link copied') . '\', { sticky: false, theme: \'info\', life: 1000 });"><span>' . $atoken['xchan_name'] . '</span><i class="fa fa-copy p-1"></i></div>';
}
}
}
$access_list_header = '';
if ($access_list) {
$access_list_header = '<div class="dropdown-header text-uppercase h6">' . t('Access') . '</div>';
}
$guest_access_list_header = '';
if ($guest_access_list) {
$guest_access_list_header = '<div class="dropdown-header text-uppercase h6">' . t('Guest access') . '</div>';
}
$divider = '';
if ($access_list && $guest_access_list) {
$divider = '<div class="dropdown-divider"></div>';
}
echo $access_list_header . implode($access_list) . $divider . $guest_access_list_header . implode($guest_access_list);
killme();
}

View File

@@ -4,11 +4,15 @@ namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\System;
use Zotlabs\Render\Theme;
class Manifest extends Controller {
function init() {
// populate App::$theme_info
Theme::current();
$ret = [
'name' => ucfirst(System::get_platform_name()),
'short_name' => ucfirst(System::get_platform_name()),
@@ -18,12 +22,13 @@ class Manifest extends Controller {
[ 'src' => '/images/app/hz-128.png', 'sizes' => '128x128', 'type' => 'image/png' ],
[ 'src' => '/images/app/hz-144.png', 'sizes' => '144x144', 'type' => 'image/png' ],
[ 'src' => '/images/app/hz-152.png', 'sizes' => '152x152', 'type' => 'image/png' ],
[ 'src' => '/images/app/hz-192.png', 'sizes' => '192x192', 'type' => 'image/png' ],
[ 'src' => '/images/app/hz-192.png', 'sizes' => '192x192', 'type' => 'image/png', 'purpose' => 'any maskable' ],
[ 'src' => '/images/app/hz-348.png', 'sizes' => '384x384', 'type' => 'image/png' ],
[ 'src' => '/images/app/hz-512.png', 'sizes' => '512x512', 'type' => 'image/png' ],
[ 'src' => '/images/app/hz.svg', 'sizes' => '64x64', 'type' => 'image/xml+svg' ]
],
'theme_color' => '#343a40',
'theme_color' => App::$theme_info['theme_color'],
'background_color' => App::$theme_info['background_color'],
'scope' => '/',
'start_url' => z_root(),
'display' => 'standalone',

View File

@@ -1,12 +1,11 @@
<?php
namespace Zotlabs\Module;
use Zotlabs\Lib\Group;
use Zotlabs\Lib\AccessList;
use Zotlabs\Lib\Apps;
use App;
require_once('include/items.php');
require_once('include/group.php');
require_once('include/contact_widgets.php');
require_once('include/conversation.php');
require_once('include/acl_selectors.php');
@@ -233,7 +232,7 @@ class Network extends \Zotlabs\Web\Controller {
if($group) {
$contact_str = '';
$contacts = group_get_members($group);
$contacts = AccessList::members(local_channel(), $group);
if($contacts) {
$contact_str = ids_to_querystr($contacts, 'xchan', true);
}
@@ -246,7 +245,7 @@ class Network extends \Zotlabs\Web\Controller {
$item_thread_top = '';
$sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str )) or allow_gid like '" . protect_sprintf('%<' . dbesc($group_hash) . '>%') . "' ) and id = parent $item_normal ) ";
$x = group_rec_byhash(local_channel(), $group_hash);
$x = AccessList::by_hash(local_channel(), $group_hash);
if($x) {
$title = replace_macros(get_markup_template('section_title.tpl'), array(

View File

@@ -138,7 +138,7 @@ class New_channel extends \Zotlabs\Web\Controller {
intval($aid)
);
if($r && (! intval($r[0]['total']))) {
$default_role = get_config('system','default_permissions_role','social');
$default_role = get_config('system','default_permissions_role','personal');
}
$limit = account_service_class_fetch(get_account_id(),'total_identities');
@@ -170,12 +170,12 @@ class New_channel extends \Zotlabs\Web\Controller {
$privacy_role = ((x($_REQUEST,'permissions_role')) ? $_REQUEST['permissions_role'] : "" );
$perm_roles = \Zotlabs\Access\PermissionRoles::roles();
$perm_roles = \Zotlabs\Access\PermissionRoles::channel_roles();
$name = array('name', t('Channel name'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), $name_help, "*");
$nickhub = '@' . \App::get_hostname();
$nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), $nick_help, "*");
$role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel permission role compatible with your usage needs and privacy requirements.') . '<br>' . '<a href="help/member/member_guide#Channel_Permission_Roles" target="_blank">' . t('Read more about channel permission roles') . '</a>',$perm_roles);
$role = array('permissions_role' , t('Channel role'), ($privacy_role) ? $privacy_role : 'personal', '', $perm_roles);
$o = replace_macros(get_markup_template('new_channel.tpl'), array(
'$title' => t('Create a Channel'),

View File

@@ -3,49 +3,156 @@
namespace Zotlabs\Module;
use App;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Access\Permissions;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Apps;
use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\AccessList;
use Zotlabs\Lib\Permcat;
class Permcats extends Controller {
function post() {
if(! local_channel())
return;
if(! Apps::system_app_installed(local_channel(), 'Permission Categories'))
if (!local_channel())
return;
$channel = App::get_channel();
check_form_security_token_redirectOnErr('/permcats', 'permcats');
$name = escape_tags(trim($_REQUEST['name']));
$is_system_role = isset($_REQUEST['is_system_role']);
$return_path = z_root() . '/permcats/' . $_REQUEST['return_path'];
$group_hash = $_REQUEST['group_select'] ?? '';
$deleted_role = $_REQUEST['deleted_role'] ?? '';
$new_role = $_REQUEST['new_role'] ?? '';
$contacts = [];
$all_perms = \Zotlabs\Access\Permissions::Perms();
$name = escape_tags(trim($_POST['name']));
if(! $name) {
notice( t('Permission category name is required.') . EOL);
if (argv(1) && hex2bin(argv(1)) !== $name) {
$return_path = z_root() . '/permcats/' . bin2hex($name);
}
if ($deleted_role && $new_role) {
$r = q("SELECT abook_xchan FROM abook WHERE abook_channel = %d AND abook_role = '%s' AND abook_self = 0 AND abook_pending = 0",
intval(local_channel()),
dbesc($deleted_role)
);
if ($r) {
$contacts = ids_to_array($r, 'abook_xchan');
}
if ($contacts) {
Permcat::assign($channel, $new_role, $contacts);
}
Permcat::delete(local_channel(), $deleted_role);
$default_role = get_pconfig(local_channel(), 'system', 'default_permcat', 'default');
if ($deleted_role === $default_role) {
set_pconfig(local_channel(), 'system', 'default_permcat', $new_role);
}
Libsync::build_sync_packet();
info(t('Contact role deleted.') . EOL);
goaway(z_root() . '/permcats/' . bin2hex($new_role));
return;
}
if ($group_hash === 'all_contacts') {
$r = q("SELECT abook_xchan FROM abook WHERE abook_channel = %d and abook_self = 0 and abook_pending = 0",
intval(local_channel())
);
$pcarr = [];
if ($r) {
$contacts = ids_to_array($r, 'abook_xchan');
}
}
if($all_perms) {
foreach($all_perms as $perm => $desc) {
if(array_key_exists('perms_' . $perm, $_POST)) {
$group = null;
if (!$contacts && $group_hash) {
$group = AccessList::by_hash(local_channel(), $group_hash);
}
if ($group) {
$contacts = AccessList::members_xchan(local_channel(), $group['id']);
}
if (!$name) {
notice(t('Permission category name is required.') . EOL);
return;
}
set_pconfig(local_channel(), 'system', 'default_permcat', 'default');
if (isset($_REQUEST['default_role'])) {
set_pconfig(local_channel(), 'system', 'default_permcat', $name);
}
if ($is_system_role) {
// if we have a system role just set the default and assign if aplicable and be done with it
if ($contacts) {
Permcat::assign($channel, $name, $contacts);
}
info(t('Contact role saved.') . EOL);
Libsync::build_sync_packet();
goaway($return_path);
return;
}
$pcarr = [];
$all_perms = Permissions::Perms();
if ($all_perms) {
foreach ($all_perms as $perm => $desc) {
if (array_key_exists('perms_' . $perm, $_POST)) {
$pcarr[] = $perm;
}
}
}
\Zotlabs\Lib\Permcat::update(local_channel(),$name,$pcarr);
$pcat = new Permcat(local_channel());
$pcatlist = $pcat->listing();
$existing_raw_perms = [];
if ($pcatlist) {
foreach ($pcatlist as $pc) {
if ($pc['name'] && ($pc['name'] === $name)) {
$existing_raw_perms = $pc['raw_perms'];
}
}
}
if (!$contacts && array_diff_assoc($existing_raw_perms, Permissions::FilledPerms($pcarr))) {
// If we don't have anyone to assign the role to and an existing role has changed,
// we will re-assign the changed role to all its members if there are any.
$r = q("SELECT abook_xchan FROM abook WHERE abook_channel = %d AND abook_role = '%s' AND abook_self = 0 AND abook_pending = 0",
intval(local_channel()),
dbesc($name)
);
if ($r) {
$contacts = ids_to_array($r, 'abook_xchan');
}
}
Permcat::update(local_channel(), $name, $pcarr);
if ($contacts) {
Permcat::assign($channel, $name, $contacts);
}
Libsync::build_sync_packet();
info( t('Permission category saved.') . EOL);
info(t('Contact role saved.') . EOL);
goaway($return_path);
return;
}
@@ -53,79 +160,107 @@ class Permcats extends Controller {
function get() {
if(! local_channel())
return;
if (!local_channel())
return EMPTY_STR;
if(! Apps::system_app_installed(local_channel(), 'Permission Categories')) {
//Do not display any associated widgets at this point
App::$pdl = '';
$papp = Apps::get_papp('Permission Categories');
return Apps::app_render($papp, 'module');
}
nav_set_selected('Contact Roles');
$channel = App::get_channel();
if(argc() > 1)
$name = '';
if (argc() > 1) {
$name = hex2bin(argv(1));
if(argc() > 2 && argv(2) === 'drop') {
\Zotlabs\Lib\Permcat::delete(local_channel(),$name);
Libsync::build_sync_packet();
json_return_and_die([ 'success' => true ]);
}
$perms = [];
$existing = [];
$pcat = new Permcat(local_channel());
$pcatlist = $pcat->listing();
$is_system_role = false;
$delete_role_select_options = [];
$is_default_role = (get_pconfig(local_channel(), 'system', 'default_permcat', 'default') === $name);
$localname = '';
$desc = t('Use this form to create permission rules for various classes of people or connections.');
$existing = [];
$pcat = new \Zotlabs\Lib\Permcat(local_channel());
$pcatlist = $pcat->listing();
$permcats = [];
if($pcatlist) {
foreach($pcatlist as $pc) {
if(($pc['name']) && ($name) && ($pc['name'] == $name))
if ($pcatlist) {
foreach ($pcatlist as $pc) {
if ($pc['name'] && $name && ($pc['name'] === $name)) {
$existing = $pc['perms'];
if(! $pc['system'])
$permcats[bin2hex($pc['name'])] = $pc['localname'];
if (isset($pc['system']) && intval($pc['system']))
$is_system_role = $pc['name'];
}
if ($pc['name'] == $name) {
$localname = $pc['localname'];
}
if ($pc['name'] !== $name) {
$delete_role_select_options[$pc['name']] = $pc['localname'];
}
}
}
$global_perms = \Zotlabs\Access\Permissions::Perms();
// select for delete action
$delete_role_select = [
'new_role',
(($is_default_role) ? t('Role to assign affected contacts and default role to') : t('Role to assign affected contacts to')),
'',
'',
$delete_role_select_options
];
foreach($global_perms as $k => $v) {
$thisperm = \Zotlabs\Lib\Permcat::find_permcat($existing,$k);
$checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(),$k);
$global_perms = Permissions::Perms();
if($existing[$k])
$thisperm = "1";
foreach ($global_perms as $k => $v) {
$thisperm = Permcat::find_permcat($existing, $k);
$checkinherited = PermissionLimits::Get(local_channel(), $k);
$perms[] = array('perms_' . $k, $v, '',$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited);
if ($existing[$k])
$thisperm = 1;
$perms[] = [
'perms_' . $k,
$v,
'',
$thisperm,
1,
(($checkinherited & PERMS_SPECIFIC) ? '' : '1'),
'',
$checkinherited
];
}
$group_select_options = [
'selected' => '',
'form_id' => 'group_select',
'label' => t('Assign this role to'),
'after' => [
'name' => t('All my contacts'),
'id' => 'all_contacts',
'selected' => false
]
];
$group_select = AccessList::select(local_channel(), $group_select_options);
$tpl = get_markup_template("permcats.tpl");
$o .= replace_macros($tpl, array(
$o = replace_macros($tpl, [
'$form_security_token' => get_form_security_token("permcats"),
'$title' => t('Permission Categories'),
'$desc' => $desc,
'$desc2' => $desc2,
'$tokens' => $t,
'$permcats' => $permcats,
'$atoken' => $atoken,
'$url1' => z_root() . '/channel/' . $channel['channel_address'],
'$url2' => z_root() . '/photos/' . $channel['channel_address'],
'$name' => array('name', t('Permission category name') . ' <span class="required">*</span>', (($name) ? $name : ''), ''),
'$me' => t('My Settings'),
'$perms' => $perms,
'$inherited' => t('inherited'),
'$notself' => 0,
'$self' => 1,
'$permlbl' => t('Individual Permissions'),
'$permnote' => t('Some permissions may be inherited from your channel\'s <a href="settings"><strong>privacy settings</strong></a>, which have higher priority than individual settings. You can <strong>not</strong> change those settings here.'),
'$submit' => t('Submit')
));
'$default_role' => ['default_role', t('Automatically assign this role to new contacts'), intval($is_default_role), '', [t('No'), t('Yes')]],
'$title' => t('Contact Roles'),
'$name' => ['name', t('Role name') . ' <span class="required">*</span>', (($localname) ? $localname : ''), (($is_system_role) ? t('System role - not editable') : ''), '', (($is_system_role) ? 'disabled' : '')],
'$delete_label' => t('Deleting') . ' ' . $localname,
'$current_role' => $name,
'$perms' => $perms,
'$inherited' => t('inherited'),
'$is_system_role' => $is_system_role,
'$permlbl' => t('Role Permissions'),
'$permnote' => t('Some permissions may be inherited from your <a href="settings">channel role</a>, which have higher priority than contact role settings.'),
'$submit' => t('Submit'),
'$return_path' => argv(1),
'$group_select' => $group_select,
'$delete_role_select' => $delete_role_select,
'$delet_role_button' => t('Delete')
]);
return $o;
}

View File

@@ -1,7 +1,11 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Daemon\Master;
use Zotlabs\Lib\Libsync;
use Zotlabs\Web\Controller;
/*
* @file Profile_photo.php
@@ -15,109 +19,123 @@ require_once('include/photos.php');
require_once('include/channel.php');
/* @brief Function for sync'ing permissions of profile-photos and their profile
*
* @param $profileid The id number of the profile to sync
* @return void
*/
class Profile_photo extends \Zotlabs\Web\Controller {
*
*/
class Profile_photo extends Controller {
/* @brief Initalize the profile-photo edit view
*
* @return void
*
*/
function init() {
if(! local_channel()) {
if (!local_channel()) {
return;
}
$channel = \App::get_channel();
profile_load($channel['channel_address']);
$channel = App::get_channel();
$profile = App::$argv[1];
profile_load($channel['channel_address'], $profile);
}
/* @brief Evaluate posted values
*
* @param $a Current application
* @return void
*
*/
function post() {
if(! local_channel()) {
if (!local_channel()) {
return;
}
$channel = \App::get_channel();
$channel = App::get_channel();
check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo');
// Remove cover photo
if(isset($_POST['remove'])) {
$r = q("select id, profile_guid, is_default, gender from profile where uid = %d",
intval(local_channel())
);
$r = q("SELECT resource_id FROM photo WHERE photo_usage = %d AND uid = %d LIMIT 1",
intval(PHOTO_PROFILE),
intval(local_channel())
);
$profile_id = intval($_POST['profile']);
$default_profile_id = null;
$profile = [];
if($r) {
q("update photo set photo_usage = %d where photo_usage = %d and uid = %d",
intval(PHOTO_NORMAL),
intval(PHOTO_PROFILE),
intval(local_channel())
);
$sync = attach_export_data($channel,$r[0]['resource_id']);
if($sync)
Libsync:: build_sync_packet($channel['channel_id'],array('file' => array($sync)));
foreach ($r as $rr) {
if ($rr['is_default']) {
$default_profile_id = intval($rr['id']);
}
if ($profile_id === intval($rr['id'])) {
$profile = $rr;
}
}
$is_default_profile = ($profile_id === $default_profile_id);
// Remove profile photo
if (isset($_POST['remove'])) {
if ($is_default_profile) {
$r = q("SELECT resource_id FROM photo WHERE photo_usage = %d AND uid = %d LIMIT 1",
intval(PHOTO_PROFILE),
intval(local_channel())
);
if ($r) {
q("update photo set photo_usage = %d where photo_usage = %d and uid = %d",
intval(PHOTO_NORMAL),
intval(PHOTO_PROFILE),
intval(local_channel())
);
q("update profile set photo = '%s', thumb = '%s' where is_default = 1 and uid = %d",
dbesc(z_root() . '/photo/profile/l/' . local_channel()),
dbesc(z_root() . '/photo/profile/m/' . local_channel()),
intval(local_channel())
);
}
}
else {
q("update profile set photo = '%s', thumb = '%s' where id = %d and uid = %d",
dbesc(z_root() . '/' . get_default_profile_photo(300)),
dbesc(z_root() . '/' . get_default_profile_photo(80)),
intval($profile_id),
intval(local_channel())
);
}
$sync = attach_export_data($channel, $r[0]['resource_id']);
if ($sync)
Libsync:: build_sync_packet($channel['channel_id'], ['file' => [$sync]]);
$_SESSION['reload_avatar'] = true;
goaway(z_root() . '/profiles');
goaway(z_root() . '/profiles/' . $profile_id);
}
if((array_key_exists('cropfinal',$_POST)) && (intval($_POST['cropfinal']) == 1)) {
if ((array_key_exists('cropfinal', $_POST)) && (intval($_POST['cropfinal']) == 1)) {
// logger('crop: ' . print_r($_POST,true));
// phase 2 - we have finished cropping
if(argc() != 2) {
notice( t('Image uploaded but image cropping failed.') . EOL );
if (argc() != 2) {
notice(t('Image uploaded but image cropping failed.') . EOL);
return;
}
$image_id = argv(1);
if(substr($image_id,-2,1) == '-') {
$scale = substr($image_id,-1,1);
$image_id = substr($image_id,0,-2);
if (substr($image_id, -2, 1) == '-') {
$scale = substr($image_id, -1, 1);
$image_id = substr($image_id, 0, -2);
}
// unless proven otherwise
$is_default_profile = 1;
if($_REQUEST['profile']) {
$r = q("select id, profile_guid, is_default, gender from profile where id = %d and uid = %d limit 1",
intval($_REQUEST['profile']),
intval(local_channel())
);
if($r) {
$profile = $r[0];
if(! intval($profile['is_default']))
$is_default_profile = 0;
}
}
$srcX = intval($_POST['xstart']);
$srcY = intval($_POST['ystart']);
$srcW = intval($_POST['xfinal']) - $srcX;
@@ -126,16 +144,18 @@ class Profile_photo extends \Zotlabs\Web\Controller {
$r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale = %d LIMIT 1",
dbesc($image_id),
dbesc(local_channel()),
intval($scale));
if($r) {
intval($scale)
);
$base_image = $r[0];
if ($r) {
$base_image = $r[0];
$base_image['content'] = (($r[0]['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content']));
$im = photo_factory($base_image['content'], $base_image['mimetype']);
if($im->is_valid()) {
if ($im->is_valid()) {
$im->cropImage(300,$srcX,$srcY,$srcW,$srcH);
$im->cropImage(300, $srcX, $srcY, $srcW, $srcH);
$aid = get_account_id();
@@ -147,12 +167,10 @@ class Profile_photo extends \Zotlabs\Web\Controller {
'album' => t('Profile Photos'),
'os_path' => $base_image['os_path'],
'display_path' => $base_image['display_path'],
'photo_usage' => PHOTO_PROFILE,
'edited' => dbescdate($base_image['edited'])
'photo_usage' => (($is_default_profile) ? PHOTO_PROFILE : PHOTO_NORMAL),
'edited' => dbescdate($base_image['edited'])
];
$p['photo_usage'] = (($is_default_profile) ? PHOTO_PROFILE : PHOTO_NORMAL);
$r1 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_300);
$im->scaleImage(80);
@@ -161,10 +179,10 @@ class Profile_photo extends \Zotlabs\Web\Controller {
$im->scaleImage(48);
$r3 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_48);
if($r1 === false || $r2 === false || $r3 === false) {
if ($r1 === false || $r2 === false || $r3 === false) {
// if one failed, delete them all so we can start over.
notice( t('Image resize failed.') . EOL );
$x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale in ( %d, %d, %d )",
notice(t('Image resize failed.') . EOL);
q("delete from photo where resource_id = '%s' and uid = %d and imgscale in ( %d, %d, %d )",
dbesc($base_image['resource_id']),
local_channel(),
intval(PHOTO_RES_PROFILE_300),
@@ -179,8 +197,8 @@ class Profile_photo extends \Zotlabs\Web\Controller {
intval(PHOTO_RES_PROFILE_80),
intval(PHOTO_RES_PROFILE_48)
);
if($x) {
foreach($x as $xx) {
if ($x) {
foreach ($x as $xx) {
@unlink(dbunescbin($xx['content']));
}
}
@@ -190,16 +208,14 @@ class Profile_photo extends \Zotlabs\Web\Controller {
// If setting for the default profile, unset the profile photo flag from any other photos I own
if($is_default_profile) {
$r = q("update profile set photo = '%s', thumb = '%s' where is_default = 1 and uid = %d",
if ($is_default_profile) {
q("update profile set photo = '%s', thumb = '%s' where is_default = 1 and uid = %d",
dbesc(z_root() . '/photo/profile/l/' . local_channel()),
dbesc(z_root() . '/photo/profile/m/' . local_channel()),
intval(local_channel())
);
$r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d
q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d
AND resource_id != '%s' AND uid = %d",
intval(PHOTO_NORMAL),
intval(PHOTO_PROFILE),
@@ -207,15 +223,13 @@ class Profile_photo extends \Zotlabs\Web\Controller {
intval(local_channel())
);
send_profile_photo_activity($channel,$base_image,$profile);
send_profile_photo_activity($channel, $base_image, $profile);
}
else {
$r = q("update profile set photo = '%s', thumb = '%s' where id = %d and uid = %d",
q("update profile set photo = '%s', thumb = '%s' where id = %d and uid = %d",
dbesc(z_root() . '/photo/' . $base_image['resource_id'] . '-4'),
dbesc(z_root() . '/photo/' . $base_image['resource_id'] . '-5'),
intval($_REQUEST['profile']),
intval($profile_id),
intval(local_channel())
);
}
@@ -223,7 +237,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
// set $send to false in profiles_build_sync() to return the data
// so that we only send one sync packet.
$sync_profiles = profiles_build_sync(local_channel(),false);
$sync_profiles = profiles_build_sync(local_channel(), false);
// We'll set the updated profile-photo timestamp even if it isn't the default profile,
// so that browsers will do a cache update unconditionally
@@ -231,7 +245,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
// changed to a generic URL by a clone operation. Otherwise the new photo may
// not get pushed to other sites correctly.
$r = q("UPDATE xchan set xchan_photo_mimetype = '%s', xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s'
q("UPDATE xchan set xchan_photo_mimetype = '%s', xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s'
where xchan_hash = '%s'",
dbesc($im->getType()),
dbescdate($base_image['edited']),
@@ -241,79 +255,123 @@ class Profile_photo extends \Zotlabs\Web\Controller {
dbesc($channel['xchan_hash'])
);
photo_profile_setperms(local_channel(),$base_image['resource_id'],$_REQUEST['profile']);
photo_profile_setperms(local_channel(), $base_image['resource_id'], $profile_id);
$sync = attach_export_data($channel,$base_image['resource_id']);
if($sync)
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync), 'profile' => $sync_profiles));
$sync = attach_export_data($channel, $base_image['resource_id']);
if ($sync)
Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync], 'profile' => $sync_profiles]);
// Similarly, tell the nav bar to bypass the cache and update the avatar image.
$_SESSION['reload_avatar'] = true;
info( t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL);
info(t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL);
// Update directory in background
\Zotlabs\Daemon\Master::Summon(array('Directory',$channel['channel_id']));
Master::Summon(['Directory', $channel['channel_id']]);
}
else
notice( t('Unable to process image') . EOL);
notice(t('Unable to process image') . EOL);
}
goaway(z_root() . '/profiles');
goaway(z_root() . '/profiles/' . $profile_id);
return; // NOTREACHED
}
// A new photo was uploaded. Store it and save some important details
// in App::$data for use in the cropping function
$hash = photo_new_resource();
$hash = photo_new_resource();
$importing = false;
$smallest = 0;
$smallest = 0;
if($_REQUEST['importfile']) {
$hash = $_REQUEST['importfile'];
if ($_REQUEST['importfile']) {
$hash = $_REQUEST['importfile'];
$importing = true;
}
else {
require_once('include/attach.php');
$res = attach_store(\App::get_channel(), get_observer_hash(), '', array('album' => t('Profile Photos'), 'hash' => $hash, 'nosync' => true, 'source' => 'photos'));
$matches = [];
$partial = false;
if (array_key_exists('HTTP_CONTENT_RANGE', $_SERVER)) {
$pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/', $_SERVER['HTTP_CONTENT_RANGE'], $matches);
if ($pm) {
logger('Content-Range: ' . print_r($matches, true));
$partial = true;
}
}
if ($partial) {
$x = save_chunk($channel, $matches[1], $matches[2], $matches[3]);
if ($x['partial']) {
header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0));
json_return_and_die($x);
}
else {
header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0));
$_FILES['userfile'] = [
'name' => $x['name'],
'type' => $x['type'],
'tmp_name' => $x['tmp_name'],
'error' => $x['error'],
'size' => $x['size']
];
}
}
else {
if (!array_key_exists('userfile', $_FILES)) {
$_FILES['userfile'] = [
'name' => $_FILES['files']['name'],
'type' => $_FILES['files']['type'],
'tmp_name' => $_FILES['files']['tmp_name'],
'error' => $_FILES['files']['error'],
'size' => $_FILES['files']['size']
];
}
}
$res = attach_store(App::get_channel(), get_observer_hash(), '', ['album' => t('Profile Photos'), 'hash' => $hash, 'nosync' => true, 'source' => 'photos']);
json_return_and_die(['message' => $hash]);
}
if(($res && intval($res['data']['is_photo'])) || $importing) {
if (($res && intval($res['data']['is_photo'])) || $importing) {
$i = q("select * from photo where resource_id = '%s' and uid = %d order by imgscale",
dbesc($hash),
intval(local_channel())
);
if(! $i) {
notice( t('Image upload failed.') . EOL );
if (!$i) {
notice(t('Image upload failed.') . EOL);
return;
}
$os_storage = false;
foreach($i as $ii) {
if(intval($ii['imgscale']) < PHOTO_RES_640) {
$smallest = intval($ii['imgscale']);
foreach ($i as $ii) {
if (intval($ii['imgscale']) < PHOTO_RES_640) {
$smallest = intval($ii['imgscale']);
$os_storage = intval($ii['os_storage']);
$imagedata = $ii['content'];
$filetype = $ii['mimetype'];
$imagedata = $ii['content'];
$filetype = $ii['mimetype'];
}
}
}
$imagedata = (($os_storage) ? @file_get_contents(dbunescbin($imagedata)) : dbunescbin($imagedata));
$ph = photo_factory($imagedata, $filetype);
$ph = photo_factory($imagedata, $filetype);
if(! $ph->is_valid()) {
notice( t('Unable to process image.') . EOL );
if (!$ph->is_valid()) {
notice(t('Unable to process image.') . EOL);
return;
}
return $this->profile_photo_crop_ui_head($a, $ph, $hash, $smallest);
return $this->profile_photo_crop_ui_head($ph, $hash, $smallest);
// This will "fall through" to the get() method, and since
// App::$data['imagecrop'] is set, it will proceed to cropping
@@ -322,101 +380,108 @@ class Profile_photo extends \Zotlabs\Web\Controller {
/* @brief Generate content of profile-photo view
*
* @param $a Current application
* @return void
*
*/
function get() {
if(! local_channel()) {
notice( t('Permission denied.') . EOL );
if (!local_channel()) {
notice(t('Permission denied.') . EOL);
return;
}
$channel = \App::get_channel();
$pf = 0;
$newuser = false;
$channel = App::get_channel();
$profile_id = (($_REQUEST['profile']) ? intval($_REQUEST['profile']) : intval(argv(1)));
$default_profile_id = null;
if(argc() == 2 && argv(1) === 'new')
$newuser = true;
$r = q("select id, profile_name as name, is_default from profile where uid = %d order by id asc",
intval(local_channel())
);
if(argv(1) === 'use') {
foreach ($r as $rr) {
if ($rr['is_default']) {
$default_profile_id = intval($rr['id']);
}
if ($profile_id === intval($rr['id'])) {
$profile = $rr;
}
}
$is_default_profile = ($profile_id === $default_profile_id);
if (argv(1) === 'use') {
if (argc() < 3) {
notice( t('Permission denied.') . EOL );
notice(t('Permission denied.') . EOL);
return;
};
$resource_id = argv(2);
$pf = (($_REQUEST['pf']) ? intval($_REQUEST['pf']) : 0);
$c = q("select id, is_default from profile where uid = %d",
intval(local_channel())
);
$multi_profiles = true;
if(($c) && (count($c) === 1) && (intval($c[0]['is_default']))) {
$_REQUEST['profile'] = $c[0]['id'];
$multi_profiles = false;
}
else {
$_REQUEST['profile'] = $pf;
}
$r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' ORDER BY imgscale ASC",
intval(local_channel()),
dbesc($resource_id)
);
if(! $r) {
notice( t('Photo not available.') . EOL );
if (!$r) {
notice(t('Photo not available.') . EOL);
return;
}
$havescale = false;
foreach($r as $rr) {
if($rr['imgscale'] == PHOTO_RES_PROFILE_80)
foreach ($r as $rr) {
if ($rr['imgscale'] == PHOTO_RES_PROFILE_80)
$havescale = true;
}
// set an already loaded and cropped photo as profile photo
if($havescale) {
// unset any existing profile photos
$x = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND uid = %d",
intval(PHOTO_NORMAL),
intval(PHOTO_PROFILE),
if ($havescale) {
if ($is_default_profile) {
// unset any existing profile photos
q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND uid = %d",
intval(PHOTO_NORMAL),
intval(PHOTO_PROFILE),
intval(local_channel())
);
$edited = datetime_convert();
q("UPDATE photo SET photo_usage = %d, edited = '%s' WHERE uid = %d AND resource_id = '%s' AND imgscale > 0",
intval(PHOTO_PROFILE),
dbescdate($edited),
intval(local_channel()),
dbesc($resource_id)
);
q("UPDATE xchan SET xchan_photo_date = '%s' WHERE xchan_hash = '%s'",
dbescdate($edited),
dbesc($channel['xchan_hash'])
);
}
q("update profile set photo = '%s', thumb = '%s' where id = %d and uid = %d",
dbesc(z_root() . '/photo/' . $resource_id . '-4'),
dbesc(z_root() . '/photo/' . $resource_id . '-5'),
intval($profile_id),
intval(local_channel())
);
$edited = datetime_convert();
photo_profile_setperms(local_channel(), $resource_id, $profile_id);
$x = q("UPDATE photo SET photo_usage = %d, edited = '%s' WHERE uid = %d AND resource_id = '%s' AND imgscale > 0",
intval(PHOTO_PROFILE),
dbescdate($edited),
intval(local_channel()),
dbesc($resource_id)
);
$x = q("UPDATE xchan SET xchan_photo_date = '%s' WHERE xchan_hash = '%s'",
dbescdate($edited),
dbesc($channel['xchan_hash'])
);
photo_profile_setperms(local_channel(),$resource_id,$_REQUEST['profile']);
$sync = attach_export_data($channel,$resource_id);
if($sync)
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
$sync = attach_export_data($channel, $resource_id);
if ($sync)
Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync]]);
$_SESSION['reload_avatar'] = true;
\Zotlabs\Daemon\Master::Summon(array('Directory',local_channel()));
Master::Summon(['Directory', local_channel()]);
goaway(z_root() . '/profiles');
goaway(z_root() . '/profiles/' . $profile_id);
}
$r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1",
@@ -424,94 +489,74 @@ class Profile_photo extends \Zotlabs\Web\Controller {
intval(local_channel())
);
if(! $r) {
notice( t('Photo not available.') . EOL );
if (!$r) {
notice(t('Photo not available.') . EOL);
return;
}
if(intval($r[0]['os_storage']))
if (intval($r[0]['os_storage'])) {
$data = @file_get_contents(dbunescbin($r[0]['content']));
else
}
else {
$data = dbunescbin($r[0]['content']);
}
$ph = photo_factory($data, $r[0]['mimetype']);
$ph = photo_factory($data, $r[0]['mimetype']);
$smallest = 0;
if($ph->is_valid()) {
if ($ph->is_valid()) {
// go ahead as if we have just uploaded a new photo to crop
$i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d order by imgscale",
dbesc($r[0]['resource_id']),
intval(local_channel())
);
if($i) {
if ($i) {
$hash = $i[0]['resource_id'];
foreach($i as $ii) {
if(intval($ii['imgscale']) < PHOTO_RES_640) {
foreach ($i as $ii) {
if (intval($ii['imgscale']) < PHOTO_RES_640) {
$smallest = intval($ii['imgscale']);
}
}
}
}
}
}
if($multi_profiles) {
\App::$data['importfile'] = $resource_id;
}
else {
$this->profile_photo_crop_ui_head($a, $ph, $hash, $smallest);
}
$this->profile_photo_crop_ui_head($ph, $hash, $smallest);
// falls through with App::$data['imagecrop'] set so we go straight to the cropping section
}
// present an upload form
$importing = ((array_key_exists('importfile', App::$data)) ? true : false);
$profiles = q("select id, profile_name as name, is_default from profile where uid = %d order by id asc",
intval(local_channel())
);
if($profiles) {
for($x = 0; $x < count($profiles); $x ++) {
$profiles[$x]['selected'] = false;
if($pf && $profiles[$x]['id'] == $pf)
$profiles[$x]['selected'] = true;
if((! $pf) && $profiles[$x]['is_default'])
$profiles[$x]['selected'] = true;
}
}
$importing = ((array_key_exists('importfile',\App::$data)) ? true : false);
if(! x(\App::$data,'imagecrop')) {
if (!x(App::$data, 'imagecrop')) {
$tpl = get_markup_template('profile_photo.tpl');
$o .= replace_macros($tpl,array(
'$user' => \App::$channel['channel_address'],
'$info' => ((count($profiles) > 1) ? t('Your default profile photo is visible to anybody on the internet. Profile photos for alternate profiles will inherit the permissions of the profile') : t('Your profile photo is visible to anybody on the internet and may be distributed to other websites.')),
'$importfile' => (($importing) ? \App::$data['importfile'] : ''),
'$lbl_upfile' => t('Upload File:'),
'$lbl_profiles' => t('Select a profile:'),
'$title' => (($importing) ? t('Use Photo for Profile') : t('Change Profile Photo')),
'$submit' => (($importing) ? t('Use') : t('Upload')),
'$remove' => t('Remove'),
'$profiles' => $profiles,
'$single' => ((count($profiles) == 1) ? true : false),
'$profile0' => $profiles[0],
'$embedPhotos' => t('Use a photo from your albums'),
'$embedPhotosModalTitle' => t('Use a photo from your albums'),
$o = replace_macros($tpl, [
'$user' => App::$channel['channel_address'],
'$info' => (($is_default_profile) ? t('This profile photo will be visible to anybody on the internet and may be distributed to other websites.') : t('This profile photo will be visible only to channels with permission to view this profile.')),
'$importfile' => (($importing) ? App::$data['importfile'] : ''),
'$title' => (($importing) ? t('Use Photo for Profile') : t('Change Profile Photo')),
'$submit' => t('Upload'),
'$remove' => t('Reset to default'),
'$profile_id' => $profile_id,
'$profile' => $profile,
'$embedPhotos' => t('Use a photo from your albums'),
'$embedPhotosModalTitle' => t('Use a photo from your albums'),
'$embedPhotosModalCancel' => t('Cancel'),
'$embedPhotosModalOK' => t('OK'),
'$modalchooseimages' => t('Choose images to embed'),
'$modalchoosealbum' => t('Choose an album'),
'$modaldiffalbum' => t('Choose a different album'),
'$modalerrorlist' => t('Error getting album list'),
'$modalerrorlink' => t('Error getting photo link'),
'$modalerroralbum' => t('Error getting album'),
'$form_security_token' => get_form_security_token("profile_photo"),
'$select' => t('Select existing photo'),
));
'$embedPhotosModalOK' => t('OK'),
'$modalchooseimages' => t('Choose images to embed'),
'$modalchoosealbum' => t('Choose an album'),
'$modaldiffalbum' => t('Choose a different album'),
'$modalerrorlist' => t('Error getting album list'),
'$modalerrorlink' => t('Error getting photo link'),
'$modalerroralbum' => t('Error getting album'),
'$form_security_token' => get_form_security_token("profile_photo"),
'$select' => t('Select existing'),
]);
call_hooks('profile_photo_content_end', $o);
@@ -521,19 +566,20 @@ class Profile_photo extends \Zotlabs\Web\Controller {
// present a cropping form
$filename = \App::$data['imagecrop'] . '-' . \App::$data['imagecrop_resolution'];
$resolution = \App::$data['imagecrop_resolution'];
$tpl = get_markup_template("cropbody.tpl");
$o .= replace_macros($tpl,array(
'$filename' => $filename,
'$profile' => intval($_REQUEST['profile']),
'$resource' => \App::$data['imagecrop'] . '-' . \App::$data['imagecrop_resolution'],
'$image_url' => z_root() . '/photo/' . $filename,
'$title' => t('Crop Image'),
'$desc' => t('Please adjust the image cropping for optimum viewing.'),
$filename = App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution'];
$tpl = get_markup_template("cropbody.tpl");
$o = replace_macros($tpl, [
'$filename' => $filename,
'$profile' => $profile_id,
'$resource' => App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution'],
'$image_url' => z_root() . '/photo/' . $filename,
'$title' => t('Crop Image'),
'$desc' => t('Please adjust the image cropping for optimum viewing.'),
'$form_security_token' => get_form_security_token("profile_photo"),
'$done' => t('Done Editing')
));
'$done' => t('Done editing')
]);
return $o;
}
@@ -542,35 +588,37 @@ class Profile_photo extends \Zotlabs\Web\Controller {
/* @brief Generate the UI for photo-cropping
*
* @param $a Current application
* @param $ph Photo-Factory
* @return void
* @param $ph
* @param $hash
* @param $smallest
*
*/
function profile_photo_crop_ui_head($ph, $hash, $smallest) {
function profile_photo_crop_ui_head(&$a, $ph, $hash, $smallest){
$max_length = get_config('system', 'max_image_length');
$max_length = get_config('system','max_image_length');
if(! $max_length)
if (!$max_length) {
$max_length = MAX_IMAGE_LENGTH;
if($max_length > 0)
}
if ($max_length > 0) {
$ph->scaleImage($max_length);
\App::$data['width'] = $ph->getWidth();
\App::$data['height'] = $ph->getHeight();
if(\App::$data['width'] < 500 || \App::$data['height'] < 500) {
$ph->scaleImageUp(400);
\App::$data['width'] = $ph->getWidth();
\App::$data['height'] = $ph->getHeight();
}
App::$data['width'] = $ph->getWidth();
App::$data['height'] = $ph->getHeight();
if (App::$data['width'] < 500 || App::$data['height'] < 500) {
$ph->scaleImageUp(400);
App::$data['width'] = $ph->getWidth();
App::$data['height'] = $ph->getHeight();
}
App::$data['imagecrop'] = $hash;
App::$data['imagecrop_resolution'] = $smallest;
App::$page['htmlhead'] .= replace_macros(get_markup_template("crophead.tpl"), []);
\App::$data['imagecrop'] = $hash;
\App::$data['imagecrop_resolution'] = $smallest;
\App::$page['htmlhead'] .= replace_macros(get_markup_template("crophead.tpl"), array());
return;
}

View File

@@ -163,34 +163,6 @@ class Profiles extends \Zotlabs\Web\Controller {
killme();
}
// Run profile_load() here to make sure the theme is set before
// we start loading content
if(((argc() > 1) && (intval(argv(1)))) || !feature_enabled(local_channel(),'multi_profiles')) {
if(feature_enabled(local_channel(),'multi_profiles'))
$id = \App::$argv[1];
else {
$x = q("select id from profile where uid = %d and is_default = 1",
intval(local_channel())
);
if($x)
$id = $x[0]['id'];
}
$r = q("SELECT * FROM profile WHERE id = %d AND uid = %d LIMIT 1",
intval($id),
intval(local_channel())
);
if(! count($r)) {
notice( t('Profile not found.') . EOL);
\App::$error = 404;
return;
}
$chan = \App::get_channel();
profile_load($chan['channel_address'],$r[0]['id']);
}
}
function post() {
@@ -316,8 +288,6 @@ class Profiles extends \Zotlabs\Web\Controller {
$work = fix_mce_lf(escape_tags(trim($_POST['work'])));
$education = fix_mce_lf(escape_tags(trim($_POST['education'])));
$hide_friends = ((intval($_POST['hide_friends'])) ? 1: 0);
// start fresh and create a new vcard. TODO: preserve the original guid or whatever else needs saving
// $orig_vcard = (($orig[0]['profile_vcard']) ? \Sabre\VObject\Reader::read($orig[0]['profile_vcard']) : null);
@@ -513,6 +483,16 @@ class Profiles extends \Zotlabs\Web\Controller {
$value = $locality . $comma1 . $region . $comma2 . $country_name;
}
$hide_friends = ((intval($_POST['hide_friends'])) ? 1: 0);
$suggestme = ((x($_POST, 'suggestme')) ? intval($_POST['suggestme']) : 0);
set_pconfig(local_channel(), 'system', 'suggestme', $suggestme);
$show_presence = (((x($_POST, 'show_presence')) && (intval($_POST['show_presence']) == 1)) ? 1 : 0);
set_pconfig(local_channel(), 'system', 'show_online_status', $show_presence);
$publish = ((x($_POST, 'profile_in_directory') && (intval($_POST['profile_in_directory']) == 1)) ? 1 : 0);
profile_activity($changes,$value);
}
@@ -551,7 +531,8 @@ class Profiles extends \Zotlabs\Web\Controller {
employment = '%s',
education = '%s',
hide_friends = %d,
profile_vcard = '%s'
profile_vcard = '%s',
publish = %d
WHERE id = %d AND uid = %d",
dbesc($profile_name),
dbesc($name),
@@ -587,6 +568,7 @@ class Profiles extends \Zotlabs\Web\Controller {
dbesc($education),
intval($hide_friends),
dbesc($profile_vcard),
intval($publish),
intval(argv(1)),
intval(local_channel())
);
@@ -597,10 +579,11 @@ class Profiles extends \Zotlabs\Web\Controller {
$channel = \App::get_channel();
if($namechanged && $is_default) {
q("UPDATE xchan SET xchan_name = '%s', xchan_name_date = '%s' WHERE xchan_hash = '%s'",
// change name on all associated xchans by matching the url
q("UPDATE xchan SET xchan_name = '%s', xchan_name_date = '%s' WHERE xchan_url = '%s'",
dbesc($name),
dbesc(datetime_convert()),
dbesc($channel['xchan_hash'])
dbesc(z_root() . '/channel/' . $channel['channel_address'])
);
q("UPDATE channel SET channel_name = '%s' WHERE channel_hash = '%s'",
dbesc($name),
@@ -618,8 +601,6 @@ class Profiles extends \Zotlabs\Web\Controller {
}
if($is_default) {
// reload the info for the sidebar widget
profile_load($channel['channel_address']);
\Zotlabs\Daemon\Master::Summon(array('Directory',local_channel()));
}
}
@@ -630,13 +611,13 @@ class Profiles extends \Zotlabs\Web\Controller {
$o = '';
$channel = \App::get_channel();
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
return;
}
$channel = \App::get_channel();
require_once('include/channel.php');
$profile_fields_basic = get_profile_fields_basic();
@@ -652,6 +633,7 @@ class Profiles extends \Zotlabs\Web\Controller {
if($x)
$id = $x[0]['id'];
}
$r = q("SELECT * FROM profile WHERE id = %d AND uid = %d LIMIT 1",
intval($id),
intval(local_channel())
@@ -662,6 +644,9 @@ class Profiles extends \Zotlabs\Web\Controller {
return;
}
// make sure we got uptodate data
profile_load($channel['channel_address'], $id);
$editselect = 'none';
\App::$page['htmlhead'] .= replace_macros(get_markup_template('profed_head.tpl'), array(
@@ -675,13 +660,43 @@ class Profiles extends \Zotlabs\Web\Controller {
else
$fields = $profile_fields_basic;
$hide_friends = array(
'hide_friends',
t('Hide your connections list from viewers of this profile'),
$r[0]['hide_friends'],
'',
array(t('No'),t('Yes'))
);
$show_presence = [];
$profile_in_dir = '';
$suggestme = '';
$hide_friends = [];
$is_default = (($r[0]['is_default']) ? 1 : 0);
if ($is_default) {
$hide_friends = array(
'hide_friends',
t('Hide my connections from viewers of this profile'),
$r[0]['hide_friends'],
'',
[t('No'), t('Yes')]
);
$opt_tpl = get_markup_template("field_checkbox.tpl");
if (get_config('system', 'publish_all')) {
$profile_in_dir = '<input type="hidden" name="profile_in_directory" value="1" />';
}
else {
$profile_in_dir = replace_macros($opt_tpl, [
'$field' => ['profile_in_directory', t('Publish my default profile in the network directory'), $r[0]['publish'], '', [t('No'), t('Yes')]],
]);
}
$suggestme = get_pconfig(local_channel(), 'system', 'suggestme');
$suggestme = (($suggestme === false) ? '0' : $suggestme); // default if not set: 0
$suggestme = replace_macros($opt_tpl, [
'$field' => ['suggestme', t('Suggest me as a potential contact to new members'), $suggestme, '', [t('No'), t('Yes')]],
]);
$show_presence_val = intval(get_pconfig(local_channel(), 'system', 'show_online_status'));
$show_presence = ['show_presence', t('Reveal my online status'), $show_presence_val, '', [t('No'), t('Yes')]];
}
$q = q("select * from profdef where true");
if($q) {
@@ -702,15 +717,15 @@ class Profiles extends \Zotlabs\Web\Controller {
//logger('extra_fields: ' . print_r($extra_fields,true));
$vc = $r[0]['profile_vcard'];
$vctmp = (($vc) ? \Sabre\VObject\Reader::read($vc) : null);
$vcard = (($vctmp) ? get_vcard_array($vctmp,$r[0]['id']) : [] );
//$vc = $r[0]['profile_vcard'];
//$vctmp = (($vc) ? \Sabre\VObject\Reader::read($vc) : null);
//$vcard = (($vctmp) ? get_vcard_array($vctmp,$r[0]['id']) : [] );
$f = get_config('system','birthday_input_format');
if(! $f)
$f = 'ymd';
$is_default = (($r[0]['is_default']) ? 1 : 0);
$tpl = get_markup_template("profile_edit.tpl");
$o .= replace_macros($tpl,array(
@@ -719,12 +734,12 @@ class Profiles extends \Zotlabs\Web\Controller {
'$profile_clone_link' => 'profiles/clone/' . $r[0]['id'] . '?t=' . get_form_security_token("profile_clone"),
'$profile_drop_link' => 'profiles/drop/' . $r[0]['id'] . '?t=' . get_form_security_token("profile_drop"),
'$fields' => $fields,
'$vcard' => $vcard,
//'$vcard' => $vcard,
'$guid' => $r[0]['profile_guid'],
'$banner' => t('Edit Profile Details'),
'$submit' => t('Submit'),
'$viewprof' => t('View this profile'),
'$editvis' => t('Edit visibility'),
'$editvis' => t('Edit visibility'),
'$tools_label' => t('Profile Tools'),
'$coverpic' => t('Change cover photo'),
'$profpic' => t('Change profile photo'),
@@ -732,7 +747,7 @@ class Profiles extends \Zotlabs\Web\Controller {
'$cl_prof' => t('Clone this profile'),
'$del_prof' => t('Delete this profile'),
'$addthing' => t('Add profile things'),
'$personal' => t('Personal'),
'$basic' => t('Basic'),
'$location' => t('Location'),
'$relation' => t('Relationship'),
'$miscellaneous'=> t('Miscellaneous'),
@@ -784,23 +799,28 @@ class Profiles extends \Zotlabs\Web\Controller {
'$contact' => array('contact', t('Contact information and social networks'), $r[0]['contact']),
'$channels' => array('channels', t('My other channels'), $r[0]['channels']),
'$extra_fields' => $extra_fields,
'$comms' => t('Communications'),
'$tel_label' => t('Phone'),
'$email_label' => t('Email'),
'$impp_label' => t('Instant messenger'),
'$url_label' => t('Website'),
'$adr_label' => t('Address'),
'$note_label' => t('Note'),
'$mobile' => t('Mobile'),
'$home' => t('Home'),
'$work' => t('Work'),
'$other' => t('Other'),
'$add_card' => t('Add Contact'),
'$add_field' => t('Add Field'),
'$create' => t('Create'),
'$update' => t('Update'),
'$delete' => t('Delete'),
'$cancel' => t('Cancel'),
//'$comms' => t('Communications'),
//'$tel_label' => t('Phone'),
//'$email_label' => t('Email'),
//'$impp_label' => t('Instant messenger'),
//'$url_label' => t('Website'),
//'$adr_label' => t('Address'),
//'$note_label' => t('Note'),
//'$mobile' => t('Mobile'),
//'$home' => t('Home'),
//'$work' => t('Work'),
//'$other' => t('Other'),
//'$add_card' => t('Add Contact'),
//'$add_field' => t('Add Field'),
//'$create' => t('Create'),
//'$update' => t('Update'),
//'$delete' => t('Delete'),
//'$cancel' => t('Cancel'),
'$show_presence' => $show_presence,
'$suggestme' => $suggestme,
'$profile_in_dir' => $profile_in_dir,
));
$arr = array('profile' => $r[0], 'entry' => $o);

View File

@@ -196,7 +196,7 @@ class Regate extends \Zotlabs\Web\Controller {
if ($invite_channel) {
$f = Connect::connect($new_channel['channel'], $invite_channel['xchan_addr']);
if ($f['success']) {
$can_view_stream = their_perms_contains($channel_id, $f['abook']['abook_xchan'], 'view_stream');
$can_view_stream = intval(get_abconfig($channel_id, $f['abook']['abook_xchan'], 'their_perms', 'view_stream'));
// If we can view their stream, pull in some posts
if ($can_view_stream) {
Master::Summon(['Onepoll', $f['abook']['abook_id']]);

View File

@@ -57,8 +57,8 @@ class Removeme extends \Zotlabs\Web\Controller {
$o .= replace_macros($tpl, array(
'$basedir' => z_root(),
'$hash' => $hash,
'$title' => t('Remove This Channel'),
'$desc' => [ t('WARNING: '), t('This channel will be completely removed from the network. '), t('This action is permanent and can not be undone!') ],
'$title' => t('Remove Channel'),
'$desc' => [ t('WARNING: '), t('This channel will be permanently removed. '), t('This action can not be undone!') ],
'$passwd' => t('Please enter your password for verification:'),
// '$global' => [ 'global', t('Remove this channel and all its clones from the network'), false, t('By default only the instance of the channel located on this hub will be removed from the network'), [ t('No'),t('Yes') ] ],
'$submit' => t('Remove Channel')

View File

@@ -7,6 +7,7 @@ use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Zotfinger;
class Search extends Controller {
@@ -58,10 +59,26 @@ class Search extends Controller {
$o .= search($search, 'search-box', '/search', ((local_channel()) ? true : false));
if (local_channel() && strpos($search, 'https://') === 0 && !$update && !$load) {
if (strpos($search, 'b64.') !== false) {
if (strpos($search, '?') !== false) {
$search = strtok($search, '?');
}
$search = unpack_link_id(basename($search));
}
$f = Libzot::fetch_conversation(App::get_channel(), punify($search), true);
if ($f) {
goaway(z_root() . '/hq/' . gen_link_id($f['message_id']));
$mid = $f[0]['message_id'];
foreach ($f as $m) {
if (strpos($search, $m['message_id']) === 0) {
$mid = $m['message_id'];
break;
}
}
goaway(z_root() . '/hq/' . gen_link_id($mid));
}
else {
// try other fetch providers (e.g. diaspora, pubcrawl)

View File

@@ -2,6 +2,10 @@
namespace Zotlabs\Module\Settings;
use App;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Access\PermissionRoles;
use Zotlabs\Daemon\Master;
use Zotlabs\Lib\Apps;
use Zotlabs\Lib\Libsync;
@@ -10,602 +14,272 @@ require_once('include/selectors.php');
class Channel {
function post() {
$channel = \App::get_channel();
check_form_security_token_redirectOnErr('/settings', 'settings');
call_hooks('settings_post', $_POST);
$set_perms = '';
$channel = App::get_channel();
$role = ((x($_POST, 'permissions_role')) ? notags(trim($_POST['permissions_role'])) : '');
$timezone = ((x($_POST, 'timezone_select')) ? notags(trim($_POST['timezone_select'])) : '');
$defloc = ((x($_POST, 'defloc')) ? notags(trim($_POST['defloc'])) : '');
$evdays = ((x($_POST, 'evdays')) ? intval($_POST['evdays']) : 3);
$photo_path = ((x($_POST, 'photo_path')) ? escape_tags(trim($_POST['photo_path'])) : '');
$attach_path = ((x($_POST, 'attach_path')) ? escape_tags(trim($_POST['attach_path'])) : '');
$allow_location = (((x($_POST, 'allow_location')) && (intval($_POST['allow_location']) == 1)) ? 1 : 0);
$post_newfriend = (($_POST['post_newfriend'] == 1) ? 1 : 0);
$post_joingroup = (($_POST['post_joingroup'] == 1) ? 1 : 0);
$post_profilechange = (($_POST['post_profilechange'] == 1) ? 1 : 0);
$adult = (($_POST['adult'] == 1) ? 1 : 0);
$mailhost = ((array_key_exists('mailhost', $_POST)) ? notags(trim($_POST['mailhost'])) : '');
$pageflags = $channel['channel_pageflags'];
$existing_adult = (($pageflags & PAGE_ADULT) ? 1 : 0);
$expire = ((x($_POST, 'expire')) ? intval($_POST['expire']) : 0);
$role = ((x($_POST,'permissions_role')) ? notags(trim($_POST['permissions_role'])) : '');
$oldrole = get_pconfig(local_channel(),'system','permissions_role');
// This mapping can be removed after 3.4 release
if($oldrole === 'social_party') {
$oldrole = 'social_federation';
}
if(($role != $oldrole) || ($role === 'custom')) {
if($role === 'custom') {
$hide_presence = (((x($_POST,'hide_presence')) && (intval($_POST['hide_presence']) == 1)) ? 1: 0);
$publish = (((x($_POST,'profile_in_directory')) && (intval($_POST['profile_in_directory']) == 1)) ? 1: 0);
$def_group = ((x($_POST,'group-selection')) ? notags(trim($_POST['group-selection'])) : '');
$r = q("update channel set channel_default_group = '%s' where channel_id = %d",
dbesc($def_group),
intval(local_channel())
);
$global_perms = \Zotlabs\Access\Permissions::Perms();
foreach($global_perms as $k => $v) {
\Zotlabs\Access\PermissionLimits::Set(local_channel(),$k,intval($_POST[$k]));
}
$acl = new \Zotlabs\Access\AccessList($channel);
$acl->set_from_array($_POST);
$x = $acl->get();
$r = q("update channel set channel_allow_cid = '%s', channel_allow_gid = '%s',
channel_deny_cid = '%s', channel_deny_gid = '%s' where channel_id = %d",
dbesc($x['allow_cid']),
dbesc($x['allow_gid']),
dbesc($x['deny_cid']),
dbesc($x['deny_gid']),
intval(local_channel())
);
}
else {
$role_permissions = \Zotlabs\Access\PermissionRoles::role_perms($_POST['permissions_role']);
if(! $role_permissions) {
notice('Permissions category could not be found.');
return;
}
$hide_presence = 1 - (intval($role_permissions['online']));
if($role_permissions['default_collection']) {
$r = q("select hash from pgrp where uid = %d and gname = '%s' limit 1",
intval(local_channel()),
dbesc( t('Friends') )
);
if(! $r) {
require_once('include/group.php');
group_add(local_channel(), t('Friends'));
group_add_member(local_channel(),t('Friends'),$channel['channel_hash']);
$r = q("select hash from pgrp where uid = %d and gname = '%s' limit 1",
intval(local_channel()),
dbesc( t('Friends') )
);
}
if($r) {
q("update channel set channel_default_group = '%s', channel_allow_gid = '%s', channel_allow_cid = '', channel_deny_gid = '', channel_deny_cid = '' where channel_id = %d",
dbesc($r[0]['hash']),
dbesc('<' . $r[0]['hash'] . '>'),
intval(local_channel())
);
}
else {
notice( sprintf('Default privacy group \'%s\' not found. Please create and re-submit permission change.', t('Friends')) . EOL);
return;
}
}
// no default collection
else {
q("update channel set channel_default_group = '', channel_allow_gid = '', channel_allow_cid = '', channel_deny_gid = '',
channel_deny_cid = '' where channel_id = %d",
intval(local_channel())
);
}
if($role_permissions['perms_connect']) {
$x = \Zotlabs\Access\Permissions::FilledPerms($role_permissions['perms_connect']);
foreach($x as $k => $v) {
set_abconfig(local_channel(),$channel['channel_hash'],'my_perms',$k, $v);
if($role_permissions['perms_auto']) {
set_pconfig(local_channel(),'autoperms',$k,$v);
}
else {
del_pconfig(local_channel(),'autoperms',$k);
}
}
}
if($role_permissions['limits']) {
foreach($role_permissions['limits'] as $k => $v) {
\Zotlabs\Access\PermissionLimits::Set(local_channel(),$k,$v);
}
}
if(array_key_exists('directory_publish',$role_permissions)) {
$publish = intval($role_permissions['directory_publish']);
}
}
set_pconfig(local_channel(),'system','hide_online_status',$hide_presence);
set_pconfig(local_channel(),'system','permissions_role',$role);
}
$username = ((x($_POST,'username')) ? notags(trim($_POST['username'])) : '');
$timezone = ((x($_POST,'timezone_select')) ? notags(trim($_POST['timezone_select'])) : '');
$defloc = ((x($_POST,'defloc')) ? notags(trim($_POST['defloc'])) : '');
$openid = ((x($_POST,'openid_url')) ? notags(trim($_POST['openid_url'])) : '');
$maxreq = ((x($_POST,'maxreq')) ? intval($_POST['maxreq']) : 0);
$expire = ((x($_POST,'expire')) ? intval($_POST['expire']) : 0);
$evdays = ((x($_POST,'evdays')) ? intval($_POST['evdays']) : 3);
$photo_path = ((x($_POST,'photo_path')) ? escape_tags(trim($_POST['photo_path'])) : '');
$attach_path = ((x($_POST,'attach_path')) ? escape_tags(trim($_POST['attach_path'])) : '');
$expire_items = ((x($_POST,'expire_items')) ? intval($_POST['expire_items']) : 0);
$expire_starred = ((x($_POST,'expire_starred')) ? intval($_POST['expire_starred']) : 0);
$expire_photos = ((x($_POST,'expire_photos'))? intval($_POST['expire_photos']) : 0);
$expire_network_only = ((x($_POST,'expire_network_only'))? intval($_POST['expire_network_only']) : 0);
$allow_location = (((x($_POST,'allow_location')) && (intval($_POST['allow_location']) == 1)) ? 1: 0);
$blocktags = (((x($_POST,'blocktags')) && (intval($_POST['blocktags']) == 1)) ? 0: 1); // this setting is inverted!
$unkmail = (((x($_POST,'unkmail')) && (intval($_POST['unkmail']) == 1)) ? 1: 0);
$cntunkmail = ((x($_POST,'cntunkmail')) ? intval($_POST['cntunkmail']) : 0);
$suggestme = ((x($_POST,'suggestme')) ? intval($_POST['suggestme']) : 0);
$autoperms = ((x($_POST,'autoperms')) ? intval($_POST['autoperms']) : 0);
$post_newfriend = (($_POST['post_newfriend'] == 1) ? 1: 0);
$post_joingroup = (($_POST['post_joingroup'] == 1) ? 1: 0);
$post_profilechange = (($_POST['post_profilechange'] == 1) ? 1: 0);
$adult = (($_POST['adult'] == 1) ? 1 : 0);
$defpermcat = ((x($_POST,'defpermcat')) ? notags(trim($_POST['defpermcat'])) : 'default');
$mailhost = ((array_key_exists('mailhost',$_POST)) ? notags(trim($_POST['mailhost'])) : '');
$pageflags = $channel['channel_pageflags'];
$existing_adult = (($pageflags & PAGE_ADULT) ? 1 : 0);
if($adult != $existing_adult)
if ($adult != $existing_adult) {
$pageflags = ($pageflags ^ PAGE_ADULT);
}
$notify = 0;
if(x($_POST,'notify1'))
if (x($_POST, 'notify1'))
$notify += intval($_POST['notify1']);
if(x($_POST,'notify2'))
if (x($_POST, 'notify2'))
$notify += intval($_POST['notify2']);
if(x($_POST,'notify3'))
if (x($_POST, 'notify3'))
$notify += intval($_POST['notify3']);
if(x($_POST,'notify4'))
if (x($_POST, 'notify4'))
$notify += intval($_POST['notify4']);
if(x($_POST,'notify5'))
if (x($_POST, 'notify5'))
$notify += intval($_POST['notify5']);
if(x($_POST,'notify6'))
if (x($_POST, 'notify6'))
$notify += intval($_POST['notify6']);
if(x($_POST,'notify7'))
if (x($_POST, 'notify7'))
$notify += intval($_POST['notify7']);
if(x($_POST,'notify8'))
if (x($_POST, 'notify8'))
$notify += intval($_POST['notify8']);
$vnotify = 0;
if(x($_POST,'vnotify1'))
if (x($_POST, 'vnotify1'))
$vnotify += intval($_POST['vnotify1']);
if(x($_POST,'vnotify2'))
if (x($_POST, 'vnotify2'))
$vnotify += intval($_POST['vnotify2']);
if(x($_POST,'vnotify3'))
if (x($_POST, 'vnotify3'))
$vnotify += intval($_POST['vnotify3']);
if(x($_POST,'vnotify4'))
if (x($_POST, 'vnotify4'))
$vnotify += intval($_POST['vnotify4']);
if(x($_POST,'vnotify5'))
if (x($_POST, 'vnotify5'))
$vnotify += intval($_POST['vnotify5']);
if(x($_POST,'vnotify6'))
if (x($_POST, 'vnotify6'))
$vnotify += intval($_POST['vnotify6']);
if(x($_POST,'vnotify7'))
if (x($_POST, 'vnotify7'))
$vnotify += intval($_POST['vnotify7']);
if(x($_POST,'vnotify8'))
if (x($_POST, 'vnotify8'))
$vnotify += intval($_POST['vnotify8']);
if(x($_POST,'vnotify9'))
if (x($_POST, 'vnotify9'))
$vnotify += intval($_POST['vnotify9']);
if(x($_POST,'vnotify10'))
if (x($_POST, 'vnotify10'))
$vnotify += intval($_POST['vnotify10']);
if(x($_POST,'vnotify11') && is_site_admin())
if (x($_POST, 'vnotify11') && is_site_admin())
$vnotify += intval($_POST['vnotify11']);
if(x($_POST,'vnotify12'))
if (x($_POST, 'vnotify12'))
$vnotify += intval($_POST['vnotify12']);
if(x($_POST,'vnotify13'))
if (x($_POST, 'vnotify13'))
$vnotify += intval($_POST['vnotify13']);
if(x($_POST,'vnotify14'))
if (x($_POST, 'vnotify14'))
$vnotify += intval($_POST['vnotify14']);
if(x($_POST,'vnotify15'))
if (x($_POST, 'vnotify15'))
$vnotify += intval($_POST['vnotify15']);
$always_show_in_notices = x($_POST, 'always_show_in_notices') ? 1 : 0;
$update_notices_per_parent = x($_POST, 'update_notices_per_parent') ? 1 : 0;
$always_show_in_notices = ((x($_POST, 'always_show_in_notices')) ? 1 : 0);
$update_notices_per_parent = ((x($_POST, 'update_notices_per_parent')) ? 1 : 0);
$err = '';
$name_change = false;
if($username != $channel['channel_name']) {
$name_change = true;
require_once('include/channel.php');
$err = validate_channelname($username);
if($err) {
notice($err);
return;
}
}
if($timezone != $channel['channel_timezone']) {
if(strlen($timezone))
if ($timezone !== $channel['channel_timezone']) {
if (strlen($timezone))
date_default_timezone_set($timezone);
}
set_pconfig(local_channel(),'system','use_browser_location',$allow_location);
set_pconfig(local_channel(),'system','suggestme', $suggestme);
set_pconfig(local_channel(),'system','post_newfriend', $post_newfriend);
set_pconfig(local_channel(),'system','post_joingroup', $post_joingroup);
set_pconfig(local_channel(),'system','post_profilechange', $post_profilechange);
set_pconfig(local_channel(),'system','blocktags',$blocktags);
set_pconfig(local_channel(),'system','vnotify',$vnotify);
set_pconfig(local_channel(),'system','always_show_in_notices',$always_show_in_notices);
set_pconfig(local_channel(),'system','update_notices_per_parent',$update_notices_per_parent);
set_pconfig(local_channel(),'system','evdays',$evdays);
set_pconfig(local_channel(),'system','photo_path',$photo_path);
set_pconfig(local_channel(),'system','attach_path',$attach_path);
set_pconfig(local_channel(),'system','default_permcat',$defpermcat);
set_pconfig(local_channel(),'system','email_notify_host',$mailhost);
set_pconfig(local_channel(),'system','autoperms',$autoperms);
if (!$role) {
notice(t('Please select a channel role') . EOL);
return;
}
$r = q("update channel set channel_name = '%s', channel_pageflags = %d, channel_timezone = '%s', channel_location = '%s', channel_notifyflags = %d, channel_max_anon_mail = %d, channel_max_friend_req = %d, channel_expire_days = %d $set_perms where channel_id = %d",
dbesc($username),
if ($role !== get_pconfig(local_channel(), 'system', 'permissions_role')) {
$role_permissions = PermissionRoles::role_perms($_POST['permissions_role']);
if (isset($role_permissions['limits'])) {
foreach ($role_permissions['limits'] as $k => $v) {
PermissionLimits::Set(local_channel(), $k, $v);
}
}
set_pconfig(local_channel(), 'system', 'group_actor', 0);
if (isset($role_permissions['channel_type']) && $role_permissions['channel_type'] === 'group') {
set_pconfig(local_channel(), 'system', 'group_actor', 1);
}
}
set_pconfig(local_channel(), 'system', 'permissions_role', $role);
set_pconfig(local_channel(), 'system', 'use_browser_location', $allow_location);
set_pconfig(local_channel(), 'system', 'post_newfriend', $post_newfriend);
set_pconfig(local_channel(), 'system', 'post_joingroup', $post_joingroup);
set_pconfig(local_channel(), 'system', 'post_profilechange', $post_profilechange);
set_pconfig(local_channel(), 'system', 'vnotify', $vnotify);
set_pconfig(local_channel(), 'system', 'always_show_in_notices', $always_show_in_notices);
set_pconfig(local_channel(), 'system', 'update_notices_per_parent', $update_notices_per_parent);
set_pconfig(local_channel(), 'system', 'evdays', $evdays);
set_pconfig(local_channel(), 'system', 'photo_path', $photo_path);
set_pconfig(local_channel(), 'system', 'attach_path', $attach_path);
set_pconfig(local_channel(), 'system', 'email_notify_host', $mailhost);
$r = q("update channel set channel_pageflags = %d, channel_timezone = '%s',
channel_location = '%s', channel_notifyflags = %d, channel_expire_days = %d
where channel_id = %d",
intval($pageflags),
dbesc($timezone),
dbesc($defloc),
intval($notify),
intval($unkmail),
intval($maxreq),
intval($expire),
intval(local_channel())
);
if($r)
info( t('Settings updated.') . EOL);
if(! is_null($publish)) {
$r = q("UPDATE profile SET publish = %d WHERE is_default = 1 AND uid = %d",
intval($publish),
intval(local_channel())
);
}
if($name_change) {
// change name on all associated xchans by matching the url
$r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_url = '%s'",
dbesc($username),
dbesc(datetime_convert()),
dbesc(z_root() . '/channel/' . $channel['channel_address'])
);
$r = q("update profile set fullname = '%s' where uid = %d and is_default = 1",
dbesc($username),
intval($channel['channel_id'])
);
}
\Zotlabs\Daemon\Master::Summon(array('Directory',local_channel()));
if ($r)
info(t('Settings updated.') . EOL);
Master::Summon(['Directory', local_channel()]);
Libsync::build_sync_packet();
if($email_changed && \App::$config['system']['register_policy'] == REGISTER_VERIFY) {
if ($email_changed && App::$config['system']['register_policy'] == REGISTER_VERIFY) {
// FIXME - set to un-verified, blocked and redirect to logout
// Q: Why? Are we verifying people or email addresses?
// A: the policy is to verify email addresses
}
goaway(z_root() . '/settings' );
goaway(z_root() . '/settings');
return; // NOTREACHED
}
function get() {
require_once('include/acl_selectors.php');
require_once('include/permissions.php');
load_pconfig(local_channel());
$channel = App::get_channel();
$nickname = $channel['channel_address'];
$timezone = $channel['channel_timezone'];
$notify = $channel['channel_notifyflags'];
$defloc = $channel['channel_location'];
$adult_flag = intval($channel['channel_pageflags'] & PAGE_ADULT);
$post_newfriend = get_pconfig(local_channel(), 'system', 'post_newfriend');
$post_newfriend = (($post_newfriend === false) ? '0' : $post_newfriend); // default if not set: 0
$post_joingroup = get_pconfig(local_channel(), 'system', 'post_joingroup');
$post_joingroup = (($post_joingroup === false) ? '0' : $post_joingroup); // default if not set: 0
$post_profilechange = get_pconfig(local_channel(), 'system', 'post_profilechange');
$post_profilechange = (($post_profilechange === false) ? '0' : $post_profilechange); // default if not set: 0
$subdir = ((strlen(App::get_path())) ? '<br />' . t('or') . ' ' . z_root() . '/channel/' . $nickname : '');
$webbie = $nickname . '@' . App::get_hostname();
$intl_nickname = unpunify($nickname) . '@' . unpunify(App::get_hostname());
$disable_discover_tab = intval(get_config('system', 'disable_discover_tab', 1)) == 1;
$site_firehose = intval(get_config('system', 'site_firehose', 0)) == 1;
$yes_no = array(t('No'),t('Yes'));
$expire = $channel['channel_expire_days'];
$sys_expire = get_config('system', 'default_expire_days');
$p = q("SELECT * FROM profile WHERE is_default = 1 AND uid = %d LIMIT 1",
intval(local_channel())
);
if(count($p))
$profile = $p[0];
load_pconfig(local_channel(),'expire');
$channel = \App::get_channel();
$global_perms = \Zotlabs\Access\Permissions::Perms();
$permiss = array();
$perm_opts = array(
array( t('Nobody except yourself'), 0),
array( t('Only those you specifically allow'), PERMS_SPECIFIC),
array( t('Approved connections'), PERMS_CONTACTS),
array( t('Any connections'), PERMS_PENDING),
array( t('Anybody on this website'), PERMS_SITE),
array( t('Anybody in this network'), PERMS_NETWORK),
array( t('Anybody authenticated'), PERMS_AUTHED),
array( t('Anybody on the internet'), PERMS_PUBLIC)
);
$limits = \Zotlabs\Access\PermissionLimits::Get(local_channel());
$anon_comments = get_config('system','anonymous_comments',true);
foreach($global_perms as $k => $perm) {
$options = array();
$can_be_public = ((strstr($k,'view') || ($k === 'post_comments' && $anon_comments)) ? true : false);
foreach($perm_opts as $opt) {
if($opt[1] == PERMS_PUBLIC && (! $can_be_public))
continue;
$options[$opt[1]] = $opt[0];
}
$permiss[] = array($k,$perm,$limits[$k],'',$options);
}
// logger('permiss: ' . print_r($permiss,true));
$username = $channel['channel_name'];
$nickname = $channel['channel_address'];
$timezone = $channel['channel_timezone'];
$notify = $channel['channel_notifyflags'];
$defloc = $channel['channel_location'];
$maxreq = $channel['channel_max_friend_req'];
$expire = $channel['channel_expire_days'];
$adult_flag = intval($channel['channel_pageflags'] & PAGE_ADULT);
$sys_expire = get_config('system','default_expire_days');
// $unkmail = \App::$user['unkmail'];
// $cntunkmail = \App::$user['cntunkmail'];
$hide_presence = intval(get_pconfig(local_channel(), 'system','hide_online_status'));
$expire_items = get_pconfig(local_channel(), 'expire','items');
$expire_items = (($expire_items===false)? '1' : $expire_items); // default if not set: 1
$expire_notes = get_pconfig(local_channel(), 'expire','notes');
$expire_notes = (($expire_notes===false)? '1' : $expire_notes); // default if not set: 1
$expire_starred = get_pconfig(local_channel(), 'expire','starred');
$expire_starred = (($expire_starred===false)? '1' : $expire_starred); // default if not set: 1
$expire_photos = get_pconfig(local_channel(), 'expire','photos');
$expire_photos = (($expire_photos===false)? '0' : $expire_photos); // default if not set: 0
$expire_network_only = get_pconfig(local_channel(), 'expire','network_only');
$expire_network_only = (($expire_network_only===false)? '0' : $expire_network_only); // default if not set: 0
$suggestme = get_pconfig(local_channel(), 'system','suggestme');
$suggestme = (($suggestme===false)? '0': $suggestme); // default if not set: 0
$post_newfriend = get_pconfig(local_channel(), 'system','post_newfriend');
$post_newfriend = (($post_newfriend===false)? '0': $post_newfriend); // default if not set: 0
$post_joingroup = get_pconfig(local_channel(), 'system','post_joingroup');
$post_joingroup = (($post_joingroup===false)? '0': $post_joingroup); // default if not set: 0
$post_profilechange = get_pconfig(local_channel(), 'system','post_profilechange');
$post_profilechange = (($post_profilechange===false)? '0': $post_profilechange); // default if not set: 0
$blocktags = get_pconfig(local_channel(),'system','blocktags');
$blocktags = (($blocktags===false) ? '0' : $blocktags);
$timezone = date_default_timezone_get();
$opt_tpl = get_markup_template("field_checkbox.tpl");
if(get_config('system','publish_all')) {
$profile_in_dir = '<input type="hidden" name="profile_in_directory" value="1" />';
}
else {
$profile_in_dir = replace_macros($opt_tpl,array(
'$field' => array('profile_in_directory', t('Publish your default profile in the network directory'), $profile['publish'], '', $yes_no),
));
}
$suggestme = replace_macros($opt_tpl,array(
'$field' => array('suggestme', t('Allow us to suggest you as a potential friend to new members?'), $suggestme, '', $yes_no),
));
$subdir = ((strlen(\App::get_path())) ? '<br />' . t('or') . ' ' . z_root() . '/channel/' . $nickname : '');
$webbie = $nickname . '@' . \App::get_hostname();
$intl_nickname = unpunify($nickname) . '@' . unpunify(\App::get_hostname());
$tpl_addr = get_markup_template("settings_nick_set.tpl");
$prof_addr = replace_macros($tpl_addr,array(
'$desc' => t('Your channel address is'),
$tpl_addr = get_markup_template("settings_nick_set.tpl");
$prof_addr = replace_macros($tpl_addr, [
'$desc' => t('Your channel address is'),
'$nickname' => (($intl_nickname === $webbie) ? $webbie : $intl_nickname . '&nbsp;(' . $webbie . ')'),
'$subdir' => $subdir,
'$davdesc' => t('Your files/photos are accessible via WebDAV at'),
'$davpath' => z_root() . '/dav/' . $nickname,
'$basepath' => \App::get_hostname()
));
'$subdir' => $subdir,
'$davdesc' => t('Your files/photos are accessible via WebDAV at'),
'$davpath' => z_root() . '/dav/' . $nickname,
'$basepath' => App::get_hostname()
]);
$pcat = new \Zotlabs\Lib\Permcat(local_channel());
$pcatlist = $pcat->listing();
$permcats = [];
if($pcatlist) {
foreach($pcatlist as $pc) {
$permcats[$pc['name']] = $pc['localname'];
}
}
$default_permcat = get_pconfig(local_channel(),'system','default_permcat','default');
$stpl = get_markup_template('settings.tpl');
$acl = new \Zotlabs\Access\AccessList($channel);
$perm_defaults = $acl->get();
require_once('include/group.php');
$group_select = mini_group_select(local_channel(),$channel['channel_default_group']);
$evdays = get_pconfig(local_channel(),'system','evdays');
if(! $evdays)
$evdays = get_pconfig(local_channel(), 'system', 'evdays');
if (!$evdays)
$evdays = 3;
$permissions_role = get_pconfig(local_channel(),'system','permissions_role');
if(! $permissions_role)
$permissions_role = 'custom';
// compatibility mapping - can be removed after 3.4 release
if($permissions_role === 'social_party')
$permissions_role = 'social_federation';
if(in_array($permissions_role,['forum','repository']))
$autoperms = replace_macros(get_markup_template('field_checkbox.tpl'), [
'$field' => [ 'autoperms',t('Automatic membership approval'), ((get_pconfig(local_channel(),'system','autoperms')) ? 1 : 0), t('If enabled, connection requests will be approved without your interaction'), $yes_no ]]);
else
$autoperms = '<input type="hidden" name="autoperms" value="' . intval(get_pconfig(local_channel(),'system','autoperms')) . '" />';
$permissions_set = (($permissions_role != 'custom') ? true : false);
$perm_roles = \Zotlabs\Access\PermissionRoles::roles();
$always_show_in_notices = get_pconfig(local_channel(),'system','always_show_in_notices');
$always_show_in_notices = get_pconfig(local_channel(), 'system', 'always_show_in_notices');
$update_notices_per_parent = get_pconfig(local_channel(), 'system', 'update_notices_per_parent', 1);
$vnotify = get_pconfig(local_channel(),'system','vnotify');
if($vnotify === false)
$vnotify = get_pconfig(local_channel(), 'system', 'vnotify');
if ($vnotify === false)
$vnotify = (-1);
$plugin = [ 'basic' => '', 'security' => '', 'notify' => '' ];
call_hooks('channel_settings',$plugin);
$perm_roles = PermissionRoles::channel_roles();
$permissions_role = get_pconfig(local_channel(), 'system', 'permissions_role');
$disable_discover_tab = intval(get_config('system','disable_discover_tab',1)) == 1;
$site_firehose = intval(get_config('system','site_firehose',0)) == 1;
if (!in_array($permissions_role, ['public', 'personal', 'group', 'custom'])) {
notice(t('Please select a channel role') . EOL);
array_unshift($perm_roles , '');
}
$plugin = ['basic' => '', 'notify' => ''];
call_hooks('channel_settings', $plugin);
$o .= replace_macros($stpl,array(
'$ptitle' => t('Channel Settings'),
$yes_no = [t('No'), t('Yes')];
'$submit' => t('Submit'),
'$baseurl' => z_root(),
'$uid' => local_channel(),
'$form_security_token' => get_form_security_token("settings"),
'$nickname_block' => $prof_addr,
'$h_basic' => t('Basic Settings'),
'$username' => array('username', t('Full Name:'), $username,''),
'$email' => array('email', t('Email Address:'), $email, ''),
'$timezone' => array('timezone_select' , t('Your Timezone:'), $timezone, '', get_timezones()),
'$defloc' => array('defloc', t('Default Post Location:'), $defloc, t('Geographical location to display on your posts')),
'$allowloc' => array('allow_location', t('Use Browser Location:'), ((get_pconfig(local_channel(),'system','use_browser_location')) ? 1 : ''), '', $yes_no),
'$adult' => array('adult', t('Adult Content'), $adult_flag, t('This channel frequently or regularly publishes adult content. (Please tag any adult material and/or nudity with #NSFW)'), $yes_no),
'$h_prv' => t('Security and Privacy Settings'),
'$permissions_set' => $permissions_set,
'$perms_set_msg' => t('Your permissions are already configured. Click to view/adjust'),
'$hide_presence' => array('hide_presence', t('Hide my online presence'),$hide_presence, t('Prevents displaying in your profile that you are online'), $yes_no),
'$lbl_pmacro' => t('Simple Privacy Settings:'),
'$pmacro3' => t('Very Public - <em>extremely permissive (should be used with caution)</em>'),
'$pmacro2' => t('Typical - <em>default public, privacy when desired (similar to social network permissions but with improved privacy)</em>'),
'$pmacro1' => t('Private - <em>default private, never open or public</em>'),
'$pmacro0' => t('Blocked - <em>default blocked to/from everybody</em>'),
'$permiss_arr' => $permiss,
'$blocktags' => array('blocktags',t('Allow others to tag your posts'), 1-$blocktags, t('Often used by the community to retro-actively flag inappropriate content'), $yes_no),
'$lbl_p2macro' => t('Channel Permission Limits'),
'$expire' => array('expire',t('Expire other channel content after this many days'),$expire, t('0 or blank to use the website limit.') . ' ' . ((intval($sys_expire)) ? sprintf( t('This website expires after %d days.'),intval($sys_expire)) : t('This website does not expire imported content.')) . ' ' . t('The website limit takes precedence if lower than your limit.')),
'$maxreq' => array('maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']) , t('May reduce spam activity')),
'$permissions' => t('Default Privacy Group'),
'$permdesc' => t("\x28click to open/close\x29"),
'$aclselect' => populate_acl($perm_defaults, false, \Zotlabs\Lib\PermissionDescription::fromDescription(t('Use my default audience setting for the type of object published'))),
'$allow_cid' => acl2json($perm_defaults['allow_cid']),
'$allow_gid' => acl2json($perm_defaults['allow_gid']),
'$deny_cid' => acl2json($perm_defaults['deny_cid']),
'$deny_gid' => acl2json($perm_defaults['deny_gid']),
'$suggestme' => $suggestme,
'$group_select' => $group_select,
'$role' => array('permissions_role' , t('Channel role and privacy'), $permissions_role, '', $perm_roles),
'$defpermcat' => [ 'defpermcat', t('Default permissions category'), $default_permcat, '', $permcats ],
'$permcat_enable' => Apps::system_app_installed(local_channel(), 'Permission Categories'),
'$profile_in_dir' => $profile_in_dir,
'$hide_friends' => $hide_friends,
'$hide_wall' => $hide_wall,
'$unkmail' => $unkmail,
'$cntunkmail' => array('cntunkmail', t('Maximum private messages per day from unknown people:'), intval($channel['channel_max_anon_mail']) ,t("Useful to reduce spamming")),
'$autoperms' => $autoperms,
'$h_not' => t('Notification Settings'),
'$activity_options' => t('By default post a status message when:'),
'$post_newfriend' => array('post_newfriend', t('accepting a friend request'), $post_newfriend, '', $yes_no),
'$post_joingroup' => array('post_joingroup', t('joining a forum/community'), $post_joingroup, '', $yes_no),
'$post_profilechange' => array('post_profilechange', t('making an <em>interesting</em> profile change'), $post_profilechange, '', $yes_no),
'$lbl_not' => t('Send a notification email when:'),
'$notify1' => array('notify1', t('You receive a connection request'), ($notify & NOTIFY_INTRO), NOTIFY_INTRO, '', $yes_no),
'$notify2' => array('notify2', t('Your connections are confirmed'), ($notify & NOTIFY_CONFIRM), NOTIFY_CONFIRM, '', $yes_no),
'$notify3' => array('notify3', t('Someone writes on your profile wall'), ($notify & NOTIFY_WALL), NOTIFY_WALL, '', $yes_no),
'$notify4' => array('notify4', t('Someone writes a followup comment'), ($notify & NOTIFY_COMMENT), NOTIFY_COMMENT, '', $yes_no),
'$notify5' => array('notify5', t('You receive a private message'), ($notify & NOTIFY_MAIL), NOTIFY_MAIL, '', $yes_no),
'$notify6' => array('notify6', t('You receive a friend suggestion'), ($notify & NOTIFY_SUGGEST), NOTIFY_SUGGEST, '', $yes_no),
'$notify7' => array('notify7', t('You are tagged in a post'), ($notify & NOTIFY_TAGSELF), NOTIFY_TAGSELF, '', $yes_no),
'$notify8' => array('notify8', t('You are poked/prodded/etc. in a post'), ($notify & NOTIFY_POKE), NOTIFY_POKE, '', $yes_no),
'$notify9' => array('notify9', t('Someone likes your post/comment'), ($notify & NOTIFY_LIKE), NOTIFY_LIKE, '', $yes_no),
'$lbl_vnot' => t('Show visual notifications including:'),
'$vnotify1' => array('vnotify1', t('Unseen stream activity'), ($vnotify & VNOTIFY_NETWORK), VNOTIFY_NETWORK, '', $yes_no),
'$vnotify2' => array('vnotify2', t('Unseen channel activity'), ($vnotify & VNOTIFY_CHANNEL), VNOTIFY_CHANNEL, '', $yes_no),
'$vnotify3' => array('vnotify3', t('Unseen private messages'), ($vnotify & VNOTIFY_MAIL), VNOTIFY_MAIL, t('Recommended'), $yes_no),
'$vnotify4' => array('vnotify4', t('Upcoming events'), ($vnotify & VNOTIFY_EVENT), VNOTIFY_EVENT, '', $yes_no),
'$vnotify5' => array('vnotify5', t('Events today'), ($vnotify & VNOTIFY_EVENTTODAY), VNOTIFY_EVENTTODAY, '', $yes_no),
'$vnotify6' => array('vnotify6', t('Upcoming birthdays'), ($vnotify & VNOTIFY_BIRTHDAY), VNOTIFY_BIRTHDAY, t('Not available in all themes'), $yes_no),
'$vnotify7' => array('vnotify7', t('System (personal) notifications'), ($vnotify & VNOTIFY_SYSTEM), VNOTIFY_SYSTEM, '', $yes_no),
'$vnotify8' => array('vnotify8', t('System info messages'), ($vnotify & VNOTIFY_INFO), VNOTIFY_INFO, t('Recommended'), $yes_no),
'$vnotify9' => array('vnotify9', t('System critical alerts'), ($vnotify & VNOTIFY_ALERT), VNOTIFY_ALERT, t('Recommended'), $yes_no),
'$vnotify10' => array('vnotify10', t('New connections'), ($vnotify & VNOTIFY_INTRO), VNOTIFY_INTRO, t('Recommended'), $yes_no),
'$vnotify11' => ((is_site_admin()) ? array('vnotify11', t('System Registrations'), ($vnotify & VNOTIFY_REGISTER), VNOTIFY_REGISTER, '', $yes_no) : array()),
'$vnotify12' => array('vnotify12', t('Unseen shared files'), ($vnotify & VNOTIFY_FILES), VNOTIFY_FILES, '', $yes_no),
'$vnotify13' => ((($disable_discover_tab && !$site_firehose) || !Apps::system_app_installed(local_channel(), 'Public Stream')) ? array() : array('vnotify13', t('Unseen public stream activity'), ($vnotify & VNOTIFY_PUBS), VNOTIFY_PUBS, '', $yes_no)),
'$vnotify14' => array('vnotify14', t('Unseen likes and dislikes'), ($vnotify & VNOTIFY_LIKE), VNOTIFY_LIKE, '', $yes_no),
'$vnotify15' => array('vnotify15', t('Unseen forum posts'), ($vnotify & VNOTIFY_FORUMS), VNOTIFY_FORUMS, '', $yes_no),
'$mailhost' => [ 'mailhost', t('Email notification hub (hostname)'), get_pconfig(local_channel(),'system','email_notify_host',\App::get_hostname()), sprintf( t('If your channel is mirrored to multiple hubs, set this to your preferred location. This will prevent duplicate email notifications. Example: %s'),\App::get_hostname()) ],
'$always_show_in_notices' => array('always_show_in_notices', t('Show new wall posts, private messages and connections under Notices'), $always_show_in_notices, 1, '', $yes_no),
'$update_notices_per_parent' => array('update_notices_per_parent', t('Mark all notices of the thread read if a notice is clicked'), $update_notices_per_parent, 1, t('If no, only the clicked notice will be marked read'), $yes_no),
'$desktop_notifications_info' => t('Desktop notifications are unavailable because the required browser permission has not been granted'),
$stpl = get_markup_template('settings.tpl');
$o = replace_macros($stpl, [
'$ptitle' => t('Channel Settings'),
'$submit' => t('Submit'),
'$baseurl' => z_root(),
'$uid' => local_channel(),
'$form_security_token' => get_form_security_token("settings"),
'$role' => ['permissions_role', t('Channel role'), $permissions_role, '', $perm_roles],
'$nickname_block' => $prof_addr,
'$h_basic' => t('Basic Settings'),
'$timezone' => ['timezone_select', t('Channel timezone:'), $timezone, '', get_timezones()],
'$defloc' => ['defloc', t('Default post location:'), $defloc, t('Geographical location to display on your posts')],
'$allowloc' => ['allow_location', t('Use browser location'), ((get_pconfig(local_channel(), 'system', 'use_browser_location')) ? 1 : ''), '', $yes_no],
'$adult' => ['adult', t('Adult content'), $adult_flag, t('This channel frequently or regularly publishes adult content'), $yes_no],
'$maxreq' => ['maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']), t('May reduce spam activity')],
'$h_not' => t('Notification Settings'),
'$activity_options' => t('By default post a status message when:'),
'$post_newfriend' => ['post_newfriend', t('accepting a friend request'), $post_newfriend, '', $yes_no],
'$post_joingroup' => ['post_joingroup', t('joining a forum/community'), $post_joingroup, '', $yes_no],
'$post_profilechange' => ['post_profilechange', t('making an <em>interesting</em> profile change'), $post_profilechange, '', $yes_no],
'$lbl_not' => t('Send a notification email when:'),
'$notify1' => ['notify1', t('You receive a connection request'), ($notify & NOTIFY_INTRO), NOTIFY_INTRO, '', $yes_no],
'$notify2' => ['notify2', t('Your connections are confirmed'), ($notify & NOTIFY_CONFIRM), NOTIFY_CONFIRM, '', $yes_no],
'$notify3' => ['notify3', t('Someone writes on your profile wall'), ($notify & NOTIFY_WALL), NOTIFY_WALL, '', $yes_no],
'$notify4' => ['notify4', t('Someone writes a followup comment'), ($notify & NOTIFY_COMMENT), NOTIFY_COMMENT, '', $yes_no],
'$notify5' => ['notify5', t('You receive a private message'), ($notify & NOTIFY_MAIL), NOTIFY_MAIL, '', $yes_no],
'$notify6' => ['notify6', t('You receive a friend suggestion'), ($notify & NOTIFY_SUGGEST), NOTIFY_SUGGEST, '', $yes_no],
'$notify7' => ['notify7', t('You are tagged in a post'), ($notify & NOTIFY_TAGSELF), NOTIFY_TAGSELF, '', $yes_no],
'$notify8' => ['notify8', t('You are poked/prodded/etc. in a post'), ($notify & NOTIFY_POKE), NOTIFY_POKE, '', $yes_no],
'$notify9' => ['notify9', t('Someone likes your post/comment'), ($notify & NOTIFY_LIKE), NOTIFY_LIKE, '', $yes_no],
'$lbl_vnot' => t('Show visual notifications including:'),
'$vnotify1' => ['vnotify1', t('Unseen stream activity'), ($vnotify & VNOTIFY_NETWORK), VNOTIFY_NETWORK, '', $yes_no],
'$vnotify2' => ['vnotify2', t('Unseen channel activity'), ($vnotify & VNOTIFY_CHANNEL), VNOTIFY_CHANNEL, '', $yes_no],
'$vnotify3' => ['vnotify3', t('Unseen private messages'), ($vnotify & VNOTIFY_MAIL), VNOTIFY_MAIL, t('Recommended'), $yes_no],
'$vnotify4' => ['vnotify4', t('Upcoming events'), ($vnotify & VNOTIFY_EVENT), VNOTIFY_EVENT, '', $yes_no],
'$vnotify5' => ['vnotify5', t('Events today'), ($vnotify & VNOTIFY_EVENTTODAY), VNOTIFY_EVENTTODAY, '', $yes_no],
'$vnotify6' => ['vnotify6', t('Upcoming birthdays'), ($vnotify & VNOTIFY_BIRTHDAY), VNOTIFY_BIRTHDAY, t('Not available in all themes'), $yes_no],
'$vnotify7' => ['vnotify7', t('System (personal) notifications'), ($vnotify & VNOTIFY_SYSTEM), VNOTIFY_SYSTEM, '', $yes_no],
'$vnotify8' => ['vnotify8', t('System info messages'), ($vnotify & VNOTIFY_INFO), VNOTIFY_INFO, t('Recommended'), $yes_no],
'$vnotify9' => ['vnotify9', t('System critical alerts'), ($vnotify & VNOTIFY_ALERT), VNOTIFY_ALERT, t('Recommended'), $yes_no],
'$vnotify10' => ['vnotify10', t('New connections'), ($vnotify & VNOTIFY_INTRO), VNOTIFY_INTRO, t('Recommended'), $yes_no],
'$vnotify11' => ((is_site_admin()) ? ['vnotify11', t('System Registrations'), ($vnotify & VNOTIFY_REGISTER), VNOTIFY_REGISTER, '', $yes_no] : []),
'$vnotify12' => ['vnotify12', t('Unseen shared files'), ($vnotify & VNOTIFY_FILES), VNOTIFY_FILES, '', $yes_no],
'$vnotify13' => ((($disable_discover_tab && !$site_firehose) || !Apps::system_app_installed(local_channel(), 'Public Stream')) ? [] : ['vnotify13', t('Unseen public stream activity'), ($vnotify & VNOTIFY_PUBS), VNOTIFY_PUBS, '', $yes_no]),
'$vnotify14' => ['vnotify14', t('Unseen likes and dislikes'), ($vnotify & VNOTIFY_LIKE), VNOTIFY_LIKE, '', $yes_no],
'$vnotify15' => ['vnotify15', t('Unseen forum posts'), ($vnotify & VNOTIFY_FORUMS), VNOTIFY_FORUMS, '', $yes_no],
'$mailhost' => ['mailhost', t('Email notification hub (hostname)'), get_pconfig(local_channel(), 'system', 'email_notify_host', App::get_hostname()), sprintf(t('If your channel is mirrored to multiple hubs, set this to your preferred location. This will prevent duplicate email notifications. Example: %s'), App::get_hostname())],
'$always_show_in_notices' => ['always_show_in_notices', t('Show new wall posts, private messages and connections under Notices'), $always_show_in_notices, 1, '', $yes_no],
'$update_notices_per_parent' => ['update_notices_per_parent', t('Mark all notices of the thread read if a notice is clicked'), $update_notices_per_parent, 1, t('If no, only the clicked notice will be marked read'), $yes_no],
'$desktop_notifications_info' => t('Desktop notifications are unavailable because the required browser permission has not been granted'),
'$desktop_notifications_request' => t('Grant permission'),
'$evdays' => array('evdays', t('Notify me of events this many days in advance'), $evdays, t('Must be greater than 0')),
'$basic_addon' => $plugin['basic'],
'$sec_addon' => $plugin['security'],
'$notify_addon' => $plugin['notify'],
'$evdays' => ['evdays', t('Notify me of events this many days in advance'), $evdays, t('Must be greater than 0')],
'$basic_addon' => $plugin['basic'],
'$notify_addon' => $plugin['notify'],
'$photo_path' => ['photo_path', t('Default photo upload folder'), get_pconfig(local_channel(), 'system', 'photo_path'), t('%Y - current year, %m - current month')],
'$attach_path' => ['attach_path', t('Default file upload folder'), get_pconfig(local_channel(), 'system', 'attach_path'), t('%Y - current year, %m - current month')],
'$removeme' => t('Remove Channel'),
'$removechannel' => t('Remove this channel.'),
'$expire' => ['expire', t('Expire other channel content after this many days'), $expire, t('0 or blank to use the website limit.') . ' ' . ((intval($sys_expire)) ? sprintf(t('This website expires after %d days.'), intval($sys_expire)) : t('This website does not expire imported content.')) . ' ' . t('The website limit takes precedence if lower than your limit.')],
]);
'$h_advn' => t('Advanced Account/Page Type Settings'),
'$h_descadvn' => t('Change the behaviour of this account for special situations'),
'$pagetype' => $pagetype,
'$lbl_misc' => t('Miscellaneous Settings'),
'$photo_path' => array('photo_path', t('Default photo upload folder'), get_pconfig(local_channel(),'system','photo_path'), t('%Y - current year, %m - current month')),
'$attach_path' => array('attach_path', t('Default file upload folder'), get_pconfig(local_channel(),'system','attach_path'), t('%Y - current year, %m - current month')),
'$removeme' => t('Remove Channel'),
'$removechannel' => t('Remove this channel.'),
));
call_hooks('settings_form',$o);
//$o .= '</form>' . "\r\n";
call_hooks('settings_form', $o);
return $o;
}

View File

@@ -0,0 +1,127 @@
<?php
namespace Zotlabs\Module\Settings;
use App;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Access\Permissions;
use Zotlabs\Daemon\Master;
use Zotlabs\Lib\Group;
use Zotlabs\Lib\Libsync;
class Privacy {
function post() {
check_form_security_token_redirectOnErr('/settings/privacy', 'settings');
call_hooks('settings_post', $_POST);
$index_opt_out = (((x($_POST, 'index_opt_out')) && (intval($_POST['index_opt_out']) == 1)) ? 1 : 0);
set_pconfig(local_channel(), 'system', 'index_opt_out', $index_opt_out);
$autoperms = (((x($_POST, 'autoperms')) && (intval($_POST['autoperms']) == 1)) ? 1 : 0);
set_pconfig(local_channel(), 'system', 'autoperms', $autoperms);
$role = get_pconfig(local_channel(), 'system', 'permissions_role');
if ($role === 'custom') {
$global_perms = Permissions::Perms();
foreach ($global_perms as $k => $v) {
PermissionLimits::Set(local_channel(), $k, intval($_POST[$k]));
}
$group_actor = (((x($_POST, 'group_actor')) && (intval($_POST['group_actor']) == 1)) ? 1 : 0);
set_pconfig(local_channel(), 'system', 'group_actor', $group_actor);
}
info(t('Privacy settings updated.') . EOL);
Master::Summon(['Directory', local_channel()]);
Libsync::build_sync_packet();
goaway(z_root() . '/settings/privacy');
return; // NOTREACHED
}
function get() {
load_pconfig(local_channel());
$channel = App::get_channel();
$global_perms = Permissions::Perms();
$permiss = [];
$perm_opts = [
[t('Only me'), 0],
[t('Only those you specifically allow'), PERMS_SPECIFIC],
[t('Approved connections'), PERMS_CONTACTS],
[t('Any connections'), PERMS_PENDING],
[t('Anybody on this website'), PERMS_SITE],
[t('Anybody in this network'), PERMS_NETWORK],
[t('Anybody authenticated'), PERMS_AUTHED],
[t('Anybody on the internet'), PERMS_PUBLIC]
];
$help = [
'view_stream',
'view_wiki',
'view_pages',
'view_storage'
];
$help_txt = t('Advise: set to "Anybody on the internet" and use privacy groups to restrict access');
$limits = PermissionLimits::Get(local_channel());
$anon_comments = get_config('system', 'anonymous_comments', true);
foreach ($global_perms as $k => $perm) {
$options = [];
$can_be_public = (strstr($k, 'view') || ($k === 'post_comments' && $anon_comments));
foreach ($perm_opts as $opt) {
if ($opt[1] == PERMS_PUBLIC && (!$can_be_public))
continue;
$options[$opt[1]] = $opt[0];
}
$permiss[] = [
$k,
$perm,
$limits[$k],
((in_array($k, $help)) ? $help_txt : ''),
$options
];
}
//logger('permiss: ' . print_r($permiss,true));
$autoperms = get_pconfig(local_channel(), 'system', 'autoperms');
$index_opt_out = get_pconfig(local_channel(), 'system', 'index_opt_out');
$group_actor = get_pconfig(local_channel(), 'system', 'group_actor');
$permissions_role = get_pconfig(local_channel(), 'system', 'permissions_role', 'custom');
$permission_limits = ($permissions_role === 'custom');
$stpl = get_markup_template('settings_privacy.tpl');
$o = replace_macros($stpl, [
'$ptitle' => t('Privacy Settings'),
'$submit' => t('Submit'),
'$form_security_token' => get_form_security_token("settings"),
'$permission_limits' => $permission_limits,
'$permiss_arr' => $permiss,
'$permission_limits_label' => t('Advanced configuration'),
'$permission_limits_warning' => [
t('Proceed with caution'),
t('Changing advanced configuration settings can impact your, and your contacts channels functionality and security.'),
t('Accept the risk and continue')
],
'$autoperms' => ['autoperms', t('Automatically approve new contacts'), $autoperms, '', [t('No'), t('Yes')]],
'$index_opt_out' => ['index_opt_out', t('Opt-out of search engine indexing'), $index_opt_out, '', [t('No'), t('Yes')]],
'$group_actor' => ['group_actor', t('Group actor'), $group_actor, t('Allow this channel to act as a forum'), [t('No'), t('Yes')]],
]);
return $o;
}
}

View File

@@ -13,14 +13,14 @@ class Profiles {
$module = substr(strrchr(strtolower(static::class), '\\'), 1);
check_form_security_token_redirectOnErr('/settings/' . $module, 'settings_' . $module);
$features = get_module_features($module);
process_module_features_post(local_channel(), $features, $_POST);
$profile_assign = ((x($_POST,'profile_assign')) ? notags(trim($_POST['profile_assign'])) : '');
set_pconfig(local_channel(),'system','profile_assign',$profile_assign);
Libsync::build_sync_packet();
if($_POST['rpath'])
@@ -38,7 +38,7 @@ class Profiles {
$extra_settings_html = '';
if(feature_enabled(local_channel(),'multi_profiles'))
$extra_settings_html = contact_profile_assign(get_pconfig(local_channel(),'system','profile_assign',''));
$extra_settings_html = contact_profile_assign(get_pconfig(local_channel(),'system','profile_assign',''), t('Default profile for new contacts'));
$tpl = get_markup_template("settings_module.tpl");
@@ -51,7 +51,7 @@ class Profiles {
'$extra_settings_html' => $extra_settings_html,
'$submit' => t('Submit')
));
return $o;
}

View File

@@ -69,17 +69,22 @@ class Setup extends \Zotlabs\Web\Controller {
$dbpass = ((isset($_POST['dbpass'])) ? trim($_POST['dbpass']) : '');
$dbdata = ((isset($_POST['dbdata'])) ? trim($_POST['dbdata']) : '');
$dbtype = ((isset($_POST['dbtype'])) ? intval(trim($_POST['dbtype'])) : 0);
$phpath = ((isset($_POST['phpath'])) ? trim($_POST['phpath']) : '');
$adminmail = ((isset($_POST['adminmail'])) ? trim($_POST['adminmail']) : '');
$siteurl = ((isset($_POST['siteurl'])) ? trim($_POST['siteurl']) : '');
if (empty($db_charset)) {
$db_charset = ((intval($db_type) === 0) ? 'utf8mb4' : 'UTF8');
}
// $siteurl should not have a trailing slash
$siteurl = rtrim($siteurl,'/');
require_once('include/dba/dba_driver.php');
$db = \DBA::dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, true);
$db = \DBA::dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, $db_charset, true);
if(! \DBA::$dba->connected) {
echo 'Database Connect failed: ' . \DBA::$dba->error;
@@ -94,11 +99,16 @@ class Setup extends \Zotlabs\Web\Controller {
$dbpass = ((isset($_POST['dbpass'])) ? trim($_POST['dbpass']) : '');
$dbdata = ((isset($_POST['dbdata'])) ? trim($_POST['dbdata']) : '');
$dbtype = ((isset($_POST['dbtype'])) ? intval(trim($_POST['dbtype'])) : 0);
$phpath = ((isset($_POST['phpath'])) ? trim($_POST['phpath']) : '');
$timezone = ((isset($_POST['timezone'])) ? trim($_POST['timezone']) : '');
$adminmail = ((isset($_POST['adminmail'])) ? trim($_POST['adminmail']) : '');
$siteurl = ((isset($_POST['siteurl'])) ? trim($_POST['siteurl']) : '');
if (empty($db_charset)) {
$db_charset = ((intval($db_type) === 0) ? 'utf8mb4' : 'UTF8');
}
if($siteurl != z_root()) {
$test = z_fetch_url($siteurl."/setup/testrewrite");
if((! $test['success']) || ($test['body'] != 'ok')) {
@@ -112,7 +122,7 @@ class Setup extends \Zotlabs\Web\Controller {
if(! isset(\DBA::$dba->connected)) {
// connect to db
$db = \DBA::dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, true);
$db = \DBA::dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, $db_charset, true);
}
if(! isset(\DBA::$dba->connected)) {

View File

@@ -5,6 +5,11 @@ namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Apps;
use Zotlabs\Lib\AccessList;
use Zotlabs\Lib\Permcat;
use Zotlabs\Lib\Libsync;
require_once('include/security.php');
class Tokens extends Controller {
@@ -13,15 +18,65 @@ class Tokens extends Controller {
if(! local_channel())
return;
if(! Apps::system_app_installed(local_channel(), 'Guest Access'))
return;
$channel = App::get_channel();
if(! Apps::system_app_installed($channel['channel_id'], 'Guest Access'))
return;
check_form_security_token_redirectOnErr('tokens', 'tokens');
if(isset($_POST['delete'])) {
$r = q("select * from atoken where atoken_id = %d and atoken_uid = %d",
intval($_POST['atoken_id']),
intval(local_channel())
);
if (!$r) {
return;
}
$atoken = $r[0];
$atoken_xchan = substr($channel['channel_hash'], 0, 16) . '.' . $atoken['atoken_guid'];
$atoken['deleted'] = true;
$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($channel['channel_id']),
dbesc($atoken_xchan)
);
if (!$r) {
return;
}
$clone = $r[0];
unset($clone['abook_id']);
unset($clone['abook_account']);
unset($clone['abook_channel']);
$clone['deleted'] = true;
$abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']);
if ($abconfig) {
$clone['abconfig'] = $abconfig;
}
atoken_delete($atoken['atoken_id']);
Libsync::build_sync_packet($channel['channel_id'], [ 'abook' => [ $clone ], 'atoken' => [ $atoken ] ], true);
return;
}
$token_errs = 0;
if(array_key_exists('token',$_POST)) {
$atoken_id = (($_POST['atoken_id']) ? intval($_POST['atoken_id']) : 0);
if (! $atoken_id) {
$atoken_guid = new_uuid();
}
$name = trim(escape_tags($_POST['name']));
$token = trim($_POST['token']);
if((! $name) || (! $token))
@@ -30,10 +85,10 @@ class Tokens extends Controller {
$expires = datetime_convert(date_default_timezone_get(),'UTC',$_POST['expires']);
else
$expires = NULL_DATE;
$max_atokens = service_class_fetch(local_channel(),'access_tokens');
$max_atokens = service_class_fetch($channel['channel_id'],'access_tokens');
if($max_atokens) {
$r = q("select count(atoken_id) as total where atoken_uid = %d",
intval(local_channel())
intval($channel['channel_id'])
);
if($r && intval($r[0]['total']) >= $max_tokens) {
notice( sprintf( t('This channel is limited to %d tokens'), $max_tokens) . EOL);
@@ -45,6 +100,17 @@ class Tokens extends Controller {
notice( t('Name and Password are required.') . EOL);
return;
}
$old_atok = q("select * from atoken where atoken_uid = %d and atoken_name = '%s'",
intval($channel['channel_id']),
dbesc($name)
);
if ($old_atok) {
$old_atok = $old_atok[0];
$old_xchan = atoken_xchan($old_atok);
}
if($atoken_id) {
$r = q("update atoken set atoken_name = '%s', atoken_token = '%s', atoken_expires = '%s'
where atoken_id = %d and atoken_uid = %d",
@@ -56,8 +122,9 @@ class Tokens extends Controller {
);
}
else {
$r = q("insert into atoken ( atoken_aid, atoken_uid, atoken_name, atoken_token, atoken_expires )
values ( %d, %d, '%s', '%s', '%s' ) ",
$r = q("insert into atoken (atoken_guid, atoken_aid, atoken_uid, atoken_name, atoken_token, atoken_expires )
values ('%s', %d, %d, '%s', '%s', '%s' ) ",
dbesc($atoken_guid),
intval($channel['channel_account_id']),
intval($channel['channel_id']),
dbesc($name),
@@ -66,21 +133,84 @@ class Tokens extends Controller {
);
}
$atoken_xchan = substr($channel['channel_hash'],0,16) . '.' . $name;
$atok = q("select * from atoken where atoken_uid = %d and atoken_name = '%s'",
intval($channel['channel_id']),
dbesc($name)
);
$all_perms = \Zotlabs\Access\Permissions::Perms();
if ($atok) {
$xchan = atoken_xchan($atok[0]);
atoken_create_xchan($xchan);
$atoken_xchan = $xchan['xchan_hash'];
if ($old_atok && $old_xchan) {
$r = q("update xchan set xchan_name = '%s' where xchan_hash = '%s'",
dbesc($xchan['xchan_name']),
dbesc($old_xchan['xchan_hash'])
);
}
}
if($all_perms) {
foreach($all_perms as $perm => $desc) {
if(array_key_exists('perms_' . $perm, $_POST)) {
set_abconfig($channel['channel_id'],$atoken_xchan,'my_perms',$perm,intval($_POST['perms_' . $perm]));
}
else {
set_abconfig($channel['channel_id'],$atoken_xchan,'my_perms',$perm,0);
if (! $atoken_id) {
// If this is a new token, create a new abook record
$closeness = get_pconfig($channel['channel_id'], 'system', 'new_abook_closeness',80);
$profile_assign = get_pconfig($channel['channel_id'], 'system', 'profile_assign', '');
$r = abook_store_lowlevel(
[
'abook_account' => $channel['channel_account_id'],
'abook_channel' => $channel['channel_id'],
'abook_closeness' => intval($closeness),
'abook_xchan' => $atoken_xchan,
'abook_profile' => $profile_assign,
'abook_feed' => 0,
'abook_created' => datetime_convert(),
'abook_updated' => datetime_convert(),
'abook_instance' => z_root(),
]
);
if (! $r) {
logger('abook creation failed');
}
/** If there is a default group for this channel, add this connection to it */
if ($channel['channel_default_group']) {
$g = AccessList::by_hash($channel['channel_id'], $channel['channel_default_group']);
if ($g) {
AccessList::member_add($channel['channel_id'], '', $atoken_xchan,$g['id']);
}
}
}
$role = ((array_key_exists('permcat', $_POST)) ? escape_tags($_POST['permcat']) : '');
\Zotlabs\Lib\Permcat::assign($channel, $role, [$atoken_xchan]);
$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($channel['chnnel_id']),
dbesc($atoken_xchan)
);
if (! $r) {
return;
}
$clone = $r[0];
unset($clone['abook_id']);
unset($clone['abook_account']);
unset($clone['abook_channel']);
$abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']);
if ($abconfig) {
$clone['abconfig'] = $abconfig;
}
Libsync::build_sync_packet($channel['channel_id'], [ 'abook' => [ $clone ], 'atoken' => $atok ], true);
info( t('Token saved.') . EOL);
return;
@@ -99,10 +229,13 @@ class Tokens extends Controller {
return Apps::app_render($papp, 'module');
}
nav_set_selected('Guest Access');
$channel = App::get_channel();
$atoken = null;
$atoken_xchan = '';
$atoken_abook = [];
if(argc() > 1) {
$id = argv(1);
@@ -114,76 +247,52 @@ class Tokens extends Controller {
if($atoken) {
$atoken = $atoken[0];
$atoken_xchan = substr($channel['channel_hash'],0,16) . '.' . $atoken['atoken_name'];
}
$atoken_xchan = substr($channel['channel_hash'],0,16) . '.' . $atoken['atoken_guid'];
if($atoken && argc() > 2 && argv(2) === 'drop') {
atoken_delete($id);
$atoken = null;
$atoken_xchan = '';
$atoken_abook = q("select * from abook where abook_channel = %d and abook_xchan = '%s'",
intval(local_channel()),
dbesc($atoken_xchan)
);
$atoken_abook = $atoken_abook[0];
}
}
$t = q("select * from atoken where atoken_uid = %d",
intval(local_channel())
);
$desc = t('Use this form to create temporary access identifiers to share things with non-members. These identities may be used in privacy groups and visitors may login using these credentials to access private content.');
$desc = t('Use this form to create temporary access identifiers to share things with non-members. These identities may be used in Access Control Lists and visitors may login using these credentials to access private content.');
$pcat = new Permcat(local_channel());
$pcatlist = $pcat->listing();
$default_role = get_pconfig(local_channel(), 'system', 'default_permcat');
$current_permcat = (($atoken_abook) ? $atoken_abook['abook_role'] : $default_role);
$desc2 = t('You may also provide <em>dropbox</em> style access links to friends and associates by adding the Login Password to any specific site URL as shown. Examples:');
$roles_dict = [];
foreach ($pcatlist as $role) {
$roles_dict[$role['name']] = $role['localname'];
}
$global_perms = \Zotlabs\Access\Permissions::Perms();
$their_perms = [];
if (!$current_permcat) {
notice(t('Please select a role for this guest!') . EOL);
$permcats[] = '';
}
$existing = get_all_perms(local_channel(),(($atoken_xchan) ? $atoken_xchan : ''),false);
if($atoken_xchan) {
$theirs = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'their_perms'",
intval(local_channel()),
dbesc($atoken_xchan)
);
if($theirs) {
foreach($theirs as $t) {
$their_perms[$t['k']] = $t['v'];
}
if ($pcatlist) {
foreach ($pcatlist as $pc) {
$permcats[$pc['name']] = $pc['localname'];
}
}
foreach($global_perms as $k => $v) {
$thisperm = get_abconfig(local_channel(),$contact['abook_xchan'],'my_perms',$k);
//fixme
$checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(),$k);
if($existing[$k])
$thisperm = "1";
$perms[] = array('perms_' . $k, $v, ((array_key_exists($k,$their_perms)) ? intval($their_perms[$k]) : ''),$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited);
}
$tpl = get_markup_template("tokens.tpl");
$o .= replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("tokens"),
'$title' => t('Guest Access Tokens'),
'$desc' => $desc,
'$desc2' => $desc2,
'$tokens' => $t,
'$form_security_token' => get_form_security_token('tokens'),
'$permcat' => ['permcat', t('Select a role for this guest'), $current_permcat, '', $permcats],
'$title' => t('Guest Access'),
'$desc' => $desc,
'$atoken' => $atoken,
'$url1' => z_root() . '/channel/' . $channel['channel_address'],
'$url2' => z_root() . '/photos/' . $channel['channel_address'],
'$name' => array('name', t('Login Name') . ' <span class="required">*</span>', (($atoken) ? $atoken['atoken_name'] : ''),''),
'$token'=> array('token', t('Login Password') . ' <span class="required">*</span>',(($atoken) ? $atoken['atoken_token'] : autoname(8)), ''),
'$token'=> array('token', t('Login Password') . ' <span class="required">*</span>',(($atoken) ? $atoken['atoken_token'] : new_token()), ''),
'$expires'=> array('expires', t('Expires (yyyy-mm-dd)'), (($atoken['atoken_expires'] && $atoken['atoken_expires'] > NULL_DATE) ? datetime_convert('UTC',date_default_timezone_get(),$atoken['atoken_expires']) : ''), ''),
'$them' => t('Their Settings'),
'$me' => t('My Settings'),
'$perms' => $perms,
'$inherited' => t('inherited'),
'$notself' => 1,
'$self' => 0,
'$permlbl' => t('Individual Permissions'),
'$permnote' => t('Some permissions may be inherited from your channel\'s <a href="settings"><strong>privacy settings</strong></a>, which have higher priority than individual settings. You can <strong>not</strong> change those settings here.'),
'$submit' => t('Submit')
'$submit' => t('Submit'),
'$delete' => t('Delete')
));
return $o;
}

View File

@@ -143,6 +143,10 @@ class Uexport extends Controller {
function get() {
if(! local_channel()) {
return;
}
if(! Apps::system_app_installed(local_channel(), 'Channel Export')) {
//Do not display any associated widgets at this point
App::$pdl = '';

View File

@@ -6,7 +6,7 @@ require_once('include/selectors.php');
class Viewconnections extends \Zotlabs\Web\Controller {
function init() {
if(observer_prohibited()) {
return;
}
@@ -16,58 +16,58 @@ class Viewconnections extends \Zotlabs\Web\Controller {
}
}
function get() {
if(observer_prohibited()) {
notice( t('Public access denied.') . EOL);
return;
}
if(((! count(\App::$profile)) || (\App::$profile['hide_friends']))) {
notice( t('Permission denied.') . EOL);
return;
}
}
if(! perm_is_allowed(\App::$profile['uid'], get_observer_hash(),'view_contacts')) {
notice( t('Permission denied.') . EOL);
return;
}
}
if(! $_REQUEST['aj'])
$_SESSION['return_url'] = \App::$query_string;
$is_owner = ((local_channel() && local_channel() == \App::$profile['uid']) ? true : false);
$abook_flags = " and abook_pending = 0 and abook_self = 0 ";
$abook_flags = " and abook_pending = 0 and abook_self = 0 and abook_blocked = 0 and abook_ignored = 0 ";
$sql_extra = '';
if(! $is_owner) {
$abook_flags .= " and abook_hidden = 0 ";
$sql_extra = " and xchan_hidden = 0 ";
}
$r = q("SELECT count(*) as total FROM abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d $abook_flags and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra ",
intval(\App::$profile['uid'])
);
if($r) {
\App::set_pager_total($r[0]['total']);
}
$r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d $abook_flags and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra order by xchan_name LIMIT %d OFFSET %d ",
intval(\App::$profile['uid']),
intval(\App::$pager['itemspage']),
intval(\App::$pager['start'])
);
if((! $r) && (! $_REQUEST['aj'])) {
info( t('No connections.') . EOL );
return $o;
}
$contacts = array();
foreach($r as $rr) {
$oneway = false;
@@ -103,7 +103,7 @@ class Viewconnections extends \Zotlabs\Web\Controller {
'id' => $rr['abook_id'],
'archived' => (intval($rr['abook_archived']) ? true : false),
'img_hover' => sprintf( t('Visit %s\'s profile [%s]'), $rr['xchan_name'], $rr['xchan_url']),
'thumb' => $rr['xchan_photo_m'],
'thumb' => $rr['xchan_photo_m'],
'name' => substr($rr['xchan_name'],0,20),
'username' => $rr['xchan_addr'],
'link' => $url,
@@ -137,11 +137,11 @@ class Viewconnections extends \Zotlabs\Web\Controller {
// '$paginate' => paginate($a),
));
}
if(! $contacts)
$o .= '<div id="content-complete"></div>';
return $o;
}
}

View File

@@ -24,7 +24,7 @@ class Vote extends Controller {
$fetch = null;
$id = argv(1);
$response = $_REQUEST['answer'];
if ($id) {
$fetch = q("select * from item where id = %d limit 1",
intval($id)
@@ -42,7 +42,7 @@ class Vote extends Controller {
}
$valid = false;
if ($obj['oneOf']) {
foreach($obj['oneOf'] as $selection) {
// logger('selection: ' . $selection);
@@ -80,7 +80,6 @@ class Vote extends Controller {
$item = [];
$item['aid'] = $channel['channel_account_id'];
$item['uid'] = $channel['channel_id'];
$item['item_origin'] = 1;
@@ -95,11 +94,8 @@ class Vote extends Controller {
$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
@@ -108,17 +104,15 @@ class Vote extends Controller {
$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)
);
@@ -128,6 +122,7 @@ class Vote extends Controller {
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

@@ -126,7 +126,7 @@ class Wfinger extends \Zotlabs\Web\Controller {
'http://webfinger.net/ns/name' => $r['channel_name'],
'http://xmlns.com/foaf/0.1/name' => $r['channel_name'],
'https://w3id.org/security/v1#publicKeyPem' => $r['xchan_pubkey'],
'http://purl.org/zot/federation' => 'zot6,zot'
'http://purl.org/zot/federation' => 'zot6'
];
foreach($aliases as $alias)
@@ -183,12 +183,6 @@ class Wfinger extends \Zotlabs\Web\Controller {
'href' => z_root() . '/profile/' . $r['channel_address'],
],
[
'rel' => 'http://schemas.google.com/g/2010#updates-from',
'type' => 'application/atom+xml',
'href' => z_root() . '/ofeed/' . $r['channel_address']
],
[
'rel' => 'http://webfinger.net/rel/blog',
'href' => z_root() . '/channel/' . $r['channel_address'],
@@ -205,11 +199,6 @@ class Wfinger extends \Zotlabs\Web\Controller {
'href' => channel_url($r)
],
[
'rel' => 'http://purl.org/zot/protocol',
'href' => z_root() . '/.well-known/zot-info' . '?address=' . $r['xchan_addr'],
],
[
'rel' => 'http://purl.org/openwebauth/v1',
'type' => 'application/x-zot+json',

View File

@@ -572,7 +572,7 @@ class Comanche {
require_once('widget/' . trim($name) . '.php');
elseif(file_exists('widget/' . trim($name) . '/' . trim($name) . '.php'))
require_once('widget/' . trim($name) . '/' . trim($name) . '.php');
if(! function_exists($func)) {
$theme_widget = $func . '.php';
if(theme_include($theme_widget)) {
@@ -640,7 +640,8 @@ class Comanche {
$cnt = preg_match_all("/\[widget=(.*?)\](.*?)\[\/widget\]/ism", $s, $matches, PREG_SET_ORDER);
if($cnt) {
foreach($matches as $mtch) {
$s = str_replace($mtch[0],$this->widget(trim($mtch[1]),$mtch[2]),$s);
$s = str_replace((string)$mtch[0], (string)$this->widget(trim((string)$mtch[1]), (string)$mtch[2]), $s);
}
}

View File

@@ -60,14 +60,16 @@ class Theme {
// Allow theme selection of the form 'theme_name:schema_name'
$themepair = explode(':', $chosen_theme);
// Check if $chosen_theme is compatible with core. If not fall back to default
$info = get_theme_info($themepair[0]);
$compatible = check_plugin_versions($info);
if(!$compatible) {
$chosen_theme = '';
}
App::$theme_info = $info;
if($chosen_theme && (file_exists('view/theme/' . $themepair[0] . '/css/style.css') || file_exists('view/theme/' . $themepair[0] . '/php/style.php'))) {
return($themepair);
}

31
Zotlabs/Update/_1249.php Normal file
View File

@@ -0,0 +1,31 @@
<?php
namespace Zotlabs\Update;
class _1249 {
function run() {
dbq("START TRANSACTION");
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
$r1 = dbq("ALTER TABLE abook ADD abook_role TEXT NOT NULL DEFAULT ''");
$r2 = dbq("CREATE INDEX \"abook_role\" ON abook (\"abook_role\")");
$r = ($r1 && $r2);
}
else {
$r = dbq("ALTER TABLE `abook` ADD `abook_role` CHAR(191) NOT NULL DEFAULT '' ,
ADD INDEX `abook_role` (`abook_role`)");
}
if($r) {
dbq("COMMIT");
return UPDATE_SUCCESS;
}
dbq("ROLLBACK");
return UPDATE_FAILED;
}
}

31
Zotlabs/Update/_1250.php Normal file
View File

@@ -0,0 +1,31 @@
<?php
namespace Zotlabs\Update;
class _1250 {
function run() {
dbq("START TRANSACTION");
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
$r1 = dbq("ALTER TABLE atoken ADD atoken_guid VARCHAR(255) NOT NULL DEFAULT ''");
$r2 = dbq("CREATE INDEX \"atoken_guid\" ON atoken (\"atoken_guid\")");
$r = ($r1 && $r2);
}
else {
$r = dbq("ALTER TABLE `atoken` ADD `atoken_guid` CHAR(191) NOT NULL DEFAULT '' ,
ADD INDEX `atoken_guid` (`atoken_guid`)");
}
if($r) {
dbq("COMMIT");
return UPDATE_SUCCESS;
}
dbq("ROLLBACK");
return UPDATE_FAILED;
}
}

23
Zotlabs/Update/_1251.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
namespace Zotlabs\Update;
class _1251 {
function run() {
dbq("START TRANSACTION");
$r = dbq("DELETE FROM app WHERE (app_name = 'Channel Home' OR app_name = 'Permission Categories') AND app_system = 1");
if($r) {
dbq("COMMIT");
return UPDATE_SUCCESS;
}
dbq("ROLLBACK");
return UPDATE_FAILED;
}
}

23
Zotlabs/Update/_1252.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
namespace Zotlabs\Update;
class _1252 {
function run() {
dbq("START TRANSACTION");
$r = dbq("DELETE FROM app WHERE app_plugin = 'mail' AND app_system = 1");
if($r) {
dbq("COMMIT");
return UPDATE_SUCCESS;
}
dbq("ROLLBACK");
return UPDATE_FAILED;
}
}

View File

@@ -156,6 +156,7 @@ class HTTPSig {
$cached_key = self::get_key($key, $keytype, $result['signer']);
if (!($cached_key && $cached_key['public_key'])) {
return $result;
}
@@ -243,7 +244,12 @@ class HTTPSig {
}
}
$key = self::get_activitystreams_key($id, $force);
$delete = false;
if ($keytype === 'delete') {
$delete = true;
}
$key = self::get_activitystreams_key($id, $force, $delete);
return $key;
@@ -274,7 +280,7 @@ class HTTPSig {
* false if no pub key found, otherwise return an array with the pub key
*/
static function get_activitystreams_key($id, $force = false) {
static function get_activitystreams_key($id, $force = false, $delete = false) {
// Check the local cache first, but remove any fragments like #main-key since these won't be present in our cached data
$url = ((strpos($id, '#')) ? substr($id, 0, strpos($id, '#')) : $id);
@@ -294,6 +300,12 @@ class HTTPSig {
}
}
if ($delete) {
// If we received a delete and we do not have the record cached,
// we probably never saw this actor. Do not try to fetch it now.
return false;
}
// The record wasn't in cache. Fetch it now.
$r = ActivityStreams::fetch($id);

View File

@@ -25,7 +25,7 @@ class Session {
ini_set('session.cookie_httponly', 1);
$this->custom_handler = boolval(get_config('system', 'session_custom', false));
/*
* Set our session storage functions.
*/
@@ -67,23 +67,24 @@ class Session {
}
// Force cookies to be secure (https only) if this site is SSL enabled.
// Force cookies to be secure (https only) if this site is SSL enabled.
// Must be done before session_start().
$arr = session_get_cookie_params();
// Note when setting cookies: set the domain to false which creates a single domain
// cookie. If you use a hostname it will create a .domain.com wildcard which will
// have some nasty side effects if you have any other subdomains running hubzilla.
// have some nasty side effects if you have any other subdomains running hubzilla.
session_set_cookie_params(
((isset($arr['lifetime'])) ? $arr['lifetime'] : 0),
((isset($arr['path'])) ? $arr['path'] : '/'),
(($arr['domain']) ? $arr['domain'] : false),
((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') ? true : false),
((isset($arr['httponly'])) ? $arr['httponly'] : true)
);
session_set_cookie_params([
'lifetime' => ((isset($arr['lifetime'])) ? $arr['lifetime'] : 0),
'path' => ((isset($arr['path'])) ? $arr['path'] : '/'),
'domain' => (($arr['domain']) ? $arr['domain'] : false),
'secure' => ((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') ? true : false),
'httponly' => ((isset($arr['httponly'])) ? $arr['httponly'] : true),
'samesite' => 'None'
]);
register_shutdown_function('session_write_close');
@@ -127,13 +128,36 @@ class Session {
$this->handler->read(session_id());
}
}
else
else
logger('no session handler');
if (x($_COOKIE, 'jsdisabled')) {
setcookie('jsdisabled', $_COOKIE['jsdisabled'], $newxtime, '/', false,((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') ? true : false),((isset($arr['httponly'])) ? $arr['httponly'] : true));
setcookie(
'jsdisabled',
$_COOKIE['jsdisabled'],
[
'expires' => $newxtime,
'path' => '/',
'domain' => false,
'secure' => ((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') ? true : false),
'httponly' => ((isset($arr['httponly'])) ? $arr['httponly'] : true),
'samesite' => 'None'
]
);
}
setcookie(session_name(),session_id(),$newxtime, '/', false,((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') ? true : false),((isset($arr['httponly'])) ? $arr['httponly'] : true));
setcookie(
session_name(),
session_id(),
[
'expires' => $newxtime,
'path' => '/',
'domain' => false,
'secure' => ((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') ? true : false),
'httponly' => ((isset($arr['httponly'])) ? $arr['httponly'] : true),
'samesite' => 'None'
]
);
$arr = array('expire' => $xtime);
call_hooks('new_cookie', $arr);
@@ -148,8 +172,21 @@ class Session {
$xtime = (($_SESSION['remember_me']) ? (60 * 60 * 24 * 365) : 0 );
if($xtime)
setcookie(session_name(),session_id(),(time() + $xtime), '/', false,((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') ? true : false),((isset($arr['httponly'])) ? $arr['httponly'] : true));
if($xtime) {
setcookie(
session_name(),
session_id(),
[
'expires' => time() + $xtime,
'path' => '/',
'domain' => false,
'secure' => ((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') ? true : false),
'httponly' => ((isset($arr['httponly'])) ? $arr['httponly'] : true),
'samesite' => 'None'
]
);
}
$arr = array('expire' => $xtime);
call_hooks('extend_cookie', $arr);
@@ -169,8 +206,8 @@ class Session {
if($_SESSION['addr'] && $_SESSION['addr'] != $_SERVER['REMOTE_ADDR']) {
logger('SECURITY: Session IP address changed: ' . $_SESSION['addr'] . ' != ' . $_SERVER['REMOTE_ADDR']);
$partial1 = substr($_SESSION['addr'], 0, strrpos($_SESSION['addr'], '.'));
$partial2 = substr($_SERVER['REMOTE_ADDR'], 0, strrpos($_SERVER['REMOTE_ADDR'], '.'));
$partial1 = substr($_SESSION['addr'], 0, strrpos($_SESSION['addr'], '.'));
$partial2 = substr($_SERVER['REMOTE_ADDR'], 0, strrpos($_SERVER['REMOTE_ADDR'], '.'));
$paranoia = intval(get_pconfig($_SESSION['uid'], 'system', 'paranoia'));

View File

@@ -6,7 +6,7 @@ namespace Zotlabs\Web;
class SessionHandler implements \SessionHandlerInterface {
function open ($s, $n) {
function open ($s, $n) : bool {
return true;
}
@@ -15,7 +15,7 @@ class SessionHandler implements \SessionHandlerInterface {
// some which call read explicitly and some that do not. So we call it explicitly
// just after sid regeneration to force a record to exist.
function read ($id) {
function read ($id) : string {
if($id) {
$r = q("SELECT sess_data FROM session WHERE sid= '%s'", dbesc($id));
@@ -36,7 +36,7 @@ class SessionHandler implements \SessionHandlerInterface {
}
function write ($id, $data) {
function write ($id, $data) : bool {
// Pretend everything is hunky-dory, even though it isn't.
// There probably isn't anything we can do about it in any event.
@@ -49,9 +49,9 @@ class SessionHandler implements \SessionHandlerInterface {
// Unless we authenticate somehow, only keep a session for 5 minutes
// The viewer can extend this by performing any web action using the
// original cookie, but this allows us to cleanup the hundreds or
// original cookie, but this allows us to cleanup the hundreds or
// thousands of empty sessions left around from web crawlers which are
// assigned cookies on each page that they never use.
// assigned cookies on each page that they never use.
$expire = time() + 300;
@@ -74,19 +74,19 @@ class SessionHandler implements \SessionHandlerInterface {
return true;
}
function close() {
function close() : bool {
return true;
}
function destroy ($id) {
function destroy ($id) : bool {
q("DELETE FROM session WHERE sid = '%s'", dbesc($id));
return true;
}
function gc($expire) {
function gc($expire) : int {
q("DELETE FROM session WHERE expire < %d", dbesc(time()));
return true;
}

View File

@@ -1,15 +1,15 @@
<?php
namespace Zotlabs\Widget;
require_once('include/group.php');
use Zotlabs\Lib\AccessList;
class Collections {
function widget($args) {
if(argc() < 2)
return;
// return;
$mode = ((array_key_exists('mode',$args)) ? $args['mode'] : 'conversation');
switch($mode) {
@@ -49,6 +49,6 @@ class Collections {
break;
}
return group_side($every, $each, $edit, $current, $abook_id, $wmode);
return AccessList::widget($every, $each, $edit, $current, $abook_id, $wmode);
}
}

View File

@@ -1,163 +0,0 @@
<?php
namespace Zotlabs\Widget;
class Conversations {
function widget($arr) {
if (! local_channel())
return;
switch(argv(1)) {
case 'inbox':
$mailbox = 'inbox';
$header = t('Received Messages');
break;
case 'outbox':
$mailbox = 'outbox';
$header = t('Sent Messages');
break;
default:
$mailbox = 'combined';
$header = t('Conversations');
break;
}
$o = '';
// private_messages_list() can do other more complicated stuff, for now keep it simple
$r = self::private_messages_list(local_channel(), $mailbox, \App::$pager['start'], \App::$pager['itemspage']);
if(! $r) {
info( t('No messages.') . EOL);
return $o;
}
$messages = [];
foreach($r as $rr) {
$selected = ((argc() == 3) ? intval(argv(2)) == intval($rr['id']) : $r[0]['id'] == $rr['id']);
$messages[] = [
'mailbox' => $mailbox,
'id' => $rr['id'],
'from_name' => $rr['from']['xchan_name'],
'from_url' => chanlink_hash($rr['from_xchan']),
'from_photo' => $rr['from']['xchan_photo_s'],
'to_name' => $rr['to']['xchan_name'],
'to_url' => chanlink_hash($rr['to_xchan']),
'to_photo' => $rr['to']['xchan_photo_s'],
'subject' => (($rr['seen']) ? $rr['title'] : '<strong>' . $rr['title'] . '</strong>'),
'delete' => t('Delete conversation'),
'body' => $rr['body'],
'date' => datetime_convert('UTC',date_default_timezone_get(),$rr['created'], 'c'),
'seen' => $rr['seen'],
'selected' => ((argv(1) != 'new') ? $selected : '')
];
}
$tpl = get_markup_template('mail_head.tpl');
$o .= replace_macros($tpl, [
'$header' => $header,
'$messages' => $messages
]);
return $o;
}
function private_messages_list($uid, $mailbox = '', $start = 0, $numitems = 0) {
$where = '';
$limit = '';
$t0 = dba_timer();
if($numitems)
$limit = " LIMIT " . intval($numitems) . " OFFSET " . intval($start);
if($mailbox !== '') {
$x = q("select channel_hash from channel where channel_id = %d limit 1",
intval($uid)
);
if(! $x)
return array();
$channel_hash = dbesc($x[0]['channel_hash']);
$local_channel = intval(local_channel());
switch($mailbox) {
case 'inbox':
$sql = "SELECT * FROM mail WHERE channel_id = $local_channel AND from_xchan != '$channel_hash' ORDER BY created DESC $limit";
break;
case 'outbox':
$sql = "SELECT * FROM mail WHERE channel_id = $local_channel AND from_xchan = '$channel_hash' ORDER BY created DESC $limit";
break;
case 'combined':
default:
$parents = q("SELECT mail.parent_mid FROM mail LEFT JOIN conv ON mail.conv_guid = conv.guid WHERE mail.mid = mail.parent_mid AND mail.channel_id = %d ORDER BY conv.updated DESC $limit",
intval($local_channel)
);
break;
}
}
$r = null;
if($parents) {
foreach($parents as $parent) {
$all = q("SELECT * FROM mail WHERE parent_mid = '%s' AND channel_id = %d ORDER BY created DESC limit 1",
dbesc($parent['parent_mid']),
intval($local_channel)
);
if($all) {
foreach($all as $single) {
$r[] = $single;
}
}
}
}
elseif($sql) {
$r = q($sql);
}
if(! $r) {
return array();
}
$chans = array();
foreach($r as $rr) {
$s = "'" . dbesc(trim($rr['from_xchan'])) . "'";
if(! in_array($s,$chans))
$chans[] = $s;
$s = "'" . dbesc(trim($rr['to_xchan'])) . "'";
if(! in_array($s,$chans))
$chans[] = $s;
}
$c = q("select * from xchan where xchan_hash in (" . protect_sprintf(implode(',',$chans)) . ")");
foreach($r as $k => $rr) {
$r[$k]['from'] = find_xchan_in_array($rr['from_xchan'],$c);
$r[$k]['to'] = find_xchan_in_array($rr['to_xchan'],$c);
$r[$k]['seen'] = intval($rr['mail_seen']);
if(intval($r[$k]['mail_obscured'])) {
if($r[$k]['title'])
$r[$k]['title'] = base64url_decode(str_rot47($r[$k]['title']));
if($r[$k]['body'])
$r[$k]['body'] = base64url_decode(str_rot47($r[$k]['body']));
}
}
return $r;
}
}

View File

@@ -1,38 +0,0 @@
<?php
namespace Zotlabs\Widget;
class Mailmenu {
function widget($arr) {
if (! local_channel())
return;
return replace_macros(get_markup_template('message_side.tpl'), array(
'$title' => t('Private Mail Menu'),
'$combined' => array(
'label' => t('Combined View'),
'url' => z_root() . '/mail/combined',
'sel' => (argv(1) == 'combined' || argc() == 1),
),
'$inbox' => array(
'label' => t('Inbox'),
'url' => z_root() . '/mail/inbox',
'sel' => (argv(1) == 'inbox'),
),
'$outbox' => array(
'label' => t('Outbox'),
'url' => z_root() . '/mail/outbox',
'sel' => (argv(1) == 'outbox'),
),
/*
'$new' => array(
'label' => t('New Message'),
'url' => z_root() . '/mail/new',
'sel'=> (argv(1) == 'new'),
)
*/
));
}
}

View File

@@ -219,7 +219,7 @@ class Messages {
$entries[$i]['info'] = '';
$entries[$i]['created'] = datetime_convert('UTC', date_default_timezone_get(), $notice['created']);
$entries[$i]['summary'] = $summary;
$entries[$i]['b64mid'] = basename($notice['link']);
$entries[$i]['b64mid'] = (($notice['ntype'] & NOTIFY_INTRO) ? '' : basename($notice['link']));
$entries[$i]['href'] = (($notice['ntype'] & NOTIFY_INTRO) ? $notice['link'] : z_root() . '/hq/' . basename($notice['link']));
$entries[$i]['icon'] = (($notice['ntype'] & NOTIFY_INTRO) ? '<i class="fa fa-user-plus"></i>' : '');

View File

@@ -0,0 +1,96 @@
<?php
namespace Zotlabs\Widget;
use Zotlabs\Lib\Permcat;
use Zotlabs\Access\PermissionLimits;
class Permcats {
function widget($arr) {
$pcat = new Permcat(local_channel());
$pcatlist = $pcat->listing();
if (!$pcatlist) {
return;
}
$roles = [];
$active_role = '';
foreach($pcatlist as $pc) {
if (!$active_role) {
$active_role = ((argc() > 1 && $pc['name'] === hex2bin(argv(1))) ? $pc['name'] : '');
}
$roles[] = [
'name' => $pc['localname'],
'url' => z_root() . '/permcats/' . bin2hex($pc['name']),
'active' => (argc() > 1 && $pc['name'] === hex2bin(argv(1)))
];
}
if($active_role) {
$roles[] = [
'name' => '<i class="fa fa-plus"></i>&nbsp;' . t('Add new role'),
'url' => z_root() . '/permcats',
'active' => ''
];
/* get role members based on permissions
$test = $pcatlist[$active]['perms'];
$role_sql = '';
$count = 0;
foreach ($test as $t) {
$checkinherited = PermissionLimits::Get(local_channel(),$t['name']);
if($checkinherited & PERMS_SPECIFIC) {
$role_sql .= "( abconfig.k = '" . dbesc($t['name']) . "' AND abconfig.v = '" . intval($t['value']) . "' ) OR ";
$count++;
}
}
$role_sql = rtrim($role_sql, ' OR ');
$r = q("SELECT abconfig.xchan, xchan.xchan_name, abook.abook_id FROM abconfig LEFT JOIN xchan on abconfig.xchan = xchan.xchan_hash LEFT JOIN abook ON abconfig.xchan = abook.abook_xchan WHERE xchan.xchan_deleted = 0 and abconfig.chan = %d AND abconfig.cat = 'my_perms' AND ( $role_sql ) GROUP BY abconfig.xchan HAVING count(abconfig.xchan) = %d ORDER BY xchan.xchan_name",
intval(local_channel()),
intval($count)
);
*/
// get role members based on abook_role
$r = q("SELECT abook.abook_id, abook.abook_role, xchan.xchan_name, xchan.xchan_addr, xchan.xchan_url, xchan.xchan_photo_s FROM abook
LEFT JOIN xchan on abook.abook_xchan = xchan.xchan_hash
WHERE abook.abook_channel = %d AND abook.abook_role = '%s' AND abook_self = 0 AND xchan_deleted = 0
ORDER BY xchan.xchan_name",
intval(local_channel()),
dbesc($active_role)
);
$members = [];
foreach ($r as $rr) {
$members[] = [
'name' => $rr['xchan_name'],
'addr' => (($rr['xchan_addr']) ? $rr['xchan_addr'] : $rr['xchan_url']),
'url' => z_root() . '/connections#' . $rr['abook_id'],
'photo' => $rr['xchan_photo_s']
];
}
}
$tpl = get_markup_template("permcats_widget.tpl");
$o .= replace_macros($tpl, [
'$roles_label' => t('Contact roles'),
'$members_label' => t('Role members'),
'$roles' => $roles,
'$members' => $members
]);
return $o;
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace Zotlabs\Widget;
use Zotlabs\Lib\AccessList;
class Privacygroups {
function widget($arr) {
$o = '';
$groups = q("SELECT id, gname FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval(local_channel())
);
if (!$groups) {
return $o;
}
$menu_items = [];
$z_root = z_root();
$active = argv(1) ?? '';
foreach($groups as $group) {
$menu_items[] = [
'href' => $z_root . '/group/' . $group['id'],
'label' => $group['gname'],
'title' => '',
'active' => ($active === $group['id']),
'count' => count(AccessList::members(local_channel(), $group['id']))
];
}
if ($active) {
$menu_items[] = [
'href' => $z_root . '/group',
'label' => '<i class="fa fa-plus"></i> &nbsp;' . t('Add new group'),
'title' => '',
'active' => '',
'count' => ''
];
}
$tpl = get_markup_template("widget_menu_count.tpl");
$o .= replace_macros($tpl, [
'$title' => t('Privacy groups'),
'$menu_items' => $menu_items,
]);
return $o;
}
}

View File

@@ -2,12 +2,16 @@
namespace Zotlabs\Widget;
use App;
class Profile {
function widget($args) {
$block = observer_prohibited();
return profile_sidebar(\App::$profile, $block, true, false);
}
if(!App::$profile['profile_uid']) {
return;
}
$block = observer_prohibited();
return profile_sidebar(App::$profile, $block, true, false);
}
}

View File

@@ -40,6 +40,11 @@ class Settings_menu {
'selected' => ((argv(1) === 'channel') ? 'active' : ''),
),
array(
'label' => t('Privacy settings'),
'url' => z_root().'/settings/privacy',
'selected' => ((argv(1) === 'privacy') ? 'active' : '')
)
);
$tabs[] = array(

51
Zotlabs/Widget/Tokens.php Normal file
View File

@@ -0,0 +1,51 @@
<?php
namespace Zotlabs\Widget;
class Tokens {
function widget($arr) {
$o = '';
$tokens = q("SELECT atoken_id, atoken_name FROM atoken WHERE atoken_uid = %d",
intval(local_channel())
);
if (!$tokens) {
return $o;
}
$menu_items = [];
$z_root = z_root();
$active = argv(1) ?? '';
foreach($tokens as $token) {
$menu_items[] = [
'href' => $z_root . '/tokens/' . $token['atoken_id'],
'label' => $token['atoken_name'],
'title' => '',
'active' => ($active === $token['atoken_id'])
];
}
if ($active) {
$menu_items[] = [
'href' => $z_root . '/tokens',
'label' => '<i class="fa fa-plus"></i> &nbsp;' . t('Add new guest'),
'title' => '',
'active' => ''
];
}
$tpl = get_markup_template("widget_menu.tpl");
$o .= replace_macros($tpl, [
'$title' => t('Guest access'),
'$menu_items' => $menu_items,
]);
return $o;
}
}

View File

@@ -1,7 +1,7 @@
version: 3
version: 4
url: $baseurl/channel/$nick, $baseurl/settings/channel_home
requires: local_channel
name: Channel Home
name: Channel
photo: icon:home
categories: nav_featured_app, Personal
desc: Your channel homepage featuring your personal posts.

View File

@@ -1,7 +1,7 @@
version: 3
version: 4
url: $baseurl/group
requires: local_channel
name: Privacy Groups
photo: icon:users
photo: icon:lock
categories: Networking
desc: A tool to create and manage privacy groups.

View File

@@ -1,7 +1,7 @@
version: 3
version: 5
url: $baseurl/permcats
requires: local_channel
name: Permission Categories
photo: icon:unlock-alt
name: Contact Roles
photo: icon:user-o
categories: Access Control
desc: Create and manage custom connection permission limits.
desc: Create and manage custom contact roles.

1620
boot.php

File diff suppressed because it is too large Load Diff

View File

@@ -15,10 +15,10 @@ use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\Activity;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Daemon\Master;
use Zotlabs\Lib\AccessList;
require_once('include/permissions.php');
require_once('include/security.php');
require_once('include/group.php');
/**
* @brief Guess the mimetype from file ending.
@@ -2208,7 +2208,7 @@ function attach_recursive_perms($arr_allow_cid, $arr_allow_gid, $arr_deny_cid, $
//lookup all channels in sharee group and add them to sharee $arr_allow_cid
if($arr_allow_gid) {
$in_group = expand_groups($arr_allow_gid);
$in_group = AccessList::expand($arr_allow_gid);
$arr_allow_cid = array_unique(array_merge($arr_allow_cid, $in_group));
}
@@ -2280,7 +2280,7 @@ function attach_recursive_perms($arr_allow_cid, $arr_allow_gid, $arr_deny_cid, $
//check sharee arr_allow_cid against members of allow_gid of all parent folders
foreach($parent_arr['allow_gid'] as $folder_arr_allow_gid) {
//get the group members
$folder_arr_allow_cid = expand_groups($folder_arr_allow_gid);
$folder_arr_allow_cid = AccessList::expand($folder_arr_allow_gid);
foreach($folder_arr_allow_cid as $ac_hash) {
$count_values[$ac_hash]++;
}

View File

@@ -1400,7 +1400,7 @@ function bbcode($Text, $options = []) {
// Check for table of content without params
while(strpos($Text,'[toc]') !== false) {
$toc_id = 'toc-' . random_string(10);
$Text = preg_replace("/\[toc\]/ism", '<ul id="' . $toc_id . '" class="toc" data-toc=".section-content-wrapper"></ul><script>$("#' . $toc_id . '").toc();</script>', $Text, 1);
$Text = preg_replace("/\[toc\]/ism", '<ul id="' . $toc_id . '" class="toc"></ul><script>$(document).ready(function() { let toc_container = $("#' . $toc_id . '").parent().closest("div").attr("id") || ".section-content-wrapper"; $("#' . $toc_id . '").toc({content: "#" + toc_container, headings: "h1,h2,h3,h4"}); });</script>', $Text, 1);
}
// Check for table of content with params
while(strpos($Text,'[toc') !== false) {

View File

@@ -15,11 +15,13 @@ use Zotlabs\Render\Comanche;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Connect;
use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\AccessList;
require_once('include/crypto.php');
require_once('include/menu.php');
require_once('include/perm_upgrade.php');
require_once('include/photo/photo_driver.php');
require_once('include/security.php');
/**
* @brief Called when creating a new channel.
@@ -240,7 +242,7 @@ function create_identity($arr) {
// Force a few things on the short term until we can provide a theme or app with choice
$publish = 1;
$publish = 0;
if(array_key_exists('publish', $arr))
$publish = intval($arr['publish']);
@@ -325,6 +327,12 @@ function create_identity($arr) {
if($role_permissions && array_key_exists('perms_auto',$role_permissions))
set_pconfig($r[0]['channel_id'],'system','autoperms',intval($role_permissions['perms_auto']));
$group_actor = false;
if($role_permissions && array_key_exists('channel_type', $role_permissions) && $role_permissions['channel_type'] === 'group') {
set_pconfig($r[0]['channel_id'], 'system', 'group_actor', 1);
$group_actor = true;
}
$ret['channel'] = $r[0];
if(intval($arr['account_id']))
@@ -374,7 +382,8 @@ function create_identity($arr) {
'xchan_network' => 'zot6',
'xchan_photo_date' => datetime_convert(),
'xchan_name_date' => datetime_convert(),
'xchan_system' => $system
'xchan_system' => $system,
'xchan_pubforum' => $group_actor
]
);
if(! $r)
@@ -399,14 +408,6 @@ function create_identity($arr) {
]
);
if($role_permissions) {
$myperms = ((array_key_exists('perms_connect',$role_permissions)) ? $role_permissions['perms_connect'] : array());
}
else {
$x = PermissionRoles::role_perms('social');
$myperms = $x['perms_connect'];
}
$r = abook_store_lowlevel(
[
'abook_account' => intval($ret['channel']['channel_account_id']),
@@ -419,19 +420,18 @@ function create_identity($arr) {
]
);
$x = Permissions::FilledPerms($myperms);
foreach($x as $k => $v) {
set_abconfig($newuid,$hash,'my_perms',$k,$v);
}
if(intval($ret['channel']['channel_account_id'])) {
// Save our permissions role so we can perhaps call it up and modify it later.
// Set the default permcat
set_pconfig($newuid,'system','default_permcat','default');
if($role_permissions) {
// Save our permissions role so we can perhaps call it up and modify it later.
set_pconfig($newuid,'system','permissions_role',$arr['permissions_role']);
if(array_key_exists('online',$role_permissions))
set_pconfig($newuid,'system','hide_presence',1-intval($role_permissions['online']));
set_pconfig($newuid,'system','show_online_status', intval($role_permissions['online']));
if(array_key_exists('perms_auto',$role_permissions)) {
$autoperms = intval($role_permissions['perms_auto']);
set_pconfig($newuid,'system','autoperms',$autoperms);
@@ -453,11 +453,10 @@ function create_identity($arr) {
// Create a group with yourself as a member. This allows somebody to use it
// right away as a default group for new contacts.
require_once('include/group.php');
$group_hash = group_add($newuid, t('Friends'));
$group_hash = AccessList::add($newuid, t('Friends'));
if($group_hash) {
group_add_member($newuid,t('Friends'),$ret['channel']['channel_hash']);
AccessList::member_add($newuid,t('Friends'),$ret['channel']['channel_hash']);
$default_collection_str = '';
// if our role_permissions indicate that we're using a default collection ACL, add it.
@@ -496,8 +495,7 @@ function create_identity($arr) {
if($acct) {
$f = connect_and_sync($ret['channel'], $acct);
if($f['success']) {
$can_view_stream = their_perms_contains($ret['channel']['channel_id'],$f['abook']['abook_xchan'],'view_stream');
$can_view_stream = intval(get_abconfig($ret['channel']['channel_id'], $f['abook']['abook_xchan'], 'their_perms', 'view_stream'));
// If we can view their stream, pull in some posts
if(($can_view_stream) || ($f['abook']['xchan_network'] === 'rss')) {
Master::Summon([ 'Onepoll',$f['abook']['abook_id'] ]);
@@ -881,6 +879,14 @@ function identity_basic_export($channel_id, $sections = null, $zap_compat = fals
}
if(in_array('connections',$sections)) {
$r = q("select * from atoken where atoken_uid = %d",
intval($channel_id)
);
if ($r) {
$ret['atoken'] = $r;
}
$xchans = array();
$r = q("select * from abook where abook_channel = %d ",
intval($channel_id)
@@ -1488,6 +1494,7 @@ function profile_load($nickname, $profile = '') {
if($can_view_profile) {
$online = get_online_status($nickname);
App::$profile['online_status'] = $online['result'];
}
@@ -1965,11 +1972,24 @@ function zat_init() {
);
if($r) {
$xchan = atoken_xchan($r[0]);
atoken_create_xchan($xchan);
//atoken_create_xchan($xchan);
atoken_login($xchan);
}
}
function atoken_delete_and_sync($channel_id, $atoken_guid) {
$r = q("select * from atoken where atoken_guid = '%s' and atoken_uid = %d",
dbesc($atoken_guid),
intval($channel_id)
);
if ($r) {
$atok = $r[0];
$atok['deleted'] = true;
atoken_delete($atok['atoken_id']);
Libsync::build_sync_packet($channel_id, ['atoken' => [ $atok ]]);
}
}
/**
* @brief Used from within PCSS themes to set theme parameters.
@@ -2060,11 +2080,12 @@ function get_online_status($nick) {
return $ret;
$r = q("select channel_id, channel_hash from channel where channel_address = '%s' limit 1",
dbesc(argv(1))
dbesc($nick)
);
if($r) {
$hide = get_pconfig($r[0]['channel_id'],'system','hide_online_status');
if($hide)
$show = get_pconfig($r[0]['channel_id'],'system','show_online_status');
if(!$show)
return $ret;
$x = q("select cp_status from chatpresence where cp_xchan = '%s' and cp_room = 0 limit 1",
@@ -2280,7 +2301,7 @@ function auto_channel_create($account_id) {
}
}
if(! $arr['permissions_role'])
$arr['permissions_role'] = 'social';
$arr['permissions_role'] = 'personal';
if(validate_channelname($arr['name']))
return false;

View File

@@ -1,5 +1,6 @@
<?php /** @file */
use Zotlabs\Daemon\Master;
function abook_store_lowlevel($arr) {
@@ -27,7 +28,8 @@ function abook_store_lowlevel($arr) {
'abook_profile' => ((array_key_exists('abook_profile',$arr)) ? $arr['abook_profile'] : ''),
'abook_incl' => ((array_key_exists('abook_incl',$arr)) ? $arr['abook_incl'] : ''),
'abook_excl' => ((array_key_exists('abook_excl',$arr)) ? $arr['abook_excl'] : ''),
'abook_instance' => ((array_key_exists('abook_instance',$arr)) ? $arr['abook_instance'] : '')
'abook_instance' => ((array_key_exists('abook_instance',$arr)) ? $arr['abook_instance'] : ''),
'abook_role' => ((array_key_exists('abook_role',$arr)) ? $arr['abook_role'] : '')
];
return create_table_from_array('abook',$store);
@@ -112,7 +114,7 @@ function vcard_from_xchan($xchan, $observer = null, $mode = '') {
// don't provide a connect button for transient or one-way identities
if(in_array($xchan['xchan_network'],['rss','anon','unknown']) || strpos($xchan['xchan_addr'],'guest:') === 0) {
if(in_array($xchan['xchan_network'],['rss', 'anon', 'unknown', 'token'])) {
$connect = false;
}
@@ -284,17 +286,18 @@ function remove_all_xchan_resources($xchan, $channel_id = 0) {
$dirmode = intval(get_config('system','directory_mode'));
$r = q("delete from photo where xchan = '%s'",
dbesc($xchan)
);
$r = q("select resource_id, resource_type, uid, id from item where ( author_xchan = '%s' or owner_xchan = '%s' ) ",
dbesc($xchan),
dbesc($xchan)
);
if($r) {
foreach($r as $rr) {
drop_item($rr,false);
drop_item($rr['id'],false);
}
}
@@ -375,52 +378,22 @@ function contact_remove($channel_id, $abook_id) {
if(intval($abook['abook_self']))
return false;
$r = q("select id, parent from item where (owner_xchan = '%s' or author_xchan = '%s') and uid = %d and item_retained = 0 and item_starred = 0",
dbesc($abook['abook_xchan']),
dbesc($abook['abook_xchan']),
intval($channel_id)
);
if($r) {
$already_saved = [];
foreach($r as $rr) {
$w = $x = $y = null;
// if this is an atoken, delete the atoken record
// optimise so we only process newly seen parent items
if (in_array($rr['parent'],$already_saved)) {
continue;
}
// if this isn't the parent, fetch the parent's item_retained and item_starred to see if the conversation
// should be retained
if($rr['id'] != $rr['parent']) {
$w = q("select id, item_retained, item_starred from item where id = %d",
intval($rr['parent'])
);
if($w) {
// see if the conversation was filed
$x = q("select uid from term where otype = %d and oid = %d and ttype = %d limit 1",
intval(TERM_OBJ_POST),
intval($w[0]['id']),
intval(TERM_FILE)
);
if (intval($w[0]['item_retained']) || intval($w[0]['item_starred']) || $x) {
$already_saved[] = $rr['parent'];
continue;
}
}
}
// see if this item was filed
$y = q("select uid from term where otype = %d and oid = %d and ttype = %d limit 1",
intval(TERM_OBJ_POST),
intval($rr['id']),
intval(TERM_FILE)
);
if ($y) {
continue;
}
drop_item($rr['id'],false);
$xchan = q("select * from xchan where xchan_hash = '%s'",
dbesc($abook['abook_xchan'])
);
if (strpos($xchan['xchan_addr'],'guest:') === 0 && strpos($abook['abook_xchan'],'.')){
$atoken_guid = substr($abook['abook_xchan'],strrpos($abook['abook_xchan'],'.') + 1);
if ($atoken_guid) {
atoken_delete_and_sync($channel_id,$atoken_guid);
}
}
// remove items in the background as this can take some time
Master::Summon(['Delxitems', $channel_id, $abook['abook_xchan']]);
q("delete from abook where abook_id = %d and abook_channel = %d",
intval($abook['abook_id']),
intval($channel_id)
@@ -449,7 +422,62 @@ function contact_remove($channel_id, $abook_id) {
return true;
}
function remove_abook_items($channel_id, $xchan_hash) {
$r = q("select id from item where (owner_xchan = '%s' or author_xchan = '%s') and uid = %d and item_retained = 0 and item_starred = 0",
dbesc($xchan_hash),
dbesc($xchan_hash),
intval($channel_id)
);
if (! $r) {
return;
}
$already_saved = [];
foreach ($r as $rr) {
$w = $x = $y = null;
// optimise so we only process newly seen parent items
if (in_array($rr['parent'], $already_saved)) {
continue;
}
// if this isn't the parent, fetch the parent's item_retained and item_starred to see if the conversation
// should be retained
if ($rr['id'] != $rr['parent']) {
$w = q("select id, item_retained, item_starred from item where id = %d",
intval($rr['parent'])
);
if ($w) {
// see if the conversation was filed
$x = q("select uid from term where otype = %d and oid = %d and ttype = %d limit 1",
intval(TERM_OBJ_POST),
intval($w[0]['id']),
intval(TERM_FILE)
);
if (intval($w[0]['item_retained']) || intval($w[0]['item_starred']) || $x) {
$already_saved[] = $rr['parent'];
continue;
}
}
}
// see if this item was filed
$y = q("select uid from term where otype = %d and oid = %d and ttype = %d limit 1",
intval(TERM_OBJ_POST),
intval($rr['id']),
intval(TERM_FILE)
);
if ($y) {
continue;
}
drop_item($rr['id'],false);
}
}
function random_profile() {
$randfunc = db_getfunc('rand');

View File

@@ -100,6 +100,10 @@ function categories_widget($baseurl,$selected = '') {
\Zotlabs\Daemon\Master::Summon([ 'Cache_query', $key, base64_encode(json_encode($arr)) ]);
}
if (!$content) {
return EMPTY_STR;
}
$r = unserialize($content);
$terms = [];

View File

@@ -558,7 +558,7 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
$page_writeable = ($profile_owner == local_channel());
if (!$update) {
$tab = notags(trim($_GET['tab']));
$tab = notags(trim((string)$_GET['tab']));
if ($tab === 'posts') {
// This is ugly, but we can't pass the profile_uid through the session to the ajax updater,
// because browser prefetching might change it on us. We have to deliver it with the page.
@@ -775,6 +775,12 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
$conv_link = ((in_array($item['item_type'],[ ITEM_TYPE_CARD, ITEM_TYPE_ARTICLE] )) ? $item['plink'] : z_root() . '/' . $conv_link_module . '/' . gen_link_id($conv_link_mid));
$contact = [];
if(App::$contacts && array_key_exists($item['author_xchan'],App::$contacts)) {
$contact = App::$contacts[$item['author_xchan']];
}
$tmp_item = array(
'template' => $tpl,
'toplevel' => 'toplevel_item',
@@ -838,7 +844,8 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
'wait' => t('Please wait'),
'thread_level' => 1,
'has_tags' => $has_tags,
'is_new' => $is_new
'is_new' => $is_new,
'contact_id' => (($contact) ? $contact['abook_id'] : '')
);
$arr = array('item' => $item, 'output' => $tmp_item);
@@ -967,7 +974,7 @@ function best_link_url($item) {
}
}
if(! $best_url) {
if(strlen($item['author-link']))
if($item['author-link'])
$best_url = $item['author-link'];
else
$best_url = $item['url'];
@@ -1061,7 +1068,7 @@ function thread_author_menu($item, $mode = '') {
}
else {
$url = (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url']);
if($local_channel && $url && (! in_array($item['author']['xchan_network'],[ 'rss', 'anon','unknown', 'zot' ]))) {
if($local_channel && $url && (! in_array($item['author']['xchan_network'],[ 'rss', 'anon','unknown', 'zot', 'token']))) {
$follow_url = z_root() . '/follow/?f=&url=' . urlencode($url) . '&interactive=0';
}
}
@@ -1070,7 +1077,7 @@ function thread_author_menu($item, $mode = '') {
if($contact) {
$poke_link = ((Apps::system_app_installed($local_channel, 'Poke')) ? z_root() . '/poke/?f=&c=' . $contact['abook_id'] : '');
if (! intval($contact['abook_self']))
$contact_url = z_root() . '/connedit/' . $contact['abook_id'];
$contact_url = z_root() . '/connections#' . $contact['abook_id'];
$posts_link = z_root() . '/network/?cid=' . $contact['abook_id'];
$clean_url = normalise_link($item['author-link']);
@@ -1086,7 +1093,9 @@ function thread_author_menu($item, $mode = '') {
'title' => t('View Profile'),
'icon' => 'fw',
'action' => '',
'href' => $profile_link
'href' => $profile_link,
'data' => '',
'class' => ''
];
}
@@ -1096,7 +1105,9 @@ function thread_author_menu($item, $mode = '') {
'title' => t('Recent Activity'),
'icon' => 'fw',
'action' => '',
'href' => $posts_link
'href' => $posts_link,
'data' => '',
'class' => ''
];
}
@@ -1107,6 +1118,8 @@ function thread_author_menu($item, $mode = '') {
'icon' => 'fw',
'action' => 'doFollowAuthor(\'' . $follow_url . '\'); return false;',
'href' => '#',
'data' => '',
'class' => ''
];
}
@@ -1116,7 +1129,9 @@ function thread_author_menu($item, $mode = '') {
'title' => t('Edit Connection'),
'icon' => 'fw',
'action' => '',
'href' => $contact_url
'href' => $contact_url,
'data' => 'data-id="' . $contact['abook_id'] . '"',
'class' => 'contact-edit'
];
}
@@ -1126,7 +1141,9 @@ function thread_author_menu($item, $mode = '') {
'title' => t('Message'),
'icon' => 'fw',
'action' => '',
'href' => $pm_url
'href' => $pm_url,
'data' => '',
'class' => ''
];
}
@@ -1136,7 +1153,9 @@ function thread_author_menu($item, $mode = '') {
'title' => t('Ratings'),
'icon' => 'fw',
'action' => '',
'href' => $ratings_url
'href' => $ratings_url,
'data' => '',
'class' => ''
];
}
@@ -1146,7 +1165,9 @@ function thread_author_menu($item, $mode = '') {
'title' => t('Poke'),
'icon' => 'fw',
'action' => '',
'href' => $poke_link
'href' => $poke_link,
'data' => '',
'class' => ''
];
}

View File

@@ -38,7 +38,7 @@ class DBA {
* @param bool $install Defaults to false
* @return null|dba_driver A database driver object (dba_pdo) or null if no driver found.
*/
static public function dba_factory($server,$port,$user,$pass,$db,$dbtype,$install = false) {
static public function dba_factory($server,$port,$user,$pass,$db,$dbtype,$db_charset,$install = false) {
self::$dba = null;
self::$dbtype = intval($dbtype);
@@ -65,7 +65,7 @@ class DBA {
}
require_once('include/dba/dba_pdo.php');
self::$dba = new dba_pdo($server,self::$scheme,$port,$user,$pass,$db,$install);
self::$dba = new dba_pdo($server,self::$scheme,$port,$user,$pass,$db,$db_charset,$install);
define('NULL_DATE', self::$null_date);
define('ACTIVE_DBTYPE', self::$dbtype);
@@ -105,7 +105,7 @@ abstract class dba_driver {
* @param string $db database name
* @return bool
*/
abstract function connect($server, $scheme, $port, $user, $pass, $db);
abstract function connect($server, $scheme, $port, $user, $pass, $db, $db_charset);
/**
* @brief Perform a DB query with the SQL statement $sql.
@@ -139,11 +139,11 @@ abstract class dba_driver {
*/
abstract function getdriver();
function __construct($server, $scheme, $port, $user,$pass,$db,$install = false) {
if(($install) && (! $this->install($server, $scheme, $port, $user, $pass, $db))) {
function __construct($server, $scheme, $port, $user,$pass,$db,$db_charset,$install = false) {
if(($install) && (! $this->install($server, $scheme, $port, $user, $pass, $db, $db_charset))) {
return;
}
$this->connect($server, $scheme, $port, $user, $pass, $db);
$this->connect($server, $scheme, $port, $user, $pass, $db, $db_charset);
}
function get_null_date() {

View File

@@ -14,7 +14,7 @@ class dba_pdo extends dba_driver {
* {@inheritDoc}
* @see dba_driver::connect()
*/
function connect($server, $scheme, $port, $user, $pass, $db) {
function connect($server, $scheme, $port, $user, $pass, $db, $db_charset) {
$this->driver_dbtype = $scheme;
@@ -27,6 +27,13 @@ class dba_pdo extends dba_driver {
$dsn .= ';dbname=' . $db;
if ($this->driver_dbtype === 'mysql') {
$dsn .= ';charset=' . $db_charset;
}
else {
$dsn .= ";options='--client_encoding=" . $db_charset . "'";
}
try {
$this->db = new PDO($dsn,$user,$pass);
$this->db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);

View File

@@ -1180,7 +1180,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
else {
$name = $author['author_name'];
}
$x = import_author_unknown(array('name' => $name,'url' => $author['author_link'],'photo' => array('src' => $author['author_photo'])));
$x = import_author_rss(array('name' => $name,'url' => $author['author_link'],'photo' => array('src' => $author['author_photo'])));
if($x)
$datarray['author_xchan'] = $x;
}
@@ -1440,7 +1440,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
else {
$name = $author['author_name'];
}
$x = import_author_unknown(array('name' => $name,'url' => $author['author_link'],'photo' => array('src' => $author['author_photo'])));
$x = import_author_rss(array('name' => $name,'url' => $author['author_link'],'photo' => array('src' => $author['author_photo'])));
if($x)
$datarray['author_xchan'] = $x;
}

View File

@@ -326,7 +326,7 @@ function group_side($every="connections",$each="group",$edit = false, $group_id
$o = replace_macros($tpl, array(
'$title' => t('Privacy Groups'),
'$edittext' => t('Edit group'),
'$createtext' => t('Add privacy group'),
'$createtext' => ((argv(1) == 'new' ) ? '' : t('Manage privacy groups')),
'$ungrouped' => (($every === 'contacts') ? t('Channels not in any privacy group') : ''),
'$groups' => $groups,
'$add' => t('add'),

View File

@@ -16,6 +16,8 @@ use Zotlabs\Daemon\Master;
*/
function hubloc_store_lowlevel($arr) {
$update = ((array_key_exists('hubloc_id',$arr) && $arr['hubloc_id']) ? 'hubloc_id = ' . intval($arr['hubloc_id']) : false);
$store = [
'hubloc_guid' => ((array_key_exists('hubloc_guid',$arr)) ? $arr['hubloc_guid'] : ''),
'hubloc_guid_sig' => ((array_key_exists('hubloc_guid_sig',$arr)) ? $arr['hubloc_guid_sig'] : ''),
@@ -40,7 +42,7 @@ function hubloc_store_lowlevel($arr) {
'hubloc_deleted' => ((array_key_exists('hubloc_deleted',$arr)) ? $arr['hubloc_deleted'] : 0)
];
return create_table_from_array('hubloc', $store);
return (($update) ? update_table_from_array('hubloc', $store, $update) : create_table_from_array('hubloc', $store));
}
function site_store_lowlevel($arr) {
@@ -283,6 +285,13 @@ function hubloc_change_primary($hubloc) {
return true;
}
function hubloc_delete($hubloc) {
if (is_array($hubloc) && array_key_exists('hubloc_id', $hubloc)) {
q("UPDATE hubloc SET hubloc_deleted = 1 WHERE hubloc_id = %d",
intval($hubloc['hubloc_id'])
);
}
}
/**
* @brief Mark a hubloc as down.

View File

@@ -162,6 +162,64 @@ function import_config($channel, $configs) {
}
}
function import_atoken($channel, $atokens) {
if ($channel && $atokens) {
foreach ($atokens as $atoken) {
unset($atoken['atoken_id']);
$atoken['atoken_aid'] = $channel['channel_account_id'];
$atoken['atoken_uid'] = $channel['channel_id'];
create_table_from_array('atoken', $atoken);
}
}
}
function sync_atoken($channel, $atokens) {
if ($channel && $atokens) {
foreach ($atokens as $atoken) {
unset($atoken['atoken_id']);
$atoken['atoken_aid'] = $channel['channel_account_id'];
$atoken['atoken_uid'] = $channel['channel_id'];
if ($atoken['deleted']) {
q("delete from atoken where atoken_uid = %d and atoken_guid = '%s' ",
intval($atoken['atoken_uid']),
dbesc($atoken['atoken_guid'])
);
continue;
}
$r = q("select * from atoken where atoken_uid = %d and atoken_guid = '%s' ",
intval($atoken['atoken_uid']),
dbesc($atoken['atoken_guid'])
);
if (! $r) {
create_table_from_array('atoken', $atoken);
}
else {
$columns = db_columns('atoken');
foreach ($atoken as $k => $v) {
if (! in_array($k,$columns)) {
continue;
}
if (in_array($k, ['atoken_guid','atoken_uid','atoken_aid'])) {
continue;
}
$r = q("UPDATE atoken SET " . TQUOT . "%s" . TQUOT . " = '%s' WHERE atoken_guid = '%s' AND atoken_uid = %d",
dbesc($k),
dbesc($v),
dbesc($atoken['atoken_guid']),
intval($channel['channel_id'])
);
}
}
}
}
}
/**
* @brief Import profiles.
*

View File

@@ -13,9 +13,10 @@ use Zotlabs\Lib\IConfig;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Access\PermissionRoles;
use Zotlabs\Access\AccessList;
use Zotlabs\Lib\AccessList;
use Zotlabs\Daemon\Master;
require_once('include/bbcode.php');
@@ -35,8 +36,6 @@ require_once('include/permissions.php');
*/
function collect_recipients($item, &$private_envelope,$include_groups = true) {
require_once('include/group.php');
$private_envelope = ((intval($item['item_private'])) ? true : false);
$recipients = array();
@@ -47,7 +46,7 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) {
$allow_people = expand_acl($item['allow_cid']);
if($include_groups) {
$allow_groups = expand_groups(expand_acl($item['allow_gid']));
$allow_groups = AccessList::expand(expand_acl($item['allow_gid']));
}
else {
$allow_groups = [];
@@ -72,7 +71,7 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) {
}
$deny_people = expand_acl($item['deny_cid']);
$deny_groups = expand_groups(expand_acl($item['deny_gid']));
$deny_groups = AccessList::expand(expand_acl($item['deny_gid']));
$deny = array_unique(array_merge($deny_people,$deny_groups));
@@ -344,6 +343,7 @@ function can_comment_on_post($observer_xchan, $item) {
return true;
break;
case 'any connections':
case 'specific':
case 'contacts':
case '':
if(local_channel() && get_abconfig(local_channel(),$item['owner_xchan'],'their_perms','post_comments')) {
@@ -476,7 +476,7 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
$arr['comment_policy'] = map_scope(PermissionLimits::Get($channel['channel_id'],'post_comments'));
if ((! $arr['plink']) && (intval($arr['item_thread_top']))) {
$arr['plink'] = substr(z_root() . '/channel/' . $channel['channel_address'] . '/' . (filter_var($arr['mid'], FILTER_VALIDATE_URL) === false ? '?f=&mid=' : '') . urlencode($arr['mid']),0,190);
$arr['plink'] = $arr['mid'];
}
@@ -1226,6 +1226,9 @@ function map_scope($scope, $strip = false) {
return 'site: ' . App::get_hostname();
case PERMS_PENDING:
return 'any connections';
// uncomment after Hubzilla version 7.0 is running on the majority of active hubs
// case PERMS_SPECIFIC:
// return 'specific';
case PERMS_CONTACTS:
default:
return 'contacts';
@@ -1443,7 +1446,7 @@ function activity_sanitise($arr) {
if(is_array($x))
$ret[$k] = activity_sanitise($x);
else
$ret[$k] = htmlspecialchars($x, ENT_COMPAT, 'UTF-8', false);
$ret[$k] = htmlspecialchars((string)$x, ENT_COMPAT, 'UTF-8', false);
}
return $ret;
}
@@ -1622,9 +1625,9 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
return $ret;
}
$arr['title'] = ((array_key_exists('title',$arr) && strlen($arr['title'])) ? trim($arr['title']) : '');
$arr['summary'] = ((array_key_exists('summary',$arr) && strlen($arr['summary'])) ? trim($arr['summary']) : '');
$arr['body'] = ((array_key_exists('body',$arr) && strlen($arr['body'])) ? trim($arr['body']) : '');
$arr['title'] = ((array_key_exists('title',$arr) && $arr['title']) ? trim($arr['title']) : '');
$arr['summary'] = ((array_key_exists('summary',$arr) && $arr['summary']) ? trim($arr['summary']) : '');
$arr['body'] = ((array_key_exists('body',$arr) && $arr['body']) ? trim($arr['body']) : '');
$arr['allow_cid'] = ((x($arr,'allow_cid')) ? trim($arr['allow_cid']) : '');
$arr['allow_gid'] = ((x($arr,'allow_gid')) ? trim($arr['allow_gid']) : '');
@@ -2537,12 +2540,7 @@ function get_item_contact($item,$contacts) {
*/
function tag_deliver($uid, $item_id) {
$role = get_pconfig($uid,'system','permissions_role');
$rolesettings = PermissionRoles::role_perms($role);
$channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal';
$is_group = (($channel_type === 'group') ? true : false);
$is_group = get_pconfig($uid, 'system', 'group_actor');
$mention = false;
/*
@@ -2579,15 +2577,18 @@ function tag_deliver($uid, $item_id) {
}
if ($is_group && intval($item['item_private']) === 2 && intval($item['item_thread_top'])) {
// do not turn the groups own direkt messages into group items
if($item['item_wall'] && $item['author_xchan'] === $u[0]['channel_hash'])
return;
// group delivery via DM
if(perm_is_allowed($uid,$item['owner_xchan'],'post_wall') || perm_is_allowed($uid,$item['owner_xchan'],'tag_deliver')) {
if(perm_is_allowed($uid,$item['owner_xchan'],'post_wall')) {
logger('group DM delivery for ' . $u[0]['channel_address']);
start_delivery_chain($u[0], $item, $item_id, 0, true, (($item['edited'] != $item['created']) || $item['item_deleted']));
q("update item set item_blocked = %d where id = %d",
intval(ITEM_HIDDEN),
intval($item_id)
);
}
return;
}
@@ -2600,13 +2601,6 @@ function tag_deliver($uid, $item_id) {
return;
}
/* this should not be required anymore due to the check above
if (strpos($item['body'],'[/share]')) {
logger('W2W post already shared');
return;
}
*/
// group delivery via W2W
logger('rewriting W2W post for ' . $u[0]['channel_address']);
start_delivery_chain($u[0], $item, $item_id, 0, true, (($item['edited'] != $item['created']) || $item['item_deleted']));
@@ -2677,9 +2671,37 @@ function tag_deliver($uid, $item_id) {
intval($uid)
);
if(($x) && intval($x[0]['item_uplink'])) {
start_delivery_chain($u[0],$item,$item_id,$x[0]);
if ($x) {
// group comments don't normally require a second delivery chain
// but we create a linked Announce so they will show up in the home timeline
// on microblog platforms and this creates a second delivery chain
if ($is_group && intval($x[0]['item_wall'])) {
// don't let the forked delivery chain recurse
if ($item['verb'] === 'Announce' && $item['author_xchan'] === $u['channel_hash']) {
return;
}
// don't announce moderated content until it has been approved
if (intval($item['item_blocked']) === ITEM_MODERATED) {
return;
}
// don't boost likes and other response activities as it is likely that
// few platforms will handle this in an elegant way
if (ActivityStreams::is_response_activity($item['verb'])) {
return;
}
logger('group_comment');
start_delivery_chain($u[0], $item, $item_id, $x[0], true, (($item['edited'] != $item['created']) || $item['item_deleted']));
}
elseif (intval($x[0]['item_uplink'])) {
start_delivery_chain($u,$item,$item_id,$x[0]);
}
}
}
@@ -2920,13 +2942,7 @@ function item_community_tag($channel,$item) {
*/
function tgroup_check($uid, $item) {
$role = get_pconfig($uid,'system','permissions_role');
$rolesettings = PermissionRoles::role_perms($role);
$channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal';
$is_group = (($channel_type === 'group') ? true : false);
$is_group = get_pconfig($uid, 'system', 'group_actor');
$mention = false;
// check that the message originated elsewhere and is a top-level post
@@ -3125,6 +3141,10 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
$arr = [];
q("update item set item_hidden = 1 where id = %d",
intval($item_id)
);
if ($edit) {
// process edit or delete action
@@ -3155,7 +3175,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
}
else {
$arr['uuid'] = item_message_id();
$arr['mid'] = z_root() . '/activity/' . $arr['uuid'];
$arr['mid'] = z_root() . '/item/' . $arr['uuid'];
$arr['parent_mid'] = $arr['mid'];
}
@@ -3173,6 +3193,10 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
$arr['item_private'] = (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
|| $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 1 : 0);
if ($channel['channel_allow_cid'] && empty($channel['channel_allow_gid'])) {
$arr['item_private'] = 2;
}
$arr['item_origin'] = 1;
$arr['item_wall'] = 1;
$arr['item_thread_top'] = 1;
@@ -3192,6 +3216,29 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
$bb .= "[/share]";
$arr['body'] = $bb;
// Conversational objects shouldn't be copied, but other objects should.
if (in_array($item['obj_type'], [ 'Image', 'Event', 'Question' ])) {
$arr['obj'] = $item['obj'];
$t = json_decode($arr['obj'],true);
if ($t !== NULL) {
$arr['obj'] = $t;
}
$arr['obj']['content'] = bbcode($bb);
$arr['obj']['source']['content'] = $bb;
$arr['obj']['id'] = $arr['mid'];
if (! array_path_exists('obj/source/mediaType',$arr)) {
$arr['obj']['source']['mediaType'] = 'text/bbcode';
}
$arr['obj']['directMessage'] = (intval($arr['item_private']) === 2);
}
$arr['tgt_type'] = $item['tgt_type'];
$arr['target'] = $item['target'];
$arr['term'] = $item['term'];
$arr['author_xchan'] = $channel['channel_hash'];
@@ -3222,6 +3269,92 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
}
if ($group && $parent) {
logger('comment arrived in group', LOGGER_DEBUG);
$arr = [];
// don't let this recurse. We checked for this before calling, but this ensures
// it doesn't sneak through another way because recursion is nasty.
if ($item['verb'] === 'Announce' && $item['author_xchan'] === $channel['channel_hash']) {
return;
}
// Don't send Announce activities for poll responses.
if ($item['obj_type'] === 'Answer') {
return;
}
if ($edit) {
if (intval($item['item_deleted'])) {
drop_item($item['id'],false,DROPITEM_PHASE1);
Master::Summon([ 'Notifier','drop',$item['id'] ]);
return;
}
return;
}
else {
$arr['uuid'] = item_message_id();
$arr['mid'] = z_root() . '/activity/' . $arr['uuid'];
$arr['parent_mid'] = $item['parent_mid'];
//IConfig::Set($arr,'activitypub','context', str_replace('/item/','/conversation/',$item['parent_mid']));
}
$arr['aid'] = $channel['channel_account_id'];
$arr['uid'] = $channel['channel_id'];
$arr['verb'] = 'Announce';
if (is_array($item['obj'])) {
$arr['obj'] = $item['obj'];
}
elseif (is_string($item['obj']) && strlen($item['obj'])) {
$arr['obj'] = json_decode($item['obj'],true);
}
if (! $arr['obj']) {
$arr['obj'] = $item['mid'];
}
if (is_array($arr['obj'])) {
$obj_actor = ((isset($arr['obj']['actor'])) ? ((is_array($arr['obj']['actor'])) ? $arr['obj']['actor']['id'] : $arr['obj']['actor']) : $arr['obj']['attributedTo']);
$mention = Activity::get_actor_bbmention($obj_actor);
$arr['body'] = sprintf( t('&#x1f501; Repeated %1$s\'s %2$s'), $mention, $arr['obj']['type']);
}
$arr['author_xchan'] = $channel['channel_hash'];
$arr['item_wall'] = 1;
$arr['item_private'] = (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 1 : 0);
$arr['item_origin'] = 1;
$arr['item_hidden'] = 1;
$arr['item_thread_top'] = 0;
$arr['allow_cid'] = $channel['channel_allow_cid'];
$arr['allow_gid'] = $channel['channel_allow_gid'];
$arr['deny_cid'] = $channel['channel_deny_cid'];
$arr['deny_gid'] = $channel['channel_deny_gid'];
$arr['comment_policy'] = map_scope(PermissionLimits::Get($channel['channel_id'],'post_comments'));
$post = item_store($arr);
$post_id = $post['item_id'];
if ($post_id) {
Master::Summon([ 'Notifier','tgroup',$post_id ]);
}
q("update channel set channel_lastpost = '%s' where channel_id = %d",
dbesc(datetime_convert()),
intval($channel['channel_id'])
);
return;
}
// Change this copy of the post to a forum head message and deliver to all the tgroup members
// also reset all the privacy bits to the forum default permissions
@@ -3510,12 +3643,11 @@ function compare_permissions($obj1,$obj2) {
* @return array
*/
function enumerate_permissions($obj) {
require_once('include/group.php');
$allow_people = expand_acl($obj['allow_cid']);
$allow_groups = expand_groups(expand_acl($obj['allow_gid']));
$allow_groups = AccessList::expand(expand_acl($obj['allow_gid']));
$deny_people = expand_acl($obj['deny_cid']);
$deny_groups = expand_groups(expand_acl($obj['deny_gid']));
$deny_groups = AccessList::expand(expand_acl($obj['deny_gid']));
$recipients = array_unique(array_merge($allow_people,$allow_groups));
$deny = array_unique(array_merge($deny_people,$deny_groups));
$recipients = array_diff($recipients,$deny);
@@ -4252,7 +4384,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
$contact_str = '';
$contacts = group_get_members($r[0]['id']);
$contacts = AccessList::members($uid, $r[0]['id']);
if ($contacts) {
foreach($contacts as $c) {
if($contact_str)
@@ -4268,7 +4400,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
$sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str)) or allow_gid like '" . protect_sprintf('%<' . dbesc($r[0]['hash']) . '>%') . "' ) and id = parent $item_normal ) ";
$x = group_rec_byhash($uid,$r[0]['hash']);
$x = AccessList::by_hash($uid, $r[0]['hash']);
$result['headline'] = sprintf( t('Privacy group: %s'),$x['gname']);
}
elseif($arr['cid'] && $uid) {
@@ -4306,7 +4438,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
);
}
if(strlen($arr['file'])) {
if($arr['file']) {
$sql_extra .= term_query('item',$arr['files'],TERM_FILE);
}
@@ -4640,8 +4772,9 @@ function send_profile_photo_activity($channel,$photo,$profile) {
$arr['body'] = sprintf($t,$channel['channel_name'],$ptext) . "\n\n" . $ltext;
$acl = new AccessList($channel);
$acl = new Zotlabs\Access\AccessList($channel);
$x = $acl->get();
$arr['allow_cid'] = $x['allow_cid'];
$arr['allow_gid'] = $x['allow_gid'];

View File

@@ -26,7 +26,7 @@ function nav($template = 'default') {
intval($channel['channel_id'])
);
if (empty($_SESSION['delegate'])) {
if (empty($_SESSION['delegate']) && feature_enabled(local_channel(), 'nav_channel_select')) {
$chans = q("select channel_name, channel_id from channel where channel_account_id = %d and channel_removed = 0 order by channel_name ",
intval(get_account_id())
);
@@ -97,13 +97,11 @@ function nav($template = 'default') {
if (empty($_SESSION['delegate'])) {
$nav['manage'] = ['manage', t('Channels'), "", t('Manage your channels'), 'manage_nav_btn'];
}
if (Apps::system_app_installed(local_channel(), 'Privacy Groups'))
$nav['group'] = ['group', t('Privacy Groups'), "", t('Manage your privacy groups'), 'group_nav_btn'];
$nav['settings'] = ['settings', t('Settings'), "", t('Account/Channel Settings'), 'settings_nav_btn'];
if ($chans && count($chans) > 1 && feature_enabled(local_channel(), 'nav_channel_select'))
if ($chans && count($chans) > 1)
$nav['channels'] = $chans;
$nav['logout'] = ['logout', t('Logout'), "", t('End this session'), 'logout_nav_btn'];

View File

@@ -400,6 +400,18 @@ function z_post_url($url, $params, $redirects = 0, $opts = array()) {
return($ret);
}
function z_curl_error($ret) {
$output = EMPTY_STR;
if (isset($ret['debug'])) {
$output .= datetime_convert() . EOL;
$output .= t('url: ') . $ret['debug']['url'] . EOL;
$output .= t('error_code: ') . $ret['debug']['error_code'] . EOL;
$output .= t('error_string: ') . $ret['error'] . EOL;
$output .= t('content-type: ') . $ret['debug']['content_type'] . EOL;
}
return $output;
}
function json_return_and_die($x, $content_type = 'application/json') {
header("Content-type: $content_type");
echo json_encode($x);

View File

@@ -21,7 +21,7 @@ require_once('include/security.php');
* @param bool $default_ignored (default true)
* if false, lie and pretend the ignored person has permissions you are ignoring (used in channel discovery)
*
* @returns array of all permissions, key is permission name, value is true or false
* @returns array of all permissions, key is permission name, value is 1 or 0
*/
function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ignored = true) {
@@ -61,7 +61,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
// The uid provided doesn't exist. This would be a big fail.
if(! $r) {
$ret[$perm_name] = false;
$ret[$perm_name] = 0;
continue;
}
@@ -70,7 +70,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
if($observer_xchan) {
if($channel_perm & PERMS_AUTHED) {
$ret[$perm_name] = true;
$ret[$perm_name] = 1;
continue;
}
@@ -80,23 +80,6 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
intval($uid),
dbesc($observer_xchan)
);
if(! $x) {
// see if they've got a guest access token; these are treated as connections
$y = atoken_abook($uid,$observer_xchan);
if($y)
$x = array($y);
if(! $x) {
// not in address book and no guest token, see if they've got an xchan
// these *may* have individual (PERMS_SPECIFIC) permissions, but are not connections
$y = q("select xchan_network from xchan where xchan_hash = '%s' limit 1",
dbesc($observer_xchan)
);
if($y) {
$x = array(pseudo_abook($y[0]));
}
}
}
$abook_checked = true;
}
@@ -104,7 +87,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
// If they're blocked - they can't read or write
if(($x) && intval($x[0]['abook_blocked'])) {
$ret[$perm_name] = false;
$ret[$perm_name] = 0;
continue;
}
@@ -115,7 +98,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
if(($x) && ($default_ignored) && in_array($perm_name,$blocked_anon_perms) && intval($x[0]['abook_ignored'])) {
$ret[$perm_name] = false;
$ret[$perm_name] = 0;
continue;
}
}
@@ -123,7 +106,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
// system is blocked to anybody who is not authenticated
if(($check_siteblock) && (! $observer_xchan) && intval(get_config('system', 'block_public'))) {
$ret[$perm_name] = false;
$ret[$perm_name] = 0;
continue;
}
@@ -133,16 +116,16 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
if(($observer_xchan) && ($r[0]['channel_hash'] === $observer_xchan)) {
if($r[0]['channel_moved'] && (in_array($perm_name,$blocked_anon_perms)))
$ret[$perm_name] = false;
$ret[$perm_name] = 0;
else
$ret[$perm_name] = true;
$ret[$perm_name] = 1;
continue;
}
// Anybody at all (that wasn't blocked or ignored). They have permission.
if($channel_perm & PERMS_PUBLIC) {
$ret[$perm_name] = true;
$ret[$perm_name] = 1;
continue;
}
@@ -150,7 +133,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
// out, permission is denied.
if(! $observer_xchan) {
$ret[$perm_name] = false;
$ret[$perm_name] = 0;
continue;
}
@@ -158,7 +141,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
if($channel_perm & PERMS_NETWORK) {
if($x && $x[0]['xchan_network'] === 'zot6') {
$ret[$perm_name] = true;
$ret[$perm_name] = 1;
continue;
}
}
@@ -175,9 +158,9 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
}
if($c)
$ret[$perm_name] = true;
$ret[$perm_name] = 1;
else
$ret[$perm_name] = false;
$ret[$perm_name] = 0;
continue;
}
@@ -186,19 +169,19 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
// handle whether we're allowing any, approved or specific ones
if(! $x) {
$ret[$perm_name] = false;
$ret[$perm_name] = 0;
continue;
}
// They are in your address book, but haven't been approved
if($channel_perm & PERMS_PENDING && (! intval($x[0]['abook_pseudo']))) {
$ret[$perm_name] = true;
$ret[$perm_name] = 1;
continue;
}
if(intval($x[0]['abook_pending'])) {
$ret[$perm_name] = false;
$ret[$perm_name] = 0;
continue;
}
@@ -207,11 +190,11 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
if($channel_perm & PERMS_CONTACTS) {
// it was a fake abook entry, not really a connection
if(array_key_exists('abook_pseudo',$x[0]) && intval($x[0]['abook_pseudo'])) {
$ret[$perm_name] = false;
$ret[$perm_name] = 0;
continue;
}
$ret[$perm_name] = true;
$ret[$perm_name] = 1;
continue;
}
@@ -221,7 +204,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
if($abperms) {
foreach($abperms as $ab) {
if(($ab['cat'] == 'my_perms') && ($ab['k'] == $perm_name)) {
$ret[$perm_name] = (intval($ab['v']) ? true : false);
$ret[$perm_name] = (intval($ab['v']) ? 1 : 0);
break;
}
}
@@ -231,7 +214,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
// No permissions allowed.
$ret[$perm_name] = false;
$ret[$perm_name] = 0;
continue;
}
@@ -309,32 +292,6 @@ function perm_is_allowed($uid, $observer_xchan, $permission, $check_siteblock =
if(($x) && in_array($permission,$blocked_anon_perms) && intval($x[0]['abook_ignored']))
return false;
if(! $x) {
// see if they've got a guest access token
$y = atoken_abook($uid,$observer_xchan);
if($y)
$x = array($y);
if(! $x) {
// not in address book and no guest token, see if they've got an xchan
$y = q("select xchan_network from xchan where xchan_hash = '%s' limit 1",
dbesc($observer_xchan)
);
if($y) {
// This requires an explanation and the effects are subtle.
// The following line creates a fake connection, and this allows
// access tokens to have specific permissions even though they are
// not actual connections.
// The existence of this fake entry must be checked when dealing
// with connection related permissions.
$x = array(pseudo_abook($y[0]));
}
}
}
$abperms = load_abconfig($uid,$observer_xchan,'my_perms');
}

View File

@@ -742,7 +742,9 @@ function get_theme_info($theme){
'credits' => '',
'maintainer' => array(),
'experimental' => false,
'unsupported' => false
'unsupported' => false,
'theme_color' => '',
'background_color' => ''
);
if(file_exists("view/theme/$theme/experimental"))

View File

@@ -89,8 +89,20 @@ function authenticate_success($user_record, $channel = null, $login_initial = fa
}
function atoken_login($atoken) {
if (!$atoken)
if (! $atoken) {
return false;
}
if (App::$cmd === 'channel' && argv(1)) {
$channel = channelx_by_nick(argv(1));
if (perm_is_allowed($channel['channel_id'],$atoken['xchan_hash'],'delegate')) {
$_SESSION['delegate_channel'] = $channel['channel_id'];
$_SESSION['delegate'] = $atoken['xchan_hash'];
$_SESSION['account_id'] = intval($channel['channel_account_id']);
change_channel($channel['channel_id']);
return;
}
}
$_SESSION['authenticated'] = 1;
$_SESSION['visitor_id'] = $atoken['xchan_hash'];
@@ -113,11 +125,11 @@ function atoken_xchan($atoken) {
if ($c) {
return [
'atoken_id' => $atoken['atoken_id'],
'xchan_hash' => substr($c['channel_hash'], 0, 16) . '.' . $atoken['atoken_name'],
'xchan_hash' => substr($c['channel_hash'], 0, 16) . '.' . $atoken['atoken_guid'],
'xchan_name' => $atoken['atoken_name'],
'xchan_addr' => 'guest:' . $atoken['atoken_name'] . '@' . App::get_hostname(),
'xchan_network' => 'unknown',
'xchan_url' => z_root() . '/guest/' . substr($c['channel_hash'], 0, 16) . '.' . $atoken['atoken_name'],
'xchan_network' => 'token',
'xchan_url' => z_root() . '/guest/' . substr($c['channel_hash'], 0, 16) . '.' . $atoken['atoken_guid'],
'xchan_hidden' => 1,
'xchan_photo_mimetype' => 'image/png',
'xchan_photo_l' => z_root() . '/' . get_default_profile_photo(300),
@@ -143,15 +155,25 @@ function atoken_delete($atoken_id) {
if (!$c)
return;
$atoken_xchan = substr($c[0]['channel_hash'], 0, 16) . '.' . $r[0]['atoken_name'];
$atoken_xchan = substr($c[0]['channel_hash'], 0, 16) . '.' . $r[0]['atoken_guid'];
q("delete from atoken where atoken_id = %d",
intval($atoken_id)
);
q("delete from abook where abook_channel = %d and abook_xchan = '%s'",
intval($c[0]['channel_id']),
dbesc($atoken_xchan)
);
q("delete from abconfig where chan = %d and xchan = '%s'",
intval($c[0]['channel_id']),
dbesc($atoken_xchan)
);
q("update xchan set xchan_deleted = 1 where xchan_hash = '%s'",
dbesc($atoken_xchan)
);
}
/**
@@ -198,7 +220,7 @@ function atoken_abook($uid, $xchan_hash) {
if (!$r)
return false;
$x = q("select * from atoken where atoken_uid = %d and atoken_name = '%s'",
$x = q("select * from atoken where atoken_uid = %d and atoken_guid = '%s'",
intval($uid),
dbesc(substr($xchan_hash, 17))
);

View File

@@ -1,7 +1,7 @@
<?php /** @file */
function contact_profile_assign($current) {
function contact_profile_assign($current, $label = '') {
$r = q("SELECT profile_guid, profile_name FROM profile WHERE uid = %d",
intval($_SESSION['uid'])
@@ -13,9 +13,13 @@ function contact_profile_assign($current) {
}
}
if (!$label) {
$label = t('Select a profile to assign to this contact');
}
$select = [
'profile_assign',
t('Profile to assign new connections'),
$label,
$current,
'',
$options
@@ -70,7 +74,7 @@ function gender_selector($current="",$suffix="") {
}
$o .= '</select>';
return $o;
}
}
function gender_selector_min($current="",$suffix="") {
$o = '';
@@ -87,7 +91,7 @@ function gender_selector_min($current="",$suffix="") {
}
$o .= '</select>';
return $o;
}
}
@@ -107,7 +111,7 @@ function sexpref_selector($current="",$suffix="") {
}
$o .= '</select>';
return $o;
}
}
function sexpref_selector_min($current="",$suffix="") {
@@ -125,7 +129,7 @@ function sexpref_selector_min($current="",$suffix="") {
}
$o .= '</select>';
return $o;
}
}
@@ -144,7 +148,7 @@ function marital_selector($current="",$suffix="") {
}
$o .= '</select>';
return $o;
}
}
function marital_selector_min($current="",$suffix="") {
$o = '';
@@ -161,5 +165,5 @@ function marital_selector_min($current="",$suffix="") {
}
$o .= '</select>';
return $o;
}
}

View File

@@ -12,6 +12,7 @@ use Ramsey\Uuid\Exception\UnableToBuildUuidException;
use Zotlabs\Lib\Crypto;
use Zotlabs\Lib\SvgSanitizer;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\AccessList;
require_once("include/bbcode.php");
@@ -416,6 +417,9 @@ function xmlify($str) {
//$buffer = '';
if (!$str)
return EMPTY_STR;
if(is_array($str)) {
// allow to fall through so we ge a PHP error, as the log statement will
@@ -481,6 +485,9 @@ function unxmlify($s) {
return $ret;
*/
if (!$s)
return EMPTY_STR;
if(is_array($s)) {
// allow to fall through so we ge a PHP error, as the log statement will
@@ -585,6 +592,7 @@ function alt_pager($i, $more = '', $less = '') {
'$less' => $less,
'$more' => $more,
'$url' => $url,
'$url_appendix' => ((strpos($url, '?')) ? '&' : '?'),
'$prevpage' => App::$pager['page'] - 1,
'$nextpage' => App::$pager['page'] + 1,
));
@@ -838,7 +846,7 @@ function activity_match($haystack,$needle) {
if($needle) {
foreach($needle as $n) {
if(($haystack === $n) || (strtolower(basename($n)) === strtolower(basename($haystack)))) {
if(($haystack === $n) || (strtolower(basename((string)$n)) === strtolower(basename((string)$haystack)))) {
return true;
}
}
@@ -864,6 +872,7 @@ function get_tags($s) {
// ignore anything in a code or svg block
$s = preg_replace('/\[code(.*?)\](.*?)\[\/code\]/sm','',$s);
$s = preg_replace('/\[svg(.*?)\](.*?)\[\/svg\]/sm','',$s);
$s = preg_replace('/\[toc(.*?)\]/sm','',$s);
// ignore anything in [style= ]
$s = preg_replace('/\[style=(.*?)\]/sm','',$s);
@@ -994,7 +1003,7 @@ function contact_block() {
$is_owner = ((local_channel() && local_channel() == App::$profile['uid']) ? true : false);
$sql_extra = '';
$abook_flags = " and abook_pending = 0 and abook_self = 0 ";
$abook_flags = " and abook_pending = 0 and abook_self = 0 and abook_blocked = 0 and abook_ignored = 0 ";
if(! $is_owner) {
$abook_flags .= " and abook_hidden = 0 ";
@@ -1008,56 +1017,58 @@ function contact_block() {
$abook_flags and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra",
intval(App::$profile['uid'])
);
if(count($r)) {
$total = intval($r[0]['total']);
}
if(! $total) {
$contacts = t('No connections');
$micropro = null;
} else {
return $o;
}
$randfunc = db_getfunc('RAND');
$randfunc = db_getfunc('RAND');
$r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash WHERE abook_channel = %d $abook_flags and abook_archived = 0 and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra ORDER BY $randfunc LIMIT %d",
intval(App::$profile['uid']),
intval($shown)
);
$r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash WHERE abook_channel = %d $abook_flags and abook_archived = 0 and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra ORDER BY $randfunc LIMIT %d",
intval(App::$profile['uid']),
intval($shown)
);
if(count($r)) {
$contacts = t('Connections');
$micropro = [];
foreach($r as $rr) {
if(! $r) {
return $o;
}
// There is no setting to discover if you are bi-directionally connected
// Use the ability to post comments as an indication that this relationship is more
// than wishful thinking; even though soapbox channels and feeds will disable it.
$rr['perminfo']['connpermcount']=0;
$rr['perminfo']['connperms']=t('Accepts').': ';
if(intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_comments'))) {
$rr['perminfo']['connpermcount']++;
$rr['perminfo']['connperms'] .= t('Comments');
}
if(intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','send_stream'))) {
$rr['perminfo']['connpermcount']++;
$rr['perminfo']['connperms'] = ($rr['perminfo']['connperms']) ? $rr['perminfo']['connperms'] . ', ' : $rr['perminfo']['connperms'] ;
$rr['perminfo']['connperms'] .= t('Stream items');
}
if(intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_wall'))) {
$rr['perminfo']['connpermcount']++;
$rr['perminfo']['connperms'] = ($rr['perminfo']['connperms']) ? $rr['perminfo']['connperms'] . ', ' : $rr['perminfo']['connperms'] ;
$rr['perminfo']['connperms'] .= t('Wall posts');
}
$contacts = t('Connections');
$micropro = [];
foreach($r as $rr) {
if ($rr['perminfo']['connpermcount'] == 0) {
$rr['perminfo']['connperms'] .= t('Nothing');
}
if(!$is_owner && $rr['perminfo']['connpermcount'] !== 0)
unset($rr['perminfo']);
$micropro[] = micropro($rr,true,'mpfriend');
}
// There is no setting to discover if you are bi-directionally connected
// Use the ability to post comments as an indication that this relationship is more
// than wishful thinking; even though soapbox channels and feeds will disable it.
$rr['perminfo']['connpermcount']=0;
$rr['perminfo']['connperms']=t('Accepts').': ';
if(intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_comments'))) {
$rr['perminfo']['connpermcount']++;
$rr['perminfo']['connperms'] .= t('Comments');
}
if(intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','send_stream'))) {
$rr['perminfo']['connpermcount']++;
$rr['perminfo']['connperms'] = ($rr['perminfo']['connperms']) ? $rr['perminfo']['connperms'] . ', ' : $rr['perminfo']['connperms'] ;
$rr['perminfo']['connperms'] .= t('Stream items');
}
if(intval(get_abconfig(App::$profile['uid'],$rr['xchan_hash'],'their_perms','post_wall'))) {
$rr['perminfo']['connpermcount']++;
$rr['perminfo']['connperms'] = ($rr['perminfo']['connperms']) ? $rr['perminfo']['connperms'] . ', ' : $rr['perminfo']['connperms'] ;
$rr['perminfo']['connperms'] .= t('Wall posts');
}
if ($rr['perminfo']['connpermcount'] == 0) {
$rr['perminfo']['connperms'] .= t('Nothing');
}
if(!$is_owner && $rr['perminfo']['connpermcount'] !== 0)
unset($rr['perminfo']);
$micropro[] = micropro($rr,true,'mpfriend');
}
$tpl = get_markup_template('contact_block.tpl');
@@ -1487,6 +1498,10 @@ function day_translate($s) {
* @return string
*/
function normalise_link($url) {
if (!$url) {
return EMPTY_STR;
}
$ret = str_replace(array('https:', '//www.'), array('http:', '//'), $url);
return(rtrim($ret, '/'));
@@ -1714,7 +1729,7 @@ function prepare_body(&$item,$attach = false,$opts = false) {
if ($is_photo) {
$object = json_decode($item['obj'],true);
$ptr = null;
if (array_key_exists('url',$object) && is_array($object['url'])) {
if (is_array($object) && array_key_exists('url',$object) && is_array($object['url'])) {
if (array_key_exists(0,$object['url'])) {
foreach ($object['url'] as $link) {
if(array_key_exists('width',$link) && $link['width'] >= 640 && $link['width'] <= 1024) {
@@ -1753,6 +1768,7 @@ function prepare_body(&$item,$attach = false,$opts = false) {
}
}
$poll = (($item['obj_type'] === 'Question' && in_array($item['verb'],[ ACTIVITY_POST, ACTIVITY_UPDATE, ACTIVITY_SHARE ])) ? format_poll($item, $s, $opts) : false);
if ($poll) {
$s = $poll;
@@ -1854,17 +1870,29 @@ function format_poll($item,$s,$opts) {
return EMPTY_STR;
}
$commentable = can_comment_on_post(((local_channel()) ? get_observer_hash() : EMPTY_STR),$item);
$commentable = can_comment_on_post(((local_channel()) ? get_observer_hash() : EMPTY_STR), $item);
//logger('format_poll: ' . print_r($item,true));
$activated = ((local_channel() && local_channel() == $item['uid']) ? true : false);
$output = $s . EOL. EOL;
$activated = ((local_channel() && local_channel() == $item['uid'] && get_observer_hash() !== $item['owner_xchan']) ? true : false);
$output = $s;
if (strpos($item['body'], '[/share]') !== false) {
$output = substr($output, 0, -12);
}
$output .= EOL . EOL;
if ($act['type'] === 'Question') {
if ($activated and $commentable) {
$output .= '<form id="question-form-' . $item['id'] . '" >';
}
if (array_key_exists('anyOf',$act) && is_array($act['anyOf'])) {
$totalResponses = 0;
foreach ($act['anyOf'] as $poll) {
if (array_path_exists('replies/totalItems',$poll)) {
$totalResponses += intval($poll['replies']['totalItems']);
}
}
foreach ($act['anyOf'] as $poll) {
if (array_key_exists('name',$poll) && $poll['name']) {
$text = html2plain(purify_html($poll['name']),256);
@@ -1875,15 +1903,34 @@ function format_poll($item,$s,$opts) {
$total = 0;
}
if ($activated && $commentable) {
$output .= '<input type="checkbox" name="answer[]" value="' . htmlspecialchars($text) . '"> ' . $text . '</input>' . ' (' . $total . ')' . EOL;
//$output .= '<input type="checkbox" name="answer[]" value="' . htmlspecialchars($text) . '"> ' . $text . '</input>' . ' (' . $total . ')' . EOL;
$output .= '<input type="checkbox" name="answer[]" value="' . htmlspecialchars($text) . '">&nbsp;&nbsp;<strong>' . $text . '</strong>' . EOL;
$output .= '<div class="progress bg-secondary bg-opacity-25" style="height: 3px;">';
$output .= '<div class="progress-bar bg-info" role="progressbar" style="width: ' . (($totalResponses) ? intval($total / $totalResponses * 100) : 0). '%;" aria-valuenow="" aria-valuemin="0" aria-valuemax="100"></div>';
$output .= '</div>';
$output .= '<div class="text-muted"><small>' . sprintf(tt('%d Vote', '%d Votes', $total, 'noun'), $total) . '&nbsp;|&nbsp;' . (($totalResponses) ? intval($total / $totalResponses * 100) . '%' : '0%') . '</small></div>';
$output .= EOL;
}
else {
$output .= '[ ] ' . $text . ' (' . $total . ')' . EOL;
//$output .= '[ ] ' . $text . ' (' . $total . ')' . EOL;
$output .= '<input type="checkbox" name="answer[]" value="' . htmlspecialchars($text) . '" disabled="disabled">&nbsp;&nbsp;<strong>' . $text . '</strong>' . EOL;
$output .= '<div class="progress bg-secondary bg-opacity-25" style="height: 3px;">';
$output .= '<div class="progress-bar bg-info" role="progressbar" style="width: ' . (($totalResponses) ? intval($total / $totalResponses * 100) : 0) . '%;" aria-valuenow="" aria-valuemin="0" aria-valuemax="100"></div>';
$output .= '</div>';
$output .= '<div class="text-muted"><small>' . sprintf(tt('%d Vote', '%d Votes', $total, 'noun'), $total) . '&nbsp;|&nbsp;' . (($totalResponses) ? intval($total / $totalResponses * 100) . '%' : '0%') . '</small></div>';
$output .= EOL;
}
}
}
}
if (array_key_exists('oneOf',$act) && is_array($act['oneOf'])) {
$totalResponses = 0;
foreach ($act['oneOf'] as $poll) {
if (array_path_exists('replies/totalItems',$poll)) {
$totalResponses += intval($poll['replies']['totalItems']);
}
}
foreach ($act['oneOf'] as $poll) {
if (array_key_exists('name',$poll) && $poll['name']) {
$text = html2plain(purify_html($poll['name']),256);
@@ -1894,29 +1941,48 @@ function format_poll($item,$s,$opts) {
$total = 0;
}
if ($activated && $commentable) {
$output .= '<input type="radio" name="answer" value="' . htmlspecialchars($text) . '"> ' . $text . '</input>' . ' (' . $total . ')' . EOL;
$output .= '<input type="radio" name="answer" value="' . htmlspecialchars($text) . '">&nbsp;&nbsp;<strong>' . $text . '</strong>' . EOL;
$output .= '<div class="progress bg-secondary bg-opacity-25" style="height: 3px;">';
$output .= '<div class="progress-bar bg-info" role="progressbar" style="width: ' . (($totalResponses) ? intval($total / $totalResponses * 100) : 0). '%;" aria-valuenow="" aria-valuemin="0" aria-valuemax="100"></div>';
$output .= '</div>';
$output .= '<div class="text-muted"><small>' . sprintf(tt('%d Vote', '%d Votes', $total, 'noun'), $total) . '&nbsp;|&nbsp;' . (($totalResponses) ? intval($total / $totalResponses * 100) . '%' : '0%') . '</small></div>';
$output .= EOL;
}
else {
$output .= '( ) ' . $text . ' (' . $total . ')' . EOL;
$output .= '<input type="radio" name="answer" value="' . htmlspecialchars($text) . '" disabled="disabled">&nbsp;&nbsp;<strong>' . $text . '</strong>' . EOL;
$output .= '<div class="progress bg-secondary bg-opacity-25" style="height: 3px;">';
$output .= '<div class="progress-bar bg-info" role="progressbar" style="width: ' . (($totalResponses) ? intval($total / $totalResponses * 100) : 0) . '%;" aria-valuenow="" aria-valuemin="0" aria-valuemax="100"></div>';
$output .= '</div>';
$output .= '<div class="text-muted"><small>' . sprintf(tt('%d Vote', '%d Votes', $total, 'noun'), $total) . '&nbsp;|&nbsp;' . (($totalResponses) ? intval($total / $totalResponses * 100) . '%' : '0%') . '</small></div>';
$output .= EOL;
}
}
}
}
$message = (($totalResponses) ? sprintf(tt('%d Vote in total', '%d Votes in total', $totalResponses, 'noun'), $totalResponses) . EOL : '');
if ($item['comments_closed'] > NULL_DATE) {
$t = datetime_convert('UTC',date_default_timezone_get(), $item['comments_closed'], 'Y-m-d H:i');
$closed = ((datetime_convert() > $item['comments_closed']) ? true : false);
if ($closed) {
$message = t('Poll has ended.');
$message .= t('Poll has ended');
}
else {
$message = sprintf(t('Poll ends: %s'),$t);
$message .= sprintf(t('Poll ends in %s'), '<span class="autotime" title="' . $t . '"></span>');
}
$output .= EOL . '<div>' . $message . '</div>';
}
if ($activated and $commentable) {
$output .= EOL . '<input type="button" class="btn btn-std btn-success" name="vote" value="' . t("Vote") . '" onclick="submitPoll(' . $item['id'] . '); return false;">'. '</form>';
}
$output .= '<div class="mb-3">' . $message . '</div>';
if ($activated && $commentable && !$closed) {
$output .= '<input type="button" class="btn btn-std btn-success" name="vote" value="' . t("Vote") . '" onclick="submitPoll(' . $item['id'] . '); return false;">'. '</form>';
}
if (strpos($item['body'], '[/share]') !== false) {
$output .= '</div></div>';
}
}
return $output;
}
@@ -2534,7 +2600,7 @@ function xchan_query(&$items, $abook = true, $effective_uid = 0) {
$chans = q("select xchan.*,hubloc.* from xchan left join hubloc on hubloc_hash = xchan_hash
where xchan_hash in (" . protect_sprintf(implode(',', $arr)) . ") and hubloc_primary = 1");
}
$xchans = q("select * from xchan where xchan_hash in (" . protect_sprintf(implode(',',$arr)) . ") and xchan_network in ('rss','unknown', 'anon')");
$xchans = q("select * from xchan where xchan_hash in (" . protect_sprintf(implode(',',$arr)) . ") and xchan_network in ('rss','unknown', 'anon', 'token')");
if(! $chans)
$chans = $xchans;
else
@@ -2989,7 +3055,7 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true)
// weird - as all the other tags are linked to something.
if(local_channel() && local_channel() == $profile_uid) {
$grp = group_byname($profile_uid,$name);
$grp = AccessList::by_name($profile_uid,$name);
if($grp) {
$g = q("select hash from pgrp where id = %d and visible = 1 limit 1",
@@ -3532,6 +3598,45 @@ function create_table_from_array($table, $arr, $binary_fields = []) {
return $r;
}
function update_table_from_array($table, $arr, $where, $binary_fields = []) {
if (! ($arr && $table)) {
return false;
}
$columns = db_columns($table);
$clean = [];
foreach ($arr as $k => $v) {
if (! in_array($k, $columns)) {
continue;
}
$matches = false;
if (preg_match('/([^a-zA-Z0-9\-\_\.])/', $k, $matches)) {
return false;
}
if (in_array($k, $binary_fields)) {
$clean[$k] = dbescbin($v);
} else {
$clean[$k] = dbesc($v);
}
}
$sql = "UPDATE " . TQUOT . $table . TQUOT . " SET ";
foreach ($clean as $k => $v) {
$sql .= TQUOT . $k . TQUOT . ' = "' . $v . '",';
}
$sql = rtrim($sql,',');
$r = dbq($sql . " WHERE " . $where);
return $r;
}
function share_shield($m) {
return str_replace($m[1],'!=+=+=!' . base64url_encode($m[1]) . '=+!=+!=',$m[0]);
}
@@ -3692,6 +3797,13 @@ function get_forum_channels($uid) {
if(! $uid)
return;
$r = q("select abook_id, xchan_pubforum, xchan_hash, xchan_network, xchan_name, xchan_url, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash where xchan_deleted = 0 and abook_channel = %d and abook_pending = 0 and abook_ignored = 0 and abook_blocked = 0 and abook_archived = 0 and abook_self = 0 and xchan_pubforum = 1 order by xchan_name",
intval($uid)
);
/*
if(isset(App::$data['forum_channels']))
return App::$data['forum_channels'];
@@ -3763,6 +3875,7 @@ function get_forum_channels($uid) {
}
App::$data['forum_channels'] = $r;
*/
return $r;
@@ -3828,6 +3941,26 @@ function array_path_exists($str,$arr) {
}
/**
* @brief provide psuedo random token (string) consisting entirely of US-ASCII letters/numbers
* and with possibly variable length
*
* @return string
*/
function new_token($minlen = 36, $maxlen = 48) {
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
$str = EMPTY_STR;
$len = (($minlen === $maxlen) ? $minlen : mt_rand($minlen, $maxlen));
for ($a = 0; $a < $len; $a++) {
$str .= $chars[mt_rand(0, 62)];
}
return $str;
}
/**
* @brief Generate a random v4 UUID.
*

View File

@@ -37,7 +37,7 @@ function is_matrix_url($url) {
* @return string
*/
function zid($s, $address = '') {
if (! strlen($s) || strpos($s,'zid='))
if (!$s || strpos($s,'zid='))
return $s;
$m = parse_url($s);

View File

@@ -37,6 +37,7 @@ CREATE TABLE IF NOT EXISTS `abook` (
`abook_incl` text NOT NULL,
`abook_excl` text NOT NULL,
`abook_instance` text NOT NULL,
`abook_role` char(191) NOT NULL DEFAULT '',
PRIMARY KEY (`abook_id`),
KEY `abook_account` (`abook_account`),
KEY `abook_channel` (`abook_channel`),
@@ -58,7 +59,8 @@ CREATE TABLE IF NOT EXISTS `abook` (
KEY `abook_unconnected` (`abook_unconnected`),
KEY `abook_self` (`abook_self`),
KEY `abook_not_here` (`abook_not_here`),
KEY `abook_feed` (`abook_feed`)
KEY `abook_feed` (`abook_feed`),
KEY `abook_role` (`abook_role`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `account` (
@@ -146,12 +148,14 @@ CREATE TABLE IF NOT EXISTS `app` (
CREATE TABLE IF NOT EXISTS `atoken` (
`atoken_id` int(11) NOT NULL AUTO_INCREMENT,
`atoken_guid` char(191) NOT NULL DEFAULT '',
`atoken_aid` int(11) NOT NULL DEFAULT 0 ,
`atoken_uid` int(11) NOT NULL DEFAULT 0 ,
`atoken_name` char(191) NOT NULL DEFAULT '',
`atoken_token` char(191) NOT NULL DEFAULT '',
`atoken_expires` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
PRIMARY KEY (`atoken_id`),
KEY `atoken_guid` (`atoken_guid`),
KEY `atoken_aid` (`atoken_aid`),
KEY `atoken_uid` (`atoken_uid`),
KEY `atoken_uid_2` (`atoken_uid`),

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