Merge branch '1.10RC'

This commit is contained in:
redmatrix 2016-07-28 19:58:05 -07:00
commit ae5c10a71c
527 changed files with 82356 additions and 51275 deletions

View File

@ -1,3 +1,44 @@
Hubzilla 1.10
Wiki:
Lots of enhanced functionality, usability improvements, and bugfixes from v1.8
Turned into an optional feature (default on) but disabled in UNO
Sync:
Items are now relocated (links patched) when syncing to clones
Access Tokens:
New feature - allows members to create access controlled guest logins and create/share 'dropbox' style links to protected resources.
UI:
Use icons instead of iconic text constructs
Only request geolocation permission when creating a post, not on page load
provide 'redeliver' option on Delivery Report page for when things really stuff up
CalDAV/CardDAV management pages with heaps of functionality
Lib:
z_fetch_url() updated to accept different request methods and request bodies
item_store(), item_store_update() now return the stored items
vcard microformat changes to remain spec compliant
microformat meta tags added to post/comments
AbConfig API changed to use channel_id rather than channel_hash, which was overly complicated to use
SuperCurl class added to provide a framework for re-use of obscure CURL options
Allow absolute links to CSS/JS files on CDN
Add Let'sEncrypt intermediate cert to lib in case you forget to install it on the server
Update fullcalendar and jquery (3.1) libs
Update sabre/dav to 3.2.0
Change content export from a month/year system to begin/end
Use streaming I/O for delivering large photos
Allow multiple App description files in a single plugin directory
optimise a couple of troublesome/inefficient SQL queries
avoid sending clone sync packets to dead sites
Resolved Issues:
channel home page not providing content to clients with javascript disabled
Replace '@' obfuscation with html entity rather than the unicode look-alike
xchan_query() failing to detect duplicates, resulting in inefficient queries
issues with 'use existing photo' for profile photo
layout editor "list all layouts" returned empty
oembed - better detect video file URLs so they aren't loaded into memory.
handcrafted bbcode tables could end up with way too much whitespace due to CRLF translation
refresh permissions whitescreen in 1.8
force immediate profile photo update on local site
regression: 'save bookmarks' post action missing
Hubzilla 1.8 Hubzilla 1.8
Administration: Administration:
Cleanup and resolve some edge cases with addon repository manager Cleanup and resolve some edge cases with addon repository manager

View File

