Merge branch 'dev' of https://github.com/redmatrix/hubzilla into dev_merge

This commit is contained in:
zotlabs 2018-01-08 14:50:58 -08:00
commit 75804d7ce5
34 changed files with 337 additions and 191 deletions

View File

@ -28,23 +28,23 @@ Hardware
Software
+ Fresh installation of Debian 9 (Stretch) on your mini-pc
+ Router with open ports 80 and 443 for your Debian
+ Fresh installation of Debian 9 (Stretch)
+ Router with open ports 80 and 443 for your Hub
## The basic steps (quick overview)
+ Register your own domain (for example at selfHOST) or a free subdomain (for example at freeDNS)
+ Install Debian 9
+ On your router: Open the ports 80 and 443
+ Log on to your fresh Debian
- apt-get install git
- mkdir -p /var/www
- cd /var/www
- git clone https://github.com/redmatrix/hubzilla.git html
- cp .homeinstall/hubzilla-config.txt.template .homeinstall/hubzilla-config.txt
- nano .homeinstall/hubzilla-config.txt
- cd /html/.homeinstall
- cp hubzilla-config.txt.template hubzilla-config.txt
- nano hubzilla-config.txt
- Read the comments carefully
- Enter your values: db pass, domain, values for dyn DNS
- Make sure your external drive (for backups) is mounted
- hubzilla-setup.sh as root
- ... wait, wait, wait until the script is finised
- reboot
@ -58,24 +58,27 @@ Software
### Recommended: USB Drive for Backups
The installation will create a daily backup.
If the backup process does not find an external device than the backup goes to
the internal disk.
The installation will create a daily backup written to an external drive.
The USB drive must be compatible with the filesystems
- ext4 (if you do not want to encrypt the USB)
- LUKS + ext4 (if you want to encrypt the USB)
The backup includes
- Hubzilla DB
- Hubzilla installation /var/www/html
- Certificates for letsencrypt
## Preparations Software
### Install Debian Linux on the Mini-PC
Download the stable Debian 9 at https://www.debian.org/
Download the stable Debian at https://www.debian.org/
(Debian 8 is no longer supported.)
Create bootable USB drive with Debian on it. You could use
Create bootable USB drive with Debian on it.You could use
- unetbootin, https://en.wikipedia.org/wiki/UNetbootin
- or simply the linux command "dd"
@ -109,12 +112,9 @@ You can use subdomains as well
my.cooldomain.org
There are two ways to get a domain
There are two ways to get a domain...
- buy a domain, or
- register a free subdomain
### Method 1: Buy an own Domain
### Method 1: Buy a Domain
...for example buy at selfHOST.de
@ -122,14 +122,14 @@ The cost are around 10,- € once and 1,50 € per month (2017).
### Method 2 Register a (free) Subdomain
...for example register at freeDNS
...for example register at freedns.afraid.org
Follow the instructions in .homeinstall/hubzilla-config.txt.
## Install Hubzilla on your Debian
Login to your Debian
Login to your debian
(Provided your username is "you" and the name of the mini pc is "debian". You
could take the IP address instead of "debian")
@ -164,6 +164,8 @@ Modify the file "hubzilla-config.txt". Read the instructions there carefully and
nano hubzilla-config.txt
Make sure your external drive (for backups) is plugged in and can be mounted as configured in "hubzilla-config.txt". Otherwise the daily backups will not work.
Run the script
./hubzilla-setup.sh
@ -187,11 +189,16 @@ Leave db type "MySQL" untouched.
Follow the instructions in the next pages.
After the daily script was executed at 05:30 (am)
- look at var/www/html/hubzilla-daily.log
- check your backup on the external drive
- optionally view the daily log under yourdomain.org/admin/logs/
- set the logfile to var/www/html/hubzilla-daily.log
## Note for the Rasperry
The script was tested with a Raspberry 3 under Raspian (Debian 9.3, 2017-11-29-raspbian-stretch.img).
Be patient when a page is loaded by your Raspi-Hub for the very first time. Especially the config pages after the install will load very slowly.
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...
@ -202,8 +209,8 @@ It is recommended to run the Raspi without graphical frontend (X-Server). Use...
sudo raspi-config
There choose "3 Boot Options" > "31 Desktop / CLI" > "B1 Console". Reboot.
to boot the Rapsi to the client console.
**DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!**
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!

View File

