Merge remote-tracking branch 'upstream/dev' into wiki
This commit is contained in:
commit
47d7fc70e8
@ -38,7 +38,7 @@ class Expire {
|
||||
|
||||
logger('site_expire: ' . $site_expire);
|
||||
|
||||
$r = q("SELECT channel_id, channel_address, channel_pageflags, channel_expire_days from channel where true");
|
||||
$r = q("SELECT channel_id, channel_system, channel_address, channel_expire_days from channel where true");
|
||||
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
|
@ -248,7 +248,7 @@ class ThreadItem {
|
||||
$has_bookmarks = false;
|
||||
if(is_array($item['term'])) {
|
||||
foreach($item['term'] as $t) {
|
||||
if(!UNO && $t['type'] == TERM_BOOKMARK)
|
||||
if(!UNO && $t['ttype'] == TERM_BOOKMARK)
|
||||
$has_bookmarks = true;
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ require_once('vendor/autoload.php');
|
||||
class Cloud extends \Zotlabs\Web\Controller {
|
||||
|
||||
function init() {
|
||||
require_once('include/reddav.php');
|
||||
|
||||
if (! is_dir('store'))
|
||||
os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false);
|
||||
@ -79,17 +78,6 @@ class Cloud extends \Zotlabs\Web\Controller {
|
||||
|
||||
$is_readable = false;
|
||||
|
||||
if($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
try {
|
||||
$x = RedFileData('/' . \App::$cmd, $auth);
|
||||
}
|
||||
catch(\Exception $e) {
|
||||
if($e instanceof Sabre\DAV\Exception\Forbidden) {
|
||||
http_status_exit(401, 'Permission denied.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// provide a directory view for the cloud in Hubzilla
|
||||
$browser = new \Zotlabs\Storage\Browser($auth);
|
||||
$auth->setBrowserPlugin($browser);
|
||||
|
@ -44,8 +44,6 @@ class Dav extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
|
||||
require_once('include/reddav.php');
|
||||
|
||||
if (! is_dir('store'))
|
||||
os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false);
|
||||
|
||||
|
@ -146,6 +146,7 @@ class Dreport extends \Zotlabs\Web\Controller {
|
||||
'$title' => sprintf( t('Delivery report for %1$s'),substr($mid,0,32)) . '...',
|
||||
'$table' => $table,
|
||||
'$mid' => urlencode($mid),
|
||||
'$options' => t('Options'),
|
||||
'$push' => t('Redeliver'),
|
||||
'$entries' => $entries
|
||||
));
|
||||
|
@ -93,7 +93,7 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
|
||||
$origin = (($api_source && array_key_exists('origin',$_REQUEST)) ? intval($_REQUEST['origin']) : 1);
|
||||
|
||||
// To represent message-ids on other networks - this will create an item_id record
|
||||
// To represent message-ids on other networks - this will create an iconfig record
|
||||
|
||||
$namespace = (($api_source && array_key_exists('namespace',$_REQUEST)) ? strip_tags($_REQUEST['namespace']) : '');
|
||||
$remote_id = (($api_source && array_key_exists('remote_id',$_REQUEST)) ? strip_tags($_REQUEST['remote_id']) : '');
|
||||
@ -535,7 +535,7 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
|
||||
/**
|
||||
* fix naked links by passing through a callback to see if this is a red site
|
||||
* fix naked links by passing through a callback to see if this is a hubzilla site
|
||||
* (already known to us) which will get a zrl, otherwise link with url, add bookmark tag to both.
|
||||
* First protect any url inside certain bbcode tags so we don't double link it.
|
||||
*/
|
||||
@ -834,21 +834,23 @@ class Item extends \Zotlabs\Web\Controller {
|
||||
if($orig_post)
|
||||
$datarray['edit'] = true;
|
||||
|
||||
// suppress duplicates, *unless* you're editing an existing post. This could get picked up
|
||||
// as a duplicate if you're editing it very soon after posting it initially and you edited
|
||||
// some attribute besides the content, such as title or categories.
|
||||
|
||||
if(feature_enabled($profile_uid,'suppress_duplicates') && (! $orig_post)) {
|
||||
|
||||
$z = q("select created from item where uid = %d and body = '%s'",
|
||||
$z = q("select created from item where uid = %d and created > %s - INTERVAL %s and body = '%s' limit 1",
|
||||
intval($profile_uid),
|
||||
db_utcnow(),
|
||||
db_quoteinterval('2 MINUTE'),
|
||||
dbesc($body)
|
||||
);
|
||||
|
||||
if($z) {
|
||||
foreach($z as $zz) {
|
||||
if($zz['created'] > datetime_convert('UTC','UTC', 'now - 2 minutes')) {
|
||||
$datarray['cancel'] = 1;
|
||||
notice( t('Duplicate post suppressed.') . EOL);
|
||||
logger('Duplicate post. Faking plugin cancel.');
|
||||
}
|
||||
}
|
||||
$datarray['cancel'] = 1;
|
||||
notice( t('Duplicate post suppressed.') . EOL);
|
||||
logger('Duplicate post. Faking plugin cancel.');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,9 +125,9 @@ class New_channel extends \Zotlabs\Web\Controller {
|
||||
}
|
||||
}
|
||||
|
||||
$name = array('name', t('Name or caption'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group"'));
|
||||
$name = array('name', t('Name or caption'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group"'), "*");
|
||||
$nickhub = '@' . \App::get_hostname();
|
||||
$nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), sprintf( t('Your nickname will be used to create an easy to remember channel address e.g. nickname%s'), $nickhub));
|
||||
$nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), sprintf( t('Your nickname will be used to create an easy to remember channel address e.g. nickname%s'), $nickhub), "*");
|
||||
$privacy_role = ((x($_REQUEST,'permissions_role')) ? $_REQUEST['permissions_role'] : "" );
|
||||
$role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel role with your privacy requirements.') . ' <a href="help/roles" target="_blank">' . t('Read more about roles') . '</a>',get_roles());
|
||||
|
||||
|
@ -180,6 +180,8 @@ class Profile_photo extends \Zotlabs\Web\Controller {
|
||||
dbesc(datetime_convert()),
|
||||
dbesc($channel['xchan_hash'])
|
||||
);
|
||||
// Similarly, tell the nav bar to bypass the cache and update the avater image.
|
||||
$_SESSION['reload_avatar'] = true;
|
||||
|
||||
info( t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL);
|
||||
|
||||
|
@ -129,9 +129,14 @@ class Tagger extends \Zotlabs\Web\Controller {
|
||||
|
||||
store_item_tag($item['uid'],$item['id'],TERM_OBJ_POST,TERM_COMMUNITYTAG,$term,$tagid);
|
||||
$ret = post_activity_item($arr);
|
||||
|
||||
if($ret['success'])
|
||||
\Zotlabs\Daemon\Master::Summon(array('Notifier','tag',$ret['activity']['id']));
|
||||
|
||||
if($ret['success']) {
|
||||
build_sync_packet(local_channel(),
|
||||
[
|
||||
'item' => [ encode_item($ret['activity'],true) ]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
killme();
|
||||
|
||||
|
@ -91,7 +91,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
$contents = RedCollectionData($this->red_path, $this->auth);
|
||||
$contents = $this->CollectionData($this->red_path, $this->auth);
|
||||
return $contents;
|
||||
}
|
||||
|
||||
@ -119,7 +119,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
|
||||
return new Directory('/' . $modulename, $this->auth);
|
||||
}
|
||||
|
||||
$x = RedFileData($this->ext_path . '/' . $name, $this->auth);
|
||||
$x = $this->FileData($this->ext_path . '/' . $name, $this->auth);
|
||||
if ($x) {
|
||||
return $x;
|
||||
}
|
||||
@ -206,6 +206,8 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
|
||||
require_once('include/attach.php');
|
||||
|
||||
$mimetype = z_mime_content_type($name);
|
||||
|
||||
$c = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1",
|
||||
@ -431,8 +433,8 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
|
||||
return true;
|
||||
}
|
||||
|
||||
$x = RedFileData($this->ext_path . '/' . $name, $this->auth, true);
|
||||
//logger('RedFileData returns: ' . print_r($x, true), LOGGER_DATA);
|
||||
$x = $this->FileData($this->ext_path . '/' . $name, $this->auth, true);
|
||||
//logger('FileData returns: ' . print_r($x, true), LOGGER_DATA);
|
||||
if ($x)
|
||||
return true;
|
||||
|
||||
@ -565,4 +567,280 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
|
||||
$free
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Array with all Directory and File DAV\Node items for the given path.
|
||||
*
|
||||
*
|
||||
* @param string $file path to a directory
|
||||
* @param \Zotlabs\Storage\BasicAuth &$auth
|
||||
* @returns null|array \Sabre\DAV\INode[]
|
||||
* @throw \Sabre\DAV\Exception\Forbidden
|
||||
* @throw \Sabre\DAV\Exception\NotFound
|
||||
*/
|
||||
|
||||
function CollectionData($file, &$auth) {
|
||||
$ret = array();
|
||||
|
||||
$x = strpos($file, '/cloud');
|
||||
if ($x === 0) {
|
||||
$file = substr($file, 6);
|
||||
}
|
||||
|
||||
// return a list of channel if we are not inside a channel
|
||||
if ((! $file) || ($file === '/')) {
|
||||
return $this->ChannelList($auth);
|
||||
}
|
||||
|
||||
$file = trim($file, '/');
|
||||
$path_arr = explode('/', $file);
|
||||
|
||||
if (! $path_arr)
|
||||
return null;
|
||||
|
||||
$channel_name = $path_arr[0];
|
||||
|
||||
$r = q("SELECT channel_id FROM channel WHERE channel_address = '%s' LIMIT 1",
|
||||
dbesc($channel_name)
|
||||
);
|
||||
|
||||
if (! $r)
|
||||
return null;
|
||||
|
||||
$channel_id = $r[0]['channel_id'];
|
||||
$perms = permissions_sql($channel_id);
|
||||
|
||||
$auth->owner_id = $channel_id;
|
||||
|
||||
$path = '/' . $channel_name;
|
||||
|
||||
$folder = '';
|
||||
$errors = false;
|
||||
$permission_error = false;
|
||||
|
||||
for ($x = 1; $x < count($path_arr); $x++) {
|
||||
$r = q("SELECT id, hash, filename, flags, is_dir FROM attach WHERE folder = '%s' AND filename = '%s' AND uid = %d AND is_dir != 0 $perms LIMIT 1",
|
||||
dbesc($folder),
|
||||
dbesc($path_arr[$x]),
|
||||
intval($channel_id)
|
||||
);
|
||||
if (! $r) {
|
||||
// path wasn't found. Try without permissions to see if it was the result of permissions.
|
||||
$errors = true;
|
||||
$r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 limit 1",
|
||||
dbesc($folder),
|
||||
basename($path_arr[$x]),
|
||||
intval($channel_id)
|
||||
);
|
||||
if ($r) {
|
||||
$permission_error = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ($r && intval($r[0]['is_dir'])) {
|
||||
$folder = $r[0]['hash'];
|
||||
$path = $path . '/' . $r[0]['filename'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($errors) {
|
||||
if ($permission_error) {
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
else {
|
||||
throw new DAV\Exception\NotFound('A component of the request file path could not be found.');
|
||||
}
|
||||
}
|
||||
|
||||
// This should no longer be needed since we just returned errors for paths not found
|
||||
if ($path !== '/' . $file) {
|
||||
logger("Path mismatch: $path !== /$file");
|
||||
return NULL;
|
||||
}
|
||||
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
|
||||
$prefix = 'DISTINCT ON (filename)';
|
||||
$suffix = 'ORDER BY filename';
|
||||
}
|
||||
else {
|
||||
$prefix = '';
|
||||
$suffix = 'GROUP BY filename';
|
||||
}
|
||||
$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),
|
||||
intval($channel_id)
|
||||
);
|
||||
|
||||
foreach ($r as $rr) {
|
||||
//logger('filename: ' . $rr['filename'], LOGGER_DEBUG);
|
||||
if (intval($rr['is_dir'])) {
|
||||
$ret[] = new Directory($path . '/' . $rr['filename'], $auth);
|
||||
}
|
||||
else {
|
||||
$ret[] = new File($path . '/' . $rr['filename'], $rr, $auth);
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns an array with viewable channels.
|
||||
*
|
||||
* Get a list of Directory objects with all the channels where the visitor
|
||||
* has <b>view_storage</b> perms.
|
||||
*
|
||||
*
|
||||
* @param BasicAuth &$auth
|
||||
* @return array Directory[]
|
||||
*/
|
||||
|
||||
function ChannelList(&$auth) {
|
||||
$ret = array();
|
||||
|
||||
$r = q("SELECT channel_id, channel_address FROM channel WHERE channel_removed = 0
|
||||
AND channel_system = 0 AND NOT (channel_pageflags & %d)>0",
|
||||
intval(PAGE_HIDDEN)
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage')) {
|
||||
logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA);
|
||||
// @todo can't we drop '/cloud'? It gets stripped off anyway in RedDirectory
|
||||
$ret[] = new Directory('/cloud/' . $rr['channel_address'], $auth);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*
|
||||
* @param string $file
|
||||
* path to file or directory
|
||||
* @param BasicAuth &$auth
|
||||
* @param boolean $test (optional) enable test mode
|
||||
* @return File|Directory|boolean|null
|
||||
* @throw \Sabre\DAV\Exception\Forbidden
|
||||
*/
|
||||
|
||||
function FileData($file, &$auth, $test = false) {
|
||||
logger($file . (($test) ? ' (test mode) ' : ''), LOGGER_DATA);
|
||||
|
||||
$x = strpos($file, '/cloud');
|
||||
if ($x === 0) {
|
||||
$file = substr($file, 6);
|
||||
}
|
||||
else {
|
||||
$x = strpos($file,'/dav');
|
||||
if($x === 0)
|
||||
$file = substr($file,4);
|
||||
}
|
||||
|
||||
|
||||
if ((! $file) || ($file === '/')) {
|
||||
return new Directory('/', $auth);
|
||||
}
|
||||
|
||||
$file = trim($file, '/');
|
||||
|
||||
$path_arr = explode('/', $file);
|
||||
|
||||
if (! $path_arr)
|
||||
return null;
|
||||
|
||||
$channel_name = $path_arr[0];
|
||||
|
||||
$r = q("select channel_id from channel where channel_address = '%s' limit 1",
|
||||
dbesc($channel_name)
|
||||
);
|
||||
|
||||
if (! $r)
|
||||
return null;
|
||||
|
||||
$channel_id = $r[0]['channel_id'];
|
||||
|
||||
$path = '/' . $channel_name;
|
||||
|
||||
$auth->owner_id = $channel_id;
|
||||
|
||||
$permission_error = false;
|
||||
|
||||
$folder = '';
|
||||
|
||||
require_once('include/security.php');
|
||||
$perms = permissions_sql($channel_id);
|
||||
|
||||
$errors = false;
|
||||
|
||||
for ($x = 1; $x < count($path_arr); $x++) {
|
||||
$r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 $perms",
|
||||
dbesc($folder),
|
||||
dbesc($path_arr[$x]),
|
||||
intval($channel_id)
|
||||
);
|
||||
|
||||
if ($r && intval($r[0]['is_dir'])) {
|
||||
$folder = $r[0]['hash'];
|
||||
$path = $path . '/' . $r[0]['filename'];
|
||||
}
|
||||
if (! $r) {
|
||||
$r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach
|
||||
where folder = '%s' and filename = '%s' and uid = %d $perms order by filename limit 1",
|
||||
dbesc($folder),
|
||||
dbesc(basename($file)),
|
||||
intval($channel_id)
|
||||
);
|
||||
}
|
||||
if (! $r) {
|
||||
$errors = true;
|
||||
$r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach
|
||||
where folder = '%s' and filename = '%s' and uid = %d order by filename limit 1",
|
||||
dbesc($folder),
|
||||
dbesc(basename($file)),
|
||||
intval($channel_id)
|
||||
);
|
||||
if ($r)
|
||||
$permission_error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($path === '/' . $file) {
|
||||
if ($test)
|
||||
return true;
|
||||
// final component was a directory.
|
||||
return new Directory($file, $auth);
|
||||
}
|
||||
|
||||
if ($errors) {
|
||||
logger('not found ' . $file);
|
||||
if ($test)
|
||||
return false;
|
||||
if ($permission_error) {
|
||||
logger('permission error ' . $file);
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ($r) {
|
||||
if ($test)
|
||||
return true;
|
||||
|
||||
if (intval($r[0]['is_dir'])) {
|
||||
return new Directory($path . '/' . $r[0]['filename'], $auth);
|
||||
}
|
||||
else {
|
||||
return new File($path . '/' . $r[0]['filename'], $r[0], $auth);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -302,11 +302,11 @@ function bb2diaspora_itemwallwall(&$item) {
|
||||
}
|
||||
}
|
||||
|
||||
if(($wallwall) && (is_array($item['author'])) && $item['author']['xchan_url'] && $item['author']['xchan_name'] && $item['author']['xchan_photo_m']) {
|
||||
if(($wallwall) && (is_array($item['author'])) && $item['author']['xchan_url'] && $item['author']['xchan_name'] && $item['author']['xchan_photo_s']) {
|
||||
logger('bb2diaspora_itemwallwall: wall to wall post',LOGGER_DEBUG);
|
||||
// post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author.
|
||||
$item['body'] = "\n\n"
|
||||
. '[img]' . $item['author']['xchan_photo_m'] . '[/img]'
|
||||
. '[img]' . $item['author']['xchan_photo_s'] . '[/img]'
|
||||
. '[url=' . $item['author']['xchan_url'] . ']' . $item['author']['xchan_name'] . '[/url]' . "\n\n"
|
||||
. $item['body'];
|
||||
}
|
||||
|
@ -393,7 +393,7 @@ function get_atom_elements($feed, $item, &$author) {
|
||||
$terms = array();
|
||||
$terms[] = array(
|
||||
'otype' => TERM_OBJ_POST,
|
||||
'type' => TERM_BOOKMARK,
|
||||
'ttype' => TERM_BOOKMARK,
|
||||
'url' => $res['plink'],
|
||||
'term' => $res['title'],
|
||||
);
|
||||
@ -403,7 +403,7 @@ function get_atom_elements($feed, $item, &$author) {
|
||||
$terms = array();
|
||||
$terms[] = array(
|
||||
'otype' => TERM_OBJ_POST,
|
||||
'type' => TERM_BOOKMARK,
|
||||
'ttype' => TERM_BOOKMARK,
|
||||
'url' => $res['plink'],
|
||||
'term' => $res['plink'],
|
||||
);
|
||||
|
@ -449,11 +449,7 @@ function post_activity_item($arr) {
|
||||
call_hooks('post_local_end', $arr);
|
||||
Zotlabs\Daemon\Master::Summon(array('Notifier','activity',$post_id));
|
||||
$ret['success'] = true;
|
||||
$r = q("select * from item where id = %d limit 1",
|
||||
intval($post_id)
|
||||
);
|
||||
if($r)
|
||||
$ret['activity'] = $r[0];
|
||||
$ret['activity'] = $post['item'];
|
||||
}
|
||||
|
||||
return $ret;
|
||||
@ -3290,15 +3286,17 @@ function item_expire($uid,$days) {
|
||||
|
||||
$item_normal = item_normal();
|
||||
|
||||
$r = q("SELECT * FROM `item`
|
||||
WHERE `uid` = %d
|
||||
AND `created` < %s - INTERVAL %s
|
||||
AND `id` = `parent`
|
||||
$sql_extra
|
||||
$r = q("SELECT id FROM item
|
||||
WHERE uid = %d
|
||||
AND created < %s - INTERVAL %s
|
||||
AND item_retained = 0
|
||||
$item_normal LIMIT $expire_limit ",
|
||||
AND item_thread_top = 1
|
||||
AND resource_type = ''
|
||||
AND item_starred = 0
|
||||
$sql_extra $item_normal LIMIT $expire_limit ",
|
||||
intval($uid),
|
||||
db_utcnow(), db_quoteinterval(intval($days).' DAY')
|
||||
db_utcnow(),
|
||||
db_quoteinterval(intval($days).' DAY')
|
||||
);
|
||||
|
||||
if(! $r)
|
||||
@ -3316,17 +3314,6 @@ function item_expire($uid,$days) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only expire posts, not photos and photo comments
|
||||
|
||||
if($item['resource_type'] === 'photo') {
|
||||
retain_item($item['id']);
|
||||
continue;
|
||||
}
|
||||
if(intval($item['item_starred'])) {
|
||||
retain_item($item['id']);
|
||||
continue;
|
||||
}
|
||||
|
||||
drop_item($item['id'],false);
|
||||
}
|
||||
|
||||
|
@ -255,6 +255,19 @@ $powered_by = '';
|
||||
'$pleasewait' => t('Please wait...')
|
||||
));
|
||||
|
||||
|
||||
if(x($_SESSION, 'reload_avatar') && $observer) {
|
||||
// The avatar has been changed on the server but the browser doesn't know that,
|
||||
// force the browser to reload the image from the server instead of its cache.
|
||||
$tpl = get_markup_template('force_image_reload.tpl');
|
||||
|
||||
App::$page['nav'] .= replace_macros($tpl, array(
|
||||
'$imgUrl' => $observer['xchan_photo_m']
|
||||
));
|
||||
unset($_SESSION['reload_avatar']);
|
||||
}
|
||||
|
||||
|
||||
call_hooks('page_header', App::$page['nav']);
|
||||
}
|
||||
|
||||
|
@ -1,299 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @file include/reddav.php
|
||||
* @brief some DAV related functions for Hubzilla.
|
||||
*
|
||||
* This file contains some functions which did not fit into one of the RedDAV
|
||||
* classes.
|
||||
*
|
||||
* The extended SabreDAV classes you will find in the RedDAV namespace under
|
||||
* @ref includes/RedDAV/.
|
||||
* The original SabreDAV classes you can find under @ref vendor/sabre/dav/.
|
||||
* We need to use SabreDAV 1.8.x for PHP5.3 compatibility. SabreDAV >= 2.0
|
||||
* requires PHP >= 5.4.
|
||||
*
|
||||
* @todo split up the classes into own files.
|
||||
*
|
||||
* @link http://github.com/friendica/red
|
||||
* @license http://opensource.org/licenses/mit-license.php The MIT License (MIT)
|
||||
*/
|
||||
|
||||
use Sabre\DAV;
|
||||
use Zotlabs\Storage;
|
||||
|
||||
require_once('vendor/autoload.php');
|
||||
require_once('include/attach.php');
|
||||
|
||||
/**
|
||||
* @brief Returns an array with viewable channels.
|
||||
*
|
||||
* Get a list of RedDirectory objects with all the channels where the visitor
|
||||
* has <b>view_storage</b> perms.
|
||||
*
|
||||
* @todo Is there any reason why this is not inside RedDirectory class?
|
||||
* @fixme function name looks like a class name, should we rename it?
|
||||
*
|
||||
* @param RedBasicAuth &$auth
|
||||
* @return array RedDirectory[]
|
||||
*/
|
||||
function RedChannelList(&$auth) {
|
||||
$ret = array();
|
||||
|
||||
$r = q("SELECT channel_id, channel_address FROM channel WHERE channel_removed = 0 AND channel_system = 0 AND NOT (channel_pageflags & %d)>0",
|
||||
intval(PAGE_HIDDEN)
|
||||
);
|
||||
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage')) {
|
||||
logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA);
|
||||
// @todo can't we drop '/cloud'? It gets stripped off anyway in RedDirectory
|
||||
$ret[] = new Zotlabs\Storage\Directory('/cloud/' . $rr['channel_address'], $auth);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief TODO what exactly does this function?
|
||||
*
|
||||
* Array with all RedDirectory and RedFile DAV\Node items for the given path.
|
||||
*
|
||||
* @todo Is there any reason why this is not inside RedDirectory class? Seems
|
||||
* only to be used there and we could simplify it a bit there.
|
||||
* @fixme function name looks like a class name, should we rename it?
|
||||
*
|
||||
* @param string $file path to a directory
|
||||
* @param RedBasicAuth &$auth
|
||||
* @returns null|array \Sabre\DAV\INode[]
|
||||
* @throw \Sabre\DAV\Exception\Forbidden
|
||||
* @throw \Sabre\DAV\Exception\NotFound
|
||||
*/
|
||||
function RedCollectionData($file, &$auth) {
|
||||
$ret = array();
|
||||
|
||||
$x = strpos($file, '/cloud');
|
||||
if ($x === 0) {
|
||||
$file = substr($file, 6);
|
||||
}
|
||||
|
||||
// return a list of channel if we are not inside a channel
|
||||
if ((! $file) || ($file === '/')) {
|
||||
return RedChannelList($auth);
|
||||
}
|
||||
|
||||
$file = trim($file, '/');
|
||||
$path_arr = explode('/', $file);
|
||||
|
||||
if (! $path_arr)
|
||||
return null;
|
||||
|
||||
$channel_name = $path_arr[0];
|
||||
|
||||
$r = q("SELECT channel_id FROM channel WHERE channel_address = '%s' LIMIT 1",
|
||||
dbesc($channel_name)
|
||||
);
|
||||
|
||||
if (! $r)
|
||||
return null;
|
||||
|
||||
$channel_id = $r[0]['channel_id'];
|
||||
$perms = permissions_sql($channel_id);
|
||||
|
||||
$auth->owner_id = $channel_id;
|
||||
|
||||
$path = '/' . $channel_name;
|
||||
|
||||
$folder = '';
|
||||
$errors = false;
|
||||
$permission_error = false;
|
||||
|
||||
for ($x = 1; $x < count($path_arr); $x++) {
|
||||
$r = q("SELECT id, hash, filename, flags, is_dir FROM attach WHERE folder = '%s' AND filename = '%s' AND uid = %d AND is_dir != 0 $perms LIMIT 1",
|
||||
dbesc($folder),
|
||||
dbesc($path_arr[$x]),
|
||||
intval($channel_id)
|
||||
);
|
||||
if (! $r) {
|
||||
// path wasn't found. Try without permissions to see if it was the result of permissions.
|
||||
$errors = true;
|
||||
$r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 limit 1",
|
||||
dbesc($folder),
|
||||
basename($path_arr[$x]),
|
||||
intval($channel_id)
|
||||
);
|
||||
if ($r) {
|
||||
$permission_error = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ($r && intval($r[0]['is_dir'])) {
|
||||
$folder = $r[0]['hash'];
|
||||
$path = $path . '/' . $r[0]['filename'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($errors) {
|
||||
if ($permission_error) {
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
} else {
|
||||
throw new DAV\Exception\NotFound('A component of the request file path could not be found.');
|
||||
}
|
||||
}
|
||||
|
||||
// This should no longer be needed since we just returned errors for paths not found
|
||||
if ($path !== '/' . $file) {
|
||||
logger("Path mismatch: $path !== /$file");
|
||||
return NULL;
|
||||
}
|
||||
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
|
||||
$prefix = 'DISTINCT ON (filename)';
|
||||
$suffix = 'ORDER BY filename';
|
||||
} else {
|
||||
$prefix = '';
|
||||
$suffix = 'GROUP BY filename';
|
||||
}
|
||||
$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),
|
||||
intval($channel_id)
|
||||
);
|
||||
|
||||
foreach ($r as $rr) {
|
||||
//logger('filename: ' . $rr['filename'], LOGGER_DEBUG);
|
||||
if (intval($rr['is_dir'])) {
|
||||
$ret[] = new Zotlabs\Storage\Directory($path . '/' . $rr['filename'], $auth);
|
||||
} else {
|
||||
$ret[] = new Zotlabs\Storage\File($path . '/' . $rr['filename'], $rr, $auth);
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief TODO What exactly is this function for?
|
||||
*
|
||||
* @fixme function name looks like a class name, should we rename it?
|
||||
*
|
||||
* @param string $file
|
||||
* path to file or directory
|
||||
* @param RedBasicAuth &$auth
|
||||
* @param boolean $test (optional) enable test mode
|
||||
* @return RedFile|RedDirectory|boolean|null
|
||||
* @throw \Sabre\DAV\Exception\Forbidden
|
||||
*/
|
||||
function RedFileData($file, &$auth, $test = false) {
|
||||
logger($file . (($test) ? ' (test mode) ' : ''), LOGGER_DATA);
|
||||
|
||||
$x = strpos($file, '/cloud');
|
||||
if ($x === 0) {
|
||||
$file = substr($file, 6);
|
||||
}
|
||||
else {
|
||||
$x = strpos($file,'/dav');
|
||||
if($x === 0)
|
||||
$file = substr($file,4);
|
||||
}
|
||||
|
||||
|
||||
if ((! $file) || ($file === '/')) {
|
||||
return new Zotlabs\Storage\Directory('/', $auth);
|
||||
}
|
||||
|
||||
$file = trim($file, '/');
|
||||
|
||||
$path_arr = explode('/', $file);
|
||||
|
||||
if (! $path_arr)
|
||||
return null;
|
||||
|
||||
$channel_name = $path_arr[0];
|
||||
|
||||
$r = q("select channel_id from channel where channel_address = '%s' limit 1",
|
||||
dbesc($channel_name)
|
||||
);
|
||||
|
||||
if (! $r)
|
||||
return null;
|
||||
|
||||
$channel_id = $r[0]['channel_id'];
|
||||
|
||||
$path = '/' . $channel_name;
|
||||
|
||||
$auth->owner_id = $channel_id;
|
||||
|
||||
$permission_error = false;
|
||||
|
||||
$folder = '';
|
||||
|
||||
require_once('include/security.php');
|
||||
$perms = permissions_sql($channel_id);
|
||||
|
||||
$errors = false;
|
||||
|
||||
for ($x = 1; $x < count($path_arr); $x++) {
|
||||
$r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 $perms",
|
||||
dbesc($folder),
|
||||
dbesc($path_arr[$x]),
|
||||
intval($channel_id)
|
||||
);
|
||||
|
||||
if ($r && intval($r[0]['is_dir'])) {
|
||||
$folder = $r[0]['hash'];
|
||||
$path = $path . '/' . $r[0]['filename'];
|
||||
}
|
||||
if (! $r) {
|
||||
$r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach
|
||||
where folder = '%s' and filename = '%s' and uid = %d $perms order by filename limit 1",
|
||||
dbesc($folder),
|
||||
dbesc(basename($file)),
|
||||
intval($channel_id)
|
||||
);
|
||||
}
|
||||
if (! $r) {
|
||||
$errors = true;
|
||||
$r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach
|
||||
where folder = '%s' and filename = '%s' and uid = %d order by filename limit 1",
|
||||
dbesc($folder),
|
||||
dbesc(basename($file)),
|
||||
intval($channel_id)
|
||||
);
|
||||
if ($r)
|
||||
$permission_error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($path === '/' . $file) {
|
||||
if ($test)
|
||||
return true;
|
||||
// final component was a directory.
|
||||
return new Zotlabs\Storage\Directory($file, $auth);
|
||||
}
|
||||
|
||||
if ($errors) {
|
||||
logger('not found ' . $file);
|
||||
if ($test)
|
||||
return false;
|
||||
if ($permission_error) {
|
||||
logger('permission error ' . $file);
|
||||
throw new DAV\Exception\Forbidden('Permission denied.');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ($r) {
|
||||
if ($test)
|
||||
return true;
|
||||
|
||||
if (intval($r[0]['is_dir'])) {
|
||||
return new Zotlabs\Storage\Directory($path . '/' . $r[0]['filename'], $auth);
|
||||
} else {
|
||||
return new Zotlabs\Storage\File($path . '/' . $r[0]['filename'], $r[0], $auth);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
<?php /** @file */
|
||||
|
||||
|
||||
function string_splitter($s) {
|
||||
|
||||
if(! $s)
|
||||
return array();
|
||||
|
||||
$s = preg_replace('/\pP+/','',$s);
|
||||
|
||||
$x = mb_split("\[|\]|\s",$s);
|
||||
|
||||
$ret = array();
|
||||
if($x) {
|
||||
foreach($x as $y) {
|
||||
if(mb_strlen($y) > 2)
|
||||
$ret[] = substr($y,0,64);
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function get_words($uid,$list) {
|
||||
|
||||
stringify($list,true);
|
||||
|
||||
$r = q("select * from spam where term in ( " . $list . ") and uid = %d",
|
||||
intval($uid)
|
||||
);
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
@ -2354,7 +2354,13 @@ function handle_tag($a, &$body, &$access_tag, &$str_tags, $profile_uid, $tag, $d
|
||||
|
||||
$str_tags .= $newtag;
|
||||
}
|
||||
return array('replaced' => $replaced, 'termtype' => $termtype, 'term' => $basetag, 'url' => $url, 'contact' => $r[0]);
|
||||
return [
|
||||
'replaced' => $replaced,
|
||||
'termtype' => $termtype,
|
||||
'term' => $basetag,
|
||||
'url' => $url,
|
||||
'contact' => $r[0]
|
||||
];
|
||||
}
|
||||
|
||||
//is it a person tag?
|
||||
@ -2545,7 +2551,13 @@ function handle_tag($a, &$body, &$access_tag, &$str_tags, $profile_uid, $tag, $d
|
||||
}
|
||||
}
|
||||
|
||||
return array('replaced' => $replaced, 'termtype' => $termtype, 'term' => $newname, 'url' => $url, 'contact' => $r[0]);
|
||||
return [
|
||||
'replaced' => $replaced,
|
||||
'termtype' => $termtype,
|
||||
'term' => $newname,
|
||||
'url' => $url,
|
||||
'contact' => $r[0]
|
||||
];
|
||||
}
|
||||
|
||||
function linkify_tags($a, &$body, $uid, $diaspora = false) {
|
||||
|
@ -1347,7 +1347,7 @@ function widget_forums($arr) {
|
||||
|
||||
$perms_sql = item_permissions_sql(local_channel()) . item_normal();
|
||||
|
||||
$r1 = q("select * from abook left join xchan on abook_xchan = xchan_hash where ( xchan_pubforum = 1 or ((abook_their_perms & %d ) != 0 and (abook_their_perms & %d ) = 0) ) and xchan_deleted = 0 and abook_channel = %d order by xchan_name $limit ",
|
||||
$r1 = q("select abook_id, xchan_hash, xchan_name, xchan_url, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash where ( xchan_pubforum = 1 or ((abook_their_perms & %d ) != 0 and (abook_their_perms & %d ) = 0) ) and xchan_deleted = 0 and abook_channel = %d order by xchan_name $limit ",
|
||||
intval(PERMS_W_TAGWALL),
|
||||
intval(PERMS_W_STREAM),
|
||||
intval(local_channel())
|
||||
@ -1361,12 +1361,34 @@ function widget_forums($arr) {
|
||||
// There also should be a way to update this via ajax.
|
||||
|
||||
for($x = 0; $x < count($r1); $x ++) {
|
||||
$r = q("select sum(item_unseen) as unseen from item where owner_xchan = '%s' and uid = %d $perms_sql ",
|
||||
$r = q("select sum(item_unseen) as unseen from item where owner_xchan = '%s' and uid = %d and item_unseen = 1 $perms_sql ",
|
||||
dbesc($r1[$x]['xchan_hash']),
|
||||
intval(local_channel())
|
||||
);
|
||||
if($r)
|
||||
$r1[$x]['unseen'] = $r[0]['unseen'];
|
||||
|
||||
/**
|
||||
* @FIXME
|
||||
* This SQL makes the counts correct when you get forum posts arriving from different routes/sources
|
||||
* (like personal channels). However the network query for these posts doesn't yet include this
|
||||
* correction and it makes the SQL for that query pretty hairy so this is left as a future exercise.
|
||||
* It may make more sense in that query to look for the mention in the body rather than another join,
|
||||
* but that makes it very inefficient.
|
||||
*
|
||||
$r = q("select sum(item_unseen) as unseen from item left join term on oid = id where otype = %d and owner_xchan != '%s' and item.uid = %d and url = '%s' and ttype = %d $perms_sql ",
|
||||
intval(TERM_OBJ_POST),
|
||||
dbesc($r1[$x]['xchan_hash']),
|
||||
intval(local_channel()),
|
||||
dbesc($r1[$x]['xchan_url']),
|
||||
intval(TERM_MENTION)
|
||||
);
|
||||
if($r)
|
||||
$r1[$x]['unseen'] = ((array_key_exists('unseen',$r1[$x])) ? $r1[$x]['unseen'] + $r[0]['unseen'] : $r[0]['unseen']);
|
||||
*
|
||||
* end @FIXME
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
if($r1) {
|
||||
|
3259
util/hmessages.po
3259
util/hmessages.po
File diff suppressed because it is too large
Load Diff
@ -56,13 +56,13 @@ $(document).ready(function() {
|
||||
function makeFullScreen(full) {
|
||||
if(typeof full=='undefined' || full == true) {
|
||||
$('main').css({'transition': 'none'}).addClass('fullscreen');
|
||||
$('#fullscreen-btn, header, nav, aside').css({'display': 'none'});
|
||||
$('#fullscreen-btn, header, nav, aside, #tabs-collapse-1').css({'visibility': 'hidden'});
|
||||
$('#inline-btn').show();
|
||||
|
||||
}
|
||||
else {
|
||||
$('main').removeClass('fullscreen');
|
||||
$('#fullscreen-btn, header, nav, aside').css({'display': ''});
|
||||
$('#fullscreen-btn, header, nav, aside, #tabs-collapse-1').css({'visibility': ''});
|
||||
$('#inline-btn').hide();
|
||||
$('main').css({'transition': ''});
|
||||
}
|
||||
|
@ -1,7 +1,14 @@
|
||||
<div class="generic-content-wrapper">
|
||||
<div class="section-title-wrapper">
|
||||
{{if $table == 'item'}}
|
||||
<a href="dreport/push/{{$mid}}"><button class="btn btn-default btn-xs pull-right">{{$push}}</button></a>
|
||||
<div class="dropdown pull-right">
|
||||
<button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" title="{{$options}}">
|
||||
<i class="fa fa-sort-desc"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="dreport/push/{{$mid}}">{{$push}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{{/if}}
|
||||
<h2>{{$title}}</h2>
|
||||
</div>
|
||||
|
72
view/tpl/force_image_reload.tpl
Normal file
72
view/tpl/force_image_reload.tpl
Normal file
@ -0,0 +1,72 @@
|
||||
{{*
|
||||
Force the browser to reload an image from the server instead of the cache.
|
||||
based on an answer from http://stackoverflow.com/a/22429796/3343347
|
||||
|
||||
Usage: Set $imgUrl to the src url you want to be re-fetched from the server
|
||||
|
||||
*}}
|
||||
|
||||
<script>
|
||||
$(document).ready(
|
||||
function() {
|
||||
forceImgReload("{{$imgUrl}}");
|
||||
}
|
||||
);
|
||||
|
||||
{{*
|
||||
* find and return any existing img tags with a matching src url, and set them to an intermediate
|
||||
* src url so they can later be reverted back once the cached version has been updated.
|
||||
*}}
|
||||
function prepareImagesForReload(srcUrl) {
|
||||
|
||||
var result = $("img[src='" + srcUrl + "']").get();
|
||||
|
||||
for (i = 0; i < result.length; i++) {
|
||||
{{*
|
||||
* Set the image to a reloading image, in this case an animated "reloading" svg
|
||||
* Ideally this wont be displayed long enough to matter.
|
||||
*}}
|
||||
result[i].src = "data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' preserveAspectRatio='xMidYMid' class='uil-reload'%3E%3Cpath fill='none' class='bk' d='M0 0h100v100H0z'/%3E%3Cg%3E%3Cpath d='M50 15a35 35 0 1 0 24.787 10.213' fill='none' stroke='%23777' stroke-width='12'/%3E%3Cpath d='M50 0v30l16-15L50 0' fill='%23777'/%3E%3CanimateTransform attributeName='transform' type='rotate' from='0 50 50' to='360 50 50' dur='1s' repeatCount='indefinite'/%3E%3C/g%3E%3C/svg%3E";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function restoreImages(srcUrl, imgList) {
|
||||
|
||||
for (i = 0; i < imgList.length; i++) {
|
||||
imgList[i].src = srcUrl;
|
||||
}
|
||||
}
|
||||
|
||||
function forceImgReload(srcUrl) {
|
||||
var imgList;
|
||||
var step = 0;
|
||||
var iframe = window.document.createElement("iframe"); // Hidden iframe, in which to perform the load+reload.
|
||||
|
||||
{{* Callback function, called after iframe load+reload completes (or fails).
|
||||
Will be called TWICE unless twostage-mode process is cancelled. (Once after load, once after reload). *}}
|
||||
var iframeLoadCallback = function(e) {
|
||||
|
||||
if (step === 0) {
|
||||
// initial load just completed. Note that it doesn't actually matter if this load succeeded or not.
|
||||
|
||||
step = 1;
|
||||
imgList = prepareImagesForReload(srcUrl);
|
||||
iframe.contentWindow.location.reload(true); // initiate forced-reload!
|
||||
|
||||
} else if (step === 1) {
|
||||
// forced re-load is done
|
||||
|
||||
restoreImages(srcUrl, imgList);
|
||||
if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
|
||||
}
|
||||
}
|
||||
|
||||
iframe.style.display = "none";
|
||||
window.parent.document.body.appendChild(iframe); {{* NOTE: if this is done AFTER setting src, Firefox MAY fail to fire the load event! *}}
|
||||
iframe.addEventListener("load", iframeLoadCallback, false);
|
||||
iframe.addEventListener("error", iframeLoadCallback, false);
|
||||
iframe.src = srcUrl;
|
||||
}
|
||||
</script>
|
Reference in New Issue
Block a user