@ -47,4 +47,16 @@ Possible website applications include
<em><a href="https://github.com/redmatrix/hubzilla/blob/master/install/INSTALL.txt">Installing Hubzilla</a></em> <em><a href="https://github.com/redmatrix/hubzilla/blob/master/install/INSTALL.txt">Installing Hubzilla</a></em>
</p> </p>
**Who Are We and What Are Our Principles?**
The Hubzilla community is powered by passionate volunteers creating an open source **commons** of decentralised services which are highly integrated and can rival the feature set of centralised providers. We are open to sponsorship and donations to cover expenses and compensate for our time and energy, however the project core is basically non-profit and is not designed for the purpose of commercial gain or exploitation.
Some sites may include monetisation strategies such as subscriptions and *freemium* models where members pay for resources they consume beyond a basic level. The project community supports such monetisation initiatives (nobody should be forced to pay "out of pocket" to provide a service to others), but we maintain the **commons** to provide open and free access of the software to all.
The software is not designed for data collection of its members or providing advertising. We don't have a need or desire for these things and feel that software built around these goals is poorly designed and represents compromised principles and ethics.
As a project, we are inclusive of all beliefs and cultures and do what we are able to provide an environment that is free from hostility and harrassment. Whether or not we succeed in this endaevour requires constant vigilance and help from all members of the community, working together to build an inter-networking tool with amazing potential.
[![Build Status](https://travis-ci.org/redmatrix/hubzilla.svg)](https://travis-ci.org/redmatrix/hubzilla) [![Build Status](https://travis-ci.org/redmatrix/hubzilla.svg)](https://travis-ci.org/redmatrix/hubzilla)

View File

@ -41,7 +41,6 @@ class Cron {
require_once('include/sharedwithme.php'); require_once('include/sharedwithme.php');
apply_updates(); apply_updates();
// expire any expired mail // expire any expired mail
q("delete from mail where expires != '%s' and expires < %s ", q("delete from mail where expires != '%s' and expires < %s ",
@ -63,6 +62,15 @@ class Cron {
} }
// delete expired access tokens
q("delete from atoken where atoken_expires != '%s' && atoken_expires < %s",
dbesc(NULL_DATE),
db_utcnow()
);
// Ensure that every channel pings a directory server once a month. This way we can discover // Ensure that every channel pings a directory server once a month. This way we can discover
// channels and sites that quietly vanished and prevent the directory from accumulating stale // channels and sites that quietly vanished and prevent the directory from accumulating stale
// or dead entries. // or dead entries.
@ -93,6 +101,18 @@ class Cron {
intval($rr['id']) intval($rr['id'])
); );
if($x) { if($x) {
$z = q("select * from item where id = %d",
intval($message_id)
);
if($z) {
xchan_query($z);
$sync_item = fetch_post_tags($z);
build_sync_packet($sync_item[0]['uid'],
[
'item' => [ encode_item($sync_item[0],true) ]
]
);
}
Master::Summon(array('Notifier','wall-new',$rr['id'])); Master::Summon(array('Notifier','wall-new',$rr['id']));
} }
} }

View File

@ -15,7 +15,6 @@ class Cron_weekly {
call_hooks('cron_weekly',datetime_convert()); call_hooks('cron_weekly',datetime_convert());
z_check_cert(); z_check_cert();
require_once('include/hubloc.php'); require_once('include/hubloc.php');

View File

@ -0,0 +1,55 @@
<?php
namespace Zotlabs\Daemon;
// generate a curl compatible cookie file with an authenticated session for the given channel_id.
// If this file is then used with curl and the destination url is sent through zid() or manually
// manipulated to add a zid, it should allow curl to provide zot magic-auth across domains.
// Handles expiration of stale cookies currently by deleting them and rewriting the file.
class CurlAuth {
static public function run($argc,$argv) {
if($argc != 2)
killme();
\App::$session->start();
$_SESSION['authenticated'] = 1;
$_SESSION['uid'] = $argv[1];
$x = session_id();
$f = 'store/[data]/cookie_' . $argv[1];
$c = 'store/[data]/cookien_' . $argv[1];
$e = file_exists($f);
$output = '';
if($e) {
$lines = file($f);
if($lines) {
foreach($lines as $line) {
if(strlen($line) > 0 && $line[0] != '#' && substr_count($line, "\t") == 6) {
$tokens = explode("\t", $line);
$tokens = array_map('trim', $tokens);
if($tokens[4] > time()) {
$output .= $line . "\n";
}
}
else
$output .= $line;
}
}
}
$t = time() + (24 * 3600);
file_put_contents($f, $output . 'HttpOnly_' . \App::get_hostname() . "\tFALSE\t/\tTRUE\t$t\tPHPSESSID\t" . $x, (($e) ? FILE_APPEND : 0));
file_put_contents($c,$x);
killme();
}
}

View File

@ -38,7 +38,7 @@ class Expire {
logger('site_expire: ' . $site_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) { if ($r) {
foreach ($r as $rr) { foreach ($r as $rr) {

43
Zotlabs/Daemon/README.md Normal file
View File

@ -0,0 +1,43 @@
Daemon (background) Processes
=============================
This directory provides background tasks which are executed by a
command-line process and detached from normal web processing.
Background tasks are invoked by calling
Zotlabs\Daemon\Master::Summon([ $cmd, $arg1, $argn... ]);
The Master class loads the desired command file and passes the arguments.
To create a background task 'Foo' use the following template.
<?php
namespace Zotlabs\Daemon;
class Foo {
static public function run($argc,$argv) {
// do something
}
}
The Master class "summons" the command by creating an executable script
from the provided arguments, then it invokes "Release" to execute the script
detached from web processing. This process calls the static::run() function
with any command line arguments using the traditional argc, argv format.
Please note: These are *real* $argc, $argv variables passed from the command
line, and not the parsed argc() and argv() functions/variables which were
obtained from parsing path components of the request URL by web processes.
Background processes do not emit displayable output except through logs. They
should also not make any assumptions about their HTML and web environment
(as they do not have a web environment), particularly with respect to global
variables such as $_SERVER, $_REQUEST, $_GET, $_POST, $_COOKIES, and $_SESSION.

View File

@ -5,18 +5,20 @@ namespace Zotlabs\Lib;
class AbConfig { class AbConfig {
static public function Load($chash,$xhash) { static public function Load($chan,$xhash,$family = '') {
$r = q("select * from abconfig where chan = '%s' and xchan = '%s'", if($family)
dbesc($chash), $where = sprintf(" and family = '%s' ",dbesc($family));
$r = q("select * from abconfig where chan = %d and xchan = '%s' $where",
intval($chan),
dbesc($xhash) dbesc($xhash)
); );
return $r; return $r;
} }
static public function Get($chash,$xhash,$family,$key) { static public function Get($chan,$xhash,$family,$key) {
$r = q("select * from abconfig where chan = '%s' and xchan = '%s' and cat = '%s' and k = '%s' limit 1", $r = q("select * from abconfig where chan = %d and xchan = '%s' and cat = '%s' and k = '%s' limit 1",
dbesc($chash), intval($chan),
dbesc($xhash), dbesc($xhash),
dbesc($family), dbesc($family),
dbesc($key) dbesc($key)
@ -28,14 +30,14 @@ class AbConfig {
} }
static public function Set($chash,$xhash,$family,$key,$value) { static public function Set($chan,$xhash,$family,$key,$value) {
$dbvalue = ((is_array($value)) ? serialize($value) : $value); $dbvalue = ((is_array($value)) ? serialize($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue); $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
if(self::Get($chash,$xhash,$family,$key) === false) { if(self::Get($chan,$xhash,$family,$key) === false) {
$r = q("insert into abconfig ( chan, xchan, cat, k, v ) values ( '%s', '%s', '%s', '%s', '%s' ) ", $r = q("insert into abconfig ( chan, xchan, cat, k, v ) values ( %d, '%s', '%s', '%s', '%s' ) ",
dbesc($chash), intval($chan),
dbesc($xhash), dbesc($xhash),
dbesc($family), dbesc($family),
dbesc($key), dbesc($key),
@ -43,9 +45,9 @@ class AbConfig {
); );
} }
else { else {
$r = q("update abconfig set v = '%s' where chan = '%s' and xchan = '%s' and cat = '%s' and k = '%s' ", $r = q("update abconfig set v = '%s' where chan = %d and xchan = '%s' and cat = '%s' and k = '%s' ",
dbesc($dbvalue), dbesc($dbvalue),
dbesc($chash), dbesc($chan),
dbesc($xhash), dbesc($xhash),
dbesc($family), dbesc($family),
dbesc($key) dbesc($key)
@ -58,10 +60,10 @@ class AbConfig {
} }
static public function Delete($chash,$xhash,$family,$key) { static public function Delete($chan,$xhash,$family,$key) {
$r = q("delete from abconfig where chan = '%s' and xchan = '%s' and cat = '%s' and k = '%s' ", $r = q("delete from abconfig where chan = %d and xchan = '%s' and cat = '%s' and k = '%s' ",
dbesc($chash), intval($chan),
dbesc($xhash), dbesc($xhash),
dbesc($family), dbesc($family),
dbesc($key) dbesc($key)

View File

@ -33,8 +33,9 @@ class Apps {
$files = glob('addon/*/*.apd'); $files = glob('addon/*/*.apd');
if($files) { if($files) {
foreach($files as $f) { foreach($files as $f) {
$n = basename($f,'.apd'); $path = explode('/',$f);
if(plugin_is_installed($n)) { $plugin = $path[1];
if(plugin_is_installed($plugin)) {
$x = self::parse_app_description($f,$translate); $x = self::parse_app_description($f,$translate);
if($x) { if($x) {
$ret[] = $x; $ret[] = $x;

46
Zotlabs/Lib/Cache.php Normal file
View File

@ -0,0 +1,46 @@
<?php /** @file */
namespace Zotlabs\Lib;
/**
* cache api
*/
class Cache {
public static function get($key) {
$r = q("SELECT v FROM cache WHERE k = '%s' limit 1",
dbesc($key)
);
if ($r)
return $r[0]['v'];
return null;
}
public static function set($key,$value) {
$r = q("SELECT * FROM cache WHERE k = '%s' limit 1",
dbesc($key)
);
if($r) {
q("UPDATE cache SET v = '%s', updated = '%s' WHERE k = '%s'",
dbesc($value),
dbesc(datetime_convert()),
dbesc($key));
}
else {
q("INSERT INTO cache ( k, v, updated) VALUES ('%s','%s','%s')",
dbesc($key),
dbesc($value),
dbesc(datetime_convert()));
}
}
public static function clear() {
q("DELETE FROM cache WHERE updated < '%s'",
dbesc(datetime_convert('UTC','UTC',"now - 30 days")));
}
}

View File

@ -1,6 +1,6 @@
<?php <?php
if(class_exists('PermissionDescription')) return; namespace Zotlabs\Lib;
require_once("include/permissions.php"); require_once("include/permissions.php");
require_once("include/language.php"); require_once("include/language.php");

127
Zotlabs/Lib/SuperCurl.php Normal file
View File

@ -0,0 +1,127 @@
<?php
namespace Zotlabs\Lib;
/**
* @brief wrapper for z_fetch_url() which can be instantiated with several built-in parameters and
* these can be modified and re-used. Useful for CalDAV and other processes which need to authenticate
* and set lots of CURL options (many of which stay the same from one call to the next).
*/
class SuperCurl {
private $auth;
private $url;
private $curlopt = array();
private $headers = null;
public $filepos = 0;
public $filehandle = 0;
public $request_data = '';
private $request_method = 'GET';
private $upload = false;
private $cookies = false;
private function set_data($s) {
$this->request_data = $s;
$this->filepos = 0;
}
public function curl_read($ch,$fh,$size) {
if($this->filepos < 0) {
unset($fh);
return '';
}
$s = substr($this->request_data,$this->filepos,$size);
if(strlen($s) < $size)
$this->filepos = (-1);
else
$this->filepos = $this->filepos + $size;
return $s;
}
public function __construct($opts = array()) {
$this->set($opts);
}
private function set($opts = array()) {
if($opts) {
foreach($opts as $k => $v) {
switch($k) {
case 'http_auth':
$this->auth = $v;
break;
case 'magicauth':
// currently experimental
$this->magicauth = $v;
\Zotlabs\Daemon\Master::Summon([ 'CurlAuth', $v ]);
break;
case 'custom':
$this->request_method = $v;
break;
case 'url':
$this->url = $v;
break;
case 'data':
$this->set_data($v);
if($v) {
$this->upload = true;
}
else {
$this->upload = false;
}
break;
case 'headers':
$this->headers = $v;
break;
default:
$this->curlopts[$k] = $v;
break;
}
}
}
}
function exec() {
$opts = $this->curlopts;
$url = $this->url;
if($this->auth)
$opts['http_auth'] = $this->auth;
if($this->magicauth) {
$opts['cookiejar'] = 'store/[data]/cookie_' . $this->magicauth;
$opts['cookiefile'] = 'store/[data]/cookie_' . $this->magicauth;
$opts['cookie'] = 'PHPSESSID=' . trim(file_get_contents('store/[data]/cookien_' . $this->magicauth));
$c = channelx_by_n($this->magicauth);
if($c)
$url = zid($this->url,$c['channel_address'] . '@' . \App::get_hostname());
}
if($this->custom)
$opts['custom'] = $this->custom;
if($this->headers)
$opts['headers'] = $this->headers;
if($this->upload) {
$opts['upload'] = true;
$opts['infile'] = $this->filehandle;
$opts['infilesize'] = strlen($this->request_data);
$opts['readfunc'] = [ $this, 'curl_read' ] ;
}
$recurse = 0;
return z_fetch_url($this->url,true,$recurse,(($opts) ? $opts : null));
}
}

View File

@ -248,7 +248,7 @@ class ThreadItem {
$has_bookmarks = false; $has_bookmarks = false;
if(is_array($item['term'])) { if(is_array($item['term'])) {
foreach($item['term'] as $t) { foreach($item['term'] as $t) {
if(!UNO && $t['type'] == TERM_BOOKMARK) if(!UNO && $t['ttype'] == TERM_BOOKMARK)
$has_bookmarks = true; $has_bookmarks = true;
} }
} }
@ -418,7 +418,7 @@ class ThreadItem {
if(($nb_children > $visible_comments) || ($thread_level > 1)) { if(($nb_children > $visible_comments) || ($thread_level > 1)) {
$result['children'][0]['comment_firstcollapsed'] = true; $result['children'][0]['comment_firstcollapsed'] = true;
$result['children'][0]['num_comments'] = $comment_count_txt; $result['children'][0]['num_comments'] = $comment_count_txt;
$result['children'][0]['hide_text'] = t('[+] show all'); $result['children'][0]['hide_text'] = sprintf( t('%s show all'), '<i class="fa fa-chevron-down"></i>');
if($thread_level > 1) { if($thread_level > 1) {
$result['children'][$nb_children - 1]['comment_lastcollapsed'] = true; $result['children'][$nb_children - 1]['comment_lastcollapsed'] = true;
} }

View File

@ -18,7 +18,7 @@ class Achievements extends \Zotlabs\Web\Controller {
$profile = 0; $profile = 0;
$profile = argv(1); $profile = argv(1);
profile_load($a,$which,$profile); profile_load($which,$profile);
$r = q("select channel_id from channel where channel_address = '%s'", $r = q("select channel_id from channel where channel_address = '%s'",
dbesc($which) dbesc($which)

View File

@ -1,7 +1,18 @@
<?php <?php
namespace Zotlabs\Module; namespace Zotlabs\Module;
/* ACL selector json backend */ /*
* ACL selector json backend
* This module provides JSON lists of connections and local/remote channels
* (xchans) to populate various tools such as the ACL (AccessControlList) popup
* and various auto-complete functions (such as email recipients, search, and
* mention targets.
* There are two primary output structural formats. One for the ACL widget and
* the other for auto-completion.
* Many of the behaviour variations are triggered on the use of single character keys
* however this functionality has grown in an ad-hoc manner and has gotten quite messy over time.
*/
require_once("include/acl_selectors.php"); require_once("include/acl_selectors.php");
require_once("include/group.php"); require_once("include/group.php");
@ -10,40 +21,63 @@ class Acl extends \Zotlabs\Web\Controller {
function init(){ function init(){
// logger('mod_acl: ' . print_r($_REQUEST,true)); // logger('mod_acl: ' . print_r($_REQUEST,true));
$start = (x($_REQUEST,'start')?$_REQUEST['start']:0); $start = (x($_REQUEST,'start') ? $_REQUEST['start'] : 0);
$count = (x($_REQUEST,'count')?$_REQUEST['count']:100); $count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 500);
$search = (x($_REQUEST,'search')?$_REQUEST['search']:""); $search = (x($_REQUEST,'search') ? $_REQUEST['search'] : '');
$type = (x($_REQUEST,'type')?$_REQUEST['type']:""); $type = (x($_REQUEST,'type') ? $_REQUEST['type'] : '');
$noforums = (x($_REQUEST,'n') ? $_REQUEST['n'] : false); $noforums = (x($_REQUEST,'n') ? $_REQUEST['n'] : false);
// $type =
// '' => standard ACL request
// 'g' => Groups only ACL request
// 'c' => Connections only ACL request or editor (textarea) mention request
// $_REQUEST['search'] contains ACL search text.
// $type =
// 'm' => autocomplete private mail recipient (checks post_mail permission)
// 'a' => autocomplete connections (mod_connections, mod_poke, mod_sources, mod_photos)
// 'x' => nav search bar autocomplete (match any xchan)
// $_REQUEST['query'] contains autocomplete search text.
// List of channels whose connections to also suggest,
// e.g. currently viewed channel or channels mentioned in a post
// List of channels whose connections to also suggest, e.g. currently viewed channel or channels mentioned in a post
$extra_channels = (x($_REQUEST,'extra_channels') ? $_REQUEST['extra_channels'] : array()); $extra_channels = (x($_REQUEST,'extra_channels') ? $_REQUEST['extra_channels'] : array());
// For use with jquery.autocomplete for private mail completion // The different autocomplete libraries use different names for the search text
// parameter. Internaly we'll use $search to represent the search text no matter
// what request variable it was attached to.
if(x($_REQUEST,'query') && strlen($_REQUEST['query'])) { if(array_key_exists('query',$_REQUEST)) {
if(! $type)
$type = 'm';
$search = $_REQUEST['query']; $search = $_REQUEST['query'];
} }
if(!(local_channel())) if( (! local_channel()) && (! ($type == 'x' || $type == 'c')))
if(!($type == 'x' || $type == 'c')) killme();
killme();
if ($search != "") { if($search) {
$sql_extra = " AND `name` LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " "; $sql_extra = " AND `name` LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ";
$sql_extra2 = "AND ( xchan_name LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR xchan_addr LIKE " . protect_sprintf( "'%" . dbesc($search) . ((strpos($search,'@') === false) ? "%@%'" : "%'")) . ") "; $sql_extra2 = "AND ( xchan_name LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR xchan_addr LIKE " . protect_sprintf( "'%" . dbesc($search) . ((strpos($search,'@') === false) ? "%@%'" : "%'")) . ") ";
// This horrible mess is needed because position also returns 0 if nothing is found. W/ould be MUCH easier if it instead returned a very large value // This horrible mess is needed because position also returns 0 if nothing is found.
// Otherwise we could just order by LEAST(POSITION($search IN xchan_name),POSITION($search IN xchan_addr)). // Would be MUCH easier if it instead returned a very large value
$order_extra2 = "CASE WHEN xchan_name LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) ." then POSITION('".dbesc($search)."' IN xchan_name) else position('".dbesc($search)."' IN xchan_addr) end, "; // Otherwise we could just
// order by LEAST(POSITION($search IN xchan_name),POSITION($search IN xchan_addr)).
$order_extra2 = "CASE WHEN xchan_name LIKE "
. protect_sprintf( "'%" . dbesc($search) . "%'" )
. " then POSITION('" . dbesc($search)
. "' IN xchan_name) else position('" . dbesc($search) . "' IN xchan_addr) end, ";
$col = ((strpos($search,'@') !== false) ? 'xchan_addr' : 'xchan_name' ); $col = ((strpos($search,'@') !== false) ? 'xchan_addr' : 'xchan_name' );
$sql_extra3 = "AND $col like " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " "; $sql_extra3 = "AND $col like " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ";
} else { }
else {
$sql_extra = $sql_extra2 = $sql_extra3 = ""; $sql_extra = $sql_extra2 = $sql_extra3 = "";
} }
@ -51,7 +85,7 @@ class Acl extends \Zotlabs\Web\Controller {
$groups = array(); $groups = array();
$contacts = array(); $contacts = array();
if ($type=='' || $type=='g'){ if($type == '' || $type == 'g') {
$r = q("SELECT `groups`.`id`, `groups`.`hash`, `groups`.`gname` $r = q("SELECT `groups`.`id`, `groups`.`hash`, `groups`.`gname`
FROM `groups`,`group_member` FROM `groups`,`group_member`
@ -82,7 +116,7 @@ class Acl extends \Zotlabs\Web\Controller {
} }
} }
if ($type=='' || $type=='c') { if($type == '' || $type == 'c') {
$extra_channels_sql = ''; $extra_channels_sql = '';
// Only include channels who allow the observer to view their permissions // Only include channels who allow the observer to view their permissions
foreach($extra_channels as $channel) { foreach($extra_channels as $channel) {
@ -97,11 +131,38 @@ class Acl extends \Zotlabs\Web\Controller {
if($extra_channels_sql != '') if($extra_channels_sql != '')
$extra_channels_sql = " OR (abook_channel IN ($extra_channels_sql)) and abook_hidden = 0 "; $extra_channels_sql = " OR (abook_channel IN ($extra_channels_sql)) and abook_hidden = 0 ";
$r2 = null;
$r1 = q("select * from atoken where atoken_uid = %d",
intval(local_channel())
);
if($r1) {
require_once('include/security.php');
$r2 = array();
foreach($r1 as $rr) {
$x = atoken_xchan($rr);
$r2[] = [
'id' => 'a' . $rr['atoken_id'] ,
'hash' => $x['xchan_hash'],
'name' => $x['xchan_name'],
'micro' => $x['xchan_photo_m'],
'url' => z_root(),
'nick' => $x['xchan_addr'],
'abook_their_perms' => 0,
'abook_flags' => 0,
'abook_self' => 0
];
}
}
$r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, abook_flags, abook_self $r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, abook_flags, abook_self
FROM abook left join xchan on abook_xchan = xchan_hash FROM abook left join xchan on abook_xchan = xchan_hash
WHERE (abook_channel = %d $extra_channels_sql) AND abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc" , WHERE (abook_channel = %d $extra_channels_sql) AND abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc" ,
intval(local_channel()) intval(local_channel())
); );
if($r2)
$r = array_merge($r2,$r);
} }
else { // Visitors else { // Visitors
@ -161,7 +222,7 @@ class Acl extends \Zotlabs\Web\Controller {
} }
elseif($type == 'm') { elseif($type == 'm') {
$r = q("SELECT xchan_hash as id, xchan_name as name, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url $r = q("SELECT xchan_hash as hash, xchan_name as name, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url
FROM abook left join xchan on abook_xchan = xchan_hash FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel = %d and ( (abook_their_perms = null) or (abook_their_perms & %d )>0) WHERE abook_channel = %d and ( (abook_their_perms = null) or (abook_their_perms & %d )>0)
and xchan_deleted = 0 and xchan_deleted = 0
@ -171,7 +232,7 @@ class Acl extends \Zotlabs\Web\Controller {
intval(PERMS_W_MAIL) intval(PERMS_W_MAIL)
); );
} }
elseif(($type == 'a') || ($type == 'p')) { elseif($type == 'a') {
$r = q("SELECT abook_id as id, xchan_name as name, xchan_hash as hash, xchan_addr as nick, xchan_photo_s as micro, xchan_network as network, xchan_url as url, xchan_addr as attag , abook_their_perms FROM abook left join xchan on abook_xchan = xchan_hash $r = q("SELECT abook_id as id, xchan_name as name, xchan_hash as hash, xchan_addr as nick, xchan_photo_s as micro, xchan_network as network, xchan_url as url, xchan_addr as attag , abook_their_perms FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel = %d WHERE abook_channel = %d
@ -296,7 +357,7 @@ class Acl extends \Zotlabs\Web\Controller {
$url = $directory['url'] . '/dirsearch'; $url = $directory['url'] . '/dirsearch';
} }
$count = (x($_REQUEST,'count')?$_REQUEST['count']:100); $count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 100);
if($url) { if($url) {
$query = $url . '?f=' ; $query = $url . '?f=' ;
$query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode($search) : ''); $query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode($search) : '');

View File

@ -12,7 +12,7 @@ class Block extends \Zotlabs\Web\Controller {
$which = argv(1); $which = argv(1);
$profile = 0; $profile = 0;
profile_load($a,$which,$profile); profile_load($which,$profile);
if(\App::$profile['profile_uid']) if(\App::$profile['profile_uid'])
head_set_icon(\App::$profile['thumb']); head_set_icon(\App::$profile['thumb']);
@ -52,8 +52,8 @@ class Block extends \Zotlabs\Web\Controller {
require_once('include/security.php'); require_once('include/security.php');
$sql_options = item_permissions_sql($u[0]['channel_id']); $sql_options = item_permissions_sql($u[0]['channel_id']);
$r = q("select item.* from item left join item_id on item.id = item_id.iid $r = q("select item.* from item left join iconfig on item.id = iconfig.iid
where item.uid = %d and sid = '%s' and service = 'BUILDBLOCK' and where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s' and iconfig.k = 'BUILDBLOCK' and
item_type = %d $sql_options $revision limit 1", item_type = %d $sql_options $revision limit 1",
intval($u[0]['channel_id']), intval($u[0]['channel_id']),
dbesc($page_id), dbesc($page_id),
@ -64,8 +64,8 @@ class Block extends \Zotlabs\Web\Controller {
// Check again with no permissions clause to see if it is a permissions issue // Check again with no permissions clause to see if it is a permissions issue
$x = q("select item.* from item left join item_id on item.id = item_id.iid $x = q("select item.* from item left join iconfig on item.id = iconfig.iid
where item.uid = %d and sid = '%s' and service = 'BUILDBLOCK' and where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s' and iconfig.k = 'BUILDBLOCK' and
item_type = %d $revision limit 1", item_type = %d $revision limit 1",
intval($u[0]['channel_id']), intval($u[0]['channel_id']),
dbesc($page_id), dbesc($page_id),

View File

@ -22,12 +22,12 @@ class Blocks extends \Zotlabs\Web\Controller {
else else
return; return;
profile_load($a,$which); profile_load($which);
} }
function get() { function get() {
if(! \App::$profile) { if(! \App::$profile) {
notice( t('Requested profile is not available.') . EOL ); notice( t('Requested profile is not available.') . EOL );
@ -111,8 +111,11 @@ class Blocks extends \Zotlabs\Web\Controller {
$editor = status_editor($a,$x); $editor = status_editor($a,$x);
$r = q("select iid, sid, mid, title, body, mimetype, created, edited from item_id left join item on item_id.iid = item.id
where item_id.uid = %d and service = 'BUILDBLOCK' and item_type = %d order by item.created desc", $r = q("select iconfig.iid, iconfig.k, iconfig.v, mid, title, body, mimetype, created, edited from iconfig
left join item on iconfig.iid = item.id
where uid = %d and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK'
and item_type = %d order by item.created desc",
intval($owner), intval($owner),
intval(ITEM_TYPE_BLOCK) intval(ITEM_TYPE_BLOCK)
); );
@ -129,12 +132,12 @@ class Blocks extends \Zotlabs\Web\Controller {
'created' => $rr['created'], 'created' => $rr['created'],
'edited' => $rr['edited'], 'edited' => $rr['edited'],
'mimetype' => $rr['mimetype'], 'mimetype' => $rr['mimetype'],
'pagetitle' => $rr['sid'], 'pagetitle' => $rr['v'],
'mid' => $rr['mid'] 'mid' => $rr['mid']
); );
$pages[$rr['iid']][] = array( $pages[$rr['iid']][] = array(
'url' => $rr['iid'], 'url' => $rr['iid'],
'name' => $rr['sid'], 'name' => $rr['v'],
'title' => $rr['title'], 'title' => $rr['title'],
'created' => $rr['created'], 'created' => $rr['created'],
'edited' => $rr['edited'], 'edited' => $rr['edited'],

View File

@ -20,7 +20,7 @@ class Cal extends \Zotlabs\Web\Controller {
if(argc() > 1) { if(argc() > 1) {
$nick = argv(1); $nick = argv(1);
profile_load($a,$nick); profile_load($nick);
$channelx = channelx_by_nick($nick); $channelx = channelx_by_nick($nick);

View File

@ -9,7 +9,6 @@ require_once('include/security.php');
require_once('include/conversation.php'); require_once('include/conversation.php');
require_once('include/acl_selectors.php'); require_once('include/acl_selectors.php');
require_once('include/permissions.php'); require_once('include/permissions.php');
require_once('include/PermissionDescription.php');
class Channel extends \Zotlabs\Web\Controller { class Channel extends \Zotlabs\Web\Controller {
@ -48,7 +47,7 @@ class Channel extends \Zotlabs\Web\Controller {
// Run profile_load() here to make sure the theme is set before // Run profile_load() here to make sure the theme is set before
// we start loading content // we start loading content
profile_load($a,$which,$profile); profile_load($which,$profile);
} }
@ -133,7 +132,7 @@ class Channel extends \Zotlabs\Web\Controller {
'default_location' => (($is_owner) ? \App::$profile['channel_location'] : ''), 'default_location' => (($is_owner) ? \App::$profile['channel_location'] : ''),
'nickname' => \App::$profile['channel_address'], 'nickname' => \App::$profile['channel_address'],
'lockstate' => (((strlen(\App::$profile['channel_allow_cid'])) || (strlen(\App::$profile['channel_allow_gid'])) || (strlen(\App::$profile['channel_deny_cid'])) || (strlen(\App::$profile['channel_deny_gid']))) ? 'lock' : 'unlock'), 'lockstate' => (((strlen(\App::$profile['channel_allow_cid'])) || (strlen(\App::$profile['channel_allow_gid'])) || (strlen(\App::$profile['channel_deny_cid'])) || (strlen(\App::$profile['channel_deny_gid']))) ? 'lock' : 'unlock'),
'acl' => (($is_owner) ? populate_acl($channel_acl,true, \PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post') : ''), 'acl' => (($is_owner) ? populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post') : ''),
'showacl' => (($is_owner) ? 'yes' : ''), 'showacl' => (($is_owner) ? 'yes' : ''),
'bang' => '', 'bang' => '',
'visitor' => (($is_owner || $observer) ? true : false), 'visitor' => (($is_owner || $observer) ? true : false),

View File

@ -39,7 +39,7 @@ class Chat extends \Zotlabs\Web\Controller {
// Run profile_load() here to make sure the theme is set before // Run profile_load() here to make sure the theme is set before
// we start loading content // we start loading content
profile_load($a,$which,$profile); profile_load($which,$profile);
} }

View File

@ -13,6 +13,9 @@ use \Zotlabs\Storage;
// composer autoloader for SabreDAV // composer autoloader for SabreDAV
require_once('vendor/autoload.php'); require_once('vendor/autoload.php');
require_once('include/attach.php');
/** /**
* @brief Fires up the SabreDAV server. * @brief Fires up the SabreDAV server.
* *
@ -23,7 +26,6 @@ require_once('vendor/autoload.php');
class Cloud extends \Zotlabs\Web\Controller { class Cloud extends \Zotlabs\Web\Controller {
function init() { function init() {
require_once('include/reddav.php');
if (! is_dir('store')) if (! is_dir('store'))
os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false); os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false);
@ -37,7 +39,7 @@ class Cloud extends \Zotlabs\Web\Controller {
\App::$page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . z_root() . '/feed/' . $which . '" />' . "\r\n"; \App::$page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . z_root() . '/feed/' . $which . '" />' . "\r\n";
if ($which) if ($which)
profile_load($a, $which, $profile); profile_load( $which, $profile);
$auth = new \Zotlabs\Storage\BasicAuth(); $auth = new \Zotlabs\Storage\BasicAuth();
@ -79,17 +81,6 @@ class Cloud extends \Zotlabs\Web\Controller {
$is_readable = false; $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 // provide a directory view for the cloud in Hubzilla
$browser = new \Zotlabs\Storage\Browser($auth); $browser = new \Zotlabs\Storage\Browser($auth);
$auth->setBrowserPlugin($browser); $auth->setBrowserPlugin($browser);

View File

@ -21,7 +21,7 @@ class Common extends \Zotlabs\Web\Controller {
); );
if($x) if($x)
profile_load($a,$x[0]['channel_address'],0); profile_load($x[0]['channel_address'],0);
} }

View File

@ -26,7 +26,7 @@ class Connect extends \Zotlabs\Web\Controller {
if($r) if($r)
\App::$data['channel'] = $r[0]; \App::$data['channel'] = $r[0];
profile_load($a,$which,''); profile_load($which,'');
} }
function post() { function post() {

View File

@ -16,14 +16,14 @@ require_once('include/zot.php');
require_once('include/widgets.php'); require_once('include/widgets.php');
require_once('include/photos.php'); require_once('include/photos.php');
/* @brief Initialize the connection-editor
*
*
*/
class Connedit extends \Zotlabs\Web\Controller { class Connedit extends \Zotlabs\Web\Controller {
/* @brief Initialize the connection-editor
*
*
*/
function init() { function init() {
if(! local_channel()) if(! local_channel())
@ -51,7 +51,7 @@ class Connedit extends \Zotlabs\Web\Controller {
* *
*/ */
function post() { function post() {
if(! local_channel()) if(! local_channel())
return; return;
@ -219,7 +219,7 @@ class Connedit extends \Zotlabs\Web\Controller {
//Update profile photo permissions //Update profile photo permissions
logger('A new profile was assigned - updating profile photos'); logger('A new profile was assigned - updating profile photos');
profile_photo_set_profile_perms($profile_id); profile_photo_set_profile_perms(local_channel(),$profile_id);
} }
@ -345,7 +345,7 @@ class Connedit extends \Zotlabs\Web\Controller {
unset($clone['abook_account']); unset($clone['abook_account']);
unset($clone['abook_channel']); unset($clone['abook_channel']);
$abconfig = load_abconfig($channel['channel_hash'],$clone['abook_xchan']); $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']);
if($abconfig) if($abconfig)
$clone['abconfig'] = $abconfig; $clone['abconfig'] = $abconfig;
@ -357,7 +357,7 @@ class Connedit extends \Zotlabs\Web\Controller {
* *
*/ */
function get() { function get() {
$sort_type = 0; $sort_type = 0;
$o = ''; $o = '';
@ -418,6 +418,12 @@ class Connedit extends \Zotlabs\Web\Controller {
goaway(z_root() . '/connedit/' . $contact_id); goaway(z_root() . '/connedit/' . $contact_id);
} }
if($cmd === 'resetphoto') {
q("update xchan set xchan_photo_date = '2001-01-01 00:00:00' where xchan_hash = '%s' limit 1",
dbesc($orig_record[0]['xchan_hash'])
);
$cmd = 'refresh';
}
if($cmd === 'refresh') { if($cmd === 'refresh') {
if($orig_record[0]['xchan_network'] === 'zot') { if($orig_record[0]['xchan_network'] === 'zot') {

View File

@ -29,7 +29,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
} }
$channel = \App::get_channel(); $channel = \App::get_channel();
profile_load($a,$channel['channel_address']); profile_load($channel['channel_address']);
} }
@ -40,7 +40,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
* *
*/ */
function post() { function post() {
if(! local_channel()) { if(! local_channel()) {
return; return;
@ -50,7 +50,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
check_form_security_token_redirectOnErr('/cover_photo', 'cover_photo'); check_form_security_token_redirectOnErr('/cover_photo', 'cover_photo');
if((x($_POST,'cropfinal')) && ($_POST['cropfinal'] == 1)) { if((array_key_exists('cropfinal',$_POST)) && ($_POST['cropfinal'] == 1)) {
// phase 2 - we have finished cropping // phase 2 - we have finished cropping
@ -271,7 +271,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
*/ */
function get() { function get() {
if(! local_channel()) { if(! local_channel()) {
notice( t('Permission denied.') . EOL ); notice( t('Permission denied.') . EOL );

View File

@ -14,6 +14,7 @@ use \Zotlabs\Storage;
// composer autoloader for SabreDAV // composer autoloader for SabreDAV
require_once('vendor/autoload.php'); require_once('vendor/autoload.php');
require_once('include/attach.php');
/** /**
* @brief Fires up the SabreDAV server. * @brief Fires up the SabreDAV server.
@ -44,59 +45,15 @@ class Dav extends \Zotlabs\Web\Controller {
} }
} }
require_once('include/reddav.php');
if (! is_dir('store')) if (! is_dir('store'))
os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false); os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false);
$which = null;
if (argc() > 1) if (argc() > 1)
$which = argv(1); profile_load(argv(1),0);
$profile = 0;
\App::$page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . z_root() . '/feed/' . $which . '" />' . "\r\n";
if ($which)
profile_load($a, $which, $profile);
$auth = new \Zotlabs\Storage\BasicAuth(); $auth = new \Zotlabs\Storage\BasicAuth();
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . 'WebDAV'); $auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV');
// $authBackend = new \Sabre\DAV\Auth\Backend\BasicCallBack(function($userName,$password) {
// if(account_verify_password($userName,$password))
// return true;
// return false;
// });
// $ob_hash = get_observer_hash();
// if ($ob_hash) {
// if (local_channel()) {
// $channel = \App::get_channel();
// $auth->setCurrentUser($channel['channel_address']);
// $auth->channel_id = $channel['channel_id'];
// $auth->channel_hash = $channel['channel_hash'];
// $auth->channel_account_id = $channel['channel_account_id'];
// if($channel['channel_timezone'])
// $auth->setTimezone($channel['channel_timezone']);
// }
// $auth->observer = $ob_hash;
// }
// if ($_GET['davguest'])
// $_SESSION['davguest'] = true;
// $_SERVER['QUERY_STRING'] = str_replace(array('?f=', '&f='), array('', ''), $_SERVER['QUERY_STRING']);
// $_SERVER['QUERY_STRING'] = strip_zids($_SERVER['QUERY_STRING']);
// $_SERVER['QUERY_STRING'] = preg_replace('/[\?&]davguest=(.*?)([\?&]|$)/ism', '', $_SERVER['QUERY_STRING']);
//
// $_SERVER['REQUEST_URI'] = str_replace(array('?f=', '&f='), array('', ''), $_SERVER['REQUEST_URI']);
// $_SERVER['REQUEST_URI'] = strip_zids($_SERVER['REQUEST_URI']);
// $_SERVER['REQUEST_URI'] = preg_replace('/[\?&]davguest=(.*?)([\?&]|$)/ism', '', $_SERVER['REQUEST_URI']);
$rootDirectory = new \Zotlabs\Storage\Directory('/', $auth); $rootDirectory = new \Zotlabs\Storage\Directory('/', $auth);
@ -114,48 +71,13 @@ class Dav extends \Zotlabs\Web\Controller {
$server->addPlugin($lockPlugin); $server->addPlugin($lockPlugin);
// The next section of code allows us to bypass prompting for http-auth if a
// FILE is being accessed anonymously and permissions allow this. This way
// one can create hotlinks to public media files in their cloud and anonymous
// viewers won't get asked to login.
// If a DIRECTORY is accessed or there are permission issues accessing the
// file and we aren't previously authenticated via zot, prompt for HTTP-auth.
// This will be the default case for mounting a DAV directory.
// In order to avoid prompting for passwords for viewing a DIRECTORY, add
// the URL query parameter 'davguest=1'.
// $isapublic_file = false;
// $davguest = ((x($_SESSION, 'davguest')) ? true : false);
// if ((! $auth->observer) && ($_SERVER['REQUEST_METHOD'] === 'GET')) {
// try {
// $x = RedFileData('/' . \App::$cmd, $auth);
// if($x instanceof \Zotlabs\Storage\File)
// $isapublic_file = true;
// }
// catch (Exception $e) {
// $isapublic_file = false;
// }
// }
// if ((! $auth->observer) && (! $isapublic_file) && (! $davguest)) {
// try {
// $auth->Authenticate($server, t('$Projectname channel'));
// }
// catch (Exception $e) {
// logger('mod_cloud: auth exception' . $e->getMessage());
// http_status_exit($e->getHTTPCode(), $e->getMessage());
// }
// }
// require_once('Zotlabs/Storage/Browser.php');
// provide a directory view for the cloud in Hubzilla // provide a directory view for the cloud in Hubzilla
$browser = new \Zotlabs\Storage\Browser($auth); $browser = new \Zotlabs\Storage\Browser($auth);
$auth->setBrowserPlugin($browser); $auth->setBrowserPlugin($browser);
// Experimental QuotaPlugin // Experimental QuotaPlugin
// require_once('Zotlabs/Storage/QuotaPlugin.php'); // require_once('Zotlabs/Storage/QuotaPlugin.php');
// $server->addPlugin(new \Zotlabs\Storage\QuotaPlugin($auth)); // $server->addPlugin(new \Zotlabs\Storage\QuotaPlugin($auth));
// All we need to do now, is to fire up the server // All we need to do now, is to fire up the server
$server->exec(); $server->exec();

View File

@ -106,12 +106,13 @@ class Display extends \Zotlabs\Web\Controller {
$x = q("select * from channel where channel_id = %d limit 1", $x = q("select * from channel where channel_id = %d limit 1",
intval($target_item['uid']) intval($target_item['uid'])
); );
$y = q("select * from item_id where uid = %d and service = 'WEBPAGE' and iid = %d limit 1", $y = q("select * from iconfig left join item on iconfig.iid = item.id
where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item.id = %d limit 1",
intval($target_item['uid']), intval($target_item['uid']),
intval($target_item['id']) intval($target_item['id'])
); );
if($x && $y) { if($x && $y) {
goaway(z_root() . '/page/' . $x[0]['channel_address'] . '/' . $y[0]['sid']); goaway(z_root() . '/page/' . $x[0]['channel_address'] . '/' . $y[0]['v']);
} }
else { else {
notice( t('Page not found.') . EOL); notice( t('Page not found.') . EOL);

View File

@ -17,6 +17,23 @@ class Dreport extends \Zotlabs\Web\Controller {
$mid = ((argc() > 1) ? argv(1) : ''); $mid = ((argc() > 1) ? argv(1) : '');
if($mid === 'push') {
$table = 'push';
$mid = ((argc() > 2) ? argv(2) : '');
if($mid) {
$i = q("select id from item where mid = '%s' and author_xchan = '%s' and uid = %d",
dbesc($mid),
dbesc($channel['channel_hash']),
intval($channel['channel_id'])
);
if($i) {
\Zotlabs\Daemon\Master::Summon([ 'Notifier', 'edit_post', $i[0]['id'] ]);
}
}
sleep(3);
goaway(z_root() . '/dreport/' . urlencode($mid));
}
if($mid === 'mail') { if($mid === 'mail') {
$table = 'mail'; $table = 'mail';
$mid = ((argc() > 2) ? argv(2) : ''); $mid = ((argc() > 2) ? argv(2) : '');
@ -60,10 +77,6 @@ class Dreport extends \Zotlabs\Web\Controller {
return; return;
} }
$o .= '<div class="generic-content-wrapper-styled">';
$o .= '<h2>' . sprintf( t('Delivery report for %1$s'),substr($mid,0,32)) . '...' . '</h2>';
$o .= '<table>';
for($x = 0; $x < count($r); $x++ ) { for($x = 0; $x < count($r); $x++ ) {
$r[$x]['name'] = escape_tags(substr($r[$x]['dreport_recip'],strpos($r[$x]['dreport_recip'],' '))); $r[$x]['name'] = escape_tags(substr($r[$x]['dreport_recip'],strpos($r[$x]['dreport_recip'],' ')));
@ -120,12 +133,24 @@ class Dreport extends \Zotlabs\Web\Controller {
usort($r,'self::dreport_gravity_sort'); usort($r,'self::dreport_gravity_sort');
$entries = array();
foreach($r as $rr) { foreach($r as $rr) {
$o .= '<tr><td width="40%">' . $rr['name'] . '</td><td width="20%">' . escape_tags($rr['dreport_result']) . '</td><td width="20%">' . escape_tags($rr['dreport_time']) . '</td></tr>'; $entries[] = [
'name' => $rr['name'],
'result' => escape_tags($rr['dreport_result']),
'time' => escape_tags(datetime_convert('UTC',date_default_timezone_get(),$rr['dreport_time']))
];
} }
$o .= '</table>';
$o .= '</div>'; $o = replace_macros(get_markup_template('dreport.tpl'), array(
'$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
));
return $o; return $o;

View File

@ -21,7 +21,7 @@ class Editblock extends \Zotlabs\Web\Controller {
else else
return; return;
profile_load($a,$which); profile_load($which);
} }
@ -85,11 +85,11 @@ class Editblock extends \Zotlabs\Web\Controller {
intval($owner) intval($owner)
); );
if($itm) { if($itm) {
$item_id = q("select * from item_id where service = 'BUILDBLOCK' and iid = %d limit 1", $item_id = q("select * from iconfig where cat = 'system' and k = 'BUILDBLOCK' and iid = %d limit 1",
intval($itm[0]['id']) intval($itm[0]['id'])
); );
if($item_id) if($item_id)
$block_title = $item_id[0]['sid']; $block_title = $item_id[0]['v'];
} }
else { else {
notice( t('Item not found') . EOL); notice( t('Item not found') . EOL);

View File

@ -21,7 +21,7 @@ class Editlayout extends \Zotlabs\Web\Controller {
else else
return; return;
profile_load($a,$which); profile_load($which);
} }
@ -96,11 +96,12 @@ class Editlayout extends \Zotlabs\Web\Controller {
intval($owner) intval($owner)
); );
$item_id = q("select * from item_id where service = 'PDL' and iid = %d limit 1", $item_id = q("select * from iconfig where cat = 'system' and k = 'PDL' and iid = %d limit 1",
intval($itm[0]['id']) intval($itm[0]['id'])
); );
if($item_id) if($item_id)
$layout_title = $item_id[0]['sid']; $layout_title = $item_id[0]['v'];
$rp = 'layouts/' . $which; $rp = 'layouts/' . $which;

View File

@ -4,7 +4,6 @@ namespace Zotlabs\Module;
require_once('include/channel.php'); require_once('include/channel.php');
require_once('include/acl_selectors.php'); require_once('include/acl_selectors.php');
require_once('include/conversation.php'); require_once('include/conversation.php');
require_once('include/PermissionDescription.php');
class Editwebpage extends \Zotlabs\Web\Controller { class Editwebpage extends \Zotlabs\Web\Controller {
@ -23,7 +22,7 @@ class Editwebpage extends \Zotlabs\Web\Controller {
else else
return; return;
profile_load($a,$which); profile_load($which);
} }
@ -114,11 +113,11 @@ class Editwebpage extends \Zotlabs\Web\Controller {
$itm[0]['body'] = crypto_unencapsulate(json_decode_plus($itm[0]['body']),$key); $itm[0]['body'] = crypto_unencapsulate(json_decode_plus($itm[0]['body']),$key);
} }
$item_id = q("select * from item_id where service = 'WEBPAGE' and iid = %d limit 1", $item_id = q("select * from iconfig where cat = 'system' and k = 'WEBPAGE' and iid = %d limit 1",
intval($itm[0]['id']) intval($itm[0]['id'])
); );
if($item_id) if($item_id)
$page_title = $item_id[0]['sid']; $page_title = $item_id[0]['v'];
$mimetype = $itm[0]['mimetype']; $mimetype = $itm[0]['mimetype'];
@ -151,7 +150,7 @@ class Editwebpage extends \Zotlabs\Web\Controller {
'body' => undo_post_tagging($itm[0]['body']), 'body' => undo_post_tagging($itm[0]['body']),
'post_id' => $post_id, 'post_id' => $post_id,
'visitor' => ($is_owner) ? true : false, 'visitor' => ($is_owner) ? true : false,
'acl' => populate_acl($itm[0],false,\PermissionDescription::fromGlobalPermission('view_pages')), 'acl' => populate_acl($itm[0],false,\Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')),
'showacl' => ($is_owner) ? true : false, 'showacl' => ($is_owner) ? true : false,
'mimetype' => $mimetype, 'mimetype' => $mimetype,
'mimeselect' => true, 'mimeselect' => true,

View File

@ -0,0 +1,180 @@
<?php
namespace Zotlabs\Module;
/**
*
* This is the POST destination for the embedphotos button
*
*/
class Embedphotos extends \Zotlabs\Web\Controller {
function get() {
}
function post() {
if (argc() > 1 && argv(1) === 'album') {
// API: /embedphotos/album
$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') {
// API: /embedphotos/albumlist
$album_list = $this->embedphotos_album_list($a);
json_return_and_die(array('status' => true, 'albumlist' => $album_list));
}
if (argc() > 1 && argv(1) === 'photolink') {
// API: /embedphotos/photolink
$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));
$r = q("SELECT obj from item where resource_type = 'photo' and resource_id = '%s' limit 1",
dbesc($resource_id)
);
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')) {
$photolink = $obj['body'];
} elseif (x($obj,'bbcode')) {
$photolink = $obj['bbcode'];
} else {
json_return_and_die(array('errormsg' => 'Error retrieving resource ' . $resource_id, 'status' => false));
}
json_return_and_die(array('status' => true, 'photolink' => $photolink));
}
}
/**
* Copied from include/widgets.php::widget_album() with a modification to get the profile_uid from
* the input array as in widget_item()
* @param type $name
* @return string
*/
function embedphotos_widget_album($args) {
$channel_id = 0;
if(array_key_exists('channel',$args))
$channel = $args['channel'];
$channel_id = intval($channel['channel_id']);
if(! $channel_id)
$channel_id = \App::$profile_uid;
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'))
return '';
if($args['album'])
$album = $args['album'];
if($args['title'])
$title = $args['title'];
/**
* 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) {
$x = q("select hash from attach where filename = '%s' and uid = %d limit 1",
dbesc($album),
intval($owner_uid)
);
if($x) {
$y = attach_can_view_folder($owner_uid,get_observer_hash(),$x[0]['hash']);
if(! $y)
return '';
}
}
$order = 'DESC';
$r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.imgscale, p.description, p.created FROM photo p INNER JOIN
(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),
dbesc($album),
intval(PHOTO_NORMAL),
intval(PHOTO_PROFILE)
);
$photos = array();
if(count($r)) {
$twist = 'rotright';
foreach($r as $rr) {
if($twist == 'rotright')
$twist = 'rotleft';
else
$twist = 'rotright';
$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']
. (($_GET['order'] === 'posted') ? '?f=&order=posted' : ''));
$photos[] = array(
'id' => $rr['id'],
'twist' => ' ' . $twist . rand(2,4),
'link' => $imagelink,
'title' => t('View Photo'),
'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['imgscale'] . '.' .$ext,
'alt' => $imgalt_e,
'desc'=> $desc_e,
'ext' => $ext,
'hash'=> $rr['resource_id'],
'unknown' => t('Unknown')
);
}
}
$tpl = get_markup_template('photo_album.tpl');
$o .= replace_macros($tpl, array(
'$photos' => $photos,
'$album' => (($title) ? $title : $album),
'$album_id' => rand(),
'$album_edit' => array(t('Edit Album'), $album_edit),
'$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
));
return $o;
}
function embedphotos_album_list($a) {
$o = '';
require_once('include/photos.php');
$p = photos_albums_list(\App::get_channel(), \App::get_observer());
if ($p['success']) {
return $p['albums'];
} else {
return null;
}
}
}

View File

@ -6,7 +6,6 @@ require_once('include/bbcode.php');
require_once('include/datetime.php'); require_once('include/datetime.php');
require_once('include/event.php'); require_once('include/event.php');
require_once('include/items.php'); require_once('include/items.php');
require_once('include/PermissionDescription.php');
class Events extends \Zotlabs\Web\Controller { class Events extends \Zotlabs\Web\Controller {
@ -471,7 +470,7 @@ class Events extends \Zotlabs\Web\Controller {
'$permissions' => t('Permission settings'), '$permissions' => t('Permission settings'),
// populating the acl dialog was a permission description from view_stream because Cal.php, which // populating the acl dialog was a permission description from view_stream because Cal.php, which
// displays events, says "since we don't currently have an event permission - use the stream permission" // displays events, says "since we don't currently have an event permission - use the stream permission"
'$acl' => (($orig_event['event_xchan']) ? '' : populate_acl(((x($orig_event)) ? $orig_event : $perm_defaults), false, \PermissionDescription::fromGlobalPermission('view_stream'))), '$acl' => (($orig_event['event_xchan']) ? '' : populate_acl(((x($orig_event)) ? $orig_event : $perm_defaults), false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'))),
'$submit' => t('Submit'), '$submit' => t('Submit'),
'$advanced' => t('Advanced Options') '$advanced' => t('Advanced Options')
@ -668,8 +667,10 @@ class Events extends \Zotlabs\Web\Controller {
'$export' => array(z_root()."/events/$y/$m/export",t('Export'),'',''), '$export' => array(z_root()."/events/$y/$m/export",t('Export'),'',''),
'$calendar' => cal($y,$m,$links, ' eventcal'), '$calendar' => cal($y,$m,$links, ' eventcal'),
'$events' => $events, '$events' => $events,
'$upload' => t('Import'), '$view_label' => t('View'),
'$submit' => t('Submit'), '$month' => t('Month'),
'$week' => t('Week'),
'$day' => t('Day'),
'$prev' => t('Previous'), '$prev' => t('Previous'),
'$next' => t('Next'), '$next' => t('Next'),
'$today' => t('Today'), '$today' => t('Today'),

View File

@ -6,7 +6,6 @@ namespace Zotlabs\Module;
*/ */
require_once('include/attach.php'); require_once('include/attach.php');
require_once('include/PermissionDescription.php');
/** /**
@ -134,7 +133,7 @@ class Filestorage extends \Zotlabs\Web\Controller {
$cloudpath = get_cloudpath($f) . (intval($f['is_dir']) ? '?f=&davguest=1' : ''); $cloudpath = get_cloudpath($f) . (intval($f['is_dir']) ? '?f=&davguest=1' : '');
$parentpath = get_parent_cloudpath($channel['channel_id'], $channel['channel_address'], $f['hash']); $parentpath = get_parent_cloudpath($channel['channel_id'], $channel['channel_address'], $f['hash']);
$aclselect_e = populate_acl($f, false, \PermissionDescription::fromGlobalPermission('view_storage')); $aclselect_e = populate_acl($f, false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_storage'));
$is_a_dir = (intval($f['is_dir']) ? true : false); $is_a_dir = (intval($f['is_dir']) ? true : false);
$lockstate = (($f['allow_cid'] || $f['allow_gid'] || $f['deny_cid'] || $f['deny_gid']) ? 'lock' : 'unlock'); $lockstate = (($f['allow_cid'] || $f['allow_gid'] || $f['deny_cid'] || $f['deny_gid']) ? 'lock' : 'unlock');

View File

@ -43,7 +43,7 @@ class Follow extends \Zotlabs\Web\Controller {
unset($clone['abook_account']); unset($clone['abook_account']);
unset($clone['abook_channel']); unset($clone['abook_channel']);
$abconfig = load_abconfig($channel['channel_hash'],$clone['abook_xchan']); $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']);
if($abconfig) if($abconfig)
$clone['abconfig'] = $abconfig; $clone['abconfig'] = $abconfig;

View File

@ -40,7 +40,7 @@ class Hcard extends \Zotlabs\Web\Controller {
} }
} }
profile_load($a,$which,$profile); profile_load($which,$profile);
} }

View File

@ -29,6 +29,19 @@ class Home extends \Zotlabs\Web\Controller {
goaway($dest); goaway($dest);
} }
if(remote_channel() && (! $splash) && $_SESSION['atoken']) {
$r = q("select * from atoken where atoken_id = %d",
intval($_SESSION['atoken'])
);
if($r) {
$x = channelx_by_n($r[0]['atoken_uid']);
if($x) {
goaway(z_root() . '/channel/' . $x['channel_address']);
}
}
}
if(get_account_id() && ! $splash) { if(get_account_id() && ! $splash) {
goaway(z_root() . '/new_channel'); goaway(z_root() . '/new_channel');
} }

View File

@ -57,7 +57,7 @@ class Id extends \Zotlabs\Web\Controller {
$profile = ''; $profile = '';
$channel = \App::get_channel(); $channel = \App::get_channel();
profile_load($a,$which,$profile); profile_load($which,$profile);
$op = new MysqlProvider; $op = new MysqlProvider;
$op->server(); $op->server();

View File

@ -138,8 +138,6 @@ class Impel extends \Zotlabs\Web\Controller {
$pagetitle = strtolower(\URLify::transliterate($j['pagetitle'])); $pagetitle = strtolower(\URLify::transliterate($j['pagetitle']));
} }
// Verify ability to use html or php!!! // Verify ability to use html or php!!!
$execflag = false; $execflag = false;
@ -154,21 +152,14 @@ class Impel extends \Zotlabs\Web\Controller {
} }
} }
$remote_id = 0;
$z = q("select * from item_id where sid = '%s' and service = '%s' and uid = %d limit 1",
dbesc($pagetitle),
dbesc($namespace),
intval(local_channel())
);
$i = q("select id, edited, item_deleted from item where mid = '%s' and uid = %d limit 1", $i = q("select id, edited, item_deleted from item where mid = '%s' and uid = %d limit 1",
dbesc($arr['mid']), dbesc($arr['mid']),
intval(local_channel()) intval(local_channel())
); );
if($z && $i) { \Zotlabs\Lib\IConfig::Set($arr,'system',$namespace,(($pagetitle) ? $pagetitle : substr($arr['mid'],0,16)),true);
$remote_id = $z[0]['id'];
if($i) {
$arr['id'] = $i[0]['id']; $arr['id'] = $i[0]['id'];
// don't update if it has the same timestamp as the original // don't update if it has the same timestamp as the original
if($arr['edited'] > $i[0]['edited']) if($arr['edited'] > $i[0]['edited'])
@ -182,12 +173,12 @@ class Impel extends \Zotlabs\Web\Controller {
intval(local_channel()) intval(local_channel())
); );
} }
$x = item_store($arr,$execflag); else
$x = item_store($arr,$execflag);
} }
if($x['success']) { if($x && $x['success']) {
$item_id = $x['item_id']; $item_id = $x['item_id'];
update_remote_id($channel,$item_id,$arr['item_type'],$pagetitle,$namespace,$remote_id,$arr['mid']);
} }
} }
@ -199,7 +190,8 @@ class Impel extends \Zotlabs\Web\Controller {
notice( sprintf( t('%s element installation failed'), $installed_type)); notice( sprintf( t('%s element installation failed'), $installed_type));
} }
//??? should perhaps return ret? //??? should perhaps return ret?
json_return_and_die(true); json_return_and_die(true);
} }

View File

@ -131,6 +131,8 @@ class Import extends \Zotlabs\Web\Controller {
// import channel // import channel
$relocate = ((array_key_exists('relocate',$data)) ? $data['relocate'] : null);
if(array_key_exists('channel',$data)) { if(array_key_exists('channel',$data)) {
if($completed < 1) { if($completed < 1) {
@ -387,8 +389,7 @@ class Import extends \Zotlabs\Web\Controller {
if($abconfig) { if($abconfig) {
// @fixme does not handle sync of del_abconfig // @fixme does not handle sync of del_abconfig
foreach($abconfig as $abc) { foreach($abconfig as $abc) {
if($abc['chan'] === $channel['channel_hash']) set_abconfig($channel['channel_id'],$abc['xchan'],$abc['cat'],$abc['k'],$abc['v']);
set_abconfig($abc['chan'],$abc['xchan'],$abc['cat'],$abc['k'],$abc['v']);
} }
} }
@ -475,7 +476,7 @@ class Import extends \Zotlabs\Web\Controller {
import_events($channel,$data['event']); import_events($channel,$data['event']);
if(is_array($data['event_item'])) if(is_array($data['event_item']))
import_items($channel,$data['event_item']); import_items($channel,$data['event_item'],false,$relocate);
if(is_array($data['menu'])) if(is_array($data['menu']))
import_menus($channel,$data['menu']); import_menus($channel,$data['menu']);
@ -486,7 +487,7 @@ class Import extends \Zotlabs\Web\Controller {
$saved_notification_flags = notifications_off($channel['channel_id']); $saved_notification_flags = notifications_off($channel['channel_id']);
if($import_posts && array_key_exists('item',$data) && $data['item']) if($import_posts && array_key_exists('item',$data) && $data['item'])
import_items($channel,$data['item']); import_items($channel,$data['item'],false,$relocate);
notifications_on($channel['channel_id'],$saved_notification_flags); notifications_on($channel['channel_id'],$saved_notification_flags);

View File

@ -78,6 +78,8 @@ class Import_items extends \Zotlabs\Web\Controller {
// logger('import: data: ' . print_r($data,true)); // logger('import: data: ' . print_r($data,true));
// print_r($data); // print_r($data);
if(! is_array($data))
return;
if(array_key_exists('compatibility',$data) && array_key_exists('database',$data['compatibility'])) { if(array_key_exists('compatibility',$data) && array_key_exists('database',$data['compatibility'])) {
$v1 = substr($data['compatibility']['database'],-4); $v1 = substr($data['compatibility']['database'],-4);
@ -92,7 +94,7 @@ class Import_items extends \Zotlabs\Web\Controller {
if(array_key_exists('item',$data) && $data['item']) { if(array_key_exists('item',$data) && $data['item']) {
import_items($channel,$data['item']); import_items($channel,$data['item'],false,((array_key_exists('relocate',$data)) ? $data['relocate'] : null));
} }
if(array_key_exists('item_id',$data) && $data['item_id']) { if(array_key_exists('item_id',$data) && $data['item_id']) {
@ -106,7 +108,7 @@ class Import_items extends \Zotlabs\Web\Controller {
function get() { function get() {
if(! local_channel()) { if(! local_channel()) {
notice( t('Permission denied') . EOL); notice( t('Permission denied') . EOL);

View File

@ -1,4 +1,5 @@
<?php <?php
namespace Zotlabs\Module; namespace Zotlabs\Module;
/** /**
@ -92,7 +93,7 @@ class Item extends \Zotlabs\Web\Controller {
$origin = (($api_source && array_key_exists('origin',$_REQUEST)) ? intval($_REQUEST['origin']) : 1); $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']) : ''); $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']) : ''); $remote_id = (($api_source && array_key_exists('remote_id',$_REQUEST)) ? strip_tags($_REQUEST['remote_id']) : '');
@ -182,7 +183,9 @@ class Item extends \Zotlabs\Web\Controller {
} }
// can_comment_on_post() needs info from the following xchan_query // can_comment_on_post() needs info from the following xchan_query
xchan_query($r); // This may be from the discover tab which means we need to correct the effective uid
xchan_query($r,true,(($r[0]['uid'] == local_channel()) ? 0 : local_channel()));
$parent_item = $r[0]; $parent_item = $r[0];
$parent = $r[0]['id']; $parent = $r[0]['id'];
@ -229,7 +232,7 @@ class Item extends \Zotlabs\Web\Controller {
if($namespace && $remote_id) { if($namespace && $remote_id) {
// It wasn't an internally generated post - see if we've got an item matching this remote service id // It wasn't an internally generated post - see if we've got an item matching this remote service id
$i = q("select iid from item_id where service = '%s' and sid = '%s' limit 1", $i = q("select iid from iconfig where cat = 'system' and k = '%s' and v = '%s' limit 1",
dbesc($namespace), dbesc($namespace),
dbesc($remote_id) dbesc($remote_id)
); );
@ -534,7 +537,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. * (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. * First protect any url inside certain bbcode tags so we don't double link it.
*/ */
@ -833,21 +836,23 @@ class Item extends \Zotlabs\Web\Controller {
if($orig_post) if($orig_post)
$datarray['edit'] = true; $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)) { 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), intval($profile_uid),
db_utcnow(),
db_quoteinterval('2 MINUTE'),
dbesc($body) dbesc($body)
); );
if($z) { if($z) {
foreach($z as $zz) { $datarray['cancel'] = 1;
if($zz['created'] > datetime_convert('UTC','UTC', 'now - 2 minutes')) { notice( t('Duplicate post suppressed.') . EOL);
$datarray['cancel'] = 1; logger('Duplicate post. Faking plugin cancel.');
notice( t('Duplicate post suppressed.') . EOL);
logger('Duplicate post. Faking plugin cancel.');
}
}
} }
} }
@ -880,12 +885,20 @@ class Item extends \Zotlabs\Web\Controller {
} }
} }
if($webpage) {
Zlib\IConfig::Set($datarray,'system', webpage_to_namespace($webpage),
(($pagetitle) ? $pagetitle : substr($datarray['mid'],0,16)),true);
}
elseif($namespace) {
Zlib\IConfig::Set($datarray,'system', $namespace,
(($remote_id) ? $remote_id : substr($datarray['mid'],0,16)),true);
}
if($orig_post) { if($orig_post) {
$datarray['id'] = $post_id; $datarray['id'] = $post_id;
item_store_update($datarray,$execflag); $x = item_store_update($datarray,$execflag);
update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid);
if(! $parent) { if(! $parent) {
$r = q("select * from item where id = %d", $r = q("select * from item where id = %d",
@ -894,10 +907,7 @@ class Item extends \Zotlabs\Web\Controller {
if($r) { if($r) {
xchan_query($r); xchan_query($r);
$sync_item = fetch_post_tags($r); $sync_item = fetch_post_tags($r);
$rid = q("select * from item_id where iid = %d", build_sync_packet($profile_uid,array('item' => array(encode_item($sync_item[0],true))));
intval($post_id)
);
build_sync_packet($uid,array('item' => array(encode_item($sync_item[0],true)),'item_id' => $rid));
} }
} }
if(! $nopush) if(! $nopush)
@ -979,9 +989,6 @@ class Item extends \Zotlabs\Web\Controller {
// NOTREACHED // NOTREACHED
} }
update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid);
if(($parent) && ($parent != $post_id)) { if(($parent) && ($parent != $post_id)) {
// Store the comment signature information in case we need to relay to Diaspora // Store the comment signature information in case we need to relay to Diaspora
//$ditem = $datarray; //$ditem = $datarray;
@ -995,10 +1002,7 @@ class Item extends \Zotlabs\Web\Controller {
if($r) { if($r) {
xchan_query($r); xchan_query($r);
$sync_item = fetch_post_tags($r); $sync_item = fetch_post_tags($r);
$rid = q("select * from item_id where iid = %d", build_sync_packet($profile_uid,array('item' => array(encode_item($sync_item[0],true))));
intval($post_id)
);
build_sync_packet($uid,array('item' => array(encode_item($sync_item[0],true)),'item_id' => $rid));
} }
} }
@ -1012,11 +1016,6 @@ class Item extends \Zotlabs\Web\Controller {
logger('post_complete'); logger('post_complete');
// figure out how to return, depending on from whence we came // figure out how to return, depending on from whence we came
if($api_source) if($api_source)

View File

@ -21,7 +21,7 @@ class Layouts extends \Zotlabs\Web\Controller {
else else
return; return;
profile_load($a,$which); profile_load($which);
} }
@ -90,13 +90,14 @@ class Layouts extends \Zotlabs\Web\Controller {
return; return;
} }
//This feature is not exposed in redbasic ui since it is not clear why one would want to // This feature is not exposed in redbasic ui since it is not clear why one would want to
//download a json encoded pdl file - we dont have a possibility to import it. // download a json encoded pdl file - we dont have a possibility to import it.
//Use the buildin share/install feature instead. // Use the buildin share/install feature instead.
if((argc() > 3) && (argv(2) === 'share') && (argv(3))) { if((argc() > 3) && (argv(2) === 'share') && (argv(3))) {
$r = q("select sid, service, mimetype, title, body from item_id $r = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig
left join item on item.id = item_id.iid left join item on item.id = iconfig.iid
where item_id.uid = %d and item.mid = '%s' and service = 'PDL' order by sid asc", where uid = %d and mid = '%s' and iconfig.cat = 'system' and iconfig.k = 'PDL' order by iconfig.v asc",
intval($owner), intval($owner),
dbesc(argv(3)) dbesc(argv(3))
); );
@ -141,8 +142,9 @@ class Layouts extends \Zotlabs\Web\Controller {
$editor = status_editor($a,$x); $editor = status_editor($a,$x);
$r = q("select iid, sid, mid, title, body, mimetype, created, edited, item_type from item_id left join item on item_id.iid = item.id $r = q("select iconfig.iid, iconfig.v, mid, title, body, mimetype, created, edited, item_type from iconfig
where item_id.uid = %d and service = 'PDL' and item_type = %d order by item.created desc", left join item on iconfig.iid = item.id
where uid = %d and iconfig.cat = 'system' and iconfig.k = 'PDL' and item_type = %d order by item.created desc",
intval($owner), intval($owner),
intval(ITEM_TYPE_PDL) intval(ITEM_TYPE_PDL)
); );
@ -164,7 +166,7 @@ class Layouts extends \Zotlabs\Web\Controller {
); );
$pages[$rr['iid']][] = array( $pages[$rr['iid']][] = array(
'url' => $rr['iid'], 'url' => $rr['iid'],
'title' => $rr['sid'], 'title' => $rr['v'],
'descr' => $rr['title'], 'descr' => $rr['title'],
'mid' => $rr['mid'], 'mid' => $rr['mid'],
'created' => $rr['created'], 'created' => $rr['created'],

View File

@ -1,17 +1,31 @@
<?php <?php
namespace Zotlabs\Module; namespace Zotlabs\Module;
require_once('include/security.php');
class Lockview extends \Zotlabs\Web\Controller { class Lockview extends \Zotlabs\Web\Controller {
function get() { function get() {
$atokens = array();
if(local_channel()) {
$at = q("select * from atoken where atoken_uid = %d",
intval(local_channel())
);
if($at) {
foreach($at as $t) {
$atokens[] = atoken_xchan($t);
}
}
}
$type = ((argc() > 1) ? argv(1) : 0); $type = ((argc() > 1) ? argv(1) : 0);
if (is_numeric($type)) { if (is_numeric($type)) {
$item_id = intval($type); $item_id = intval($type);
$type='item'; $type='item';
} else { }
else {
$item_id = ((argc() > 2) ? intval(argv(2)) : 0); $item_id = ((argc() > 2) ? intval(argv(2)) : 0);
} }
@ -98,6 +112,13 @@ class Lockview extends \Zotlabs\Web\Controller {
if($r) if($r)
foreach($r as $rr) foreach($r as $rr)
$l[] = '<li>' . $rr['xchan_name'] . '</li>'; $l[] = '<li>' . $rr['xchan_name'] . '</li>';
if($atokens) {
foreach($atokens as $at) {
if(in_array("'" . $at['xchan_hash'] . "'",$allowed_users)) {
$l[] = '<li>' . $at['xchan_name'] . '</li>';
}
}
}
} }
if(count($deny_groups)) { if(count($deny_groups)) {
$r = q("SELECT gname FROM `groups` WHERE hash IN ( " . implode(', ', $deny_groups) . " )"); $r = q("SELECT gname FROM `groups` WHERE hash IN ( " . implode(', ', $deny_groups) . " )");
@ -110,6 +131,16 @@ class Lockview extends \Zotlabs\Web\Controller {
if($r) if($r)
foreach($r as $rr) foreach($r as $rr)
$l[] = '<li><strike>' . $rr['xchan_name'] . '</strike></li>'; $l[] = '<li><strike>' . $rr['xchan_name'] . '</strike></li>';
if($atokens) {
foreach($atokens as $at) {
if(in_array("'" . $at['xchan_hash'] . "'",$deny_users)) {
$l[] = '<li><strike>' . $at['xchan_name'] . '</strike></li>';
}
}
}
} }
echo $o . implode($l); echo $o . implode($l);

View File

@ -7,6 +7,9 @@ class Login extends \Zotlabs\Web\Controller {
function get() { function get() {
if(local_channel()) if(local_channel())
goaway(z_root()); goaway(z_root());
if(remote_channel() && $_SESSION['atoken'])
goaway(z_root());
return login((\App::$config['system']['register_policy'] == REGISTER_CLOSED) ? false : true); return login((\App::$config['system']['register_policy'] == REGISTER_CLOSED) ? false : true);
} }

View File

@ -6,8 +6,6 @@ require_once('include/group.php');
require_once('include/contact_widgets.php'); require_once('include/contact_widgets.php');
require_once('include/conversation.php'); require_once('include/conversation.php');
require_once('include/acl_selectors.php'); require_once('include/acl_selectors.php');
require_once('include/PermissionDescription.php');
class Network extends \Zotlabs\Web\Controller { class Network extends \Zotlabs\Web\Controller {
@ -171,7 +169,7 @@ class Network extends \Zotlabs\Web\Controller {
'default_location' => $channel['channel_location'], 'default_location' => $channel['channel_location'],
'nickname' => $channel['channel_address'], 'nickname' => $channel['channel_address'],
'lockstate' => (($private_editing || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), 'lockstate' => (($private_editing || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
'acl' => populate_acl((($private_editing) ? $def_acl : $channel_acl), true, \PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), 'acl' => populate_acl((($private_editing) ? $def_acl : $channel_acl), true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
'bang' => (($private_editing) ? '!' : ''), 'bang' => (($private_editing) ? '!' : ''),
'visitor' => true, 'visitor' => true,
'profile_uid' => local_channel(), 'profile_uid' => local_channel(),

View File

@ -62,7 +62,7 @@ class New_channel extends \Zotlabs\Web\Controller {
} }
function post() { function post() {
$arr = $_POST; $arr = $_POST;
@ -96,7 +96,7 @@ class New_channel extends \Zotlabs\Web\Controller {
} }
function get() { function get() {
$acc = \App::get_account(); $acc = \App::get_account();
@ -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(); $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'] : "" ); $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()); $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());

View File

@ -48,7 +48,7 @@ class Openid extends \Zotlabs\Web\Controller {
$_SESSION['uid'] = $r[0]['channel_id']; $_SESSION['uid'] = $r[0]['channel_id'];
$_SESSION['account_id'] = $r[0]['channel_account_id']; $_SESSION['account_id'] = $r[0]['channel_account_id'];
$_SESSION['authenticated'] = true; $_SESSION['authenticated'] = true;
authenticate_success($record,true,true,true,true); authenticate_success($record,$r[0],true,true,true,true);
goaway(z_root()); goaway(z_root());
} }
} }

View File

@ -13,7 +13,7 @@ class Page extends \Zotlabs\Web\Controller {
$which = argv(1); $which = argv(1);
$profile = 0; $profile = 0;
profile_load($a,$which,$profile); profile_load($which,$profile);
@ -65,9 +65,10 @@ class Page extends \Zotlabs\Web\Controller {
require_once('include/security.php'); require_once('include/security.php');
$sql_options = item_permissions_sql($u[0]['channel_id']); $sql_options = item_permissions_sql($u[0]['channel_id']);
$r = q("select item.* from item left join item_id on item.id = item_id.iid $r = q("select item.* from item left join iconfig on item.id = iconfig.iid
where item.uid = %d and sid = '%s' and item.item_delayed = 0 and (( service = 'WEBPAGE' and item_type = %d ) where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s' and item.item_delayed = 0
OR ( service = 'PDL' AND item_type = %d )) $sql_options $revision limit 1", and (( iconfig.k = 'WEBPAGE' and item_type = %d )
OR ( iconfig.k = 'PDL' AND item_type = %d )) $sql_options $revision limit 1",
intval($u[0]['channel_id']), intval($u[0]['channel_id']),
dbesc($page_id), dbesc($page_id),
intval(ITEM_TYPE_WEBPAGE), intval(ITEM_TYPE_WEBPAGE),
@ -77,9 +78,9 @@ class Page extends \Zotlabs\Web\Controller {
// Check again with no permissions clause to see if it is a permissions issue // Check again with no permissions clause to see if it is a permissions issue
$x = q("select item.* from item left join item_id on item.id = item_id.iid $x = q("select item.* from item left join iconfig on item.id = iconfig.iid
where item.uid = %d and sid = '%s' and item.item_delayed = 0 and service = 'WEBPAGE' and where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s' and item.item_delayed = 0
item_type = %d $revision limit 1", and iconfig.k = 'WEBPAGE' and item_type = %d $revision limit 1",
intval($u[0]['channel_id']), intval($u[0]['channel_id']),
dbesc($page_id), dbesc($page_id),
intval(ITEM_TYPE_WEBPAGE) intval(ITEM_TYPE_WEBPAGE)
@ -120,10 +121,7 @@ class Page extends \Zotlabs\Web\Controller {
} }
function get() {
function get() {
$r = \App::$data['webpage']; $r = \App::$data['webpage'];
if(! $r) if(! $r)

View File

@ -2,6 +2,7 @@
namespace Zotlabs\Module; namespace Zotlabs\Module;
require_once('include/security.php'); require_once('include/security.php');
require_once('include/attach.php');
require_once('include/photo/photo_driver.php'); require_once('include/photo/photo_driver.php');
@ -10,6 +11,8 @@ class Photo extends \Zotlabs\Web\Controller {
function init() { function init() {
$prvcachecontrol = false; $prvcachecontrol = false;
$streaming = null;
$channel = null;
switch(argc()) { switch(argc()) {
case 4: case 4:
@ -62,7 +65,7 @@ class Photo extends \Zotlabs\Web\Controller {
intval($uid), intval($uid),
intval(PHOTO_PROFILE) intval(PHOTO_PROFILE)
); );
if(count($r)) { if($r) {
$data = dbunescbin($r[0]['content']); $data = dbunescbin($r[0]['content']);
$mimetype = $r[0]['mimetype']; $mimetype = $r[0]['mimetype'];
} }
@ -79,7 +82,7 @@ class Photo extends \Zotlabs\Web\Controller {
* Other photos * Other photos
*/ */
/* Check for a cookie to indicate display pixel density, in order to detect high-resolution /* Check for a cookie to indicate display pixel density, in order to detect high-resolution
displays. This procedure was derived from the "Retina Images" by Jeremey Worboys, displays. This procedure was derived from the "Retina Images" by Jeremey Worboys,
used in accordance with the Creative Commons Attribution 3.0 Unported License. used in accordance with the Creative Commons Attribution 3.0 Unported License.
Project link: https://github.com/Retina-Images/Retina-Images Project link: https://github.com/Retina-Images/Retina-Images
@ -131,6 +134,8 @@ class Photo extends \Zotlabs\Web\Controller {
$sql_extra = permissions_sql($r[0]['uid']); $sql_extra = permissions_sql($r[0]['uid']);
$channel = channelx_by_n($r[0]['uid']);
// Now we'll see if we can access the photo // Now we'll see if we can access the photo
$r = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale = %d $sql_extra LIMIT 1", $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale = %d $sql_extra LIMIT 1",
@ -141,8 +146,9 @@ class Photo extends \Zotlabs\Web\Controller {
if($r && $allowed) { if($r && $allowed) {
$data = dbunescbin($r[0]['content']); $data = dbunescbin($r[0]['content']);
$mimetype = $r[0]['mimetype']; $mimetype = $r[0]['mimetype'];
if(intval($r[0]['os_storage'])) if(intval($r[0]['os_storage'])) {
$data = file_get_contents($data); $streaming = $data;
}
} }
else { else {
@ -242,7 +248,25 @@ class Photo extends \Zotlabs\Web\Controller {
header("Cache-Control: max-age=" . $cache); header("Cache-Control: max-age=" . $cache);
} }
echo $data;
// If it's a file resource, stream it.
if($streaming && $channel) {
if(strpos($streaming,'store') !== false)
$istream = fopen($streaming,'rb');
else
$istream = fopen('store/' . $channel['channel_address'] . '/' . $streaming,'rb');
$ostream = fopen('php://output','wb');
if($istream && $ostream) {
pipe_streams($istream,$ostream);
fclose($istream);
fclose($ostream);
}
}
else {
echo $data;
}
killme(); killme();
// NOTREACHED // NOTREACHED
} }

View File

@ -9,8 +9,6 @@ require_once('include/bbcode.php');
require_once('include/security.php'); require_once('include/security.php');
require_once('include/attach.php'); require_once('include/attach.php');
require_once('include/text.php'); require_once('include/text.php');
require_once('include/PermissionDescription.php');
class Photos extends \Zotlabs\Web\Controller { class Photos extends \Zotlabs\Web\Controller {
@ -27,7 +25,7 @@ class Photos extends \Zotlabs\Web\Controller {
if(argc() > 1) { if(argc() > 1) {
$nick = argv(1); $nick = argv(1);
profile_load($a,$nick); profile_load($nick);
$channelx = channelx_by_nick($nick); $channelx = channelx_by_nick($nick);
@ -633,7 +631,7 @@ class Photos extends \Zotlabs\Web\Controller {
$lockstate = (($acl->is_private()) ? 'lock' : 'unlock'); $lockstate = (($acl->is_private()) ? 'lock' : 'unlock');
} }
$aclselect = (($_is_owner) ? populate_acl($channel_acl,false, \PermissionDescription::fromGlobalPermission('view_storage')) : ''); $aclselect = (($_is_owner) ? populate_acl($channel_acl,false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_storage')) : '');
// this is wrong but is to work around an issue with js_upload wherein it chokes if these variables // this is wrong but is to work around an issue with js_upload wherein it chokes if these variables
// don't exist. They really should be set to a parseable representation of the channel's default permissions // don't exist. They really should be set to a parseable representation of the channel's default permissions
@ -1023,7 +1021,7 @@ class Photos extends \Zotlabs\Web\Controller {
if($can_post) { if($can_post) {
$album_e = $ph[0]['album']; $album_e = $ph[0]['album'];
$caption_e = $ph[0]['description']; $caption_e = $ph[0]['description'];
$aclselect_e = (($_is_owner) ? populate_acl($ph[0], true, \PermissionDescription::fromGlobalPermission('view_storage')) : ''); $aclselect_e = (($_is_owner) ? populate_acl($ph[0], true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_storage')) : '');
$albums = ((array_key_exists('albums', \App::$data)) ? \App::$data['albums'] : photos_albums_list(\App::$data['channel'],\App::$data['observer'])); $albums = ((array_key_exists('albums', \App::$data)) ? \App::$data['albums'] : photos_albums_list(\App::$data['channel'],\App::$data['observer']));
$_SESSION['album_return'] = bin2hex($ph[0]['album']); $_SESSION['album_return'] = bin2hex($ph[0]['album']);

View File

@ -173,7 +173,7 @@ class Ping extends \Zotlabs\Web\Controller {
); );
break; break;
case 'all_events': case 'all_events':
$r = q("update event set `dimissed` = 1 where `dismissed` = 0 and uid = %d AND dtstart < '%s' AND dtstart > '%s' ", $r = q("update event set `dismissed` = 1 where `dismissed` = 0 and uid = %d AND dtstart < '%s' AND dtstart > '%s' ",
intval(local_channel()), intval(local_channel()),
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')), dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')),
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days')) dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))

View File

@ -48,7 +48,7 @@ class Profile extends \Zotlabs\Web\Controller {
} }
} }
profile_load($a,$which,$profile); profile_load($which,$profile);
} }

View File

@ -23,19 +23,18 @@ class Profile_photo extends \Zotlabs\Web\Controller {
/* @brief Initalize the profile-photo edit view /* @brief Initalize the profile-photo edit view
* *
* @param $a Current application
* @return void * @return void
* *
*/ */
function init() { function init() {
if(! local_channel()) { if(! local_channel()) {
return; return;
} }
$channel = \App::get_channel(); $channel = \App::get_channel();
profile_load($a,$channel['channel_address']); profile_load($channel['channel_address']);
} }
@ -46,7 +45,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
* *
*/ */
function post() { function post() {
if(! local_channel()) { if(! local_channel()) {
return; return;
@ -54,7 +53,22 @@ class Profile_photo extends \Zotlabs\Web\Controller {
check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo'); check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo');
if((x($_POST,'cropfinal')) && ($_POST['cropfinal'] == 1)) { if((array_key_exists('cropfinal',$_POST)) && (intval($_POST['cropfinal']) == 1)) {
// phase 2 - we have finished cropping
if(argc() != 2) {
notice( t('Image uploaded but image cropping failed.') . EOL );
return;
}
$image_id = argv(1);
if(substr($image_id,-2,1) == '-') {
$scale = substr($image_id,-1,1);
$image_id = substr($image_id,0,-2);
}
// unless proven otherwise // unless proven otherwise
$is_default_profile = 1; $is_default_profile = 1;
@ -72,22 +86,6 @@ class Profile_photo extends \Zotlabs\Web\Controller {
} }
// phase 2 - we have finished cropping
if(argc() != 2) {
notice( t('Image uploaded but image cropping failed.') . EOL );
return;
}
$image_id = argv(1);
if(substr($image_id,-2,1) == '-') {
$scale = substr($image_id,-1,1);
$image_id = substr($image_id,0,-2);
}
$srcX = $_POST['xstart']; $srcX = $_POST['xstart'];
$srcY = $_POST['ystart']; $srcY = $_POST['ystart'];
$srcW = $_POST['xfinal'] - $srcX; $srcW = $_POST['xfinal'] - $srcX;
@ -97,7 +95,6 @@ class Profile_photo extends \Zotlabs\Web\Controller {
dbesc($image_id), dbesc($image_id),
dbesc(local_channel()), dbesc(local_channel()),
intval($scale)); intval($scale));
if($r) { if($r) {
$base_image = $r[0]; $base_image = $r[0];
@ -110,30 +107,38 @@ class Profile_photo extends \Zotlabs\Web\Controller {
$aid = get_account_id(); $aid = get_account_id();
$p = array('aid' => $aid, 'uid' => local_channel(), 'resource_id' => $base_image['resource_id'], $p = [
'filename' => $base_image['filename'], 'album' => t('Profile Photos')); 'aid' => $aid,
'uid' => local_channel(),
'resource_id' => $base_image['resource_id'],
'filename' => $base_image['filename'],
'album' => t('Profile Photos')
];
$p['imgscale'] = 4; $p['imgscale'] = PHOTO_RES_PROFILE_300;
$p['photo_usage'] = (($is_default_profile) ? PHOTO_PROFILE : PHOTO_NORMAL); $p['photo_usage'] = (($is_default_profile) ? PHOTO_PROFILE : PHOTO_NORMAL);
$r1 = $im->save($p); $r1 = $im->save($p);
$im->scaleImage(80); $im->scaleImage(80);
$p['imgscale'] = 5; $p['imgscale'] = PHOTO_RES_PROFILE_80;
$r2 = $im->save($p); $r2 = $im->save($p);
$im->scaleImage(48); $im->scaleImage(48);
$p['imgscale'] = 6; $p['imgscale'] = PHOTO_RES_PROFILE_48;
$r3 = $im->save($p); $r3 = $im->save($p);
if($r1 === false || $r2 === false || $r3 === false) { if($r1 === false || $r2 === false || $r3 === false) {
// if one failed, delete them all so we can start over. // if one failed, delete them all so we can start over.
notice( t('Image resize failed.') . EOL ); notice( t('Image resize failed.') . EOL );
$x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale >= 4 ", $x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale in ( %d, %d, %d ) ",
dbesc($base_image['resource_id']), dbesc($base_image['resource_id']),
local_channel() local_channel(),
intval(PHOTO_RES_PROFILE_300),
intval(PHOTO_RES_PROFILE_80),
intval(PHOTO_RES_PROFILE_48)
); );
return; return;
} }
@ -175,6 +180,8 @@ class Profile_photo extends \Zotlabs\Web\Controller {
dbesc(datetime_convert()), dbesc(datetime_convert()),
dbesc($channel['xchan_hash']) 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); info( t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL);
@ -183,10 +190,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
// Now copy profile-permissions to pictures, to prevent privacyleaks by automatically created folder 'Profile Pictures' // Now copy profile-permissions to pictures, to prevent privacyleaks by automatically created folder 'Profile Pictures'
profile_photo_set_profile_perms($_REQUEST['profile']); profile_photo_set_profile_perms(local_channel(),$_REQUEST['profile']);
} }
else else
notice( t('Unable to process image') . EOL); notice( t('Unable to process image') . EOL);
@ -196,6 +200,8 @@ class Profile_photo extends \Zotlabs\Web\Controller {
return; // NOTREACHED return; // NOTREACHED
} }
// A new photo was uploaded. Store it and save some important details
// in App::$data for use in the cropping function
$hash = photo_new_resource(); $hash = photo_new_resource();
@ -220,7 +226,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
$os_storage = false; $os_storage = false;
foreach($i as $ii) { foreach($i as $ii) {
if(intval($ii['imgscale']) < 2) { if(intval($ii['imgscale']) < PHOTO_RES_640) {
$smallest = intval($ii['imgscale']); $smallest = intval($ii['imgscale']);
$os_storage = intval($ii['os_storage']); $os_storage = intval($ii['os_storage']);
$imagedata = $ii['content']; $imagedata = $ii['content'];
@ -239,6 +245,9 @@ class Profile_photo extends \Zotlabs\Web\Controller {
return $this->profile_photo_crop_ui_head($a, $ph, $hash, $smallest); return $this->profile_photo_crop_ui_head($a, $ph, $hash, $smallest);
// This will "fall through" to the get() method, and since
// App::$data['imagecrop'] is set, it will proceed to cropping
// rather than present the upload form
} }
@ -270,10 +279,18 @@ class Profile_photo extends \Zotlabs\Web\Controller {
return; return;
}; };
// check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo');
$resource_id = argv(2); $resource_id = argv(2);
// When using an existing photo, we don't have a dialogue to offer a choice of profiles,
// so it gets attached to the default
$p = q("select id from profile where is_default = 1 and uid = %d",
intval(local_channel())
);
if($p) {
$_REQUEST['profile'] = $p[0]['id'];
}
$r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' ORDER BY imgscale ASC", $r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' ORDER BY imgscale ASC",
intval(local_channel()), intval(local_channel()),
@ -285,11 +302,11 @@ class Profile_photo extends \Zotlabs\Web\Controller {
} }
$havescale = false; $havescale = false;
foreach($r as $rr) { foreach($r as $rr) {
if($rr['imgscale'] == 5) if($rr['imgscale'] == PHOTO_RES_PROFILE_80)
$havescale = true; $havescale = true;
} }
// set an already loaded photo as profile photo // set an already loaded and cropped photo as profile photo
if(($r[0]['album'] == t('Profile Photos')) && ($havescale)) { if(($r[0]['album'] == t('Profile Photos')) && ($havescale)) {
// unset any existing profile photos // unset any existing profile photos
@ -310,7 +327,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
dbesc($channel['xchan_hash']) dbesc($channel['xchan_hash'])
); );
profile_photo_set_profile_perms(); //Reset default photo permissions to public profile_photo_set_profile_perms(local_channel()); // Reset default photo permissions to public
\Zotlabs\Daemon\Master::Summon(array('Directory',local_channel())); \Zotlabs\Daemon\Master::Summon(array('Directory',local_channel()));
goaway(z_root() . '/profiles'); goaway(z_root() . '/profiles');
} }
@ -342,7 +359,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
if($i) { if($i) {
$hash = $i[0]['resource_id']; $hash = $i[0]['resource_id'];
foreach($i as $ii) { foreach($i as $ii) {
if(intval($ii['imgscale']) < 2) { if(intval($ii['imgscale']) < PHOTO_RES_640) {
$smallest = intval($ii['imgscale']); $smallest = intval($ii['imgscale']);
} }
} }
@ -350,9 +367,14 @@ class Profile_photo extends \Zotlabs\Web\Controller {
} }
$this->profile_photo_crop_ui_head($a, $ph, $hash, $smallest); $this->profile_photo_crop_ui_head($a, $ph, $hash, $smallest);
// falls through with App::$data['imagecrop'] set so we go straight to the cropping section
} }
$profiles = q("select id, profile_name as name, is_default from profile where uid = %d",
// present an upload form
$profiles = q("select id, profile_name as name, is_default from profile where uid = %d order by id asc",
intval(local_channel()) intval(local_channel())
); );
@ -379,6 +401,9 @@ class Profile_photo extends \Zotlabs\Web\Controller {
return $o; return $o;
} }
else { else {
// present a cropping form
$filename = \App::$data['imagecrop'] . '-' . \App::$data['imagecrop_resolution']; $filename = \App::$data['imagecrop'] . '-' . \App::$data['imagecrop_resolution'];
$resolution = \App::$data['imagecrop_resolution']; $resolution = \App::$data['imagecrop_resolution'];
$tpl = get_markup_template("cropbody.tpl"); $tpl = get_markup_template("cropbody.tpl");
@ -416,13 +441,13 @@ class Profile_photo extends \Zotlabs\Web\Controller {
if($max_length > 0) if($max_length > 0)
$ph->scaleImage($max_length); $ph->scaleImage($max_length);
$width = $ph->getWidth(); \App::$data['width'] = $ph->getWidth();
$height = $ph->getHeight(); \App::$data['height'] = $ph->getHeight();
if($width < 500 || $height < 500) { if(\App::$data['width'] < 500 || \App::$data['height'] < 500) {
$ph->scaleImageUp(400); $ph->scaleImageUp(400);
$width = $ph->getWidth(); \App::$data['width'] = $ph->getWidth();
$height = $ph->getHeight(); \App::$data['height'] = $ph->getHeight();
} }

View File

@ -193,7 +193,7 @@ class Profiles extends \Zotlabs\Web\Controller {
$chan = \App::get_channel(); $chan = \App::get_channel();
profile_load($a,$chan['channel_address'],$r[0]['id']); profile_load($chan['channel_address'],$r[0]['id']);
} }
} }
@ -584,7 +584,7 @@ class Profiles extends \Zotlabs\Web\Controller {
if($is_default) { if($is_default) {
// reload the info for the sidebar widget - why does this not work? // reload the info for the sidebar widget - why does this not work?
profile_load($a,$channel['channel_address']); profile_load($channel['channel_address']);
\Zotlabs\Daemon\Master::Summon(array('Directory',local_channel())); \Zotlabs\Daemon\Master::Summon(array('Directory',local_channel()));
} }
} }

View File

@ -17,7 +17,7 @@ class Profperm extends \Zotlabs\Web\Controller {
$profile = \App::$argv[1]; $profile = \App::$argv[1];
profile_load($a,$which,$profile); profile_load($which,$profile);
} }
@ -97,7 +97,7 @@ class Profperm extends \Zotlabs\Web\Controller {
//Time to update the permissions on the profile-pictures as well //Time to update the permissions on the profile-pictures as well
profile_photo_set_profile_perms($profile['id']); profile_photo_set_profile_perms(local_channel(),$profile['id']);
$r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d AND abook_profile = '%s'", $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d AND abook_profile = '%s'",
intval(local_channel()), intval(local_channel()),

80
Zotlabs/Module/README.md Normal file
View File

@ -0,0 +1,80 @@
Zotlabs/Module
==============
This directory contains controller modules for handling web requests. The
lowercase class name indicates the head of the URL path which this module
handles. There are other methods of attaching (routing) URL paths to
controllers, but this is the primary method used in this project.
Module controllers MUST reside in this directory and namespace to be
autoloaded (unless other specific routing methods are employed). They
typically use and extend the class definition in Zotlabs/Web/Controller
as a template.
Template:
<?php
namespace Zotlabs\Web;
class Controller {
function init() {}
function post() {}
function get() {}
}
Typical Module declaration for the '/foo' URL route:
<?php
namespace Zotlabs\Module;
class Foo extends \Zotlabs\Web\Controller {
function init() {
// init() handler goes here
}
function post() {
// post handler goes here
}
function get() {
return 'Hello world.' . EOL;
}
}
This model provides callbacks for public functions named init(), post(),
and get(). init() is always called. post() is called if $_POST variables
are present, and get() is called if none of the prior functions terminated
the handler. The get() method typically retuns a string which represents
the contents of the content region of the resulting page. Modules which emit
json, xml or other machine-readable formats typically emit their contents
inside the init() function and call 'killme()' to terminate the Module.
Modules are passed the URL path as argc,argv arguments. For a path such as
https://mysite.something/foo/bar/baz
The app will typically invoke the Module class 'Foo' and pass it
$x = argc(); // $x = 3
$x = argv(0); // $x = 'foo'
$x = argv(1); // $x = 'bar'
$x = argv(2); // $x = 'baz'
These are handled in a similar fashion to their counterparts in the Unix shell
or C/C++ languages. Do not confuse the argc(),argv() functions with the
global variables $argc,$argv which are passed to command line programs. These
are handled separately by command line and Zotlabs/Daemon class functions.

View File

@ -146,7 +146,7 @@ class Register extends \Zotlabs\Web\Controller {
goaway(z_root()); goaway(z_root());
} }
authenticate_success($result['account'],true,false,true); authenticate_success($result['account'],null,true,false,true);
$new_channel = false; $new_channel = false;
$next_page = 'new_channel'; $next_page = 'new_channel';
@ -259,7 +259,8 @@ class Register extends \Zotlabs\Web\Controller {
'$email' => $email, '$email' => $email,
'$pass1' => $password, '$pass1' => $password,
'$pass2' => $password2, '$pass2' => $password2,
'$submit' => ((UNO || $auto_create || $registration_is) ? t('Register') : t('Proceed to create your first channel')) '$submit' => t('Register'),
'$verify_note' => t('This site may require email verification after submitting this form. If you are returned to a login page, please check your email for instructions.')
)); ));
return $o; return $o;

View File

@ -25,7 +25,8 @@ class Removeaccount extends \Zotlabs\Web\Controller {
$account = \App::get_account(); $account = \App::get_account();
$account_id = get_account_id(); $account_id = get_account_id();
if(! account_verify_password($account['account_email'],$_POST['qxz_password'])) $x = account_verify_password($account['account_email'],$_POST['qxz_password']);
if(! ($x && $x['account']))
return; return;
if($account['account_password_changed'] != NULL_DATE) { if($account['account_password_changed'] != NULL_DATE) {

View File

@ -24,7 +24,9 @@ class Removeme extends \Zotlabs\Web\Controller {
$account = \App::get_account(); $account = \App::get_account();
if(! account_verify_password($account['account_email'],$_POST['qxz_password']))
$x = account_verify_password($account['account_email'],$_POST['qxz_password']);
if(! ($x && $x['account']))
return; return;
if($account['account_password_changed'] != NULL_DATE) { if($account['account_password_changed'] != NULL_DATE) {

View File

@ -2,7 +2,6 @@
namespace Zotlabs\Module; namespace Zotlabs\Module;
class Rmagic extends \Zotlabs\Web\Controller { class Rmagic extends \Zotlabs\Web\Controller {
function init() { function init() {

View File

@ -7,7 +7,6 @@ require_once('include/items.php');
require_once('include/taxonomy.php'); require_once('include/taxonomy.php');
require_once('include/conversation.php'); require_once('include/conversation.php');
require_once('include/zot.php'); require_once('include/zot.php');
require_once('include/PermissionDescription.php');
/** /**
* remote post * remote post
@ -116,7 +115,7 @@ class Rpost extends \Zotlabs\Web\Controller {
'default_location' => $channel['channel_location'], 'default_location' => $channel['channel_location'],
'nickname' => $channel['channel_address'], 'nickname' => $channel['channel_address'],
'lockstate' => (($acl->is_private()) ? 'lock' : 'unlock'), 'lockstate' => (($acl->is_private()) ? 'lock' : 'unlock'),
'acl' => populate_acl($channel_acl, true, \PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), 'acl' => populate_acl($channel_acl, true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
'bang' => '', 'bang' => '',
'visitor' => true, 'visitor' => true,
'profile_uid' => local_channel(), 'profile_uid' => local_channel(),

View File

@ -2,8 +2,6 @@
namespace Zotlabs\Module; /** @file */ namespace Zotlabs\Module; /** @file */
require_once('include/zot.php'); require_once('include/zot.php');
require_once('include/PermissionDescription.php');
class Settings extends \Zotlabs\Web\Controller { class Settings extends \Zotlabs\Web\Controller {
@ -30,7 +28,7 @@ class Settings extends \Zotlabs\Web\Controller {
} }
function post() { function post() {
if(! local_channel()) if(! local_channel())
return; return;
@ -121,6 +119,60 @@ class Settings extends \Zotlabs\Web\Controller {
} }
if((argc() > 1) && (argv(1) == 'tokens')) {
check_form_security_token_redirectOnErr('/settings/tokens', 'settings_tokens');
$token_errs = 0;
if(array_key_exists('token',$_POST)) {
$atoken_id = (($_POST['atoken_id']) ? intval($_POST['atoken_id']) : 0);
$name = trim(escape_tags($_POST['name']));
$token = trim($_POST['token']);
if((! $name) || (! $token))
$token_errs ++;
if(trim($_POST['expires']))
$expires = datetime_convert(date_default_timezone_get(),'UTC',$_POST['expires']);
else
$expires = NULL_DATE;
$max_atokens = service_class_fetch(local_channel(),'access_tokens');
if($max_atokens) {
$r = q("select count(atoken_id) as total where atoken_uid = %d",
intval(local_channel())
);
if($r && intval($r[0]['total']) >= $max_tokens) {
notice( sprintf( t('This channel is limited to %d tokens'), $max_tokens) . EOL);
return;
}
}
}
if($token_errs) {
notice( t('Name and Password are required.') . EOL);
return;
}
if($atoken_id) {
$r = q("update atoken set atoken_name = '%s', atoken_token = '%s' atoken_expires = '%s'
where atoken_id = %d and atoken_uid = %d",
dbesc($name),
dbesc($token),
dbesc($expires),
intval($atoken_id),
intval($channel['channel_id'])
);
}
else {
$r = q("insert into atoken ( atoken_aid, atoken_uid, atoken_name, atoken_token, atoken_expires )
values ( %d, %d, '%s', '%s', '%s' ) ",
intval($channel['channel_account_id']),
intval($channel['channel_id']),
dbesc($name),
dbesc($token),
dbesc($expires)
);
}
info( t('Token saved.') . EOL);
return;
}
if((argc() > 1) && (argv(1) === 'features')) { if((argc() > 1) && (argv(1) === 'features')) {
check_form_security_token_redirectOnErr('/settings/features', 'settings_features'); check_form_security_token_redirectOnErr('/settings/features', 'settings_features');
@ -709,6 +761,53 @@ class Settings extends \Zotlabs\Web\Controller {
return $o; return $o;
} }
if((argc() > 1) && (argv(1) === 'tokens')) {
$atoken = null;
if(argc() > 2) {
$id = argv(2);
$atoken = q("select * from atoken where atoken_id = %d and atoken_uid = %d",
intval($id),
intval(local_channel())
);
if($atoken)
$atoken = $atoken[0];
if($atoken && argc() > 3 && argv(3) === 'drop') {
$r = q("delete from atoken where atoken_id = %d",
intval($id)
);
}
}
$t = q("select * from atoken where atoken_uid = %d",
intval(local_channel())
);
$desc = t('Use this form to create temporary access identifiers to share things with non-members. These identities may be used in Access Control Lists and visitors may login using these credentials to access the private content.');
$desc2 = t('You may also provide <em>dropbox</em> style access links to friends and associates by adding the Login Password to any specific site URL as shown. Examples:');
$tpl = get_markup_template("settings_tokens.tpl");
$o .= replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("settings_tokens"),
'$title' => t('Guest Access Tokens'),
'$desc' => $desc,
'$desc2' => $desc2,
'$tokens' => $t,
'$atoken' => $atoken,
'$url1' => z_root() . '/channel/' . $channel['channel_address'],
'$url2' => z_root() . '/photos/' . $channel['channel_address'],
'$name' => array('name', t('Login Name') . ' <span class="required">*</span>', (($atoken) ? $atoken['atoken_name'] : ''),''),
'$token'=> array('token', t('Login Password') . ' <span class="required">*</span>',(($atoken) ? $atoken['atoken_token'] : autoname(8)), ''),
'$expires'=> array('expires', t('Expires (yyyy-mm-dd)'), (($atoken['atoken_expires'] && $atoken['atoken_expires'] != NULL_DATE) ? datetime_convert('UTC',date_default_timezone_get(),$atoken['atoken_expires']) : ''), ''),
'$submit' => t('Submit')
));
return $o;
}
if((argc() > 1) && (argv(1) === 'features')) { if((argc() > 1) && (argv(1) === 'features')) {
@ -1066,7 +1165,7 @@ class Settings extends \Zotlabs\Web\Controller {
'$maxreq' => array('maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']) , t('May reduce spam activity')), '$maxreq' => array('maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']) , t('May reduce spam activity')),
'$permissions' => t('Default Post and Publish Permissions'), '$permissions' => t('Default Post and Publish Permissions'),
'$permdesc' => t("\x28click to open/close\x29"), '$permdesc' => t("\x28click to open/close\x29"),
'$aclselect' => populate_acl($perm_defaults, false, \PermissionDescription::fromDescription(t('Use my default audience setting for the type of object published'))), '$aclselect' => populate_acl($perm_defaults, false, \Zotlabs\Lib\PermissionDescription::fromDescription(t('Use my default audience setting for the type of object published'))),
'$suggestme' => $suggestme, '$suggestme' => $suggestme,
'$group_select' => $group_select, '$group_select' => $group_select,
'$role' => array('permissions_role' , t('Channel permissions category:'), $permissions_role, '', get_roles()), '$role' => array('permissions_role' , t('Channel permissions category:'), $permissions_role, '', get_roles()),

View File

@ -493,7 +493,6 @@ class Setup extends \Zotlabs\Web\Controller {
$this->check_add($ck_funcs, t('OpenSSL PHP module'), true, true); $this->check_add($ck_funcs, t('OpenSSL PHP module'), true, true);
$this->check_add($ck_funcs, t('mysqli or postgres PHP module'), true, true); $this->check_add($ck_funcs, t('mysqli or postgres PHP module'), true, true);
$this->check_add($ck_funcs, t('mb_string PHP module'), true, true); $this->check_add($ck_funcs, t('mb_string PHP module'), true, true);
$this->check_add($ck_funcs, t('mcrypt PHP module'), true, true);
$this->check_add($ck_funcs, t('xml PHP module'), true, true); $this->check_add($ck_funcs, t('xml PHP module'), true, true);
if(function_exists('apache_get_modules')){ if(function_exists('apache_get_modules')){
@ -530,10 +529,6 @@ class Setup extends \Zotlabs\Web\Controller {
$ck_funcs[4]['status'] = false; $ck_funcs[4]['status'] = false;
$ck_funcs[4]['help'] = t('Error: mb_string PHP module required but not installed.'); $ck_funcs[4]['help'] = t('Error: mb_string PHP module required but not installed.');
} }
if(! function_exists('mcrypt_encrypt')) {
$ck_funcs[5]['status'] = false;
$ck_funcs[5]['help'] = t('Error: mcrypt PHP module required but not installed.');
}
if(! extension_loaded('xml')) { if(! extension_loaded('xml')) {
$ck_funcs[6]['status'] = false; $ck_funcs[6]['status'] = false;
$ck_funcs[6]['help'] = t('Error: xml PHP module required for DAV but not installed.'); $ck_funcs[6]['help'] = t('Error: xml PHP module required for DAV but not installed.');
@ -596,7 +591,7 @@ class Setup extends \Zotlabs\Web\Controller {
if(! is_writable('store')) { if(! is_writable('store')) {
$status = false; $status = false;
$help = t('Red uses the store directory to save uploaded files. The web server needs to have write access to the store directory under the Red top level folder') . EOL; $help = t('This software uses the store directory to save uploaded files. The web server needs to have write access to the store directory under the Red top level folder') . EOL;
$help .= t('Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder.').EOL; $help .= t('Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder.').EOL;
} }
@ -640,6 +635,9 @@ class Setup extends \Zotlabs\Web\Controller {
$help .= t('This can cause usability issues elsewhere (not just on your own site) so we must insist on this requirement.') .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('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); $this->check_add($checks, t('SSL certificate validation'), false, true, $help);
} }
} }
@ -695,6 +693,7 @@ class Setup extends \Zotlabs\Web\Controller {
// install the standard theme // install the standard theme
set_config('system', 'allowed_themes', 'redbasic'); set_config('system', 'allowed_themes', 'redbasic');
// Set a lenient list of ciphers if using openssl. Other ssl engines // Set a lenient list of ciphers if using openssl. Other ssl engines
// (e.g. NSS used in RedHat) require different syntax, so hopefully // (e.g. NSS used in RedHat) require different syntax, so hopefully
// the default curl cipher list will work for most sites. If not, // the default curl cipher list will work for most sites. If not,
@ -704,7 +703,9 @@ class Setup extends \Zotlabs\Web\Controller {
// z_fetch_url() is also used to import shared links and other content // z_fetch_url() is also used to import shared links and other content
// so in theory most any cipher could show up and we should do our best // so in theory most any cipher could show up and we should do our best
// to make the content available rather than tell folks that there's a // to make the content available rather than tell folks that there's a
// weird SSL error which they can't do anything about. // weird SSL error which they can't do anything about. This does not affect
// the SSL server, but is only a client negotiation to find something workable.
// Hence it will not make your system susceptible to POODL or other nasties.
$x = curl_version(); $x = curl_version();
if(stristr($x['ssl_version'],'openssl')) if(stristr($x['ssl_version'],'openssl'))

View File

@ -27,27 +27,11 @@ class Siteinfo extends \Zotlabs\Web\Controller {
else { else {
$version = $commit = ''; $version = $commit = '';
} }
$visible_plugins = array();
if(is_array(\App::$plugins) && count(\App::$plugins)) { $plugins_list = implode(', ',visible_plugin_list());
$r = q("select * from addon where hidden = 0");
if(count($r)) if($plugins_list)
foreach($r as $rr) $plugins_text = t('Installed plugins/addons/apps:');
$visible_plugins[] = $rr['aname'];
}
$plugins_list = '';
if(count($visible_plugins)) {
$plugins_text = t('Installed plugins/addons/apps:');
$sorted = $visible_plugins;
$s = '';
sort($sorted);
foreach($sorted as $p) {
if(strlen($p)) {
if(strlen($s)) $s .= ', ';
$s .= $p;
}
}
$plugins_list .= $s;
}
else else
$plugins_text = t('No installed plugins/addons/apps'); $plugins_text = t('No installed plugins/addons/apps');

View File

@ -31,6 +31,19 @@ class Starred extends \Zotlabs\Web\Controller {
intval($message_id) intval($message_id)
); );
$r = q("select * from item where id = %d",
intval($message_id)
);
if($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
build_sync_packet(local_channel(),[
'item' => [
encode_item($sync_item[0],true)
]
]);
}
header('Content-type: application/json'); header('Content-type: application/json');
echo json_encode(array('result' => $item_starred)); echo json_encode(array('result' => $item_starred));
killme(); killme();

View File

@ -130,8 +130,13 @@ class Tagger extends \Zotlabs\Web\Controller {
store_item_tag($item['uid'],$item['id'],TERM_OBJ_POST,TERM_COMMUNITYTAG,$term,$tagid); store_item_tag($item['uid'],$item['id'],TERM_OBJ_POST,TERM_COMMUNITYTAG,$term,$tagid);
$ret = post_activity_item($arr); $ret = post_activity_item($arr);
if($ret['success']) if($ret['success']) {
\Zotlabs\Daemon\Master::Summon(array('Notifier','tag',$ret['activity']['id'])); build_sync_packet(local_channel(),
[
'item' => [ encode_item($ret['activity'],true) ]
]
);
}
killme(); killme();

View File

@ -44,7 +44,7 @@ class Uexport extends \Zotlabs\Web\Controller {
} }
} }
function get() { function get() {
$y = datetime_convert('UTC',date_default_timezone_get(),'now','Y'); $y = datetime_convert('UTC',date_default_timezone_get(),'now','Y');

View File

@ -10,8 +10,11 @@ class Viewconnections extends \Zotlabs\Web\Controller {
if(observer_prohibited()) { if(observer_prohibited()) {
return; return;
} }
if(argc() > 1)
profile_load($a,argv(1)); if(argc() > 1) {
profile_load(argv(1));
}
} }
function get() { function get() {

View File

@ -4,7 +4,6 @@ namespace Zotlabs\Module;
require_once('include/channel.php'); require_once('include/channel.php');
require_once('include/conversation.php'); require_once('include/conversation.php');
require_once('include/acl_selectors.php'); require_once('include/acl_selectors.php');
require_once('include/PermissionDescription.php');
class Webpages extends \Zotlabs\Web\Controller { class Webpages extends \Zotlabs\Web\Controller {
@ -23,12 +22,12 @@ class Webpages extends \Zotlabs\Web\Controller {
else else
return; return;
profile_load($a,$which); profile_load($which);
} }
function get() { function get() {
if(! \App::$profile) { if(! \App::$profile) {
notice( t('Requested profile is not available.') . EOL ); notice( t('Requested profile is not available.') . EOL );
@ -105,7 +104,7 @@ class Webpages extends \Zotlabs\Web\Controller {
'is_owner' => true, 'is_owner' => true,
'nickname' => \App::$profile['channel_address'], 'nickname' => \App::$profile['channel_address'],
'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
'acl' => (($is_owner) ? populate_acl($channel_acl,false, \PermissionDescription::fromGlobalPermission('view_pages')) : ''), 'acl' => (($is_owner) ? populate_acl($channel_acl,false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')) : ''),
'showacl' => (($is_owner) ? true : false), 'showacl' => (($is_owner) ? true : false),
'visitor' => true, 'visitor' => true,
'hide_location' => true, 'hide_location' => true,
@ -138,12 +137,20 @@ class Webpages extends \Zotlabs\Web\Controller {
$sql_extra = item_permissions_sql($owner); $sql_extra = item_permissions_sql($owner);
$r = q("select * from item_id left join item on item_id.iid = item.id
where item_id.uid = %d and service = 'WEBPAGE' and item_type = %d $sql_extra order by item.created desc", $r = q("select * from iconfig left join item on iconfig.iid = item.id
where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item_type = %d
$sql_extra order by item.created desc",
intval($owner), intval($owner),
intval(ITEM_TYPE_WEBPAGE) intval(ITEM_TYPE_WEBPAGE)
); );
// $r = q("select * from item_id left join item on item_id.iid = item.id
// where item_id.uid = %d and service = 'WEBPAGE' and item_type = %d $sql_extra order by item.created desc",
// intval($owner),
// intval(ITEM_TYPE_WEBPAGE)
// );
$pages = null; $pages = null;
if($r) { if($r) {
@ -160,13 +167,13 @@ class Webpages extends \Zotlabs\Web\Controller {
'created' => $rr['created'], 'created' => $rr['created'],
'edited' => $rr['edited'], 'edited' => $rr['edited'],
'mimetype' => $rr['mimetype'], 'mimetype' => $rr['mimetype'],
'pagetitle' => $rr['sid'], 'pagetitle' => $rr['v'],
'mid' => $rr['mid'], 'mid' => $rr['mid'],
'layout_mid' => $rr['layout_mid'] 'layout_mid' => $rr['layout_mid']
); );
$pages[$rr['iid']][] = array( $pages[$rr['iid']][] = array(
'url' => $rr['iid'], 'url' => $rr['iid'],
'pagetitle' => $rr['sid'], 'pagetitle' => $rr['v'],
'title' => $rr['title'], 'title' => $rr['title'],
'created' => datetime_convert('UTC',date_default_timezone_get(),$rr['created']), 'created' => datetime_convert('UTC',date_default_timezone_get(),$rr['created']),
'edited' => datetime_convert('UTC',date_default_timezone_get(),$rr['edited']), 'edited' => datetime_convert('UTC',date_default_timezone_get(),$rr['edited']),

View File

@ -1,6 +1,6 @@
<?php <?php /** @file */
namespace Zotlabs\Module;/** @file */ namespace Zotlabs\Module;
class Wiki extends \Zotlabs\Web\Controller { class Wiki extends \Zotlabs\Web\Controller {
@ -20,11 +20,28 @@ class Wiki extends \Zotlabs\Web\Controller {
notice(t('You must be logged in to see this page.') . EOL); notice(t('You must be logged in to see this page.') . EOL);
goaway('/login'); goaway('/login');
} }
profile_load($nick);
} }
function get() { function get() {
if(observer_prohibited(true)) {
return login();
}
if(! feature_enabled(\App::$profile_uid,'wiki')) {
notice( t('Not found') . EOL);
return;
}
$tab = 'wiki';
require_once('include/wiki.php'); require_once('include/wiki.php');
require_once('include/acl_selectors.php'); require_once('include/acl_selectors.php');
require_once('include/conversation.php');
// TODO: Combine the interface configuration into a unified object // TODO: Combine the interface configuration into a unified object
// Something like $interface = array('new_page_button' => false, 'new_wiki_button' => false, ...) // Something like $interface = array('new_page_button' => false, 'new_wiki_button' => false, ...)
$wiki_owner = false; $wiki_owner = false;
@ -72,8 +89,11 @@ class Wiki extends \Zotlabs\Web\Controller {
switch (argc()) { switch (argc()) {
case 2: case 2:
// Configure page template // Configure page template
$wikiheader = t('Wiki Sandbox'); $wikiheaderName = t('Wiki');
$content = '"# Wiki Sandbox\n\nContent you **edit** and **preview** here *will not be saved*."'; $wikiheaderPage = t('Sandbox');
require_once('library/markdown.php');
$content = t('"# Wiki Sandbox\n\nContent you **edit** and **preview** here *will not be saved*."');
$renderedContent = Markdown(json_decode($content));
$hide_editor = false; $hide_editor = false;
$showPageControls = false; $showPageControls = false;
$showNewWikiButton = $wiki_owner; $showNewWikiButton = $wiki_owner;
@ -113,13 +133,18 @@ class Wiki extends \Zotlabs\Web\Controller {
} else { } else {
$wiki_editor = true; $wiki_editor = true;
} }
$wikiheader = urldecode($wikiUrlName) . ': ' . urldecode($pageUrlName); // show wiki name and page $wikiheaderName = urldecode($wikiUrlName);
$wikiheaderPage = urldecode($pageUrlName);
$p = wiki_get_page_content(array('resource_id' => $resource_id, 'pageUrlName' => $pageUrlName)); $p = wiki_get_page_content(array('resource_id' => $resource_id, 'pageUrlName' => $pageUrlName));
if(!$p['success']) { if(!$p['success']) {
notice('Error retrieving page content' . EOL); notice('Error retrieving page content' . EOL);
goaway('/'.argv(0).'/'.argv(1).'/'.$wikiUrlName); goaway('/'.argv(0).'/'.argv(1).'/'.$wikiUrlName);
} }
$content = ($p['content'] !== '' ? $p['content'] : '"# New page\n"'); $content = ($p['content'] !== '' ? htmlspecialchars_decode($p['content'],ENT_COMPAT) : '"# New page\n"');
// Render the Markdown-formatted page content in HTML
require_once('library/markdown.php');
$html = wiki_generate_toc(purify_html(Markdown(json_decode($content))));
$renderedContent = wiki_convert_links($html,argv(0).'/'.argv(1).'/'.$wikiUrlName);
$hide_editor = false; $hide_editor = false;
$showPageControls = $wiki_editor; $showPageControls = $wiki_editor;
$showNewWikiButton = $wiki_owner; $showNewWikiButton = $wiki_owner;
@ -131,11 +156,25 @@ class Wiki extends \Zotlabs\Web\Controller {
default: // Strip the extraneous URL components default: // Strip the extraneous URL components
goaway('/'.argv(0).'/'.argv(1).'/'.$wikiUrlName.'/'.$pageUrlName); goaway('/'.argv(0).'/'.argv(1).'/'.$wikiUrlName.'/'.$pageUrlName);
} }
// Render the Markdown-formatted page content in HTML
require_once('library/markdown.php'); $wikiModalID = random_string(3);
$wikiModal = replace_macros(
get_markup_template('generic_modal.tpl'), array(
'$id' => $wikiModalID,
'$title' => t('Revision Comparison'),
'$ok' => t('Revert'),
'$cancel' => t('Cancel')
)
);
$is_owner = ((local_channel()) && (local_channel() == \App::$profile['profile_uid']) ? true : false);
$o .= profile_tabs($a, $is_owner, \App::$profile['channel_address']);
$o .= replace_macros(get_markup_template('wiki.tpl'),array( $o .= replace_macros(get_markup_template('wiki.tpl'),array(
'$wikiheader' => $wikiheader, '$wikiheaderName' => $wikiheaderName,
'$wikiheaderPage' => $wikiheaderPage,
'$hideEditor' => $hide_editor, '$hideEditor' => $hide_editor,
'$showPageControls' => $showPageControls, '$showPageControls' => $showPageControls,
'$showNewWikiButton'=> $showNewWikiButton, '$showNewWikiButton'=> $showNewWikiButton,
@ -149,11 +188,25 @@ class Wiki extends \Zotlabs\Web\Controller {
'$acl' => $x['acl'], '$acl' => $x['acl'],
'$bang' => $x['bang'], '$bang' => $x['bang'],
'$content' => $content, '$content' => $content,
'$renderedContent' => Markdown(json_decode($content)), '$renderedContent' => $renderedContent,
'$wikiName' => array('wikiName', t('Enter the name of your new wiki:'), '', ''), '$wikiName' => array('wikiName', t('Enter the name of your new wiki:'), '', ''),
'$pageName' => array('pageName', t('Enter the name of the new page:'), '', ''), '$pageName' => array('pageName', t('Enter the name of the new page:'), '', ''),
'$pageRename' => array('pageRename', t('Enter the new name:'), '', ''),
'$commitMsg' => array('commitMsg', '', '', '', '', 'placeholder="(optional) Enter a custom message when saving the page..."'), '$commitMsg' => array('commitMsg', '', '', '', '', 'placeholder="(optional) Enter a custom message when saving the page..."'),
'$pageHistory' => $pageHistory['history'] '$pageHistory' => $pageHistory['history'],
'$wikiModal' => $wikiModal,
'$wikiModalID' => $wikiModalID,
'$commit' => 'HEAD',
'$embedPhotos' => t('Embed image from photo albums'),
'$embedPhotosModalTitle' => t('Embed an image from your albums'),
'$embedPhotosModalCancel' => t('Cancel'),
'$embedPhotosModalOK' => t('OK'),
'$modalchooseimages' => t('Choose images to embed'),
'$modalchoosealbum' => t('Choose an album'),
'$modaldiffalbum' => t('Choose a different album...'),
'$modalerrorlist' => t('Error getting album list'),
'$modalerrorlink' => t('Error getting photo link'),
'$modalerroralbum' => t('Error getting album'),
)); ));
head_add_js('library/ace/ace.js'); // Ace Code Editor head_add_js('library/ace/ace.js'); // Ace Code Editor
return $o; return $o;
@ -166,8 +219,12 @@ class Wiki extends \Zotlabs\Web\Controller {
// Render mardown-formatted text in HTML for preview // Render mardown-formatted text in HTML for preview
if((argc() > 2) && (argv(2) === 'preview')) { if((argc() > 2) && (argv(2) === 'preview')) {
$content = $_POST['content']; $content = $_POST['content'];
$resource_id = $_POST['resource_id'];
require_once('library/markdown.php'); require_once('library/markdown.php');
$html = purify_html(Markdown($content)); $html = wiki_generate_toc(purify_html(Markdown($content)));
$w = wiki_get_wiki($resource_id);
$wikiURL = argv(0).'/'.argv(1).'/'.$w['urlName'];
$html = wiki_convert_links($html,$wikiURL);
json_return_and_die(array('html' => $html, 'success' => true)); json_return_and_die(array('html' => $html, 'success' => true));
} }
@ -185,6 +242,7 @@ class Wiki extends \Zotlabs\Web\Controller {
} }
$wiki = array(); $wiki = array();
// Generate new wiki info from input name // Generate new wiki info from input name
$wiki['postVisible'] = ((intval($_POST['postVisible']) === 0) ? 0 : 1);
$wiki['rawName'] = $_POST['wikiName']; $wiki['rawName'] = $_POST['wikiName'];
$wiki['htmlName'] = escape_tags($_POST['wikiName']); $wiki['htmlName'] = escape_tags($_POST['wikiName']);
$wiki['urlName'] = urlencode($_POST['wikiName']); $wiki['urlName'] = urlencode($_POST['wikiName']);
@ -218,19 +276,6 @@ class Wiki extends \Zotlabs\Web\Controller {
if (local_channel() !== intval($channel['channel_id'])) { if (local_channel() !== intval($channel['channel_id'])) {
logger('Wiki delete permission denied.' . EOL); logger('Wiki delete permission denied.' . EOL);
json_return_and_die(array('message' => 'Wiki delete permission denied.', 'success' => false)); json_return_and_die(array('message' => 'Wiki delete permission denied.', 'success' => false));
} else {
/*
$channel = get_channel_by_nick($nick);
$observer_hash = get_observer_hash();
// Figure out who the page owner is.
$perms = get_all_perms(intval($channel['channel_id']), $observer_hash);
// TODO: Create a new permission setting for wiki analogous to webpages. Until
// then, use webpage permissions
if (!$perms['write_pages']) {
logger('Wiki delete permission denied.' . EOL);
json_return_and_die(array('success' => false));
}
*/
} }
$resource_id = $_POST['resource_id']; $resource_id = $_POST['resource_id'];
$deleted = wiki_delete_wiki($resource_id); $deleted = wiki_delete_wiki($resource_id);
@ -377,7 +422,7 @@ class Wiki extends \Zotlabs\Web\Controller {
if($deleted['success']) { if($deleted['success']) {
$ob = \App::get_observer(); $ob = \App::get_observer();
$commit = wiki_git_commit(array( $commit = wiki_git_commit(array(
'commit_msg' => 'Deleted ' . $pageHtmlName, 'commit_msg' => 'Deleted ' . $pageUrlName,
'resource_id' => $resource_id, 'resource_id' => $resource_id,
'observer' => $ob, 'observer' => $ob,
'files' => null 'files' => null
@ -408,7 +453,7 @@ class Wiki extends \Zotlabs\Web\Controller {
json_return_and_die(array('success' => false)); json_return_and_die(array('success' => false));
} }
} }
$reverted = wiki_revert_page(array('commitHash' => $commitHash, 'observer' => \App::get_observer(), 'resource_id' => $resource_id, 'pageUrlName' => $pageUrlName)); $reverted = wiki_revert_page(array('commitHash' => $commitHash, 'resource_id' => $resource_id, 'pageUrlName' => $pageUrlName));
if($reverted['success']) { if($reverted['success']) {
json_return_and_die(array('content' => $reverted['content'], 'message' => '', 'success' => true)); json_return_and_die(array('content' => $reverted['content'], 'message' => '', 'success' => true));
} else { } else {
@ -416,6 +461,73 @@ class Wiki extends \Zotlabs\Web\Controller {
} }
} }
// Compare page revisions
if ((argc() === 4) && (argv(2) === 'compare') && (argv(3) === 'page')) {
$resource_id = $_POST['resource_id'];
$pageUrlName = $_POST['name'];
$compareCommit = $_POST['compareCommit'];
$currentCommit = $_POST['currentCommit'];
// Determine if observer has permission to revert pages
$nick = argv(1);
$channel = get_channel_by_nick($nick);
if (local_channel() !== intval($channel['channel_id'])) {
$observer_hash = get_observer_hash();
$perms = wiki_get_permissions($resource_id, intval($channel['channel_id']), $observer_hash);
if(!$perms['read']) {
logger('Wiki read permission denied.' . EOL);
json_return_and_die(array('success' => false));
}
}
$compare = wiki_compare_page(array('currentCommit' => $currentCommit, 'compareCommit' => $compareCommit, 'resource_id' => $resource_id, 'pageUrlName' => $pageUrlName));
if($compare['success']) {
$diffHTML = '<table class="text-center" width="100%"><tr><td class="lead" width="50%">Current Revision</td><td class="lead" width="50%">Selected Revision</td></tr></table>' . $compare['diff'];
json_return_and_die(array('diff' => $diffHTML, 'message' => '', 'success' => true));
} else {
json_return_and_die(array('diff' => '', 'message' => 'Error comparing page', 'success' => false));
}
}
// Rename a page
if ((argc() === 4) && (argv(2) === 'rename') && (argv(3) === 'page')) {
$resource_id = $_POST['resource_id'];
$pageUrlName = $_POST['oldName'];
$pageNewName = $_POST['newName'];
if ($pageUrlName === 'Home') {
json_return_and_die(array('message' => 'Cannot rename Home','success' => false));
}
if(urlencode(escape_tags($pageNewName)) === '') {
json_return_and_die(array('message' => 'Error renaming page. Invalid name.', 'success' => false));
}
// Determine if observer has permission to rename pages
$nick = argv(1);
$channel = get_channel_by_nick($nick);
if (local_channel() !== intval($channel['channel_id'])) {
$observer_hash = get_observer_hash();
$perms = wiki_get_permissions($resource_id, intval($channel['channel_id']), $observer_hash);
if(!$perms['write']) {
logger('Wiki write permission denied. ' . EOL);
json_return_and_die(array('success' => false));
}
}
$renamed = wiki_rename_page(array('resource_id' => $resource_id, 'pageUrlName' => $pageUrlName, 'pageNewName' => $pageNewName));
if($renamed['success']) {
$ob = \App::get_observer();
$commit = wiki_git_commit(array(
'commit_msg' => 'Renamed ' . urldecode($pageUrlName) . ' to ' . $renamed['page']['htmlName'],
'resource_id' => $resource_id,
'observer' => $ob,
'files' => array($pageUrlName . '.md', $renamed['page']['fileName']),
'all' => true
));
if($commit['success']) {
json_return_and_die(array('name' => $renamed['page'], 'message' => 'Wiki git repo commit made', 'success' => true));
} else {
json_return_and_die(array('message' => 'Error making git commit','success' => false));
}
} else {
json_return_and_die(array('message' => 'Error renaming page', 'success' => false));
}
}
//notice('You must be authenticated.'); //notice('You must be authenticated.');
json_return_and_die(array('message' => 'You must be authenticated.', 'success' => false)); json_return_and_die(array('message' => 'You must be authenticated.', 'success' => false));

View File

@ -179,7 +179,8 @@ class Comanche {
$channel_id = $this->get_channel_id(); $channel_id = $this->get_channel_id();
if($channel_id) { if($channel_id) {
$r = q("select * from item inner join item_id on iid = item.id and item_id.uid = item.uid and item.uid = %d and service = 'BUILDBLOCK' and sid = '%s' limit 1", $r = q("select * from item inner join iconfig on iconfig.iid = item.id and item.uid = %d
and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK' and iconfig.v = '%s' limit 1",
intval($channel_id), intval($channel_id),
dbesc($name) dbesc($name)
); );
@ -282,12 +283,12 @@ class Comanche {
/** /**
* Widgets will have to get any operational arguments from the session, the * Render a widget
* global app environment, or config storage until we implement argument passing
* *
* @param string $name * @param string $name
* @param string $text * @param string $text
*/ */
function widget($name, $text) { function widget($name, $text) {
$vars = array(); $vars = array();
$matches = array(); $matches = array();
@ -314,7 +315,7 @@ class Comanche {
require_once(theme_include($theme_widget)); require_once(theme_include($theme_widget));
} }
if (function_exists($func)) if(function_exists($func))
return $func($vars); return $func($vars);
} }

View File

@ -3,6 +3,8 @@
namespace Zotlabs\Storage; namespace Zotlabs\Storage;
use Sabre\DAV; use Sabre\DAV;
use Sabre\HTTP\RequestInterface;
use Sabre\HTTP\ResponseInterface;
/** /**
* @brief Authentication backend class for DAV. * @brief Authentication backend class for DAV.
@ -89,33 +91,20 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic {
require_once('include/auth.php'); require_once('include/auth.php');
$record = account_verify_password($username, $password); $record = account_verify_password($username, $password);
if ($record && $record['account_default_channel']) { if($record && $record['account']) {
$r = q("SELECT * FROM channel WHERE channel_account_id = %d AND channel_id = %d LIMIT 1", if($record['channel'])
intval($record['account_id']), $channel = $record['channel'];
intval($record['account_default_channel']) else {
); $r = q("SELECT * FROM channel WHERE channel_account_id = %d AND channel_id = %d LIMIT 1",
if($r && $this->check_module_access($r[0]['channel_id'])) { intval($record['account']['account_id']),
return $this->setAuthenticated($r[0]); intval($record['account']['account_default_channel'])
);
if($r)
$channel = $r[0];
} }
} }
$r = q("SELECT * FROM channel WHERE channel_address = '%s' LIMIT 1", if($channel && $this->check_module_access($channel['channel_id'])) {
dbesc($username) return $this->setAuthenticated($channel);
);
if ($r) {
$x = q("SELECT account_flags, account_salt, account_password FROM account WHERE account_id = %d LIMIT 1",
intval($r[0]['channel_account_id'])
);
if ($x) {
// @fixme this foreach should not be needed?
foreach ($x as $record) {
if ((($record['account_flags'] == ACCOUNT_OK) || ($record['account_flags'] == ACCOUNT_UNVERIFIED))
&& (hash('whirlpool', $record['account_salt'] . $password) === $record['account_password'])) {
logger('password verified for ' . $username);
if($this->check_module_access($r[0]['channel_id']))
return $this->setAuthenticated($r[0]);
}
}
}
} }
if($this->module_disabled) if($this->module_disabled)
@ -145,6 +134,58 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic {
return true; return true;
} }
/**
* When this method is called, the backend must check if authentication was
* successful.
*
* The returned value must be one of the following
*
* [true, "principals/username"]
* [false, "reason for failure"]
*
* If authentication was successful, it's expected that the authentication
* backend returns a so-called principal url.
*
* Examples of a principal url:
*
* principals/admin
* principals/user1
* principals/users/joe
* principals/uid/123457
*
* If you don't use WebDAV ACL (RFC3744) we recommend that you simply
* return a string such as:
*
* principals/users/[username]
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @return array
*/
function check(RequestInterface $request, ResponseInterface $response) {
if(local_channel()) {
$this->setAuthenticated(\App::get_channel());
return [ true, $this->principalPrefix . $this->channel_name ];
}
$auth = new \Sabre\HTTP\Auth\Basic(
$this->realm,
$request,
$response
);
$userpass = $auth->getCredentials();
if (!$userpass) {
return [false, "No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured"];
}
if (!$this->validateUserPass($userpass[0], $userpass[1])) {
return [false, "Username or password was incorrect"];
}
return [true, $this->principalPrefix . $userpass[0]];
}
protected function check_module_access($channel_id) { protected function check_module_access($channel_id) {
if($channel_id && \App::$module === 'cdav') { if($channel_id && \App::$module === 'cdav') {
$x = get_pconfig($channel_id,'cdav','enabled'); $x = get_pconfig($channel_id,'cdav','enabled');

View File

@ -219,7 +219,7 @@ class Browser extends DAV\Browser\Plugin {
$output = ''; $output = '';
if ($this->enablePost) { if ($this->enablePost) {
$this->server->emit('onHTMLActionsPanel', array($parent, &$output)); $this->server->emit('onHTMLActionsPanel', array($parent, &$output, $path));
} }
$html .= replace_macros(get_markup_template('cloud.tpl'), array( $html .= replace_macros(get_markup_template('cloud.tpl'), array(
@ -266,7 +266,7 @@ class Browser extends DAV\Browser\Plugin {
* @param \Sabre\DAV\INode $node * @param \Sabre\DAV\INode $node
* @param string &$output * @param string &$output
*/ */
public function htmlActionsPanel(DAV\INode $node, &$output) { public function htmlActionsPanel(DAV\INode $node, &$output, $path) {
if (! $node instanceof DAV\ICollection) if (! $node instanceof DAV\ICollection)
return; return;

View File

@ -0,0 +1,738 @@
<?php
namespace Zotlabs\Storage;
// The Hubzilla CalDAV client will store calendar information in the 'cal' DB table.
// Event information will remain in the 'event' table. In order to implement CalDAV on top of our
// existing system, there is an event table column called vdata. This will hold the "one true record"
// of the event in VCALENDAR format. When we receive a foreign event, we will pick out the fields
// of this entry that are important to us and use it to populate the other event table fields.
// When we make an event change, it is required that we load this entry as a vobject, make the changes on the
// vobject, and then store the result back in event.vdata. This will preserve foreign keys which we
// know nothing about. Then we sync this back to the DAV server.
// We still need a DB update to create a 'cal' table entry for our existing events and link these together.
// I'm currently anticipating separating tasks/to-do items from events, so each new account wil get two default calendars.
// We will eventually provide for magic-auth or cookie login of the CURL process so we won't be required to
// store our hubzilla password. Currently for testing we are using HTTP BASIC-AUTH and must initialise the
// username/password correctly to make the connection.
// Repeating events will be awkward because every instance has the same UUID. This would make it difficult to
// search for upcoming events if the initial instance was created (for instance) a few years ago. So the current plan is
// to create event instances for a prescribed time limit from now (perhaps 5-10 years for annual events).
// This plan may change. The repurcussions of this decision mean that an edit to a recurring event must
// edit all existing instances of the event, and only one unique instance can be used for sync.
// Sabre vobject provides a function to automatically expand recurring events into individual event instances.
class CalDAVClient {
private $username;
private $password;
private $url;
public $filepos = 0;
public $request_data = '';
function __construct($user,$pass,$url) {
$this->username = $user;
$this->password = $pass;
$this->url = $url;
}
private function set_data($s) {
$this->request_data = $s;
$this->filepos = 0;
}
public function curl_read($ch,$fh,$size) {
if($this->filepos < 0) {
unset($fh);
return '';
}
$s = substr($this->request_data,$this->filepos,$size);
if(strlen($s) < $size)
$this->filepos = (-1);
else
$this->filepos = $this->filepos + $size;
return $s;
}
function ctag_fetch() {
$headers = [ 'Depth: 0', 'Prefer: return-minimal', 'Content-Type: application/xml; charset=utf-8'];
// recommended ctag fetch by sabre
$this->set_data('<?xml version="1.0"?>
<d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/">
<d:prop>
<d:displayname />
<cs:getctag />
<d:sync-token />
</d:prop>
</d:propfind>');
// thunderbird uses this - it's a bit more verbose on what capabilities
// are provided by the server
$this->set_data('<?xml version="1.0" encoding="UTF-8"?>
<D:propfind xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<D:resourcetype/>
<D:owner/>
<D:current-user-principal/>
<D:supported-report-set/>
<C:supported-calendar-component-set/>
<CS:getctag/>
</D:prop>
</D:propfind>');
$auth = $this->username . ':' . $this->password;
$recurse = 0;
$x = z_fetch_url($this->url,true,$recurse,
[ 'headers' => $headers,
'http_auth' => $auth,
'custom' => 'PROPFIND',
'upload' => true,
'infile' => 3,
'infilesize' => strlen($this->request_data),
'readfunc' => [ $this, 'curl_read' ]
]);
return $x;
}
function detail_fetch() {
$headers = [ 'Depth: 1', 'Prefer: return-minimal', 'Content-Type: application/xml; charset=utf-8'];
// this query should return all objects in the given calendar, you can filter it appropriately
// using filter options
$this->set_data('<?xml version="1.0"?>
<c:calendar-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">
<d:prop>
<d:getetag />
<c:calendar-data />
</d:prop>
<c:filter>
<c:comp-filter name="VCALENDAR" />
</c:filter>
</c:calendar-query>');
$auth = $this->username . ':' . $this->password;
$recurse = 0;
$x = z_fetch_url($this->url,true,$recurse,
[ 'headers' => $headers,
'http_auth' => $auth,
'custom' => 'REPORT',
'upload' => true,
'infile' => 3,
'infilesize' => strlen($this->request_data),
'readfunc' => [ $this, 'curl_read' ]
]);
return $x;
}
}
/*
PROPFIND /calendars/johndoe/home/ HTTP/1.1
Depth: 0
Prefer: return-minimal
Content-Type: application/xml; charset=utf-8
<d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/">
<d:prop>
<d:displayname />
<cs:getctag />
</d:prop>
</d:propfind>
// Responses: success
HTTP/1.1 207 Multi-status
Content-Type: application/xml; charset=utf-8
<d:multistatus xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/">
<d:response>
<d:href>/calendars/johndoe/home/</d:href>
<d:propstat>
<d:prop>
<d:displayname>Home calendar</d:displayname>
<cs:getctag>3145</cs:getctag>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
</d:multistatus>
// Responses: fail
HTTP/1.1 207 Multi-status
Content-Type: application/xml; charset=utf-8
<d:multistatus xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/">
<d:response>
<d:href>/calendars/johndoe/home/</d:href>
<d:propstat>
<d:prop>
<d:displayname />
<cs:getctag />
</d:prop>
<d:status>HTTP/1.1 403 Forbidden</d:status>
</d:propstat>
</d:response>
</d:multistatus>
// sample request body in DOM
// prepare request body
$doc = new DOMDocument('1.0', 'utf-8');
$doc->formatOutput = true;
$query = $doc->createElement('c:calendar-query');
$query->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:c', 'urn:ietf:params:xml:ns:caldav');
$query->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:d', 'DAV:');
$prop = $doc->createElement('d:prop');
$prop->appendChild($doc->createElement('d:getetag'));
$prop->appendChild($doc->createElement('c:calendar-data'));
$query->appendChild($prop);
$doc->appendChild($query);
$body = $doc->saveXML();
echo "Body: " . $body . "<br>";
Now we download every single object in this calendar. To do this, we use a REPORT method.
REPORT /calendars/johndoe/home/ HTTP/1.1
Depth: 1
Prefer: return-minimal
Content-Type: application/xml; charset=utf-8
<c:calendar-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
<d:prop>
<d:getetag />
<c:calendar-data />
</d:prop>
<c:filter>
<c:comp-filter name="VCALENDAR" />
</c:filter>
</c:calendar-query>
This request will give us every object that's a VCALENDAR object, and its etag.
If you're only interested in VTODO (because you're writing a todo app) you can also filter for just those:
REPORT /calendars/johndoe/home/ HTTP/1.1
Depth: 1
Prefer: return-minimal
Content-Type: application/xml; charset=utf-8
<c:calendar-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
<d:prop>
<d:getetag />
<c:calendar-data />
</d:prop>
<c:filter>
<c:comp-filter name="VCALENDAR">
<c:comp-filter name="VTODO" />
</c:comp-filter>
</c:filter>
</c:calendar-query>
Similarly it's also possible to filter to just events, or only get events within a specific time-range.
This report will return a multi-status object again:
HTTP/1.1 207 Multi-status
Content-Type: application/xml; charset=utf-8
<d:multistatus xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/">
<d:response>
<d:href>/calendars/johndoe/home/132456762153245.ics</d:href>
<d:propstat>
<d:prop>
<d:getetag>"2134-314"</d:getetag>
<c:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
BEGIN:VTODO
UID:132456762153245
SUMMARY:Do the dishes
DUE:20121028T115600Z
END:VTODO
END:VCALENDAR
</c:calendar-data>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:response>
<d:href>/calendars/johndoe/home/132456-34365.ics</d:href>
<d:propstat>
<d:prop>
<d:getetag>"5467-323"</d:getetag>
<c:calendar-data>BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
BEGIN:VEVENT
UID:132456-34365
SUMMARY:Weekly meeting
DTSTART:20120101T120000
DURATION:PT1H
RRULE:FREQ=WEEKLY
END:VEVENT
END:VCALENDAR
</c:calendar-data>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
</d:multistatus>
This calendar only contained 2 objects. A todo and a weekly event.
So after you retrieved and processed these, for each object you must retain:
The calendar data itself
The url
The etag
In this case all urls ended with .ics. This is often the case, but you must not rely on this. In this case the UID in the calendar object was also identical to a part of the url. This too is often the case, but again not something you can rely on, so don't make any assumptions.
The url and the UID have no meaningful relationship, so treat both those items as separate unique identifiers.
Finding out if anything changed
To see if anything in a calendar changed, we simply request the ctag again on the calendar. If the ctag did not change, you still have the latest copy.
If it did change, you must request all the etags in the entire calendar again:
REPORT /calendars/johndoe/home/ HTTP/1.1
Depth: 1
Prefer: return-minimal
Content-Type: application/xml; charset=utf-8
<c:calendar-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
<d:prop>
<d:getetag />
</d:prop>
<c:filter>
<c:comp-filter name="VCALENDAR">
<c:comp-filter name="VTODO" />
</c:comp-filter>
</c:filter>
</c:calendar-query>
Note that this last request is extremely similar to a previous one, but we are only asking fo the etag, not the calendar-data.
The reason for this, is that calendars can be rather huge. It will save a TON of bandwidth to only check the etag first.
HTTP/1.1 207 Multi-status
Content-Type: application/xml; charset=utf-8
<d:multistatus xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/">
<d:response>
<d:href>/calendars/johndoe/home/132456762153245.ics</d:href>
<d:propstat>
<d:prop>
<d:getetag>"xxxx-xxx"</d:getetag>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:response>
<d:href>/calendars/johndoe/home/fancy-caldav-client-1234253678.ics</d:href>
<d:propstat>
<d:prop>
<d:getetag>"5-12"</d:getetag>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
</d:multistatus>
Judging from this last request, 3 things have changed:
The etag for the task has changed, so the contents must be different
There's a new url, some other client must have added an object
One object is missing, something must have deleted it.
So based on those 3 items we know that we need to delete an object from our local list, and fetch the contents for the new item, and the updated one.
To fetch the data for these, you can simply issue GET requests:
GET /calendars/johndoe/home/132456762153245.ics HTTP/1.1
But, because in a worst-case scenario this could result in a LOT of GET requests we can do a 'multiget'.
REPORT /calendars/johndoe/home/ HTTP/1.1
Depth: 1
Prefer: return-minimal
Content-Type: application/xml; charset=utf-8
<c:calendar-multiget xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
<d:prop>
<d:getetag />
<c:calendar-data />
</d:prop>
<d:href>/calendars/johndoe/home/132456762153245.ics</d:href>
<d:href>/calendars/johndoe/home/fancy-caldav-client-1234253678.ics</d:href>
</c:calendar-multiget>
This request will simply return a multi-status again with the calendar-data and etag.
A small note about application design
If you read this far and understood what's been said, you may have realized that it's a bit cumbersome to have a separate step for the initial sync, and subsequent updates.
It would totally be possible to skip the 'initial sync', and just use calendar-query and calendar-multiget REPORTS for the initial sync as well.
Updating a calendar object
Updating a calendar object is rather simple:
PUT /calendars/johndoe/home/132456762153245.ics HTTP/1.1
Content-Type: text/calendar; charset=utf-8
If-Match: "2134-314"
BEGIN:VCALENDAR
....
END:VCALENDAR
A response to this will be something like this:
HTTP/1.1 204 No Content
ETag: "2134-315"
The update gave us back the new ETag. SabreDAV gives this ETag on updates back most of the time, but not always.
There are cases where the caldav server must modify the iCalendar object right after storage. In those cases an ETag will not be returned, and you should issue a GET request immediately to get the correct object.
A few notes:
You must not change the UID of the original object
Every object should hold only 1 event or task.
You cannot change an VEVENT into a VTODO.
Creating a calendar object
Creating a calendar object is almost identical, except that you don't have a url yet to a calendar object.
Instead, it is up to you to determine the new url.
PUT /calendars/johndoe/home/somerandomstring.ics HTTP/1.1
Content-Type: text/calendar; charset=utf-8
BEGIN:VCALENDAR
....
END:VCALENDAR
A response to this will be something like this:
HTTP/1.1 201 Created
ETag: "21345-324"
Similar to updating, an ETag is often returned, but there are cases where this is not true.
Deleting a calendar object
Deleting is simple enough:
DELETE /calendars/johndoe/home/132456762153245.ics HTTP/1.1
If-Match: "2134-314"
Speeding up Sync with WebDAV-Sync
WebDAV-Sync is a protocol extension that is defined in rfc6578. Because this extension was defined later, some servers may not support this yet.
SabreDAV supports this since 2.0.
WebDAV-Sync allows a client to ask just for calendars that have changed. The process on a high-level is as follows:
Client requests sync-token from server.
Server reports token 15.
Some time passes.
Client does a Sync REPORT on an calendar, and supplied token 15.
Server returns vcard urls that have changed or have been deleted and returns token 17.
As you can see, after the initial sync, only items that have been created, modified or deleted will ever be sent.
This has a lot of advantages. The transmitted xml bodies can generally be a lot shorter, and is also easier on both client and server in terms of memory and CPU usage, because only a limited set of items will have to be compared.
It's important to note, that a client should only do Sync operations, if the server reports that it has support for it. The quickest way to do so, is to request {DAV}sync-token on the calendar you wish to sync.
Technically, a server may support 'sync' on one calendar, and it may not support it on another, although this is probably rare.
Getting the first sync-token
Initially, we just request a sync token when asking for calendar information:
PROPFIND /calendars/johndoe/home/ HTTP/1.1
Depth: 0
Content-Type: application/xml; charset=utf-8
<d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/">
<d:prop>
<d:displayname />
<cs:getctag />
<d:sync-token />
</d:prop>
</d:propfind>
This would return something as follows:
<d:multistatus xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/">
<d:response>
<d:href>/calendars/johndoe/home/</d:href>
<d:propstat>
<d:prop>
<d:displayname>My calendar</d:displayname>
<cs:getctag>3145</cs:getctag>
<d:sync-token>http://sabredav.org/ns/sync-token/3145</d:sync-token>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
</d:multistatus>
As you can see, the sync-token is a url. It always should be a url. Even though a number appears in the url, you are not allowed to attach any meaning to that url. Some servers may have use an increasing number, another server may use a completely random string.
Receiving changes
After a sync token has been obtained, and the client already has the initial copy of the calendar, the client is able to request all changes since the token was issued.
This is done with a REPORT request that may look like this:
REPORT /calendars/johndoe/home/ HTTP/1.1
Host: dav.example.org
Content-Type: application/xml; charset="utf-8"
<?xml version="1.0" encoding="utf-8" ?>
<d:sync-collection xmlns:d="DAV:">
<d:sync-token>http://sabredav.org/ns/sync/3145</d:sync-token>
<d:sync-level>1</d:sync-level>
<d:prop>
<d:getetag/>
</d:prop>
</d:sync-collection>
This requests all the changes since sync-token identified by http://sabredav.org/ns/sync/3145, and for the calendar objects that have been added or modified, we're requesting the etag.
The response to a query like this is another multistatus xml body. Example:
HTTP/1.1 207 Multi-Status
Content-Type: application/xml; charset="utf-8"
<?xml version="1.0" encoding="utf-8" ?>
<d:multistatus xmlns:d="DAV:">
<d:response>
<d:href>/calendars/johndoe/home/newevent.ics</d:href>
<d:propstat>
<d:prop>
<d:getetag>"33441-34321"</d:getetag>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:response>
<d:href>/calendars/johndoe/home/updatedevent.ics</d:href>
<d:propstat>
<d:prop>
<d:getetag>"33541-34696"</d:getetag>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:response>
<d:href>/calendars/johndoe/home/deletedevent.ics</d:href>
<d:status>HTTP/1.1 404 Not Found</d:status>
</d:response>
<d:sync-token>http://sabredav.org/ns/sync/5001</d:sync-token>
</d:multistatus>
The last response reported two changes: newevent.ics and updatedevent.ics. There's no way to tell from the response wether those cards got created or updated, you, as a client can only infer this based on the vcards you are already aware of.
The entry with name deletedevent.ics got deleted as indicated by the 404 status. Note that the status element is here a child of d:response when in all previous examples it has been a child of d:propstat.
The other difference with the other multi-status examples, is that this one has a sync-token element with the latest sync-token.
Caveats
Note that a server is free to 'forget' any sync-tokens that have been previously issued. In this case it may be needed to do a full-sync again.
In case the supplied sync-token is not recognized by the server, a HTTP error is emitted. SabreDAV emits a 403.
Discovery
Ideally you will want to make sure that all the calendars in an account are automatically discovered. The best user interface would be to just have to ask for three items:
Username
Password
Server
And the server should be as short as possible. This is possible with most servers.
If, for example a user specified 'dav.example.org' for the server, the first thing you should do is attempt to send a PROPFIND request to https://dav.example.org/. Note that you SHOULD try the https url before the http url.
This PROPFIND request looks as follows:
PROPFIND / HTTP/1.1
Depth: 0
Prefer: return-minimal
Content-Type: application/xml; charset=utf-8
<d:propfind xmlns:d="DAV:">
<d:prop>
<d:current-user-principal />
</d:prop>
</d:propfind>
This will return a response such as the following:
HTTP/1.1 207 Multi-status
Content-Type: application/xml; charset=utf-8
<d:multistatus xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/">
<d:response>
<d:href>/</d:href>
<d:propstat>
<d:prop>
<d:current-user-principal>
<d:href>/principals/users/johndoe/</d:href>
</d:current-user-principal>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
</d:multistatus>
A 'principal' is a user. The url that's being returned, is a url that refers to the current user. On this url you can request additional information about the user.
What we need from this url, is their 'calendar home'. The calendar home is a collection that contains all of the users' calendars.
To request that, issue the following request:
PROPFIND /principals/users/johndoe/ HTTP/1.1
Depth: 0
Prefer: return-minimal
Content-Type: application/xml; charset=utf-8
<d:propfind xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
<d:prop>
<c:calendar-home-set />
</d:prop>
</d:propfind>
This will return a response such as the following:
HTTP/1.1 207 Multi-status
Content-Type: application/xml; charset=utf-8
<d:multistatus xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
<d:response>
<d:href>/principals/users/johndoe/</d:href>
<d:propstat>
<d:prop>
<c:calendar-home-set>
<d:href>/calendars/johndoe/</d:href>
</c:calendar-home-set>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
</d:multistatus>
Lastly, to list all the calendars for the user, issue a PROPFIND request with Depth: 1.
PROPFIND /calendars/johndoe/ HTTP/1.1
Depth: 1
Prefer: return-minimal
Content-Type: application/xml; charset=utf-8
<d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/" xmlns:c="urn:ietf:params:xml:ns:caldav">
<d:prop>
<d:resourcetype />
<d:displayname />
<cs:getctag />
<c:supported-calendar-component-set />
</d:prop>
</d:propfind>
In that last request, we asked for 4 properties.
The resourcetype tells us what type of object we're getting back. You must read out the resourcetype and ensure that it contains at least a calendar element in the CalDAV namespace. Other items may be returned, including non- calendar, which your application should ignore.
The displayname is a human-readable string for the calendarname, the ctag was already covered in an earlier section.
Lastly, supported-calendar-component-set. This gives us a list of components that the calendar accepts. This could be just VTODO, VEVENT, VJOURNAL or a combination of these three.
If you are just creating a todo-list application, this means you should only list the calendars that support the VTODO component.
HTTP/1.1 207 Multi-status
Content-Type: application/xml; charset=utf-8
<d:multistatus xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/" xmlns:c="urn:ietf:params:xml:ns:caldav">
<d:response>
<d:href>/calendars/johndoe/</d:href>
<d:propstat>
<d:prop>
<d:resourcetype>
<d:collection/>
</d:resourcetype>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:response>
<d:href>/calendars/johndoe/home/</d:href>
<d:propstat>
<d:prop>
<d:resourcetype>
<d:collection/>
<c:calendar/>
</d:resourcetype>
<d:displayname>Home calendar</d:displayname>
<cs:getctag>3145</cs:getctag>
<c:supported-calendar-component-set>
<c:comp name="VEVENT" />
</c:supported-calendar-component-set>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
<d:response>
<d:href>/calendars/johndoe/tasks/</d:href>
<d:propstat>
<d:prop>
<d:resourcetype>
<d:collection/>
<c:calendar/>
</d:resourcetype>
<d:displayname>My TODO list</d:displayname>
<cs:getctag>3345</cs:getctag>
<c:supported-calendar-component-set>
<c:comp name="VTODO" />
</c:supported-calendar-component-set>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
</d:multistatus>
*/

View File

@ -3,6 +3,7 @@
namespace Zotlabs\Storage; namespace Zotlabs\Storage;
use Sabre\DAV; use Sabre\DAV;
use Sabre\HTTP;
/** /**
* @brief RedDirectory class. * @brief RedDirectory class.
@ -91,7 +92,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
throw new DAV\Exception\Forbidden('Permission denied.'); throw new DAV\Exception\Forbidden('Permission denied.');
} }
$contents = RedCollectionData($this->red_path, $this->auth); $contents = $this->CollectionData($this->red_path, $this->auth);
return $contents; return $contents;
} }
@ -119,7 +120,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
return new Directory('/' . $modulename, $this->auth); 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) { if ($x) {
return $x; return $x;
} }
@ -159,7 +160,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
throw new DAV\Exception\Forbidden('Permission denied.'); throw new DAV\Exception\Forbidden('Permission denied.');
} }
list($parent_path, ) = DAV\URLUtil::splitPath($this->red_path); list($parent_path, ) = HTTP\URLUtil::splitPath($this->red_path);
$new_path = $parent_path . '/' . $name; $new_path = $parent_path . '/' . $name;
$r = q("UPDATE attach SET filename = '%s' WHERE hash = '%s' AND uid = %d", $r = q("UPDATE attach SET filename = '%s' WHERE hash = '%s' AND uid = %d",
@ -206,6 +207,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
throw new DAV\Exception\Forbidden('Permission denied.'); throw new DAV\Exception\Forbidden('Permission denied.');
} }
$mimetype = z_mime_content_type($name); $mimetype = z_mime_content_type($name);
$c = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1", $c = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1",
@ -432,8 +434,8 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
return true; return true;
} }
$x = RedFileData($this->ext_path . '/' . $name, $this->auth, true); $x = $this->FileData($this->ext_path . '/' . $name, $this->auth, true);
//logger('RedFileData returns: ' . print_r($x, true), LOGGER_DATA); //logger('FileData returns: ' . print_r($x, true), LOGGER_DATA);
if ($x) if ($x)
return true; return true;
@ -566,4 +568,280 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
$free $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;
}
} }

View File

@ -337,6 +337,10 @@ class File extends DAV\Node implements DAV\IFile {
} }
} }
if(get_pconfig($this->auth->owner_id,'system','os_delete_prohibit') && \App::$module == 'dav') {
throw new DAV\Exception\Forbidden('Permission denied.');
}
attach_delete($this->auth->owner_id, $this->data['hash']); attach_delete($this->auth->owner_id, $this->data['hash']);
$ch = channelx_by_n($this->auth->owner_id); $ch = channelx_by_n($this->auth->owner_id);

View File

@ -21,6 +21,9 @@ class CheckJS {
$page = urlencode(\App::$query_string); $page = urlencode(\App::$query_string);
if($test) { if($test) {
self::$jsdisabled = 1;
if(array_key_exists('jsdisabled',$_COOKIE))
self::$jsdisabled = $_COOKIE['jsdisabled'];
if(! array_key_exists('jsdisabled',$_COOKIE)) { 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"; \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";

View File

@ -10,3 +10,4 @@ class Controller {
function get() {} function get() {}
} }

View File

@ -24,7 +24,8 @@ class SessionHandler implements \SessionHandlerInterface {
return $r[0]['sess_data']; return $r[0]['sess_data'];
} }
else { else {
q("INSERT INTO `session` (sid, expire) values ('%s', '%s')", q("INSERT INTO `session` (sess_data, sid, expire) values ('%s', '%s', '%s')",
dbesc(''),
dbesc($id), dbesc($id),
dbesc(time() + 300) dbesc(time() + 300)
); );

View File

@ -59,7 +59,14 @@ class WebServer {
\App::$query_string = strip_zids(\App::$query_string); \App::$query_string = strip_zids(\App::$query_string);
if(! local_channel()) { if(! local_channel()) {
$_SESSION['my_address'] = $_GET['zid']; $_SESSION['my_address'] = $_GET['zid'];
zid_init($a); zid_init();
}
}
if((x($_GET,'zat')) && (! \App::$install)) {
\App::$query_string = strip_zats(\App::$query_string);
if(! local_channel()) {
zat_init();
} }
} }

View File

@ -28,7 +28,7 @@ class Finger {
if (strpos($webbie,'@') === false) { if (strpos($webbie,'@') === false) {
$address = $webbie; $address = $webbie;
$host = App::get_hostname(); $host = \App::get_hostname();
} else { } else {
$address = substr($webbie,0,strpos($webbie,'@')); $address = substr($webbie,0,strpos($webbie,'@'));
$host = substr($webbie,strpos($webbie,'@')+1); $host = substr($webbie,strpos($webbie,'@')+1);

View File

@ -34,7 +34,6 @@ require_once('include/text.php');
require_once('include/datetime.php'); require_once('include/datetime.php');
require_once('include/language.php'); require_once('include/language.php');
require_once('include/nav.php'); require_once('include/nav.php');
require_once('include/cache.php');
require_once('include/permissions.php'); require_once('include/permissions.php');
require_once('library/Mobile_Detect/Mobile_Detect.php'); require_once('library/Mobile_Detect/Mobile_Detect.php');
require_once('include/features.php'); require_once('include/features.php');
@ -45,10 +44,10 @@ require_once('include/account.php');
define ( 'PLATFORM_NAME', 'hubzilla' ); define ( 'PLATFORM_NAME', 'hubzilla' );
define ( 'STD_VERSION', '1.8.1' ); define ( 'STD_VERSION', '1.10' );
define ( 'ZOT_REVISION', '1.1' ); define ( 'ZOT_REVISION', '1.1' );
define ( 'DB_UPDATE_VERSION', 1176 ); define ( 'DB_UPDATE_VERSION', 1180 );
/** /**
@ -771,6 +770,7 @@ class App {
public static $groups; public static $groups;
public static $language; public static $language;
public static $langsave; public static $langsave;
public static $rtl = false;
public static $plugins_admin; public static $plugins_admin;
public static $module_loaded = false; public static $module_loaded = false;
public static $query_string; public static $query_string;
@ -1703,7 +1703,7 @@ function login($register = false, $form_id = 'main-login', $hiddens=false) {
'$logout' => t('Logout'), '$logout' => t('Logout'),
'$login' => t('Login'), '$login' => t('Login'),
'$form_id' => $form_id, '$form_id' => $form_id,
'$lname' => array('username', t('Email') , '', ''), '$lname' => array('username', t('Login/Email') , '', ''),
'$lpassword' => array('password', t('Password'), '', ''), '$lpassword' => array('password', t('Password'), '', ''),
'$remember_me' => array('remember_me', t('Remember me'), '', '',array(t('No'),t('Yes'))), '$remember_me' => array('remember_me', t('Remember me'), '', '',array(t('No'),t('Yes'))),
'$hiddens' => $hiddens, '$hiddens' => $hiddens,
@ -2282,6 +2282,12 @@ function construct_page(&$a) {
$page = App::$page; $page = App::$page;
$profile = App::$profile; $profile = App::$profile;
// There's some experimental support for right-to-left text in the view/php/default.php page template.
// In v1.9 we started providing direction preference in the per language hstrings.php file
// This requires somebody with fluency in a RTL language to make happen
$page['direction'] = 0; // ((App::$rtl) ? 1 : 0);
header("Content-type: text/html; charset=utf-8"); header("Content-type: text/html; charset=utf-8");
// security headers - see https://securityheaders.io // security headers - see https://securityheaders.io
@ -2457,9 +2463,10 @@ function check_cron_broken() {
return; return;
} }
set_config('system','lastcroncheck',datetime_convert());
if(($d) && ($d > datetime_convert('UTC','UTC','now - 3 days'))) { if(($d) && ($d > datetime_convert('UTC','UTC','now - 3 days'))) {
// Scheduled tasks have run successfully in the last 3 days. // Scheduled tasks have run successfully in the last 3 days.
set_config('system','lastcroncheck',datetime_convert());
return; return;
} }

View File

@ -14,6 +14,7 @@
<li>[img float=right]https://zothub.com/images/default_profile_photos/rainbow_man/48.jpg[/img] <img src="https://zothub.com/images/default_profile_photos/rainbow_man/48.jpg" style="float:right;" alt="Image/photo" /><br /> <li>[img float=right]https://zothub.com/images/default_profile_photos/rainbow_man/48.jpg[/img] <img src="https://zothub.com/images/default_profile_photos/rainbow_man/48.jpg" style="float:right;" alt="Image/photo" /><br />
<div style="clear:both;"></div> <div style="clear:both;"></div>
<li>[code]code[/code] <code>code</code><br /> <li>[code]code[/code] <code>code</code><br />
<li>[code=xxx]syntax highlighted code[/code] <code>supported languages php, css, mysql, sql, abap, diff, html, perl, ruby, vbscript, avrc, dtd, java, xml, cpp, python, javascript, js, json, sh</code><br />
<li>[quote]quote[/quote] <blockquote>quote</blockquote><br /> <li>[quote]quote[/quote] <blockquote>quote</blockquote><br />
<li>[quote=Author]Author? Me? No, no, no...[/quote] <br /><strong class="author">Author wrote:</strong><blockquote>Author? Me? No, no, no...</blockquote><br /> <li>[quote=Author]Author? Me? No, no, no...[/quote] <br /><strong class="author">Author wrote:</strong><blockquote>Author? Me? No, no, no...</blockquote><br />
<li> [nobb] may be used to escape bbcode.</ul><br /> <li> [nobb] may be used to escape bbcode.</ul><br />
@ -83,7 +84,7 @@ or<br /><br />[dl terms="b"]<br />[*= First element term] First element descript
<li>[spoiler] for hiding spoilers<br /><br /></li> <li>[spoiler] for hiding spoilers<br /><br /></li>
<li>[rpost=title]Text to post[/rpost] The observer will be returned to their home hub to enter a post with the specified title and body. Both are optional</li> <li>[rpost=title]Text to post[/rpost] The observer will be returned to their home hub to enter a post with the specified title and body. Both are optional</li>
<li>[qr]text to post[/qr] - create a QR code.</li> <li>[qr]text to post[/qr] - create a QR code (if the qrator plugin is installed).</li>
<li>[toc] - create a table of content in a webpage. Please refer to the <a href="http://ndabas.github.io/toc/" target="_blank">original jquery toc</a> to get more explanations. <li>[toc] - create a table of content in a webpage. Please refer to the <a href="http://ndabas.github.io/toc/" target="_blank">original jquery toc</a> to get more explanations.
<ul> <ul>
<li>Optional param: 'data-toc'. If ommited the default is 'body'</li> <li>Optional param: 'data-toc'. If ommited the default is 'body'</li>

View File

@ -0,0 +1,10 @@
<dl class="dl-horizontal">
<dt>Allgemein</dt>
<dd>Jedes Wiki ist eine Sammlung aus mit Markdown formatierten Seiten.</dd>
<dt><a href="#" onclick='contextualHelpFocus("#wiki_list", 1); return false;' title="Click to highlight element...">Wiki Liste</a></dt>
<dd>Wikis die dem eigenen Kanal gehören und <i>mit der Berechtigung zum Anschauen</i>, sind in der Seitenleiste gelistet.</dd>
<dt><a href="#" onclick='contextualHelpFocus("#wiki-get-history", 0); return false;' title="Click to highlight element...">Seiten Versionen</a></dt>
<dd>Jede Änderung einer Seite wird gespeichert, um eine schnelle Berichtigung zu ermöglichen. Klick auf das <b>Versionsgeschichte</b> Tab um den Verlauf der Seitenbearbeitung zu sehen, einschließlich Datum und Autor. Der Zurück-Knopf lädt die ausgewählte Änderung, aber ohne die Seite automatisch zu spreichern.</dd>
<dt><a href="#" onclick='contextualHelpFocus("#wiki_page_list", 1); return false;' title="Click to highlight element...">Seiten</a></dt>
<dd>Die Seiten des Wikis werden in <b>Wiki Seiten</b> gelistet. Vor dem Speichern einer Seite über das <b>Seiten</b> Dropdown Menu, hast Du die Möglichkeit eine <a href="#" onclick='contextualHelpFocus("#id_commitMsg", 0); return false;' title="Click to highlight element...">Zusammenfassung der Änderungen</a> einzutragen. Dieser Text wird anschließend unter <a href="#" onclick='contextualHelpFocus("#wiki-get-history", 0); return false;' title="Click to highlight element..."><b>Seiten Versionen</b></a> in der Versionsgeschichte angezeigt.</dd>
</dl>

View File

@ -0,0 +1,10 @@
<dl class="dl-horizontal">
<dt>General</dt>
<dd>Each wiki is a collection of pages, composed as Markdown-formatted text files.</dd>
<dt><a href='#' onclick='contextualHelpFocus("#wiki_list", 1); return false;' title="Click to highlight element...">Wiki List</a></dt>
<dd>Wikis owned by the channel <i>that you have permission to view</i> are listed in the side panel.</dd>
<dt><a href='#' onclick='contextualHelpFocus("#wiki-get-history", 0); return false;' title="Click to highlight element...">Page History</a></dt>
<dd>Every revision of a page is saved to allow quick reversion. Click the <b>History</b> tab to view a history of page revisions, including the date and author of each. The revert button will load the selected revision but will not automatically save the page.</dd>
<dt><a href='#' onclick='contextualHelpFocus("#wiki_page_list", 1); return false;' title="Click to highlight element...">Pages</a></dt>
<dd>The list of pages in the wiki are listed in the <b>Wiki Pages</b> panel. Prior to saving page edits using the <b>Page</b> control dropdown menu, you may <a href='#' onclick='contextualHelpFocus("#id_commitMsg", 0); return false;' title="Click to highlight element...">enter a custom message</a> to be displayed in the <a href='#' onclick='contextualHelpFocus("#wiki-get-history", 0); return false;' title="Click to highlight element..."><b>Page History</b></a> viewer along with the revision.</dd>
</dl>

View File

@ -0,0 +1,10 @@
<dl class="dl-horizontal">
<dt>General</dt>
<dd>Cada wiki es una colección de páginas, compuestas como ficheros de texto formateados en Markdown.</dd>
<dt><a href='#' onclick='contextualHelpFocus("#wiki_list", 1); return false;' title="Pulsar para resaltar el elemento...">Lista de wikis</a></dt>
<dd>Las páginas wiki propiedad del canal <i>que esté autorizado a ver</i> aparecen en el panel lateral.</dd>
<dt><a href='#' onclick='contextualHelpFocus("#wiki-get-history", 0); return false;' title="Pulsar para resaltar el elemento...">Historial de la página</a></dt>
<dd>Cada revisión de una página se salva para permitir su rápida recuperación. Pulsar en la pestaña <b>Historial</b> para ver las revisiones de la página, incluyendo la fecha y el autor de cada una. El botón de reversión cargará la revisión seleccionada, pero no salvará automáticamente la página.</dd>
<dt><a href='#' onclick='contextualHelpFocus("#wiki_page_list", 1); return false;' title="Pulsar para resaltar el elemento...">Páginas</a></dt>
<dd>La lista de páginas en el wiki aparece en el panel <b>Páginas del wiki</b>. Antes de salvar las páginas editadas usando el control <b>Página</b> en el menú desplegable, puede <a href='#' onclick='contextualHelpFocus("#id_commitMsg", 0); return false;' title="Pulsar para resaltar el elemento...">escribir un mensaje personalizado</a> que se verá en el visor <a href='#' onclick='contextualHelpFocus("#wiki-get-history", 0); return false;' title="Pulsar para resaltar el elemento..."><b>Historial de la página</b></a> junto con la revisión.</dd>
</dl>

View File

@ -0,0 +1,10 @@
<dl class="dl-horizontal">
<dt>General</dt>
<dd>Ogni wiki è una raccolta di pagine, composta di file di testo formattati con Markdown.</dd>
<dt><a href="#" onclick='contextualHelpFocus("#wiki_list", 1); return false;' title="Fai click per evidenziare l'elemento...">Elenco dei Wiki</a></dt>
<dd>I Wiki del canale <i>che sei abilitato a vedere</i> sono elencati nel pannello laterale.</dd>
<dt><a href="#" onclick='contextualHelpFocus("#wiki-get-history", 0); return false;' title="Fai click per evidenziare l'elemento...">Cronologia della pagina</a></dt>
<dd>Le revisioni di ogni pagina vengono salvate per rendere possibile un ripristino veloce. Fai click sulla tab <b>Cronologia</b> per vedere l'elenco delle revisioni, con autore e data delle stesse. Il bottone di ripristino riporterà alla revisione selezionata, senza salvare automaticamente la pagina.</dd>
<dt><a href="#" onclick='contextualHelpFocus("#wiki_page_list", 1); return false;' title="Fai click per evidenziare l'elemento...">Pagine</a></dt>
<dd>L'elenco delle pagine del wiki si trova nel pannello <b>Pagine del wiki</b>. Prima di salvare le modifiche con il menu a discela <b>Pagina</b>, puoi <a href="#" onclick='contextualHelpFocus("#id_commitMsg", 0); return false;' title="Fai click per evidenziare l'elemento...">inserire un messaggio</a> che verrà visualizzato nella visualizzazione della <a href="#" onclick='contextualHelpFocus("#wiki-get-history", 0); return false;' title="Fai click per evidenziare l'elemento..."><b>storia della pagina</b></a> insieme alla revisione.</dd>
</dl>

View File

@ -1,6 +1,7 @@
[h2]Database Tables[/h2] [h2]Database Tables[/h2]
[table] [table]
[tr][th]Table[/th][th]Description[/th][/tr] [tr][th]Table[/th][th]Description[/th][/tr]
[tr][td][zrl=[baseurl]/help/database/db_abconfig]abconfig[/zrl][/td][td]arbitrary storage for connections of local channels[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_abook]abook[/zrl][/td][td]connections of local channels[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_abook]abook[/zrl][/td][td]connections of local channels[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_account]account[/zrl][/td][td]service provider account[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_account]account[/zrl][/td][td]service provider account[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_addon]addon[/zrl][/td][td]registered plugins[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_addon]addon[/zrl][/td][td]registered plugins[/td][/tr]
@ -8,6 +9,7 @@
[tr][td][zrl=[baseurl]/help/database/db_attach]attach[/zrl][/td][td]file attachments[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_attach]attach[/zrl][/td][td]file attachments[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_auth_codes]auth_codes[/zrl][/td][td]OAuth usage[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_auth_codes]auth_codes[/zrl][/td][td]OAuth usage[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_cache]cache[/zrl][/td][td]OEmbed cache[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_cache]cache[/zrl][/td][td]OEmbed cache[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_cal]cal[/zrl][/td][td]CalDAV containers for events[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_channel]channel[/zrl][/td][td]local channels[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_channel]channel[/zrl][/td][td]local channels[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_chat]chat[/zrl][/td][td]chat room content[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_chat]chat[/zrl][/td][td]chat room content[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_chatpresence]chatpresence[/zrl][/td][td]channel presence information for chat[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_chatpresence]chatpresence[/zrl][/td][td]channel presence information for chat[/td][/tr]
@ -16,17 +18,14 @@
[tr][td][zrl=[baseurl]/help/database/db_config]config[/zrl][/td][td]main configuration storage[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_config]config[/zrl][/td][td]main configuration storage[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_conv]conv[/zrl][/td][td]Diaspora private messages meta conversation structure[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_conv]conv[/zrl][/td][td]Diaspora private messages meta conversation structure[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_event]event[/zrl][/td][td]Events[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_event]event[/zrl][/td][td]Events[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_fcontact]fcontact[/zrl][/td][td]friend suggestion stuff (obsolete)[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_ffinder]ffinder[/zrl][/td][td]friend suggestion stuff (obsolete)[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_fserver]fserver[/zrl][/td][td]obsolete[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_fsuggest]fsuggest[/zrl][/td][td]friend suggestion stuff (unused)[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_group_member]group_member[/zrl][/td][td]privacy groups (collections), group info[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_group_member]group_member[/zrl][/td][td]privacy groups (collections), group info[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_groups]groups[/zrl][/td][td]privacy groups (collections), member info[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_groups]groups[/zrl][/td][td]privacy groups (collections), member info[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_hook]hook[/zrl][/td][td]plugin hook registry[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_hook]hook[/zrl][/td][td]plugin hook registry[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_hubloc]hubloc[/zrl][/td][td]xchan location storage, ties a hub location to an xchan[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_hubloc]hubloc[/zrl][/td][td]xchan location storage, ties a hub location to an xchan[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_iconfig]iconfig[/zrl][/td][td]extensible arbitrary storage for items[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_issue]issue[/zrl][/td][td]future bug/issue database[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_issue]issue[/zrl][/td][td]future bug/issue database[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_item]item[/zrl][/td][td]all posts and webpages[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_item]item[/zrl][/td][td]all posts and webpages[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_item_id]item_id[/zrl][/td][td]other identifiers on other services for posts[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_item_id]item_id[/zrl][/td][td](deprecated by iconfig) other identifiers on other services for posts[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_likes]likes[/zrl][/td][td]likes of 'things'[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_likes]likes[/zrl][/td][td]likes of 'things'[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_mail]mail[/zrl][/td][td]private messages[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_mail]mail[/zrl][/td][td]private messages[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_menu]menu[/zrl][/td][td]webpage menu data[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_menu]menu[/zrl][/td][td]webpage menu data[/td][/tr]
@ -48,7 +47,6 @@
[tr][td][zrl=[baseurl]/help/database/db_sign]sign[/zrl][/td][td]Diaspora signatures. To be phased out.[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_sign]sign[/zrl][/td][td]Diaspora signatures. To be phased out.[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_site]site[/zrl][/td][td]site table to find directory peers[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_site]site[/zrl][/td][td]site table to find directory peers[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_source]source[/zrl][/td][td]channel sources data[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_source]source[/zrl][/td][td]channel sources data[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_spam]spam[/zrl][/td][td]unfinished[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_sys_perms]sys_perms[/zrl][/td][td]extensible permissions for OAuth[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_sys_perms]sys_perms[/zrl][/td][td]extensible permissions for OAuth[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_term]term[/zrl][/td][td]item taxonomy (categories, tags, etc.) table[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_term]term[/zrl][/td][td]item taxonomy (categories, tags, etc.) table[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_tokens]tokens[/zrl][/td][td]OAuth usage[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_tokens]tokens[/zrl][/td][td]OAuth usage[/td][/tr]
@ -60,6 +58,7 @@
[tr][td][zrl=[baseurl]/help/database/db_xconfig]xconfig[/zrl][/td][td]as pconfig but for channels with no local account[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_xconfig]xconfig[/zrl][/td][td]as pconfig but for channels with no local account[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_xign]xign[/zrl][/td][td]channels ignored by friend suggestions[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_xign]xign[/zrl][/td][td]channels ignored by friend suggestions[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_xlink]xlink[/zrl][/td][td]"friends of friends" linkages derived from poco, also ratings storage[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_xlink]xlink[/zrl][/td][td]"friends of friends" linkages derived from poco, also ratings storage[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_xperm]xperm[/zrl][/td][td]OAuth/OpenID-Connect extensible permissions permissions storage[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_xprof]xprof[/zrl][/td][td]if this hub is a directory server, contains basic public profile info of everybody in the network[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_xprof]xprof[/zrl][/td][td]if this hub is a directory server, contains basic public profile info of everybody in the network[/td][/tr]
[tr][td][zrl=[baseurl]/help/database/db_xtag]xtag[/zrl][/td][td]if this hub is a directory server, contains tags or interests of everybody in the network[/td][/tr] [tr][td][zrl=[baseurl]/help/database/db_xtag]xtag[/zrl][/td][td]if this hub is a directory server, contains tags or interests of everybody in the network[/td][/tr]
[/table] [/table]

View File

@ -15,10 +15,6 @@
[/td][/tr] [/td][/tr]
[tr][td]abook_closeness[/td][td]"closeness" value for optional affinity tool, 0-99[/td][td]tinyint(3) unsigned[/td][td]NO[/td][td]MUL[/td][td]99[/td][td] [tr][td]abook_closeness[/td][td]"closeness" value for optional affinity tool, 0-99[/td][td]tinyint(3) unsigned[/td][td]NO[/td][td]MUL[/td][td]99[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]abook_rating[/td][td]The channel owner's (public) rating of this connection -10 to +10, default 0 or unrated[/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr]
[tr][td]abook_rating_text[/td][td]The channel owner's (public) rating of this connection free form text[/td][td]text[/td][td]NO[/td][td]MUL[/td][td][/td][td]
[/td][/tr]
[tr][td]abook_created[/td][td]Datetime this record was created[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] [tr][td]abook_created[/td][td]Datetime this record was created[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]abook_updated[/td][td]Datetime this record was modified[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] [tr][td]abook_updated[/td][td]Datetime this record was modified[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td]
@ -32,16 +28,27 @@
[tr][td]abook_profile[/td][td]profile.guid of profile to display to this connection if authenticated[/td][td]char(64)[/td][td]NO[/td][td]MUL[/td][td][/td][td] [tr][td]abook_profile[/td][td]profile.guid of profile to display to this connection if authenticated[/td][td]char(64)[/td][td]NO[/td][td]MUL[/td][td][/td][td]
[/td][/tr] [/td][/tr]
[tr][td]abook_blocked[/td][td]Bi-directional communications with this channel are blocked, regardless of other permissions. [/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]abook_blocked[/td][td]Bi-directional communications with this channel are blocked, regardless of other permissions. [/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr]
[tr][td]abook_ignored[/td][td]Incoming communications from this channel are blocked, regardless of other permissions. [/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]abook_ignored[/td][td]Incoming communications from this channel are blocked, regardless of other permissions. [/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr]
[tr][td]abook_hidden[/td][td]This connection will not be shown as a connection to anybody but the channel owner[/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]abook_hidden[/td][td]This connection will not be shown as a connection to anybody but the channel owner[/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr]
[tr][td]abook_archived[/td][td]This connection is likely non-functioning and the entry and conversations are preserved, but further polled communications will not be attempted. [/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]abook_archived[/td][td]This connection is likely non-functioning and the entry and conversations are preserved, but further polled communications will not be attempted. [/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr]
[tr][td]abook_pending[/td][td]A connection request was received from this channel but has not been approved by the channel owner, public communications may still be visible but no additional permissions have been granted. [/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]abook_pending[/td][td]A connection request was received from this channel but has not been approved by the channel owner, public communications may still be visible but no additional permissions have been granted. [/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr]
[tr][td]abook_unconnected[/td][td]currently unused. Projected usage is to indicate "one-way" connections which were insitgated on this end but are still pending on the remote end. [/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]abook_unconnected[/td][td]currently unused. Projected usage is to indicate "one-way" connections which were insitgated on this end but are still pending on the remote end. [/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr]
[tr][td]abook_self[/td][td]is a special case where the owner is the target. Every channel has one abook entry with abook_self and with a target abook_xchan set to channel.channel_hash . When this flag is present, abook_my_perms is the default permissions granted to all new connections and several other fields are unused.[/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]abook_self[/td][td]is a special case where the owner is the target. Every channel has one abook entry with abook_self and with a target abook_xchan set to channel.channel_hash . When this flag is present, abook_my_perms is the default permissions granted to all new connections and several other fields are unused.[/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr]
[tr][td]abook_feed[/td][td]indicates this connection is an RSS/Atom feed and may trigger special handling.[/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]abook_feed[/td][td]indicates this connection is an RSS/Atom feed and may trigger special handling.[/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr]
[tr][td]abook_incl[/td][td]connection filter allow rules separated by LF[/td][td]text[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]abook_incl[/td][td]connection filter allow rules separated by LF[/td][td]text[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr]
[tr][td]abook_excl[/td][td]connection filter deny rules separated by LF[/td][td]text[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]abook_excl[/td][td]connection filter deny rules separated by LF[/td][td]text[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr]
[tr][td]abook_instance[/td][td]comma separated list of site urls of all channel clones that this connection is connected with (used only for singleton networks which don't support cloning)[/td][td]text[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]abook_instance[/td][td]comma separated list of site urls of all channel clones that this connection is connected with (used only for singleton networks which don't support cloning)[/td][td]text[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr]
[/table] [/table]

View File

@ -3,7 +3,7 @@
[/th][/tr] [/th][/tr]
[tr][td]id[/td][td][/td]generated index[td]int(11)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment [tr][td]id[/td][td][/td]generated index[td]int(11)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment
[/td][/tr] [/td][/tr]
[tr][td]name[/td][td]plugin base (file)name[/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] [tr][td]aname[/td][td]plugin base (file)name[/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]version[/td][td]currently unused[/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] [tr][td]version[/td][td]currently unused[/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
@ -11,7 +11,7 @@
[/td][/tr] [/td][/tr]
[tr][td]hidden[/td][td]currently unused[/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]hidden[/td][td]currently unused[/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]timestamp[/td][td]file timestamp to check for reloads[/td][td]bigint(20)[/td][td]NO[/td][td][/td][td]0[/td][td] [tr][td]tstamp[/td][td]file timestamp to check for reloads[/td][td]bigint(20)[/td][td]NO[/td][td][/td][td]0[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]plugin_admin[/td][td]1 = has admin config, 0 = has no admin config[/td][td]tinyint(1)[/td][td]NO[/td][td][/td][td]0[/td][td] [tr][td]plugin_admin[/td][td]1 = has admin config, 0 = has no admin config[/td][td]tinyint(1)[/td][td]NO[/td][td][/td][td]0[/td][td]
[/td][/tr] [/td][/tr]

View File

@ -27,8 +27,20 @@
[/td][/tr] [/td][/tr]
[tr][td]app_page[/td][td]currently unused[/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] [tr][td]app_page[/td][td]currently unused[/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td]
[/td][/tr] [/td][/tr]
[tr][td]app_requires[/td][td]currently unused[/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] [tr][td]app_requires[/td][td]access rules[/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td]
[/td][/tr] [/td][/tr]
[tr][td]app_created[/td][td]datetime of app creation[/td][td]datetime[/td][td]NO[/td][td][/td][td][/td][td]
[/td][/tr]
[tr][td]app_edited[/td][td]datetime of last app edit[/td][td]datetime[/td][td]NO[/td][td][/td][td][/td][td]
[/td][/tr]
[tr][td]app_deleted[/td][td]1 = deleted, 0 = normal[/td][td]int(11)[/td][td]NO[/td][td][/td][td][/td][td]
[/td][/tr]
[tr][td]app_system[/td][td]1 = imported system app, 0 = member created app[/td][td]int(11)[/td][td]NO[/td][td][/td][td][/td][td]
[/td][/tr]
[/table] [/table]
Storage for personal apps Storage for personal apps

View File

@ -29,9 +29,11 @@
[/td][/tr] [/td][/tr]
[tr][td]os_storage[/td][td]if 0, data contains content; if 1 data contains path to content (always 1 in hubzilla)[/td][td]tinyint[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]os_storage[/td][td]if 0, data contains content; if 1 data contains path to content (always 1 in hubzilla)[/td][td]tinyint[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]os_path[/td][td]under construction, store the system path[/td][td]mediumtext[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr]
[tr][td]display_path[/td][td]under construction, store the human readable path[/td][td]mediumtext[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]display_path[/td][td]under construction, store the human readable path[/td][td]mediumtext[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]data[/td][td]file data or pathname to stored data if ATTACH_FLAG_OS[/td][td]longblob[/td][td]NO[/td][td][/td][td]NULL[/td][td] [tr][td]content[/td][td]file data or pathname to stored data if ATTACH_FLAG_OS[/td][td]longblob[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]created[/td][td]creation time[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] [tr][td]created[/td][td]creation time[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td]
[/td][/tr] [/td][/tr]

View File

@ -35,6 +35,8 @@
[/td][/tr] [/td][/tr]
[tr][td]channel_dirdate[/td][td]time when directory was last pinged. Must do this once a month[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] [tr][td]channel_dirdate[/td][td]time when directory was last pinged. Must do this once a month[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]channel_lastpost[/td][td]date of last post for this channel. May not be fully implemented[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td]
[/td][/tr]
[tr][td]channel_deleted[/td][td]time when channel was deleted[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] [tr][td]channel_deleted[/td][td]time when channel was deleted[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]channel_max_anon_mail[/td][td]unused[/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]10[/td][td] [tr][td]channel_max_anon_mail[/td][td]unused[/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]10[/td][td]
@ -95,6 +97,8 @@
[/td][/tr] [/td][/tr]
[tr][td]channel_system[/td][td]if 1, this is the special system channel on this site[/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] [tr][td]channel_system[/td][td]if 1, this is the special system channel on this site[/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]channel_moved[/td][td]URL of relocated channel, making this instance abandoned if set[/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td]
[/td][/tr]
[/table] [/table]
Return to [zrl=[baseurl]/help/database]database documentation[/zrl] Return to [zrl=[baseurl]/help/database]database documentation[/zrl]

View File

@ -11,7 +11,7 @@
[/td][/tr] [/td][/tr]
[tr][td]cp_status[/td][td]text status description e.g. "online"[/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] [tr][td]cp_status[/td][td]text status description e.g. "online"[/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]cp_client[/td][td][/td]IP address of this client[td]char(128)[/td][td]NO[/td][td][/td][td][/td][td] [tr][td]cp_client[/td][td]IP address of this client[/td][td]char(128)[/td][td]NO[/td][td][/td][td][/td][td]
[/td][/tr] [/td][/tr]
[/table] [/table]

View File

@ -7,7 +7,7 @@
[/td][/tr] [/td][/tr]
[tr][td]redirect_uri[/td][td][/td][td]varchar(200)[/td][td]NO[/td][td][/td][td]NULL[/td][td] [tr][td]redirect_uri[/td][td][/td][td]varchar(200)[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]name[/td][td][/td][td]text[/td][td]YES[/td][td][/td][td]NULL[/td][td] [tr][td]clname[/td][td][/td][td]text[/td][td]YES[/td][td][/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]icon[/td][td][/td][td]text[/td][td]YES[/td][td][/td][td]NULL[/td][td] [tr][td]icon[/td][td][/td][td]text[/td][td]YES[/td][td][/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]

View File

@ -15,9 +15,9 @@
[/td][/tr] [/td][/tr]
[tr][td]edited[/td][td][/td][td]datetime[/td][td]NO[/td][td][/td][td]NULL[/td][td] [tr][td]edited[/td][td][/td][td]datetime[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]start[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] [tr][td]dtstart[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]finish[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] [tr][td]dtend[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]summary[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] [tr][td]summary[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
@ -25,13 +25,13 @@
[/td][/tr] [/td][/tr]
[tr][td]location[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] [tr][td]location[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]type[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] [tr][td]etype[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]nofinish[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]nofinish[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]adjust[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]1[/td][td] [tr][td]adjust[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]1[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]ignore[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]dismissed[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]allow_cid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] [tr][td]allow_cid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
@ -41,6 +41,24 @@
[/td][/tr] [/td][/tr]
[tr][td]deny_gid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] [tr][td]deny_gid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]event_status[/td][td][/td][td]charr(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr]
[tr][td]event_status_date[/td][td][/td][td]datetime[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr]
[tr][td]event_percent[/td][td][/td][td]smallint(6)[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr]
[tr][td]event_repeat[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr]
[tr][td]event_sequence[/td][td][/td][td]smallint[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr]
[tr][td]event_priority[/td][td][/td][td]smallint[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr]
[tr][td]event_vdata[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr]
[tr][td]cal_id[/td][td][/td][td]int(10)[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr]
[/table] [/table]
Return to [zrl=[baseurl]/help/database]database documentation[/zrl] Return to [zrl=[baseurl]/help/database]database documentation[/zrl]

View File

@ -11,7 +11,7 @@
[/td][/tr] [/td][/tr]
[tr][td]deleted[/td][td]1 indicates the group has been deleted[/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] [tr][td]deleted[/td][td]1 indicates the group has been deleted[/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]name[/td][td]human readable name of group[/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] [tr][td]gname[/td][td]human readable name of group[/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
[/table] [/table]

View File

@ -7,9 +7,11 @@
[/td][/tr] [/td][/tr]
[tr][td]file[/td][td]relative filename of hook handler[/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] [tr][td]file[/td][td]relative filename of hook handler[/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]function[/td][td]function name of hook handler[/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] [tr][td]fn[/td][td]function name of hook handler[/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]priority[/td][td]not yet implemented - can be used to sort conflicts in hook handling by calling handlers in priority order[/td][td]int(11) unsigned[/td][td]NO[/td][td][/td][td]0[/td][td] [tr][td]priority[/td][td]can be used to sort conflicts in hook handling by calling handlers in priority order[/td][td]int(11) unsigned[/td][td]NO[/td][td][/td][td]0[/td][td]
[/td][/tr]
[tr][td]hook_version[/td][td]version 0 hooks must have two arguments, the App and the hook data. version 1 hooks have 1 argument - the hook data[/td][td]int(11) unsigned[/td][td]NO[/td][td][/td][td]0[/td][td]
[/td][/tr] [/td][/tr]
[/table] [/table]

View File

@ -51,7 +51,7 @@
[/td][/tr] [/td][/tr]
[tr][td]obj_type[/td][td]ActivityStreams object type (old style URI)[/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] [tr][td]obj_type[/td][td]ActivityStreams object type (old style URI)[/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td]
[/td][/tr] [/td][/tr]
[tr][td]object[/td][td]JSON encoded object structure unless it is an implied object (normal post)[/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] [tr][td]obj[/td][td]JSON encoded object structure unless it is an implied object (normal post)[/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td]
[/td][/tr] [/td][/tr]
[tr][td]tgt_type[/td][td]ActivityStreams target type if applicable (URI)[/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] [tr][td]tgt_type[/td][td]ActivityStreams target type if applicable (URI)[/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td]
[/td][/tr] [/td][/tr]

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