@ -13,10 +13,10 @@ db_pass=
# This script automates installation of an SSL certificate from
# Let's Encrypt (https://letsencrypt.org)
#
# Please give the domain name of your hub. Examples:
# Please give the domain name of your hub
#
# le_domain=my.cooldomain.org
# le_domain=cooldomain.org
# Example: my.cooldomain.org
# Example: cooldomain.org
#
# Email is optional
#
@ -25,7 +25,7 @@ le_domain=
le_email=
###############################################
### OPTIONAL - dynamic IP address - selfHOST ##
### OPTIONAL - selfHOST - dynamic IP address ##
#
# 1. Register a domain at selfhost.de
# - choose offer "DOMAIN dynamisch" 1,50€/mon at 08.01.2016
@ -42,7 +42,7 @@ selfhost_user=
selfhost_pass=
###############################################
### OPTIONAL - dynamic IP address - FreeDNS ###
### OPTIONAL - FreeDNS - dynamic IP address ###
#
# Please give the alpha-numeric-key of freedns
#

View File

@ -459,11 +459,6 @@ function configure_cron_selfhost {
fi
}
function install_git {
print_info "installing git..."
nocheck_install "git"
}
function install_letsencrypt {
print_info "installing let's encrypt ..."
# check if user gave domain
@ -570,20 +565,13 @@ function check_https {
}
function install_hubzilla {
print_info "installing hubzilla..."
# rm -R /var/www/html/ # for "stand alone" usage
cd /var/www/
# git clone https://github.com/redmatrix/hubzilla html # for "stand alone" usage
cd html/
git clone https://github.com/redmatrix/hubzilla-addons addon
print_info "installing hubzilla addons..."
cd /var/www/html/
util/add_addon_repo https://github.com/redmatrix/hubzilla-addons.git hzaddons
mkdir -p "store/[data]/smarty3"
chmod -R 777 store
touch .htconfig.php
chmod ou+w .htconfig.php
# uncomment the last function call "install_hubzilla_plugins"
# - if you want to install addons and themes that are not officially supported
# - and read the comments in function "install_hubzilla_plugins" how do do it
# install_hubzilla_plugins
cd /var/www/
chown -R www-data:www-data html
chown root:www-data /var/www/html/
@ -598,72 +586,6 @@ function install_hubzilla {
print_info "installed hubzilla"
}
function install_hubzilla_plugins {
print_info "installing hubzilla plugins..."
cd /var/www/html
plugin_install=.homeinstall/plugin_install.txt
theme_install=.homeinstall/theme_install.txt
# overwrite script to update the plugin and themes
rm -f $plugins_update
echo "cd /var/www/html" >> $plugins_update
###################
# write plugin file
if [ ! -f "$plugin_install" ]
then
echo "# To install a plugin" >> $plugin_install
echo "# 1. add the plugin in a new line and run" >> $plugin_install
echo "# 2. run" >> $plugin_install
echo "# cd /var/www/html/.homeinstall" >> $plugin_install
echo "# ./hubzilla-setup.sh" >> $plugin_install
echo "https://gitlab.com/zot/ownmapp.git ownMapp" >> $plugin_install
fi
# install plugins
while read -r line; do
[[ "$line" =~ ^#.*$ ]] && continue
p_url=$(echo $line | awk -F' ' '{print $1}')
p_name=$(echo $line | awk -F' ' '{print $2}')
# basic check of format
if [ ${#p_url} -ge 1 ] && [ ${#p_name} -ge 1 ]
then
# install addon
util/add_addon_repo $line
util/update_addon_repo $p_name # not sure if this line is neccessary
echo "util/update_addon_repo $p_name" >> $plugins_update
else
print_info "skipping installation of a plugin from file $plugin_install - something wrong with format in line: $line"
fi
done < "$plugin_install"
###################
# write theme file
if [ ! -f "$theme_install" ]
then
echo "# To install a theme" >> $theme_install
echo "# 1. add the theme in a new line and run" >> $theme_install
echo "# 2. run" >> $theme_install
echo "# cd /var/www/html/.homeinstall" >> $theme_install
echo "# ./hubzilla-setup.sh" >> $theme_install
echo "https://github.com/DeadSuperHero/hubzilla-themes.git DeadSuperHeroThemes" >> $theme_install
fi
# install plugins
while read -r line; do
[[ "$line" =~ ^#.*$ ]] && continue
p_url=$(echo $line | awk -F' ' '{print $1}')
p_name=$(echo $line | awk -F' ' '{print $2}')
# basic check of format
if [ ${#p_url} -ge 1 ] && [ ${#p_name} -ge 1 ]
then
# install addon
util/add_theme_repo $line
util/update_theme_repo $p_name # not sure if this line is neccessary
echo "util/update_theme_repo $p_name" >> $plugins_update
else
print_info "skipping installation of a theme from file $theme_install - something wrong with format in line: $line"
fi
done < "$theme_install"
print_info "installed hubzilla plugins and themes"
}
function rewrite_to_https {
print_info "configuring apache to redirect http to httpS ..."
htaccessfile=/var/www/html/.htaccess
@ -788,12 +710,11 @@ echo " fi" >> /var/www/$hubzilladaily
echo "fi" >> /var/www/$hubzilladaily
echo "if [ \$device_mounted == 0 ]" >> /var/www/$hubzilladaily
echo "then" >> /var/www/$hubzilladaily
echo " echo \"device could not be mounted $backup_device_name. Using internal disk for backup...\"" >> /var/www/$hubzilladaily
echo " rsnapshot -c $snapshotconfig alpha" >> /var/www/$hubzilladaily
echo " echo \"device could not be mounted $backup_device_name. No backup written.\"" >> /var/www/$hubzilladaily
echo "fi" >> /var/www/$hubzilladaily
echo "#" >> /var/www/$hubzilladaily
echo "echo \"\$(date) - db size...\"" >> /var/www/$hubzilladaily
echo "du -h /var/cache/rsnapshot/ | grep mysql/hubzilla" >> /var/www/$hubzilladaily
echo "du -h /var/lib/mysql/ | grep mysql/hubzilla" >> /var/www/$hubzilladaily
echo "#" >> /var/www/$hubzilladaily
echo "# update" >> /var/www/$hubzilladaily
echo "echo \"\$(date) - updating dehydrated...\"" >> /var/www/$hubzilladaily

View File

@ -1,4 +1,8 @@
Hubzilla 3.0 (????-??-??)
- Updated homeinstall script
- Sort cloud directory by 1. is_dir and 2. name
- Document that imagick calls/execs ffmpeg for mp4 video thumbnails
- Use pipe_stream() instead of file_{get, put}_contents() in attach_store()
- Make homeinstall script ready for Debian 9
- Add url and headings to bbco_autocomplete()
- Remove additional linebreaks after headings
@ -82,6 +86,12 @@ Hubzilla 3.0 (????-??-??)
- Table structure for pseudo or proxy channels (pchan)
Bugfixes
- Fix sync non-default profile photo changes to clones - github issue #113
- Fix prev/next buttons on connedit can show deleted connections - github issue #673
- Fix affinity widget settings
- Fix dupe bug in content hooks - github issue #943
- Fix directory keywords returned from dir_tagadelic() in standalone mode
- Fix argument warning when arguments are correct in util/dcp
- Fix issue with long filenames in mod cloud
- Fix misc. issues with new 'insert photo from photo album' github issue #475
- Fix regression in channel sources delivery
@ -116,6 +126,10 @@ Hubzilla 3.0 (????-??-??)
- Fix unstar
Plugins/Addon
Diaspora: fix 'view full size' photo link - core github issue #947
Diaspora: implement recent changes in diaspora account_migration spec
GNU-Social: fix uploading a photo to a post results in double post - github issue 75
GNU-Social: fix gnusoc plugin not respecting delayed delivery - github issue 74
Pubcrawl: fix PHP warning
Diaspora: remove garbage from magic envelope
Diaspora: fix permalinks for zot reshares

View File

@ -0,0 +1,121 @@
<?php
namespace Zotlabs\Lib;
class Img_filesize {
private $url;
function __construct($url) {
$this->url = $url;
}
function getSize() {
$size = null;
if(stripos($this->url,z_root() . '/photo') !== false) {
$size = self::getLocalFileSize($this->url);
}
if(! $size) {
$size = getRemoteFileSize($this->url);
}
return $size;
}
static function getLocalFileSize($url) {
$fname = basename($url);
$resolution = 0;
if(strpos($fname,'.') !== false)
$fname = substr($fname,0,strpos($fname,'.'));
if(substr($fname,-2,1) == '-') {
$resolution = intval(substr($fname,-1,1));
$fname = substr($fname,0,-2);
}
$r = q("SELECT filesize FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
dbesc($fname),
intval($resolution)
);
if($r) {
return $r[0]['filesize'];
}
return null;
}
}
/**
* Try to determine the size of a remote file by making an HTTP request for
* a byte range, or look for the content-length header in the response.
* The function aborts the transfer as soon as the size is found, or if no
* length headers are returned, it aborts the transfer.
*
* @return int|null null if size could not be determined, or length of content
*/
function getRemoteFileSize($url)
{
$ch = curl_init($url);
$headers = array(
'Range: bytes=0-1',
'Connection: close',
);
$in_headers = true;
$size = null;
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2450.0 Iron/46.0.2450.0');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_VERBOSE, 0); // set to 1 to debug
curl_setopt($ch, CURLOPT_STDERR, fopen('php://output', 'r'));
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($curl, $line) use (&$in_headers, &$size) {
$length = strlen($line);
if (trim($line) == '') {
$in_headers = false;
}
list($header, $content) = explode(':', $line, 2);
$header = strtolower(trim($header));
if ($header == 'content-range') {
// found a content-range header
list($rng, $s) = explode('/', $content, 2);
$size = (int)$s;
return 0; // aborts transfer
} else if ($header == 'content-length' && 206 != curl_getinfo($curl, CURLINFO_HTTP_CODE)) {
// found content-length header and this is not a 206 Partial Content response (range response)
$size = (int)$content;
return 0;
} else {
// continue
return $length;
}
});
curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($curl, $data) use ($in_headers) {
if (!$in_headers) {
// shouldn't be here unless we couldn't determine file size
// abort transfer
return 0;
}
// write function is also called when reading headers
return strlen($data);
});
$result = curl_exec($ch);
$info = curl_getinfo($ch);
return $size;
}

View File

@ -22,7 +22,8 @@ class Apps extends \Zotlabs\Web\Controller {
if(local_channel()) {
Zlib\Apps::import_system_apps();
$syslist = array();
$list = Zlib\Apps::app_list(local_channel(), (($mode == 'edit') ? true : false), $_GET['cat']);
$cat = ((array_key_exists('cat',$_GET) && $_GET['cat']) ? [ escape_tags($_GET['cat']) ] : '');
$list = Zlib\Apps::app_list(local_channel(), (($mode == 'edit') ? true : false), $cat);
if($list) {
foreach($list as $x) {
$syslist[] = Zlib\Apps::app_encode($x);
@ -43,7 +44,7 @@ class Apps extends \Zotlabs\Web\Controller {
return replace_macros(get_markup_template('myapps.tpl'), array(
'$sitename' => get_config('system','sitename'),
'$cat' => ((array_key_exists('cat',$_GET) && $_GET['cat']) ? escape_tags($_GET['cat']) : ''),
'$cat' => $cat,
'$title' => t('Apps'),
'$apps' => $apps,
'$authed' => ((local_channel()) ? true : false),

View File

@ -567,7 +567,7 @@ class Connedit extends \Zotlabs\Web\Controller {
$contact_id = \App::$poi['abook_id'];
$contact = \App::$poi;
$cn = q("SELECT abook_id, xchan_name from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 order by xchan_name",
$cn = q("SELECT abook_id, xchan_name from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and xchan_deleted = 0 order by xchan_name",
intval(local_channel())
);

View File

@ -16,12 +16,15 @@ class Feed extends \Zotlabs\Web\Controller {
$params['type'] = ((stristr(argv(0),'json')) ? 'json' : 'xml');
$params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0);
$params['top'] = ((x($_REQUEST,'top')) ? intval($_REQUEST['top']) : 0);
$params['start'] = ((x($params,'start')) ? intval($params['start']) : 0);
$params['records'] = ((x($params,'records')) ? intval($params['records']) : 40);
$params['direction'] = ((x($params,'direction')) ? dbesc($params['direction']) : 'desc');
$params['start'] = ((x($_REQUEST,'start')) ? intval($_REQUEST['start']) : 0);
$params['records'] = ((x($_REQUEST,'records')) ? intval($_REQUEST['records']) : 40);
$params['direction'] = ((x($_REQUEST,'direction')) ? dbesc($_REQUEST['direction']) : 'desc');
$params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : '');
$params['compat'] = ((x($_REQUEST,'compat')) ? intval($_REQUEST['compat']) : 0);
if(! in_array($params['direction'],['asc','desc'])) {
$params['direction'] = 'desc';
}
if(argc() > 1) {

View File

@ -35,8 +35,11 @@ class Network extends \Zotlabs\Web\Controller {
return login(false);
}
if($load)
$o = '';
if($load) {
$_SESSION['loadtime'] = datetime_convert();
}
$arr = array('query' => \App::$query_string);
@ -104,7 +107,9 @@ class Network extends \Zotlabs\Web\Controller {
$def_acl = array('allow_gid' => '<' . $r[0]['hash'] . '>');
}
$o = '';
$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 no tabs are selected, defaults to comments
@ -115,8 +120,8 @@ class Network extends \Zotlabs\Web\Controller {
$liked = ((x($_GET,'liked')) ? intval($_GET['liked']) : 0);
$conv = ((x($_GET,'conv')) ? intval($_GET['conv']) : 0);
$spam = ((x($_GET,'spam')) ? intval($_GET['spam']) : 0);
$cmin = ((x($_GET,'cmin')) ? intval($_GET['cmin']) : 0);
$cmax = ((x($_GET,'cmax')) ? intval($_GET['cmax']) : 99);
$cmin = ((array_key_exists('cmin',$_GET)) ? intval($_GET['cmin']) : $default_cmin);
$cmax = ((array_key_exists('cmax',$_GET)) ? intval($_GET['cmax']) : $default_cmax);
$file = ((x($_GET,'file')) ? $_GET['file'] : '');
$xchan = ((x($_GET,'xchan')) ? $_GET['xchan'] : '');
$net = ((x($_GET,'net')) ? $_GET['net'] : '');
@ -404,7 +409,6 @@ class Network extends \Zotlabs\Web\Controller {
if($cmax == 99)
$sql_nets .= " OR abook.abook_closeness IS NULL ) ";
}
$net_query = (($net) ? " left join xchan on xchan_hash = author_xchan " : '');
@ -473,7 +477,6 @@ class Network extends \Zotlabs\Web\Controller {
if($load) {
// Fetch a page full of parent items for this page
$r = q("SELECT distinct item.id AS item_id, $ordering FROM item
left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids )
$net_query
@ -484,7 +487,6 @@ class Network extends \Zotlabs\Web\Controller {
$net_query2
ORDER BY $ordering DESC $pager_sql "
);
}
else {

View File

@ -17,12 +17,15 @@ class Ofeed extends \Zotlabs\Web\Controller {
$params['type'] = ((stristr(argv(0),'json')) ? 'json' : 'xml');
$params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0);
$params['top'] = ((x($_REQUEST,'top')) ? intval($_REQUEST['top']) : 0);
$params['start'] = ((x($params,'start')) ? intval($params['start']) : 0);
$params['records'] = ((x($params,'records')) ? intval($params['records']) : 10);
$params['direction'] = ((x($params,'direction')) ? dbesc($params['direction']) : 'desc');
$params['start'] = ((x($_REQUEST,'start')) ? intval($_REQUEST['start']) : 0);
$params['records'] = ((x($_REQUEST,'records')) ? intval($_REQUEST['records']) : 10);
$params['direction'] = ((x($_REQUEST,'direction')) ? dbesc($_REQUEST['direction']) : 'desc');
$params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : '');
$params['compat'] = ((x($_REQUEST,'compat')) ? intval($_REQUEST['compat']) : 1);
if(! in_array($params['direction'],['asc','desc'])) {
$params['direction'] = 'desc';
}
if(argc() > 1) {

View File

@ -179,7 +179,10 @@ class Profile_photo extends \Zotlabs\Web\Controller {
);
}
profiles_build_sync(local_channel());
// set $send to false in profiles_build_sync() to return the data
// so that we only send one sync packet.
$sync_profiles = profiles_build_sync(local_channel(),false);
// We'll set the updated profile-photo timestamp even if it isn't the default profile,
// so that browsers will do a cache update unconditionally
@ -201,7 +204,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
$sync = attach_export_data($channel,$base_image['resource_id']);
if($sync)
build_sync_packet($channel['channel_id'],array('file' => array($sync)));
build_sync_packet($channel['channel_id'],array('file' => array($sync), 'profile' => $sync_profiles));
// Similarly, tell the nav bar to bypass the cache and update the avatar image.

View File

@ -11,15 +11,17 @@ class Featured {
call_hooks('feature_settings_post', $_POST);
if($_POST['affinity_slider-submit']) {
if(intval($_POST['affinity_cmax'])) {
set_pconfig(local_channel(),'affinity','cmax',intval($_POST['affinity_cmax']));
}
if(intval($_POST['affinity_cmin'])) {
set_pconfig(local_channel(),'affinity','cmin',intval($_POST['affinity_cmin']));
}
if(intval($_POST['affinity_cmax']) || intval($_POST['affinity_cmin'])) {
info( t('Affinity Slider settings updated.') . EOL);
}
$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();
@ -40,12 +42,12 @@ class Featured {
$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, '')
'$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, '')
'$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(

View File

@ -691,7 +691,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
}
$prefix = '';
$suffix = '';
$suffix = ' order by is_dir desc, filename asc ';
$r = q("select $prefix id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, created, edited from attach where folder = '%s' and uid = %d $perms $suffix",
dbesc($folder),

View File

@ -32,12 +32,24 @@ class Video {
fclose($ostream);
}
/*
* Note: imagick convert may try to call 'ffmpeg' (or other conversion utilities) under
* the covers for this particular operation. If this is not installed or not in the path
* for the web server user, errors may be reported in the web server logs.
*/
$ffmpeg = trim(shell_exec('which ffmpeg'));
if($ffmpeg) {
logger('ffmpeg not found in path. Video thumbnails may fail.');
}
$imagick_path = get_config('system','imagick_convert_path');
if($imagick_path && @file_exists($imagick_path)) {
$cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmpfile . '[0]') . ' -thumbnail ' . $width . 'x' . $height . ' ' . escapeshellarg(PROJECT_BASE . '/' . $outfile);
// logger('imagick thumbnail command: ' . $cmd);
exec($cmd);
@exec($cmd);
if(! file_exists($outfile)) {
logger('imagick scale failed.');

View File

@ -265,7 +265,7 @@ class Router {
if(! \App::$error) {
$arr = array('content' => \App::$page['content'], 'replace' => false);
call_hooks(\App::$module . '_mod_content', $arr);
\App::$page['content'] = $arr['content'];
if(! $arr['replace']) {
if($this->controller && method_exists($this->controller,'get')) {
$arr = array('content' => $this->controller->get());
@ -276,7 +276,7 @@ class Router {
}
}
call_hooks(\App::$module . '_mod_aftercontent', $arr);
\App::$page['content'] .= $arr['content'];
\App::$page['content'] = (($arr['replace']) ? $arr['content'] : \App::$page['content'] . $arr['content']);
}
}
}

View File

@ -9,15 +9,11 @@ class Affinity {
if(! local_channel())
return '';
// Get default cmin value from pconfig, but allow GET parameter to override
$cmin = intval(get_pconfig(local_channel(),'affinity','cmin'));
$cmin = (($cmin) ? $cmin : 0);
$cmin = ((x($_REQUEST,'cmin')) ? intval($_REQUEST['cmin']) : $cmin);
$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);
// Get default cmax value from pconfig, but allow GET parameter to override
$cmax = intval(get_pconfig(local_channel(),'affinity','cmax'));
$cmax = (($cmax) ? $cmax : 99);
$cmax = ((x($_REQUEST,'cmax')) ? intval($_REQUEST['cmax']) : $cmax);
$cmin = ((x($_REQUEST,'cmin')) ? intval($_REQUEST['cmin']) : $default_cmin);
$cmax = ((x($_REQUEST,'cmax')) ? intval($_REQUEST['cmax']) : $default_cmax);
if(feature_enabled(local_channel(),'affinity')) {

View File

@ -144,6 +144,7 @@ class Notifications {
$o = replace_macros(get_markup_template('notifications_widget.tpl'), array(
'$module' => \App::$module,
'$notifications' => $notifications,
'$no_notifications' => t('Sorry, you have got no notifications at the moment'),
'$loading' => t('Loading')
));

View File

@ -50,7 +50,7 @@ require_once('include/hubloc.php');
require_once('include/attach.php');
define ( 'PLATFORM_NAME', 'hubzilla' );
define ( 'STD_VERSION', '3.1' );
define ( 'STD_VERSION', '3.1.1' );
define ( 'ZOT_REVISION', '1.3' );
define ( 'DB_UPDATE_VERSION', 1198 );

View File

@ -550,6 +550,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$type = $f['type'];
} else {
if(! x($_FILES,'userfile')) {
logger('No source file');
$ret['message'] = t('No source file.');
return $ret;
}
@ -590,6 +591,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
intval($channel_id)
);
if(! $x) {
logger('update file source not found');
$ret['message'] = t('Cannot locate file to revise/update');
return $ret;
}
@ -731,6 +733,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$maxfilesize = get_config('system','maxfilesize');
if(($maxfilesize) && ($filesize > $maxfilesize)) {
logger('quota_exceeded');
$ret['message'] = sprintf( t('File exceeds size limit of %d'), $maxfilesize);
if($remove_when_processed)
@unlink($src);
@ -751,6 +754,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
intval($channel['channel_account_id'])
);
if(($r) && (($r[0]['total'] + $filesize) > ($limit - $existing_size))) {
logger('service_class limit exceeded');
$ret['message'] = upgrade_message(true) . sprintf(t("You have reached your limit of %1$.0f Mbytes attachment storage."), $limit / 1024000);
if($remove_when_processed)
@unlink($src);
@ -783,8 +787,15 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$os_path = $os_relpath;
$display_path = ltrim($pathname . '/' . $filename,'/');
if($src)
@file_put_contents($os_basepath . $os_relpath,@file_get_contents($src));
if($src) {
$istream = @fopen($src,'rb');
$ostream = @fopen($os_basepath . $os_relpath,'wb');
if($istream && $ostream) {
pipe_streams($istream,$ostream,65535);
fclose($istream);
fclose($ostream);
}
}
if(array_key_exists('created', $arr))
$created = $arr['created'];

View File

@ -1982,12 +1982,17 @@ function get_channel_default_perms($uid) {
}
function profiles_build_sync($channel_id) {
function profiles_build_sync($channel_id,$send = true) {
$r = q("select * from profile where uid = %d",
intval($channel_id)
);
if($r) {
build_sync_packet($channel_id,array('profile' => $r));
if($send) {
build_sync_packet($channel_id,array('profile' => $r));
}
else {
return $r;
}
}
}

View File

@ -1801,12 +1801,17 @@ function compat_photos_list($s) {
if($found) {
foreach($matches as $match) {
$ret[] = [
$entry = [
'href' => $match[2],
'length' => 0,
'type' => guess_image_type($match[2])
];
$sizer = new \Zotlabs\Lib\Img_filesize($match[2]);
$size = $sizer->getSize();
if(intval($size)) {
$entry['length'] = intval($size);
}
$ret[] = $entry;
}
}

View File

@ -162,13 +162,17 @@ function import_profiles($channel, $profiles) {
convert_oldfields($profile,'work','employment');
/**
* @TODO we are going to reset all profile photos to the original
* somebody will have to fix this later and put all the applicable
* photos into the export.
* @TODO put all the applicable photos into the export.
*/
$profile['photo'] = z_root() . '/photo/profile/l/' . $channel['channel_id'];
$profile['thumb'] = z_root() . '/photo/profile/m/' . $channel['channel_id'];
if((strpos($profile['thumb'],'/photo/profile/l/') !== false) || intval($profile['is_default'])) {
$profile['photo'] = z_root() . '/photo/profile/l/' . $channel['channel_id'];
$profile['thumb'] = z_root() . '/photo/profile/m/' . $channel['channel_id'];
}
else {
$profile['photo'] = z_root() . '/photo/' . basename($profile['photo']);
$profile['thumb'] = z_root() . '/photo/' . basename($profile['thumb']);
}
create_table_from_array('profile', $profile);
}
@ -1328,6 +1332,9 @@ function sync_files($channel, $files) {
}
}
}
\Zotlabs\Daemon\Master::Summon([ 'Thumbnail' , $att['hash'] ]);
if($f['item']) {
sync_items($channel,$f['item'],
['channel_address' => $original_channel,'url' => $oldbase]

View File

@ -4063,8 +4063,9 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
$item_uids = ' true ';
$item_normal = item_normal();
if ($arr['uid']) $uid= $arr['uid'];
if($arr['uid']) {
$uid = $arr['uid'];
}
if($channel) {
$uid = $channel['channel_id'];
@ -4226,7 +4227,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
$items = q("SELECT item.*, item.id AS item_id FROM item
WHERE $item_uids $item_restrict
$simple_update
$sql_extra $sql_nets
$sql_extra $sql_nets $sql_extra3
ORDER BY item.received DESC $pager_sql"
);

View File

@ -752,13 +752,14 @@ function scale_external_images($s, $include_link = true, $scale_replace = false)
if($orig_width > 1024 || $orig_height > 1024) {
$tag = (($match[1] == 'z') ? 'zmg' : 'img');
$linktag = (($match[1] == 'z') ? 'zrl' : 'url');
$ph->scaleImage(1024);
$new_width = $ph->getWidth();
$new_height = $ph->getHeight();
logger('data: ' . $orig_width . '->' . $new_width . 'w ' . $orig_height . '->' . $new_height . 'h' . ' match: ' . $mtch[0], LOGGER_DEBUG);
$s = str_replace($mtch[0],'[' . $tag . '=' . $new_width . 'x' . $new_height. ']' . $scaled . '[/' . $tag . ']'
. "\n" . (($include_link)
? '[zrl=' . $mtch[2] . ']' . t('view full size') . '[/zrl]' . "\n"
? '[' . $linktag . '=' . $mtch[3] . ']' . t('view full size') . '[/' . $linktag . ']' . "\n"
: ''),$s);
logger('new string: ' . $s, LOGGER_DEBUG);
}

View File

@ -313,12 +313,25 @@ function dir_tagadelic($count = 0) {
$count = intval($count);
// Fetch tags
$r = q("select xtag_term as term, count(xtag_term) as total from xtag where xtag_flags = 0
group by xtag_term order by total desc %s",
((intval($count)) ? "limit $count" : '')
);
$dirmode = get_config('system','directory_mode');
if($dirmode == DIRECTORY_MODE_STANDALONE) {
// Fetch tags
$r = q("select xtag_term as term, count(xtag_term) as total from xtag
left join hubloc on xtag_hash = hubloc_hash
where xtag_flags = 0 and hubloc_url = '%s'
group by xtag_term order by total desc %s",
dbesc(z_root()),
((intval($count)) ? "limit $count" : '')
);
}
else {
// Fetch tags
$r = q("select xtag_term as term, count(xtag_term) as total from xtag where xtag_flags = 0
group by xtag_term order by total desc %s",
((intval($count)) ? "limit $count" : '')
);
}
if(! $r)
return array();

View File

@ -105,8 +105,8 @@ function strip_zats($s) {
function clean_query_string() {
$x = strip_zids(\App::$query_string);
function clean_query_string($s = '') {
$x = strip_zids(($s) ? $s : \App::$query_string);
$x = strip_owt($x);
$x = strip_zats($x);

View File

@ -3745,6 +3745,15 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
* @TODO
* We also need to import local photos if a custom photo is selected
*/
if((strpos($profile['thumb'],'/photo/profile/l/') !== false) || intval($profile['is_default'])) {
$profile['photo'] = z_root() . '/photo/profile/l/' . $channel['channel_id'];
$profile['thumb'] = z_root() . '/photo/profile/m/' . $channel['channel_id'];
}
else {
$profile['photo'] = z_root() . '/photo/' . basename($profile['photo']);
$profile['thumb'] = z_root() . '/photo/' . basename($profile['thumb']);
}
}
if(count($clean)) {

View File

@ -14,7 +14,7 @@ require_once('include/attach.php');
cli_startup();
if($argc <= 3) {
if($argc < 3) {
echo "Usage: " . $argv[0] . ' src dstdir' . "\n";
echo 'Always run from the toplevel web directory.' . "\n";
echo 'destination should begin with store/$nickname/desired/path or $nickname/desired/path' . "\n";

View File

@ -170,6 +170,9 @@ a.wikilist {
}
/* notifications */
.notifications-btn {
opacity: .5;
}
.notification-content {
max-height: 70vh;

View File

@ -373,10 +373,12 @@ function notificationsUpdate() {
if(data.network || data.home || data.intros || data.register || data.mail || data.all_events || data.notify || data.files || data.pubs) {
$('.notifications-btn').css('opacity', 1);
$('#no_notifications').hide();
}
else {
$('.notifications-btn').css('opacity', 0.5);
$('#navbar-collapse-1').removeClass('show');
$('#no_notifications').show();
}
if(data.home || data.intros || data.register || data.mail || data.notify || data.files) {

View File

@ -23,7 +23,7 @@
$.post(url, data, function(data) {
if(timer) clearTimeout(timer);
NavUpdate();
updateInit();
$.colorbox.close();
})

View File

@ -340,7 +340,7 @@ var activeCommentText = '';
$.get('{{$baseurl}}/tagger/' + id + '?term=' + reply);
if(timer) clearTimeout(timer);
timer = setTimeout(NavUpdate,3000);
timer = setTimeout(updateInit,3000);
liking = 1;
}
}
@ -359,7 +359,7 @@ var activeCommentText = '';
if(reply && reply.length) {
commentBusy = true;
$('body').css('cursor', 'wait');
$.get('{{$baseurl}}/filer/' + id + '?term=' + reply, NavUpdate);
$.get('{{$baseurl}}/filer/' + id + '?term=' + reply, updateInit);
liking = 1;
$('#item-filer-dialog').modal('hide');
}
@ -372,13 +372,13 @@ var activeCommentText = '';
function itemBookmark(id) {
$.get('{{$baseurl}}/bookmarks?f=&item=' + id);
if(timer) clearTimeout(timer);
timer = setTimeout(NavUpdate,1000);
timer = setTimeout(updateInit,1000);
}
function itemAddToCal(id) {
$.get('{{$baseurl}}/events/add/' + id);
if(timer) clearTimeout(timer);
timer = setTimeout(NavUpdate,1000);
timer = setTimeout(updateInit,1000);
}
function toggleVoting() {
@ -409,7 +409,7 @@ var activeCommentText = '';
if(id && icon) {
$.get('{{$baseurl}}/react?f=&postid=' + id + '&emoji=' + icon);
if(timer) clearTimeout(timer);
timer = setTimeout(NavUpdate,1000);
timer = setTimeout(updateInit,1000);
}
}

View File

@ -4,10 +4,10 @@
{{if $create}}
<a href="appman" class="pull-right btn btn-success btn-sm"><i class="fa fa-pencil-square-o"></i>&nbsp;{{$create}}</a>
{{else}}
<a href="apps/edit{{if $cat}}/?f=&cat={{$cat}}{{/if}}" class="pull-right btn btn-primary btn-sm">{{$manage}}</a>
<a href="apps/edit{{if $cat.0}}/?f=&cat={{$cat.0}}{{/if}}" class="pull-right btn btn-primary btn-sm">{{$manage}}</a>
{{/if}}
{{/if}}
<h2>{{$title}}{{if $cat}} - {{$cat}}{{/if}}</h2>
<h2>{{$title}}{{if $cat.0}} - {{$cat.0}}{{/if}}</h2>
</div>
<div class="clearfix section-content-wrapper">
{{foreach $apps as $ap}}

View File

@ -63,7 +63,7 @@
$(document).on('click', '#tt-{{$notification.type}}-only', function(e) {
e.preventDefault();
$('#nav-{{$notification.type}}-menu [data-thread_top=false]').toggle();
$(this).toggleClass('active');
$(this).toggleClass('active sticky-top');
});
{{/if}}
{{/foreach}}
@ -85,6 +85,9 @@
{{if $notifications}}
<div id="notifications_wrapper">
<div id="no_notifications" class="d-xl-none">
{{$no_notifications}}<span class="jumping-dots"><span class="dot-1">.</span><span class="dot-2">.</span><span class="dot-3">.</span></span>
</div>
<div id="notifications" class="navbar-nav" data-children=".nav-item">
<div id="nav-notifications-template" rel="template">
<a class="list-group-item clearfix notification {5}" href="{0}" title="{2} {3}" data-b64mid="{6}" data-notify_id="{7}" data-thread_top="{8}">