Merge branch 'origin' into 'master'
marge from origin 4.0 See merge request harukin/core!42
This commit is contained in:
commit
23fc7e65d4
116
.gitlab-ci.yml
116
.gitlab-ci.yml
@ -1,36 +1,126 @@
|
||||
# Select image from https://hub.docker.com/_/php/
|
||||
image: php:7.1
|
||||
#image: php:7.2
|
||||
# Use a prepared Hubzilla image to optimise pipeline run
|
||||
image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.2
|
||||
|
||||
|
||||
stages:
|
||||
- test
|
||||
- deploy
|
||||
|
||||
|
||||
# Select what we should cache
|
||||
cache:
|
||||
paths:
|
||||
- vendor/
|
||||
- .cache/
|
||||
|
||||
|
||||
# global variables for all jobs, if no job specific variables
|
||||
variables:
|
||||
# Configure mysql service (https://hub.docker.com/_/mysql/)
|
||||
# Tell composer to use the project workspace .cache folder
|
||||
COMPOSER_CACHE_DIR: "$CI_PROJECT_DIR/.cache/composer"
|
||||
# Ignore a Composer warning
|
||||
COMPOSER_ALLOW_SUPERUSER: 1
|
||||
# Configure MySQL/MariaDB service (https://hub.docker.com/_/mysql/, https://hub.docker.com/_/mariadb/)
|
||||
MYSQL_DATABASE: hello_world_test
|
||||
MYSQL_ROOT_PASSWORD: mysql
|
||||
# Configure PostgreSQL service (https://hub.docker.com/_/postgres/)
|
||||
POSTGRES_DB: ci-db
|
||||
POSTGRES_USER: ci-user
|
||||
POSTGRES_PASSWORD: ci-pass
|
||||
|
||||
|
||||
services:
|
||||
- mysql:5.7
|
||||
|
||||
before_script:
|
||||
- apt-get update -yqq
|
||||
- apt-get install -yqq git mysql-server mysql-client libmcrypt-dev libpq-dev libcurl4-gnutls-dev libicu-dev libvpx-dev libjpeg-dev libpng-dev libxpm-dev zlib1g-dev libfreetype6-dev libxml2-dev libexpat1-dev libbz2-dev libgmp3-dev libldap2-dev unixodbc-dev libsqlite3-dev libaspell-dev libsnmp-dev libpcre3-dev libtidy-dev
|
||||
# Install PHP extensions
|
||||
- docker-php-ext-install mbstring mcrypt pdo_mysql pdo_pgsql curl json intl gd xml zip bz2 opcache
|
||||
# Install & enable Xdebug for code coverage reports
|
||||
- pecl install xdebug
|
||||
- docker-php-ext-enable xdebug
|
||||
# Install and run Composer
|
||||
# Install composer
|
||||
- curl -sS https://getcomposer.org/installer | php
|
||||
- php composer.phar install
|
||||
# Install dev libraries from composer
|
||||
- php composer.phar install --no-progress
|
||||
|
||||
# We test PHP7 with MySQL, but we allow it to fail
|
||||
test:php:mysql:
|
||||
|
||||
# test PHP7 with MySQL 5.7
|
||||
php7.2_mysql 1/2:
|
||||
stage: test
|
||||
services:
|
||||
- mysql:5.7
|
||||
script:
|
||||
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
|
||||
|
||||
|
||||
# test PHP7 with MySQL latest (8)
|
||||
php7.2_mysql 2/2:
|
||||
stage: test
|
||||
services:
|
||||
- name: mysql:latest
|
||||
command: ["--default-authentication-plugin=mysql_native_password"]
|
||||
script:
|
||||
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
|
||||
|
||||
|
||||
# test PHP7 with MariaDB latest (10.3)
|
||||
php7.2_mariadb:
|
||||
stage: test
|
||||
services:
|
||||
- name: mariadb:latest
|
||||
alias: mysql
|
||||
script:
|
||||
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
|
||||
- vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
|
||||
|
||||
|
||||
# test PHP7 with PostgreSQL latest
|
||||
php7.2_postgres:
|
||||
stage: test
|
||||
services:
|
||||
- postgres:latest
|
||||
script:
|
||||
- export PGPASSWORD=$POSTGRES_PASSWORD
|
||||
- psql --version
|
||||
- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT VERSION();"
|
||||
# Import hubzilla's DB schema
|
||||
- psql -h "postgres" -U "$POSTGRES_USER" -v ON_ERROR_STOP=1 --quiet "$POSTGRES_DB" < ./install/schema_postgres.sql
|
||||
# Show databases and relations/tables of hubzilla's database
|
||||
#- psql -h "postgres" -U "$POSTGRES_USER" -l
|
||||
#- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\dt;"
|
||||
# Run the actual tests
|
||||
- vendor/bin/phpunit --configuration tests/phpunit-pgsql.xml --testdox
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
# Gitlab should show the results, but has problems parsing PHPUnit's junit file.
|
||||
reports:
|
||||
junit: tests/results/junit.xml
|
||||
# Archive test results (coverage, testdox, junit)
|
||||
name: "$CI_COMMIT_REF_SLUG-$CI_JOB_NAME"
|
||||
paths:
|
||||
- tests/results/
|
||||
|
||||
|
||||
# Generate Doxygen API Documentation and deploy it at GitLab pages
|
||||
pages:
|
||||
stage: deploy
|
||||
cache: {}
|
||||
image: php:7-cli-alpine
|
||||
before_script:
|
||||
- apk update
|
||||
- apk add doxygen ttf-freefont graphviz
|
||||
script:
|
||||
- doxygen util/Doxyfile
|
||||
- mv doc/html/ public/
|
||||
- echo "API documentation should be accessible at https://hubzilla.frama.io/core/ soon"
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
only:
|
||||
# Only generate it on main repo's master branch
|
||||
- master@hubzilla/core
|
||||
|
@ -5,8 +5,8 @@ Run hubzilla-setup.sh for an unattended installation of hubzilla.
|
||||
The script is known to work without adjustments with
|
||||
|
||||
+ Hardware
|
||||
- Mini-PC with Debian-9.2-amd64, or
|
||||
- Rapberry 3 with Raspbian, Debian-9.3
|
||||
- Mini-PC with Debian-9.5-amd64, or
|
||||
- Rapberry 3 with Raspbian, Debian-9.5
|
||||
+ DynDNS
|
||||
- selfHOST.de
|
||||
- freedns.afraid.org
|
||||
@ -38,7 +38,7 @@ Software
|
||||
- apt-get install git
|
||||
- mkdir -p /var/www
|
||||
- cd /var/www
|
||||
- git clone https://github.com/redmatrix/hubzilla.git html
|
||||
- git clone https://framagit.org/hubzilla/core.git html
|
||||
- cd html/.homeinstall
|
||||
- cp hubzilla-config.txt.template hubzilla-config.txt
|
||||
- nano hubzilla-config.txt
|
||||
@ -100,7 +100,7 @@ Create bootable USB drive with Debian on it.You could use
|
||||
Example for command dd...
|
||||
|
||||
su -
|
||||
dd if=2017-11-29-raspbian-stretch.img of=/dev/mmcblk0
|
||||
dd if=2018-10-09-raspbian-stretch.img of=/dev/mmcblk0
|
||||
|
||||
Do not forget to unmount the SD card before and check if unmounted like in this example...
|
||||
|
||||
@ -164,7 +164,7 @@ Make the directory for apache and change diretory to it
|
||||
|
||||
Clone hubzilla from git ("git pull" will update it later)
|
||||
|
||||
git clone https://framagit.org/hubzilla/core html
|
||||
git clone https://framagit.org/hubzilla/core.git html
|
||||
|
||||
Change to the install script
|
||||
|
||||
@ -217,14 +217,20 @@ After the daily script was executed at 05:30 (am)
|
||||
- optionally view the daily log under yourdomain.org/admin/logs/
|
||||
- set the logfile to var/www/html/hubzilla-daily.log
|
||||
|
||||
|
||||
## Install Hubzilla in a Virtual Machine for Test Purposes
|
||||
|
||||
Modify the file "hubzilla-config.txt".
|
||||
|
||||
nano hubzilla-config.txt
|
||||
|
||||
There use
|
||||
|
||||
le_domain=localhost
|
||||
|
||||
## Note for the Rasperry
|
||||
|
||||
The script was tested with an Raspberry 3 under Raspian (Debian 9.3, 2017-11-29-raspbian-stretch.img).
|
||||
|
||||
It is recommended to deinstall these programms to avoid endless updates. Use...
|
||||
|
||||
sudo apt-get purge wolfram-engine sonic-pi
|
||||
sudo apt-get autoremove
|
||||
The script was tested with an Raspberry 3 under Raspian (Debian 9.5, 2018-10-09-raspbian-stretch.img).
|
||||
|
||||
It is recommended to run the Raspi without graphical frontend (X-Server). Use...
|
||||
|
||||
@ -234,7 +240,7 @@ to boot the Rapsi to the client console.
|
||||
|
||||
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
|
||||
|
||||
On a Raspian Stretch (Debian 9) the validation of the mail address fails for the very first user.
|
||||
If the validation of the mail address fails for the very first registered user...
|
||||
This used to happen on some *bsd distros but there was some work to fix that a year ago (2017).
|
||||
|
||||
So if your system isn't registered in DNS or DNS isn't active do
|
||||
|
@ -18,6 +18,8 @@ db_pass=
|
||||
# Example: my.cooldomain.org
|
||||
# Example: cooldomain.org
|
||||
#
|
||||
# Example: localhost (test installation without certificates for httpS)
|
||||
#
|
||||
# Email is optional
|
||||
#
|
||||
#
|
||||
|
@ -816,15 +816,35 @@ install_run_selfhost
|
||||
ping_domain
|
||||
configure_cron_freedns
|
||||
configure_cron_selfhost
|
||||
install_letsencrypt
|
||||
configure_apache_for_https
|
||||
check_https
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
install_letsencrypt
|
||||
configure_apache_for_https
|
||||
check_https
|
||||
else
|
||||
print_info "is localhost - skipped installation of letsencrypt and configuration of apache for https"
|
||||
fi
|
||||
|
||||
install_hubzilla
|
||||
rewrite_to_https
|
||||
install_rsnapshot
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
rewrite_to_https
|
||||
install_rsnapshot
|
||||
else
|
||||
print_info "is localhost - skipped rewrite to https and installation of rsnapshot"
|
||||
fi
|
||||
|
||||
configure_cron_daily
|
||||
install_cryptosetup
|
||||
write_uninstall_script
|
||||
|
||||
if [ "$le_domain" != "localhost" ]
|
||||
then
|
||||
install_cryptosetup
|
||||
write_uninstall_script
|
||||
else
|
||||
print_info "is localhost - skipped installation of cryptosetup"
|
||||
fi
|
||||
|
||||
#set +x # stop debugging from here
|
||||
|
||||
|
115
CHANGELOG
115
CHANGELOG
@ -1,3 +1,118 @@
|
||||
Hubzilla 4.0 (2019-03-08)
|
||||
- Add CURLOPT_CONNECTTIMEOUT option
|
||||
- Allow parameters as final path argument in API router
|
||||
- Remove clones from delivery recipients for top-level posts in favor of clone sync
|
||||
- Mention php-zip module dependency in administrator guide
|
||||
- Iron out some kinks with scrollToItem() in combination with collapsed content and images
|
||||
- Zot API changes to support combined content (items+files) import addon
|
||||
- Update PHP Version check during setup - min version is now 7.1
|
||||
- Urlencode links in category widget
|
||||
- Implement ability for channel visitors to be able to delete their own content
|
||||
- Support zot location independent urls
|
||||
- MySQL 8 admin summary compatibility
|
||||
- Improved gitlab-ci environment
|
||||
- Deprecate and remove addon settings in favour of per app settings
|
||||
- Refactor PhotoDriver class and add tests
|
||||
- Convert affinity tool to app
|
||||
- Refactor linkify_tags() so it works with xchans across multiple protocols
|
||||
- Add the actual mid to viewsrc for debuging reasons
|
||||
- Add filter hooks and the ability to add buttons to the default status editor
|
||||
- Prevent Hubzilla usage for SEO backlinks
|
||||
- Implement privacy warning for forum posts via !-tag
|
||||
- Set document title when title changes on a page update
|
||||
- Cache embeds in the background on initial storage rather than on first access
|
||||
- Custom sessionhandler support
|
||||
- Update nginx and lighttpd sample server configs to explicit disallow access to util
|
||||
- Introduce command line tool for managing site admins
|
||||
- Various doxygen improvements
|
||||
- Add privacygroup_extras_post/drop hooks
|
||||
- Add collect_public_recipients hook
|
||||
- Prevent memory exhaustion on zot message pickup with large message queue
|
||||
- Remove experimental worker queue from core
|
||||
- Add get_base_apps hook
|
||||
- Improve handling of notification updates while commenting
|
||||
- Add warning if upload_filesize < 4MB
|
||||
- Add ITEM_TYPE_CUSTOM and hooks for processing custom item types
|
||||
- Set min/maxversion for plugins to STD_VERSION unless otherwise specified
|
||||
- Add option to make affinity slider 'sticky' across page loads
|
||||
- Add photo_view_filter hook
|
||||
- Reset page title if article has no title
|
||||
- Implement the zot6 protocol
|
||||
- Add PHOTO_CACHE photo type
|
||||
- Basic support for HTTP3
|
||||
- Add native summary support
|
||||
- Disable image caching if personal or group permissions enabled
|
||||
|
||||
Bugfixes
|
||||
- Fix guest access token xchan record not created on URL login
|
||||
- Fix regression where mod oep was still using hex2bin/bin2hex instead of album hash
|
||||
- Fix regression when selecting multiple images in embed images
|
||||
- Fix broken sync_an_item()
|
||||
- Fix page jumping on like if comments are expanded (show all x comments)
|
||||
- Fix regression in mod display where an page update could display items from multiple channels
|
||||
- Fix starring and filing allowed for other unsupported item types
|
||||
- Fix wrong variable in z_get_temp_dir()
|
||||
- Fix page jumping when liking a collapsed/expanded post
|
||||
- Fix tags detection in URL
|
||||
- Fix warnings in mod embedphotos
|
||||
- Fix wrong variable in can_comment_on_post()
|
||||
- Fix mod new_channel counting removed channels
|
||||
- Fix regression where not all content variables were sslified
|
||||
- Fix default values for affinity tool and other information which could be lost when approving a connection
|
||||
- Fix regression in linkdropper()
|
||||
- Fix issue with unset auto_save_draft variable which resultet in a javascript error
|
||||
- Fix home notifications won't expand if there are more than 300 unseen network notifications ahead of them
|
||||
- Fix total_identities count
|
||||
- Fix delayed items propagate before publication on cloned channels
|
||||
|
||||
Addons
|
||||
- twitter_api: fedilab needs profile_image_url_https
|
||||
- New addon: content_import - imports items and files to cloned channels (this obsoletes hzfiles)
|
||||
- Diaspora: prevent processing of incomplete messages in various places
|
||||
- hzfiles: fix add missing load/unload functions
|
||||
- chess: do not look for games if we have no game_id - improves initial pageload performance
|
||||
- chess: convert to app
|
||||
- channelreputation: convert to app
|
||||
- irc: convert to per app
|
||||
- Provide the addon_common directory for common addon libraries
|
||||
- fuzzloc: convert to app
|
||||
- flattrwidget: convert to app
|
||||
- jappixmini: convert to app
|
||||
- xmpp: convert to app
|
||||
- visage: convert to app
|
||||
- diaspora: reflect linkify_tags() rewrite
|
||||
- twitter: convert to app
|
||||
- smileybutton: convert to app
|
||||
- skeleton: convert to app
|
||||
- planets: convert to app
|
||||
- pumpio: convert to app
|
||||
- pageheader: convert to app
|
||||
- nsabait: convert to app
|
||||
- dwpost: convert to app
|
||||
- diaspora: set the preserve_lf option in various places
|
||||
- diaspora: fix comments from unknown persons are not accpted
|
||||
- nofed: convert to app
|
||||
- ljpost: convert to app
|
||||
- diaspora: call update_queue_item() if delivery failed
|
||||
- pubcrawl: call update_queue_item() if delivery failed
|
||||
- libertree: convert to app
|
||||
- New addon: queueworker advanced - queue handling (experimental)
|
||||
- gallery: extended functionality: implements stream image viewer, converts images at the beginning of a post to a gallery
|
||||
- authchoose: correction to query, add affinity setting
|
||||
- New addon: photocache - local caching for public photos
|
||||
- New addon: totp - two factor authentication using time-based one-time passwords
|
||||
|
||||
|
||||
Hubzilla 3.8.9 (2018-02-03)
|
||||
- Fix typos in mod oep
|
||||
- Fix page jumping when liking collapsed/expanded post
|
||||
- Fix failure to import mail in mod import
|
||||
- Fix wrong channel count in mod new_channel
|
||||
- Fix diaspora addon regression
|
||||
- Remove deprecated diaspora addon endpoint
|
||||
- Fix wrong function call in gallery addon
|
||||
|
||||
|
||||
Hubzilla 3.8.8 (2018-12-22)
|
||||
- Fix issue with linkinfo
|
||||
- Fix cURL with HTTP/2
|
||||
|
27
Zotlabs/Daemon/Cache_embeds.php
Normal file
27
Zotlabs/Daemon/Cache_embeds.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php /** @file */
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
|
||||
class Cache_embeds {
|
||||
|
||||
static public function run($argc,$argv) {
|
||||
|
||||
if(! $argc == 2)
|
||||
return;
|
||||
|
||||
$c = q("select body from item where id = %d ",
|
||||
dbesc(intval($argv[1]))
|
||||
);
|
||||
|
||||
if(! $c)
|
||||
return;
|
||||
|
||||
$item = $c[0];
|
||||
|
||||
// bbcode conversion by default processes embeds that aren't already cached.
|
||||
// Ignore the returned html output.
|
||||
|
||||
bbcode($item['body']);
|
||||
}
|
||||
}
|
@ -95,6 +95,29 @@ class Cron {
|
||||
}
|
||||
}
|
||||
|
||||
// Clean expired photos from cache
|
||||
|
||||
$age = get_config('system','active_expire_days', '30');
|
||||
$r = q("SELECT DISTINCT xchan, content FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
||||
intval(PHOTO_CACHE),
|
||||
db_utcnow(),
|
||||
db_quoteinterval($age . ' DAY')
|
||||
);
|
||||
if($r) {
|
||||
foreach($r as $rr) {
|
||||
$file = dbunescbin($rr['content']);
|
||||
if(is_file($file)) {
|
||||
@unlink($file);
|
||||
logger('info: deleted cached photo file ' . $file, LOGGER_DEBUG);
|
||||
}
|
||||
}
|
||||
}
|
||||
q("DELETE FROM photo WHERE photo_usage = %d AND expires < %s - INTERVAL %s",
|
||||
intval(PHOTO_CACHE),
|
||||
db_utcnow(),
|
||||
db_quoteinterval($age . ' DAY')
|
||||
);
|
||||
|
||||
// publish any applicable items that were set to be published in the future
|
||||
// (time travel posts). Restrict to items that have come of age in the last
|
||||
// couple of days to limit the query to something reasonable.
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\DReport;
|
||||
|
||||
require_once('include/zot.php');
|
||||
require_once('include/queue_fn.php');
|
||||
|
||||
@ -58,11 +60,12 @@ class Deliver {
|
||||
|
||||
foreach($dresult as $xx) {
|
||||
if(is_array($xx) && array_key_exists('message_id',$xx)) {
|
||||
if(delivery_report_is_storable($xx)) {
|
||||
q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s','%s','%s','%s','%s' ) ",
|
||||
if(DReport::is_storable($xx)) {
|
||||
q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
|
||||
dbesc($xx['message_id']),
|
||||
dbesc($xx['location']),
|
||||
dbesc($xx['recipient']),
|
||||
dbesc(($xx['name']) ? $xx['name'] : EMPTY_STR),
|
||||
dbesc($xx['status']),
|
||||
dbesc(datetime_convert($xx['date'])),
|
||||
dbesc($xx['sender'])
|
||||
|
@ -16,8 +16,6 @@ if(array_search( __file__ , get_included_files()) === 0) {
|
||||
|
||||
class Master {
|
||||
|
||||
static public $queueworker = null;
|
||||
|
||||
static public function Summon($arr) {
|
||||
proc_run('php','Zotlabs/Daemon/Master.php',$arr);
|
||||
}
|
||||
@ -25,126 +23,21 @@ class Master {
|
||||
static public function Release($argc,$argv) {
|
||||
cli_startup();
|
||||
|
||||
$maxworkers = get_config('system','max_queue_workers');
|
||||
$hookinfo = [
|
||||
'argv'=>$argv
|
||||
];
|
||||
|
||||
if (!$maxworkers || $maxworkers == 0) {
|
||||
logger('Master: release: ' . print_r($argv,true), LOGGER_ALL,LOG_DEBUG);
|
||||
$cls = '\\Zotlabs\\Daemon\\' . $argv[0];
|
||||
$cls::run($argc,$argv);
|
||||
self::ClearQueue();
|
||||
} else {
|
||||
logger('Master: enqueue: ' . print_r($argv,true), LOGGER_ALL,LOG_DEBUG);
|
||||
$workinfo = ['argc'=>$argc,'argv'=>$argv];
|
||||
q("insert into config (cat,k,v) values ('queuework','%s','%s')",
|
||||
dbesc(uniqid('workitem:',true)),
|
||||
dbesc(serialize($workinfo)));
|
||||
self::Process();
|
||||
}
|
||||
call_hooks ('daemon_master_release',$hookinfo);
|
||||
|
||||
$argv = $hookinfo['argv'];
|
||||
$argc = count($argv);
|
||||
|
||||
if ((!is_array($argv) || (count($argv) < 1))) {
|
||||
return;
|
||||
}
|
||||
|
||||
static public function GetWorkerID() {
|
||||
$maxworkers = get_config('system','max_queue_workers');
|
||||
$maxworkers = ($maxworkers) ? $maxworkers : 3;
|
||||
|
||||
$workermaxage = get_config('system','max_queue_worker_age');
|
||||
$workermaxage = ($workermaxage) ? $workermaxage : 300;
|
||||
|
||||
$workers = q("select * from config where cat='queueworkers' and k like '%s'", 'workerstarted_%');
|
||||
|
||||
if (count($workers) > $maxworkers) {
|
||||
foreach ($workers as $idx => $worker) {
|
||||
$curtime = time();
|
||||
$age = (intval($curtime) - intval($worker['v']));
|
||||
if ( $age > $workermaxage) {
|
||||
logger("Prune worker: ".$worker['k'], LOGGER_ALL, LOGGER_DEBUG);
|
||||
$k = explode('_',$worker['k']);
|
||||
q("delete from config where cat='queueworkers' and k='%s'",
|
||||
'workerstarted_'.$k[1]);
|
||||
q("update config set k='%s' where cat='queuework' and k='%s'",
|
||||
dbesc(uniqid('workitem:',true)),
|
||||
'workitem_'.$k[1]);
|
||||
unset($workers[$idx]);
|
||||
}
|
||||
}
|
||||
if (count($workers) > $maxworkers) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return uniqid('',true);
|
||||
|
||||
}
|
||||
|
||||
static public function Process() {
|
||||
|
||||
self::$queueworker = self::GetWorkerID();
|
||||
|
||||
if (!self::$queueworker) {
|
||||
logger('Master: unable to obtain worker ID.');
|
||||
killme();
|
||||
}
|
||||
|
||||
set_config('queueworkers','workerstarted_'.self::$queueworker,time());
|
||||
|
||||
$workersleep = get_config('system','queue_worker_sleep');
|
||||
$workersleep = ($workersleep) ? $workersleep : 5;
|
||||
cli_startup();
|
||||
|
||||
$work = q("update config set k='%s' where cat='queuework' and k like '%s' limit 1",
|
||||
'workitem_'.self::$queueworker,
|
||||
dbesc('workitem:%'));
|
||||
$jobs = 0;
|
||||
while ($work) {
|
||||
$workitem = q("select * from config where cat='queuework' and k='%s'",
|
||||
'workitem_'.self::$queueworker);
|
||||
|
||||
if (isset($workitem[0])) {
|
||||
$jobs++;
|
||||
$workinfo = unserialize($workitem[0]['v']);
|
||||
$argc = $workinfo['argc'];
|
||||
$argv = $workinfo['argv'];
|
||||
logger('Master: process: ' . print_r($argv,true), LOGGER_ALL,LOG_DEBUG);
|
||||
|
||||
//Delete unclaimed duplicate workitems.
|
||||
q("delete from config where cat='queuework' and k='workitem' and v='%s'",
|
||||
serialize($argv));
|
||||
|
||||
$cls = '\\Zotlabs\\Daemon\\' . $argv[0];
|
||||
$cls::run($argc,$argv);
|
||||
|
||||
//Right now we assume that if we get a return, everything is OK.
|
||||
//At some point we may want to test whether the run returns true/false
|
||||
// and requeue the work to be tried again. But we probably want
|
||||
// to implement some sort of "retry interval" first.
|
||||
|
||||
q("delete from config where cat='queuework' and k='%s'",
|
||||
'workitem_'.self::$queueworker);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
sleep ($workersleep);
|
||||
$work = q("update config set k='%s' where cat='queuework' and k like '%s' limit 1",
|
||||
'workitem_'.self::$queueworker,
|
||||
dbesc('workitem:%'));
|
||||
|
||||
}
|
||||
logger('Master: Worker Thread: queue items processed:' . $jobs);
|
||||
q("delete from config where cat='queueworkers' and k='%s'",
|
||||
'workerstarted_'.self::$queueworker);
|
||||
}
|
||||
|
||||
static public function ClearQueue() {
|
||||
$work = q("select * from config where cat='queuework' and k like '%s'",
|
||||
dbesc('workitem%'));
|
||||
foreach ($work as $workitem) {
|
||||
$workinfo = unserialize($workitem['v']);
|
||||
$argc = $workinfo['argc'];
|
||||
$argv = $workinfo['argv'];
|
||||
logger('Master: process: ' . print_r($argv,true), LOGGER_ALL,LOG_DEBUG);
|
||||
logger('Master: release: ' . json_encode($argv), LOGGER_ALL,LOG_DEBUG);
|
||||
$cls = '\\Zotlabs\\Daemon\\' . $argv[0];
|
||||
$cls::run($argc,$argv);
|
||||
}
|
||||
$work = q("delete from config where cat='queuework' and k like '%s'",
|
||||
dbesc('workitem%'));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace Zotlabs\Daemon;
|
||||
|
||||
use Zotlabs\Lib\Libzot;
|
||||
|
||||
require_once('include/queue_fn.php');
|
||||
require_once('include/html2plain.php');
|
||||
require_once('include/conversation.php');
|
||||
@ -345,6 +347,15 @@ class Notifier {
|
||||
|
||||
$encoded_item = encode_item($target_item);
|
||||
|
||||
// activitystreams version
|
||||
$m = get_iconfig($target_item,'activitystreams','signed_data');
|
||||
if($m) {
|
||||
$activity = json_decode($m,true);
|
||||
}
|
||||
else {
|
||||
$activity = \Zotlabs\Lib\Activity::encode_activity($target_item);
|
||||
}
|
||||
|
||||
// Send comments to the owner to re-deliver to everybody in the conversation
|
||||
// We only do this if the item in question originated on this site. This prevents looping.
|
||||
// To clarify, a site accepting a new comment is responsible for sending it to the owner for relay.
|
||||
@ -401,6 +412,12 @@ class Notifier {
|
||||
$private = false;
|
||||
$recipients = collect_recipients($parent_item,$private);
|
||||
|
||||
|
||||
if ($top_level_post) {
|
||||
// remove clones who will receive the post via sync
|
||||
$recipients = array_diff($recipients, [ $target_item['owner_xchan'] ]);
|
||||
}
|
||||
|
||||
// FIXME add any additional recipients such as mentions, etc.
|
||||
|
||||
// don't send deletions onward for other people's stuff
|
||||
@ -423,6 +440,8 @@ class Notifier {
|
||||
$x['body'] = 'private';
|
||||
logger('notifier: encoded item: ' . print_r($x,true), LOGGER_DATA, LOG_DEBUG);
|
||||
|
||||
//logger('notifier: encoded activity: ' . print_r($activity,true), LOGGER_DATA, LOG_DEBUG);
|
||||
|
||||
stringify_array_elms($recipients);
|
||||
if(! $recipients) {
|
||||
logger('no recipients');
|
||||
@ -561,7 +580,7 @@ class Notifier {
|
||||
|
||||
logger('notifier_hub: ' . $hub['hubloc_url'],LOGGER_DEBUG);
|
||||
|
||||
if($hub['hubloc_network'] !== 'zot') {
|
||||
if(! in_array($hub['hubloc_network'], [ 'zot','zot6' ])) {
|
||||
$narr = [
|
||||
'channel' => $channel,
|
||||
'upstream' => $upstream,
|
||||
@ -610,20 +629,32 @@ class Notifier {
|
||||
continue;
|
||||
}
|
||||
|
||||
// default: zot protocol
|
||||
if(! in_array($hub['hubloc_network'], [ 'zot','zot6' ])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not change this to a uuid as long as we have traditional zot servers
|
||||
// in the loop. The signature verification step can't handle dashes in the
|
||||
// hashes.
|
||||
|
||||
$hash = random_string(48);
|
||||
|
||||
$hash = random_string();
|
||||
$packet = null;
|
||||
$pmsg = '';
|
||||
|
||||
if($packet_type === 'refresh' || $packet_type === 'purge') {
|
||||
if($hub['hubloc_network'] === 'zot6') {
|
||||
$packet = Libzot::build_packet($channel, $packet_type, ids_to_array($packet_recips,'hash'));
|
||||
}
|
||||
else {
|
||||
$packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null));
|
||||
}
|
||||
if($packet_type === 'keychange') {
|
||||
}
|
||||
if($packet_type === 'keychange' && $hub['hubloc_network'] === 'zot') {
|
||||
$pmsg = get_pconfig($channel['channel_id'],'system','keychange');
|
||||
$packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null));
|
||||
}
|
||||
elseif($packet_type === 'request') {
|
||||
elseif($packet_type === 'request' && $hub['hubloc_network'] === 'zot') {
|
||||
$env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : '');
|
||||
$packet = zot_build_packet($channel,$packet_type,$env,$hub['hubloc_sitekey'],$hub['site_crypto'],
|
||||
$hash, array('message_id' => $request_message_id)
|
||||
@ -636,6 +667,7 @@ class Notifier {
|
||||
'account_id' => $channel['channel_account_id'],
|
||||
'channel_id' => $channel['channel_id'],
|
||||
'posturl' => $hub['hubloc_callback'],
|
||||
'driver' => $hub['hubloc_network'],
|
||||
'notify' => $packet,
|
||||
'msg' => (($pmsg) ? json_encode($pmsg) : '')
|
||||
));
|
||||
@ -643,6 +675,30 @@ class Notifier {
|
||||
else {
|
||||
$env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : '');
|
||||
|
||||
|
||||
if($hub['hubloc_network'] === 'zot6') {
|
||||
$zenv = [];
|
||||
if($env) {
|
||||
foreach($env as $e) {
|
||||
$zenv[] = $e['hash'];
|
||||
}
|
||||
}
|
||||
|
||||
$packet_type = (($upstream || $uplink) ? 'response' : 'activity');
|
||||
|
||||
// block zot private reshares from zot6, as this could cause a number of privacy issues
|
||||
// due to parenting differences between the reshare implementations. In zot a reshare is
|
||||
// a standalone parent activity and in zot6 it is a followup/child of the original activity.
|
||||
// For public reshares, some comments to the reshare on the zot fork will not make it to zot6
|
||||
// due to these different message models. This cannot be prevented at this time.
|
||||
|
||||
if($packet_type === 'activity' && $activity['type'] === 'Announce' && intval($target_item['item_private'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$packet = Libzot::build_packet($channel,$packet_type,$zenv,$activity,'activitystreams',(($private) ? $hub['hubloc_sitekey'] : null),$hub['site_crypto']);
|
||||
}
|
||||
else {
|
||||
// currently zot6 delivery is only performed on normal items and not sync items or mail or anything else
|
||||
// Eventually we will do this for all deliveries, but for now ensure this is precisely what we are dealing
|
||||
// with before switching to zot6 as the primary zot6 handler checks for the existence of a message delivery report
|
||||
@ -656,6 +712,7 @@ class Notifier {
|
||||
$packet = zot_build_packet($channel,'notify',$env, (($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'],$hash);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
queue_insert(
|
||||
[
|
||||
@ -663,6 +720,7 @@ class Notifier {
|
||||
'account_id' => $target_item['aid'],
|
||||
'channel_id' => $target_item['uid'],
|
||||
'posturl' => $hub['hubloc_callback'],
|
||||
'driver' => $hub['hubloc_network'],
|
||||
'notify' => $packet,
|
||||
'msg' => json_encode($encoded_item)
|
||||
]
|
||||
|
@ -69,7 +69,7 @@ class Onepoll {
|
||||
return;
|
||||
}
|
||||
|
||||
if($contact['xchan_network'] !== 'zot')
|
||||
if(! in_array($contact['xchan_network'],['zot','zot6']))
|
||||
return;
|
||||
|
||||
// update permissions
|
||||
|
@ -110,7 +110,7 @@ class Poller {
|
||||
}
|
||||
|
||||
|
||||
if($contact['xchan_network'] !== 'zot')
|
||||
if(! in_array($contact['xchan_network'],['zot','zot6']))
|
||||
continue;
|
||||
|
||||
if($c == $t) {
|
||||
|
@ -12,7 +12,6 @@ class Queue {
|
||||
require_once('include/items.php');
|
||||
require_once('include/bbcode.php');
|
||||
|
||||
|
||||
if($argc > 1)
|
||||
$queue_id = $argv[1];
|
||||
else
|
||||
@ -62,9 +61,19 @@ class Queue {
|
||||
// the site is permanently down, there's no reason to attempt delivery at all, or at most not more than once
|
||||
// or twice a day.
|
||||
|
||||
$r = q("SELECT * FROM outq WHERE outq_delivered = 0 and outq_scheduled < %s ",
|
||||
$sqlrandfunc = db_getfunc('rand');
|
||||
|
||||
$r = q("SELECT *,$sqlrandfunc as rn FROM outq WHERE outq_delivered = 0 and outq_scheduled < %s order by rn limit 1",
|
||||
db_utcnow()
|
||||
);
|
||||
while ($r) {
|
||||
foreach($r as $rv) {
|
||||
queue_deliver($rv);
|
||||
}
|
||||
$r = q("SELECT *,$sqlrandfunc as rn FROM outq WHERE outq_delivered = 0 and outq_scheduled < %s order by rn limit 1",
|
||||
db_utcnow()
|
||||
);
|
||||
}
|
||||
}
|
||||
if(! $r)
|
||||
return;
|
||||
|
@ -2,18 +2,21 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\Libsync;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\Group;
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
|
||||
class Activity {
|
||||
|
||||
static function encode_object($x) {
|
||||
|
||||
|
||||
if(($x) && (! is_array($x)) && (substr(trim($x),0,1)) === '{' ) {
|
||||
$x = json_decode($x,true);
|
||||
}
|
||||
|
||||
if(is_array($x) && array_key_exists('asld',$x)) {
|
||||
$x = $x['asld'];
|
||||
}
|
||||
|
||||
if($x['type'] === ACTIVITY_OBJ_PERSON) {
|
||||
return self::fetch_person($x);
|
||||
}
|
||||
@ -26,11 +29,57 @@ class Activity {
|
||||
if($x['type'] === ACTIVITY_OBJ_THING) {
|
||||
return self::fetch_thing($x);
|
||||
}
|
||||
if($x['type'] === ACTIVITY_OBJ_EVENT) {
|
||||
return self::fetch_event($x);
|
||||
}
|
||||
if($x['type'] === ACTIVITY_OBJ_PHOTO) {
|
||||
return self::fetch_image($x);
|
||||
}
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
|
||||
static function fetch($url,$channel = null) {
|
||||
$redirects = 0;
|
||||
if(! check_siteallowed($url)) {
|
||||
logger('blacklisted: ' . $url);
|
||||
return null;
|
||||
}
|
||||
if(! $channel) {
|
||||
$channel = get_sys_channel();
|
||||
}
|
||||
|
||||
logger('fetch: ' . $url, LOGGER_DEBUG);
|
||||
|
||||
if(strpos($url,'x-zot:') === 0) {
|
||||
$x = ZotURL::fetch($url,$channel);
|
||||
}
|
||||
else {
|
||||
$m = parse_url($url);
|
||||
$headers = [
|
||||
'Accept' => 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||
'Host' => $m['host'],
|
||||
'(request-target)' => 'get ' . get_request_string($url),
|
||||
'Date' => datetime_convert('UTC','UTC','now','D, d M Y H:i:s') . ' UTC'
|
||||
];
|
||||
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false);
|
||||
$x = z_fetch_url($url, true, $redirects, [ 'headers' => $h ] );
|
||||
}
|
||||
|
||||
if($x['success']) {
|
||||
$y = json_decode($x['body'],true);
|
||||
logger('returned: ' . json_encode($y,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));
|
||||
return json_decode($x['body'], true);
|
||||
}
|
||||
else {
|
||||
logger('fetch failed: ' . $url);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static function fetch_person($x) {
|
||||
return self::fetch_profile($x);
|
||||
@ -93,6 +142,63 @@ class Activity {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static function fetch_image($x) {
|
||||
|
||||
|
||||
$ret = [
|
||||
'type' => 'Image',
|
||||
'id' => $x['id'],
|
||||
'name' => $x['title'],
|
||||
'content' => bbcode($x['body']),
|
||||
'source' => [ 'mediaType' => 'text/bbcode', 'content' => $x['body'] ],
|
||||
'published' => datetime_convert('UTC','UTC',$x['created'],ATOM_TIME),
|
||||
'updated' => datetime_convert('UTC','UTC', $x['edited'],ATOM_TIME),
|
||||
'url' => [
|
||||
'type' => 'Link',
|
||||
'mediaType' => $x['link'][0]['type'],
|
||||
'href' => $x['link'][0]['href'],
|
||||
'width' => $x['link'][0]['width'],
|
||||
'height' => $x['link'][0]['height']
|
||||
]
|
||||
];
|
||||
return $ret;
|
||||
}
|
||||
|
||||
static function fetch_event($x) {
|
||||
|
||||
// convert old Zot event objects to ActivityStreams Event objects
|
||||
|
||||
if (array_key_exists('content',$x) && array_key_exists('dtstart',$x)) {
|
||||
$ev = bbtoevent($x['content']);
|
||||
if($ev) {
|
||||
|
||||
$actor = null;
|
||||
if(array_key_exists('author',$x) && array_key_exists('link',$x['author'])) {
|
||||
$actor = $x['author']['link'][0]['href'];
|
||||
}
|
||||
$y = [
|
||||
'type' => 'Event',
|
||||
'id' => z_root() . '/event/' . $ev['event_hash'],
|
||||
'summary' => bbcode($ev['summary']),
|
||||
// RFC3339 Section 4.3
|
||||
'startTime' => (($ev['adjust']) ? datetime_convert('UTC','UTC',$ev['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$ev['dtstart'],'Y-m-d\\TH:i:s-00:00')),
|
||||
'content' => bbcode($ev['description']),
|
||||
'location' => [ 'type' => 'Place', 'content' => bbcode($ev['location']) ],
|
||||
'source' => [ 'content' => format_event_bbcode($ev), 'mediaType' => 'text/bbcode' ],
|
||||
'actor' => $actor,
|
||||
];
|
||||
if($actor) {
|
||||
return $y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $x;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static function encode_item_collection($items,$id,$type,$extra = null) {
|
||||
|
||||
$ret = [
|
||||
@ -167,7 +273,7 @@ class Activity {
|
||||
$ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/item/' . urlencode($i['mid']));
|
||||
|
||||
if($i['title'])
|
||||
$ret['title'] = bbcode($i['title']);
|
||||
$ret['name'] = $i['title'];
|
||||
|
||||
$ret['published'] = datetime_convert('UTC','UTC',$i['created'],ATOM_TIME);
|
||||
if($i['created'] !== $i['edited'])
|
||||
@ -342,10 +448,17 @@ class Activity {
|
||||
$ret['type'] = 'Tombstone';
|
||||
$ret['formerType'] = self::activity_obj_mapper($i['obj_type']);
|
||||
$ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/item/' . urlencode($i['mid']));
|
||||
$actor = self::encode_person($i['author'],false);
|
||||
if($actor)
|
||||
$ret['actor'] = $actor;
|
||||
else
|
||||
return [];
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$ret['type'] = self::activity_mapper($i['verb']);
|
||||
|
||||
|
||||
$ret['id'] = ((strpos($i['mid'],'http') === 0) ? $i['mid'] : z_root() . '/activity/' . urlencode($i['mid']));
|
||||
|
||||
if($i['title'])
|
||||
@ -417,6 +530,10 @@ class Activity {
|
||||
if(! is_array($i['obj'])) {
|
||||
$i['obj'] = json_decode($i['obj'],true);
|
||||
}
|
||||
if($i['obj']['type'] === ACTIVITY_OBJ_PHOTO) {
|
||||
$i['obj']['id'] = $i['id'];
|
||||
}
|
||||
|
||||
$obj = self::encode_object($i['obj']);
|
||||
if($obj)
|
||||
$ret['object'] = $obj;
|
||||
@ -540,6 +657,12 @@ class Activity {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static function activity_mapper($verb) {
|
||||
|
||||
if(strpos($verb,'/') === false) {
|
||||
@ -556,6 +679,9 @@ class Activity {
|
||||
'http://activitystrea.ms/schema/1.0/tag' => 'Add',
|
||||
'http://activitystrea.ms/schema/1.0/follow' => 'Follow',
|
||||
'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow',
|
||||
'http://purl.org/zot/activity/attendyes' => 'Accept',
|
||||
'http://purl.org/zot/activity/attendno' => 'Reject',
|
||||
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
|
||||
];
|
||||
|
||||
|
||||
@ -582,6 +708,70 @@ class Activity {
|
||||
}
|
||||
|
||||
|
||||
|
||||
static function activity_decode_mapper($verb) {
|
||||
|
||||
$acts = [
|
||||
'http://activitystrea.ms/schema/1.0/post' => 'Create',
|
||||
'http://activitystrea.ms/schema/1.0/share' => 'Announce',
|
||||
'http://activitystrea.ms/schema/1.0/update' => 'Update',
|
||||
'http://activitystrea.ms/schema/1.0/like' => 'Like',
|
||||
'http://activitystrea.ms/schema/1.0/favorite' => 'Like',
|
||||
'http://purl.org/zot/activity/dislike' => 'Dislike',
|
||||
'http://activitystrea.ms/schema/1.0/tag' => 'Add',
|
||||
'http://activitystrea.ms/schema/1.0/follow' => 'Follow',
|
||||
'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow',
|
||||
'http://purl.org/zot/activity/attendyes' => 'Accept',
|
||||
'http://purl.org/zot/activity/attendno' => 'Reject',
|
||||
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept'
|
||||
];
|
||||
|
||||
|
||||
foreach($acts as $k => $v) {
|
||||
if($verb === $v) {
|
||||
return $k;
|
||||
}
|
||||
}
|
||||
|
||||
logger('Unmapped activity: ' . $verb);
|
||||
return 'Create';
|
||||
|
||||
}
|
||||
|
||||
static function activity_obj_decode_mapper($obj) {
|
||||
|
||||
$objs = [
|
||||
'http://activitystrea.ms/schema/1.0/note' => 'Note',
|
||||
'http://activitystrea.ms/schema/1.0/note' => 'Article',
|
||||
'http://activitystrea.ms/schema/1.0/comment' => 'Note',
|
||||
'http://activitystrea.ms/schema/1.0/person' => 'Person',
|
||||
'http://purl.org/zot/activity/profile' => 'Profile',
|
||||
'http://activitystrea.ms/schema/1.0/photo' => 'Image',
|
||||
'http://activitystrea.ms/schema/1.0/profile-photo' => 'Icon',
|
||||
'http://activitystrea.ms/schema/1.0/event' => 'Event',
|
||||
'http://activitystrea.ms/schema/1.0/wiki' => 'Document',
|
||||
'http://purl.org/zot/activity/location' => 'Place',
|
||||
'http://purl.org/zot/activity/chessgame' => 'Game',
|
||||
'http://purl.org/zot/activity/tagterm' => 'zot:Tag',
|
||||
'http://purl.org/zot/activity/thing' => 'Object',
|
||||
'http://purl.org/zot/activity/file' => 'zot:File',
|
||||
'http://purl.org/zot/activity/mood' => 'zot:Mood',
|
||||
|
||||
];
|
||||
|
||||
foreach($objs as $k => $v) {
|
||||
if($obj === $v) {
|
||||
return $k;
|
||||
}
|
||||
}
|
||||
|
||||
logger('Unmapped activity object: ' . $obj);
|
||||
return 'Note';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static function activity_obj_mapper($obj) {
|
||||
|
||||
if(strpos($obj,'/') === false) {
|
||||
@ -1149,7 +1339,7 @@ class Activity {
|
||||
}
|
||||
|
||||
if($act->obj['type'] === 'Note' && $s['attach']) {
|
||||
$s['body'] .= self::bb_attach($s['attach']);
|
||||
$s['body'] .= self::bb_attach($s['attach'],$s['body']);
|
||||
}
|
||||
|
||||
// we will need a hook here to extract magnet links e.g. peertube
|
||||
@ -1230,21 +1420,39 @@ class Activity {
|
||||
|
||||
}
|
||||
|
||||
static function get_actor_bbmention($id) {
|
||||
|
||||
$x = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_hash = '%s' or hubloc_id_url = '%s' limit 1",
|
||||
dbesc($id),
|
||||
dbesc($id)
|
||||
);
|
||||
|
||||
if($x) {
|
||||
return sprintf('@[zrl=%s]%s[/zrl]',$x[0]['xchan_url'],$x[0]['xchan_name']);
|
||||
}
|
||||
return '@{' . $id . '}';
|
||||
|
||||
}
|
||||
|
||||
|
||||
static function decode_note($act) {
|
||||
|
||||
$response_activity = false;
|
||||
|
||||
$s = [];
|
||||
|
||||
|
||||
|
||||
if(is_array($act->obj)) {
|
||||
$content = self::get_content($act->obj);
|
||||
}
|
||||
|
||||
$s['owner_xchan'] = $act->actor['id'];
|
||||
$s['author_xchan'] = $act->actor['id'];
|
||||
|
||||
$s['mid'] = $act->id;
|
||||
$s['parent_mid'] = $act->parent_id;
|
||||
// ensure we store the original actor
|
||||
self::actor_store($act->actor['id'],$act->actor);
|
||||
|
||||
$s['mid'] = $act->obj['id'];
|
||||
$s['parent_mid'] = $act->parent_id;
|
||||
|
||||
if($act->data['published']) {
|
||||
$s['created'] = datetime_convert('UTC','UTC',$act->data['published']);
|
||||
@ -1259,75 +1467,139 @@ class Activity {
|
||||
$s['edited'] = datetime_convert('UTC','UTC',$act->obj['updated']);
|
||||
}
|
||||
|
||||
|
||||
if(in_array($act->type, [ 'Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept' ])) {
|
||||
|
||||
$response_activity = true;
|
||||
|
||||
$s['mid'] = $act->id;
|
||||
$s['parent_mid'] = $act->obj['id'];
|
||||
|
||||
// over-ride the object timestamp with the activity
|
||||
|
||||
if($act->data['published']) {
|
||||
$s['created'] = datetime_convert('UTC','UTC',$act->data['published']);
|
||||
}
|
||||
|
||||
if($act->data['updated']) {
|
||||
$s['edited'] = datetime_convert('UTC','UTC',$act->data['updated']);
|
||||
}
|
||||
|
||||
$obj_actor = ((isset($act->obj['actor'])) ? $act->obj['actor'] : $act->get_actor('attributedTo', $act->obj));
|
||||
// ensure we store the original actor
|
||||
self::actor_store($obj_actor['id'],$obj_actor);
|
||||
|
||||
$mention = self::get_actor_bbmention($obj_actor['id']);
|
||||
|
||||
if($act->type === 'Like') {
|
||||
$content['content'] = sprintf( t('Likes %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content'];
|
||||
}
|
||||
if($act->type === 'Dislike') {
|
||||
$content['content'] = sprintf( t('Doesn\'t like %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content'];
|
||||
}
|
||||
if($act->type === 'Accept' && $act->obj['type'] === 'Event' ) {
|
||||
$content['content'] = sprintf( t('Will attend %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content'];
|
||||
}
|
||||
if($act->type === 'Reject' && $act->obj['type'] === 'Event' ) {
|
||||
$content['content'] = sprintf( t('Will not attend %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content'];
|
||||
}
|
||||
if($act->type === 'TentativeAccept' && $act->obj['type'] === 'Event' ) {
|
||||
$content['content'] = sprintf( t('May attend %1$s\'s %2$s'),$mention,$act->obj['type']) . "\n\n" . $content['content'];
|
||||
}
|
||||
if($act->type === 'Announce') {
|
||||
$content['content'] = sprintf( t('🔁 Repeated %1$s\'s %2$s'), $mention, $act->obj['type']);
|
||||
}
|
||||
}
|
||||
|
||||
if(! $s['created'])
|
||||
$s['created'] = datetime_convert();
|
||||
|
||||
if(! $s['edited'])
|
||||
$s['edited'] = $s['created'];
|
||||
|
||||
if(in_array($act->type,['Announce'])) {
|
||||
$root_content = self::get_content($act->raw);
|
||||
|
||||
$s['title'] = self::bb_content($root_content,'name');
|
||||
$s['summary'] = self::bb_content($root_content,'summary');
|
||||
$s['body'] = (self::bb_content($root_content,'bbcode') ? : self::bb_content($root_content,'content'));
|
||||
|
||||
if(strpos($s['body'],'[share') === false) {
|
||||
|
||||
// @fixme - error check and set defaults
|
||||
|
||||
$name = urlencode($act->obj['actor']['name']);
|
||||
$profile = $act->obj['actor']['id'];
|
||||
$photo = $act->obj['icon']['url'];
|
||||
|
||||
$s['body'] .= "\r\n[share author='" . $name .
|
||||
"' profile='" . $profile .
|
||||
"' avatar='" . $photo .
|
||||
"' link='" . $act->obj['id'] .
|
||||
"' auth='" . ((is_matrix_url($act->obj['id'])) ? 'true' : 'false' ) .
|
||||
"' posted='" . $act->obj['published'] .
|
||||
"' message_id='" . $act->obj['id'] .
|
||||
"']";
|
||||
}
|
||||
}
|
||||
else {
|
||||
$s['title'] = self::bb_content($content,'name');
|
||||
$s['summary'] = self::bb_content($content,'summary');
|
||||
$s['body'] = (self::bb_content($content,'bbcode') ? : self::bb_content($content,'content'));
|
||||
}
|
||||
$s['body'] = ((self::bb_content($content,'bbcode') && (! $response_activity)) ? self::bb_content($content,'bbcode') : self::bb_content($content,'content'));
|
||||
|
||||
$s['verb'] = self::activity_mapper($act->type);
|
||||
$s['verb'] = self::activity_decode_mapper($act->type);
|
||||
|
||||
if($act->type === 'Tombstone') {
|
||||
|
||||
if($act->type === 'Tombstone' || ($act->type === 'Create' && $act->obj['type'] === 'Tombstone')) {
|
||||
$s['item_deleted'] = 1;
|
||||
}
|
||||
|
||||
$s['obj_type'] = self::activity_obj_mapper($act->obj['type']);
|
||||
$s['obj_type'] = self::activity_obj_decode_mapper($act->obj['type']);
|
||||
if($s['obj_type'] === ACTIVITY_OBJ_NOTE && $s['mid'] !== $s['parent_mid']) {
|
||||
$s['obj_type'] = ACTIVITY_OBJ_COMMENT;
|
||||
}
|
||||
|
||||
if($act->obj['type'] === 'Event') {
|
||||
$s['obj'] = [];
|
||||
$s['obj']['asld'] = $act->obj;
|
||||
$s['obj']['type'] = ACTIVITY_OBJ_EVENT;
|
||||
$s['obj']['id'] = $act->obj['id'];
|
||||
$s['obj']['title'] = $act->obj['summary'];
|
||||
|
||||
if(strpos($act->obj['startTime'],'Z'))
|
||||
$s['obj']['adjust'] = true;
|
||||
else
|
||||
$s['obj']['adjust'] = false;
|
||||
|
||||
$s['obj']['dtstart'] = datetime_convert('UTC','UTC',$act->obj['startTime']);
|
||||
if($act->obj['endTime'])
|
||||
$s['obj']['dtend'] = datetime_convert('UTC','UTC',$act->obj['endTime']);
|
||||
else
|
||||
$s['obj']['nofinish'] = true;
|
||||
$s['obj']['description'] = $act->obj['content'];
|
||||
|
||||
if(array_path_exists('location/content',$act->obj))
|
||||
$s['obj']['location'] = $act->obj['location']['content'];
|
||||
|
||||
}
|
||||
else {
|
||||
$s['obj'] = $act->obj;
|
||||
}
|
||||
|
||||
$instrument = $act->get_property_obj('instrument');
|
||||
if(! $instrument)
|
||||
if((! $instrument) && (! $response_activity)) {
|
||||
$instrument = $act->get_property_obj('instrument',$act->obj);
|
||||
}
|
||||
|
||||
if($instrument && array_key_exists('type',$instrument)
|
||||
&& $instrument['type'] === 'Service' && array_key_exists('name',$instrument)) {
|
||||
$s['app'] = escape_tags($instrument['name']);
|
||||
}
|
||||
|
||||
|
||||
if(! $response_activity) {
|
||||
$a = self::decode_taxonomy($act->obj);
|
||||
if($a) {
|
||||
$s['term'] = $a;
|
||||
foreach($a as $b) {
|
||||
if($b['ttype'] === TERM_EMOJI) {
|
||||
$s['title'] = str_replace($b['term'],'[img=16x16]' . $b['url'] . '[/img]',$s['title']);
|
||||
$s['summary'] = str_replace($b['term'],'[img=16x16]' . $b['url'] . '[/img]',$s['summary']);
|
||||
$s['body'] = str_replace($b['term'],'[img=16x16]' . $b['url'] . '[/img]',$s['body']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$a = self::decode_attachment($act->obj);
|
||||
if($a) {
|
||||
$s['attach'] = $a;
|
||||
}
|
||||
}
|
||||
|
||||
if($act->obj['type'] === 'Note' && $s['attach']) {
|
||||
$s['body'] .= self::bb_attach($s['attach'],$s['body']);
|
||||
}
|
||||
|
||||
|
||||
// we will need a hook here to extract magnet links e.g. peertube
|
||||
// right now just link to the largest mp4 we find that will fit in our
|
||||
// standard content region
|
||||
|
||||
if(! $response_activity) {
|
||||
if($act->obj['type'] === 'Video') {
|
||||
|
||||
$vtypes = [
|
||||
@ -1337,8 +1609,19 @@ class Activity {
|
||||
];
|
||||
|
||||
$mps = [];
|
||||
if(array_key_exists('url',$act->obj) && is_array($act->obj['url'])) {
|
||||
foreach($act->obj['url'] as $vurl) {
|
||||
$ptr = null;
|
||||
|
||||
if(array_key_exists('url',$act->obj)) {
|
||||
if(is_array($act->obj['url'])) {
|
||||
if(array_key_exists(0,$act->obj['url'])) {
|
||||
$ptr = $act->obj['url'];
|
||||
}
|
||||
else {
|
||||
$ptr = [ $act->obj['url'] ];
|
||||
}
|
||||
foreach($ptr as $vurl) {
|
||||
// peertube uses the non-standard element name 'mimeType' here
|
||||
if(array_key_exists('mimeType',$vurl)) {
|
||||
if(in_array($vurl['mimeType'], $vtypes)) {
|
||||
if(! array_key_exists('width',$vurl)) {
|
||||
$vurl['width'] = 0;
|
||||
@ -1346,16 +1629,161 @@ class Activity {
|
||||
$mps[] = $vurl;
|
||||
}
|
||||
}
|
||||
elseif(array_key_exists('mediaType',$vurl)) {
|
||||
if(in_array($vurl['mediaType'], $vtypes)) {
|
||||
if(! array_key_exists('width',$vurl)) {
|
||||
$vurl['width'] = 0;
|
||||
}
|
||||
$mps[] = $vurl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if($mps) {
|
||||
usort($mps,'as_vid_sort');
|
||||
usort($mps,[ __CLASS__, 'vid_sort' ]);
|
||||
foreach($mps as $m) {
|
||||
if(intval($m['width']) < 500) {
|
||||
if(intval($m['width']) < 500 && self::media_not_in_body($m['href'],$s['body'])) {
|
||||
$s['body'] .= "\n\n" . '[video]' . $m['href'] . '[/video]';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif(is_string($act->obj['url']) && self::media_not_in_body($act->obj['url'],$s['body'])) {
|
||||
$s['body'] .= "\n\n" . '[video]' . $act->obj['url'] . '[/video]';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($act->obj['type'] === 'Audio') {
|
||||
|
||||
$atypes = [
|
||||
'audio/mpeg',
|
||||
'audio/ogg',
|
||||
'audio/wav'
|
||||
];
|
||||
|
||||
$ptr = null;
|
||||
|
||||
if(array_key_exists('url',$act->obj)) {
|
||||
if(is_array($act->obj['url'])) {
|
||||
if(array_key_exists(0,$act->obj['url'])) {
|
||||
$ptr = $act->obj['url'];
|
||||
}
|
||||
else {
|
||||
$ptr = [ $act->obj['url'] ];
|
||||
}
|
||||
foreach($ptr as $vurl) {
|
||||
if(in_array($vurl['mediaType'], $atypes) && self::media_not_in_body($vurl['href'],$s['body'])) {
|
||||
$s['body'] .= "\n\n" . '[audio]' . $vurl['href'] . '[/audio]';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif(is_string($act->obj['url']) && self::media_not_in_body($act->obj['url'],$s['body'])) {
|
||||
$s['body'] .= "\n\n" . '[audio]' . $act->obj['url'] . '[/audio]';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// avoid double images from hubzilla to zap/osada
|
||||
|
||||
if($act->obj['type'] === 'Image' && strpos($s['body'],'zrl=') === false) {
|
||||
|
||||
$ptr = null;
|
||||
|
||||
if(array_key_exists('url',$act->obj)) {
|
||||
if(is_array($act->obj['url'])) {
|
||||
if(array_key_exists(0,$act->obj['url'])) {
|
||||
$ptr = $act->obj['url'];
|
||||
}
|
||||
else {
|
||||
$ptr = [ $act->obj['url'] ];
|
||||
}
|
||||
foreach($ptr as $vurl) {
|
||||
if(strpos($s['body'],$vurl['href']) === false) {
|
||||
$s['body'] .= "\n\n" . '[zmg]' . $vurl['href'] . '[/zmg]';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif(is_string($act->obj['url'])) {
|
||||
if(strpos($s['body'],$act->obj['url']) === false) {
|
||||
$s['body'] .= "\n\n" . '[zmg]' . $act->obj['url'] . '[/zmg]';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if($act->obj['type'] === 'Page' && ! $s['body']) {
|
||||
|
||||
$ptr = null;
|
||||
$purl = EMPTY_STR;
|
||||
|
||||
if(array_key_exists('url',$act->obj)) {
|
||||
if(is_array($act->obj['url'])) {
|
||||
if(array_key_exists(0,$act->obj['url'])) {
|
||||
$ptr = $act->obj['url'];
|
||||
}
|
||||
else {
|
||||
$ptr = [ $act->obj['url'] ];
|
||||
}
|
||||
foreach($ptr as $vurl) {
|
||||
if(array_key_exists('mediaType',$vurl) && $vurl['mediaType'] === 'text/html') {
|
||||
$purl = $vurl['href'];
|
||||
break;
|
||||
}
|
||||
elseif(array_key_exists('mimeType',$vurl) && $vurl['mimeType'] === 'text/html') {
|
||||
$purl = $vurl['href'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif(is_string($act->obj['url'])) {
|
||||
$purl = $act->obj['url'];
|
||||
}
|
||||
if($purl) {
|
||||
$li = z_fetch_url(z_root() . '/linkinfo?binurl=' . bin2hex($purl));
|
||||
if($li['success'] && $li['body']) {
|
||||
$s['body'] .= "\n" . $li['body'];
|
||||
}
|
||||
else {
|
||||
$s['body'] .= "\n\n" . $purl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(in_array($act->obj['type'],[ 'Note','Article','Page' ])) {
|
||||
$ptr = null;
|
||||
|
||||
if(array_key_exists('url',$act->obj)) {
|
||||
if(is_array($act->obj['url'])) {
|
||||
if(array_key_exists(0,$act->obj['url'])) {
|
||||
$ptr = $act->obj['url'];
|
||||
}
|
||||
else {
|
||||
$ptr = [ $act->obj['url'] ];
|
||||
}
|
||||
foreach($ptr as $vurl) {
|
||||
if(array_key_exists('mediaType',$vurl) && $vurl['mediaType'] === 'text/html') {
|
||||
$s['plink'] = $vurl['href'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif(is_string($act->obj['url'])) {
|
||||
$s['plink'] = $act->obj['url'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(! $s['plink']) {
|
||||
$s['plink'] = $s['mid'];
|
||||
}
|
||||
|
||||
if($act->recips && (! in_array(ACTIVITY_PUBLIC_INBOX,$act->recips)))
|
||||
@ -1371,8 +1799,6 @@ class Activity {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
static function announce_note($channel,$observer_hash,$act) {
|
||||
|
||||
$s = [];
|
||||
@ -1464,7 +1890,7 @@ class Activity {
|
||||
$body .= self::bb_content($content,'content');
|
||||
|
||||
if($act->obj['type'] === 'Note' && $s['attach']) {
|
||||
$body .= self::bb_attach($s['attach']);
|
||||
$body .= self::bb_attach($s['attach'],$body);
|
||||
}
|
||||
|
||||
$body .= "[/share]";
|
||||
@ -1642,36 +2068,58 @@ class Activity {
|
||||
}
|
||||
|
||||
|
||||
static function bb_attach($attach) {
|
||||
|
||||
static function bb_attach($attach,$body) {
|
||||
|
||||
$ret = false;
|
||||
|
||||
foreach($attach as $a) {
|
||||
if(strpos($a['type'],'image') !== false) {
|
||||
if(self::media_not_in_body($a['href'],$body)) {
|
||||
$ret .= "\n\n" . '[img]' . $a['href'] . '[/img]';
|
||||
}
|
||||
}
|
||||
if(array_key_exists('type',$a) && strpos($a['type'], 'video') === 0) {
|
||||
if(self::media_not_in_body($a['href'],$body)) {
|
||||
$ret .= "\n\n" . '[video]' . $a['href'] . '[/video]';
|
||||
}
|
||||
}
|
||||
if(array_key_exists('type',$a) && strpos($a['type'], 'audio') === 0) {
|
||||
if(self::media_not_in_body($a['href'],$body)) {
|
||||
$ret .= "\n\n" . '[audio]' . $a['href'] . '[/audio]';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
// check for the existence of existing media link in body
|
||||
|
||||
static function media_not_in_body($s,$body) {
|
||||
|
||||
if((strpos($body,']' . $s . '[/img]') === false) &&
|
||||
(strpos($body,']' . $s . '[/zmg]') === false) &&
|
||||
(strpos($body,']' . $s . '[/video]') === false) &&
|
||||
(strpos($body,']' . $s . '[/audio]') === false)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static function bb_content($content,$field) {
|
||||
|
||||
require_once('include/html2bbcode.php');
|
||||
|
||||
require_once('include/event.php');
|
||||
$ret = false;
|
||||
|
||||
if(is_array($content[$field])) {
|
||||
foreach($content[$field] as $k => $v) {
|
||||
$ret .= '[language=' . $k . ']' . html2bbcode($v) . '[/language]';
|
||||
$ret .= html2bbcode($v);
|
||||
// save this for auto-translate or dynamic filtering
|
||||
// $ret .= '[language=' . $k . ']' . html2bbcode($v) . '[/language]';
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -1682,6 +2130,9 @@ class Activity {
|
||||
$ret = html2bbcode($content[$field]);
|
||||
}
|
||||
}
|
||||
if($field === 'content' && $content['event'] && (! strpos($ret,'[event'))) {
|
||||
$ret .= format_event_bbcode($content['event']);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
@ -1690,21 +2141,52 @@ class Activity {
|
||||
static function get_content($act) {
|
||||
|
||||
$content = [];
|
||||
if (! $act) {
|
||||
$event = null;
|
||||
|
||||
if ((! $act) || (! is_array($act))) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
if($act['type'] === 'Event') {
|
||||
$adjust = false;
|
||||
$event = [];
|
||||
$event['event_hash'] = $act['id'];
|
||||
if(array_key_exists('startTime',$act) && strpos($act['startTime'],-1,1) === 'Z') {
|
||||
$adjust = true;
|
||||
$event['adjust'] = 1;
|
||||
$event['dtstart'] = datetime_convert('UTC','UTC',$event['startTime'] . (($adjust) ? '' : 'Z'));
|
||||
}
|
||||
if(array_key_exists('endTime',$act)) {
|
||||
$event['dtend'] = datetime_convert('UTC','UTC',$event['endTime'] . (($adjust) ? '' : 'Z'));
|
||||
}
|
||||
else {
|
||||
$event['nofinish'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ([ 'name', 'summary', 'content' ] as $a) {
|
||||
if (($x = self::get_textfield($act,$a)) !== false) {
|
||||
$content[$a] = $x;
|
||||
}
|
||||
}
|
||||
|
||||
if($event) {
|
||||
$event['summary'] = html2bbcode($content['summary']);
|
||||
$event['description'] = html2bbcode($content['content']);
|
||||
if($event['summary'] && $event['dtstart']) {
|
||||
$content['event'] = $event;
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists('source',$act) && array_key_exists('mediaType',$act['source'])) {
|
||||
if ($act['source']['mediaType'] === 'text/bbcode') {
|
||||
$content['bbcode'] = purify_html($act['source']['content']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
@ -1722,4 +2204,6 @@ class Activity {
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -7,12 +7,15 @@ namespace Zotlabs\Lib;
|
||||
*
|
||||
* Parses an ActivityStream JSON string.
|
||||
*/
|
||||
|
||||
class ActivityStreams {
|
||||
|
||||
public $raw = null;
|
||||
public $data;
|
||||
public $data = null;
|
||||
public $valid = false;
|
||||
public $deleted = false;
|
||||
public $id = '';
|
||||
public $parent_id = '';
|
||||
public $type = '';
|
||||
public $actor = null;
|
||||
public $obj = null;
|
||||
@ -35,16 +38,49 @@ class ActivityStreams {
|
||||
function __construct($string) {
|
||||
|
||||
$this->raw = $string;
|
||||
|
||||
if(is_array($string)) {
|
||||
$this->data = $string;
|
||||
}
|
||||
else {
|
||||
$this->data = json_decode($string, true);
|
||||
}
|
||||
|
||||
if($this->data) {
|
||||
|
||||
// verify and unpack JSalmon signature if present
|
||||
|
||||
if(is_array($this->data) && array_key_exists('signed',$this->data)) {
|
||||
$ret = JSalmon::verify($this->data);
|
||||
$tmp = JSalmon::unpack($this->data['data']);
|
||||
if($ret && $ret['success']) {
|
||||
if($ret['signer']) {
|
||||
$saved = json_encode($this->data,JSON_UNESCAPED_SLASHES);
|
||||
$this->data = $tmp;
|
||||
$this->data['signer'] = $ret['signer'];
|
||||
$this->data['signed_data'] = $saved;
|
||||
if($ret['hubloc']) {
|
||||
$this->data['hubloc'] = $ret['hubloc'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->valid = true;
|
||||
|
||||
if(array_key_exists('type',$this->data) && array_key_exists('actor',$this->data) && array_key_exists('object',$this->data)) {
|
||||
if($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) {
|
||||
$this->deleted = $this->data['actor'];
|
||||
$this->valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if($this->is_valid()) {
|
||||
$this->id = $this->get_property_obj('id');
|
||||
$this->type = $this->get_primary_type();
|
||||
$this->actor = $this->get_compound_property('actor');
|
||||
$this->actor = $this->get_actor('actor','','');
|
||||
$this->obj = $this->get_compound_property('object');
|
||||
$this->tgt = $this->get_compound_property('target');
|
||||
$this->origin = $this->get_compound_property('origin');
|
||||
@ -53,14 +89,31 @@ class ActivityStreams {
|
||||
$this->ldsig = $this->get_compound_property('signature');
|
||||
if($this->ldsig) {
|
||||
$this->signer = $this->get_compound_property('creator',$this->ldsig);
|
||||
if($this->signer && $this->signer['publicKey'] && $this->signer['publicKey']['publicKeyPem']) {
|
||||
$this->sigok = \Zotlabs\Lib\LDSignatures::verify($this->data,$this->signer['publicKey']['publicKeyPem']);
|
||||
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']);
|
||||
}
|
||||
}
|
||||
|
||||
if(($this->type === 'Note') && (! $this->obj)) {
|
||||
if(! $this->obj) {
|
||||
$this->obj = $this->data;
|
||||
$this->type = 'Create';
|
||||
if(! $this->actor) {
|
||||
$this->actor = $this->get_actor('attributedTo',$this->obj);
|
||||
}
|
||||
}
|
||||
|
||||
if($this->obj && is_array($this->obj) && $this->obj['actor'])
|
||||
$this->obj['actor'] = $this->get_actor('actor',$this->obj);
|
||||
if($this->tgt && is_array($this->tgt) && $this->tgt['actor'])
|
||||
$this->tgt['actor'] = $this->get_actor('actor',$this->tgt);
|
||||
|
||||
$this->parent_id = $this->get_property_obj('inReplyTo');
|
||||
|
||||
if((! $this->parent_id) && is_array($this->obj)) {
|
||||
$this->parent_id = $this->obj['inReplyTo'];
|
||||
}
|
||||
if((! $this->parent_id) && is_array($this->obj)) {
|
||||
$this->parent_id = $this->obj['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -190,28 +243,32 @@ class ActivityStreams {
|
||||
$base = (($base) ? $base : $this->data);
|
||||
$propname = (($prefix) ? $prefix . ':' : '') . $property;
|
||||
|
||||
if(! is_array($base)) {
|
||||
btlogger('not an array: ' . print_r($base,true));
|
||||
return null;
|
||||
}
|
||||
|
||||
return ((array_key_exists($propname, $base)) ? $base[$propname] : null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Fetches a property from an URL.
|
||||
*
|
||||
* @param string $url
|
||||
* @return NULL|mixed
|
||||
*/
|
||||
|
||||
function fetch_property($url) {
|
||||
$redirects = 0;
|
||||
if(! check_siteallowed($url)) {
|
||||
logger('blacklisted: ' . $url);
|
||||
return null;
|
||||
return self::fetch($url);
|
||||
}
|
||||
|
||||
$x = z_fetch_url($url, true, $redirects,
|
||||
['headers' => [ 'Accept: application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ]]);
|
||||
if($x['success'])
|
||||
return json_decode($x['body'], true);
|
||||
static function fetch($url,$channel = null) {
|
||||
return Activity::fetch($url,$channel);
|
||||
}
|
||||
|
||||
return null;
|
||||
static function is_an_actor($s) {
|
||||
return(in_array($s,[ 'Application','Group','Organization','Person','Service' ]));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -222,12 +279,70 @@ class ActivityStreams {
|
||||
* @param string $namespace (optional) default empty
|
||||
* @return NULL|mixed
|
||||
*/
|
||||
function get_compound_property($property, $base = '', $namespace = '') {
|
||||
|
||||
function get_actor($property,$base='',$namespace = '') {
|
||||
$x = $this->get_property_obj($property, $base, $namespace);
|
||||
if($this->is_url($x)) {
|
||||
|
||||
// SECURITY: If we have already stored the actor profile, re-generate it
|
||||
// from cached data - don't refetch it from the network
|
||||
|
||||
$r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1",
|
||||
dbesc($x)
|
||||
);
|
||||
if($r) {
|
||||
$y = Activity::encode_person($r[0]);
|
||||
$y['cached'] = true;
|
||||
return $y;
|
||||
}
|
||||
}
|
||||
$actor = $this->get_compound_property($property,$base,$namespace,true);
|
||||
if(is_array($actor) && self::is_an_actor($actor['type'])) {
|
||||
if(array_key_exists('id',$actor) && (! array_key_exists('inbox',$actor))) {
|
||||
$actor = $this->fetch_property($actor['id']);
|
||||
}
|
||||
return $actor;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param string $property
|
||||
* @param array $base
|
||||
* @param string $namespace (optional) default empty
|
||||
* @param boolean $first (optional) default false, if true and result is a sequential array return only the first element
|
||||
* @return NULL|mixed
|
||||
*/
|
||||
function get_compound_property($property, $base = '', $namespace = '', $first = false) {
|
||||
$x = $this->get_property_obj($property, $base, $namespace);
|
||||
if($this->is_url($x)) {
|
||||
$x = $this->fetch_property($x);
|
||||
}
|
||||
|
||||
// verify and unpack JSalmon signature if present
|
||||
|
||||
if(is_array($x) && array_key_exists('signed',$x)) {
|
||||
$ret = JSalmon::verify($x);
|
||||
$tmp = JSalmon::unpack($x['data']);
|
||||
if($ret && $ret['success']) {
|
||||
if($ret['signer']) {
|
||||
$saved = json_encode($x,JSON_UNESCAPED_SLASHES);
|
||||
$x = $tmp;
|
||||
$x['signer'] = $ret['signer'];
|
||||
$x['signed_data'] = $saved;
|
||||
if($ret['hubloc']) {
|
||||
$x['hubloc'] = $ret['hubloc'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if($first && is_array($x) && array_key_exists(0,$x)) {
|
||||
return $x[0];
|
||||
}
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
@ -273,4 +388,18 @@ class ActivityStreams {
|
||||
return $x;
|
||||
}
|
||||
|
||||
|
||||
static function is_as_request() {
|
||||
|
||||
$x = getBestSupportedMimeType([
|
||||
'application/ld+json;profile="https://www.w3.org/ns/activitystreams"',
|
||||
'application/activity+json',
|
||||
'application/ld+json;profile="http://www.w3.org/ns/activitystreams"'
|
||||
]);
|
||||
|
||||
return(($x) ? true : false);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -12,8 +12,16 @@ class Api_router {
|
||||
}
|
||||
|
||||
static function find($path) {
|
||||
if(array_key_exists($path,self::$routes))
|
||||
if (array_key_exists($path,self::$routes)) {
|
||||
return self::$routes[$path];
|
||||
}
|
||||
|
||||
$with_params = dirname($path) . '/[id]';
|
||||
|
||||
if (array_key_exists($with_params,self::$routes)) {
|
||||
return self::$routes[$with_params];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1,32 +1,34 @@
|
||||
<?php /** @file */
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
/**
|
||||
* Apps
|
||||
*
|
||||
*/
|
||||
|
||||
require_once('include/plugin.php');
|
||||
require_once('include/channel.php');
|
||||
|
||||
|
||||
/**
|
||||
* @brief Apps class.
|
||||
*
|
||||
*/
|
||||
class Apps {
|
||||
|
||||
static public $available_apps = null;
|
||||
static public $installed_apps = null;
|
||||
|
||||
static public $base_apps = null;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param boolean $translate (optional) default true
|
||||
* @return array
|
||||
*/
|
||||
static public function get_system_apps($translate = true) {
|
||||
$ret = [];
|
||||
|
||||
$ret = array();
|
||||
if(is_dir('apps'))
|
||||
$files = glob('apps/*.apd');
|
||||
else
|
||||
$files = glob('app/*.apd');
|
||||
|
||||
if($files) {
|
||||
foreach($files as $f) {
|
||||
$x = self::parse_app_description($f,$translate);
|
||||
@ -50,14 +52,17 @@ class Apps {
|
||||
}
|
||||
}
|
||||
|
||||
call_hooks('get_system_apps',$ret);
|
||||
/**
|
||||
* @hooks get_system_apps
|
||||
* Hook to manipulate the system apps array.
|
||||
*/
|
||||
call_hooks('get_system_apps', $ret);
|
||||
|
||||
return $ret;
|
||||
|
||||
}
|
||||
|
||||
static public function get_base_apps() {
|
||||
return get_config('system','base_apps',[
|
||||
$x = get_config('system','base_apps',[
|
||||
'Connections',
|
||||
'Network',
|
||||
'Settings',
|
||||
@ -72,6 +77,14 @@ class Apps {
|
||||
'Mail',
|
||||
'Profile Photo'
|
||||
]);
|
||||
|
||||
/**
|
||||
* @hooks get_base_apps
|
||||
* Hook to manipulate the base apps array.
|
||||
*/
|
||||
call_hooks('get_base_apps', $x);
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
static public function import_system_apps() {
|
||||
@ -104,6 +117,7 @@ class Apps {
|
||||
// $id will be boolean true or false to install an app, or an integer id to update an existing app
|
||||
if($id === false)
|
||||
continue;
|
||||
|
||||
if($id !== true) {
|
||||
// if we already installed this app, but it changed, preserve any categories we created
|
||||
$s = EMPTY_STR;
|
||||
@ -124,7 +138,6 @@ class Apps {
|
||||
$app['guid'] = hash('whirlpool',$app['name']);
|
||||
$app['system'] = 1;
|
||||
self::app_install(local_channel(),$app);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -132,8 +145,10 @@ class Apps {
|
||||
/**
|
||||
* Install the system app if no system apps have been installed, or if a new system app
|
||||
* is discovered, or if the version of a system app changes.
|
||||
*
|
||||
* @param array $app
|
||||
* @return boolean|int
|
||||
*/
|
||||
|
||||
static public function check_install_system_app($app) {
|
||||
if((! is_array(self::$available_apps)) || (! count(self::$available_apps))) {
|
||||
return true;
|
||||
@ -157,14 +172,13 @@ class Apps {
|
||||
return $notfound;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Install the system app if no system apps have been installed, or if a new system app
|
||||
* is discovered, or if the version of a system app changes.
|
||||
* Install the personal app if no personal apps have been installed, or if a new personal app
|
||||
* is discovered, or if the version of a personal app changes.
|
||||
*
|
||||
* @param array $app
|
||||
* @return boolean|int
|
||||
*/
|
||||
|
||||
|
||||
|
||||
static public function check_install_personal_app($app) {
|
||||
$installed = false;
|
||||
foreach(self::$installed_apps as $iapp) {
|
||||
@ -187,20 +201,25 @@ class Apps {
|
||||
return strcasecmp($a['name'],$b['name']);
|
||||
}
|
||||
|
||||
|
||||
static public function parse_app_description($f,$translate = true) {
|
||||
|
||||
$ret = array();
|
||||
/**
|
||||
* @brief Parse app description.
|
||||
*
|
||||
* @param string $f filename
|
||||
* @param boolean $translate (optional) default true
|
||||
* @return boolean|array
|
||||
*/
|
||||
static public function parse_app_description($f, $translate = true) {
|
||||
$ret = [];
|
||||
$matches = [];
|
||||
|
||||
$baseurl = z_root();
|
||||
$channel = \App::get_channel();
|
||||
$address = (($channel) ? $channel['channel_address'] : '');
|
||||
//$channel = \App::get_channel();
|
||||
//$address = (($channel) ? $channel['channel_address'] : '');
|
||||
|
||||
//future expansion
|
||||
|
||||
$observer = \App::get_observer();
|
||||
|
||||
|
||||
$lines = @file($f);
|
||||
if($lines) {
|
||||
foreach($lines as $x) {
|
||||
@ -290,8 +309,10 @@ class Apps {
|
||||
if($ret) {
|
||||
if($translate)
|
||||
self::translate_system_apps($ret);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -299,12 +320,14 @@ class Apps {
|
||||
static public function translate_system_apps(&$arr) {
|
||||
$apps = array(
|
||||
'Apps' => t('Apps'),
|
||||
'Affinity Tool' => t('Affinity Tool'),
|
||||
'Articles' => t('Articles'),
|
||||
'Cards' => t('Cards'),
|
||||
'Admin' => t('Site Admin'),
|
||||
'Report Bug' => t('Report Bug'),
|
||||
'Bookmarks' => t('Bookmarks'),
|
||||
'Chatrooms' => t('Chatrooms'),
|
||||
'Content Filter' => t('Content Filter'),
|
||||
'Connections' => t('Connections'),
|
||||
'Remote Diagnostics' => t('Remote Diagnostics'),
|
||||
'Suggest Channels' => t('Suggest Channels'),
|
||||
@ -369,25 +392,26 @@ class Apps {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// papp is a portable app
|
||||
|
||||
static public function app_render($papp,$mode = 'view') {
|
||||
|
||||
/**
|
||||
* modes:
|
||||
* view: normal mode for viewing an app via bbcode from a conversation or page
|
||||
* @brief
|
||||
*
|
||||
* @param array $papp
|
||||
* papp is a portable app
|
||||
* @param string $mode (optional) default 'view'
|
||||
* Render modes:
|
||||
* * \b view: normal mode for viewing an app via bbcode from a conversation or page
|
||||
* provides install/update button if you're logged in locally
|
||||
* install: like view but does not display app-bin options if they are present
|
||||
* list: normal mode for viewing an app on the app page
|
||||
* * \b install: like view but does not display app-bin options if they are present
|
||||
* * \b list: normal mode for viewing an app on the app page
|
||||
* no buttons are shown
|
||||
* edit: viewing the app page in editing mode provides a delete button
|
||||
* nav: render apps for app-bin
|
||||
* * \b edit: viewing the app page in editing mode provides a delete button
|
||||
* * \b nav: render apps for app-bin
|
||||
*
|
||||
* @return void|string Parsed HTML
|
||||
*/
|
||||
|
||||
static public function app_render($papp, $mode = 'view') {
|
||||
$installed = false;
|
||||
|
||||
if(! $papp)
|
||||
@ -425,7 +449,6 @@ class Apps {
|
||||
$papp['url'] = z_root() . ((strpos($papp['url'],'/') === 0) ? '' : '/') . $papp['url'];
|
||||
|
||||
|
||||
|
||||
foreach($papp as $k => $v) {
|
||||
if(strpos($v,'http') === 0 && $k != 'papp') {
|
||||
if(! (local_channel() && strpos($v,z_root()) === 0)) {
|
||||
@ -590,8 +613,14 @@ class Apps {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static public function can_delete($uid,$app) {
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param mixed $uid If not set return false, otherwise no influence
|
||||
* @param array $app
|
||||
* @return boolean
|
||||
*/
|
||||
static public function can_delete($uid, $app) {
|
||||
if(! $uid) {
|
||||
return false;
|
||||
}
|
||||
@ -599,7 +628,7 @@ class Apps {
|
||||
$base_apps = self::get_base_apps();
|
||||
if($base_apps) {
|
||||
foreach($base_apps as $b) {
|
||||
if($app['guid'] === hash('whirlpool',$b)) {
|
||||
if($app['guid'] === hash('whirlpool', $b)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -611,7 +640,6 @@ class Apps {
|
||||
static public function app_destroy($uid,$app) {
|
||||
|
||||
if($uid && $app['guid']) {
|
||||
|
||||
$x = q("select * from app where app_id = '%s' and app_channel = %d limit 1",
|
||||
dbesc($app['guid']),
|
||||
intval($uid)
|
||||
@ -620,7 +648,7 @@ class Apps {
|
||||
if(! intval($x[0]['app_deleted'])) {
|
||||
$x[0]['app_deleted'] = 1;
|
||||
if(self::can_delete($uid,$app)) {
|
||||
$r = q("delete from app where app_id = '%s' and app_channel = %d",
|
||||
q("delete from app where app_id = '%s' and app_channel = %d",
|
||||
dbesc($app['guid']),
|
||||
intval($uid)
|
||||
);
|
||||
@ -628,10 +656,15 @@ class Apps {
|
||||
intval(TERM_OBJ_APP),
|
||||
intval($x[0]['id'])
|
||||
);
|
||||
/**
|
||||
* @hooks app_destroy
|
||||
* Called after app entry got removed from database
|
||||
* and provide app array from database.
|
||||
*/
|
||||
call_hooks('app_destroy', $x[0]);
|
||||
}
|
||||
else {
|
||||
$r = q("update app set app_deleted = 1 where app_id = '%s' and app_channel = %d",
|
||||
q("update app set app_deleted = 1 where app_id = '%s' and app_channel = %d",
|
||||
dbesc($app['guid']),
|
||||
intval($uid)
|
||||
);
|
||||
@ -645,22 +678,23 @@ class Apps {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static public function app_undestroy($uid,$app) {
|
||||
|
||||
// undelete a system app
|
||||
|
||||
/**
|
||||
* @brief Undelete a system app.
|
||||
*
|
||||
* @param int $uid
|
||||
* @param array $app
|
||||
*/
|
||||
static public function app_undestroy($uid, $app) {
|
||||
if($uid && $app['guid']) {
|
||||
|
||||
$x = q("select * from app where app_id = '%s' and app_channel = %d limit 1",
|
||||
dbesc($app['guid']),
|
||||
intval($uid)
|
||||
);
|
||||
if($x) {
|
||||
if($x[0]['app_system']) {
|
||||
$r = q("update app set app_deleted = 0 where app_id = '%s' and app_channel = %d",
|
||||
q("update app set app_deleted = 0 where app_id = '%s' and app_channel = %d",
|
||||
dbesc($app['guid']),
|
||||
intval($uid)
|
||||
);
|
||||
@ -669,7 +703,15 @@ class Apps {
|
||||
}
|
||||
}
|
||||
|
||||
static public function app_feature($uid,$app,$term) {
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param int $uid
|
||||
* @param array $app
|
||||
* @param string $term
|
||||
* @return void
|
||||
*/
|
||||
static public function app_feature($uid, $app, $term) {
|
||||
$r = q("select id from app where app_id = '%s' and app_channel = %d limit 1",
|
||||
dbesc($app['guid']),
|
||||
intval($uid)
|
||||
@ -693,23 +735,37 @@ class Apps {
|
||||
}
|
||||
}
|
||||
|
||||
static public function app_installed($uid,$app,$bypass_filter=false) {
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param int $uid
|
||||
* @param array $app
|
||||
* @param boolean $bypass_filter (optional) default false
|
||||
* @return boolean
|
||||
*/
|
||||
static public function app_installed($uid, $app, $bypass_filter = false) {
|
||||
|
||||
$r = q("select id from app where app_id = '%s' and app_channel = %d limit 1",
|
||||
dbesc((array_key_exists('guid',$app)) ? $app['guid'] : ''),
|
||||
dbesc((array_key_exists('guid', $app)) ? $app['guid'] : ''),
|
||||
intval($uid)
|
||||
);
|
||||
if (!$bypass_filter) {
|
||||
if(!$bypass_filter) {
|
||||
$filter_arr = [
|
||||
'uid'=>$uid,
|
||||
'app'=>$app,
|
||||
'installed'=>$r
|
||||
'uid' => $uid,
|
||||
'app' => $app,
|
||||
'installed' => $r
|
||||
];
|
||||
call_hooks('app_installed_filter',$filter_arr);
|
||||
/**
|
||||
* @hooks app_installed_filter
|
||||
* * \e int \b uid
|
||||
* * \e array \b app
|
||||
* * \e mixed \b installed - return value
|
||||
*/
|
||||
call_hooks('app_installed_filter', $filter_arr);
|
||||
$r = $filter_arr['installed'];
|
||||
}
|
||||
return(($r) ? true : false);
|
||||
|
||||
return(($r) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
@ -725,11 +781,17 @@ class Apps {
|
||||
'app'=>$app,
|
||||
'installed'=>$r
|
||||
];
|
||||
call_hooks('addon_app_installed_filter',$filter_arr);
|
||||
/**
|
||||
* @hooks addon_app_installed_filter
|
||||
* * \e int \b uid
|
||||
* * \e array \b app
|
||||
* * \e mixed \b installed - return value
|
||||
*/
|
||||
call_hooks('addon_app_installed_filter', $filter_arr);
|
||||
$r = $filter_arr['installed'];
|
||||
}
|
||||
return(($r) ? true : false);
|
||||
|
||||
return(($r) ? true : false);
|
||||
}
|
||||
|
||||
static public function system_app_installed($uid,$app,$bypass_filter=false) {
|
||||
@ -744,28 +806,39 @@ class Apps {
|
||||
'app'=>$app,
|
||||
'installed'=>$r
|
||||
];
|
||||
call_hooks('system_app_installed_filter',$filter_arr);
|
||||
/**
|
||||
* @hooks system_app_installed_filter
|
||||
* * \e int \b uid
|
||||
* * \e array \b app
|
||||
* * \e mixed \b installed - return value
|
||||
*/
|
||||
call_hooks('system_app_installed_filter', $filter_arr);
|
||||
$r = $filter_arr['installed'];
|
||||
}
|
||||
return(($r) ? true : false);
|
||||
|
||||
return(($r) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param int $uid
|
||||
* @param boolean $deleted
|
||||
* @param array $cats
|
||||
* @return boolean|array
|
||||
*/
|
||||
static public function app_list($uid, $deleted = false, $cats = []) {
|
||||
if($deleted)
|
||||
$sql_extra = "";
|
||||
$sql_extra = '';
|
||||
else
|
||||
$sql_extra = " and app_deleted = 0 ";
|
||||
$sql_extra = ' and app_deleted = 0 ';
|
||||
|
||||
if($cats) {
|
||||
|
||||
$cat_sql_extra = " and ( ";
|
||||
$cat_sql_extra = ' and ( ';
|
||||
|
||||
foreach($cats as $cat) {
|
||||
if(strpos($cat_sql_extra, 'term'))
|
||||
$cat_sql_extra .= "or ";
|
||||
$cat_sql_extra .= 'or ';
|
||||
|
||||
$cat_sql_extra .= "term = '" . dbesc($cat) . "' ";
|
||||
}
|
||||
@ -777,11 +850,13 @@ class Apps {
|
||||
);
|
||||
if(! $r)
|
||||
return $r;
|
||||
$sql_extra .= " and app.id in ( ";
|
||||
|
||||
$sql_extra .= ' and app.id in ( ';
|
||||
$s = '';
|
||||
foreach($r as $rr) {
|
||||
if($s)
|
||||
$s .= ',';
|
||||
|
||||
$s .= intval($rr['oid']);
|
||||
}
|
||||
$sql_extra .= $s . ') ';
|
||||
@ -792,12 +867,26 @@ class Apps {
|
||||
);
|
||||
|
||||
if($r) {
|
||||
$hookinfo = Array('uid'=>$uid,'deleted'=>$deleted,'cats'=>$cats,'apps'=>$r);
|
||||
call_hooks('app_list',$hookinfo);
|
||||
$hookinfo = [
|
||||
'uid' => $uid,
|
||||
'deleted' => $deleted,
|
||||
'cats' => $cats,
|
||||
'apps' => $r,
|
||||
];
|
||||
/**
|
||||
* @hooks app_list
|
||||
* * \e int \b uid
|
||||
* * \e boolean \b deleted
|
||||
* * \e array \b cats
|
||||
* * \e array \b apps - return value
|
||||
*/
|
||||
call_hooks('app_list', $hookinfo);
|
||||
$r = $hookinfo['apps'];
|
||||
for($x = 0; $x < count($r); $x ++) {
|
||||
|
||||
for($x = 0; $x < count($r); $x++) {
|
||||
if(! $r[$x]['app_system'])
|
||||
$r[$x]['type'] = 'personal';
|
||||
|
||||
$r[$x]['term'] = q("select * from term where otype = %d and oid = %d",
|
||||
intval(TERM_OBJ_APP),
|
||||
intval($r[$x]['id'])
|
||||
@ -805,7 +894,7 @@ class Apps {
|
||||
}
|
||||
}
|
||||
|
||||
return($r);
|
||||
return $r;
|
||||
}
|
||||
|
||||
static public function app_order($uid,$apps,$menu) {
|
||||
@ -837,13 +926,14 @@ class Apps {
|
||||
$ret[] = $ap;
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
static function find_app_in_array($name,$arr) {
|
||||
if(! $arr)
|
||||
return false;
|
||||
|
||||
foreach($arr as $x) {
|
||||
if($x['name'] === $name) {
|
||||
return $x;
|
||||
@ -852,8 +942,16 @@ class Apps {
|
||||
return false;
|
||||
}
|
||||
|
||||
static function moveup($uid,$guid,$menu) {
|
||||
$syslist = array();
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param int $uid
|
||||
* @param int $guid
|
||||
* @param string $menu
|
||||
* @return void
|
||||
*/
|
||||
static function moveup($uid, $guid, $menu) {
|
||||
$syslist = [];
|
||||
|
||||
$conf = (($menu === 'nav_featured_app') ? 'app_order' : 'app_pin_order');
|
||||
|
||||
@ -863,6 +961,7 @@ class Apps {
|
||||
$papp = self::app_encode($li);
|
||||
if($menu !== 'nav_pinned_app' && strpos($papp['categories'],'nav_pinned_app') !== false)
|
||||
continue;
|
||||
|
||||
$syslist[] = $papp;
|
||||
}
|
||||
}
|
||||
@ -875,8 +974,6 @@ class Apps {
|
||||
if(! $syslist)
|
||||
return;
|
||||
|
||||
$newlist = [];
|
||||
|
||||
foreach($syslist as $k => $li) {
|
||||
if($li['guid'] === $guid) {
|
||||
$position = $k;
|
||||
@ -885,6 +982,7 @@ class Apps {
|
||||
}
|
||||
if(! $position)
|
||||
return;
|
||||
|
||||
$dest_position = $position - 1;
|
||||
$saved = $syslist[$dest_position];
|
||||
$syslist[$dest_position] = $syslist[$position];
|
||||
@ -896,11 +994,18 @@ class Apps {
|
||||
}
|
||||
|
||||
set_pconfig($uid,'system',$conf,implode(',',$narr));
|
||||
|
||||
}
|
||||
|
||||
static function movedown($uid,$guid,$menu) {
|
||||
$syslist = array();
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param int $uid
|
||||
* @param int $guid
|
||||
* @param string $menu
|
||||
* @return void
|
||||
*/
|
||||
static function movedown($uid, $guid, $menu) {
|
||||
$syslist = [];
|
||||
|
||||
$conf = (($menu === 'nav_featured_app') ? 'app_order' : 'app_pin_order');
|
||||
|
||||
@ -910,6 +1015,7 @@ class Apps {
|
||||
$papp = self::app_encode($li);
|
||||
if($menu !== 'nav_pinned_app' && strpos($papp['categories'],'nav_pinned_app') !== false)
|
||||
continue;
|
||||
|
||||
$syslist[] = $papp;
|
||||
}
|
||||
}
|
||||
@ -922,8 +1028,6 @@ class Apps {
|
||||
if(! $syslist)
|
||||
return;
|
||||
|
||||
$newlist = [];
|
||||
|
||||
foreach($syslist as $k => $li) {
|
||||
if($li['guid'] === $guid) {
|
||||
$position = $k;
|
||||
@ -932,6 +1036,7 @@ class Apps {
|
||||
}
|
||||
if($position >= count($syslist) - 1)
|
||||
return;
|
||||
|
||||
$dest_position = $position + 1;
|
||||
$saved = $syslist[$dest_position];
|
||||
$syslist[$dest_position] = $syslist[$position];
|
||||
@ -943,7 +1048,6 @@ class Apps {
|
||||
}
|
||||
|
||||
set_pconfig($uid,'system',$conf,implode(',',$narr));
|
||||
|
||||
}
|
||||
|
||||
static public function app_decode($s) {
|
||||
@ -951,8 +1055,14 @@ class Apps {
|
||||
return json_decode($x,true);
|
||||
}
|
||||
|
||||
|
||||
static public function app_macros($uid,&$arr) {
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param int $uid
|
||||
* @param[in,out] array $arr
|
||||
* @return void
|
||||
*/
|
||||
static public function app_macros($uid, &$arr) {
|
||||
|
||||
if(! intval($uid))
|
||||
return;
|
||||
@ -963,18 +1073,14 @@ class Apps {
|
||||
|
||||
//future expansion
|
||||
|
||||
$observer = \App::get_observer();
|
||||
//$observer = \App::get_observer();
|
||||
|
||||
$arr['url'] = str_replace(array('$baseurl','$nick'),array($baseurl,$address),$arr['url']);
|
||||
$arr['photo'] = str_replace(array('$baseurl','$nick'),array($baseurl,$address),$arr['photo']);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static public function app_store($arr) {
|
||||
|
||||
//logger('app_store: ' . print_r($arr,true));
|
||||
@ -1158,13 +1264,17 @@ class Apps {
|
||||
}
|
||||
|
||||
return $ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static public function app_encode($app,$embed = false) {
|
||||
|
||||
$ret = array();
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param array $app
|
||||
* @param boolean $embed (optional) default false
|
||||
* @return array|string
|
||||
*/
|
||||
static public function app_encode($app, $embed = false) {
|
||||
$ret = [];
|
||||
|
||||
$ret['type'] = 'personal';
|
||||
|
||||
@ -1224,12 +1334,12 @@ class Apps {
|
||||
foreach($app['term'] as $t) {
|
||||
if($s)
|
||||
$s .= ',';
|
||||
|
||||
$s .= $t['term'];
|
||||
}
|
||||
$ret['categories'] = $s;
|
||||
}
|
||||
|
||||
|
||||
if(! $embed)
|
||||
return $ret;
|
||||
|
||||
@ -1239,16 +1349,13 @@ class Apps {
|
||||
unset($ret['categories']);
|
||||
|
||||
$j = json_encode($ret);
|
||||
return '[app]' . chunk_split(base64_encode($j),72,"\n") . '[/app]';
|
||||
|
||||
return '[app]' . chunk_split(base64_encode($j),72,"\n") . '[/app]';
|
||||
}
|
||||
|
||||
|
||||
static public function papp_encode($papp) {
|
||||
return chunk_split(base64_encode(json_encode($papp)),72,"\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -14,6 +14,7 @@ class DReport {
|
||||
$this->location = $location;
|
||||
$this->sender = $sender;
|
||||
$this->recipient = $recipient;
|
||||
$this->name = EMPTY_STR;
|
||||
$this->message_id = $message_id;
|
||||
$this->status = $status;
|
||||
$this->date = datetime_convert();
|
||||
@ -24,8 +25,8 @@ class DReport {
|
||||
$this->date = datetime_convert();
|
||||
}
|
||||
|
||||
function addto_recipient($name) {
|
||||
$this->recipient = $this->recipient . ' ' . $name;
|
||||
function set_name($name) {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
function addto_update($status) {
|
||||
@ -37,6 +38,7 @@ class DReport {
|
||||
$this->location = $arr['location'];
|
||||
$this->sender = $arr['sender'];
|
||||
$this->recipient = $arr['recipient'];
|
||||
$this->name = $arr['name'];
|
||||
$this->message_id = $arr['message_id'];
|
||||
$this->status = $arr['status'];
|
||||
$this->date = $arr['date'];
|
||||
@ -47,9 +49,99 @@ class DReport {
|
||||
'location' => $this->location,
|
||||
'sender' => $this->sender,
|
||||
'recipient' => $this->recipient,
|
||||
'name' => $this->name,
|
||||
'message_id' => $this->message_id,
|
||||
'status' => $this->status,
|
||||
'date' => $this->date
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief decide whether to store a returned delivery report
|
||||
*
|
||||
* @param array $dr
|
||||
* @return boolean
|
||||
*/
|
||||
|
||||
static function is_storable($dr) {
|
||||
|
||||
if(get_config('system', 'disable_dreport'))
|
||||
return false;
|
||||
|
||||
/**
|
||||
* @hooks dreport_is_storable
|
||||
* Called before storing a dreport record to determine whether to store it.
|
||||
* * \e array
|
||||
*/
|
||||
|
||||
call_hooks('dreport_is_storable', $dr);
|
||||
|
||||
// let plugins accept or reject - if neither, continue on
|
||||
if(array_key_exists('accept',$dr) && intval($dr['accept']))
|
||||
return true;
|
||||
if(array_key_exists('reject',$dr) && intval($dr['reject']))
|
||||
return false;
|
||||
|
||||
if(! ($dr['sender']))
|
||||
return false;
|
||||
|
||||
// Is the sender one of our channels?
|
||||
|
||||
$c = q("select channel_id from channel where channel_hash = '%s' or channel_portable_id = '%s' limit 1",
|
||||
dbesc($dr['sender']),
|
||||
dbesc($dr['sender'])
|
||||
);
|
||||
|
||||
if(! $c)
|
||||
return false;
|
||||
|
||||
// legacy zot recipients add a space and their name to the xchan. remove it if true.
|
||||
|
||||
$legacy_recipient = strpos($dr['recipient'], ' ');
|
||||
if($legacy_recipient !== false) {
|
||||
$legacy_recipient_parts = explode(' ', $dr['recipient'], 2);
|
||||
$rxchan = $legacy_recipient_parts[0];
|
||||
}
|
||||
else {
|
||||
$rxchan = $dr['recipient'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
// is the recipient one of our connections, or do we want to store every report?
|
||||
|
||||
$pcf = get_pconfig($c[0]['channel_id'],'system','dreport_store_all');
|
||||
if($pcf)
|
||||
return true;
|
||||
|
||||
// We always add ourself as a recipient to private and relayed posts
|
||||
// So if a remote site says they can't find us, that's no big surprise
|
||||
// and just creates a lot of extra report noise
|
||||
|
||||
if(($dr['location'] !== z_root()) && ($dr['sender'] === $rxchan) && ($dr['status'] === 'recipient_not_found'))
|
||||
return false;
|
||||
|
||||
// If you have a private post with a recipient list, every single site is going to report
|
||||
// back a failed delivery for anybody on that list that isn't local to them. We're only
|
||||
// concerned about this if we have a local hubloc record which says we expected them to
|
||||
// have a channel on that site.
|
||||
|
||||
$r = q("select hubloc_id from hubloc where hubloc_hash = '%s' and hubloc_url = '%s'",
|
||||
dbesc($rxchan),
|
||||
dbesc($dr['location'])
|
||||
);
|
||||
if((! $r) && ($dr['status'] === 'recipient_not_found'))
|
||||
return false;
|
||||
|
||||
$r = q("select abook_id from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
|
||||
dbesc($rxchan),
|
||||
intval($c[0]['channel_id'])
|
||||
);
|
||||
if($r)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -2,15 +2,13 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
|
||||
class JSalmon {
|
||||
|
||||
static function sign($data,$key_id,$key) {
|
||||
static function sign($data,$key_id,$key,$data_type = 'application/x-zot+json') {
|
||||
|
||||
$arr = $data;
|
||||
$data = json_encode($data,JSON_UNESCAPED_SLASHES);
|
||||
$data = base64url_encode($data, false); // do not strip padding
|
||||
$data_type = 'application/x-zot+json';
|
||||
$data = base64url_encode(json_encode($data,true),true); // strip padding
|
||||
$encoding = 'base64url';
|
||||
$algorithm = 'RSA-SHA256';
|
||||
|
||||
@ -18,9 +16,9 @@ class JSalmon {
|
||||
|
||||
// precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
|
||||
|
||||
$precomputed = '.' . base64url_encode($data_type,false) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
|
||||
$precomputed = '.' . base64url_encode($data_type,true) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng';
|
||||
|
||||
$signature = base64url_encode(rsa_sign($data . $precomputed, $key), false);
|
||||
$signature = base64url_encode(rsa_sign($data . $precomputed, $key), true);
|
||||
|
||||
return ([
|
||||
'signed' => true,
|
||||
@ -30,9 +28,45 @@ class JSalmon {
|
||||
'alg' => $algorithm,
|
||||
'sigs' => [
|
||||
'value' => $signature,
|
||||
'key_id' => base64url_encode($key_id)
|
||||
'key_id' => base64url_encode($key_id, true)
|
||||
]
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
static function verify($x) {
|
||||
|
||||
logger('verify');
|
||||
$ret = [ 'results' => [] ];
|
||||
|
||||
if(! is_array($x)) {
|
||||
return $false;
|
||||
}
|
||||
if(! ( array_key_exists('signed',$x) && $x['signed'])) {
|
||||
return $false;
|
||||
}
|
||||
|
||||
$signed_data = preg_replace('/\s+/','',$x['data']) . '.'
|
||||
. base64url_encode($x['data_type'],true) . '.'
|
||||
. base64url_encode($x['encoding'],true) . '.'
|
||||
. base64url_encode($x['alg'],true);
|
||||
|
||||
$key = HTTPSig::get_key(EMPTY_STR,base64url_decode($x['sigs']['key_id']));
|
||||
logger('key: ' . print_r($key,true));
|
||||
if($key['portable_id'] && $key['public_key']) {
|
||||
if(rsa_verify($signed_data,base64url_decode($x['sigs']['value']),$key['public_key'])) {
|
||||
logger('verified');
|
||||
$ret = [ 'success' => true, 'signer' => $key['portable_id'], 'hubloc' => $key['hubloc'] ];
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
|
||||
}
|
||||
|
||||
static function unpack($data) {
|
||||
return json_decode(base64url_decode($data),true);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -2,11 +2,6 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
/**
|
||||
* @brief lowlevel implementation of Zot6 protocol.
|
||||
*
|
||||
*/
|
||||
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Access\Permissions;
|
||||
use Zotlabs\Access\PermissionLimits;
|
||||
@ -14,14 +9,17 @@ use Zotlabs\Daemon\Master;
|
||||
|
||||
require_once('include/crypto.php');
|
||||
|
||||
|
||||
/**
|
||||
* @brief Lowlevel implementation of Zot6 protocol.
|
||||
*
|
||||
*/
|
||||
class Libzot {
|
||||
|
||||
/**
|
||||
* @brief Generates a unique string for use as a zot guid.
|
||||
*
|
||||
* Generates a unique string for use as a zot guid using our DNS-based url, the
|
||||
* channel nickname and some entropy.
|
||||
* Generates a unique string for use as a zot guid using our DNS-based url,
|
||||
* the channel nickname and some entropy.
|
||||
* The entropy ensures uniqueness against re-installs where the same URL and
|
||||
* nickname are chosen.
|
||||
*
|
||||
@ -32,9 +30,8 @@ class Libzot {
|
||||
* immediate universe.
|
||||
*
|
||||
* @param string $channel_nick a unique nickname of controlling entity
|
||||
* @returns string
|
||||
* @return string
|
||||
*/
|
||||
|
||||
static function new_uid($channel_nick) {
|
||||
$rawstr = z_root() . '/' . $channel_nick . '.' . mt_rand();
|
||||
return(base64url_encode(hash('whirlpool', $rawstr, true), true));
|
||||
@ -52,8 +49,8 @@ class Libzot {
|
||||
*
|
||||
* @param string $guid
|
||||
* @param string $pubkey
|
||||
* @return string
|
||||
*/
|
||||
|
||||
static function make_xchan_hash($guid, $pubkey) {
|
||||
return base64url_encode(hash('whirlpool', $guid . $pubkey, true));
|
||||
}
|
||||
@ -65,10 +62,8 @@ class Libzot {
|
||||
* should only be used by channels which are defined on this hub.
|
||||
*
|
||||
* @param string $hash - xchan_hash
|
||||
* @returns array of hubloc (hub location structures)
|
||||
*
|
||||
* @return array of hubloc (hub location structures)
|
||||
*/
|
||||
|
||||
static function get_hublocs($hash) {
|
||||
|
||||
/* Only search for active hublocs - e.g. those that haven't been marked deleted */
|
||||
@ -92,16 +87,17 @@ class Libzot {
|
||||
* packet type: one of 'ping', 'pickup', 'purge', 'refresh', 'keychange', 'force_refresh', 'notify', 'auth_check'
|
||||
* @param array $recipients
|
||||
* envelope recipients, array of portable_id's; empty for public posts
|
||||
* @param string msg
|
||||
* @param string $msg
|
||||
* optional message
|
||||
* @param string $encoding
|
||||
* optional encoding, default 'activitystreams'
|
||||
* @param string $remote_key
|
||||
* optional public site key of target hub used to encrypt entire packet
|
||||
* NOTE: remote_key and encrypted packets are required for 'auth_check' packets, optional for all others
|
||||
* @param string $methods
|
||||
* optional comma separated list of encryption methods @ref self::best_algorithm()
|
||||
* optional comma separated list of encryption methods @ref best_algorithm()
|
||||
* @returns string json encoded zot packet
|
||||
*/
|
||||
|
||||
static function build_packet($channel, $type = 'activity', $recipients = null, $msg = '', $encoding = 'activitystreams', $remote_key = null, $methods = '') {
|
||||
|
||||
$sig_method = get_config('system','signature_algorithm','sha256');
|
||||
@ -109,7 +105,7 @@ class Libzot {
|
||||
$data = [
|
||||
'type' => $type,
|
||||
'encoding' => $encoding,
|
||||
'sender' => $channel['channel_hash'],
|
||||
'sender' => $channel['channel_portable_id'],
|
||||
'site_id' => self::make_xchan_hash(z_root(), get_config('system','pubkey')),
|
||||
'version' => System::get_zot_revision(),
|
||||
];
|
||||
@ -146,11 +142,10 @@ class Libzot {
|
||||
* @brief Choose best encryption function from those available on both sites.
|
||||
*
|
||||
* @param string $methods
|
||||
* comma separated list of encryption methods
|
||||
* Comma separated list of encryption methods
|
||||
* @return string first match from our site method preferences crypto_methods() array
|
||||
* of a method which is common to both sites; or 'aes256cbc' if no matches are found.
|
||||
*/
|
||||
|
||||
static function best_algorithm($methods) {
|
||||
|
||||
$x = [
|
||||
@ -164,7 +159,6 @@ class Libzot {
|
||||
* * \e string \b methods - comma separated list of encryption methods
|
||||
* * \e string \b result - the algorithm to return
|
||||
*/
|
||||
|
||||
call_hooks('zot_best_algorithm', $x);
|
||||
|
||||
if($x['result'])
|
||||
@ -190,7 +184,7 @@ class Libzot {
|
||||
|
||||
|
||||
/**
|
||||
* @brief send a zot message
|
||||
* @brief Send a zot message.
|
||||
*
|
||||
* @see z_post_url()
|
||||
*
|
||||
@ -200,7 +194,6 @@ class Libzot {
|
||||
* @param array $crypto (required if encrypted httpsig, requires hubloc_sitekey and site_crypto elements)
|
||||
* @return array see z_post_url() for returned data format
|
||||
*/
|
||||
|
||||
static function zot($url, $data, $channel = null,$crypto = null) {
|
||||
|
||||
if($channel) {
|
||||
@ -227,7 +220,6 @@ class Libzot {
|
||||
/**
|
||||
* @brief Refreshes after permission changed or friending, etc.
|
||||
*
|
||||
*
|
||||
* refresh is typically invoked when somebody has changed permissions of a channel and they are notified
|
||||
* to fetch new permissions via a finger/discovery operation. This may result in a new connection
|
||||
* (abook entry) being added to a local channel and it may result in auto-permissions being granted.
|
||||
@ -251,7 +243,6 @@ class Libzot {
|
||||
* * \b true if successful
|
||||
* * otherwise \b false
|
||||
*/
|
||||
|
||||
static function refresh($them, $channel = null, $force = false) {
|
||||
|
||||
logger('them: ' . print_r($them,true), LOGGER_DATA, LOG_DEBUG);
|
||||
@ -271,7 +262,7 @@ class Libzot {
|
||||
// correct hubloc. If this doesn't work we may have to re-write this section to try them all.
|
||||
|
||||
if(array_key_exists('xchan_addr',$them) && $them['xchan_addr']) {
|
||||
$r = q("select hubloc_id_url, hubloc_primary from hubloc where hubloc_addr = '%s' order by hubloc_id desc",
|
||||
$r = q("select hubloc_id_url, hubloc_primary from hubloc where hubloc_addr = '%s' and hubloc_network = 'zot6' order by hubloc_id desc",
|
||||
dbesc($them['xchan_addr'])
|
||||
);
|
||||
}
|
||||
@ -317,7 +308,7 @@ class Libzot {
|
||||
|
||||
if(! $hsig_valid) {
|
||||
logger('http signature not valid: ' . print_r($hsig,true));
|
||||
return $result;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -329,8 +320,14 @@ class Libzot {
|
||||
return false;
|
||||
|
||||
if($channel && $record['data']['permissions']) {
|
||||
$old_read_stream_perm = their_perms_contains($channel['channel_id'],$x['hash'],'view_stream');
|
||||
set_abconfig($channel['channel_id'],$x['hash'],'system','their_perms',$record['data']['permissions']);
|
||||
$permissions = explode(',',$record['data']['permissions']);
|
||||
if($permissions && is_array($permissions)) {
|
||||
$old_read_stream_perm = get_abconfig($channel['channel_id'],$x['hash'],'their_perms','view_stream');
|
||||
|
||||
foreach($permissions as $p) {
|
||||
set_abconfig($channel['channel_id'],$x['hash'],'their_perms',$p,'1');
|
||||
}
|
||||
}
|
||||
|
||||
if(array_key_exists('profile',$record['data']) && array_key_exists('next_birthday',$record['data']['profile'])) {
|
||||
$next_birthday = datetime_convert('UTC','UTC',$record['data']['profile']['next_birthday']);
|
||||
@ -379,19 +376,19 @@ class Libzot {
|
||||
else {
|
||||
|
||||
$p = Permissions::connect_perms($channel['channel_id']);
|
||||
$my_perms = Permissions::serialise($p['perms']);
|
||||
$my_perms = $p['perms'];
|
||||
|
||||
$automatic = $p['automatic'];
|
||||
|
||||
// new connection
|
||||
|
||||
if($my_perms) {
|
||||
set_abconfig($channel['channel_id'],$x['hash'],'system','my_perms',$my_perms);
|
||||
foreach($my_perms as $k => $v) {
|
||||
set_abconfig($channel['channel_id'],$x['hash'],'my_perms',$k,$v);
|
||||
}
|
||||
}
|
||||
|
||||
$closeness = get_pconfig($channel['channel_id'],'system','new_abook_closeness');
|
||||
if($closeness === false)
|
||||
$closeness = 80;
|
||||
$closeness = get_pconfig($channel['channel_id'],'system','new_abook_closeness',80);
|
||||
|
||||
$y = abook_store_lowlevel(
|
||||
[
|
||||
@ -409,7 +406,7 @@ class Libzot {
|
||||
|
||||
if($y) {
|
||||
logger("New introduction received for {$channel['channel_name']}");
|
||||
$new_perms = get_all_perms($channel['channel_id'],$x['hash']);
|
||||
$new_perms = get_all_perms($channel['channel_id'],$x['hash'],false);
|
||||
|
||||
// Send a clone sync packet and a permissions update if permissions have changed
|
||||
|
||||
@ -425,7 +422,7 @@ class Libzot {
|
||||
[
|
||||
'type' => NOTIFY_INTRO,
|
||||
'from_xchan' => $x['hash'],
|
||||
'to_xchan' => $channel['channel_hash'],
|
||||
'to_xchan' => $channel['channel_portable_id'],
|
||||
'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id']
|
||||
]
|
||||
);
|
||||
@ -500,6 +497,7 @@ class Libzot {
|
||||
$r = q("select hubloc.*, site.site_crypto from hubloc left join site on hubloc_url = site_url
|
||||
where hubloc_guid = '%s' and hubloc_guid_sig = '%s'
|
||||
and hubloc_url = '%s' and hubloc_url_sig = '%s'
|
||||
and hubloc_network = 'zot6'
|
||||
and hubloc_site_id = '%s' $limit",
|
||||
dbesc($arr['id']),
|
||||
dbesc($arr['id_sig']),
|
||||
@ -517,10 +515,14 @@ class Libzot {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static function valid_hub($sender,$site_id) {
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param string $sender
|
||||
* @param string $site_id
|
||||
* @return null|array
|
||||
*/
|
||||
static function valid_hub($sender, $site_id) {
|
||||
|
||||
$r = q("select hubloc.*, site.site_crypto from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and hubloc_site_id = '%s' limit 1",
|
||||
dbesc($sender),
|
||||
@ -541,7 +543,6 @@ class Libzot {
|
||||
}
|
||||
|
||||
return $r[0];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -552,21 +553,14 @@ class Libzot {
|
||||
* origination address. This will fetch the discovery packet of the sender,
|
||||
* which contains the public key we need to verify our guid and url signatures.
|
||||
*
|
||||
* @param array $arr an associative array which must contain:
|
||||
* * \e string \b guid => guid of conversant
|
||||
* * \e string \b guid_sig => guid signed with conversant's private key
|
||||
* * \e string \b url => URL of the origination hub of this communication
|
||||
* * \e string \b url_sig => URL signed with conversant's private key
|
||||
* @param string $id
|
||||
*
|
||||
* @return array An associative array with
|
||||
* * \b success boolean true or false
|
||||
* * \b message (optional) error string only if success is false
|
||||
* * \e boolean \b success
|
||||
* * \e string \b message (optional, unused) error string only if success is false
|
||||
*/
|
||||
|
||||
static function register_hub($id) {
|
||||
|
||||
$id_hash = false;
|
||||
$valid = false;
|
||||
$hsig_valid = false;
|
||||
|
||||
$result = [ 'success' => false ];
|
||||
@ -691,9 +685,27 @@ class Libzot {
|
||||
$adult_changed = 1;
|
||||
if(intval($r[0]['xchan_deleted']) != intval($arr['deleted']))
|
||||
$deleted_changed = 1;
|
||||
|
||||
// new style 6-MAR-2019
|
||||
|
||||
if(array_key_exists('channel_type',$arr)) {
|
||||
if($arr['channel_type'] === 'collection') {
|
||||
// do nothing at this time.
|
||||
}
|
||||
elseif($arr['channel_type'] === 'group') {
|
||||
$arr['public_forum'] = 1;
|
||||
}
|
||||
else {
|
||||
$arr['public_forum'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// old style
|
||||
|
||||
if(intval($r[0]['xchan_pubforum']) != intval($arr['public_forum']))
|
||||
$pubforum_changed = 1;
|
||||
|
||||
|
||||
if($arr['protocols']) {
|
||||
$protocols = implode(',',$arr['protocols']);
|
||||
if($protocols !== 'zot6') {
|
||||
@ -776,7 +788,7 @@ class Libzot {
|
||||
|
||||
// see if this is a channel clone that's hosted locally - which we treat different from other xchans/connections
|
||||
|
||||
$local = q("select channel_account_id, channel_id from channel where channel_hash = '%s' limit 1",
|
||||
$local = q("select channel_account_id, channel_id from channel where channel_portable_id = '%s' limit 1",
|
||||
dbesc($xchan_hash)
|
||||
);
|
||||
if($local) {
|
||||
@ -947,8 +959,8 @@ class Libzot {
|
||||
* @param string $hub - url of site we just contacted
|
||||
* @param array $arr - output of z_post_url()
|
||||
* @param array $outq - The queue structure attached to this request
|
||||
* @return void
|
||||
*/
|
||||
|
||||
static function process_response($hub, $arr, $outq) {
|
||||
|
||||
logger('remote: ' . print_r($arr,true),LOGGER_DATA);
|
||||
@ -966,6 +978,7 @@ class Libzot {
|
||||
}
|
||||
|
||||
$x = crypto_unencapsulate($x, get_config('system','prvkey'));
|
||||
|
||||
if(! is_array($x)) {
|
||||
$x = json_decode($x,true);
|
||||
}
|
||||
@ -987,16 +1000,26 @@ class Libzot {
|
||||
}
|
||||
|
||||
if(is_array($x) && array_key_exists('delivery_report',$x) && is_array($x['delivery_report'])) {
|
||||
|
||||
foreach($x['delivery_report'] as $xx) {
|
||||
call_hooks('dreport_process',$xx);
|
||||
if(is_array($xx) && array_key_exists('message_id',$xx) && DReport::is_storable($xx)) {
|
||||
|
||||
// legacy recipients add a space and their name to the xchan. split those if true.
|
||||
$legacy_recipient = strpos($xx['recipient'], ' ');
|
||||
if($legacy_recipient !== false) {
|
||||
$legacy_recipient_parts = explode(' ', $xx['recipient'], 2);
|
||||
$xx['recipient'] = $legacy_recipient_parts[0];
|
||||
$xx['name'] = $legacy_recipient_parts[1];
|
||||
}
|
||||
|
||||
q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s', '%s','%s','%s','%s','%s' ) ",
|
||||
dbesc($xx['message_id']),
|
||||
dbesc($xx['location']),
|
||||
dbesc($xx['recipient']),
|
||||
dbesc($xx['name']),
|
||||
dbesc($xx['status']),
|
||||
dbesc(datetime_convert($xx['date'])),
|
||||
dbesc(datetime_convert('UTC','UTC',$xx['date'])),
|
||||
dbesc($xx['sender'])
|
||||
);
|
||||
}
|
||||
@ -1065,11 +1088,6 @@ class Libzot {
|
||||
*
|
||||
* @param array $arr
|
||||
* 'pickup' structure returned from remote site
|
||||
* @param string $sender_url
|
||||
* the url specified by the sender in the initial communication.
|
||||
* We will verify the sender and url in each returned message structure and
|
||||
* also verify that all the messages returned match the site url that we are
|
||||
* currently processing.
|
||||
*
|
||||
* @returns array
|
||||
* Suitable for logging remotely, enumerating the processing results of each message/recipient combination
|
||||
@ -1077,7 +1095,6 @@ class Libzot {
|
||||
* * [1] => \e string $delivery_status
|
||||
* * [2] => \e string $address
|
||||
*/
|
||||
|
||||
static function import($arr) {
|
||||
|
||||
$env = $arr;
|
||||
@ -1108,9 +1125,14 @@ class Libzot {
|
||||
logger('Activity rejected: ' . print_r($data,true));
|
||||
return;
|
||||
}
|
||||
if (is_array($AS->obj)) {
|
||||
$arr = Activity::decode_note($AS);
|
||||
}
|
||||
else {
|
||||
$arr = [];
|
||||
}
|
||||
|
||||
logger($AS->debug());
|
||||
logger($AS->debug(),LOGGER_DATA);
|
||||
}
|
||||
|
||||
|
||||
@ -1129,7 +1151,7 @@ class Libzot {
|
||||
if($recip_arr) {
|
||||
stringify_array_elms($recip_arr,true);
|
||||
$recips = implode(',',$recip_arr);
|
||||
$r = q("select channel_hash as hash from channel where channel_hash in ( " . $recips . " ) and channel_removed = 0 ");
|
||||
$r = q("select channel_portable_id as hash from channel where channel_portable_id in ( " . $recips . " ) and channel_removed = 0 ");
|
||||
}
|
||||
|
||||
if(! $r) {
|
||||
@ -1157,7 +1179,6 @@ class Libzot {
|
||||
|
||||
$deliveries = self::public_recips($env,$AS);
|
||||
|
||||
|
||||
}
|
||||
|
||||
$deliveries = array_unique($deliveries);
|
||||
@ -1176,7 +1197,7 @@ class Libzot {
|
||||
|
||||
//logger($AS->debug());
|
||||
|
||||
$r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1",
|
||||
$r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
|
||||
dbesc($AS->actor['id'])
|
||||
);
|
||||
|
||||
@ -1185,7 +1206,7 @@ class Libzot {
|
||||
}
|
||||
|
||||
|
||||
$s = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1",
|
||||
$s = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
|
||||
dbesc($env['sender'])
|
||||
);
|
||||
|
||||
@ -1200,7 +1221,7 @@ class Libzot {
|
||||
if($private) {
|
||||
$arr['item_private'] = true;
|
||||
}
|
||||
// @fixme - spoofable
|
||||
/// @FIXME - spoofable
|
||||
if($AS->data['hubloc']) {
|
||||
$arr['item_verified'] = true;
|
||||
}
|
||||
@ -1214,7 +1235,7 @@ class Libzot {
|
||||
|
||||
$relay = (($env['type'] === 'response') ? true : false );
|
||||
|
||||
$result = self::process_delivery($env['sender'],$arr,$deliveries,$relay,false,$message_request);
|
||||
$result = self::process_delivery($env['sender'],$AS,$arr,$deliveries,$relay,false,$message_request);
|
||||
}
|
||||
elseif($env['type'] === 'sync') {
|
||||
// $arr = get_channelsync_elements($data);
|
||||
@ -1234,7 +1255,14 @@ class Libzot {
|
||||
}
|
||||
|
||||
|
||||
static function is_top_level($env,$act) {
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param array $env
|
||||
* @param object $act
|
||||
* @return boolean
|
||||
*/
|
||||
static function is_top_level($env, $act) {
|
||||
if($env['encoding'] === 'zot' && array_key_exists('flags',$env) && in_array('thread_parent', $env['flags'])) {
|
||||
return true;
|
||||
}
|
||||
@ -1277,9 +1305,9 @@ class Libzot {
|
||||
* Some of these will be rejected, but this gives us a place to start.
|
||||
*
|
||||
* @param array $msg
|
||||
* @return NULL|array
|
||||
* @param object $act
|
||||
* @return array
|
||||
*/
|
||||
|
||||
static function public_recips($msg, $act) {
|
||||
|
||||
require_once('include/channel.php');
|
||||
@ -1303,12 +1331,12 @@ class Libzot {
|
||||
|
||||
$r = [];
|
||||
|
||||
$c = q("select channel_id, channel_hash from channel where channel_removed = 0");
|
||||
$c = q("select channel_id, channel_portable_id from channel where channel_removed = 0");
|
||||
|
||||
if($c) {
|
||||
foreach($c as $cc) {
|
||||
if(perm_is_allowed($cc['channel_id'],$msg['sender'],$perm)) {
|
||||
$r[] = $cc['channel_hash'];
|
||||
$r[] = $cc['channel_portable_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1316,7 +1344,7 @@ class Libzot {
|
||||
if($include_sys) {
|
||||
$sys = get_sys_channel();
|
||||
if($sys)
|
||||
$r[] = $sys['channel_hash'];
|
||||
$r[] = $sys['channel_portable_id'];
|
||||
}
|
||||
|
||||
|
||||
@ -1332,7 +1360,7 @@ class Libzot {
|
||||
if($tag['type'] === 'Mention' && (strpos($tag['href'],z_root()) !== false)) {
|
||||
$address = basename($tag['href']);
|
||||
if($address) {
|
||||
$z = q("select channel_hash as hash from channel where channel_address = '%s'
|
||||
$z = q("select channel_portable_id as hash from channel where channel_address = '%s'
|
||||
and channel_removed = 0 limit 1",
|
||||
dbesc($address)
|
||||
);
|
||||
@ -1353,7 +1381,7 @@ class Libzot {
|
||||
$thread_parent = self::find_parent($msg,$act);
|
||||
|
||||
if($thread_parent) {
|
||||
$z = q("select channel_hash as hash from channel left join item on channel.channel_id = item.uid where ( item.thr_parent = '%s' OR item.parent_mid = '%s' ) ",
|
||||
$z = q("select channel_portable_id as hash from channel left join item on channel.channel_id = item.uid where ( item.thr_parent = '%s' OR item.parent_mid = '%s' ) ",
|
||||
dbesc($thread_parent),
|
||||
dbesc($thread_parent)
|
||||
);
|
||||
@ -1380,7 +1408,7 @@ class Libzot {
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param array $sender
|
||||
* @param string $sender
|
||||
* @param array $arr
|
||||
* @param array $deliveries
|
||||
* @param boolean $relay
|
||||
@ -1389,7 +1417,7 @@ class Libzot {
|
||||
* @return array
|
||||
*/
|
||||
|
||||
static function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $request = false) {
|
||||
static function process_delivery($sender, $act, $arr, $deliveries, $relay, $public = false, $request = false) {
|
||||
|
||||
$result = [];
|
||||
|
||||
@ -1408,7 +1436,7 @@ class Libzot {
|
||||
|
||||
$DR = new DReport(z_root(),$sender,$d,$arr['mid']);
|
||||
|
||||
$channel = channelx_by_hash($d);
|
||||
$channel = channelx_by_portid($d);
|
||||
|
||||
if (! $channel) {
|
||||
$DR->update('recipient not found');
|
||||
@ -1418,6 +1446,24 @@ class Libzot {
|
||||
|
||||
$DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
|
||||
|
||||
if(($act) && ($act->obj) && (! is_array($act->obj))) {
|
||||
// The initial object fetch failed using the sys channel credentials.
|
||||
// Try again using the delivery channel credentials.
|
||||
// We will also need to re-parse the $item array,
|
||||
// but preserve any values that were set during anonymous parsing.
|
||||
|
||||
$o = Activity::fetch($act->obj,$channel);
|
||||
if($o) {
|
||||
$act->obj = $o;
|
||||
$arr = array_merge(Activity::decode_note($act),$arr);
|
||||
}
|
||||
else {
|
||||
$DR->update('Incomplete or corrupt activity');
|
||||
$result[] = $DR->get();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to block normal top-level message delivery from our clones, as the delivered
|
||||
* message doesn't have ACL information in it as the cloned copy does. That copy
|
||||
@ -1427,7 +1473,7 @@ class Libzot {
|
||||
* access checks.
|
||||
*/
|
||||
|
||||
if($sender === $channel['channel_hash'] && $arr['author_xchan'] === $channel['channel_hash'] && $arr['mid'] === $arr['parent_mid']) {
|
||||
if($sender === $channel['channel_portable_id'] && $arr['author_xchan'] === $channel['channel_portable_id'] && $arr['mid'] === $arr['parent_mid']) {
|
||||
$DR->update('self delivery ignored');
|
||||
$result[] = $DR->get();
|
||||
continue;
|
||||
@ -1479,11 +1525,34 @@ class Libzot {
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
if ($parent) {
|
||||
$allowed = can_comment_on_post($d,$parent[0]);
|
||||
$allowed = can_comment_on_post($sender,$parent[0]);
|
||||
}
|
||||
}
|
||||
if($request) {
|
||||
|
||||
if ($request) {
|
||||
|
||||
// Conversation fetches (e.g. $request == true) take place for
|
||||
// a) new comments on expired posts
|
||||
// b) hyperdrive (friend-of-friend) conversations
|
||||
// c) Repeats of posts by others
|
||||
|
||||
|
||||
// over-ride normal connection permissions for hyperdrive (friend-of-friend) conversations
|
||||
// (if hyperdrive is enabled) and repeated posts by a friend.
|
||||
// If $allowed is already true, this is probably the conversation of a direct friend or a
|
||||
// conversation fetch for a new comment on an expired post
|
||||
// Comments of all these activities are allowed and will only be rejected (later) if the parent
|
||||
// doesn't exist.
|
||||
|
||||
if ($perm === 'send_stream') {
|
||||
if (get_pconfig($channel['channel_id'],'system','hyperdrive',false) || $arr['verb'] === ACTIVITY_SHARE) {
|
||||
$allowed = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$allowed = true;
|
||||
}
|
||||
|
||||
$friendofriend = true;
|
||||
}
|
||||
|
||||
@ -1495,7 +1564,11 @@ class Libzot {
|
||||
}
|
||||
}
|
||||
|
||||
if($arr['mid'] != $arr['parent_mid']) {
|
||||
// logger('item: ' . print_r($arr,true), LOGGER_DATA);
|
||||
|
||||
if($arr['mid'] !== $arr['parent_mid']) {
|
||||
|
||||
logger('checking source: "' . $arr['mid'] . '" != "' . $arr['parent_mid'] . '"');
|
||||
|
||||
// check source route.
|
||||
// We are only going to accept comments from this sender if the comment has the same route as the top-level-post,
|
||||
@ -1517,10 +1590,7 @@ class Libzot {
|
||||
// have the copy and we don't want the request to loop.
|
||||
// Also don't do this if this comment came from a conversation request packet.
|
||||
// It's possible that comments are allowed but posting isn't and that could
|
||||
// cause a conversation fetch loop. We can detect these packets since they are
|
||||
// delivered via a 'notify' packet type that has a message_id element in the
|
||||
// initial zot packet (just like the corresponding 'request' packet type which
|
||||
// makes the request).
|
||||
// cause a conversation fetch loop.
|
||||
// We'll also check the send_stream permission - because if it isn't allowed,
|
||||
// the top level post is unlikely to be imported and
|
||||
// this is just an exercise in futility.
|
||||
@ -1709,7 +1779,7 @@ class Libzot {
|
||||
|
||||
$stored = (($item_result && $item_result['item']) ? $item_result['item'] : false);
|
||||
if((is_array($stored)) && ($stored['id'] != $stored['parent'])
|
||||
&& ($stored['author_xchan'] === $channel['channel_hash'])) {
|
||||
&& ($stored['author_xchan'] === $channel['channel_hash'] || $stored['author_xchan'] === $channel['channel_portable_id'])) {
|
||||
retain_item($stored['item']['parent']);
|
||||
}
|
||||
|
||||
@ -1759,14 +1829,14 @@ class Libzot {
|
||||
logger($AS->debug());
|
||||
|
||||
|
||||
$r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1",
|
||||
$r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
|
||||
dbesc($AS->actor['id'])
|
||||
);
|
||||
|
||||
if(! $r) {
|
||||
$y = import_author_xchan([ 'url' => $AS->actor['id'] ]);
|
||||
if($y) {
|
||||
$r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1",
|
||||
$r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
|
||||
dbesc($AS->actor['id'])
|
||||
);
|
||||
}
|
||||
@ -1789,7 +1859,7 @@ class Libzot {
|
||||
$arr['author_xchan'] = $r[0]['hubloc_hash'];
|
||||
}
|
||||
|
||||
$s = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1",
|
||||
$s = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
|
||||
dbesc($a['signature']['signer'])
|
||||
);
|
||||
|
||||
@ -1800,7 +1870,8 @@ class Libzot {
|
||||
$arr['owner_xchan'] = $a['signature']['signer'];
|
||||
}
|
||||
|
||||
// @fixme - spoofable
|
||||
|
||||
/// @FIXME - spoofable
|
||||
if($AS->data['hubloc']) {
|
||||
$arr['item_verified'] = true;
|
||||
}
|
||||
@ -1809,9 +1880,9 @@ class Libzot {
|
||||
}
|
||||
|
||||
logger('FOF Activity received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
|
||||
logger('FOF Activity recipient: ' . $channel['channel_hash'], LOGGER_DATA, LOG_DEBUG);
|
||||
logger('FOF Activity recipient: ' . $channel['channel_portable_id'], LOGGER_DATA, LOG_DEBUG);
|
||||
|
||||
$result = self::process_delivery($arr['owner_xchan'],$arr, [ $channel['channel_hash'] ],false,false,true);
|
||||
$result = self::process_delivery($arr['owner_xchan'],$AS, $arr, [ $channel['channel_portable_id'] ],false,false,true);
|
||||
if ($result) {
|
||||
$ret = array_merge($ret, $result);
|
||||
}
|
||||
@ -1824,15 +1895,14 @@ class Libzot {
|
||||
/**
|
||||
* @brief Remove community tag.
|
||||
*
|
||||
* @param array $sender an associative array with
|
||||
* * \e string \b hash a xchan_hash
|
||||
* @param string $sender
|
||||
* @param array $arr an associative array
|
||||
* * \e int \b verb
|
||||
* * \e int \b obj_type
|
||||
* * \e int \b mid
|
||||
* @param int $uid
|
||||
* @return void
|
||||
*/
|
||||
|
||||
static function remove_community_tag($sender, $arr, $uid) {
|
||||
|
||||
if(! (activity_match($arr['verb'], ACTIVITY_TAG) && ($arr['obj_type'] == ACTIVITY_OBJ_TAGTERM)))
|
||||
@ -1898,13 +1968,13 @@ class Libzot {
|
||||
*
|
||||
* @see item_store_update()
|
||||
*
|
||||
* @param array $sender
|
||||
* @param string $sender
|
||||
* @param array $item
|
||||
* @param array $orig
|
||||
* @param int $uid
|
||||
* @param boolean $tag_delivery
|
||||
* @return void|array
|
||||
*/
|
||||
|
||||
static function update_imported_item($sender, $item, $orig, $uid, $tag_delivery) {
|
||||
|
||||
// If this is a comment being updated, remove any privacy information
|
||||
@ -1949,7 +2019,7 @@ class Libzot {
|
||||
/**
|
||||
* @brief Deletes an imported item.
|
||||
*
|
||||
* @param array $sender
|
||||
* @param string $sender
|
||||
* * \e string \b hash a xchan_hash
|
||||
* @param array $item
|
||||
* @param int $uid
|
||||
@ -1967,9 +2037,9 @@ class Libzot {
|
||||
|
||||
$r = q("select id, author_xchan, owner_xchan, source_xchan, item_deleted from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' )
|
||||
and mid = '%s' and uid = %d limit 1",
|
||||
dbesc($sender['hash']),
|
||||
dbesc($sender['hash']),
|
||||
dbesc($sender['hash']),
|
||||
dbesc($sender),
|
||||
dbesc($sender),
|
||||
dbesc($sender),
|
||||
dbesc($item['mid']),
|
||||
intval($uid)
|
||||
);
|
||||
@ -2047,7 +2117,7 @@ class Libzot {
|
||||
|
||||
$DR = new DReport(z_root(),$sender,$d,$arr['mid']);
|
||||
|
||||
$r = q("select * from channel where channel_hash = '%s' limit 1",
|
||||
$r = q("select * from channel where channel_portable_id = '%s' limit 1",
|
||||
dbesc($d['hash'])
|
||||
);
|
||||
|
||||
@ -2123,18 +2193,18 @@ class Libzot {
|
||||
* @brief Processes delivery of profile.
|
||||
*
|
||||
* @see import_directory_profile()
|
||||
* @param array $sender an associative array
|
||||
* * \e string \b hash a xchan_hash
|
||||
*
|
||||
* @param string $sender
|
||||
* @param array $arr
|
||||
* @param array $deliveries (unused)
|
||||
* @return void
|
||||
*/
|
||||
|
||||
static function process_profile_delivery($sender, $arr, $deliveries) {
|
||||
|
||||
logger('process_profile_delivery', LOGGER_DEBUG);
|
||||
|
||||
$r = q("select xchan_addr from xchan where xchan_hash = '%s' limit 1",
|
||||
dbesc($sender['hash'])
|
||||
dbesc($sender)
|
||||
);
|
||||
if($r) {
|
||||
Libzotdir::import_directory_profile($sender, $arr, $r[0]['xchan_addr'], UPDATE_FLAGS_UPDATED, 0);
|
||||
@ -2145,10 +2215,10 @@ class Libzot {
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param array $sender an associative array
|
||||
* * \e string \b hash a xchan_hash
|
||||
* @param string $sender
|
||||
* @param array $arr
|
||||
* @param array $deliveries (unused) deliveries is irrelevant
|
||||
* @return void
|
||||
*/
|
||||
static function process_location_delivery($sender, $arr, $deliveries) {
|
||||
|
||||
@ -2166,7 +2236,7 @@ class Libzot {
|
||||
$x = Libsync::sync_locations($xchan,$arr,true);
|
||||
logger('results: ' . print_r($x,true), LOGGER_DEBUG);
|
||||
if($x['changed']) {
|
||||
$guid = random_string() . '@' . App::get_hostname();
|
||||
//$guid = random_string() . '@' . App::get_hostname();
|
||||
Libzotdir::update_modtime($sender,$r[0]['xchan_guid'],$arr['locations'][0]['address'],UPDATE_FLAGS_UPDATED);
|
||||
}
|
||||
}
|
||||
@ -2190,8 +2260,8 @@ class Libzot {
|
||||
*
|
||||
* @param string $sender_hash A channel hash
|
||||
* @param array $locations
|
||||
* @return void
|
||||
*/
|
||||
|
||||
static function check_location_move($sender_hash, $locations) {
|
||||
|
||||
if(! $locations)
|
||||
@ -2202,7 +2272,7 @@ class Libzot {
|
||||
|
||||
$loc = $locations[0];
|
||||
|
||||
$r = q("select * from channel where channel_hash = '%s' limit 1",
|
||||
$r = q("select * from channel where channel_portable_id = '%s' limit 1",
|
||||
dbesc($sender_hash)
|
||||
);
|
||||
|
||||
@ -2210,7 +2280,7 @@ class Libzot {
|
||||
return;
|
||||
|
||||
if($loc['url'] !== z_root()) {
|
||||
$x = q("update channel set channel_moved = '%s' where channel_hash = '%s' limit 1",
|
||||
$x = q("update channel set channel_moved = '%s' where channel_portable_id = '%s' limit 1",
|
||||
dbesc($loc['url']),
|
||||
dbesc($sender_hash)
|
||||
);
|
||||
@ -2233,7 +2303,6 @@ class Libzot {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns an array with all known distinct hubs for this channel.
|
||||
*
|
||||
@ -2242,11 +2311,10 @@ class Libzot {
|
||||
* * \e string \b channel_hash the hash of the channel
|
||||
* @return array an array with associative arrays
|
||||
*/
|
||||
|
||||
static function encode_locations($channel) {
|
||||
$ret = [];
|
||||
|
||||
$x = self::get_hublocs($channel['channel_hash']);
|
||||
$x = self::get_hublocs($channel['channel_portable_id']);
|
||||
|
||||
if($x && count($x)) {
|
||||
foreach($x as $hub) {
|
||||
@ -2296,10 +2364,8 @@ class Libzot {
|
||||
* @brief
|
||||
*
|
||||
* @param array $arr
|
||||
* @param string $pubkey
|
||||
* @return boolean true if updated or inserted
|
||||
*/
|
||||
|
||||
static function import_site($arr) {
|
||||
|
||||
if( (! is_array($arr)) || (! $arr['url']) || (! $arr['site_sig']))
|
||||
@ -2557,6 +2623,9 @@ class Libzot {
|
||||
|
||||
static function zotinfo($arr) {
|
||||
|
||||
logger('arr: ' . print_r($arr,true));
|
||||
|
||||
|
||||
$ret = [];
|
||||
|
||||
$zhash = ((x($arr,'guid_hash')) ? $arr['guid_hash'] : '');
|
||||
@ -2571,7 +2640,7 @@ class Libzot {
|
||||
$feed = ((x($arr,'feed')) ? intval($arr['feed']) : 0);
|
||||
|
||||
if($ztarget) {
|
||||
$t = q("select * from hubloc where hubloc_id_url = '%s' limit 1",
|
||||
$t = q("select * from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
|
||||
dbesc($ztarget)
|
||||
);
|
||||
if($t) {
|
||||
@ -2593,13 +2662,13 @@ class Libzot {
|
||||
$r = null;
|
||||
|
||||
if(strlen($zhash)) {
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
|
||||
where channel_hash = '%s' limit 1",
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
|
||||
where channel_portable_id = '%s' limit 1",
|
||||
dbesc($zhash)
|
||||
);
|
||||
}
|
||||
elseif(strlen($zguid) && strlen($zguid_sig)) {
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
|
||||
where channel_guid = '%s' and channel_guid_sig = '%s' limit 1",
|
||||
dbesc($zguid),
|
||||
dbesc($zguid_sig)
|
||||
@ -2607,7 +2676,7 @@ class Libzot {
|
||||
}
|
||||
elseif(strlen($zaddr)) {
|
||||
if(strpos($zaddr,'[system]') === false) { /* normal address lookup */
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
|
||||
where ( channel_address = '%s' or xchan_addr = '%s' ) limit 1",
|
||||
dbesc($zaddr),
|
||||
dbesc($zaddr)
|
||||
@ -2627,10 +2696,10 @@ class Libzot {
|
||||
*
|
||||
*/
|
||||
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
|
||||
where channel_system = 1 order by channel_id limit 1");
|
||||
if(! $r) {
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
|
||||
$r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
|
||||
where channel_removed = 0 order by channel_id limit 1");
|
||||
}
|
||||
}
|
||||
@ -2749,7 +2818,7 @@ class Libzot {
|
||||
];
|
||||
|
||||
$ret['channel_role'] = get_pconfig($e['channel_id'],'system','permissions_role','custom');
|
||||
$ret['protocols'] = [ 'zot6' ];
|
||||
$ret['protocols'] = [ 'zot', 'zot6' ];
|
||||
$ret['searchable'] = $searchable;
|
||||
$ret['adult_content'] = $adult_channel;
|
||||
$ret['public_forum'] = $public_forum;
|
||||
@ -2774,7 +2843,7 @@ class Libzot {
|
||||
if(! $ret['follow_url'])
|
||||
$ret['follow_url'] = z_root() . '/follow?f=&url=%s';
|
||||
|
||||
$permissions = get_all_perms($e['channel_id'],$ztarget_hash,false);
|
||||
$permissions = get_all_perms($e['channel_id'],$ztarget_hash,false,false);
|
||||
|
||||
if($ztarget_hash) {
|
||||
$permissions['connected'] = false;
|
||||
@ -2811,14 +2880,20 @@ class Libzot {
|
||||
$ret['locations'] = $x;
|
||||
|
||||
$ret['site'] = self::site_info();
|
||||
/**
|
||||
* @hooks zotinfo
|
||||
* Hook to manipulate the zotinfo array before it is returned.
|
||||
*/
|
||||
call_hooks('zotinfo', $ret);
|
||||
|
||||
call_hooks('zotinfo',$ret);
|
||||
|
||||
return($ret);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get siteinfo.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static function site_info() {
|
||||
|
||||
$signing_key = get_config('system','prvkey');
|
||||
@ -2902,18 +2977,16 @@ class Libzot {
|
||||
}
|
||||
|
||||
return $ret['site'];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param array $hub
|
||||
* @param string $sitekey (optional, default empty)
|
||||
* @param string $site_id (optional, default empty)
|
||||
*
|
||||
* @return string hubloc_url
|
||||
*/
|
||||
|
||||
static function update_hub_connected($hub, $site_id = '') {
|
||||
|
||||
if ($site_id) {
|
||||
@ -2972,12 +3045,21 @@ class Libzot {
|
||||
return $hub['hubloc_url'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param string $data
|
||||
* @param string $key
|
||||
* @param string $alg (optional) default 'sha256'
|
||||
* @return string
|
||||
*/
|
||||
static function sign($data,$key,$alg = 'sha256') {
|
||||
if(! $key)
|
||||
return 'no key';
|
||||
|
||||
$sig = '';
|
||||
openssl_sign($data,$sig,$key,$alg);
|
||||
|
||||
return $alg . '.' . base64url_encode($sig);
|
||||
}
|
||||
|
||||
@ -3003,11 +3085,14 @@ class Libzot {
|
||||
return(($verify > 0) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
static function is_zot_request() {
|
||||
|
||||
$x = getBestSupportedMimeType([ 'application/x-zot+json' ]);
|
||||
|
||||
return(($x) ? true : false);
|
||||
}
|
||||
|
||||
|
@ -40,26 +40,17 @@ class NativeWiki {
|
||||
|
||||
function create_wiki($channel, $observer_hash, $wiki, $acl) {
|
||||
|
||||
// Generate unique resource_id using the same method as item_message_id()
|
||||
do {
|
||||
$dups = false;
|
||||
$resource_id = random_string();
|
||||
$r = q("SELECT mid FROM item WHERE resource_id = '%s' AND resource_type = '%s' AND uid = %d LIMIT 1",
|
||||
dbesc($resource_id),
|
||||
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
|
||||
intval($channel['channel_id'])
|
||||
);
|
||||
if($r)
|
||||
$dups = true;
|
||||
} while($dups == true);
|
||||
$resource_id = new_uuid();
|
||||
$uuid = new_uuid();
|
||||
|
||||
$ac = $acl->get();
|
||||
$mid = item_message_id();
|
||||
$mid = z_root() . '/item/' . $uuid;
|
||||
|
||||
$arr = array(); // Initialize the array of parameters for the post
|
||||
$item_hidden = ((intval($wiki['postVisible']) === 0) ? 1 : 0);
|
||||
$wiki_url = z_root() . '/wiki/' . $channel['channel_address'] . '/' . $wiki['urlName'];
|
||||
$arr['aid'] = $channel['channel_account_id'];
|
||||
$arr['uuid'] = $uuid;
|
||||
$arr['uid'] = $channel['channel_id'];
|
||||
$arr['mid'] = $mid;
|
||||
$arr['parent_mid'] = $mid;
|
||||
|
@ -112,9 +112,11 @@ class PConfig {
|
||||
* The configuration key to set
|
||||
* @param string $value
|
||||
* The value to store
|
||||
* @param string $updated (optional)
|
||||
* The datetime to store
|
||||
* @return mixed Stored $value or false
|
||||
*/
|
||||
static public function Set($uid, $family, $key, $value, $updated=NULL) {
|
||||
static public function Set($uid, $family, $key, $value, $updated = NULL) {
|
||||
|
||||
// this catches subtle errors where this function has been called
|
||||
// with local_channel() when not logged in (which returns false)
|
||||
@ -131,14 +133,19 @@ class PConfig {
|
||||
$dbvalue = ((is_array($value)) ? serialize($value) : $value);
|
||||
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
|
||||
|
||||
$now = datetime_convert();
|
||||
if (! $updated) {
|
||||
$updated = datetime_convert();
|
||||
//Sometimes things happen fast... very fast.
|
||||
//To make sure legitimate updates aren't rejected
|
||||
//because not enough time has passed. We say our updates
|
||||
//happened just a short time in the past rather than right now.
|
||||
$updated = datetime_convert('UTC','UTC','-2 seconds');
|
||||
}
|
||||
|
||||
$hash = hash('sha256',$family.':'.$key);
|
||||
|
||||
if (self::Get($uid, 'hz_delpconfig', $hash) !== false) {
|
||||
if (self::Get($uid, 'hz_delpconfig', $hash) > $updated) {
|
||||
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 {
|
||||
@ -173,7 +180,7 @@ class PConfig {
|
||||
|
||||
}
|
||||
else {
|
||||
$new = (\App::$config[$uid][$family]['pcfgud:'.$key] < $updated);
|
||||
$new = (\App::$config[$uid][$family]['pcfgud:'.$key] < $now);
|
||||
|
||||
if ($new) {
|
||||
|
||||
@ -234,16 +241,18 @@ class PConfig {
|
||||
* The category of the configuration value
|
||||
* @param string $key
|
||||
* The configuration key to delete
|
||||
* @return mixed
|
||||
* @param string $updated (optional)
|
||||
* The datetime to store
|
||||
* @return boolean
|
||||
*/
|
||||
static public function Delete($uid, $family, $key, $updated = NULL) {
|
||||
|
||||
if(is_null($uid) || $uid === false)
|
||||
return false;
|
||||
|
||||
$updated = ($updated) ? $updated : datetime_convert();
|
||||
|
||||
$newer = (\App::$config[$uid][$family]['pcfgud:'.$key] < $updated);
|
||||
$updated = ($updated) ? $updated : datetime_convert('UTC','UTC','-2 seconds');
|
||||
$now = datetime_convert();
|
||||
$newer = (\App::$config[$uid][$family]['pcfgud:'.$key] < $now);
|
||||
|
||||
if (! $newer) {
|
||||
logger('Refusing to delete pconfig with outdated delete request.', LOGGER_NORMAL, LOG_ERR);
|
||||
@ -266,22 +275,13 @@ class PConfig {
|
||||
dbesc($key)
|
||||
);
|
||||
|
||||
// Synchronize delete with clones.
|
||||
|
||||
if ($family != 'hz_delpconfig') {
|
||||
$hash = hash('sha256',$family.':'.$key);
|
||||
set_pconfig($uid,'hz_delpconfig',$hash,$updated);
|
||||
}
|
||||
|
||||
// Synchronize delete with 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 ($new) {
|
||||
\App::$config[$uid]['transient'][$family]['pcfgdel:'.$key] = $updated;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,7 @@ class Share {
|
||||
if(! $this->item)
|
||||
return $obj;
|
||||
|
||||
$obj['asld'] = $this->item['mid'];
|
||||
$obj['type'] = $this->item['obj_type'];
|
||||
$obj['id'] = $this->item['mid'];
|
||||
$obj['content'] = $this->item['body'];
|
||||
|
@ -39,6 +39,8 @@ class ThreadItem {
|
||||
$this->data = $data;
|
||||
$this->toplevel = ($this->get_id() == $this->get_data_value('parent'));
|
||||
|
||||
$observer = \App::get_observer();
|
||||
|
||||
// Prepare the children
|
||||
if($data['children']) {
|
||||
foreach($data['children'] as $item) {
|
||||
@ -51,6 +53,7 @@ class ThreadItem {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$child = new ThreadItem($item);
|
||||
$this->add_child($child);
|
||||
}
|
||||
@ -73,7 +76,7 @@ class ThreadItem {
|
||||
* _ false on failure
|
||||
*/
|
||||
|
||||
public function get_template_data($conv_responses, $thread_level=1) {
|
||||
public function get_template_data($conv_responses, $thread_level=1, $conv_flags = []) {
|
||||
|
||||
$result = array();
|
||||
|
||||
@ -98,6 +101,7 @@ class ThreadItem {
|
||||
|| strlen($item['deny_cid']) || strlen($item['deny_gid']))))
|
||||
? t('Private Message')
|
||||
: false);
|
||||
|
||||
$shareable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && ($item['item_private'] != 1)) ? true : false);
|
||||
|
||||
// allow an exemption for sharing stuff from your private feeds
|
||||
@ -112,6 +116,19 @@ class ThreadItem {
|
||||
$privacy_warning = true;
|
||||
}
|
||||
|
||||
if ($lock) {
|
||||
if (($item['mid'] == $item['parent_mid']) && count(get_terms_oftype($item['term'],TERM_FORUM))) {
|
||||
$privacy_warning = true;
|
||||
$conv_flags['parent_privacy_warning'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$privacy_warning = (isset($conv_flags['parent_privacy_warning'])) ? $conv_flags['parent_privacy_warning'] : $privacy_warning;
|
||||
|
||||
if ($lock && $privacy_warning) {
|
||||
$lock = t('Privacy conflict. Discretion advised.');
|
||||
}
|
||||
|
||||
$mode = $conv->get_mode();
|
||||
|
||||
switch($item['item_type']) {
|
||||
@ -290,8 +307,15 @@ class ThreadItem {
|
||||
$dislike = array( t("I don't like this \x28toggle\x29"), t("dislike"));
|
||||
}
|
||||
|
||||
if ($shareable)
|
||||
$share = array( t('Share This'), t('share'));
|
||||
if ($shareable) {
|
||||
// This actually turns out not to be possible in some protocol stacks without opening up hundreds of new issues.
|
||||
// Will allow it only for uri resolvable sources.
|
||||
if(strpos($item['mid'],'http') === 0) {
|
||||
$share = []; //Not yet ready for primetime
|
||||
//$share = array( t('Repeat This'), t('repeat'));
|
||||
}
|
||||
$embed = array( t('Share This'), t('share'));
|
||||
}
|
||||
|
||||
$dreport = '';
|
||||
|
||||
@ -299,8 +323,10 @@ class ThreadItem {
|
||||
if($keep_reports === 0)
|
||||
$keep_reports = 10;
|
||||
|
||||
if((! get_config('system','disable_dreport')) && strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC',"now - $keep_reports days")) > 0)
|
||||
if((! get_config('system','disable_dreport')) && strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC',"now - $keep_reports days")) > 0) {
|
||||
$dreport = t('Delivery Report');
|
||||
$dreport_link = gen_link_id($item['mid']);
|
||||
}
|
||||
|
||||
if(strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC','now - 12 hours')) > 0)
|
||||
$is_new = true;
|
||||
@ -316,7 +342,7 @@ class ThreadItem {
|
||||
$owner_address = substr($item['owner']['xchan_addr'],0,strpos($item['owner']['xchan_addr'],'@'));
|
||||
$viewthread = $item['llink'];
|
||||
if($conv->get_mode() === 'channel')
|
||||
$viewthread = z_root() . '/channel/' . $owner_address . '?f=&mid=' . urlencode($item['mid']);
|
||||
$viewthread = z_root() . '/channel/' . $owner_address . '?f=&mid=' . urlencode(gen_link_id($item['mid']));
|
||||
|
||||
$comment_count_txt = sprintf( tt('%d comment','%d comments',$total_children),$total_children );
|
||||
$list_unseen_txt = (($unseen_comments) ? sprintf('%d unseen',$unseen_comments) : '');
|
||||
@ -364,6 +390,7 @@ class ThreadItem {
|
||||
'thread_action_menu' => thread_action_menu($item,$conv->get_mode()),
|
||||
'thread_author_menu' => thread_author_menu($item,$conv->get_mode()),
|
||||
'dreport' => $dreport,
|
||||
'dreport_link' => $dreport_link,
|
||||
'name' => $profile_name,
|
||||
'thumb' => $profile_avatar,
|
||||
'osparkle' => $osparkle,
|
||||
@ -402,12 +429,13 @@ class ThreadItem {
|
||||
'like' => $like,
|
||||
'dislike' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike : ''),
|
||||
'share' => $share,
|
||||
'embed' => $embed,
|
||||
'rawmid' => $item['mid'],
|
||||
'plink' => get_plink($item),
|
||||
'edpost' => $edpost, // ((feature_enabled($conv->get_profile_owner(),'edit_posts')) ? $edpost : ''),
|
||||
'star' => ((feature_enabled($conv->get_profile_owner(),'star_posts')) ? $star : ''),
|
||||
'star' => ((feature_enabled($conv->get_profile_owner(),'star_posts') && ($item['item_type'] == ITEM_TYPE_POST)) ? $star : ''),
|
||||
'tagger' => ((feature_enabled($conv->get_profile_owner(),'commtag')) ? $tagger : ''),
|
||||
'filer' => ((feature_enabled($conv->get_profile_owner(),'filing')) ? $filer : ''),
|
||||
'filer' => ((feature_enabled($conv->get_profile_owner(),'filing') && ($item['item_type'] == ITEM_TYPE_POST)) ? $filer : ''),
|
||||
'bookmark' => (($conv->get_profile_owner() == local_channel() && local_channel() && $has_bookmarks) ? t('Save Bookmarks') : ''),
|
||||
'addtocal' => (($has_event) ? t('Add to Calendar') : ''),
|
||||
'drop' => $drop,
|
||||
@ -464,7 +492,7 @@ class ThreadItem {
|
||||
|
||||
if(($this->get_display_mode() === 'normal') && ($nb_children > 0)) {
|
||||
foreach($children as $child) {
|
||||
$result['children'][] = $child->get_template_data($conv_responses, $thread_level + 1);
|
||||
$result['children'][] = $child->get_template_data($conv_responses, $thread_level + 1,$conv_flags);
|
||||
}
|
||||
// Collapse
|
||||
if(($nb_children > $visible_comments) || ($thread_level > 1)) {
|
||||
|
53
Zotlabs/Lib/ThreadListener.php
Normal file
53
Zotlabs/Lib/ThreadListener.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
class ThreadListener {
|
||||
|
||||
static public function store($target_id,$portable_id,$ltype = 0) {
|
||||
$x = self::fetch($target_id,$portable_id,$ltype = 0);
|
||||
if(! $x) {
|
||||
$r = q("insert into listeners ( target_id, portable_id, ltype ) values ( '%s', '%s' , %d ) ",
|
||||
dbesc($target_id),
|
||||
dbesc($portable_id),
|
||||
intval($ltype)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static public function fetch($target_id,$portable_id,$ltype = 0) {
|
||||
$x = q("select * from listeners where target_id = '%s' and portable_id = '%s' and ltype = %d limit 1",
|
||||
dbesc($target_id),
|
||||
dbesc($portable_id),
|
||||
intval($ltype)
|
||||
);
|
||||
if($x) {
|
||||
return $x[0];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static public function fetch_by_target($target_id,$ltype = 0) {
|
||||
$x = q("select * from listeners where target_id = '%s' and ltype = %d",
|
||||
dbesc($target_id),
|
||||
intval($ltype)
|
||||
);
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
static public function delete_by_target($target_id, $ltype = 0) {
|
||||
return q("delete from listeners where target_id = '%s' and ltype = %d",
|
||||
dbesc($target_id),
|
||||
intval($ltype)
|
||||
);
|
||||
}
|
||||
|
||||
static public function delete_by_pid($portable_id, $ltype = 0) {
|
||||
return q("delete from listeners where portable_id = '%s' and ltype = %d",
|
||||
dbesc($portable_id),
|
||||
intval($ltype)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
91
Zotlabs/Lib/ZotURL.php
Normal file
91
Zotlabs/Lib/ZotURL.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
|
||||
|
||||
class ZotURL {
|
||||
|
||||
static public function fetch($url,$channel) {
|
||||
|
||||
$ret = [ 'success' => false ];
|
||||
|
||||
if(strpos($url,'x-zot:') !== 0) {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
if(! $url) {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$portable_url = substr($url,6);
|
||||
$u = explode('/',$portable_url);
|
||||
$portable_id = $u[0];
|
||||
|
||||
$hosts = self::lookup($portable_id);
|
||||
|
||||
if(! $hosts) {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
foreach($hosts as $h) {
|
||||
$newurl = $h . '/id/' . $portable_url;
|
||||
|
||||
$m = parse_url($newurl);
|
||||
|
||||
$data = json_encode([ 'zot_token' => random_string() ]);
|
||||
|
||||
if($channel && $m) {
|
||||
|
||||
$headers = [
|
||||
'Accept' => 'application/x-zot+json',
|
||||
'Content-Type' => 'application/x-zot+json',
|
||||
'X-Zot-Token' => random_string(),
|
||||
'Digest' => HTTPSig::generate_digest_header($data),
|
||||
'Host' => $m['host'],
|
||||
'(request-target)' => 'post ' . get_request_string($newurl)
|
||||
];
|
||||
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false);
|
||||
}
|
||||
else {
|
||||
$h = [ 'Accept: application/x-zot+json' ];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
$redirects = 0;
|
||||
$x = z_post_url($newurl,$data,$redirects, [ 'headers' => $h ] );
|
||||
if($x['success']) {
|
||||
return $x;
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
|
||||
}
|
||||
|
||||
static public function is_zoturl($s) {
|
||||
|
||||
if(strpos($url,'x-zot:') === 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static public function lookup($portable_id) {
|
||||
|
||||
$r = q("select * from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and site_dead = 0 order by hubloc_primary desc",
|
||||
dbesc($portable_id)
|
||||
);
|
||||
|
||||
if(! $r) {
|
||||
// extend to network lookup
|
||||
return false;
|
||||
}
|
||||
return ids_to_array($r,'hubloc_url');
|
||||
}
|
||||
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Zotlabs\Lib;
|
||||
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
|
||||
class Zotfinger {
|
||||
|
||||
@ -12,10 +12,19 @@ class Zotfinger {
|
||||
return false;
|
||||
}
|
||||
|
||||
if($channel) {
|
||||
$m = parse_url($resource);
|
||||
|
||||
$data = json_encode([ 'zot_token' => random_string() ]);
|
||||
|
||||
if($channel && $m) {
|
||||
|
||||
$headers = [
|
||||
'Accept' => 'application/x-zot+json',
|
||||
'Content-Type' => 'application/x-zot+json',
|
||||
'X-Zot-Token' => random_string(),
|
||||
'Digest' => HTTPSig::generate_digest_header($data),
|
||||
'Host' => $m['host'],
|
||||
'(request-target)' => 'post ' . get_request_string($resource)
|
||||
];
|
||||
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false);
|
||||
}
|
||||
@ -27,7 +36,9 @@ class Zotfinger {
|
||||
|
||||
|
||||
$redirects = 0;
|
||||
$x = z_fetch_url($resource,false,$redirects, [ 'headers' => $h ] );
|
||||
$x = z_post_url($resource,$data,$redirects, [ 'headers' => $h ] );
|
||||
|
||||
logger('fetch: ' . print_r($x,true));
|
||||
|
||||
if($x['success']) {
|
||||
|
||||
@ -39,6 +50,8 @@ class Zotfinger {
|
||||
$result['data'] = json_decode(crypto_unencapsulate($result['data'],get_config('system','prvkey')),true);
|
||||
}
|
||||
|
||||
logger('decrypted: ' . print_r($result,true));
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ class Admin extends \Zotlabs\Web\Controller {
|
||||
|
||||
// list total user accounts, expirations etc.
|
||||
$accounts = array();
|
||||
$r = q("SELECT COUNT(*) AS total, COUNT(CASE WHEN account_expires > %s THEN 1 ELSE NULL END) AS expiring, COUNT(CASE WHEN account_expires < %s AND account_expires > '%s' THEN 1 ELSE NULL END) AS expired, COUNT(CASE WHEN (account_flags & %d)>0 THEN 1 ELSE NULL END) AS blocked FROM account",
|
||||
$r = q("SELECT COUNT(CASE WHEN account_id > 0 THEN 1 ELSE NULL END) AS total, COUNT(CASE WHEN account_expires > %s THEN 1 ELSE NULL END) AS expiring, COUNT(CASE WHEN account_expires < %s AND account_expires > '%s' THEN 1 ELSE NULL END) AS expired, COUNT(CASE WHEN (account_flags & %d)>0 THEN 1 ELSE NULL END) AS blocked FROM account",
|
||||
db_utcnow(),
|
||||
db_utcnow(),
|
||||
dbesc(NULL_DATE),
|
||||
|
@ -375,6 +375,9 @@ class Addons {
|
||||
if($files) {
|
||||
foreach($files as $file) {
|
||||
if (is_dir($file)){
|
||||
if($file == 'addon/addon_common/')
|
||||
continue;
|
||||
|
||||
list($tmp, $id) = array_map('trim', explode('/', $file));
|
||||
$info = get_plugin_info($id);
|
||||
$enabled = in_array($id,\App::$plugins);
|
||||
|
@ -119,7 +119,7 @@ class Site {
|
||||
del_config('system', 'admininfo');
|
||||
} else {
|
||||
require_once('include/text.php');
|
||||
linkify_tags($a, $admininfo, local_channel());
|
||||
linkify_tags($admininfo, local_channel());
|
||||
set_config('system', 'admininfo', $admininfo);
|
||||
}
|
||||
set_config('system','siteinfo',$siteinfo);
|
||||
|
94
Zotlabs/Module/Affinity.php
Normal file
94
Zotlabs/Module/Affinity.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Lib\Apps;
|
||||
use Zotlabs\Lib\Libsync;
|
||||
|
||||
class Affinity extends \Zotlabs\Web\Controller {
|
||||
|
||||
function post() {
|
||||
|
||||
if(! local_channel())
|
||||
return;
|
||||
|
||||
if(! Apps::system_app_installed(local_channel(),'Affinity Tool'))
|
||||
return;
|
||||
|
||||
check_form_security_token_redirectOnErr('affinity', 'affinity');
|
||||
|
||||
$cmax = intval($_POST['affinity_cmax']);
|
||||
if($cmax < 0 || $cmax > 99)
|
||||
$cmax = 99;
|
||||
|
||||
$cmin = intval($_POST['affinity_cmin']);
|
||||
if($cmin < 0 || $cmin > 99)
|
||||
$cmin = 0;
|
||||
|
||||
$lock = intval($_POST['affinity_lock']);
|
||||
|
||||
set_pconfig(local_channel(),'affinity','cmin',$cmin);
|
||||
set_pconfig(local_channel(),'affinity','cmax',$cmax);
|
||||
set_pconfig(local_channel(),'affinity','lock',$lock);
|
||||
|
||||
info( t('Affinity Tool settings updated.') . EOL);
|
||||
|
||||
Libsync::build_sync_packet();
|
||||
|
||||
}
|
||||
|
||||
|
||||
function get() {
|
||||
|
||||
if(! local_channel())
|
||||
return;
|
||||
|
||||
$desc = t('This app presents a slider control in your connection editor and also on your network page. The slider represents your degree of friendship (affinity) with each connection. It allows you to zoom in or out and display conversations from only your closest friends or everybody in your stream.');
|
||||
if(! Apps::system_app_installed(local_channel(),'Affinity Tool')) {
|
||||
//Do not display any associated widgets at this point
|
||||
App::$pdl = '';
|
||||
|
||||
$o = '<b>' . t('Affinity Tool App') . ' (' . t('Not Installed') . '):</b><br>';
|
||||
$o .= $desc;
|
||||
return $o;
|
||||
}
|
||||
|
||||
$text = t('The numbers below represent the minimum and maximum slider default positions for your network/stream page as a percentage.');
|
||||
|
||||
$content = '<div class="section-content-info-wrapper">' . $text . '</div>';
|
||||
|
||||
$cmax = intval(get_pconfig(local_channel(),'affinity','cmax'));
|
||||
$cmax = (($cmax) ? $cmax : 99);
|
||||
$content .= replace_macros(get_markup_template('field_input.tpl'), array(
|
||||
'$field' => array('affinity_cmax', t('Default maximum affinity level'), $cmax, t('0-99 default 99'))
|
||||
));
|
||||
|
||||
$cmin = intval(get_pconfig(local_channel(),'affinity','cmin'));
|
||||
$cmin = (($cmin) ? $cmin : 0);
|
||||
$content .= replace_macros(get_markup_template('field_input.tpl'), array(
|
||||
'$field' => array('affinity_cmin', t('Default minimum affinity level'), $cmin, t('0-99 - default 0'))
|
||||
));
|
||||
|
||||
$lock = intval(get_pconfig(local_channel(),'affinity','lock',1));
|
||||
|
||||
$content .= replace_macros(get_markup_template('field_checkbox.tpl'), array(
|
||||
'$field' => array('affinity_lock', t('Persistent affinity levels'), $lock, t('If disabled the max and min levels will be reset to default after page reload'), ['No','Yes'])
|
||||
));
|
||||
|
||||
$tpl = get_markup_template("settings_addon.tpl");
|
||||
|
||||
$o = replace_macros($tpl, array(
|
||||
'$action_url' => 'affinity',
|
||||
'$form_security_token' => get_form_security_token("affinity"),
|
||||
'$title' => t('Affinity Tool Settings'),
|
||||
'$content' => $content,
|
||||
'$baseurl' => z_root(),
|
||||
'$submit' => t('Submit'),
|
||||
));
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -10,9 +10,13 @@ require_once('include/channel.php');
|
||||
require_once('include/conversation.php');
|
||||
require_once('include/acl_selectors.php');
|
||||
|
||||
/**
|
||||
* @brief Provides the Cards module.
|
||||
*
|
||||
*/
|
||||
class Cards extends Controller {
|
||||
|
||||
function init() {
|
||||
public function init() {
|
||||
|
||||
if(argc() > 1)
|
||||
$which = argv(1);
|
||||
@ -20,14 +24,15 @@ class Cards extends Controller {
|
||||
return;
|
||||
|
||||
profile_load($which);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see \Zotlabs\Web\Controller::get()
|
||||
* @see \\Zotlabs\\Web\\Controller::get()
|
||||
*
|
||||
* @return string Parsed HTML from template 'cards.tpl'
|
||||
*/
|
||||
function get($update = 0, $load = false) {
|
||||
public function get($update = 0, $load = false) {
|
||||
|
||||
if(observer_prohibited(true)) {
|
||||
return login();
|
||||
@ -99,7 +104,6 @@ class Cards extends Controller {
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(perm_is_allowed($owner, $ob_hash, 'write_pages')) {
|
||||
|
||||
$x = [
|
||||
|
@ -6,6 +6,8 @@ namespace Zotlabs\Module;
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\PermissionDescription;
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
|
||||
require_once('include/items.php');
|
||||
require_once('include/security.php');
|
||||
@ -43,6 +45,48 @@ class Channel extends Controller {
|
||||
$profile = 0;
|
||||
$channel = App::get_channel();
|
||||
|
||||
if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
|
||||
$which = $channel['channel_address'];
|
||||
$profile = argv(1);
|
||||
}
|
||||
|
||||
$channel = channelx_by_nick($which);
|
||||
if(! $channel) {
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
|
||||
// handle zot6 channel discovery
|
||||
|
||||
if(Libzot::is_zot_request()) {
|
||||
|
||||
$sigdata = HTTPSig::verify(file_get_contents('php://input'));
|
||||
|
||||
if($sigdata && $sigdata['signer'] && $sigdata['header_valid']) {
|
||||
$data = json_encode(Libzot::zotinfo([ 'address' => $channel['channel_address'], 'target_url' => $sigdata['signer'] ]));
|
||||
$s = q("select site_crypto, hubloc_sitekey from site left join hubloc on hubloc_url = site_url where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
|
||||
dbesc($sigdata['signer'])
|
||||
);
|
||||
|
||||
if($s) {
|
||||
$data = json_encode(crypto_encapsulate($data,$s[0]['hubloc_sitekey'],Libzot::best_algorithm($s[0]['site_crypto'])));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$data = json_encode(Libzot::zotinfo([ 'address' => $channel['channel_address'] ]));
|
||||
}
|
||||
|
||||
$headers = [
|
||||
'Content-Type' => 'application/x-zot+json',
|
||||
'Digest' => HTTPSig::generate_digest_header($data),
|
||||
'(request-target)' => strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']
|
||||
];
|
||||
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel));
|
||||
HTTPSig::set_headers($h);
|
||||
echo $data;
|
||||
killme();
|
||||
}
|
||||
|
||||
|
||||
if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
|
||||
$which = $channel['channel_address'];
|
||||
$profile = argv(1);
|
||||
|
@ -106,7 +106,7 @@ class Chanview extends \Zotlabs\Web\Controller {
|
||||
|
||||
if (\App::$poi) {
|
||||
$url = \App::$poi['xchan_url'];
|
||||
if(\App::$poi['xchan_network'] === 'zot') {
|
||||
if(in_array(\App::$poi['xchan_network'], ['zot', 'zot6'])) {
|
||||
$is_zot = true;
|
||||
}
|
||||
if(local_channel()) {
|
||||
|
@ -8,6 +8,7 @@ namespace Zotlabs\Module;
|
||||
*/
|
||||
|
||||
use Zotlabs\Lib\Apps;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
|
||||
require_once('include/socgraph.php');
|
||||
require_once('include/selectors.php');
|
||||
@ -100,7 +101,8 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
|
||||
$profile_id = $_POST['profile_assign'];
|
||||
$profile_id = ((array_key_exists('profile_assign',$_POST)) ? $_POST['profile_assign'] : $orig_record[0]['abook_profile']);
|
||||
|
||||
if($profile_id) {
|
||||
$r = q("SELECT profile_guid FROM profile WHERE profile_guid = '%s' AND uid = %d LIMIT 1",
|
||||
dbesc($profile_id),
|
||||
@ -112,8 +114,9 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
|
||||
$abook_incl = escape_tags($_POST['abook_incl']);
|
||||
$abook_excl = escape_tags($_POST['abook_excl']);
|
||||
$abook_incl = ((array_key_exists('abook_incl',$_POST)) ? escape_tags($_POST['abook_incl']) : $orig_record[0]['abook_incl']);
|
||||
$abook_excl = ((array_key_exists('abook_excl',$_POST)) ? escape_tags($_POST['abook_excl']) : $orig_record[0]['abook_excl']);
|
||||
|
||||
|
||||
$hidden = intval($_POST['hidden']);
|
||||
|
||||
@ -121,9 +124,13 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
if($priority > 5 || $priority < 0)
|
||||
$priority = 0;
|
||||
|
||||
if(! array_key_exists('closeness',$_POST)) {
|
||||
$_POST['closeness'] = 80;
|
||||
}
|
||||
$closeness = intval($_POST['closeness']);
|
||||
if($closeness < 0)
|
||||
$closeness = 99;
|
||||
if($closeness < 0 || $closeness > 99) {
|
||||
$closeness = 80;
|
||||
}
|
||||
|
||||
$rating = intval($_POST['rating']);
|
||||
if($rating < (-10))
|
||||
@ -231,6 +238,8 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
|
||||
$abook_pending = (($new_friend) ? 0 : $orig_record[0]['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",
|
||||
@ -475,6 +484,10 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
if(! zot_refresh($orig_record[0],\App::get_channel()))
|
||||
notice( t('Refresh failed - channel is currently unavailable.') );
|
||||
}
|
||||
elseif($orig_record[0]['xchan_network'] === 'zot6') {
|
||||
if(! Libzot::refresh($orig_record[0],\App::get_channel()))
|
||||
notice( 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
|
||||
@ -697,7 +710,7 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
|
||||
$tpl = get_markup_template("abook_edit.tpl");
|
||||
|
||||
if(feature_enabled(local_channel(),'affinity')) {
|
||||
if(Apps::system_app_installed(local_channel(),'Affinity Tool')) {
|
||||
|
||||
$sections['affinity'] = [
|
||||
'label' => t('Affinity'),
|
||||
@ -728,9 +741,12 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
$slider_tpl = get_markup_template('contact_slider.tpl');
|
||||
|
||||
$slideval = intval($contact['abook_closeness']);
|
||||
|
||||
$slide = replace_macros($slider_tpl,array(
|
||||
'$min' => 1,
|
||||
'$val' => (($contact['abook_closeness']) ? $contact['abook_closeness'] : 99),
|
||||
'$val' => $slideval,
|
||||
'$labels' => $label_str,
|
||||
));
|
||||
}
|
||||
@ -887,7 +903,7 @@ class Connedit extends \Zotlabs\Web\Controller {
|
||||
'$inherited' => t('inherited'),
|
||||
'$submit' => t('Submit'),
|
||||
'$lbl_vis2' => sprintf( t('Please choose the profile you would like to display to %s when viewing your profile securely.'), $contact['xchan_name']),
|
||||
'$close' => $contact['abook_closeness'],
|
||||
'$close' => (($contact['abook_closeness']) ? $contact['abook_closeness'] : 80),
|
||||
'$them' => t('Their Settings'),
|
||||
'$me' => t('My Settings'),
|
||||
'$perms' => $perms,
|
||||
|
@ -179,7 +179,6 @@ class Display extends \Zotlabs\Web\Controller {
|
||||
|
||||
$static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0);
|
||||
|
||||
|
||||
$simple_update = (($update) ? " AND item_unseen = 1 " : '');
|
||||
|
||||
if($update && $_SESSION['loadtime'])
|
||||
@ -314,7 +313,7 @@ class Display extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
|
||||
if(! $r) {
|
||||
if($r === null) {
|
||||
// in case somebody turned off public access to sys channel content using permissions
|
||||
// make that content unsearchable by ensuring the owner_xchan can't match
|
||||
if(! perm_is_allowed($sysid,$observer_hash,'view_stream'))
|
||||
|
@ -17,9 +17,17 @@ class Dreport extends \Zotlabs\Web\Controller {
|
||||
|
||||
$mid = ((argc() > 1) ? argv(1) : '');
|
||||
|
||||
if(strpos($mid,'b64.') === 0)
|
||||
$mid = @base64url_decode(substr($mid,4));
|
||||
|
||||
|
||||
if($mid === 'push') {
|
||||
$table = 'push';
|
||||
$mid = ((argc() > 2) ? argv(2) : '');
|
||||
|
||||
if(strpos($mid,'b64.') === 0)
|
||||
$mid = @base64url_decode(substr($mid,4));
|
||||
|
||||
if($mid) {
|
||||
$i = q("select id from item where mid = '%s' and uid = %d and ( author_xchan = '%s' or ( owner_xchan = '%s' and item_wall = 1 )) ",
|
||||
dbesc($mid),
|
||||
@ -38,6 +46,9 @@ class Dreport extends \Zotlabs\Web\Controller {
|
||||
if($mid === 'mail') {
|
||||
$table = 'mail';
|
||||
$mid = ((argc() > 2) ? argv(2) : '');
|
||||
if(strpos($mid,'b64.') === 0)
|
||||
$mid = @base64url_decode(substr($mid,4));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -69,8 +80,9 @@ 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' or dreport_xchan = '%s') and dreport_mid = '%s'",
|
||||
dbesc($channel['channel_hash']),
|
||||
dbesc($channel['channel_portable_id']),
|
||||
dbesc($mid)
|
||||
);
|
||||
|
||||
@ -80,7 +92,6 @@ class Dreport extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
for($x = 0; $x < count($r); $x++ ) {
|
||||
$r[$x]['name'] = escape_tags(substr($r[$x]['dreport_recip'],strpos($r[$x]['dreport_recip'],' ')));
|
||||
|
||||
// This has two purposes: 1. make the delivery report strings translateable, and
|
||||
// 2. assign an ordering to item delivery results so we can group them and provide
|
||||
@ -138,14 +149,14 @@ class Dreport extends \Zotlabs\Web\Controller {
|
||||
$entries = array();
|
||||
foreach($r as $rr) {
|
||||
$entries[] = [
|
||||
'name' => $rr['name'],
|
||||
'name' => escape_tags($rr['dreport_name'] ?: $rr['dreport_recip']),
|
||||
'result' => escape_tags($rr['dreport_result']),
|
||||
'time' => escape_tags(datetime_convert('UTC',date_default_timezone_get(),$rr['dreport_time']))
|
||||
];
|
||||
}
|
||||
|
||||
$o = replace_macros(get_markup_template('dreport.tpl'), array(
|
||||
'$title' => sprintf( t('Delivery report for %1$s'),substr($mid,0,32)) . '...',
|
||||
'$title' => sprintf( t('Delivery report for %1$s'),basename($mid)) . '...',
|
||||
'$table' => $table,
|
||||
'$mid' => urlencode($mid),
|
||||
'$options' => t('Options'),
|
||||
@ -162,9 +173,9 @@ class Dreport extends \Zotlabs\Web\Controller {
|
||||
|
||||
private static function dreport_gravity_sort($a,$b) {
|
||||
if($a['gravity'] == $b['gravity']) {
|
||||
if($a['name'] === $b['name'])
|
||||
if($a['dreport_name'] === $b['dreport_name'])
|
||||
return strcmp($a['dreport_time'],$b['dreport_time']);
|
||||
return strcmp($a['name'],$b['name']);
|
||||
return strcmp($a['dreport_name'],$b['dreport_name']);
|
||||
}
|
||||
return (($a['gravity'] > $b['gravity']) ? 1 : (-1));
|
||||
}
|
||||
|
22
Zotlabs/Module/Embed.php
Normal file
22
Zotlabs/Module/Embed.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
require_once('include/security.php');
|
||||
require_once('include/bbcode.php');
|
||||
|
||||
|
||||
class Embed extends \Zotlabs\Web\Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
$post_id = ((argc() > 1) ? intval(argv(1)) : 0);
|
||||
|
||||
if(! $post_id)
|
||||
killme();
|
||||
|
||||
echo '[share=' . $post_id . '][/share]';
|
||||
killme();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -3,8 +3,10 @@
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Embedphoto endpoint.
|
||||
*
|
||||
* Provide an AJAX endpoint to fill the embedPhotoModal with folders and photos
|
||||
* selection.
|
||||
*/
|
||||
class Embedphotos extends \Zotlabs\Web\Controller {
|
||||
|
||||
@ -13,42 +15,42 @@ class Embedphotos extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This is the POST destination for the embedphotos button.
|
||||
*
|
||||
* This is the POST destination for the embedphotos button
|
||||
*
|
||||
* @return string A JSON string.
|
||||
*/
|
||||
function post() {
|
||||
public function post() {
|
||||
if (argc() > 1 && argv(1) === 'album') {
|
||||
// API: /embedphotos/album
|
||||
$name = (x($_POST,'name') ? $_POST['name'] : null );
|
||||
if(!$name) {
|
||||
$name = (x($_POST, 'name') ? $_POST['name'] : null );
|
||||
if (!$name) {
|
||||
json_return_and_die(array('errormsg' => 'Error retrieving album', 'status' => false));
|
||||
}
|
||||
$album = $this->embedphotos_widget_album(array('channel' => \App::get_channel(), 'album' => $name));
|
||||
json_return_and_die(array('status' => true, 'content' => $album));
|
||||
}
|
||||
if(argc() > 1 && argv(1) === 'albumlist') {
|
||||
if (argc() > 1 && argv(1) === 'albumlist') {
|
||||
// API: /embedphotos/albumlist
|
||||
$album_list = $this->embedphotos_album_list($a);
|
||||
$album_list = $this->embedphotos_album_list();
|
||||
json_return_and_die(array('status' => true, 'albumlist' => $album_list));
|
||||
}
|
||||
if(argc() > 1 && argv(1) === 'photolink') {
|
||||
if (argc() > 1 && argv(1) === 'photolink') {
|
||||
// API: /embedphotos/photolink
|
||||
$href = (x($_POST,'href') ? $_POST['href'] : null );
|
||||
if(!$href) {
|
||||
$href = (x($_POST, 'href') ? $_POST['href'] : null );
|
||||
if (!$href) {
|
||||
json_return_and_die(array('errormsg' => 'Error retrieving link ' . $href, 'status' => false));
|
||||
}
|
||||
$resource_id = array_pop(explode("/", $href));
|
||||
$resource_id = array_pop(explode('/', $href));
|
||||
$r = q("SELECT obj from item where resource_type = 'photo' and resource_id = '%s' limit 1",
|
||||
dbesc($resource_id)
|
||||
);
|
||||
if(!$r) {
|
||||
if (!$r) {
|
||||
json_return_and_die(array('errormsg' => 'Error retrieving resource ' . $resource_id, 'status' => false));
|
||||
}
|
||||
$obj = json_decode($r[0]['obj'], true);
|
||||
if(x($obj,'body')) {
|
||||
if (x($obj, 'body')) {
|
||||
$photolink = $obj['body'];
|
||||
} elseif (x($obj,'bbcode')) {
|
||||
} elseif (x($obj, 'bbcode')) {
|
||||
$photolink = $obj['bbcode'];
|
||||
} else {
|
||||
json_return_and_die(array('errormsg' => 'Error retrieving resource ' . $resource_id, 'status' => false));
|
||||
@ -58,48 +60,51 @@ class Embedphotos extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied from include/widgets.php::widget_album() with a modification to get the profile_uid from
|
||||
* the input array as in widget_item()
|
||||
* @brief Get photos from an album.
|
||||
*
|
||||
* @param array $args
|
||||
* @return string with HTML
|
||||
* @see \\Zotlabs\\Widget\\Album::widget()
|
||||
*
|
||||
* @param array $args associative array with
|
||||
* * \e array \b channel
|
||||
* * \e string \b album
|
||||
* @return string with HTML code from 'photo_album.tpl'
|
||||
*/
|
||||
function embedphotos_widget_album($args) {
|
||||
|
||||
protected function embedphotos_widget_album($args) {
|
||||
$channel_id = 0;
|
||||
if(array_key_exists('channel', $args))
|
||||
|
||||
if (array_key_exists('channel', $args)) {
|
||||
$channel = $args['channel'];
|
||||
$channel_id = intval($channel['channel_id']);
|
||||
if(! $channel_id)
|
||||
}
|
||||
if (! $channel_id)
|
||||
$channel_id = \App::$profile_uid;
|
||||
if(! $channel_id)
|
||||
if (! $channel_id)
|
||||
return '';
|
||||
|
||||
$owner_uid = $channel_id;
|
||||
require_once('include/security.php');
|
||||
$sql_extra = permissions_sql($channel_id);
|
||||
|
||||
if(! perm_is_allowed($channel_id,get_observer_hash(),'view_storage'))
|
||||
if (! perm_is_allowed($channel_id, get_observer_hash(), 'view_storage'))
|
||||
return '';
|
||||
|
||||
if($args['album'])
|
||||
if (isset($args['album']))
|
||||
$album = (($args['album'] === '/') ? '' : $args['album']);
|
||||
if($args['title'])
|
||||
if (isset($args['title']))
|
||||
$title = $args['title'];
|
||||
|
||||
/**
|
||||
* This may return incorrect permissions if you have multiple directories of the same name.
|
||||
* @note This may return incorrect permissions if you have multiple directories of the same name.
|
||||
* It is a limitation of the photo table using a name for a photo album instead of a folder hash
|
||||
*/
|
||||
if($album) {
|
||||
if ($album) {
|
||||
require_once('include/attach.php');
|
||||
$x = q("select hash from attach where filename = '%s' and uid = %d limit 1",
|
||||
dbesc($album),
|
||||
intval($owner_uid)
|
||||
intval($channel_id)
|
||||
);
|
||||
if($x) {
|
||||
$y = attach_can_view_folder($owner_uid,get_observer_hash(),$x[0]['hash']);
|
||||
if(! $y)
|
||||
if ($x) {
|
||||
$y = attach_can_view_folder($channel_id, get_observer_hash(), $x[0]['hash']);
|
||||
if (! $y)
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@ -110,30 +115,33 @@ class Embedphotos extends \Zotlabs\Web\Controller {
|
||||
(SELECT resource_id, max(imgscale) imgscale FROM photo WHERE uid = %d AND album = '%s' AND imgscale <= 4 AND photo_usage IN ( %d, %d ) $sql_extra GROUP BY resource_id) ph
|
||||
ON (p.resource_id = ph.resource_id AND p.imgscale = ph.imgscale)
|
||||
ORDER BY created $order",
|
||||
intval($owner_uid),
|
||||
intval($channel_id),
|
||||
dbesc($album),
|
||||
intval(PHOTO_NORMAL),
|
||||
intval(PHOTO_PROFILE)
|
||||
);
|
||||
|
||||
$photos = array();
|
||||
if(count($r)) {
|
||||
$photos = [];
|
||||
if (count($r)) {
|
||||
$twist = 'rotright';
|
||||
foreach($r as $rr) {
|
||||
if($twist == 'rotright')
|
||||
foreach ($r as $rr) {
|
||||
if ($twist == 'rotright')
|
||||
$twist = 'rotleft';
|
||||
else
|
||||
$twist = 'rotright';
|
||||
|
||||
$ph = photo_factory('');
|
||||
$phototypes = $ph->supportedTypes();
|
||||
|
||||
$ext = $phototypes[$rr['mimetype']];
|
||||
|
||||
$imgalt_e = $rr['filename'];
|
||||
$desc_e = $rr['description'];
|
||||
|
||||
$imagelink = (z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/image/' . $rr['resource_id']
|
||||
$imagelink = (z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $rr['resource_id']
|
||||
. (($_GET['order'] === 'posted') ? '?f=&order=posted' : ''));
|
||||
|
||||
$photos[] = array(
|
||||
$photos[] = [
|
||||
'id' => $rr['id'],
|
||||
'twist' => ' ' . $twist . rand(2,4),
|
||||
'link' => $imagelink,
|
||||
@ -143,35 +151,43 @@ class Embedphotos extends \Zotlabs\Web\Controller {
|
||||
'desc'=> $desc_e,
|
||||
'ext' => $ext,
|
||||
'hash'=> $rr['resource_id'],
|
||||
'unknown' => t('Unknown')
|
||||
);
|
||||
'unknown' => t('Unknown'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$tpl = get_markup_template('photo_album.tpl');
|
||||
$o .= replace_macros($tpl, array(
|
||||
$o = replace_macros($tpl, [
|
||||
'$photos' => $photos,
|
||||
'$album' => (($title) ? $title : $album),
|
||||
'$album_id' => rand(),
|
||||
'$album_edit' => array(t('Edit Album'), $album_edit),
|
||||
'$album_edit' => array(t('Edit Album'), false),
|
||||
'$can_post' => false,
|
||||
'$upload' => array(t('Upload'), z_root() . '/photos/' . \App::$profile['channel_address'] . '/upload/' . bin2hex($album)),
|
||||
'$order' => false,
|
||||
'$upload_form' => $upload_form,
|
||||
'$no_fullscreen_btn' => true
|
||||
));
|
||||
'$upload_form' => '',
|
||||
'$no_fullscreen_btn' => true,
|
||||
]);
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
function embedphotos_album_list($a) {
|
||||
/**
|
||||
* @brief Get albums observer is allowed to see.
|
||||
*
|
||||
* @see photos_albums_list()
|
||||
*
|
||||
* @return NULL|array
|
||||
*/
|
||||
protected function embedphotos_album_list() {
|
||||
require_once('include/photos.php');
|
||||
$p = photos_albums_list(\App::get_channel(), \App::get_observer());
|
||||
if($p['success']) {
|
||||
|
||||
if ($p['success']) {
|
||||
return $p['albums'];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -97,8 +97,8 @@ class Events extends \Zotlabs\Web\Controller {
|
||||
$type = escape_tags(trim($_POST['type']));
|
||||
|
||||
require_once('include/text.php');
|
||||
linkify_tags($a, $desc, local_channel());
|
||||
linkify_tags($a, $location, local_channel());
|
||||
linkify_tags($desc, local_channel());
|
||||
linkify_tags($location, local_channel());
|
||||
|
||||
//$action = ($event_hash == '') ? 'new' : "event/" . $event_hash;
|
||||
|
||||
|
@ -5,6 +5,8 @@ namespace Zotlabs\Module;
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
class Filestorage extends \Zotlabs\Web\Controller {
|
||||
|
||||
function post() {
|
||||
@ -71,14 +73,6 @@ class Filestorage extends \Zotlabs\Web\Controller {
|
||||
return;
|
||||
}
|
||||
|
||||
// Since we have ACL'd files in the wild, but don't have ACL here yet, we
|
||||
// need to return for anyone other than the owner, despite the perms check for now.
|
||||
|
||||
$is_owner = (((local_channel()) && ($owner == local_channel())) ? true : false);
|
||||
if(! ($is_owner || is_site_admin())){
|
||||
info( t('Permission Denied.') . EOL );
|
||||
return;
|
||||
}
|
||||
|
||||
if(argc() > 3 && argv(3) === 'delete') {
|
||||
|
||||
@ -101,18 +95,31 @@ class Filestorage extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
$file = intval(argv(2));
|
||||
$r = q("SELECT hash FROM attach WHERE id = %d AND uid = %d LIMIT 1",
|
||||
$r = q("SELECT hash, creator FROM attach WHERE id = %d AND uid = %d LIMIT 1",
|
||||
dbesc($file),
|
||||
intval($owner)
|
||||
);
|
||||
if(! $r) {
|
||||
notice( t('File not found.') . EOL);
|
||||
|
||||
if($json_return)
|
||||
json_return_and_die([ 'success' => false ]);
|
||||
|
||||
notice( t('File not found.') . EOL);
|
||||
goaway(z_root() . '/cloud/' . $which);
|
||||
}
|
||||
|
||||
if(local_channel() !== $owner) {
|
||||
if($r[0]['creator'] && $r[0]['creator'] !== $ob_hash) {
|
||||
notice( t('Permission denied.') . EOL);
|
||||
|
||||
if($json_return)
|
||||
json_return_and_die([ 'success' => false ]);
|
||||
|
||||
goaway(z_root() . '/cloud/' . $which);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$f = $r[0];
|
||||
|
||||
$channel = channelx_by_n($owner);
|
||||
@ -134,6 +141,19 @@ class Filestorage extends \Zotlabs\Web\Controller {
|
||||
goaway(dirname($url));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Since we have ACL'd files in the wild, but don't have ACL here yet, we
|
||||
// need to return for anyone other than the owner, despite the perms check for now.
|
||||
|
||||
$is_owner = (((local_channel()) && ($owner == local_channel())) ? true : false);
|
||||
if(! ($is_owner || is_site_admin())){
|
||||
info( t('Permission Denied.') . EOL );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(argc() > 3 && argv(3) === 'edit') {
|
||||
require_once('include/acl_selectors.php');
|
||||
if(! $perms['write_storage']) {
|
||||
|
@ -66,6 +66,9 @@ class Group extends Controller {
|
||||
$groupname = notags(trim($_POST['groupname']));
|
||||
$public = intval($_POST['public']);
|
||||
|
||||
$hookinfo = [ 'pgrp_extras' => '', 'group'=>$group['id'] ];
|
||||
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",
|
||||
dbesc($groupname),
|
||||
@ -75,6 +78,8 @@ class Group extends Controller {
|
||||
);
|
||||
if($r)
|
||||
info( t('Privacy group updated.') . EOL );
|
||||
|
||||
|
||||
build_sync_packet(local_channel(),null,true);
|
||||
}
|
||||
|
||||
@ -127,6 +132,10 @@ class Group extends Controller {
|
||||
$i++;
|
||||
}
|
||||
|
||||
$hookinfo = [ 'pgrp_extras' => '', 'group'=>argv(1) ];
|
||||
call_hooks ('privacygroup_extras',$hookinfo);
|
||||
$pgrp_extras = $hookinfo['pgrp_extras'];
|
||||
|
||||
$tpl = get_markup_template('privacy_groups.tpl');
|
||||
$o = replace_macros($tpl, [
|
||||
'$title' => t('Privacy Groups'),
|
||||
@ -136,6 +145,7 @@ class Group extends Controller {
|
||||
// new group form
|
||||
'$gname' => array('groupname',t('Privacy group name')),
|
||||
'$public' => array('public',t('Members are visible to other channels'), false),
|
||||
'$pgrp_extras' => $pgrp_extras,
|
||||
'$form_security_token' => get_form_security_token("group_edit"),
|
||||
'$submit' => t('Submit'),
|
||||
|
||||
@ -166,8 +176,11 @@ class Group extends Controller {
|
||||
);
|
||||
if($r)
|
||||
$result = group_rmv(local_channel(),$r[0]['gname']);
|
||||
if($result)
|
||||
if($result) {
|
||||
$hookinfo = [ 'pgrp_extras' => '', 'group'=>$argv(2) ];
|
||||
call_hooks ('privacygroup_extras_drop',$hookinfo);
|
||||
info( t('Privacy group removed.') . EOL);
|
||||
}
|
||||
else
|
||||
notice( t('Unable to remove privacy group.') . EOL);
|
||||
}
|
||||
@ -230,6 +243,10 @@ class Group extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
$hookinfo = [ 'pgrp_extras' => '', 'group'=>$group['id'] ];
|
||||
call_hooks ('privacygroup_extras',$hookinfo);
|
||||
$pgrp_extras = $hookinfo['pgrp_extras'];
|
||||
|
||||
$context = $context + array(
|
||||
'$title' => sprintf(t('Privacy Group: %s'), $group['gname']),
|
||||
'$details_label' => t('Edit'),
|
||||
@ -240,6 +257,7 @@ class Group extends Controller {
|
||||
'$form_security_token_edit' => get_form_security_token('group_edit'),
|
||||
'$delete' => t('Delete Group'),
|
||||
'$form_security_token_drop' => get_form_security_token("group_drop"),
|
||||
'$pgrp_extras' => $pgrp_extras,
|
||||
);
|
||||
|
||||
}
|
||||
@ -283,6 +301,7 @@ class Group extends Controller {
|
||||
|
||||
$context['$groupeditor'] = $groupeditor;
|
||||
$context['$desc'] = t('Click a channel to toggle membership');
|
||||
$context['$pgrp_extras'] = $pgrp_extras;
|
||||
|
||||
if($change) {
|
||||
$tpl = get_markup_template('groupeditor.tpl');
|
||||
|
119
Zotlabs/Module/Id.php
Normal file
119
Zotlabs/Module/Id.php
Normal file
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
/**
|
||||
*
|
||||
* Controller for responding to x-zot: protocol requests
|
||||
* x-zot:_jkfRG85nJ-714zn-LW_VbTFW8jSjGAhAydOcJzHxqHkvEHWG2E0RbA_pbch-h4R63RG1YJZifaNzgccoLa3MQ/453c1678-1a79-4af7-ab65-6b012f6cab77
|
||||
*
|
||||
*/
|
||||
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\LDSignatures;
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\ThreadListener;
|
||||
use Zotlabs\Lib\IConfig;
|
||||
use Zotlabs\Lib\Enotify;
|
||||
use App;
|
||||
|
||||
require_once('include/attach.php');
|
||||
require_once('include/bbcode.php');
|
||||
require_once('include/security.php');
|
||||
|
||||
|
||||
class Id extends Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
if(Libzot::is_zot_request()) {
|
||||
|
||||
$conversation = false;
|
||||
|
||||
$request_portable_id = argv(1);
|
||||
if(argc() > 2) {
|
||||
$item_id = argv(2);
|
||||
}
|
||||
|
||||
$portable_id = EMPTY_STR;
|
||||
|
||||
$sigdata = HTTPSig::verify(EMPTY_STR);
|
||||
if($sigdata['portable_id'] && $sigdata['header_valid']) {
|
||||
$portable_id = $sigdata['portable_id'];
|
||||
}
|
||||
|
||||
|
||||
$chan = channelx_by_hash($request_portable_id);
|
||||
|
||||
if($chan) {
|
||||
$channel_id = $chan['channel_id'];
|
||||
if(! $item_id) {
|
||||
$handler = new Channel();
|
||||
App::$argc = 2;
|
||||
App::$argv[0] = 'channel';
|
||||
App::$argv[1] = $chan['channel_address'];
|
||||
$handler->init();
|
||||
}
|
||||
}
|
||||
else {
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 ";
|
||||
|
||||
$sql_extra = item_permissions_sql(0);
|
||||
|
||||
$r = q("select * from item where uuid = '%s' $item_normal $sql_extra and uid = %d limit 1",
|
||||
dbesc($item_id),
|
||||
intval($channel_id)
|
||||
);
|
||||
if(! $r) {
|
||||
|
||||
$r = q("select * from item where uuid = '%s' $item_normal and uid = %d limit 1",
|
||||
dbesc($item_id),
|
||||
intval($channel_id)
|
||||
);
|
||||
if($r) {
|
||||
http_status_exit(403, 'Forbidden');
|
||||
}
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
|
||||
if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream'))
|
||||
http_status_exit(403, 'Forbidden');
|
||||
|
||||
xchan_query($r,true);
|
||||
$items = fetch_post_tags($r,true);
|
||||
|
||||
$i = Activity::encode_item($items[0]);
|
||||
|
||||
if(! $i)
|
||||
http_status_exit(404, 'Not found');
|
||||
|
||||
$x = array_merge(['@context' => [
|
||||
ACTIVITYSTREAMS_JSONLD_REV,
|
||||
'https://w3id.org/security/v1',
|
||||
z_root() . ZOT_APSCHEMA_REV
|
||||
]], $i);
|
||||
|
||||
$headers = [];
|
||||
$headers['Content-Type'] = 'application/x-zot+json' ;
|
||||
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
|
||||
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
|
||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
$h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan));
|
||||
HTTPSig::set_headers($h);
|
||||
echo $ret;
|
||||
killme();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -133,9 +133,11 @@ class Impel extends \Zotlabs\Web\Controller {
|
||||
$arr['author_xchan'] = (($j['author_xchan']) ? $j['author_xchan'] : get_observer_hash());
|
||||
$arr['mimetype'] = (($j['mimetype']) ? $j['mimetype'] : 'text/bbcode');
|
||||
|
||||
if(! $j['mid'])
|
||||
$j['mid'] = item_message_id();
|
||||
|
||||
if(! $j['mid']) {
|
||||
$j['uuid'] = item_message_id();
|
||||
$j['mid'] = z_root() . '/item/' . $j['uuid'];
|
||||
}
|
||||
$arr['uuid'] = $j['uuid'];
|
||||
$arr['mid'] = $arr['parent_mid'] = $j['mid'];
|
||||
|
||||
|
||||
|
@ -2,6 +2,23 @@
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Lib\IConfig;
|
||||
use Zotlabs\Lib\Enotify;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Daemon\Master;
|
||||
use Zotlabs\Lib\Activity;
|
||||
use Zotlabs\Lib\ActivityStreams;
|
||||
use Zotlabs\Lib\LDSignatures;
|
||||
use Zotlabs\Zot6\HTTPSig;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Lib\ThreadListener;
|
||||
use App;
|
||||
|
||||
require_once('include/crypto.php');
|
||||
require_once('include/items.php');
|
||||
require_once('include/security.php');
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* This is the POST destination for most all locally posted
|
||||
@ -17,16 +34,146 @@ namespace Zotlabs\Module;
|
||||
*
|
||||
*/
|
||||
|
||||
require_once('include/crypto.php');
|
||||
require_once('include/items.php');
|
||||
require_once('include/attach.php');
|
||||
require_once('include/bbcode.php');
|
||||
require_once('include/security.php');
|
||||
|
||||
class Item extends Controller {
|
||||
|
||||
|
||||
use \Zotlabs\Lib as Zlib;
|
||||
function init() {
|
||||
|
||||
if(Libzot::is_zot_request()) {
|
||||
|
||||
$conversation = false;
|
||||
|
||||
$item_id = argv(1);
|
||||
|
||||
if(! $item_id)
|
||||
http_status_exit(404, 'Not found');
|
||||
|
||||
|
||||
$portable_id = EMPTY_STR;
|
||||
|
||||
$sigdata = HTTPSig::verify(EMPTY_STR);
|
||||
if($sigdata['portable_id'] && $sigdata['header_valid']) {
|
||||
$portable_id = $sigdata['portable_id'];
|
||||
}
|
||||
|
||||
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 ";
|
||||
|
||||
$sql_extra = item_permissions_sql(0);
|
||||
|
||||
$r = q("select * from item where mid = '%s' $item_normal $sql_extra limit 1",
|
||||
dbesc(z_root() . '/item/' . $item_id)
|
||||
);
|
||||
if(! $r) {
|
||||
|
||||
|
||||
$r = q("select * from item where mid = '%s' $item_normal limit 1",
|
||||
dbesc(z_root() . '/item/' . $item_id)
|
||||
);
|
||||
if($r) {
|
||||
http_status_exit(403, 'Forbidden');
|
||||
}
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
|
||||
|
||||
$items = q("select parent as item_id from item where mid = '%s' and uid = %d $item_normal $sql_extra ",
|
||||
dbesc($r[0]['parent_mid']),
|
||||
intval($r[0]['uid'])
|
||||
);
|
||||
if(! $items) {
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
|
||||
$r = $items;
|
||||
|
||||
$parents_str = ids_to_querystr($r,'item_id');
|
||||
|
||||
$items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent IN ( %s ) $item_normal $sql_extra ",
|
||||
dbesc($parents_str)
|
||||
);
|
||||
|
||||
if(! $items) {
|
||||
http_status_exit(404, 'Not found');
|
||||
}
|
||||
|
||||
$r = $items;
|
||||
xchan_query($r,true);
|
||||
$items = fetch_post_tags($r,true);
|
||||
|
||||
$observer = App::get_observer();
|
||||
$parent = $items[0];
|
||||
$recips = (($parent['owner']['xchan_network'] === 'activitypub') ? get_iconfig($parent['id'],'activitypub','recips', []) : []);
|
||||
$to = (($recips && array_key_exists('to',$recips) && is_array($recips['to'])) ? $recips['to'] : null);
|
||||
$nitems = [];
|
||||
foreach($items as $i) {
|
||||
|
||||
$mids = [];
|
||||
|
||||
if(intval($i['item_private'])) {
|
||||
if(! $observer) {
|
||||
continue;
|
||||
}
|
||||
// ignore private reshare, possibly from hubzilla
|
||||
if($i['verb'] === 'Announce') {
|
||||
if(! in_array($i['thr_parent'],$mids)) {
|
||||
$mids[] = $i['thr_parent'];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// also ignore any children of the private reshares
|
||||
if(in_array($i['thr_parent'],$mids)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if((! $to) || (! in_array($observer['xchan_url'],$to))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
$nitems[] = $i;
|
||||
}
|
||||
|
||||
if(! $nitems)
|
||||
http_status_exit(404, 'Not found');
|
||||
|
||||
$chan = channelx_by_n($nitems[0]['uid']);
|
||||
|
||||
if(! $chan)
|
||||
http_status_exit(404, 'Not found');
|
||||
|
||||
if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream'))
|
||||
http_status_exit(403, 'Forbidden');
|
||||
|
||||
$i = Activity::encode_item_collection($nitems,'conversation/' . $item_id,'OrderedCollection',( defined('NOMADIC') ? false : true));
|
||||
if($portable_id) {
|
||||
ThreadListener::store(z_root() . '/item/' . $item_id,$portable_id);
|
||||
}
|
||||
|
||||
if(! $i)
|
||||
http_status_exit(404, 'Not found');
|
||||
|
||||
$x = array_merge(['@context' => [
|
||||
ACTIVITYSTREAMS_JSONLD_REV,
|
||||
'https://w3id.org/security/v1',
|
||||
z_root() . ZOT_APSCHEMA_REV
|
||||
]], $i);
|
||||
|
||||
$headers = [];
|
||||
$headers['Content-Type'] = 'application/x-zot+json' ;
|
||||
$x['signature'] = LDSignatures::sign($x,$chan);
|
||||
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
|
||||
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
|
||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
$h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan));
|
||||
HTTPSig::set_headers($h);
|
||||
echo $ret;
|
||||
killme();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Item extends \Zotlabs\Web\Controller {
|
||||
|
||||
function post() {
|
||||
|
||||
@ -392,6 +539,7 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
$verb = $orig_post['verb'];
|
||||
$app = $orig_post['app'];
|
||||
$title = escape_tags(trim($_REQUEST['title']));
|
||||
$summary = trim($_REQUEST['summary']);
|
||||
$body = trim($_REQUEST['body']);
|
||||
$item_flags = $orig_post['item_flags'];
|
||||
|
||||
@ -454,6 +602,7 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
$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']);
|
||||
$postopts = '';
|
||||
@ -505,12 +654,14 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
&& ($channel['channel_pageflags'] & PAGE_ALLOWCODE)) ? true : false);
|
||||
|
||||
if($preview) {
|
||||
$summary = z_input_filter($summary,$mimetype,$execflag);
|
||||
$body = z_input_filter($body,$mimetype,$execflag);
|
||||
}
|
||||
|
||||
|
||||
$arr = [ 'profile_uid' => $profile_uid, 'content' => $body, 'mimetype' => $mimetype ];
|
||||
$arr = [ 'profile_uid' => $profile_uid, 'summary' => $summary, 'content' => $body, 'mimetype' => $mimetype ];
|
||||
call_hooks('post_content',$arr);
|
||||
$summary = $arr['summary'];
|
||||
$body = $arr['content'];
|
||||
$mimetype = $arr['mimetype'];
|
||||
|
||||
@ -531,10 +682,24 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
// we may need virtual or template classes to implement the possible alternatives
|
||||
|
||||
|
||||
if(strpos($body,'[/summary]') !== false) {
|
||||
$match = '';
|
||||
$cnt = preg_match("/\[summary\](.*?)\[\/summary\]/ism",$body,$match);
|
||||
if($cnt) {
|
||||
$summary .= $match[1];
|
||||
}
|
||||
$body_content = preg_replace("/^(.*?)\[summary\](.*?)\[\/summary\](.*?)$/ism", '',$body);
|
||||
$body = trim($body_content);
|
||||
}
|
||||
|
||||
$summary = cleanup_bbcode($summary);
|
||||
|
||||
$body = cleanup_bbcode($body);
|
||||
|
||||
// Look for tags and linkify them
|
||||
$results = linkify_tags($a, $body, ($uid) ? $uid : $profile_uid);
|
||||
|
||||
$results = linkify_tags($summary, ($uid) ? $uid : $profile_uid);
|
||||
$results = linkify_tags($body, ($uid) ? $uid : $profile_uid);
|
||||
|
||||
if($results) {
|
||||
|
||||
@ -579,6 +744,9 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
if(! $preview) {
|
||||
fix_attached_photo_permissions($profile_uid,$owner_xchan['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny);
|
||||
|
||||
fix_attached_photo_permissions($profile_uid,$owner_xchan['xchan_hash'],((strpos($summary,'[/crypt]')) ? $_POST['media_str'] : $summary),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny);
|
||||
|
||||
|
||||
fix_attached_file_permissions($channel,$observer['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny);
|
||||
|
||||
}
|
||||
@ -616,9 +784,9 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
|
||||
|
||||
if(preg_match_all('/(\[share=(.*?)\](.*?)\[\/share\])/',$body,$match)) {
|
||||
|
||||
// process share by id
|
||||
|
||||
$verb = ACTIVITY_SHARE;
|
||||
$i = 0;
|
||||
foreach($match[2] as $mtch) {
|
||||
$reshare = new \Zotlabs\Lib\Share($mtch);
|
||||
@ -711,7 +879,8 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
$notify_type = (($parent) ? 'comment-new' : 'wall-new' );
|
||||
|
||||
if(! $mid) {
|
||||
$mid = (($message_id) ? $message_id : item_message_id());
|
||||
$uuid = (($message_id) ? $message_id : item_message_id());
|
||||
$mid = z_root() . '/item/' . $uuid;
|
||||
}
|
||||
|
||||
|
||||
@ -736,7 +905,7 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
// fix permalinks for cards
|
||||
|
||||
if($webpage == ITEM_TYPE_CARD) {
|
||||
$plink = z_root() . '/cards/' . $channel['channel_address'] . '/' . (($pagetitle) ? $pagetitle : substr($mid,0,16));
|
||||
$plink = z_root() . '/cards/' . $channel['channel_address'] . '/' . (($pagetitle) ? $pagetitle : $uuid);
|
||||
}
|
||||
if(($parent_item) && ($parent_item['item_type'] == ITEM_TYPE_CARD)) {
|
||||
$r = q("select v from iconfig where iconfig.cat = 'system' and iconfig.k = 'CARD' and iconfig.iid = %d limit 1",
|
||||
@ -748,7 +917,7 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
if($webpage == ITEM_TYPE_ARTICLE) {
|
||||
$plink = z_root() . '/articles/' . $channel['channel_address'] . '/' . (($pagetitle) ? $pagetitle : substr($mid,0,16));
|
||||
$plink = z_root() . '/articles/' . $channel['channel_address'] . '/' . (($pagetitle) ? $pagetitle : $uuid);
|
||||
}
|
||||
if(($parent_item) && ($parent_item['item_type'] == ITEM_TYPE_ARTICLE)) {
|
||||
$r = q("select v from iconfig where iconfig.cat = 'system' and iconfig.k = 'ARTICLE' and iconfig.iid = %d limit 1",
|
||||
@ -760,12 +929,13 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
if ((! $plink) && ($item_thread_top)) {
|
||||
$plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $mid;
|
||||
$plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . gen_link_id($mid);
|
||||
$plink = substr($plink,0,190);
|
||||
}
|
||||
|
||||
$datarray['aid'] = $channel['channel_account_id'];
|
||||
$datarray['uid'] = $profile_uid;
|
||||
$datarray['uuid'] = $uuid;
|
||||
$datarray['owner_xchan'] = (($owner_hash) ? $owner_hash : $owner_xchan['xchan_hash']);
|
||||
$datarray['author_xchan'] = $observer['xchan_hash'];
|
||||
$datarray['created'] = $created;
|
||||
@ -778,6 +948,7 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
$datarray['parent_mid'] = $parent_mid;
|
||||
$datarray['mimetype'] = $mimetype;
|
||||
$datarray['title'] = $title;
|
||||
$datarray['summary'] = $summary;
|
||||
$datarray['body'] = $body;
|
||||
$datarray['app'] = $app;
|
||||
$datarray['location'] = $location;
|
||||
@ -887,12 +1058,12 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
$datarray['title'] = mb_substr($datarray['title'],0,191);
|
||||
|
||||
if($webpage) {
|
||||
Zlib\IConfig::Set($datarray,'system', webpage_to_namespace($webpage),
|
||||
(($pagetitle) ? $pagetitle : substr($datarray['mid'],0,16)),true);
|
||||
IConfig::Set($datarray,'system', webpage_to_namespace($webpage),
|
||||
(($pagetitle) ? $pagetitle : basename($datarray['mid'])), true);
|
||||
}
|
||||
elseif($namespace) {
|
||||
Zlib\IConfig::Set($datarray,'system', $namespace,
|
||||
(($remote_id) ? $remote_id : substr($datarray['mid'],0,16)),true);
|
||||
IConfig::Set($datarray,'system', $namespace,
|
||||
(($remote_id) ? $remote_id : basename($datarray['mid'])), true);
|
||||
}
|
||||
|
||||
|
||||
@ -924,7 +1095,7 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
if(! $nopush)
|
||||
\Zotlabs\Daemon\Master::Summon(array('Notifier', 'edit_post', $post_id));
|
||||
Master::Summon([ 'Notifier', 'edit_post', $post_id ]);
|
||||
|
||||
|
||||
if($api_source)
|
||||
@ -959,7 +1130,7 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
// otherwise it will happen during delivery
|
||||
|
||||
if(($datarray['owner_xchan'] != $datarray['author_xchan']) && (intval($parent_item['item_wall']))) {
|
||||
Zlib\Enotify::submit(array(
|
||||
Enotify::submit(array(
|
||||
'type' => NOTIFY_COMMENT,
|
||||
'from_xchan' => $datarray['author_xchan'],
|
||||
'to_xchan' => $datarray['owner_xchan'],
|
||||
@ -977,7 +1148,7 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
$parent = $post_id;
|
||||
|
||||
if(($datarray['owner_xchan'] != $datarray['author_xchan']) && ($datarray['item_type'] == ITEM_TYPE_POST)) {
|
||||
Zlib\Enotify::submit(array(
|
||||
Enotify::submit(array(
|
||||
'type' => NOTIFY_WALL,
|
||||
'from_xchan' => $datarray['author_xchan'],
|
||||
'to_xchan' => $datarray['owner_xchan'],
|
||||
@ -1039,7 +1210,7 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
call_hooks('post_local_end', $datarray);
|
||||
|
||||
if(! $nopush)
|
||||
\Zotlabs\Daemon\Master::Summon(array('Notifier', $notify_type, $post_id));
|
||||
Master::Summon([ 'Notifier', $notify_type, $post_id ]);
|
||||
|
||||
logger('post_complete');
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Lib\Activity;
|
||||
|
||||
require_once('include/security.php');
|
||||
require_once('include/bbcode.php');
|
||||
require_once('include/items.php');
|
||||
@ -374,10 +376,13 @@ class Like extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
|
||||
$mid = item_message_id();
|
||||
$uuid = item_message_id();
|
||||
|
||||
$arr = array();
|
||||
|
||||
$arr['uuid'] = $uuid;
|
||||
$arr['mid'] = z_root() . '/item/' . $uuid;
|
||||
|
||||
if($extended_like) {
|
||||
$arr['item_thread_top'] = 1;
|
||||
$arr['item_origin'] = 1;
|
||||
@ -400,6 +405,7 @@ class Like extends \Zotlabs\Web\Controller {
|
||||
$object = json_encode(array(
|
||||
'type' => $objtype,
|
||||
'id' => $item['mid'],
|
||||
'asld' => Activity::fetch_item( [ 'id' => $item['mid'] ] ),
|
||||
'parent' => (($item['thr_parent']) ? $item['thr_parent'] : $item['parent_mid']),
|
||||
'link' => $links,
|
||||
'title' => $item['title'],
|
||||
@ -479,7 +485,6 @@ class Like extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
|
||||
$arr['mid'] = $mid;
|
||||
$arr['aid'] = (($extended_like) ? $ch[0]['channel_account_id'] : $owner_aid);
|
||||
$arr['uid'] = $owner_uid;
|
||||
|
||||
|
@ -34,7 +34,7 @@ class Mail extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
else {
|
||||
$body = cleanup_bbcode($body);
|
||||
$results = linkify_tags($a, $body, local_channel());
|
||||
$results = linkify_tags($body, local_channel());
|
||||
|
||||
if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) {
|
||||
$attachments = array();
|
||||
@ -111,7 +111,7 @@ class Mail extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
require_once('include/text.php');
|
||||
linkify_tags($a, $body, local_channel());
|
||||
linkify_tags($body, local_channel());
|
||||
|
||||
|
||||
if(! $recipient) {
|
||||
|
@ -70,7 +70,8 @@ class Mood extends Controller {
|
||||
|
||||
$poster = App::get_observer();
|
||||
|
||||
$mid = item_message_id();
|
||||
$uuid = item_message_id();
|
||||
$mid = z_root() . '/item/' . $uuid;
|
||||
|
||||
$action = sprintf( t('%1$s is %2$s','mood'), '[zrl=' . $poster['xchan_url'] . ']' . $poster['xchan_name'] . '[/zrl]' , $verbs[$verb]);
|
||||
|
||||
@ -78,6 +79,7 @@ class Mood extends Controller {
|
||||
|
||||
$arr['aid'] = get_account_id();
|
||||
$arr['uid'] = $uid;
|
||||
$arr['uuid'] = $uuid;
|
||||
$arr['mid'] = $mid;
|
||||
$arr['parent_mid'] = (($parent_mid) ? $parent_mid : $mid);
|
||||
$arr['author_xchan'] = $poster['xchan_hash'];
|
||||
|
@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use Zotlabs\Lib\Group;
|
||||
use Zotlabs\Lib\Apps;
|
||||
use App;
|
||||
|
||||
require_once('include/items.php');
|
||||
@ -114,8 +116,8 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
$def_acl = array('allow_gid' => '<' . $r[0]['hash'] . '>');
|
||||
}
|
||||
|
||||
$default_cmin = ((feature_enabled(local_channel(),'affinity')) ? get_pconfig(local_channel(),'affinity','cmin',0) : (-1));
|
||||
$default_cmax = ((feature_enabled(local_channel(),'affinity')) ? get_pconfig(local_channel(),'affinity','cmax',99) : (-1));
|
||||
$default_cmin = ((Apps::system_app_installed(local_channel(),'Affinity Tool')) ? get_pconfig(local_channel(),'affinity','cmin',0) : (-1));
|
||||
$default_cmax = ((Apps::system_app_installed(local_channel(),'Affinity Tool')) ? get_pconfig(local_channel(),'affinity','cmax',99) : (-1));
|
||||
|
||||
$cid = ((x($_GET,'cid')) ? intval($_GET['cid']) : 0);
|
||||
$star = ((x($_GET,'star')) ? intval($_GET['star']) : 0);
|
||||
@ -132,6 +134,13 @@ class Network extends \Zotlabs\Web\Controller {
|
||||
|
||||
$deftag = '';
|
||||
|
||||
if (Apps::system_app_installed(local_channel(),'Affinity Tool')) {
|
||||
$affinity_locked = intval(get_pconfig(local_channel(),'affinity','lock',1));
|
||||
if ($affinity_locked) {
|
||||
set_pconfig(local_channel(),'affinity','cmin',$cmin);
|
||||
set_pconfig(local_channel(),'affinity','cmax',$cmax);
|
||||
}
|
||||
}
|
||||
|
||||
if(x($_GET,'search') || $file || (!$pf && $cid) || $hashtags || $verb || $category || $conv || $unseen)
|
||||
$nouveau = true;
|
||||
|
@ -1,15 +0,0 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
|
||||
class Nojs extends \Zotlabs\Web\Controller {
|
||||
|
||||
function init() {
|
||||
$n = ((argc() > 1) ? intval(argv(1)) : 1);
|
||||
setcookie('jsdisabled', $n, 0, '/');
|
||||
$p = hex2bin($_GET['redir']);
|
||||
$hasq = strpbrk($p,'?&');
|
||||
goaway(z_root() . (($p) ? '/' . $p : '') . (($hasq) ? '' : '?f=' ) . '&jsdisabled=' . $n);
|
||||
|
||||
}
|
||||
}
|
@ -1,10 +1,13 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module; /** @file */
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Web\Controller;
|
||||
use Zotlabs\Lib\Apps;
|
||||
|
||||
/**
|
||||
* @brief Notes Module controller.
|
||||
*/
|
||||
class Notes extends Controller {
|
||||
|
||||
function post() {
|
||||
@ -40,11 +43,9 @@ class Notes extends Controller {
|
||||
|
||||
logger('notes saved.', LOGGER_DEBUG);
|
||||
json_return_and_die($ret);
|
||||
|
||||
}
|
||||
|
||||
function get() {
|
||||
|
||||
if(! local_channel())
|
||||
return EMPTY_STR;
|
||||
|
||||
@ -61,7 +62,6 @@ class Notes extends Controller {
|
||||
$arr = ['app' => true];
|
||||
|
||||
return $w->widget($arr);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -456,7 +456,7 @@ class Oep extends \Zotlabs\Web\Controller {
|
||||
|
||||
if(preg_match('|//(.*?)/(.*?)/(.*?)/album/|',$url,$matches)) {
|
||||
$chn = $matches[3];
|
||||
$res = hex2bin(basename($url));
|
||||
$res = basename($url);
|
||||
}
|
||||
|
||||
if(! ($chn && $res))
|
||||
|
@ -24,7 +24,7 @@ class Pconfig extends \Zotlabs\Web\Controller {
|
||||
$aj = intval($_POST['aj']);
|
||||
|
||||
// Do not store "serialized" data received in the $_POST
|
||||
if (preg_match('|^a:[0-9]+:{.*}$|s',$v) || preg_match('O:8:"stdClass":[0-9]+:{.*}$|s',$v)) {
|
||||
if (preg_match('|^a:[0-9]+:{.*}$|s',$v) || preg_match('|O:8:"stdClass":[0-9]+:{.*}$|s',$v)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,19 +1,20 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
require_once('include/security.php');
|
||||
require_once('include/attach.php');
|
||||
require_once('include/photo/photo_driver.php');
|
||||
|
||||
|
||||
class Photo extends \Zotlabs\Web\Controller {
|
||||
|
||||
function init() {
|
||||
|
||||
$prvcachecontrol = false;
|
||||
$streaming = null;
|
||||
$channel = null;
|
||||
$person = 0;
|
||||
$renew = false;
|
||||
|
||||
switch(argc()) {
|
||||
case 4:
|
||||
@ -30,6 +31,14 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
// NOTREACHED
|
||||
}
|
||||
|
||||
$cache_mode = array(
|
||||
'on' => false,
|
||||
'age' => 86400,
|
||||
'exp' => true,
|
||||
'leak' => false
|
||||
);
|
||||
call_hooks('cache_mode_hook', $cache_mode);
|
||||
|
||||
$observer_xchan = get_observer_hash();
|
||||
$ismodified = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
|
||||
|
||||
@ -106,13 +115,14 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
License link: http://creativecommons.org/licenses/by/3.0/
|
||||
*/
|
||||
|
||||
// @FIXME It seems this part doesn't work because we are not setting such cookie
|
||||
$cookie_value = false;
|
||||
if (isset($_COOKIE['devicePixelRatio'])) {
|
||||
$cookie_value = intval($_COOKIE['devicePixelRatio']);
|
||||
}
|
||||
else {
|
||||
// Force revalidation of cache on next request
|
||||
$cache_directive = 'no-cache';
|
||||
// $prvcachecontrol = 'no-cache';
|
||||
$status = 'no cookie';
|
||||
}
|
||||
|
||||
@ -129,27 +139,42 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
$resolution = 1;
|
||||
}
|
||||
|
||||
$r = q("SELECT uid, photo_usage FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
|
||||
$r = q("SELECT uid, photo_usage, display_path FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
|
||||
dbesc($photo),
|
||||
intval($resolution)
|
||||
);
|
||||
if($r) {
|
||||
|
||||
$allowed = (-1);
|
||||
|
||||
if(intval($r[0]['photo_usage'])) {
|
||||
$u = intval($r[0]['photo_usage']);
|
||||
if($u) {
|
||||
$allowed = 1;
|
||||
if(intval($r[0]['photo_usage']) === PHOTO_COVER)
|
||||
if($u === PHOTO_COVER)
|
||||
if($resolution < PHOTO_RES_COVER_1200)
|
||||
$allowed = (-1);
|
||||
if(intval($r[0]['photo_usage']) === PHOTO_PROFILE)
|
||||
if($u === PHOTO_PROFILE)
|
||||
if(! in_array($resolution,[4,5,6]))
|
||||
$allowed = (-1);
|
||||
if($u === PHOTO_CACHE) {
|
||||
// Validate cache
|
||||
$cache = array(
|
||||
'resid' => $photo,
|
||||
'status' => false
|
||||
);
|
||||
if($cache_mode['on'])
|
||||
call_hooks('cache_url_hook', $cache);
|
||||
if(! $cache['status']) {
|
||||
$url = htmlspecialchars_decode($r[0]['display_path']);
|
||||
if(strpos(z_root(),'https:') !== false && strpos($url,'https:') === false)
|
||||
$url = z_root() . '/sslify/' . $filename . '?f=&url=' . urlencode($url);
|
||||
header("Location: " . $url);
|
||||
killme();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($allowed === (-1)) {
|
||||
if($allowed === (-1))
|
||||
$allowed = attach_can_view($r[0]['uid'],$observer_xchan,$photo);
|
||||
}
|
||||
|
||||
$channel = channelx_by_n($r[0]['uid']);
|
||||
|
||||
@ -162,14 +187,17 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
$exists = (($e) ? true : false);
|
||||
|
||||
if($exists && $allowed) {
|
||||
$expires = strtotime($e[0]['expires'] . 'Z');
|
||||
$data = dbunescbin($e[0]['content']);
|
||||
$filesize = $e[0]['filesize'];
|
||||
$mimetype = $e[0]['mimetype'];
|
||||
$modified = strtotime($e[0]['edited'] . 'Z');
|
||||
if(intval($e[0]['os_storage']))
|
||||
|
||||
if(intval($e[0]['os_storage'])) {
|
||||
$streaming = $data;
|
||||
}
|
||||
if($e[0]['allow_cid'] != '' || $e[0]['allow_gid'] != '' || $e[0]['deny_gid'] != '' || $e[0]['deny_gid'] != '')
|
||||
$prvcachecontrol = true;
|
||||
$prvcachecontrol = 'no-store, no-cache, must-revalidate';
|
||||
}
|
||||
else {
|
||||
if(! $allowed) {
|
||||
@ -180,9 +208,9 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
http_status_exit(404,'not found');
|
||||
}
|
||||
else
|
||||
http_status_exit(404,'not found');
|
||||
}
|
||||
|
||||
header_remove('Pragma');
|
||||
@ -226,23 +254,13 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
|
||||
// @FIXME Seems never invoked
|
||||
// Writing in cachefile
|
||||
if (isset($cachefile) && $cachefile != '') {
|
||||
file_put_contents($cachefile, $data);
|
||||
$modified = filemtime($cachefile);
|
||||
}
|
||||
|
||||
|
||||
header("Content-type: " . $mimetype);
|
||||
|
||||
if($prvcachecontrol) {
|
||||
if(isset($prvcachecontrol)) {
|
||||
|
||||
// it is a private photo that they have no permission to view.
|
||||
// tell the browser not to cache it, in case they authenticate
|
||||
// and subsequently have permission to see it
|
||||
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
header("Cache-Control: " . $prvcachecontrol);
|
||||
|
||||
}
|
||||
else {
|
||||
@ -255,18 +273,23 @@ class Photo extends \Zotlabs\Web\Controller {
|
||||
// This has performance considerations but we highly recommend you
|
||||
// leave it alone.
|
||||
|
||||
$cache = get_config('system','photo_cache_time', 86400); // 1 day by default
|
||||
$maxage = $cache_mode['age'];
|
||||
|
||||
header("Expires: " . gmdate("D, d M Y H:i:s", time() + $cache) . " GMT");
|
||||
header("Cache-Control: max-age=" . $cache);
|
||||
if($cache_mode['exp'] || (! isset($expires)) || (isset($expires) && $expires - 60 < time()))
|
||||
$expires = time() + $maxage;
|
||||
else
|
||||
$maxage = $expires - time();
|
||||
|
||||
header("Expires: " . gmdate("D, d M Y H:i:s", $expires) . " GMT");
|
||||
header("Cache-Control: max-age=" . $maxage);
|
||||
|
||||
}
|
||||
|
||||
header("Content-type: " . $mimetype);
|
||||
header("Last-Modified: " . gmdate("D, d M Y H:i:s", $modified) . " GMT");
|
||||
header("Content-Length: " . (isset($filesize) ? $filesize : strlen($data)));
|
||||
|
||||
// If it's a file resource, stream it.
|
||||
|
||||
if($streaming && $channel) {
|
||||
if(strpos($streaming,'store') !== false)
|
||||
$istream = fopen($streaming,'rb');
|
||||
|
@ -422,7 +422,7 @@ class Photos extends \Zotlabs\Web\Controller {
|
||||
require_once('include/text.php');
|
||||
$profile_uid = \App::$profile['profile_uid'];
|
||||
|
||||
$results = linkify_tags($a, $rawtags, (local_channel()) ? local_channel() : $profile_uid);
|
||||
$results = linkify_tags($rawtags, (local_channel()) ? local_channel() : $profile_uid);
|
||||
|
||||
$success = $results['success'];
|
||||
$post_tags = array();
|
||||
|
@ -354,20 +354,20 @@ class Profiles extends \Zotlabs\Web\Controller {
|
||||
|
||||
|
||||
require_once('include/text.php');
|
||||
linkify_tags($a, $likes, local_channel());
|
||||
linkify_tags($a, $dislikes, local_channel());
|
||||
linkify_tags($a, $about, local_channel());
|
||||
linkify_tags($a, $interest, local_channel());
|
||||
linkify_tags($a, $interest, local_channel());
|
||||
linkify_tags($a, $contact, local_channel());
|
||||
linkify_tags($a, $channels, local_channel());
|
||||
linkify_tags($a, $music, local_channel());
|
||||
linkify_tags($a, $book, local_channel());
|
||||
linkify_tags($a, $tv, local_channel());
|
||||
linkify_tags($a, $film, local_channel());
|
||||
linkify_tags($a, $romance, local_channel());
|
||||
linkify_tags($a, $work, local_channel());
|
||||
linkify_tags($a, $education, local_channel());
|
||||
linkify_tags($likes, local_channel());
|
||||
linkify_tags($dislikes, local_channel());
|
||||
linkify_tags($about, local_channel());
|
||||
linkify_tags($interest, local_channel());
|
||||
linkify_tags($interest, local_channel());
|
||||
linkify_tags($contact, local_channel());
|
||||
linkify_tags($channels, local_channel());
|
||||
linkify_tags($music, local_channel());
|
||||
linkify_tags($book, local_channel());
|
||||
linkify_tags($tv, local_channel());
|
||||
linkify_tags($film, local_channel());
|
||||
linkify_tags($romance, local_channel());
|
||||
linkify_tags($work, local_channel());
|
||||
linkify_tags($education, local_channel());
|
||||
|
||||
|
||||
$with = ((x($_POST,'with')) ? escape_tags(trim($_POST['with'])) : '');
|
||||
|
@ -44,6 +44,7 @@ class React extends \Zotlabs\Web\Controller {
|
||||
return;
|
||||
}
|
||||
|
||||
$uuid = item_message_id();
|
||||
|
||||
$n = array();
|
||||
$n['aid'] = $channel['channel_account_id'];
|
||||
@ -52,7 +53,8 @@ class React extends \Zotlabs\Web\Controller {
|
||||
$n['item_type'] = $i[0]['item_type'];
|
||||
$n['parent'] = $postid;
|
||||
$n['parent_mid'] = $i[0]['mid'];
|
||||
$n['mid'] = item_message_id();
|
||||
$n['uuid'] = $uuid;
|
||||
$n['mid'] = z_root() . '/item/' . $uuid;
|
||||
$n['verb'] = ACTIVITY_REACT . '#' . $emoji;
|
||||
$n['body'] = "\n\n[zmg=32x32]" . z_root() . '/images/emoji/' . $emoji . '.png[/zmg]' . "\n\n";
|
||||
$n['author_xchan'] = $channel['channel_hash'];
|
||||
|
@ -14,6 +14,15 @@ class Rmagic extends \Zotlabs\Web\Controller {
|
||||
$r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1",
|
||||
dbesc($me)
|
||||
);
|
||||
if(! $r) {
|
||||
$w = discover_by_webbie($me);
|
||||
if($w) {
|
||||
$r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1",
|
||||
dbesc($me)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if($r) {
|
||||
if($r[0]['hubloc_url'] === z_root())
|
||||
goaway(z_root() . '/login');
|
||||
@ -49,7 +58,16 @@ class Rmagic extends \Zotlabs\Web\Controller {
|
||||
$r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1",
|
||||
dbesc($address)
|
||||
);
|
||||
if(! $r) {
|
||||
$w = discover_by_webbie($address);
|
||||
if($w) {
|
||||
$r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1",
|
||||
dbesc($address)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($r) {
|
||||
$url = $r[0]['hubloc_url'];
|
||||
}
|
||||
|
@ -10,20 +10,6 @@ class Featured {
|
||||
|
||||
call_hooks('feature_settings_post', $_POST);
|
||||
|
||||
if($_POST['affinity_slider-submit']) {
|
||||
$cmax = intval($_POST['affinity_cmax']);
|
||||
if($cmax < 0 || $cmax > 99)
|
||||
$cmax = 99;
|
||||
$cmin = intval($_POST['affinity_cmin']);
|
||||
if($cmin < 0 || $cmin > 99)
|
||||
$cmin = 0;
|
||||
set_pconfig(local_channel(),'affinity','cmin',$cmin);
|
||||
set_pconfig(local_channel(),'affinity','cmax',$cmax);
|
||||
|
||||
info( t('Affinity Slider settings updated.') . EOL);
|
||||
|
||||
}
|
||||
|
||||
build_sync_packet();
|
||||
return;
|
||||
}
|
||||
@ -37,30 +23,10 @@ class Featured {
|
||||
if(! $r)
|
||||
$settings_addons = t('No feature settings configured');
|
||||
|
||||
if(feature_enabled(local_channel(),'affinity')) {
|
||||
|
||||
$cmax = intval(get_pconfig(local_channel(),'affinity','cmax'));
|
||||
$cmax = (($cmax) ? $cmax : 99);
|
||||
$setting_fields .= replace_macros(get_markup_template('field_input.tpl'), array(
|
||||
'$field' => array('affinity_cmax', t('Default maximum affinity level'), $cmax, t('0-99 default 99'))
|
||||
));
|
||||
$cmin = intval(get_pconfig(local_channel(),'affinity','cmin'));
|
||||
$cmin = (($cmin) ? $cmin : 0);
|
||||
$setting_fields .= replace_macros(get_markup_template('field_input.tpl'), array(
|
||||
'$field' => array('affinity_cmin', t('Default minimum affinity level'), $cmin, t('0-99 - default 0'))
|
||||
));
|
||||
|
||||
$settings_addons .= replace_macros(get_markup_template('generic_addon_settings.tpl'), array(
|
||||
'$addon' => array('affinity_slider', '' . t('Affinity Slider Settings'), '', t('Submit')),
|
||||
'$content' => $setting_fields
|
||||
));
|
||||
}
|
||||
|
||||
call_hooks('feature_settings', $settings_addons);
|
||||
|
||||
$this->sortpanels($settings_addons);
|
||||
|
||||
|
||||
$tpl = get_markup_template("settings_addons.tpl");
|
||||
$o .= replace_macros($tpl, array(
|
||||
'$form_security_token' => get_form_security_token("settings_featured"),
|
||||
|
@ -39,12 +39,12 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
ini_set('display_errors', '1');
|
||||
|
||||
// $baseurl/setup/testrewrite to test if rewrite in .htaccess is working
|
||||
if (argc() == 2 && argv(1) == "testrewrite") {
|
||||
if(argc() == 2 && argv(1) == 'testrewrite') {
|
||||
echo 'ok';
|
||||
killme();
|
||||
}
|
||||
|
||||
if (x($_POST, 'pass')) {
|
||||
if(x($_POST, 'pass')) {
|
||||
$this->install_wizard_pass = intval($_POST['pass']);
|
||||
} else {
|
||||
$this->install_wizard_pass = 1;
|
||||
@ -63,7 +63,6 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
return;
|
||||
// implied break;
|
||||
case 3:
|
||||
$urlpath = \App::get_path();
|
||||
$dbhost = trim($_POST['dbhost']);
|
||||
$dbport = intval(trim($_POST['dbport']));
|
||||
$dbuser = trim($_POST['dbuser']);
|
||||
@ -89,7 +88,6 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
return;
|
||||
// implied break;
|
||||
case 4:
|
||||
$urlpath = \App::get_path();
|
||||
$dbhost = trim($_POST['dbhost']);
|
||||
$dbport = intval(trim($_POST['dbport']));
|
||||
$dbuser = trim($_POST['dbuser']);
|
||||
@ -162,7 +160,6 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
*
|
||||
* @return string parsed HTML output
|
||||
*/
|
||||
|
||||
function get() {
|
||||
|
||||
$o = '';
|
||||
@ -213,10 +210,10 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
if(x(\App::$data, 'txt') && strlen(\App::$data['txt'])) {
|
||||
$db_return_text .= $this->manual_config($a);
|
||||
$db_return_text .= $this->manual_config();
|
||||
}
|
||||
|
||||
if ($db_return_text != "") {
|
||||
if($db_return_text != '') {
|
||||
$tpl = get_markup_template('install.tpl');
|
||||
return replace_macros($tpl, array(
|
||||
'$title' => $install_title,
|
||||
@ -242,7 +239,7 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
|
||||
$this->check_keys($checks);
|
||||
|
||||
if (x($_POST, 'phpath'))
|
||||
if(x($_POST, 'phpath'))
|
||||
$phpath = notags(trim($_POST['phpath']));
|
||||
|
||||
$this->check_php($phpath, $checks);
|
||||
@ -278,7 +275,6 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
$dbtype = intval(trim($_POST['dbtype']));
|
||||
$phpath = trim($_POST['phpath']);
|
||||
$adminmail = trim($_POST['adminmail']);
|
||||
$siteurl = trim($_POST['siteurl']);
|
||||
|
||||
$tpl = get_markup_template('install_db.tpl');
|
||||
$o .= replace_macros($tpl, array(
|
||||
@ -320,7 +316,6 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
$phpath = trim($_POST['phpath']);
|
||||
|
||||
$adminmail = trim($_POST['adminmail']);
|
||||
$siteurl = trim($_POST['siteurl']);
|
||||
$timezone = ((x($_POST,'timezone')) ? ($_POST['timezone']) : 'America/Los_Angeles');
|
||||
|
||||
|
||||
@ -363,12 +358,12 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
* @param string $help optional help string
|
||||
*/
|
||||
function check_add(&$checks, $title, $status, $required, $help = '') {
|
||||
$checks[] = array(
|
||||
$checks[] = [
|
||||
'title' => $title,
|
||||
'status' => $status,
|
||||
'required' => $required,
|
||||
'help' => $help
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -380,12 +375,12 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
function check_php(&$phpath, &$checks) {
|
||||
$help = '';
|
||||
|
||||
if(version_compare(PHP_VERSION, '5.5') < 0) {
|
||||
$help .= t('PHP version 5.5 or greater is required.');
|
||||
if(version_compare(PHP_VERSION, '7.1') < 0) {
|
||||
$help .= t('PHP version 7.1 or greater is required.');
|
||||
$this->check_add($checks, t('PHP version'), false, false, $help);
|
||||
}
|
||||
|
||||
if (strlen($phpath)) {
|
||||
if(strlen($phpath)) {
|
||||
$passed = file_exists($phpath);
|
||||
}
|
||||
elseif(function_exists('shell_exec')) {
|
||||
@ -419,6 +414,7 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
$result = trim(shell_exec($cmd));
|
||||
else
|
||||
$help .= t('Unable to check command line PHP, as shell_exec() is disabled. This is required.') . EOL;
|
||||
|
||||
$passed2 = (($result == $str) ? true : false);
|
||||
if(!$passed2) {
|
||||
$help .= t('The command line version of PHP on your system does not have "register_argc_argv" enabled.'). EOL;
|
||||
@ -441,13 +437,18 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
require_once 'include/environment.php';
|
||||
|
||||
$help = '';
|
||||
$mem_warning = '';
|
||||
|
||||
$result = getPhpiniUploadLimits();
|
||||
if($result['post_max_size'] < 4194304 || $result['max_upload_filesize'] < 4194304) {
|
||||
$mem_warning = '<strong>' .t('This is not sufficient to upload larger images or files. You should be able to upload at least 4 MB at once.') . '</strong>';
|
||||
}
|
||||
$help = sprintf(t('Your max allowed total upload size is set to %s. Maximum size of one file to upload is set to %s. You are allowed to upload up to %d files at once.'),
|
||||
userReadableSize($result['post_max_size']),
|
||||
userReadableSize($result['max_upload_filesize']),
|
||||
$result['max_file_uploads']
|
||||
);
|
||||
$help .= $mem_warning;
|
||||
$help .= '<br><br>' . t('You can adjust these settings in the server php.ini file.');
|
||||
|
||||
$this->check_add($checks, t('PHP upload limits'), true, false, $help);
|
||||
@ -462,7 +463,7 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
$help = '';
|
||||
$res = false;
|
||||
|
||||
if (function_exists('openssl_pkey_new')) {
|
||||
if(function_exists('openssl_pkey_new')) {
|
||||
$res = openssl_pkey_new(array(
|
||||
'digest_alg' => 'sha1',
|
||||
'private_key_bits' => 4096,
|
||||
@ -472,7 +473,7 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
|
||||
// Get private key
|
||||
|
||||
if (! $res) {
|
||||
if(! $res) {
|
||||
$help .= t('Error: the "openssl_pkey_new" function on this system is not able to generate encryption keys'). EOL;
|
||||
$help .= t('If running under Windows, please see "http://www.php.net/manual/en/openssl.installation.php".');
|
||||
}
|
||||
@ -503,7 +504,7 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
$this->check_add($ck_funcs, t('zip PHP module'), true, true);
|
||||
|
||||
if(function_exists('apache_get_modules')){
|
||||
if (! in_array('mod_rewrite', apache_get_modules())) {
|
||||
if(! in_array('mod_rewrite', apache_get_modules())) {
|
||||
$this->check_add($ck_funcs, t('Apache mod_rewrite module'), false, true, t('Error: Apache webserver mod-rewrite module is required but not installed.'));
|
||||
} else {
|
||||
$this->check_add($ck_funcs, t('Apache mod_rewrite module'), true, true);
|
||||
@ -638,7 +639,7 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
|
||||
$url = z_root() . '/setup/testrewrite';
|
||||
|
||||
if (function_exists('curl_init')){
|
||||
if(function_exists('curl_init')){
|
||||
$test = z_fetch_url($url);
|
||||
if(! $test['success']) {
|
||||
if(strstr($url,'https://')) {
|
||||
@ -661,14 +662,13 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
$help .= t('If your certificate is not recognized, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues.') . EOL;
|
||||
$help .= t('This can cause usability issues elsewhere (not just on your own site) so we must insist on this requirement.') .EOL;
|
||||
$help .= t('Providers are available that issue free certificates which are browser-valid.'). EOL;
|
||||
|
||||
$help .= t('If you are confident that the certificate is valid and signed by a trusted authority, check to see if you have failed to install an intermediate cert. These are not normally required by browsers, but are required for server-to-server communications.') . EOL;
|
||||
|
||||
$this->check_add($checks, t('SSL certificate validation'), false, true, $help);
|
||||
}
|
||||
}
|
||||
|
||||
if ((! $test['success']) || ($test['body'] != "ok")) {
|
||||
if((! $test['success']) || ($test['body'] != "ok")) {
|
||||
$status = false;
|
||||
$help = t('Url rewrite in .htaccess is not working. Check your server configuration.'.'Test: '.var_export($test,true));
|
||||
}
|
||||
@ -682,10 +682,9 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param App &$a
|
||||
* @return string with paresed HTML
|
||||
*/
|
||||
function manual_config(&$a) {
|
||||
function manual_config() {
|
||||
$data = htmlspecialchars(\App::$data['txt'], ENT_COMPAT, 'UTF-8');
|
||||
$o = t('The database configuration file ".htconfig.php" could not be written. Please use the enclosed text to create a configuration file in your web server root.');
|
||||
$o .= "<textarea rows=\"24\" cols=\"80\" >$data</textarea>";
|
||||
@ -695,14 +694,19 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
|
||||
function load_database_rem($v, $i){
|
||||
$l = trim($i);
|
||||
if (strlen($l)>1 && ($l[0]=="-" || ($l[0]=="/" && $l[1]=="*"))){
|
||||
if(strlen($l)>1 && ($l[0]=="-" || ($l[0]=="/" && $l[1]=="*"))){
|
||||
return $v;
|
||||
} else {
|
||||
return $v."\n".$i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Executes the SQL install script and create database tables.
|
||||
*
|
||||
* @param dba_driver $db (unused)
|
||||
* @return boolean|string false on success or error message as string
|
||||
*/
|
||||
function load_database($db) {
|
||||
$str = file_get_contents(\DBA::$dba->get_install_script());
|
||||
$arr = explode(';', $str);
|
||||
@ -762,12 +766,12 @@ class Setup extends \Zotlabs\Web\Controller {
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param unknown $v
|
||||
* @param array $v
|
||||
* @param array $c
|
||||
* @return array
|
||||
*/
|
||||
static private function check_passed($v, $c) {
|
||||
if ($c['required'])
|
||||
if($c['required'])
|
||||
$v = $v && $c['status'];
|
||||
|
||||
return $v;
|
||||
|
@ -1,6 +1,11 @@
|
||||
<?php
|
||||
namespace Zotlabs\Module;
|
||||
|
||||
use App;
|
||||
use Zotlabs\Daemon\Master;
|
||||
use Zotlabs\Lib\Activity;
|
||||
|
||||
|
||||
require_once('include/security.php');
|
||||
require_once('include/bbcode.php');
|
||||
|
||||
@ -14,23 +19,23 @@ class Share extends \Zotlabs\Web\Controller {
|
||||
if(! $post_id)
|
||||
killme();
|
||||
|
||||
echo '[share=' . $post_id . '][/share]';
|
||||
if(! local_channel()) {
|
||||
killme();
|
||||
}
|
||||
|
||||
$observer = App::get_observer();
|
||||
|
||||
/**
|
||||
* The remaining code is deprecated and handled in Zotlabs/Lib/Share.php at post
|
||||
* submission time.
|
||||
*/
|
||||
|
||||
if(! (local_channel() || remote_channel()))
|
||||
killme();
|
||||
$channel = App::get_channel();
|
||||
|
||||
$r = q("SELECT * from item left join xchan on author_xchan = xchan_hash WHERE id = %d LIMIT 1",
|
||||
intval($post_id)
|
||||
);
|
||||
if(! $r)
|
||||
killme();
|
||||
|
||||
|
||||
|
||||
|
||||
if(($r[0]['item_private']) && ($r[0]['xchan_network'] !== 'rss'))
|
||||
killme();
|
||||
|
||||
@ -47,58 +52,85 @@ class Share extends \Zotlabs\Web\Controller {
|
||||
if($r[0]['mimetype'] !== 'text/bbcode')
|
||||
killme();
|
||||
|
||||
/** @FIXME eventually we want to post remotely via rpost on your home site */
|
||||
// When that works remove this next bit:
|
||||
|
||||
if(! local_channel())
|
||||
killme();
|
||||
|
||||
xchan_query($r);
|
||||
|
||||
$is_photo = (($r[0]['obj_type'] === ACTIVITY_OBJ_PHOTO) ? true : false);
|
||||
if($is_photo) {
|
||||
$object = json_decode($r[0]['obj'],true);
|
||||
$photo_bb = $object['body'];
|
||||
}
|
||||
$arr = [];
|
||||
|
||||
if (strpos($r[0]['body'], "[/share]") !== false) {
|
||||
$pos = strpos($r[0]['body'], "[share");
|
||||
$o = substr($r[0]['body'], $pos);
|
||||
} else {
|
||||
$o = "[share author='" . urlencode($r[0]['author']['xchan_name']) .
|
||||
"' profile='" . $r[0]['author']['xchan_url'] .
|
||||
"' avatar='" . $r[0]['author']['xchan_photo_s'] .
|
||||
"' link='" . $r[0]['plink'] .
|
||||
"' auth='" . (($r[0]['author']['network'] === 'zot') ? 'true' : 'false') .
|
||||
"' posted='" . $r[0]['created'] .
|
||||
"' message_id='" . $r[0]['mid'] .
|
||||
"']";
|
||||
if($r[0]['title'])
|
||||
$o .= '[b]'.$r[0]['title'].'[/b]'."\r\n";
|
||||
$o .= (($is_photo) ? $photo_bb . "\r\n" . $r[0]['body'] : $r[0]['body']);
|
||||
$o .= "[/share]";
|
||||
}
|
||||
$item = $r[0];
|
||||
|
||||
if(local_channel()) {
|
||||
echo $o;
|
||||
$owner_uid = $r[0]['uid'];
|
||||
$owner_aid = $r[0]['aid'];
|
||||
|
||||
$can_comment = false;
|
||||
if((array_key_exists('owner',$item)) && intval($item['owner']['abook_self']))
|
||||
$can_comment = perm_is_allowed($item['uid'],$observer['xchan_hash'],'post_comments');
|
||||
else
|
||||
$can_comment = can_comment_on_post($observer['xchan_hash'],$item);
|
||||
|
||||
if(! $can_comment) {
|
||||
notice( t('Permission denied') . EOL);
|
||||
killme();
|
||||
}
|
||||
|
||||
$observer = \App::get_observer();
|
||||
$parsed = $observer['xchan_url'];
|
||||
if($parsed) {
|
||||
$post_url = $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : '')
|
||||
. '/rpost';
|
||||
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
|
||||
dbesc($item['owner_xchan'])
|
||||
);
|
||||
|
||||
/**
|
||||
* @FIXME we were probably called from JS so we don't know the return page.
|
||||
* In fact we won't be able to load the remote page.
|
||||
* we might need an iframe
|
||||
*/
|
||||
|
||||
$x = z_post_url($post_url, array('f' => '', 'body' => $o ));
|
||||
if($r)
|
||||
$thread_owner = $r[0];
|
||||
else
|
||||
killme();
|
||||
|
||||
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
|
||||
dbesc($item['author_xchan'])
|
||||
);
|
||||
if($r)
|
||||
$item_author = $r[0];
|
||||
else
|
||||
killme();
|
||||
|
||||
|
||||
$arr['aid'] = $owner_aid;
|
||||
$arr['uid'] = $owner_uid;
|
||||
|
||||
$arr['item_origin'] = 1;
|
||||
$arr['item_wall'] = $item['item_wall'];
|
||||
$arr['uuid'] = item_message_id();
|
||||
$arr['mid'] = z_root() . '/activity/' . $arr['uuid'];
|
||||
$arr['parent_mid'] = $item['mid'];
|
||||
|
||||
$mention = '@[zrl=' . $item['author']['xchan_url'] . ']' . $item['author']['xchan_name'] . '[/zrl]';
|
||||
$arr['body'] = sprintf( t('🔁 Repeated %1$s\'s %2$s'), $mention, Activity::activity_obj_mapper($item['obj_type']));
|
||||
|
||||
$arr['author_xchan'] = $channel['channel_hash'];
|
||||
$arr['owner_xchan'] = $item['author_xchan'];
|
||||
$arr['obj'] = Activity::encode_item($item);
|
||||
$arr['obj_type'] = $item['obj_type'];
|
||||
$arr['verb'] = 'Announce';
|
||||
|
||||
$post = item_store($arr);
|
||||
|
||||
$post_id = $post['item_id'];
|
||||
|
||||
$arr['id'] = $post_id;
|
||||
|
||||
call_hooks('post_local_end', $arr);
|
||||
|
||||
info( t('Post repeated') . EOL);
|
||||
|
||||
$r = q("select * from item where id = %d",
|
||||
intval($post_id)
|
||||
);
|
||||
if($r) {
|
||||
xchan_query($r);
|
||||
$sync_item = fetch_post_tags($r);
|
||||
build_sync_packet($channel['channel_id'], [ 'item' => [ encode_item($sync_item[0],true) ] ]);
|
||||
}
|
||||
|
||||
Master::Summon([ 'Notifier','like',$post_id ]);
|
||||
|
||||
killme();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,10 +12,16 @@ class Sslify extends \Zotlabs\Web\Controller {
|
||||
list($k,$v) = array_map("trim", explode(":", trim($l), 2));
|
||||
$hdrs[strtolower($k)] = $v;
|
||||
}
|
||||
if (array_key_exists('content-type', $hdrs)) {
|
||||
$type = $hdrs['content-type'];
|
||||
header('Content-Type: ' . $type);
|
||||
}
|
||||
|
||||
if (array_key_exists('content-type', $hdrs))
|
||||
header('Content-Type: ' . $hdrs['content-type']);
|
||||
if (array_key_exists('last-modified', $hdrs))
|
||||
header('Last-Modified: ' . $hdrs['last-modified']);
|
||||
if (array_key_exists('cache-control', $hdrs))
|
||||
header('Cache-Control: ' . $hdrs['cache-control']);
|
||||
if (array_key_exists('expires', $hdrs))
|
||||
header('Expires: ' . $hdrs['expires']);
|
||||
|
||||
|
||||
echo $x['body'];
|
||||
killme();
|
||||
|
@ -106,7 +106,8 @@ class Subthread extends \Zotlabs\Web\Controller {
|
||||
|
||||
|
||||
|
||||
$mid = item_message_id();
|
||||
$uuid = item_message_id();
|
||||
$mid = z_root() . '/item/' . $uuid;
|
||||
|
||||
$post_type = (($item['resource_type'] === 'photo') ? t('photo') : t('status'));
|
||||
|
||||
@ -145,6 +146,7 @@ class Subthread extends \Zotlabs\Web\Controller {
|
||||
|
||||
$arr = array();
|
||||
|
||||
$arr['uuid'] = $uuid;
|
||||
$arr['mid'] = $mid;
|
||||
$arr['aid'] = $owner_aid;
|
||||
$arr['uid'] = $owner_uid;
|
||||
|
@ -25,10 +25,10 @@ class Viewsrc extends \Zotlabs\Web\Controller {
|
||||
notice( t('Item not found.') . EOL);
|
||||
}
|
||||
|
||||
$item_normal = item_normal();
|
||||
$item_normal = item_normal_search();
|
||||
|
||||
if(local_channel() && $item_id) {
|
||||
$r = q("select id, item_flags, mimetype, item_obscured, body, llink, plink from item where uid in (%d , %d) and id = %d $item_normal limit 1",
|
||||
$r = q("select id, mid, item_flags, mimetype, item_obscured, body, llink, plink from item where uid in (%d , %d) and id = %d $item_normal limit 1",
|
||||
intval(local_channel()),
|
||||
intval($sys['channel_id']),
|
||||
intval($item_id)
|
||||
@ -53,7 +53,7 @@ class Viewsrc extends \Zotlabs\Web\Controller {
|
||||
|
||||
if(is_ajax()) {
|
||||
echo '<div class="p-1">';
|
||||
echo '<div>id: ' . $r[0]['id'] . ' | <a href="' . $r[0]['plink'] . '" target="_blank">plink</a> | <a href="' . $r[0]['llink'] . '" target="_blank">llink</a></div>';
|
||||
echo '<div>id: ' . $r[0]['id'] . ' | <a href="' . $r[0]['plink'] . '" target="_blank">plink</a> | <a href="' . $r[0]['llink'] . '" target="_blank">llink</a><br>mid: ' . $r[0]['mid'] . '</div>';
|
||||
echo '<hr>';
|
||||
echo '<pre class="p-1">' . $o . '</pre>';
|
||||
echo '</div>';
|
||||
|
@ -43,6 +43,9 @@ class Wfinger extends \Zotlabs\Web\Controller {
|
||||
|
||||
if(strpos($resource,'acct:') === 0) {
|
||||
$channel = str_replace('acct:','',$resource);
|
||||
if(substr($channel,0,1) === '@' && strpos(substr($channel,1),'@')) {
|
||||
$channel = substr($channel,1);
|
||||
}
|
||||
if(strpos($channel,'@') !== false) {
|
||||
$host = substr($channel,strpos($channel,'@')+1);
|
||||
|
||||
@ -204,6 +207,12 @@ class Wfinger extends \Zotlabs\Web\Controller {
|
||||
'href' => z_root() . '/.well-known/zot-info' . '?address=' . $r[0]['xchan_addr'],
|
||||
],
|
||||
|
||||
[
|
||||
'rel' => 'http://purl.org/zot/protocol/6.0',
|
||||
'type' => 'application/x-zot+json',
|
||||
'href' => channel_url($r[0])
|
||||
],
|
||||
|
||||
[
|
||||
'rel' => 'http://purl.org/openwebauth/v1',
|
||||
'type' => 'application/x-zot+json',
|
||||
|
498
Zotlabs/Photo/PhotoDriver.php
Normal file
498
Zotlabs/Photo/PhotoDriver.php
Normal file
@ -0,0 +1,498 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Photo;
|
||||
|
||||
/**
|
||||
* @brief Abstract photo driver class.
|
||||
*
|
||||
* Inheritance seems not to be the best design pattern for such photo drivers.
|
||||
*/
|
||||
abstract class PhotoDriver {
|
||||
|
||||
/**
|
||||
* @brief This variable keeps the image.
|
||||
*
|
||||
* For GD it is a PHP image resource.
|
||||
* For ImageMagick it is an \Imagick object.
|
||||
*
|
||||
* @var resource|\Imagick
|
||||
*/
|
||||
protected $image;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
protected $width;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
protected $height;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $valid;
|
||||
|
||||
/**
|
||||
* @brief The mimetype of the image.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* @brief Supported mimetypes by the used photo driver.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $types;
|
||||
|
||||
/**
|
||||
* @brief Return an array with supported mimetypes.
|
||||
*
|
||||
* @return array
|
||||
* Associative array with mimetype as key and file extension as value.
|
||||
*/
|
||||
abstract public function supportedTypes();
|
||||
|
||||
abstract protected function load($data, $type);
|
||||
|
||||
abstract protected function destroy();
|
||||
|
||||
abstract protected function setDimensions();
|
||||
|
||||
/**
|
||||
* @brief Return the current image.
|
||||
*
|
||||
* @fixme Shouldn't his method be protected, because outside of the current
|
||||
* driver it makes no sense at all because of the different return values.
|
||||
*
|
||||
* @return boolean|resource|\Imagick
|
||||
* false on failure, a PHP image resource for GD driver, an \Imagick object
|
||||
* for ImageMagick driver.
|
||||
*/
|
||||
abstract public function getImage();
|
||||
|
||||
abstract public function doScaleImage($new_width, $new_height);
|
||||
|
||||
abstract public function rotate($degrees);
|
||||
|
||||
abstract public function flip($horiz = true, $vert = false);
|
||||
|
||||
/**
|
||||
* @brief Crops the image.
|
||||
*
|
||||
* @param int $maxx width of the new image
|
||||
* @param int $maxy height of the new image
|
||||
* @param int $x x-offset for region
|
||||
* @param int $y y-offset for region
|
||||
* @param int $w width of region
|
||||
* @param int $h height of region
|
||||
*
|
||||
* @return boolean|void false on failure
|
||||
*/
|
||||
abstract public function cropImageRect($maxx, $maxy, $x, $y, $w, $h);
|
||||
|
||||
/**
|
||||
* @brief Return a binary string from the image resource.
|
||||
*
|
||||
* @return string A Binary String.
|
||||
*/
|
||||
abstract public function imageString();
|
||||
|
||||
abstract public function clearexif();
|
||||
|
||||
|
||||
/**
|
||||
* @brief PhotoDriver constructor.
|
||||
*
|
||||
* @param string $data Image
|
||||
* @param string $type mimetype
|
||||
*/
|
||||
public function __construct($data, $type = '') {
|
||||
$this->types = $this->supportedTypes();
|
||||
if(! array_key_exists($type, $this->types)) {
|
||||
$type = 'image/jpeg';
|
||||
}
|
||||
$this->type = $type;
|
||||
$this->valid = false;
|
||||
$this->load($data, $type);
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
if($this->is_valid())
|
||||
$this->destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Is it a valid image object.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_valid() {
|
||||
return $this->valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the width of the image.
|
||||
*
|
||||
* @return boolean|number Width of image in pixels, or false on failure
|
||||
*/
|
||||
public function getWidth() {
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
return $this->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the height of the image.
|
||||
*
|
||||
* @return boolean|number Height of image in pixels, or false on failure
|
||||
*/
|
||||
public function getHeight() {
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
return $this->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Saves the image resource to a file in filesystem.
|
||||
*
|
||||
* @param string $path Path and filename where to save the image
|
||||
* @return boolean False on failure, otherwise true
|
||||
*/
|
||||
public function saveImage($path) {
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
return (file_put_contents($path, $this->imageString()) ? true : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return mimetype of the image resource.
|
||||
*
|
||||
* @return boolean|string False on failure, otherwise mimetype.
|
||||
*/
|
||||
public function getType() {
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return file extension of the image resource.
|
||||
*
|
||||
* @return boolean|string False on failure, otherwise file extension.
|
||||
*/
|
||||
public function getExt() {
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
return $this->types[$this->getType()];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Scale image to max pixel size in either dimension.
|
||||
*
|
||||
* @param int $max maximum pixel size in either dimension
|
||||
* @param boolean $float_height (optional)
|
||||
* If true allow height to float to any length on tall images, constraining
|
||||
* only the width
|
||||
* @return boolean|void false on failure, otherwise void
|
||||
*/
|
||||
public function scaleImage($max, $float_height = true) {
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
$width = $this->width;
|
||||
$height = $this->height;
|
||||
|
||||
$dest_width = $dest_height = 0;
|
||||
|
||||
if((! $width) || (! $height))
|
||||
return false;
|
||||
|
||||
if($width > $max && $height > $max) {
|
||||
|
||||
// very tall image (greater than 16:9)
|
||||
// constrain the width - let the height float.
|
||||
|
||||
if(((($height * 9) / 16) > $width) && ($float_height)) {
|
||||
$dest_width = $max;
|
||||
$dest_height = intval(($height * $max) / $width);
|
||||
} // else constrain both dimensions
|
||||
elseif($width > $height) {
|
||||
$dest_width = $max;
|
||||
$dest_height = intval(($height * $max) / $width);
|
||||
} else {
|
||||
$dest_width = intval(($width * $max) / $height);
|
||||
$dest_height = $max;
|
||||
}
|
||||
} else {
|
||||
if($width > $max) {
|
||||
$dest_width = $max;
|
||||
$dest_height = intval(($height * $max) / $width);
|
||||
} else {
|
||||
if($height > $max) {
|
||||
|
||||
// very tall image (greater than 16:9)
|
||||
// but width is OK - don't do anything
|
||||
|
||||
if(((($height * 9) / 16) > $width) && ($float_height)) {
|
||||
$dest_width = $width;
|
||||
$dest_height = $height;
|
||||
} else {
|
||||
$dest_width = intval(($width * $max) / $height);
|
||||
$dest_height = $max;
|
||||
}
|
||||
} else {
|
||||
$dest_width = $width;
|
||||
$dest_height = $height;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->doScaleImage($dest_width, $dest_height);
|
||||
}
|
||||
|
||||
public function scaleImageUp($min) {
|
||||
if(! $this->is_valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$width = $this->width;
|
||||
$height = $this->height;
|
||||
|
||||
$dest_width = $dest_height = 0;
|
||||
|
||||
if((! $width) || (! $height))
|
||||
return false;
|
||||
|
||||
if($width < $min && $height < $min) {
|
||||
if($width > $height) {
|
||||
$dest_width = $min;
|
||||
$dest_height = intval(($height * $min) / $width);
|
||||
} else {
|
||||
$dest_width = intval(($width * $min) / $height);
|
||||
$dest_height = $min;
|
||||
}
|
||||
} else {
|
||||
if($width < $min) {
|
||||
$dest_width = $min;
|
||||
$dest_height = intval(($height * $min) / $width);
|
||||
} else {
|
||||
if($height < $min) {
|
||||
$dest_width = intval(($width * $min) / $height);
|
||||
$dest_height = $min;
|
||||
} else {
|
||||
$dest_width = $width;
|
||||
$dest_height = $height;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->doScaleImage($dest_width, $dest_height);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Scales image to a square.
|
||||
*
|
||||
* @param int $dim Pixel of square image
|
||||
* @return boolean|void false on failure, otherwise void
|
||||
*/
|
||||
public function scaleImageSquare($dim) {
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
$this->doScaleImage($dim, $dim);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Crops a square image.
|
||||
*
|
||||
* @see cropImageRect()
|
||||
*
|
||||
* @param int $max size of the new image
|
||||
* @param int $x x-offset for region
|
||||
* @param int $y y-offset for region
|
||||
* @param int $w width of region
|
||||
* @param int $h height of region
|
||||
*
|
||||
* @return boolean|void false on failure
|
||||
*/
|
||||
public function cropImage($max, $x, $y, $w, $h) {
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
$this->cropImageRect($max, $max, $x, $y, $w, $h);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads exif data from a given filename.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return boolean|array
|
||||
*/
|
||||
public function exif($filename) {
|
||||
if((! function_exists('exif_read_data'))
|
||||
|| (! in_array($this->getType(), ['image/jpeg', 'image/tiff'])))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* PHP 7.2 allows you to use a stream resource, which should reduce/avoid
|
||||
* memory exhaustion on large images.
|
||||
*/
|
||||
|
||||
if(version_compare(PHP_VERSION, '7.2.0') >= 0) {
|
||||
$f = @fopen($filename, 'rb');
|
||||
} else {
|
||||
$f = $filename;
|
||||
}
|
||||
|
||||
if($f) {
|
||||
return @exif_read_data($f, null, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Orients current image based on exif orientation information.
|
||||
*
|
||||
* @param array $exif
|
||||
* @return boolean true if oriented, otherwise false
|
||||
*/
|
||||
public function orient($exif) {
|
||||
if(! ($this->is_valid() && $exif)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ort = ((array_key_exists('IFD0', $exif)) ? $exif['IFD0']['Orientation'] : $exif['Orientation']);
|
||||
|
||||
if(! $ort) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch($ort) {
|
||||
case 1 : // nothing
|
||||
break;
|
||||
case 2 : // horizontal flip
|
||||
$this->flip();
|
||||
break;
|
||||
case 3 : // 180 rotate left
|
||||
$this->rotate(180);
|
||||
break;
|
||||
case 4 : // vertical flip
|
||||
$this->flip(false, true);
|
||||
break;
|
||||
case 5 : // vertical flip + 90 rotate right
|
||||
$this->flip(false, true);
|
||||
$this->rotate(-90);
|
||||
break;
|
||||
case 6 : // 90 rotate right
|
||||
$this->rotate(-90);
|
||||
break;
|
||||
case 7 : // horizontal flip + 90 rotate right
|
||||
$this->flip();
|
||||
$this->rotate(-90);
|
||||
break;
|
||||
case 8 : // 90 rotate left
|
||||
$this->rotate(90);
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Save photo to database.
|
||||
*
|
||||
* @param array $arr
|
||||
* @param boolean $skipcheck (optional) default false
|
||||
* @return boolean|array
|
||||
*/
|
||||
public function save($arr, $skipcheck = false) {
|
||||
if(! ($skipcheck || $this->is_valid())) {
|
||||
logger('Attempt to store invalid photo.');
|
||||
return false;
|
||||
}
|
||||
|
||||
$p = [];
|
||||
|
||||
$p['aid'] = ((intval($arr['aid'])) ? intval($arr['aid']) : 0);
|
||||
$p['uid'] = ((intval($arr['uid'])) ? intval($arr['uid']) : 0);
|
||||
$p['xchan'] = (($arr['xchan']) ? $arr['xchan'] : '');
|
||||
$p['resource_id'] = (($arr['resource_id']) ? $arr['resource_id'] : '');
|
||||
$p['filename'] = (($arr['filename']) ? $arr['filename'] : '');
|
||||
$p['mimetype'] = (($arr['mimetype']) ? $arr['mimetype'] : $this->getType());
|
||||
$p['album'] = (($arr['album']) ? $arr['album'] : '');
|
||||
$p['imgscale'] = ((intval($arr['imgscale'])) ? intval($arr['imgscale']) : 0);
|
||||
$p['allow_cid'] = (($arr['allow_cid']) ? $arr['allow_cid'] : '');
|
||||
$p['allow_gid'] = (($arr['allow_gid']) ? $arr['allow_gid'] : '');
|
||||
$p['deny_cid'] = (($arr['deny_cid']) ? $arr['deny_cid'] : '');
|
||||
$p['deny_gid'] = (($arr['deny_gid']) ? $arr['deny_gid'] : '');
|
||||
$p['edited'] = (($arr['edited']) ? $arr['edited'] : datetime_convert());
|
||||
$p['title'] = (($arr['title']) ? $arr['title'] : '');
|
||||
$p['description'] = (($arr['description']) ? $arr['description'] : '');
|
||||
$p['photo_usage'] = intval($arr['photo_usage']);
|
||||
$p['os_storage'] = intval($arr['os_storage']);
|
||||
$p['os_path'] = $arr['os_path'];
|
||||
$p['os_syspath'] = ((array_key_exists('os_syspath', $arr)) ? $arr['os_syspath'] : '');
|
||||
$p['display_path'] = (($arr['display_path']) ? $arr['display_path'] : '');
|
||||
$p['width'] = (($arr['width']) ? $arr['width'] : $this->getWidth());
|
||||
$p['height'] = (($arr['height']) ? $arr['height'] : $this->getHeight());
|
||||
$p['expires'] = (($arr['expires']) ? $arr['expires'] : gmdate('Y-m-d H:i:s', time() + get_config('system', 'photo_cache_time', 86400)));
|
||||
|
||||
if(! intval($p['imgscale']))
|
||||
logger('save: ' . print_r($arr, true), LOGGER_DATA);
|
||||
|
||||
$x = q("select id, created from photo where resource_id = '%s' and uid = %d and xchan = '%s' and imgscale = %d limit 1", dbesc($p['resource_id']), intval($p['uid']), dbesc($p['xchan']), intval($p['imgscale']));
|
||||
|
||||
if($x) {
|
||||
$p['created'] = (($x['created']) ? $x['created'] : $p['edited']);
|
||||
$r = q("UPDATE photo set
|
||||
aid = %d,
|
||||
uid = %d,
|
||||
xchan = '%s',
|
||||
resource_id = '%s',
|
||||
created = '%s',
|
||||
edited = '%s',
|
||||
filename = '%s',
|
||||
mimetype = '%s',
|
||||
album = '%s',
|
||||
height = %d,
|
||||
width = %d,
|
||||
content = '%s',
|
||||
os_storage = %d,
|
||||
filesize = %d,
|
||||
imgscale = %d,
|
||||
photo_usage = %d,
|
||||
title = '%s',
|
||||
description = '%s',
|
||||
os_path = '%s',
|
||||
display_path = '%s',
|
||||
allow_cid = '%s',
|
||||
allow_gid = '%s',
|
||||
deny_cid = '%s',
|
||||
deny_gid = '%s',
|
||||
expires = '%s'
|
||||
where id = %d",
|
||||
intval($p['aid']), intval($p['uid']), dbesc($p['xchan']), dbesc($p['resource_id']), dbescdate($p['created']), dbescdate($p['edited']), dbesc(basename($p['filename'])), dbesc($p['mimetype']), dbesc($p['album']), intval($p['height']), intval($p['width']), (intval($p['os_storage']) ? dbescbin($p['os_syspath']) : dbescbin($this->imageString())), intval($p['os_storage']), (intval($p['os_storage']) ? @filesize($p['os_syspath']) : strlen($this->imageString())), intval($p['imgscale']), intval($p['photo_usage']), dbesc($p['title']), dbesc($p['description']), dbesc($p['os_path']), dbesc($p['display_path']), dbesc($p['allow_cid']), dbesc($p['allow_gid']), dbesc($p['deny_cid']), dbesc($p['deny_gid']), dbescdate($p['expires']), intval($x[0]['id']));
|
||||
} else {
|
||||
$p['created'] = (($arr['created']) ? $arr['created'] : $p['edited']);
|
||||
$r = q("INSERT INTO photo
|
||||
( aid, uid, xchan, resource_id, created, edited, filename, mimetype, album, height, width, content, os_storage, filesize, imgscale, photo_usage, title, description, os_path, display_path, allow_cid, allow_gid, deny_cid, deny_gid, expires )
|
||||
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", intval($p['aid']), intval($p['uid']), dbesc($p['xchan']), dbesc($p['resource_id']), dbescdate($p['created']), dbescdate($p['edited']), dbesc(basename($p['filename'])), dbesc($p['mimetype']), dbesc($p['album']), intval($p['height']), intval($p['width']), (intval($p['os_storage']) ? dbescbin($p['os_syspath']) : dbescbin($this->imageString())), intval($p['os_storage']), (intval($p['os_storage']) ? @filesize($p['os_syspath']) : strlen($this->imageString())), intval($p['imgscale']), intval($p['photo_usage']), dbesc($p['title']), dbesc($p['description']), dbesc($p['os_path']), dbesc($p['display_path']), dbesc($p['allow_cid']), dbesc($p['allow_gid']), dbesc($p['deny_cid']), dbesc($p['deny_gid']), dbescdate($p['expires']));
|
||||
}
|
||||
logger('Photo save imgscale ' . $p['imgscale'] . ' returned ' . intval($r));
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
}
|
176
Zotlabs/Photo/PhotoGd.php
Normal file
176
Zotlabs/Photo/PhotoGd.php
Normal file
@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Photo;
|
||||
|
||||
/**
|
||||
* @brief GD photo driver.
|
||||
*
|
||||
*/
|
||||
class PhotoGd extends PhotoDriver {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see \Zotlabs\Photo\PhotoDriver::supportedTypes()
|
||||
*/
|
||||
public function supportedTypes() {
|
||||
$t = [];
|
||||
$t['image/jpeg'] = 'jpg';
|
||||
if(imagetypes() & IMG_PNG)
|
||||
$t['image/png'] = 'png';
|
||||
if(imagetypes() & IMG_GIF)
|
||||
$t['image/gif'] = 'gif';
|
||||
|
||||
return $t;
|
||||
}
|
||||
|
||||
protected function load($data, $type) {
|
||||
$this->valid = false;
|
||||
if(! $data)
|
||||
return;
|
||||
|
||||
$this->image = @imagecreatefromstring($data);
|
||||
if($this->image !== false) {
|
||||
$this->valid = true;
|
||||
$this->setDimensions();
|
||||
imagealphablending($this->image, false);
|
||||
imagesavealpha($this->image, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected function setDimensions() {
|
||||
$this->width = imagesx($this->image);
|
||||
$this->height = imagesy($this->image);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief GD driver does not preserve EXIF, so not need to clear it.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clearexif() {
|
||||
return;
|
||||
}
|
||||
|
||||
protected function destroy() {
|
||||
if($this->is_valid()) {
|
||||
imagedestroy($this->image);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return a PHP image resource of the current image.
|
||||
*
|
||||
* @see \Zotlabs\Photo\PhotoDriver::getImage()
|
||||
*
|
||||
* @return boolean|resource
|
||||
*/
|
||||
public function getImage() {
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
return $this->image;
|
||||
}
|
||||
|
||||
public function doScaleImage($dest_width, $dest_height) {
|
||||
|
||||
$dest = imagecreatetruecolor($dest_width, $dest_height);
|
||||
$width = imagesx($this->image);
|
||||
$height = imagesy($this->image);
|
||||
|
||||
imagealphablending($dest, false);
|
||||
imagesavealpha($dest, true);
|
||||
if($this->type == 'image/png')
|
||||
imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha
|
||||
|
||||
imagecopyresampled($dest, $this->image, 0, 0, 0, 0, $dest_width, $dest_height, $width, $height);
|
||||
if($this->image)
|
||||
imagedestroy($this->image);
|
||||
|
||||
$this->image = $dest;
|
||||
$this->setDimensions();
|
||||
}
|
||||
|
||||
public function rotate($degrees) {
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
$this->image = imagerotate($this->image, $degrees, 0);
|
||||
$this->setDimensions();
|
||||
}
|
||||
|
||||
public function flip($horiz = true, $vert = false) {
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
$w = imagesx($this->image);
|
||||
$h = imagesy($this->image);
|
||||
$flipped = imagecreate($w, $h);
|
||||
if($horiz) {
|
||||
for($x = 0; $x < $w; $x++) {
|
||||
imagecopy($flipped, $this->image, $x, 0, $w - $x - 1, 0, 1, $h);
|
||||
}
|
||||
}
|
||||
if($vert) {
|
||||
for($y = 0; $y < $h; $y++) {
|
||||
imagecopy($flipped, $this->image, 0, $y, 0, $h - $y - 1, $w, 1);
|
||||
}
|
||||
}
|
||||
$this->image = $flipped;
|
||||
$this->setDimensions(); // Shouldn't really be necessary
|
||||
}
|
||||
|
||||
public function cropImageRect($maxx, $maxy, $x, $y, $w, $h) {
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
$dest = imagecreatetruecolor($maxx, $maxy);
|
||||
imagealphablending($dest, false);
|
||||
imagesavealpha($dest, true);
|
||||
if($this->type == 'image/png')
|
||||
imagefill($dest, 0, 0, imagecolorallocatealpha($dest, 0, 0, 0, 127)); // fill with alpha
|
||||
|
||||
imagecopyresampled($dest, $this->image, 0, 0, $x, $y, $maxx, $maxy, $w, $h);
|
||||
if($this->image)
|
||||
imagedestroy($this->image);
|
||||
|
||||
$this->image = $dest;
|
||||
$this->setDimensions();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see \Zotlabs\Photo\PhotoDriver::imageString()
|
||||
*/
|
||||
public function imageString() {
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
$quality = false;
|
||||
|
||||
ob_start();
|
||||
|
||||
switch($this->getType()){
|
||||
case 'image/png':
|
||||
$quality = get_config('system', 'png_quality');
|
||||
if((! $quality) || ($quality > 9))
|
||||
$quality = PNG_QUALITY;
|
||||
|
||||
\imagepng($this->image, NULL, $quality);
|
||||
break;
|
||||
case 'image/jpeg':
|
||||
// gd can lack imagejpeg(), but we verify during installation it is available
|
||||
default:
|
||||
$quality = get_config('system', 'jpeg_quality');
|
||||
if((! $quality) || ($quality > 100))
|
||||
$quality = JPEG_QUALITY;
|
||||
|
||||
\imagejpeg($this->image, NULL, $quality);
|
||||
break;
|
||||
}
|
||||
$string = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
}
|
@ -1,45 +1,44 @@
|
||||
<?php /** @file */
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Photo;
|
||||
|
||||
require_once('include/photo/photo_driver.php');
|
||||
/**
|
||||
* @brief ImageMagick photo driver.
|
||||
*/
|
||||
class PhotoImagick extends PhotoDriver {
|
||||
|
||||
|
||||
class photo_imagick extends photo_driver {
|
||||
|
||||
|
||||
function supportedTypes() {
|
||||
return array(
|
||||
public function supportedTypes() {
|
||||
return [
|
||||
'image/jpeg' => 'jpg',
|
||||
'image/png' => 'png',
|
||||
'image/gif' => 'gif'
|
||||
);
|
||||
'image/gif' => 'gif',
|
||||
];
|
||||
}
|
||||
|
||||
public function get_FormatsMap() {
|
||||
return array(
|
||||
private function get_FormatsMap() {
|
||||
return [
|
||||
'image/jpeg' => 'JPG',
|
||||
'image/png' => 'PNG',
|
||||
'image/gif' => 'GIF'
|
||||
);
|
||||
'image/gif' => 'GIF',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
function load($data, $type) {
|
||||
protected function load($data, $type) {
|
||||
$this->valid = false;
|
||||
$this->image = new Imagick();
|
||||
$this->image = new \Imagick();
|
||||
|
||||
if(! $data)
|
||||
return;
|
||||
|
||||
try {
|
||||
$this->image->readImageBlob($data);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
logger('imagick readImageBlob() exception:' . print_r($e,true));
|
||||
} catch(\Exception $e) {
|
||||
logger('Imagick readImageBlob() exception:' . print_r($e, true));
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Setup the image to the format it will be saved to
|
||||
*/
|
||||
|
||||
@ -52,19 +51,18 @@ class photo_imagick extends photo_driver {
|
||||
// Always coalesce, if it is not a multi-frame image it won't hurt anyway
|
||||
$this->image = $this->image->coalesceImages();
|
||||
|
||||
|
||||
$this->valid = true;
|
||||
$this->setDimensions();
|
||||
|
||||
/**
|
||||
/*
|
||||
* setup the compression here, so we'll do it only once
|
||||
*/
|
||||
switch($this->getType()) {
|
||||
case "image/png":
|
||||
$quality = get_config('system','png_quality');
|
||||
case 'image/png':
|
||||
$quality = get_config('system', 'png_quality');
|
||||
if((! $quality) || ($quality > 9))
|
||||
$quality = PNG_QUALITY;
|
||||
/**
|
||||
/*
|
||||
* From http://www.imagemagick.org/script/command-line-options.php#quality:
|
||||
*
|
||||
* 'For the MNG and PNG image formats, the quality value sets
|
||||
@ -75,56 +73,64 @@ class photo_imagick extends photo_driver {
|
||||
$quality = $quality * 10;
|
||||
$this->image->setCompressionQuality($quality);
|
||||
break;
|
||||
case "image/jpeg":
|
||||
$quality = get_config('system','jpeg_quality');
|
||||
case 'image/jpeg':
|
||||
$quality = get_config('system', 'jpeg_quality');
|
||||
if((! $quality) || ($quality > 100))
|
||||
$quality = JPEG_QUALITY;
|
||||
$this->image->setCompressionQuality($quality);
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy() {
|
||||
protected function destroy() {
|
||||
if($this->is_valid()) {
|
||||
$this->image->clear();
|
||||
$this->image->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function setDimensions() {
|
||||
protected function setDimensions() {
|
||||
$this->width = $this->image->getImageWidth();
|
||||
$this->height = $this->image->getImageHeight();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Strips the image of all profiles and comments.
|
||||
*
|
||||
* Keep ICC profile for better colors.
|
||||
*
|
||||
* @see \Zotlabs\Photo\PhotoDriver::clearexif()
|
||||
*/
|
||||
public function clearexif() {
|
||||
|
||||
$profiles = $this->image->getImageProfiles("icc", true);
|
||||
$profiles = $this->image->getImageProfiles('icc', true);
|
||||
|
||||
$this->image->stripImage();
|
||||
|
||||
if(!empty($profiles)) {
|
||||
$this->image->profileImage("icc", $profiles['icc']);
|
||||
if(! empty($profiles)) {
|
||||
$this->image->profileImage('icc', $profiles['icc']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a \Imagick object of the current image.
|
||||
*
|
||||
* @see \Zotlabs\Photo\PhotoDriver::getImage()
|
||||
*
|
||||
* @return boolean|\Imagick
|
||||
*/
|
||||
public function getImage() {
|
||||
if(!$this->is_valid())
|
||||
return FALSE;
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
$this->image = $this->image->deconstructImages();
|
||||
return $this->image;
|
||||
}
|
||||
|
||||
public function doScaleImage($dest_width,$dest_height) {
|
||||
|
||||
/**
|
||||
public function doScaleImage($dest_width, $dest_height) {
|
||||
/*
|
||||
* If it is not animated, there will be only one iteration here,
|
||||
* so don't bother checking
|
||||
*/
|
||||
@ -132,82 +138,63 @@ class photo_imagick extends photo_driver {
|
||||
$this->image->setFirstIterator();
|
||||
do {
|
||||
$this->image->scaleImage($dest_width, $dest_height);
|
||||
} while ($this->image->nextImage());
|
||||
} while($this->image->nextImage());
|
||||
|
||||
$this->setDimensions();
|
||||
}
|
||||
|
||||
public function rotate($degrees) {
|
||||
if(!$this->is_valid())
|
||||
return FALSE;
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
$this->image->setFirstIterator();
|
||||
do {
|
||||
// ImageMagick rotates in the opposite direction of imagerotate()
|
||||
$this->image->rotateImage(new ImagickPixel(), -$degrees);
|
||||
} while ($this->image->nextImage());
|
||||
$this->image->rotateImage(new \ImagickPixel(), -$degrees);
|
||||
} while($this->image->nextImage());
|
||||
|
||||
$this->setDimensions();
|
||||
}
|
||||
|
||||
public function flip($horiz = true, $vert = false) {
|
||||
if(!$this->is_valid())
|
||||
return FALSE;
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
$this->image->setFirstIterator();
|
||||
do {
|
||||
if($horiz) $this->image->flipImage();
|
||||
if($vert) $this->image->flopImage();
|
||||
} while ($this->image->nextImage());
|
||||
} while($this->image->nextImage());
|
||||
|
||||
$this->setDimensions(); // Shouldn't really be necessary
|
||||
}
|
||||
|
||||
public function cropImage($max,$x,$y,$w,$h) {
|
||||
if(!$this->is_valid())
|
||||
return FALSE;
|
||||
public function cropImageRect($maxx, $maxy, $x, $y, $w, $h) {
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
$this->image->setFirstIterator();
|
||||
do {
|
||||
$this->image->cropImage($w, $h, $x, $y);
|
||||
/**
|
||||
/*
|
||||
* We need to remove the canvas,
|
||||
* or the image is not resized to the crop:
|
||||
* http://php.net/manual/en/imagick.cropimage.php#97232
|
||||
*/
|
||||
$this->image->setImagePage(0, 0, 0, 0);
|
||||
} while ($this->image->nextImage());
|
||||
} while($this->image->nextImage());
|
||||
|
||||
$this->doScaleImage($max,$max);
|
||||
}
|
||||
|
||||
public function cropImageRect($maxx,$maxy,$x,$y,$w,$h) {
|
||||
if(!$this->is_valid())
|
||||
return FALSE;
|
||||
|
||||
$this->image->setFirstIterator();
|
||||
do {
|
||||
$this->image->cropImage($w, $h, $x, $y);
|
||||
/**
|
||||
* We need to remove the canvas,
|
||||
* or the image is not resized to the crop:
|
||||
* http://php.net/manual/en/imagick.cropimage.php#97232
|
||||
*/
|
||||
$this->image->setImagePage(0, 0, 0, 0);
|
||||
} while ($this->image->nextImage());
|
||||
|
||||
$this->doScaleImage($maxx,$maxy);
|
||||
$this->doScaleImage($maxx, $maxy);
|
||||
}
|
||||
|
||||
public function imageString() {
|
||||
if(!$this->is_valid())
|
||||
return FALSE;
|
||||
if(! $this->is_valid())
|
||||
return false;
|
||||
|
||||
/* Clean it */
|
||||
$this->image = $this->image->deconstructImages();
|
||||
|
||||
return $this->image->getImagesBlob();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -205,18 +205,22 @@ class Browser extends DAV\Browser\Plugin {
|
||||
// upload access. system.thumbnail_security should be set to 1 if you want to include these
|
||||
// types
|
||||
|
||||
$is_creator = false;
|
||||
$photo_icon = '';
|
||||
$preview_style = intval(get_config('system','thumbnail_security',0));
|
||||
|
||||
$r = q("select content from attach where hash = '%s' and uid = %d limit 1",
|
||||
$r = q("select content, creator from attach where hash = '%s' and uid = %d limit 1",
|
||||
dbesc($attachHash),
|
||||
intval($owner)
|
||||
);
|
||||
|
||||
if($r && file_exists(dbunescbin($r[0]['content']) . '.thumb')) {
|
||||
if($r) {
|
||||
$is_creator = (($r[0]['creator'] === get_observer_hash()) ? true : false);
|
||||
if(file_exists(dbunescbin($r[0]['content']) . '.thumb')) {
|
||||
$photo_icon = 'data:image/jpeg;base64,' . base64_encode(file_get_contents(dbunescbin($r[0]['content']) . '.thumb'));
|
||||
// logger('found thumb: ' . $photo_icon);
|
||||
}
|
||||
}
|
||||
|
||||
if(strpos($type,'image/') === 0 && $attachHash) {
|
||||
$r = q("select resource_id, imgscale from photo where resource_id = '%s' and imgscale in ( %d, %d ) order by imgscale asc limit 1",
|
||||
@ -247,6 +251,7 @@ class Browser extends DAV\Browser\Plugin {
|
||||
$ft['attachIcon'] = (($size) ? $attachIcon : '');
|
||||
// @todo Should this be an item value, not a global one?
|
||||
$ft['is_owner'] = $is_owner;
|
||||
$ft['is_creator'] = $is_creator;
|
||||
$ft['fullPath'] = $fullPath;
|
||||
$ft['displayName'] = $displayName;
|
||||
$ft['type'] = $type;
|
||||
@ -256,6 +261,7 @@ class Browser extends DAV\Browser\Plugin {
|
||||
$ft['iconFromType'] = getIconFromType($type);
|
||||
|
||||
$f[] = $ft;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -224,7 +224,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
|
||||
}
|
||||
|
||||
$filesize = 0;
|
||||
$hash = random_string();
|
||||
$hash = new_uuid();
|
||||
|
||||
$f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $hash;
|
||||
|
||||
|
78
Zotlabs/Update/_1226.php
Normal file
78
Zotlabs/Update/_1226.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Update;
|
||||
|
||||
use Zotlabs\Lib\Libzot;
|
||||
|
||||
class _1226 {
|
||||
|
||||
function run() {
|
||||
|
||||
q("START TRANSACTION");
|
||||
|
||||
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
|
||||
$r1 = q("ALTER TABLE channel ADD channel_portable_id text NOT NULL DEFAULT '' ");
|
||||
$r2 = q("create index \"channel_portable_id_idx\" on channel (\"channel_portable_id\")");
|
||||
|
||||
$r = ($r1 && $r2);
|
||||
}
|
||||
else {
|
||||
$r = q("ALTER TABLE `channel` ADD `channel_portable_id` char(191) NOT NULL DEFAULT '' ,
|
||||
ADD INDEX `channel_portable_id` (`channel_portable_id`)");
|
||||
}
|
||||
|
||||
if($r) {
|
||||
q("COMMIT");
|
||||
self::upgrade();
|
||||
return UPDATE_SUCCESS;
|
||||
}
|
||||
|
||||
q("ROLLBACK");
|
||||
return UPDATE_FAILED;
|
||||
}
|
||||
|
||||
|
||||
static function upgrade() {
|
||||
|
||||
$r = q("select * from channel where channel_portable_id = '' ");
|
||||
|
||||
if($r) {
|
||||
foreach($r as $rv) {
|
||||
|
||||
$zhash = Libzot::make_xchan_hash($rv['channel_guid'],$rv['channel_pubkey']);
|
||||
q("update channel set channel_portable_id = '%s' where channel_id = %d",
|
||||
dbesc($zhash),
|
||||
intval($rv['channel_id'])
|
||||
);
|
||||
$x = q("select * from xchan where xchan_hash = '%s' limit 1",
|
||||
dbesc($rv['channel_hash'])
|
||||
);
|
||||
if($x) {
|
||||
$rec = $x[0];
|
||||
$rec['xchan_hash'] = $zhash;
|
||||
$rec['xchan_guid_sig'] = 'sha256.' . $rec['xchan_guid_sig'];
|
||||
$rec['xchan_network'] = 'zot6';
|
||||
|
||||
xchan_store_lowlevel($rec);
|
||||
}
|
||||
$x = q("select * from hubloc where hubloc_hash = '%s' and hubloc_url = '%s' limit 1",
|
||||
dbesc($rv['channel_hash']),
|
||||
dbesc(z_root())
|
||||
);
|
||||
if($x) {
|
||||
$rec = $x[0];
|
||||
$rec['hubloc_hash'] = $zhash;
|
||||
$rec['hubloc_guid_sig'] = 'sha256.' . $rec['hubloc_guid_sig'];
|
||||
$rec['hubloc_network'] = 'zot6';
|
||||
$rec['hubloc_url_sig'] = 'sha256.' . $rec['hubloc_url_sig'];
|
||||
$rec['hubloc_callback'] = z_root() . '/zot';
|
||||
$rec['hubloc_id_url'] = channel_url($rv);
|
||||
$rec['hubloc_site_id'] = Libzot::make_xchan_hash(z_root(),get_config('system','pubkey'));
|
||||
hubloc_store_lowlevel($rec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
30
Zotlabs/Update/_1227.php
Normal file
30
Zotlabs/Update/_1227.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Update;
|
||||
|
||||
|
||||
class _1227 {
|
||||
|
||||
function run() {
|
||||
|
||||
q("START TRANSACTION");
|
||||
|
||||
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
|
||||
$r = q("ALTER TABLE dreport ADD dreport_name text NOT NULL DEFAULT '' ");
|
||||
}
|
||||
else {
|
||||
$r = q("ALTER TABLE `dreport` ADD `dreport_name` char(191) NOT NULL DEFAULT ''");
|
||||
}
|
||||
|
||||
if($r) {
|
||||
q("COMMIT");
|
||||
return UPDATE_SUCCESS;
|
||||
}
|
||||
|
||||
q("ROLLBACK");
|
||||
return UPDATE_FAILED;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
36
Zotlabs/Update/_1228.php
Normal file
36
Zotlabs/Update/_1228.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Update;
|
||||
|
||||
|
||||
class _1228 {
|
||||
|
||||
function run() {
|
||||
|
||||
q("START TRANSACTION");
|
||||
|
||||
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
|
||||
$r1 = q("ALTER TABLE item ADD uuid text NOT NULL DEFAULT '' ");
|
||||
$r2 = q("create index \"uuid_idx\" on item (\"uuid\")");
|
||||
$r3 = q("ALTER TABLE item add summary TEXT NOT NULL DEFAULT ''");
|
||||
|
||||
$r = ($r1 && $r2 && $r3);
|
||||
}
|
||||
else {
|
||||
$r1 = q("ALTER TABLE `item` ADD `uuid` char(191) NOT NULL DEFAULT '' ,
|
||||
ADD INDEX `uuid` (`uuid`)");
|
||||
$r2 = q("ALTER TABLE `item` ADD `summary` mediumtext NOT NULL");
|
||||
$r = ($r1 && $r2);
|
||||
}
|
||||
|
||||
if($r) {
|
||||
q("COMMIT");
|
||||
return UPDATE_SUCCESS;
|
||||
}
|
||||
|
||||
q("ROLLBACK");
|
||||
return UPDATE_FAILED;
|
||||
}
|
||||
|
||||
}
|
||||
|
32
Zotlabs/Update/_1229.php
Normal file
32
Zotlabs/Update/_1229.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Update;
|
||||
|
||||
class _1229 {
|
||||
|
||||
function run() {
|
||||
|
||||
q("START TRANSACTION");
|
||||
|
||||
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
|
||||
$r1 = q("ALTER TABLE photo ADD expires timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' ");
|
||||
$r2 = q("create index \"photo_expires_idx\" on photo (\"expires\")");
|
||||
|
||||
$r = ($r1 && $r2);
|
||||
}
|
||||
else {
|
||||
$r = q("ALTER TABLE `photo` ADD `expires` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' ,
|
||||
ADD INDEX `expires` (`expires`)");
|
||||
}
|
||||
|
||||
if($r) {
|
||||
q("COMMIT");
|
||||
return UPDATE_SUCCESS;
|
||||
}
|
||||
|
||||
q("ROLLBACK");
|
||||
return UPDATE_FAILED;
|
||||
|
||||
}
|
||||
|
||||
}
|
12
Zotlabs/Update/_1230.php
Normal file
12
Zotlabs/Update/_1230.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Update;
|
||||
|
||||
class _1230 {
|
||||
|
||||
function run() {
|
||||
q("update abook set abook_closeness = 80 where abook_closeness = 0 and abook_self = 0");
|
||||
return UPDATE_SUCCESS;
|
||||
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Zotlabs\Web;
|
||||
|
||||
|
||||
class CheckJS {
|
||||
|
||||
private static $jsdisabled = 0;
|
||||
|
||||
function __construct($test = 0) {
|
||||
if(intval($_REQUEST['jsdisabled']))
|
||||
$this->jsdisabled = 1;
|
||||
else
|
||||
$this->jsdisabled = 0;
|
||||
if(intval($_COOKIE['jsdisabled']))
|
||||
$this->jsdisabled = 1;
|
||||
else
|
||||
$this->jsdisabled = 0;
|
||||
|
||||
$page = bin2hex(\App::$query_string);
|
||||
|
||||
if(! $this->jsdisabled) {
|
||||
if($test) {
|
||||
$this->jsdisabled = 1;
|
||||
if(array_key_exists('jsdisabled',$_COOKIE))
|
||||
$this->jsdisabled = $_COOKIE['jsdisabled'];
|
||||
|
||||
if(! array_key_exists('jsdisabled',$_COOKIE)) {
|
||||
\App::$page['htmlhead'] .= "\r\n" . '<script>document.cookie="jsdisabled=0; path=/"; var jsMatch = /\&jsdisabled=0/; if (!jsMatch.exec(location.href)) { location.href = "' . z_root() . '/nojs/0?f=&redir=' . $page . '" ; }</script>' . "\r\n";
|
||||
/* emulate JS cookie if cookies are not accepted */
|
||||
if (array_key_exists('jsdisabled',$_GET)) {
|
||||
$_COOKIE['jsdisabled'] = $_GET['jsdisabled'];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
\App::$page['htmlhead'] .= "\r\n" . '<noscript><meta http-equiv="refresh" content="0; url=' . z_root() . '/nojs?f=&redir=' . $page . '"></noscript>' . "\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function disabled() {
|
||||
return $this->jsdisabled;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -342,6 +342,10 @@ class HTTPSig {
|
||||
*/
|
||||
static function parse_sigheader($header) {
|
||||
|
||||
if(is_array($header)) {
|
||||
btlogger('is_array: ' . print_r($header,true));
|
||||
}
|
||||
|
||||
$ret = [];
|
||||
$matches = [];
|
||||
|
||||
@ -397,7 +401,7 @@ class HTTPSig {
|
||||
$data = $matches[1];
|
||||
|
||||
if($iv && $key && $alg && $data) {
|
||||
return crypto_unencapsulate([ 'iv' => $iv, 'key' => $key, 'alg' => $alg, 'data' => $data ] , $prvkey);
|
||||
return crypto_unencapsulate([ 'encrypted' => true, 'iv' => $iv, 'key' => $key, 'alg' => $alg, 'data' => $data ] , $prvkey);
|
||||
}
|
||||
|
||||
return '';
|
||||
|
@ -15,7 +15,7 @@ class Session {
|
||||
|
||||
private $handler = null;
|
||||
private $session_started = false;
|
||||
|
||||
private $custom_handler = false;
|
||||
public function init() {
|
||||
|
||||
$gc_probability = 50;
|
||||
@ -24,10 +24,30 @@ class Session {
|
||||
ini_set('session.use_only_cookies', 1);
|
||||
ini_set('session.cookie_httponly', 1);
|
||||
|
||||
$this->custom_handler = boolval(get_config('system', 'session_custom', false));
|
||||
|
||||
/*
|
||||
* Set our session storage functions.
|
||||
*/
|
||||
|
||||
if($this->custom_handler) {
|
||||
/* Custom handler (files, memached, redis..) */
|
||||
|
||||
$session_save_handler = strval(get_config('system', 'session_save_handler', Null));
|
||||
$session_save_path = strval(get_config('system', 'session_save_path', Null));
|
||||
$session_gc_probability = intval(get_config('system', 'session_gc_probability', 1));
|
||||
$session_gc_divisor = intval(get_config('system', 'session_gc_divisor', 100));
|
||||
if(!$session_save_handler || !$session_save_path) {
|
||||
logger('Session save handler or path not set.',LOGGER_NORMAL,LOG_ERR);
|
||||
}
|
||||
else {
|
||||
ini_set('session.save_handler', $session_save_handler);
|
||||
ini_set('session.save_path', $session_save_path);
|
||||
ini_set('session.gc_probability', $session_gc_probability);
|
||||
ini_set('session.gc_divisor', $session_gc_divisor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$handler = new \Zotlabs\Web\SessionHandler();
|
||||
|
||||
$this->handler = $handler;
|
||||
@ -35,6 +55,7 @@ class Session {
|
||||
$x = session_set_save_handler($handler,false);
|
||||
if(! $x)
|
||||
logger('Session save handler initialisation failed.',LOGGER_NORMAL,LOG_ERR);
|
||||
}
|
||||
|
||||
// Force cookies to be secure (https only) if this site is SSL enabled.
|
||||
// Must be done before session_start().
|
||||
@ -86,15 +107,16 @@ class Session {
|
||||
|
||||
$arr = session_get_cookie_params();
|
||||
|
||||
if($this->handler && $this->session_started) {
|
||||
if(($this->handler || $this->custom_handler) && $this->session_started) {
|
||||
|
||||
session_regenerate_id(true);
|
||||
|
||||
// force SessionHandler record creation with the new session_id
|
||||
// which occurs as a side effect of read()
|
||||
|
||||
if (! $this->custom_handler) {
|
||||
$this->handler->read(session_id());
|
||||
}
|
||||
}
|
||||
else
|
||||
logger('no session handler');
|
||||
|
||||
|
@ -2,21 +2,29 @@
|
||||
|
||||
namespace Zotlabs\Widget;
|
||||
|
||||
use Zotlabs\Lib\Apps;
|
||||
|
||||
class Affinity {
|
||||
|
||||
function widget($arr) {
|
||||
|
||||
if(! local_channel())
|
||||
return '';
|
||||
return;
|
||||
|
||||
$default_cmin = ((feature_enabled(local_channel(),'affinity')) ? get_pconfig(local_channel(),'affinity','cmin',0) : 0);
|
||||
$default_cmax = ((feature_enabled(local_channel(),'affinity')) ? get_pconfig(local_channel(),'affinity','cmax',99) : 99);
|
||||
if(! Apps::system_app_installed(local_channel(),'Affinity Tool'))
|
||||
return;
|
||||
|
||||
$default_cmin = ((Apps::system_app_installed(local_channel(),'Affinity Tool')) ? get_pconfig(local_channel(),'affinity','cmin',0) : 0);
|
||||
$default_cmax = ((Apps::system_app_installed(local_channel(),'Affinity Tool')) ? get_pconfig(local_channel(),'affinity','cmax',99) : 99);
|
||||
|
||||
$cmin = ((x($_REQUEST,'cmin')) ? intval($_REQUEST['cmin']) : $default_cmin);
|
||||
$cmax = ((x($_REQUEST,'cmax')) ? intval($_REQUEST['cmax']) : $default_cmax);
|
||||
|
||||
|
||||
if(feature_enabled(local_channel(),'affinity')) {
|
||||
$affinity_locked = intval(get_pconfig(local_channel(),'affinity','lock',1));
|
||||
if ($affinity_locked) {
|
||||
set_pconfig(local_channel(),'affinity','cmin',$cmin);
|
||||
set_pconfig(local_channel(),'affinity','cmax',$cmax);
|
||||
}
|
||||
|
||||
$labels = array(
|
||||
t('Me'),
|
||||
@ -26,6 +34,7 @@ class Affinity {
|
||||
t('All')
|
||||
);
|
||||
call_hooks('affinity_labels',$labels);
|
||||
|
||||
$label_str = '';
|
||||
|
||||
if($labels) {
|
||||
@ -48,9 +57,10 @@ class Affinity {
|
||||
|
||||
$arr = array('html' => $x);
|
||||
call_hooks('main_slider',$arr);
|
||||
|
||||
return $arr['html'];
|
||||
}
|
||||
return '';
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -42,19 +42,12 @@ class Settings_menu {
|
||||
|
||||
);
|
||||
|
||||
|
||||
$tabs[] = array(
|
||||
'label' => t('Display settings'),
|
||||
'url' => z_root().'/settings/display',
|
||||
'selected' => ((argv(1) === 'display') ? 'active' : ''),
|
||||
);
|
||||
|
||||
$tabs[] = array(
|
||||
'label' => t('Addon settings'),
|
||||
'url' => z_root().'/settings/featured',
|
||||
'selected' => ((argv(1) === 'featured') ? 'active' : ''),
|
||||
);
|
||||
|
||||
if($hublocs) {
|
||||
$tabs[] = array(
|
||||
'label' => t('Manage locations'),
|
||||
|
@ -55,7 +55,7 @@ class Finger {
|
||||
|
||||
$r = q("select xchan.*, hubloc.* from xchan
|
||||
left join hubloc on xchan_hash = hubloc_hash
|
||||
where xchan_addr = '%s' and hubloc_primary = 1 and hubloc_deleted = 0 limit 1",
|
||||
where xchan_addr = '%s' and hubloc_primary = 1 and hubloc_deleted = 0 and hubloc_network = 'zot' limit 1",
|
||||
dbesc($xchan_addr)
|
||||
);
|
||||
|
||||
|
@ -48,12 +48,14 @@ class HTTPSig {
|
||||
$h = new HTTPHeaders($data['header']);
|
||||
$headers = $h->fetcharr();
|
||||
$body = $data['body'];
|
||||
$headers['(request-target)'] = $data['request_target'];
|
||||
}
|
||||
|
||||
else {
|
||||
$headers = [];
|
||||
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
|
||||
$headers['content-type'] = $_SERVER['CONTENT_TYPE'];
|
||||
$headers['content-length'] = $_SERVER['CONTENT_LENGTH'];
|
||||
|
||||
foreach($_SERVER as $k => $v) {
|
||||
if(strpos($k,'HTTP_') === 0) {
|
||||
@ -121,6 +123,17 @@ class HTTPSig {
|
||||
if(array_key_exists($h,$headers)) {
|
||||
$signed_data .= $h . ': ' . $headers[$h] . "\n";
|
||||
}
|
||||
if($h === 'date') {
|
||||
$d = new \DateTime($headers[$h]);
|
||||
$d->setTimeZone(new \DateTimeZone('UTC'));
|
||||
$dplus = datetime_convert('UTC','UTC','now + 1 day');
|
||||
$dminus = datetime_convert('UTC','UTC','now - 1 day');
|
||||
$c = $d->format('Y-m-d H:i:s');
|
||||
if($c > $dplus || $c < $dminus) {
|
||||
logger('bad time: ' . $c);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
$signed_data = rtrim($signed_data,"\n");
|
||||
|
||||
@ -147,8 +160,15 @@ class HTTPSig {
|
||||
|
||||
logger('verified: ' . $x, LOGGER_DEBUG);
|
||||
|
||||
if(! $x)
|
||||
if(! $x) {
|
||||
logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($key['public_key']) ? '' : ' no key'));
|
||||
$sig_block['signature'] = base64_encode($sig_block['signature']);
|
||||
logger('affected sigblock: ' . print_r($sig_block,true));
|
||||
logger('signed_data: ' . print_r($signed_data,true));
|
||||
logger('headers: ' . print_r($headers,true));
|
||||
logger('server: ' . print_r($_SERVER,true));
|
||||
return $result;
|
||||
}
|
||||
|
||||
$result['portable_id'] = $key['portable_id'];
|
||||
$result['header_valid'] = true;
|
||||
@ -180,7 +200,9 @@ class HTTPSig {
|
||||
return [ 'public_key' => $key ];
|
||||
}
|
||||
|
||||
if(strpos($id,'#') === false) {
|
||||
$key = self::get_webfinger_key($id);
|
||||
}
|
||||
|
||||
if(! $key) {
|
||||
$key = self::get_activitystreams_key($id);
|
||||
@ -216,25 +238,29 @@ class HTTPSig {
|
||||
|
||||
function get_activitystreams_key($id) {
|
||||
|
||||
// remove fragment
|
||||
|
||||
$url = ((strpos($id,'#')) ? substr($id,0,strpos($id,'#')) : $id);
|
||||
|
||||
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
|
||||
dbesc(str_replace('acct:','',$id)),
|
||||
dbesc($id)
|
||||
dbesc(str_replace('acct:','',$url)),
|
||||
dbesc($url)
|
||||
);
|
||||
|
||||
if($x && $x[0]['xchan_pubkey']) {
|
||||
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
|
||||
}
|
||||
|
||||
$r = ActivityStreams::fetch_property($id);
|
||||
$r = ActivityStreams::fetch($id);
|
||||
|
||||
if($r) {
|
||||
if(array_key_exists('publicKey',$j) && array_key_exists('publicKeyPem',$j['publicKey']) && array_key_exists('id',$j['publicKey'])) {
|
||||
if($j['publicKey']['id'] === $id || $j['id'] === $id) {
|
||||
return [ 'public_key' => self::convertKey($j['publicKey']['publicKeyPem']), 'portable_id' => '', 'hubloc' => [] ];
|
||||
if(array_key_exists('publicKey',$r) && array_key_exists('publicKeyPem',$r['publicKey']) && array_key_exists('id',$r['publicKey'])) {
|
||||
if($r['publicKey']['id'] === $id || $r['id'] === $id) {
|
||||
$portable_id = ((array_key_exists('owner',$r['publicKey'])) ? $r['publicKey']['owner'] : EMPTY_STR);
|
||||
return [ 'public_key' => self::convertKey($r['publicKey']['publicKeyPem']), 'portable_id' => $portable_id, 'hubloc' => [] ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -409,6 +435,8 @@ class HTTPSig {
|
||||
$headers = '';
|
||||
$fields = '';
|
||||
|
||||
logger('signing: ' . print_r($head,true), LOGGER_DATA);
|
||||
|
||||
if($head) {
|
||||
foreach($head as $k => $v) {
|
||||
$headers .= strtolower($k) . ': ' . trim($v) . "\n";
|
||||
|
@ -4,7 +4,7 @@ namespace Zotlabs\Zot6;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
|
||||
class Receiver {
|
||||
|
||||
|
@ -58,11 +58,11 @@ class Zot6Handler implements IHandler {
|
||||
*
|
||||
* @param array $sender
|
||||
* @param array $recipients
|
||||
* @param array $hub
|
||||
*
|
||||
* @return json_return_and_die()
|
||||
* @return array
|
||||
*/
|
||||
|
||||
static function reply_refresh($sender, $recipients,$hub) {
|
||||
static function reply_refresh($sender, $recipients, $hub) {
|
||||
$ret = array('success' => false);
|
||||
|
||||
if($recipients) {
|
||||
@ -71,17 +71,17 @@ class Zot6Handler implements IHandler {
|
||||
|
||||
foreach ($recipients as $recip) {
|
||||
$r = q("select channel.*,xchan.* from channel
|
||||
left join xchan on channel_hash = xchan_hash
|
||||
where channel_hash ='%s' limit 1",
|
||||
left join xchan on channel_portable_id = xchan_hash
|
||||
where xchan_hash ='%s' limit 1",
|
||||
dbesc($recip)
|
||||
);
|
||||
|
||||
/// @FIXME $msgtype is undefined
|
||||
$x = Libzot::refresh( [ 'hubloc_id_url' => $hub['hubloc_id_url'] ], $r[0], (($msgtype === 'force_refresh') ? true : false));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// system wide refresh
|
||||
|
||||
/// @FIXME $msgtype is undefined
|
||||
$x = Libzot::refresh( [ 'hubloc_id_url' => $hub['hubloc_id_url'] ], null, (($msgtype === 'force_refresh') ? true : false));
|
||||
}
|
||||
|
||||
@ -104,12 +104,11 @@ class Zot6Handler implements IHandler {
|
||||
* this 'message_list' at the destination and split it into individual messages which are
|
||||
* processed/delivered in order.
|
||||
*
|
||||
*
|
||||
* @param array $data
|
||||
* @param array $hub
|
||||
* @return array
|
||||
*/
|
||||
|
||||
static function reply_message_request($data,$hub) {
|
||||
static function reply_message_request($data, $hub) {
|
||||
$ret = [ 'success' => false ];
|
||||
|
||||
$message_id = EMPTY_STR;
|
||||
@ -140,7 +139,7 @@ class Zot6Handler implements IHandler {
|
||||
|
||||
$arr = $data['recipients'][0];
|
||||
|
||||
$c = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_hash = '%s' limit 1",
|
||||
$c = q("select * from channel left join xchan on channel_portable_id = xchan_hash where channel_portable_id = '%s' limit 1",
|
||||
dbesc($arr['portable_id'])
|
||||
);
|
||||
if (! $c) {
|
||||
@ -152,11 +151,10 @@ class Zot6Handler implements IHandler {
|
||||
/*
|
||||
* fetch the requested conversation
|
||||
*/
|
||||
|
||||
/// @FIXME $sender_hash is undefined
|
||||
$messages = zot_feed($c[0]['channel_id'],$sender_hash, [ 'message_id' => $data['message_id'], 'encoding' => 'activitystreams' ]);
|
||||
|
||||
return (($messages) ? : [] );
|
||||
|
||||
}
|
||||
|
||||
static function rekey_request($sender,$data,$hub) {
|
||||
@ -218,10 +216,10 @@ class Zot6Handler implements IHandler {
|
||||
*
|
||||
* @param array $sender
|
||||
* @param array $recipients
|
||||
* @param array $hub
|
||||
*
|
||||
* return json_return_and_die()
|
||||
* @return array
|
||||
*/
|
||||
|
||||
static function reply_purge($sender, $recipients, $hub) {
|
||||
|
||||
$ret = array('success' => false);
|
||||
@ -230,8 +228,8 @@ class Zot6Handler implements IHandler {
|
||||
// basically this means "unfriend"
|
||||
foreach ($recipients as $recip) {
|
||||
$r = q("select channel.*,xchan.* from channel
|
||||
left join xchan on channel_hash = xchan_hash
|
||||
where channel_hash = '%s' and channel_guid_sig = '%s' limit 1",
|
||||
left join xchan on channel_portable_id = xchan_hash
|
||||
where channel_portable_id = '%s' limit 1",
|
||||
dbesc($recip)
|
||||
);
|
||||
if ($r) {
|
||||
@ -258,9 +256,4 @@ class Zot6Handler implements IHandler {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
7
app/affinity.apd
Normal file
7
app/affinity.apd
Normal file
@ -0,0 +1,7 @@
|
||||
version: 1
|
||||
url: $baseurl/affinity
|
||||
requires: local_channel
|
||||
name: Affinity Tool
|
||||
photo: icon:arrows-h
|
||||
categories: Networking
|
||||
desc: This app presents a slider control in your connection editor and also on your network page. The slider represents your degree of friendship (affinity) with each connection. It allows you to zoom in or out and display conversations from only your closest friends or everybody in your stream.
|
19
boot.php
19
boot.php
@ -50,10 +50,10 @@ require_once('include/attach.php');
|
||||
require_once('include/bbcode.php');
|
||||
|
||||
define ( 'PLATFORM_NAME', 'hubzilla' );
|
||||
define ( 'STD_VERSION', '3.8.9' );
|
||||
define ( 'STD_VERSION', '4.0' );
|
||||
define ( 'ZOT_REVISION', '6.0a' );
|
||||
|
||||
define ( 'DB_UPDATE_VERSION', 1225 );
|
||||
define ( 'DB_UPDATE_VERSION', 1230 );
|
||||
|
||||
define ( 'PROJECT_BASE', __DIR__ );
|
||||
|
||||
@ -83,8 +83,8 @@ define ( 'DIRECTORY_REALM', 'RED_GLOBAL');
|
||||
define ( 'DIRECTORY_FALLBACK_MASTER', 'https://zotadel.net');
|
||||
|
||||
$DIRECTORY_FALLBACK_SERVERS = array(
|
||||
'https://hubzilla.zottel.net',
|
||||
'https://zotadel.net'
|
||||
'https://zotadel.net',
|
||||
'https://zotsite.net'
|
||||
);
|
||||
|
||||
|
||||
@ -217,6 +217,7 @@ define ( 'PHOTO_PROFILE', 0x0001 );
|
||||
define ( 'PHOTO_XCHAN', 0x0002 );
|
||||
define ( 'PHOTO_THING', 0x0004 );
|
||||
define ( 'PHOTO_COVER', 0x0010 );
|
||||
define ( 'PHOTO_CACHE', 0x0020 );
|
||||
|
||||
define ( 'PHOTO_ADULT', 0x0008 );
|
||||
define ( 'PHOTO_FLAG_OS', 0x4000 );
|
||||
@ -438,6 +439,7 @@ define ( 'TERM_OBJ_APP', 7 );
|
||||
* various namespaces we may need to parse
|
||||
*/
|
||||
define ( 'PROTOCOL_ZOT', 'http://purl.org/zot/protocol' );
|
||||
define ( 'PROTOCOL_ZOT6', 'http://purl.org/zot/protocol/6.0' );
|
||||
define ( 'NAMESPACE_ZOT', 'http://purl.org/zot' );
|
||||
define ( 'NAMESPACE_DFRN' , 'http://purl.org/macgirvin/dfrn/1.0' );
|
||||
define ( 'NAMESPACE_THREAD' , 'http://purl.org/syndication/thread/1.0' );
|
||||
@ -465,7 +467,7 @@ define ( 'NAMESPACE_YMEDIA', 'http://search.yahoo.com/mrss/' );
|
||||
|
||||
define ( 'ACTIVITYSTREAMS_JSONLD_REV', 'https://www.w3.org/ns/activitystreams' );
|
||||
|
||||
define ( 'ZOT_APSCHEMA_REV', '/apschema/v1.2' );
|
||||
define ( 'ZOT_APSCHEMA_REV', '/apschema/v1.3' );
|
||||
/**
|
||||
* activity stream defines
|
||||
*/
|
||||
@ -510,6 +512,7 @@ define ( 'ACTIVITY_MOOD', NAMESPACE_ZOT . '/activity/mood' );
|
||||
define ( 'ACTIVITY_OBJ_COMMENT', NAMESPACE_ACTIVITY_SCHEMA . 'comment' );
|
||||
define ( 'ACTIVITY_OBJ_ACTIVITY',NAMESPACE_ACTIVITY_SCHEMA . 'activity' );
|
||||
define ( 'ACTIVITY_OBJ_NOTE', NAMESPACE_ACTIVITY_SCHEMA . 'note' );
|
||||
define ( 'ACTIVITY_OBJ_ARTICLE', NAMESPACE_ACTIVITY_SCHEMA . 'article' );
|
||||
define ( 'ACTIVITY_OBJ_PERSON', NAMESPACE_ACTIVITY_SCHEMA . 'person' );
|
||||
define ( 'ACTIVITY_OBJ_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'photo' );
|
||||
define ( 'ACTIVITY_OBJ_P_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'profile-photo' );
|
||||
@ -574,6 +577,8 @@ define ( 'ITEM_TYPE_BUG', 4 );
|
||||
define ( 'ITEM_TYPE_DOC', 5 );
|
||||
define ( 'ITEM_TYPE_CARD', 6 );
|
||||
define ( 'ITEM_TYPE_ARTICLE', 7 );
|
||||
//OSADA ITEM_TYPE_MAIL = 8
|
||||
define ( 'ITEM_TYPE_CUSTOM', 9 );
|
||||
|
||||
define ( 'ITEM_IS_STICKY', 1000 );
|
||||
|
||||
@ -1828,8 +1833,6 @@ function proc_run(){
|
||||
|
||||
$args = func_get_args();
|
||||
|
||||
$newargs = array();
|
||||
|
||||
if(! count($args))
|
||||
return;
|
||||
|
||||
@ -2396,7 +2399,7 @@ function z_get_temp_dir() {
|
||||
if(! $temp_dir)
|
||||
$temp_dir = sys_get_temp_dir();
|
||||
|
||||
return $upload_dir;
|
||||
return $temp_dir;
|
||||
}
|
||||
|
||||
|
||||
|
340
composer.lock
generated
340
composer.lock
generated
@ -63,16 +63,16 @@
|
||||
},
|
||||
{
|
||||
"name": "bshaffer/oauth2-server-php",
|
||||
"version": "v1.10.0",
|
||||
"version": "v1.11.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bshaffer/oauth2-server-php.git",
|
||||
"reference": "d158878425392fe5a0cc34f15dbaf46315ae0ed9"
|
||||
"reference": "5a0c8000d4763b276919e2106f54eddda6bc50fa"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/bshaffer/oauth2-server-php/zipball/d158878425392fe5a0cc34f15dbaf46315ae0ed9",
|
||||
"reference": "d158878425392fe5a0cc34f15dbaf46315ae0ed9",
|
||||
"url": "https://api.github.com/repos/bshaffer/oauth2-server-php/zipball/5a0c8000d4763b276919e2106f54eddda6bc50fa",
|
||||
"reference": "5a0c8000d4763b276919e2106f54eddda6bc50fa",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -117,7 +117,7 @@
|
||||
"oauth",
|
||||
"oauth2"
|
||||
],
|
||||
"time": "2017-11-15T01:41:02+00:00"
|
||||
"time": "2018-12-04T00:29:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "commerceguys/intl",
|
||||
@ -251,16 +251,16 @@
|
||||
},
|
||||
{
|
||||
"name": "league/html-to-markdown",
|
||||
"version": "4.8.0",
|
||||
"version": "4.8.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/html-to-markdown.git",
|
||||
"reference": "f9a879a068c68ff47b722de63f58bec79e448f9d"
|
||||
"reference": "250d1bf45f80d15594fb6b316df777d6d4c97ad1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/f9a879a068c68ff47b722de63f58bec79e448f9d",
|
||||
"reference": "f9a879a068c68ff47b722de63f58bec79e448f9d",
|
||||
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/250d1bf45f80d15594fb6b316df777d6d4c97ad1",
|
||||
"reference": "250d1bf45f80d15594fb6b316df777d6d4c97ad1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -311,7 +311,7 @@
|
||||
"html",
|
||||
"markdown"
|
||||
],
|
||||
"time": "2018-09-18T12:18:08+00:00"
|
||||
"time": "2018-12-24T17:21:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "lukasreschke/id3parser",
|
||||
@ -1925,32 +1925,33 @@
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
"version": "1.4.2",
|
||||
"version": "1.5.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/psr7.git",
|
||||
"reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c"
|
||||
"reference": "9f83dded91781a01c63574e387eaa769be769115"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
|
||||
"reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/9f83dded91781a01c63574e387eaa769be769115",
|
||||
"reference": "9f83dded91781a01c63574e387eaa769be769115",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.0",
|
||||
"psr/http-message": "~1.0"
|
||||
"psr/http-message": "~1.0",
|
||||
"ralouphie/getallheaders": "^2.0.5"
|
||||
},
|
||||
"provide": {
|
||||
"psr/http-message-implementation": "1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
"phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4-dev"
|
||||
"dev-master": "1.5-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -1980,13 +1981,14 @@
|
||||
"keywords": [
|
||||
"http",
|
||||
"message",
|
||||
"psr-7",
|
||||
"request",
|
||||
"response",
|
||||
"stream",
|
||||
"uri",
|
||||
"url"
|
||||
],
|
||||
"time": "2017-03-20T17:10:46+00:00"
|
||||
"time": "2018-12-04T20:46:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
@ -2571,6 +2573,7 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"abandoned": true,
|
||||
"time": "2018-02-07T06:47:59+00:00"
|
||||
},
|
||||
{
|
||||
@ -2827,16 +2830,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "7.4.4",
|
||||
"version": "7.5.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "b1be2c8530c4c29c3519a052c9fb6cee55053bbd"
|
||||
"reference": "c23d78776ad415d5506e0679723cb461d71f488f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b1be2c8530c4c29c3519a052c9fb6cee55053bbd",
|
||||
"reference": "b1be2c8530c4c29c3519a052c9fb6cee55053bbd",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c23d78776ad415d5506e0679723cb461d71f488f",
|
||||
"reference": "c23d78776ad415d5506e0679723cb461d71f488f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2857,7 +2860,7 @@
|
||||
"phpunit/php-timer": "^2.0",
|
||||
"sebastian/comparator": "^3.0",
|
||||
"sebastian/diff": "^3.0",
|
||||
"sebastian/environment": "^3.1 || ^4.0",
|
||||
"sebastian/environment": "^4.0",
|
||||
"sebastian/exporter": "^3.1",
|
||||
"sebastian/global-state": "^2.0",
|
||||
"sebastian/object-enumerator": "^3.0.3",
|
||||
@ -2881,7 +2884,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "7.4-dev"
|
||||
"dev-master": "7.5-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -2907,7 +2910,7 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2018-11-14T16:52:02+00:00"
|
||||
"time": "2018-12-12T07:20:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
@ -3008,6 +3011,46 @@
|
||||
],
|
||||
"time": "2016-08-06T14:39:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ralouphie/getallheaders",
|
||||
"version": "2.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ralouphie/getallheaders.git",
|
||||
"reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/5601c8a83fbba7ef674a7369456d12f1e0d0eafa",
|
||||
"reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~3.7.0",
|
||||
"satooshi/php-coveralls": ">=1.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/getallheaders.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ralph Khattar",
|
||||
"email": "ralph.khattar@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "A polyfill for getallheaders.",
|
||||
"time": "2016-02-11T07:05:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/code-unit-reverse-lookup",
|
||||
"version": "1.0.1",
|
||||
@ -3175,28 +3218,28 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
"version": "3.1.0",
|
||||
"version": "4.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/environment.git",
|
||||
"reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5"
|
||||
"reference": "febd209a219cea7b56ad799b30ebbea34b71eb8f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5",
|
||||
"reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/febd209a219cea7b56ad799b30ebbea34b71eb8f",
|
||||
"reference": "febd209a219cea7b56ad799b30ebbea34b71eb8f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.0"
|
||||
"php": "^7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^6.1"
|
||||
"phpunit/phpunit": "^7.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.1.x-dev"
|
||||
"dev-master": "4.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -3221,7 +3264,7 @@
|
||||
"environment",
|
||||
"hhvm"
|
||||
],
|
||||
"time": "2017-07-01T08:51:00+00:00"
|
||||
"time": "2018-11-25T09:31:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
@ -3573,16 +3616,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/browser-kit",
|
||||
"version": "v4.1.7",
|
||||
"version": "v4.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/browser-kit.git",
|
||||
"reference": "c55fe9257003b2d95c0211b3f6941e8dfd26dffd"
|
||||
"reference": "db7e59fec9c82d45e745eb500e6ede2d96f4a6e9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/c55fe9257003b2d95c0211b3f6941e8dfd26dffd",
|
||||
"reference": "c55fe9257003b2d95c0211b3f6941e8dfd26dffd",
|
||||
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/db7e59fec9c82d45e745eb500e6ede2d96f4a6e9",
|
||||
"reference": "db7e59fec9c82d45e745eb500e6ede2d96f4a6e9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3599,7 +3642,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.1-dev"
|
||||
"dev-master": "4.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -3626,20 +3669,20 @@
|
||||
],
|
||||
"description": "Symfony BrowserKit Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-07-26T09:10:45+00:00"
|
||||
"time": "2018-11-26T11:49:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/class-loader",
|
||||
"version": "v3.4.18",
|
||||
"version": "v3.4.20",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/class-loader.git",
|
||||
"reference": "5605edec7b8f034ead2497ff4aab17bb70d558c1"
|
||||
"reference": "420458095cf60025eb0841276717e0da7f75e50e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/class-loader/zipball/5605edec7b8f034ead2497ff4aab17bb70d558c1",
|
||||
"reference": "5605edec7b8f034ead2497ff4aab17bb70d558c1",
|
||||
"url": "https://api.github.com/repos/symfony/class-loader/zipball/420458095cf60025eb0841276717e0da7f75e50e",
|
||||
"reference": "420458095cf60025eb0841276717e0da7f75e50e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3682,20 +3725,20 @@
|
||||
],
|
||||
"description": "Symfony ClassLoader Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-10-31T09:06:03+00:00"
|
||||
"time": "2018-11-11T19:48:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/config",
|
||||
"version": "v4.1.7",
|
||||
"version": "v4.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/config.git",
|
||||
"reference": "991fec8bbe77367fc8b48ecbaa8a4bd6e905a238"
|
||||
"reference": "005d9a083d03f588677d15391a716b1ac9b887c0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/991fec8bbe77367fc8b48ecbaa8a4bd6e905a238",
|
||||
"reference": "991fec8bbe77367fc8b48ecbaa8a4bd6e905a238",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/005d9a083d03f588677d15391a716b1ac9b887c0",
|
||||
"reference": "005d9a083d03f588677d15391a716b1ac9b887c0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3718,7 +3761,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.1-dev"
|
||||
"dev-master": "4.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -3745,24 +3788,25 @@
|
||||
],
|
||||
"description": "Symfony Config Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-10-31T09:09:42+00:00"
|
||||
"time": "2018-11-30T22:21:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.1.7",
|
||||
"version": "v4.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "432122af37d8cd52fba1b294b11976e0d20df595"
|
||||
"reference": "4dff24e5d01e713818805c1862d2e3f901ee7dd0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/432122af37d8cd52fba1b294b11976e0d20df595",
|
||||
"reference": "432122af37d8cd52fba1b294b11976e0d20df595",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/4dff24e5d01e713818805c1862d2e3f901ee7dd0",
|
||||
"reference": "4dff24e5d01e713818805c1862d2e3f901ee7dd0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"symfony/contracts": "^1.0",
|
||||
"symfony/polyfill-mbstring": "~1.0"
|
||||
},
|
||||
"conflict": {
|
||||
@ -3786,7 +3830,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.1-dev"
|
||||
"dev-master": "4.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -3813,20 +3857,88 @@
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-10-31T09:30:44+00:00"
|
||||
"time": "2018-11-27T07:40:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/css-selector",
|
||||
"version": "v3.4.18",
|
||||
"name": "symfony/contracts",
|
||||
"version": "v1.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/css-selector.git",
|
||||
"reference": "3503415d4aafabc31cd08c3a4ebac7f43fde8feb"
|
||||
"url": "https://github.com/symfony/contracts.git",
|
||||
"reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/3503415d4aafabc31cd08c3a4ebac7f43fde8feb",
|
||||
"reference": "3503415d4aafabc31cd08c3a4ebac7f43fde8feb",
|
||||
"url": "https://api.github.com/repos/symfony/contracts/zipball/1aa7ab2429c3d594dd70689604b5cf7421254cdf",
|
||||
"reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/cache": "^1.0",
|
||||
"psr/container": "^1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/cache": "When using the Cache contracts",
|
||||
"psr/container": "When using the Service contracts",
|
||||
"symfony/cache-contracts-implementation": "",
|
||||
"symfony/service-contracts-implementation": "",
|
||||
"symfony/translation-contracts-implementation": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Contracts\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"**/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "A set of abstractions extracted out of the Symfony components",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"abstractions",
|
||||
"contracts",
|
||||
"decoupling",
|
||||
"interfaces",
|
||||
"interoperability",
|
||||
"standards"
|
||||
],
|
||||
"time": "2018-12-05T08:06:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/css-selector",
|
||||
"version": "v3.4.20",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/css-selector.git",
|
||||
"reference": "345b9a48595d1ab9630db791dbc3e721bf0233e8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/345b9a48595d1ab9630db791dbc3e721bf0233e8",
|
||||
"reference": "345b9a48595d1ab9630db791dbc3e721bf0233e8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3866,37 +3978,39 @@
|
||||
],
|
||||
"description": "Symfony CssSelector Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-10-02T16:33:53+00:00"
|
||||
"time": "2018-11-11T19:48:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dependency-injection",
|
||||
"version": "v4.1.7",
|
||||
"version": "v4.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dependency-injection.git",
|
||||
"reference": "e72ee2c23d952e4c368ee98610fa22b79b89b483"
|
||||
"reference": "e4adc57a48d3fa7f394edfffa9e954086d7740e5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e72ee2c23d952e4c368ee98610fa22b79b89b483",
|
||||
"reference": "e72ee2c23d952e4c368ee98610fa22b79b89b483",
|
||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e4adc57a48d3fa7f394edfffa9e954086d7740e5",
|
||||
"reference": "e4adc57a48d3fa7f394edfffa9e954086d7740e5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"psr/container": "^1.0"
|
||||
"psr/container": "^1.0",
|
||||
"symfony/contracts": "^1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/config": "<4.1.1",
|
||||
"symfony/config": "<4.2",
|
||||
"symfony/finder": "<3.4",
|
||||
"symfony/proxy-manager-bridge": "<3.4",
|
||||
"symfony/yaml": "<3.4"
|
||||
},
|
||||
"provide": {
|
||||
"psr/container-implementation": "1.0"
|
||||
"psr/container-implementation": "1.0",
|
||||
"symfony/service-contracts-implementation": "1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/config": "~4.1",
|
||||
"symfony/config": "~4.2",
|
||||
"symfony/expression-language": "~3.4|~4.0",
|
||||
"symfony/yaml": "~3.4|~4.0"
|
||||
},
|
||||
@ -3910,7 +4024,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.1-dev"
|
||||
"dev-master": "4.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -3937,20 +4051,20 @@
|
||||
],
|
||||
"description": "Symfony DependencyInjection Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-10-31T10:54:16+00:00"
|
||||
"time": "2018-12-02T15:59:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dom-crawler",
|
||||
"version": "v4.1.7",
|
||||
"version": "v4.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dom-crawler.git",
|
||||
"reference": "80e60271bb288de2a2259662cff125cff4f93f95"
|
||||
"reference": "7438a32108fdd555295f443605d6de2cce473159"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/80e60271bb288de2a2259662cff125cff4f93f95",
|
||||
"reference": "80e60271bb288de2a2259662cff125cff4f93f95",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/7438a32108fdd555295f443605d6de2cce473159",
|
||||
"reference": "7438a32108fdd555295f443605d6de2cce473159",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3967,7 +4081,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.1-dev"
|
||||
"dev-master": "4.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -3994,24 +4108,25 @@
|
||||
],
|
||||
"description": "Symfony DomCrawler Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-10-02T12:40:59+00:00"
|
||||
"time": "2018-11-26T10:55:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v4.1.7",
|
||||
"version": "v4.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "552541dad078c85d9414b09c041ede488b456cd5"
|
||||
"reference": "921f49c3158a276d27c0d770a5a347a3b718b328"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/552541dad078c85d9414b09c041ede488b456cd5",
|
||||
"reference": "552541dad078c85d9414b09c041ede488b456cd5",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/921f49c3158a276d27c0d770a5a347a3b718b328",
|
||||
"reference": "921f49c3158a276d27c0d770a5a347a3b718b328",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3"
|
||||
"php": "^7.1.3",
|
||||
"symfony/contracts": "^1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/dependency-injection": "<3.4"
|
||||
@ -4030,7 +4145,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.1-dev"
|
||||
"dev-master": "4.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -4057,20 +4172,20 @@
|
||||
],
|
||||
"description": "Symfony EventDispatcher Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-10-10T13:52:42+00:00"
|
||||
"time": "2018-12-01T08:52:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v4.1.7",
|
||||
"version": "v4.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "fd7bd6535beb1f0a0a9e3ee960666d0598546981"
|
||||
"reference": "2f4c8b999b3b7cadb2a69390b01af70886753710"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/fd7bd6535beb1f0a0a9e3ee960666d0598546981",
|
||||
"reference": "fd7bd6535beb1f0a0a9e3ee960666d0598546981",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/2f4c8b999b3b7cadb2a69390b01af70886753710",
|
||||
"reference": "2f4c8b999b3b7cadb2a69390b01af70886753710",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4080,7 +4195,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.1-dev"
|
||||
"dev-master": "4.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -4107,7 +4222,7 @@
|
||||
],
|
||||
"description": "Symfony Filesystem Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-10-30T13:18:25+00:00"
|
||||
"time": "2018-11-11T19:52:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
@ -4170,20 +4285,21 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation",
|
||||
"version": "v4.1.7",
|
||||
"version": "v4.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/translation.git",
|
||||
"reference": "aa04dc1c75b7d3da7bd7003104cd0cfc5dff635c"
|
||||
"reference": "c0e2191e9bed845946ab3d99767513b56ca7dcd6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/aa04dc1c75b7d3da7bd7003104cd0cfc5dff635c",
|
||||
"reference": "aa04dc1c75b7d3da7bd7003104cd0cfc5dff635c",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/c0e2191e9bed845946ab3d99767513b56ca7dcd6",
|
||||
"reference": "c0e2191e9bed845946ab3d99767513b56ca7dcd6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"symfony/contracts": "^1.0.2",
|
||||
"symfony/polyfill-mbstring": "~1.0"
|
||||
},
|
||||
"conflict": {
|
||||
@ -4191,6 +4307,9 @@
|
||||
"symfony/dependency-injection": "<3.4",
|
||||
"symfony/yaml": "<3.4"
|
||||
},
|
||||
"provide": {
|
||||
"symfony/translation-contracts-implementation": "1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/config": "~3.4|~4.0",
|
||||
@ -4208,7 +4327,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.1-dev"
|
||||
"dev-master": "4.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -4235,20 +4354,20 @@
|
||||
],
|
||||
"description": "Symfony Translation Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-10-28T18:38:52+00:00"
|
||||
"time": "2018-12-06T10:45:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v4.1.7",
|
||||
"version": "v4.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "367e689b2fdc19965be435337b50bc8adf2746c9"
|
||||
"reference": "c41175c801e3edfda90f32e292619d10c27103d7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/367e689b2fdc19965be435337b50bc8adf2746c9",
|
||||
"reference": "367e689b2fdc19965be435337b50bc8adf2746c9",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/c41175c801e3edfda90f32e292619d10c27103d7",
|
||||
"reference": "c41175c801e3edfda90f32e292619d10c27103d7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4267,7 +4386,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.1-dev"
|
||||
"dev-master": "4.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -4294,7 +4413,7 @@
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-10-02T16:36:10+00:00"
|
||||
"time": "2018-11-11T19:52:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
@ -4338,20 +4457,21 @@
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
"version": "1.3.0",
|
||||
"version": "1.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/webmozart/assert.git",
|
||||
"reference": "0df1908962e7a3071564e857d86874dad1ef204a"
|
||||
"reference": "83e253c8e0be5b0257b881e1827274667c5c17a9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a",
|
||||
"reference": "0df1908962e7a3071564e857d86874dad1ef204a",
|
||||
"url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9",
|
||||
"reference": "83e253c8e0be5b0257b881e1827274667c5c17a9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.3.3 || ^7.0"
|
||||
"php": "^5.3.3 || ^7.0",
|
||||
"symfony/polyfill-ctype": "^1.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.6",
|
||||
@ -4384,7 +4504,7 @@
|
||||
"check",
|
||||
"validate"
|
||||
],
|
||||
"time": "2018-01-29T19:49:41+00:00"
|
||||
"time": "2018-12-25T11:19:39+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
@ -95,7 +95,7 @@ PHP might differ from the _webserver_ version
|
||||
php.ini file * and with no hosting provider restrictions on the use of
|
||||
exec() and proc_open().
|
||||
|
||||
* curl, gd (with at least jpeg and png support), mysqli, mbstring, mcrypt,
|
||||
* curl, gd (with at least jpeg and png support), mysqli, mbstring, mcrypt, zip,
|
||||
and openssl extensions. The imagick extension is not required but desirable.
|
||||
|
||||
* xml extension is required if you want webdav to work.
|
||||
|
@ -21,7 +21,7 @@ If you get a blank white screen when doing something, this is almost always a co
|
||||
|
||||
[h3]I'm stumped. I can't figure out what is wrong.[/h3]
|
||||
|
||||
At this point it might be worthwhile discussing the issue on one of the online forums. There may be several of these and some may be more suited to your spoken language. At this time, the 'Hubzilla Support' channel (support@gravizot.de) is the recommended forum for discussing bugs.
|
||||
At this point it might be worthwhile discussing the issue on one of the online forums. There may be several of these and some may be more suited to your spoken language. At this time, the 'Hubzilla Support' channel (support@zotadel.net) is the recommended forum for discussing bugs.
|
||||
|
||||
If community members with software engineering training/expertise can't help you right away, understand that they are volunteers and may have a lot of other work and demands on their time. At this point you need to file a bug report. You will need an account on framagit.org to do this. So register, and then visit https://framagit.org/hubzilla/core/issues . Create an issue here and provide all the same information that you provided online. Don't leave out anything.
|
||||
|
||||
|
42
doc/hook/collect_public_recipients.bb
Normal file
42
doc/hook/collect_public_recipients.bb
Normal file
@ -0,0 +1,42 @@
|
||||
[h2]collect_public_recipients[/h2]
|
||||
|
||||
Replace the default list of public recipients (i.e., all contacts).
|
||||
|
||||
Allow plugins to create a list of recipients for public messages instead of the default
|
||||
of all channel connections.
|
||||
|
||||
Called with the following array:
|
||||
[
|
||||
'recipients' => [],
|
||||
'item' => $item,
|
||||
'private_envelope' => $private_envelope,
|
||||
'include_groups' => $include_groups
|
||||
];
|
||||
|
||||
[code]
|
||||
if(array_key_exists('public_policy',$item) && $item['public_policy'] !== 'self') {
|
||||
|
||||
$hookinfo = [
|
||||
'recipients' => [],
|
||||
'item' => $item,
|
||||
'private_envelope' => $private_envelope,
|
||||
'include_groups' => $include_groups
|
||||
];
|
||||
|
||||
call_hooks('collect_public_recipients',$hookinfo);
|
||||
|
||||
if ($hookinfo['recipients']) {
|
||||
$r = $hookinfo['recipients'];
|
||||
} else {
|
||||
$r = q("select abook_xchan, xchan_network from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and abook_pending = 0 and abook_archived = 0 ",
|
||||
intval($item['uid'])
|
||||
);
|
||||
}
|
||||
|
||||
if($r) {
|
||||
|
||||
. . .
|
||||
|
||||
[/code]
|
||||
|
||||
see: include/item.php
|
5
doc/hook/daemon_master_release.bb
Normal file
5
doc/hook/daemon_master_release.bb
Normal file
@ -0,0 +1,5 @@
|
||||
[h2]daemon_master_release[/h2]
|
||||
|
||||
Permit filtering or alternate methods of processing of background processes when [code] \Zotlabs\Daemon\Master::Release() [/code] is called.
|
||||
|
||||
Default behavior is for a new PHP process to fire immediately upon a call to Master::Summon(). This hook permits pre-emption and the ability to provide queuing or other alternatives to this procedure.
|
24
doc/hook/item_custom.bb
Normal file
24
doc/hook/item_custom.bb
Normal file
@ -0,0 +1,24 @@
|
||||
[h2]item_custom[/h2]
|
||||
|
||||
Allow addons to create and process custom item types.
|
||||
|
||||
Addon authors will need to use iconfig meta data (with sharing on) or some other method
|
||||
to specify and determine whether the custom item is destined for their addon.
|
||||
|
||||
It is fed an array of ['item' => ${item_array}, 'allow_exec' => {true/false}]
|
||||
|
||||
By default $arr['item']['cancel'] is set to TRUE which will abort storage of the
|
||||
custom item in the item table unless the addon unsets it or sets it to false.
|
||||
|
||||
[code]
|
||||
if ($arr['item_type']==ITEM_TYPE_CUSTOM) {
|
||||
/* Custom items are not stored by default
|
||||
because they require an addon to process. */
|
||||
$d['item']['cancel']=true;
|
||||
|
||||
call_hooks('item_custom',$d);
|
||||
}
|
||||
|
||||
[/code]
|
||||
|
||||
see: include/items.php
|
18
doc/hook/item_stored.bb
Normal file
18
doc/hook/item_stored.bb
Normal file
@ -0,0 +1,18 @@
|
||||
[h2]item_stored[/h2]
|
||||
|
||||
Allow addons to continue processing after an item has been stored in the event
|
||||
that they need access to the item_id or other data that gets assigned during
|
||||
the storage process.
|
||||
|
||||
It is fed an array of type item (including terms and iconfig data).
|
||||
|
||||
[code]
|
||||
/**
|
||||
* @hooks item_stored
|
||||
* Called after new item is stored in the database.
|
||||
* (By this time we have an item_id and other frequently needed info.)
|
||||
*/
|
||||
call_hooks('item_stored',$arr);
|
||||
[/code]
|
||||
|
||||
see: include/items.php
|
15
doc/hook/item_stored_update.bb
Normal file
15
doc/hook/item_stored_update.bb
Normal file
@ -0,0 +1,15 @@
|
||||
[h2]item_stored_update[/h2]
|
||||
|
||||
Allow addons to continue processing after an item update has been stored
|
||||
|
||||
It is fed an array of type item (including terms and iconfig data).
|
||||
|
||||
[code]
|
||||
/**
|
||||
* @hooks item_stored_update
|
||||
* Called after updated item is stored in the database.
|
||||
*/
|
||||
call_hooks('item_stored_update',$arr);
|
||||
[/code]
|
||||
|
||||
see: include/items.php
|
5
doc/hook/jot_header_tpl_filter.bb
Normal file
5
doc/hook/jot_header_tpl_filter.bb
Normal file
@ -0,0 +1,5 @@
|
||||
[h2]jot_header_tpl_filter[/h2]
|
||||
|
||||
Allows addon developers to modify the values of replacements fed into jot-header.tpl
|
||||
|
||||
cxref: include/conversation.php
|
5
doc/hook/jot_tpl_filter.bb
Normal file
5
doc/hook/jot_tpl_filter.bb
Normal file
@ -0,0 +1,5 @@
|
||||
[h2]jot_tpl_filter[/h2]
|
||||
|
||||
Allows addon developers to alter the macro replacements prior to being fed into jot.tpl
|
||||
|
||||
cxref: include/conversation.php
|
12
doc/hook/privacygroup_extras.bb
Normal file
12
doc/hook/privacygroup_extras.bb
Normal file
@ -0,0 +1,12 @@
|
||||
[h2]privacygroup_extras[/h2]
|
||||
|
||||
Add items to the Privacy Group edit form
|
||||
|
||||
[code]
|
||||
$hookinfo = [ 'pgrp_extras' => '', 'group'=>$argv(1) ];
|
||||
call_hooks ('privacygroup_extras',$hookinfo);
|
||||
$pgrp_extras = $hookinfo['pgrp_extras'];
|
||||
[/code]
|
||||
|
||||
see: Zotlabs/Module/Group.php
|
||||
see: view/tpl/privacy_groups.tpl
|
11
doc/hook/privacygroup_extras_drop.bb
Normal file
11
doc/hook/privacygroup_extras_drop.bb
Normal file
@ -0,0 +1,11 @@
|
||||
[h2]privacygroup_extras_drop[/h2]
|
||||
|
||||
Called after privacy group is dropped
|
||||
|
||||
[code]
|
||||
$hookinfo = [ 'pgrp_extras' => '', 'group'=>$argv(2) ];
|
||||
call_hooks ('privacygroup_extras_drop',$hookinfo);
|
||||
[/code]
|
||||
|
||||
see: Zotlabs/Module/Group.php
|
||||
see: view/tpl/privacy_groups.tpl
|
11
doc/hook/privacygroup_extras_post.bb
Normal file
11
doc/hook/privacygroup_extras_post.bb
Normal file
@ -0,0 +1,11 @@
|
||||
[h2]privacygroup_extras_post[/h2]
|
||||
|
||||
Called as privacy group edit form is edited.
|
||||
|
||||
[code]
|
||||
$hookinfo = [ 'pgrp_extras' => '', 'group'=>$group['id'] ];
|
||||
call_hooks ('privacygroup_extras_post',$hookinfo);
|
||||
[/code]
|
||||
|
||||
see: Zotlabs/Module/Group.php
|
||||
see: view/tpl/privacy_groups.tpl
|
@ -136,6 +136,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
|
||||
[zrl=[baseurl]/help/hook/check_siteallowed]check_siteallowed[/zrl]
|
||||
Used to over-ride or bypass the site black/white block lists
|
||||
|
||||
[zrl=[baseurl]/help/hook/collect_public_recipients]collect_public_recipients[/zrl]
|
||||
Used to establish a list of recipients to send a public message to.
|
||||
|
||||
[zrl=[baseurl]/help/hook/comment_buttons]comment_buttons[/zrl]
|
||||
Called when rendering the edit buttons for comments
|
||||
|
||||
@ -190,6 +193,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
|
||||
[zrl=[baseurl]/help/hook/daemon_addon]daemon_addon[/zrl]
|
||||
Called when invoking the extensible background daemon
|
||||
|
||||
[zrl=[baseurl]/help/hook/daemon_master_release]daemon_master_release[/zrl]
|
||||
Called at the start of processing \Zotlabs\Daemon\Master::Release()
|
||||
|
||||
[zrl=[baseurl]/help/hook/directory_item]directory_item[/zrl]
|
||||
Called when generating a directory listing for display
|
||||
|
||||
@ -343,9 +349,18 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
|
||||
[zrl=[baseurl]/help/hook/item_store]item_store[/zrl]
|
||||
Called when item_store() stores a record of type item
|
||||
|
||||
[zrl=[baseurl]/help/hook/item_stored]item_stored[/zrl]
|
||||
Called after item_store() has stored a record of type item in the database.
|
||||
|
||||
[zrl=[baseurl]/help/hook/item_custom]item_custom[/zrl]
|
||||
Called before item_store() stores a record of type item (allowing addons to process ITEM_TYPE_CUSTOM items).
|
||||
|
||||
[zrl=[baseurl]/help/hook/item_store_update]item_store_update[/zrl]
|
||||
Called when item_store_update() is called to update a stored item.
|
||||
|
||||
[zrl=[baseurl]/help/hook/item_stored_update]item_stored_update[/zrl]
|
||||
Called after item_store_update() has updated a stored item.
|
||||
|
||||
[zrl=[baseurl]/help/hook/item_translate]item_translate[/zrl]
|
||||
Called from item_store and item_store_update after the post language has been autodetected
|
||||
|
||||
@ -355,6 +370,12 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
|
||||
[zrl=[baseurl]/help/hook/jot_tool]jot_tool[/zrl]
|
||||
Deprecated and possibly obsolete. Allows one to add action buttons to the post editor.
|
||||
|
||||
[zrl=[baseurl]/help/hook/jot_tpl_filter]jot_tpl_filter[/zrl]
|
||||
Called to filter template vars before replacement in jot.tpl.
|
||||
|
||||
[zrl=[baseurl]/help/hook/jot_header_tpl_filter]jot_header_tpl_filter[/zrl]
|
||||
Called to filter template vars before replacement in jot_header.tpl.
|
||||
|
||||
[zrl=[baseurl]/help/hook/legal_webbie]legal_webbie[/zrl]
|
||||
Called to validate a channel address
|
||||
|
||||
@ -544,6 +565,15 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the
|
||||
[zrl=[baseurl]/help/hook/prepare_body_init]prepare_body_init[/zrl]
|
||||
Called before generating the HTML for a displayed conversation item
|
||||
|
||||
[zrl=[baseurl]/help/hook/privacygroup_extras]privacygroup_extras[/zrl]
|
||||
Called before generating the HTML for the Privacy Group edit options
|
||||
|
||||
[zrl=[baseurl]/help/hook/privacygroup_extras_delete]privacygroup_extras_delete[/zrl]
|
||||
Called after privacy group is dropped.
|
||||
|
||||
[zrl=[baseurl]/help/hook/privacygroup_extras_post]privacygroup_extras_post[/zrl]
|
||||
Called when privacy group edit form is submitted.
|
||||
|
||||
[zrl=[baseurl]/help/hook/proc_run]proc_run[/zrl]
|
||||
Called when invoking PHP sub processes
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user