Merge branch '3.6RC'

This commit is contained in:
Mario Vavti 2018-07-25 10:19:19 +02:00
commit 1b1d11dcf1
459 changed files with 35374 additions and 22655 deletions

View File

@ -39,7 +39,7 @@ Software
- mkdir -p /var/www
- cd /var/www
- git clone https://github.com/redmatrix/hubzilla.git html
- cd /html/.homeinstall
- cd html/.homeinstall
- cp hubzilla-config.txt.template hubzilla-config.txt
- nano hubzilla-config.txt
- Read the comments carefully
@ -50,6 +50,20 @@ Software
- reboot
+ Open your domain with a browser and step throught the initial configuration of hubzilla.
## Troubleshooting
If the check of the mail address fails when you try to register the very first user in the browser. Do...
cd /var/www/html
util/config system.do_not_check_dns 1
## Optional - Set path to imagemagick
In Admin settings of hubzilla or via terminal
cd /var/www/html
util/config system.imagick_convert_path /usr/bin/convert
# Step-by-Step in Detail
## Preparations Hardware
@ -120,7 +134,7 @@ There are two ways to get a domain...
The cost are around 10,- € once and 1,50 € per month (2017).
The cost are around 10,- € once and 1,50 € per month (2017).
### Method 2: Register a free subdomain
...for example register at freedns.afraid.org
@ -150,7 +164,7 @@ Make the directory for apache and change diretory to it
Clone hubzilla from git ("git pull" will update it later)
git clone https://github.com/redmatrix/hubzilla html
git clone https://framagit.org/hubzilla/core html
Change to the install script
@ -189,9 +203,16 @@ Leave db type "MySQL" untouched.
Follow the instructions in the next pages.
Recommended: Set path to imagemagick
- in admin settings of hubzilla or
- via terminal
util/config system.imagick_convert_path /usr/bin/convert
After the daily script was executed at 05:30 (am)
- look at var/www/html/hubzilla-daily.log
- look at /var/www/html/hubzilla-daily.log
- check your backup on the external drive
- optionally view the daily log under yourdomain.org/admin/logs/
- set the logfile to var/www/html/hubzilla-daily.log
@ -213,4 +234,12 @@ to boot the Rapsi to the client console.
DO NOT FORGET TO CHANGE THE DEFAULT PASSWORD FOR USER PI!
On a Raspian Stretch (Debian 9) the validation of the mail address fails for the very first user.
This used to happen on some *bsd distros but there was some work to fix that a year ago (2017).
So if your system isn't registered in DNS or DNS isn't active do
cd /var/www/html
util/config system.do_not_check_dns 1

View File

@ -136,17 +136,17 @@ function check_config {
# backup is important and should be checked
if [ -n "$backup_device_name" ]
then
device_mounted=0
if [ ! -d "$backup_mount_point" ]
then
mkdir "$backup_mount_point"
fi
device_mounted=0
if fdisk -l | grep -i "$backup_device_name.*linux"
then
print_info "ok - filesystem of external device is linux"
if [ -n "$backup_device_pass" ]
then
echo "$backup_device_pass" | cryptsetup luksOpen $backup_device_name cryptobackup
if [ ! -d /media/hubzilla_backup ]
then
mkdir /media/hubzilla_backup
fi
if mount /dev/mapper/cryptobackup /media/hubzilla_backup
then
device_mounted=1
@ -246,6 +246,11 @@ function install_apache {
nocheck_install "apache2 apache2-utils"
}
function install_imagemagick {
print_info "installing imagemagick..."
nocheck_install "imagemagick"
}
function install_curl {
print_info "installing curl..."
nocheck_install "curl"
@ -567,7 +572,7 @@ function check_https {
function install_hubzilla {
print_info "installing hubzilla addons..."
cd /var/www/html/
util/add_addon_repo https://github.com/redmatrix/hubzilla-addons.git hzaddons
util/add_addon_repo https://framagit.org/hubzilla/addons.git hzaddons
mkdir -p "store/[data]/smarty3"
chmod -R 777 store
touch .htconfig.php
@ -801,6 +806,7 @@ update_upgrade
install_curl
install_sendmail
install_apache
install_imagemagick
install_php
install_mysql
install_phpmyadmin

View File

@ -1,3 +1,97 @@
Hubzilla 3.6 (????-??-??)
- Update jquery.timeago library
- Implement Hookable CSP
- ActivityStreams: accept header changes to support plume
- Streamline inconsistencies in addon naming
- SECURITY: hash the session_id in logs
- Update justified gallery library
- Hide channel in /cloud root if channel is hidden in directory
- Add resend option to channel sources tp discard original author.
- Provide flag to exclude privacy groups for federation plugin use in collect_recipients()
- Upgrading from redmatrix is no longer supported
- Deal with htmlentity encoding during authentication workflow
- Rework mod group
- Make droping posts of removed connections more memory efficient
- Refactor getOutainfo() for DAV storage
- Optionally report total available space when uploading
- SECURITY: provide option to disable the cloud 'root' directory and make the cloud module require a target channel nickname
- Add plink and llink to viewsource
- Add new 'filter by name' feature
- Remove network tabs
- New activity filter widget
- New activity order widget
- Make menus editable by visitors with webpage write permissions
- Move forum notifications to notifications
- Move manage privacy groups to the panel channel menu
- Don't remove items that are starred, filed, or that you replied to when removing a connection
- Don't deliver local items more than once
- Make navbar search use the module search function in /network and /channel
- Paint the locks on private activitypub items red. Their privacy model is "slightly" different from hubzillas
- Improve new channel creation workflow
- Add hook 'get_system_apps'
- Implement reset button for jot
- Adjust accept header to make pleroma happy
- Provide a general purpose GDPR document
- Provide function to fetch photo contents from url
- Make get_default_profile_photo() pluggable
- Refactor tags/mentions
- Refactor autocomplete mechanism
- Display pubsites link in info area if invite only
- Add cancel button to editor
- Implement MessageFilter for pubstream and sourced messages
- Add supported protocols to siteinfo
- Allow pdf embeds
- Allow uninstall of plugins which no longer exists via cmdline tool
- Improve the homeinstall script
- Provide easy access to the autoperms setting for forum and repository channels
- Implement admin delete of files, photos and posts
- Allow a different username to be used when importing a channel
- Provide warnings about profile photo and cover photo permissions
- Set the 'force' flag on attach_mkdir when initiated from a DAV operation
Bugfixes
- Fix double file uploads when dropping files into jot
- Fix jot collapsing when drag and drop to open jot
- Fix wrong album name when moving photos
- Fix wrong timestamp localization before first update in mod mail
- Fix post exiration not propagated to other networks (which support it)
- Fix sys channels visible in dirsearch
- Fix remote_self not working correctly
- Fix photos not syncing properly if destination is a postgres site
- Fix wrong hubloc_url for activitypub hublocs
- Fix z_check_dns() for BSD
- Fix not null violation in oauth1
- Fix DB issues with oauth2 on postgresql
- Fix 'anybody authenticated' not correctly handled in can_comment_on_post()
- Fix postgres issue if register mode is set to yes - with approval
- Fix tag search not finding articles
- Fix issue with mentions when markdown post addon is enabled
- Fix duplicate addressbook entries on repeated channel imports
Addons
- Cart: various display improvements
- Cart: make cart work with postgresql DB backend
- Cart: add new hzservice for service_classes
- Cart: add storewide currency settings
- Cart: provide channel app 'Shop' for cart addon
- Cart: implement order updating
- Cart: use CSP hook for paypals checkout.js
- Cart: provide a cancel mechanism for orders
- Cart: add paypal button
- Gallery: new addon to display photo albums with the photoswipe library
- Ldapauth: optionally auto create channel
- Pubcrawl: new setting to ignore ActivityPub recipients in privacy groups
- Diaspora: fix issue with displaying multiple photos
- Pubcrawl: provide plink
- Pubcrawl: hubloc_url should be baseurl, not actor url
- Pubcrawl: deliver restricted posts from hubzilla as direct messages (there is no other way to address only a subset of followers in mastodon)
- Pubcrawl: address comments to a restricted mastodon post to /followers
Hubzilla 3.4.2 (2018-07-19)
- Compatibility fix for future versions
Hubzilla 3.4.1 (2018-06-08)
- Say bye, bye to GitHub and move sourcecode repositories to #^https://framagit.org/hubzilla
- When removing a connection, don't remove items that are starred, filed or replied to

View File

@ -5,7 +5,7 @@ Hubzilla - Community Server
<p align="center" markdown="1">
<em><a href="install/INSTALL.txt">Installing Hubzilla</a></em>
<em><a href="https://framagit.org/hubzilla/core/blob/master/install/INSTALL.txt">Installing Hubzilla</a></em>
</p>
**What is Hubzilla?**

View File

@ -308,6 +308,8 @@ class PermissionRoles {
]
];
call_hooks('list_permission_roles',$roles);
return $roles;
}

View File

@ -67,7 +67,7 @@ class Permissions {
'post_comments' => t('Can comment on or like my posts'),
'post_mail' => t('Can send me private mail messages'),
'post_like' => t('Can like/dislike profiles and profile things'),
'tag_deliver' => t('Can forward to all my channel connections via @+ mentions in posts'),
'tag_deliver' => t('Can forward to all my channel connections via ! mentions in posts'),
'chat' => t('Can chat with me'),
'republish' => t('Can source my public posts in derived channels'),
'delegate' => t('Can administer my channel')

View File

@ -50,14 +50,19 @@ class Cron {
// expire any expired items
$r = q("select id from item where expires > '2001-01-01 00:00:00' and expires < %s
$r = q("select id,item_wall from item where expires > '2001-01-01 00:00:00' and expires < %s
and item_deleted = 0 ",
db_utcnow()
);
if($r) {
require_once('include/items.php');
foreach($r as $rr)
drop_item($rr['id'],false);
foreach($r as $rr) {
drop_item($rr['id'],false,(($rr['item_wall']) ? DROPITEM_PHASE1 : DROPITEM_NORMAL));
if($rr['item_wall']) {
// The notifier isn't normally invoked unless item_drop is interactive.
Zotlabs\Daemon\Master::Summon( [ 'Notifier', 'drop', $rr['id'] ] );
}
}
}

View File

@ -71,14 +71,18 @@ class Poller {
$randfunc = db_getfunc('RAND');
$contacts = q("SELECT * FROM abook LEFT JOIN xchan on abook_xchan = xchan_hash
$contacts = q("SELECT abook.abook_updated, abook.abook_connected, abook.abook_feed,
abook.abook_channel, abook.abook_id, abook.abook_archived, abook.abook_pending,
abook.abook_ignored, abook.abook_blocked,
xchan.xchan_network,
account.account_lastlog, account.account_flags
FROM abook LEFT JOIN xchan on abook_xchan = xchan_hash
LEFT JOIN account on abook_account = account_id
where abook_self = 0
$sql_extra
AND (( account_flags = %d ) OR ( account_flags = %d )) $abandon_sql ORDER BY $randfunc",
intval(ACCOUNT_OK),
intval(ACCOUNT_UNVERIFIED) // FIXME
);
if($contacts) {

View File

@ -9,6 +9,7 @@ namespace Zotlabs\Lib;
*/
class ActivityStreams {
public $raw = null;
public $data;
public $valid = false;
public $id = '';
@ -33,7 +34,9 @@ class ActivityStreams {
*/
function __construct($string) {
$this->raw = $string;
$this->data = json_decode($string, true);
if($this->data) {
$this->valid = true;
}
@ -204,7 +207,7 @@ class ActivityStreams {
}
$x = z_fetch_url($url, true, $redirects,
['headers' => [ 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/activity+json' ]]);
['headers' => [ 'Accept: application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ]]);
if($x['success'])
return json_decode($x['body'], true);

View File

@ -13,7 +13,12 @@ require_once('include/channel.php');
class Apps {
static public $installed_system_apps = null;
static public $available_apps = null;
static public $installed_apps = null;
static public $base_apps = null;
static public function get_system_apps($translate = true) {
@ -45,6 +50,8 @@ class Apps {
}
}
call_hooks('get_system_apps',$ret);
return $ret;
}
@ -53,22 +60,52 @@ class Apps {
static public function import_system_apps() {
if(! local_channel())
return;
self::$base_apps = get_config('system','base_apps',[
'Connections',
'Suggest Channels',
'Grid',
'Settings',
'Files',
'Channel Home',
'View Profile',
'Photos',
'Events',
'Directory',
'Search',
'Help',
'Mail',
'Profile Photo'
]);
$apps = self::get_system_apps(false);
self::$installed_system_apps = q("select * from app where app_system = 1 and app_channel = %d",
self::$available_apps = q("select * from app where app_channel = 0");
self::$installed_apps = q("select * from app where app_channel = %d",
intval(local_channel())
);
if($apps) {
foreach($apps as $app) {
$id = self::check_install_system_app($app);
// $id will be boolean true or false to install an app, or an integer id to update an existing app
if($id !== false) {
$app['uid'] = 0;
$app['guid'] = hash('whirlpool',$app['name']);
$app['system'] = 1;
self::app_install(0,$app);
}
$id = self::check_install_personal_app($app);
// $id will be boolean true or false to install an app, or an integer id to update an existing app
if($id === false)
continue;
if($id !== true) {
// if we already installed this app, but it changed, preserve any categories we created
$s = '';
$r = q("select * from term where otype = %d and oid = %d",
$s = EMPTY_STR;
$r = q("select term from term where otype = %d and oid = %d",
intval(TERM_OBJ_APP),
intval($id)
);
@ -85,6 +122,7 @@ class Apps {
$app['guid'] = hash('whirlpool',$app['name']);
$app['system'] = 1;
self::app_install(local_channel(),$app);
}
}
}
@ -95,11 +133,11 @@ class Apps {
*/
static public function check_install_system_app($app) {
if((! is_array(self::$installed_system_apps)) || (! count(self::$installed_system_apps))) {
if((! is_array(self::$available_apps)) || (! count(self::$available_apps))) {
return true;
}
$notfound = true;
foreach(self::$installed_system_apps as $iapp) {
foreach(self::$available_apps as $iapp) {
if($iapp['app_id'] == hash('whirlpool',$app['name'])) {
$notfound = false;
if(($iapp['app_version'] != $app['version'])
@ -113,6 +151,31 @@ class Apps {
}
/**
* Install the system app if no system apps have been installed, or if a new system app
* is discovered, or if the version of a system app changes.
*/
static public function check_install_personal_app($app) {
$installed = false;
foreach(self::$installed_apps as $iapp) {
if($iapp['app_id'] == hash('whirlpool',$app['name'])) {
$installed = true;
if(($iapp['app_version'] != $app['version'])
|| ($app['plugin'] && (! $iapp['app_plugin']))) {
return intval($iapp['app_id']);
}
}
}
if(! $installed && in_array($app['name'],self::$base_apps)) {
return true;
}
return false;
}
static public function app_name_compare($a,$b) {
return strcasecmp($a['name'],$b['name']);
}
@ -233,7 +296,6 @@ class Apps {
'View Bookmarks' => t('View Bookmarks'),
'My Chatrooms' => t('My Chatrooms'),
'Connections' => t('Connections'),
'Firefox Share' => t('Firefox Share'),
'Remote Diagnostics' => t('Remote Diagnostics'),
'Suggest Channels' => t('Suggest Channels'),
'Login' => t('Login'),
@ -288,6 +350,7 @@ class Apps {
* modes:
* view: normal mode for viewing an app via bbcode from a conversation or page
* provides install/update button if you're logged in locally
* install: like view but does not display app-bin options if they are present
* list: normal mode for viewing an app on the app page
* no buttons are shown
* edit: viewing the app page in editing mode provides a delete button
@ -300,7 +363,7 @@ class Apps {
return;
if(! $papp['photo'])
$papp['photo'] = z_root() . '/' . get_default_profile_photo(80);
$papp['photo'] = 'icon:gear';
self::translate_system_apps($papp);
@ -400,12 +463,15 @@ class Apps {
));
}
if($mode === 'install') {
$papp['embed'] = true;
}
return replace_macros(get_markup_template('app.tpl'),array(
'$app' => $papp,
'$icon' => $icon,
'$hosturl' => $hosturl,
'$purchase' => (($papp['page'] && (! $installed)) ? t('Purchase') : ''),
'$install' => (($hosturl && $mode == 'view') ? $install_action : ''),
'$install' => (($hosturl && in_array($mode, ['view','install'])) ? $install_action : ''),
'$edit' => ((local_channel() && $installed && $mode == 'edit') ? t('Edit') : ''),
'$delete' => ((local_channel() && $installed && $mode == 'edit') ? t('Delete') : ''),
'$undelete' => ((local_channel() && $installed && $mode == 'edit') ? t('Undelete') : ''),
@ -468,21 +534,13 @@ class Apps {
intval(TERM_OBJ_APP),
intval($x[0]['id'])
);
if($x[0]['app_system']) {
$r = q("update app set app_deleted = 1 where app_id = '%s' and app_channel = %d",
dbesc($app['guid']),
intval($uid)
);
}
else {
$r = q("delete from app where app_id = '%s' and app_channel = %d",
dbesc($app['guid']),
intval($uid)
);
$r = q("delete from app where app_id = '%s' and app_channel = %d",
dbesc($app['guid']),
intval($uid)
);
// we don't sync system apps - they may be completely different on the other system
build_sync_packet($uid,array('app' => $x));
}
// we don't sync system apps - they may be completely different on the other system
build_sync_packet($uid,array('app' => $x));
}
else {
self::app_undestroy($uid,$app);
@ -736,12 +794,19 @@ class Apps {
$darray = array();
$ret = array('success' => false);
$sys = get_sys_channel();
$darray['app_url'] = ((x($arr,'url')) ? $arr['url'] : '');
$darray['app_channel'] = ((x($arr,'uid')) ? $arr['uid'] : 0);
if((! $darray['app_url']) || (! $darray['app_channel']))
if(! $darray['app_url'])
return $ret;
if((! $arr['uid']) && (! $arr['author'])) {
$arr['author'] = $sys['channel_hash'];
}
if($arr['photo'] && (strpos($arr['photo'],'icon:') !== 0) && (! strstr($arr['photo'],z_root()))) {
$x = import_xchan_photo($arr['photo'],get_observer_hash(),true);
$arr['photo'] = $x[1];
@ -875,7 +940,7 @@ class Apps {
// if updating an embed app, don't mess with any existing categories.
if(array_key_exists('embed',$arr) && intval($arr['embed']))
if(array_key_exists('embed',$arr) && intval($arr['embed']) && (intval($darray['app_channel'])))
return $ret;
if($x) {

View File

@ -0,0 +1,79 @@
<?php
namespace Zotlabs\Lib;
class MessageFilter {
static public function evaluate($item,$incl,$excl) {
require_once('include/html2plain.php');
unobscure($item);
$text = prepare_text($item['body'],$item['mimetype']);
$text = html2plain(($item['title']) ? $item['title'] . ' ' . $text : $text);
$lang = null;
if((strpos($incl,'lang=') !== false) || (strpos($excl,'lang=') !== false)) {
$lang = detect_language($text);
}
$tags = ((is_array($item['term']) && count($item['term'])) ? $item['term'] : false);
// exclude always has priority
$exclude = (($excl) ? explode("\n",$excl) : null);
if($exclude) {
foreach($exclude as $word) {
$word = trim($word);
if(! $word)
continue;
if(substr($word,0,1) === '#' && $tags) {
foreach($tags as $t)
if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
return false;
}
elseif((strpos($word,'/') === 0) && preg_match($word,$text))
return false;
elseif((strpos($word,'lang=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,5))) == 0))
return false;
elseif(stristr($text,$word) !== false)
return false;
}
}
$include = (($incl) ? explode("\n",$incl) : null);
if($include) {
foreach($include as $word) {
$word = trim($word);
if(! $word)
continue;
if(substr($word,0,1) === '#' && $tags) {
foreach($tags as $t)
if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
return true;
}
elseif((strpos($word,'/') === 0) && preg_match($word,$text))
return true;
elseif((strpos($word,'lang=') === 0) && ($lang) && (strcasecmp($lang,trim(substr($word,5))) == 0))
return true;
elseif(stristr($text,$word) !== false)
return true;
}
}
else {
return true;
}
return false;
}
}

View File

@ -102,6 +102,13 @@ class ThreadItem {
if($item['author']['xchan_network'] === 'rss')
$shareable = true;
$privacy_warning = false;
if(($item['item_private'] == 1) && ($item['owner']['xchan_network'] === 'activitypub')) {
$recips = get_iconfig($item['parent'], 'activitypub', 'recips');
if(! in_array($observer['xchan_url'], $recips['to']))
$privacy_warning = true;
}
$mode = $conv->get_mode();
@ -141,6 +148,10 @@ class ThreadItem {
'delete' => t('Delete'),
);
}
elseif(is_site_admin()) {
$drop = [ 'dropping' => true, 'delete' => t('Admin Delete') ];
}
// FIXME
if($observer_is_pageowner) {
$multidrop = array(
@ -232,16 +243,9 @@ class ThreadItem {
// FIXME check this permission
if(($conv->get_profile_owner() == local_channel()) && (! array_key_exists('real_uid',$item))) {
// FIXME we don't need all this stuff, some can be done in the template
$star = array(
'do' => t("Add Star"),
'undo' => t("Remove Star"),
'toggle' => t("Toggle Star Status"),
'classdo' => ((intval($item['item_starred'])) ? "hidden" : ""),
'classundo' => ((intval($item['item_starred'])) ? "" : "hidden"),
'isstarred' => ((intval($item['item_starred'])) ? true : false),
'starred' => t('starred'),
);
}
@ -366,6 +370,7 @@ class ThreadItem {
'editedtime' => (($item['edited'] != $item['created']) ? sprintf( t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r')) : ''),
'expiretime' => (($item['expires'] > NULL_DATE) ? sprintf( t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r')):''),
'lock' => $lock,
'privacy_warning' => $privacy_warning,
'verified' => $verified,
'unverified' => $unverified,
'forged' => $forged,
@ -756,7 +761,7 @@ class ThreadItem {
'$edquote' => t('Quote'),
'$edcode' => t('Code'),
'$edimg' => t('Image'),
'$edatt' => t('Attach File'),
'$edatt' => t('Attach/Upload file'),
'$edurl' => t('Insert Link'),
'$edvideo' => t('Video'),
'$preview' => t('Preview'), // ((feature_enabled($conv->get_profile_owner(),'preview')) ? t('Preview') : ''),

View File

@ -24,7 +24,7 @@ class Acl extends \Zotlabs\Web\Controller {
function init() {
logger('mod_acl: ' . print_r($_REQUEST,true),LOGGER_DATA);
// logger('mod_acl: ' . print_r($_GET,true),LOGGER_DATA);
$start = (x($_REQUEST,'start') ? $_REQUEST['start'] : 0);
$count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 500);
@ -94,8 +94,7 @@ class Acl extends \Zotlabs\Web\Controller {
. " then POSITION('" . protect_sprintf(dbesc($search))
. "' IN xchan_name) else position('" . protect_sprintf(dbesc(punify($search))) . "' IN xchan_addr) end, ";
$col = ((strpos($search,'@') !== false) ? 'xchan_addr' : 'xchan_name' );
$sql_extra3 = "AND $col like " . protect_sprintf( "'%" . dbesc(($col === 'xchan_addr') ? punify($search) : $search) . "%'" ) . " ";
$sql_extra3 = "AND ( xchan_addr like " . protect_sprintf( "'%" . dbesc(punify($search)) . "%'" ) . " OR xchan_name like " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ) ";
}
else {
@ -268,15 +267,15 @@ class Acl extends \Zotlabs\Web\Controller {
});
}
}
if(intval(get_config('system','taganyone')) || intval(get_pconfig(local_channel(),'system','taganyone'))) {
if((count($r) < 100) && $type == 'c') {
$r2 = q("SELECT substr(xchan_hash,1,18) as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags, 0 as abook_self
FROM xchan
WHERE xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc"
);
if($r2)
$r = array_merge($r,$r2);
}
if((count($r) < 100) && $type == 'c') {
$r2 = q("SELECT substr(xchan_hash,1,18) as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags, 0 as abook_self
FROM xchan
WHERE xchan_deleted = 0 and not xchan_network in ('rss','anon','unknown') $sql_extra2 order by $order_extra2 xchan_name asc"
);
if($r2) {
$r = array_merge($r,$r2);
$r = unique_multidim_array($r,'hash');
}
}
}
elseif($type == 'm') {
@ -337,24 +336,23 @@ class Acl extends \Zotlabs\Web\Controller {
if($r) {
foreach($r as $g) {
if(($g['network'] === 'rss') && ($type != 'a'))
if(in_array($g['network'],['rss','anon','unknown']) && ($type != 'a'))
continue;
$g['hash'] = urlencode($g['hash']);
if(! $g['nick']) {
$t = explode(' ',strtolower($g['name']));
$g['nick'] = $t[0] . '@';
$g['nick'] = $g['url'];
}
if(in_array($g['hash'],$permitted) && in_array($type, [ 'c', 'f' ]) && (! $noforums)) {
if(in_array($g['hash'],$permitted) && $type === 'f' && (! $noforums)) {
$contacts[] = array(
"type" => "c",
"photo" => "images/twopeople.png",
"name" => $g['name'] . (($type === 'f') ? '' : '+'),
"id" => urlencode($g['id']) . (($type === 'f') ? '' : '+'),
"name" => $g['name'],
"id" => urlencode($g['id']),
"xid" => $g['hash'],
"link" => $g['nick'],
"link" => (($g['nick']) ? $g['nick'] : $g['url']),
"nick" => substr($g['nick'],0,strpos($g['nick'],'@')),
"self" => (intval($g['abook_self']) ? 'abook-self' : ''),
"taggable" => 'taggable',
@ -368,8 +366,8 @@ class Acl extends \Zotlabs\Web\Controller {
"name" => $g['name'],
"id" => urlencode($g['id']),
"xid" => $g['hash'],
"link" => $g['nick'],
"nick" => (($g['nick']) ? substr($g['nick'],0,strpos($g['nick'],'@')) : $g['nick']),
"link" => (($g['nick']) ? $g['nick'] : $g['url']),
"nick" => ((strpos($g['nick'],'@')) ? substr($g['nick'],0,strpos($g['nick'],'@')) : $g['nick']),
"self" => (intval($g['abook_self']) ? 'abook-self' : ''),
"taggable" => '',
"label" => '',

View File

@ -100,8 +100,12 @@ class Admin extends \Zotlabs\Web\Controller {
}
// pending registrations
$r = q("SELECT COUNT(id) AS rtotal FROM register WHERE uid != '0'");
$pending = $r[0]['rtotal'];
$pdg = q("SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d ) > 0 ",
intval(ACCOUNT_PENDING)
);
$pending = (($pdg) ? count($pdg) : 0);
// available channels, primary and clones
$channels = array();
@ -140,7 +144,7 @@ class Admin extends \Zotlabs\Web\Controller {
'$accounts' => array( t('Registered accounts'), $accounts),
'$pending' => array( t('Pending registrations'), $pending),
'$channels' => array( t('Registered channels'), $channels),
'$plugins' => array( t('Active plugins'), $plugins ),
'$plugins' => array( t('Active addons'), $plugins ),
'$version' => array( t('Version'), STD_VERSION),
'$vmaster' => array( t('Repository version (master)'), $vmaster),
'$vdev' => array( t('Repository version (dev)'), $vdev),

View File

@ -2,10 +2,10 @@
namespace Zotlabs\Module\Admin;
use \Zotlabs\Storage\GitRepo as GitRepo;
use \Zotlabs\Storage\GitRepo;
use \Michelf\MarkdownExtra;
class Plugins {
class Addons {
/**
* @brief
@ -20,7 +20,7 @@ class Plugins {
$func($a);
}
goaway(z_root() . '/admin/plugins/' . argv(2) );
goaway(z_root() . '/admin/addons/' . argv(2) );
}
elseif(argc() > 2) {
switch(argv(2)) {
@ -243,7 +243,7 @@ class Plugins {
}
/**
* @brief Plugins admin page.
* @brief Addons admin page.
*
* @return string with parsed HTML
*/
@ -278,7 +278,7 @@ class Plugins {
$info['disabled'] = 1-intval($x);
if (x($_GET,"a") && $_GET['a']=="t"){
check_form_security_token_redirectOnErr('/admin/plugins', 'admin_plugins', 't');
check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't');
$pinstalled = false;
// Toggle plugin status
$idx = array_search($plugin, \App::$plugins);
@ -298,9 +298,9 @@ class Plugins {
if($pinstalled) {
@require_once("addon/$plugin/$plugin.php");
if(function_exists($plugin.'_plugin_admin'))
goaway(z_root() . '/admin/plugins/' . $plugin);
goaway(z_root() . '/admin/addons/' . $plugin);
}
goaway(z_root() . '/admin/plugins' );
goaway(z_root() . '/admin/addons' );
}
// display plugin details
@ -339,7 +339,7 @@ class Plugins {
$t = get_markup_template('admin_plugins_details.tpl');
return replace_macros($t, array(
'$title' => t('Administration'),
'$page' => t('Plugins'),
'$page' => t('Addons'),
'$toggle' => t('Toggle'),
'$settings' => t('Settings'),
'$baseurl' => z_root(),
@ -358,11 +358,11 @@ class Plugins {
'$disabled' => t('Disabled - version incompatibility'),
'$admin_form' => $admin_form,
'$function' => 'plugins',
'$function' => 'addons',
'$screenshot' => '',
'$readme' => $readme,
'$form_security_token' => get_form_security_token('admin_plugins'),
'$form_security_token' => get_form_security_token('admin_addons'),
));
}
@ -407,11 +407,11 @@ class Plugins {
$admin_plugins_add_repo_form= replace_macros(
get_markup_template('admin_plugins_addrepo.tpl'), array(
'$post' => 'admin/plugins/addrepo',
'$desc' => t('Enter the public git repository URL of the plugin repo.'),
'$repoURL' => array('repoURL', t('Plugin repo git URL'), '', ''),
'$post' => 'admin/addons/addrepo',
'$desc' => t('Enter the public git repository URL of the addon repo.'),
'$repoURL' => array('repoURL', t('Addon repo git URL'), '', ''),
'$repoName' => array('repoName', t('Custom repo name'), '', '', t('(optional)')),
'$submit' => t('Download Plugin Repo')
'$submit' => t('Download Addon Repo')
)
);
$newRepoModalID = random_string(3);
@ -434,17 +434,17 @@ class Plugins {
$t = get_markup_template('admin_plugins.tpl');
return replace_macros($t, array(
'$title' => t('Administration'),
'$page' => t('Plugins'),
'$page' => t('Addons'),
'$submit' => t('Submit'),
'$baseurl' => z_root(),
'$function' => 'plugins',
'$function' => 'addons',
'$plugins' => $plugins,
'$disabled' => t('Disabled - version incompatibility'),
'$form_security_token' => get_form_security_token('admin_plugins'),
'$form_security_token' => get_form_security_token('admin_addons'),
'$allowManageRepos' => $allowManageRepos,
'$managerepos' => t('Manage Repos'),
'$installedtitle' => t('Installed Plugin Repositories'),
'$addnewrepotitle' => t('Install a New Plugin Repository'),
'$installedtitle' => t('Installed Addon Repositories'),
'$addnewrepotitle' => t('Install a New Addon Repository'),
'$expandform' => false,
'$form' => $admin_plugins_add_repo_form,
'$newRepoModal' => $newRepoModal,

View File

@ -16,7 +16,13 @@ class Security {
$block_public = ((x($_POST,'block_public')) ? True : False);
set_config('system','block_public',$block_public);
$cloud_noroot = ((x($_POST,'cloud_noroot')) ? 1 : 0);
set_config('system','cloud_disable_siteroot',1 - $cloud_noroot);
$cloud_disksize = ((x($_POST,'cloud_disksize')) ? 1 : 0);
set_config('system','cloud_report_disksize',$cloud_disksize);
$ws = $this->trim_array_elems(explode("\n",$_POST['whitelisted_sites']));
set_config('system','whitelisted_sites',$ws);
@ -87,6 +93,8 @@ class Security {
'$page' => t('Security'),
'$form_security_token' => get_form_security_token('admin_security'),
'$block_public' => array('block_public', t("Block public"), get_config('system','block_public'), t("Check to block public access to all otherwise public personal pages on this site unless you are currently authenticated.")),
'$cloud_noroot' => [ 'cloud_noroot', t('Provide a cloud root directory'), 1 - intval(get_config('system','cloud_disable_siteroot')), t('The cloud root directory lists all channel names which provide public files') ],
'$cloud_disksize' => [ 'cloud_disksize', t('Show total disk space available to cloud uploads'), intval(get_config('system','cloud_report_disksize')), '' ],
'$transport_security' => array('transport_security', t('Set "Transport Security" HTTP header'),intval(get_config('system','transport_security_header')),''),
'$content_security' => array('content_security', t('Set "Content Security Policy" HTTP header'),intval(get_config('system','content_security_policy')),''),
'$allowed_email' => array('allowed_email', t("Allowed email domains"), get_config('system','allowed_email'), t("Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains")),

View File

@ -76,6 +76,10 @@ class Site {
$imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
$thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
$force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000);
$pub_incl = escape_tags(trim($_POST['pub_incl']));
$pub_excl = escape_tags(trim($_POST['pub_excl']));
$permissions_role = escape_tags(trim($_POST['permissions_role']));
$techlevel = null;
if(array_key_exists('techlevel', $_POST))
@ -102,6 +106,9 @@ class Site {
set_config('system', 'from_email_name' , $from_email_name);
set_config('system', 'imagick_convert_path' , $imagick_path);
set_config('system', 'thumbnail_security' , $thumbnail_security);
set_config('system', 'default_permissions_role', $permissions_role);
set_config('system', 'pubstream_incl',$pub_incl);
set_config('system', 'pubstream_excl',$pub_excl);
set_config('system', 'techlevel_lock', $techlevel_lock);
@ -286,6 +293,12 @@ class Site {
'5' => t('Wizard - I probably know more than you do')
];
$perm_roles = \Zotlabs\Access\PermissionRoles::roles();
$default_role = get_config('system','default_permissions_role','social');
$role = array('permissions_role' , t('Default permission role for new accounts'), $default_role, t('This role will be used for the first channel created after registration.'),$perm_roles);
$homelogin = get_config('system','login_on_homepage');
$enable_context_help = get_config('system','enable_context_help');
@ -321,6 +334,7 @@ class Site {
'$minimum_age' => array('minimum_age', t("Minimum age"), (x(get_config('system','minimum_age'))?get_config('system','minimum_age'):13), t("Minimum age (in years) for who may register on this site.")),
'$access_policy' => array('access_policy', t("Which best describes the types of account offered by this hub?"), get_config('system','access_policy'), "This is displayed on the public server site list.", $access_choices),
'$register_text' => array('register_text', t("Register text"), htmlspecialchars(get_config('system','register_text'), ENT_QUOTES, 'UTF-8'), t("Will be displayed prominently on the registration page.")),
'$role' => $role,
'$frontpage' => array('frontpage', t("Site homepage to show visitors (default: login box)"), get_config('system','frontpage'), t("example: 'public' to show public stream, 'page/sys/home' to show a system webpage called 'home' or 'include:home.html' to include a file.")),
'$mirror_frontpage' => array('mirror_frontpage', t("Preserve site homepage URL"), get_config('system','mirror_frontpage'), t('Present the site homepage in a frame at the original location instead of redirecting')),
'$abandon_days' => array('abandon_days', t('Accounts abandoned after x days'), get_config('system','account_abandon_days'), t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.')),
@ -330,6 +344,10 @@ class Site {
'$disable_discover_tab' => array('disable_discover_tab', t('Import Public Streams'), $discover_tab, t('Import and allow access to public content pulled from other sites. Warning: this content is unmoderated.')),
'$site_firehose' => array('site_firehose', t('Site only Public Streams'), get_config('system','site_firehose'), t('Allow access to public content originating only from this site if Imported Public Streams are disabled.')),
'$open_pubstream' => array('open_pubstream', t('Allow anybody on the internet to access the Public streams'), get_config('system','open_pubstream',1), t('Disable to require authentication before viewing. Warning: this content is unmoderated.')),
'$incl' => array('pub_incl',t('Only import Public stream posts with this text'), get_config('system','pubstream_incl'),t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')),
'$excl' => array('pub_excl',t('Do not import Public stream posts with this text'), get_config('system','pubstream_excl'),t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')),
'$login_on_homepage' => array('login_on_homepage', t("Login on Homepage"),((intval($homelogin) || $homelogin === false) ? 1 : '') , t("Present a login box to visitors on the home page if no other content has been configured.")),
'$enable_context_help' => array('enable_context_help', t("Enable context help"),((intval($enable_context_help) === 1 || $enable_context_help === false) ? 1 : 0) , t("Display contextual help for the current page when the help button is pressed.")),
@ -353,7 +371,7 @@ class Site {
'$active_expire_days' => array('active_expire_days', t('Do not expire any posts which have comments less than this many days ago'), intval(get_config('system','active_expire_days',7)), ''),
'$sellpage' => array('site_sellpage', t('Public servers: Optional landing (marketing) webpage for new registrants'), get_config('system','sellpage',''), sprintf( t('Create this page first. Default is %s/register'),z_root())),
'$first_page' => array('first_page', t('Page to display after creating a new channel'), get_config('system','workflow_channel_next','profiles'), t('Recommend: profiles, go, or settings')),
'$first_page' => array('first_page', t('Page to display after creating a new channel'), get_config('system','workflow_channel_next','profiles'), t('Default: profiles')),
'$location' => array('site_location', t('Optional: site location'), get_config('system','site_location',''), t('Region or country')),

View File

@ -15,6 +15,8 @@ class Apps extends \Zotlabs\Web\Controller {
else
$mode = 'list';
$available = ((argc() == 2 && argv(1) === 'available') ? true : false);
$_SESSION['return_url'] = \App::$query_string;
$apps = array();
@ -23,7 +25,7 @@ class Apps extends \Zotlabs\Web\Controller {
Zlib\Apps::import_system_apps();
$syslist = array();
$cat = ((array_key_exists('cat',$_GET) && $_GET['cat']) ? [ escape_tags($_GET['cat']) ] : '');
$list = Zlib\Apps::app_list(local_channel(), (($mode == 'edit') ? true : false), $cat);
$list = Zlib\Apps::app_list((($available) ? 0 : local_channel()), (($mode == 'edit') ? true : false), $cat);
if($list) {
foreach($list as $x) {
$syslist[] = Zlib\Apps::app_encode($x);
@ -39,7 +41,7 @@ class Apps extends \Zotlabs\Web\Controller {
// logger('apps: ' . print_r($syslist,true));
foreach($syslist as $app) {
$apps[] = Zlib\Apps::app_render($app,$mode);
$apps[] = Zlib\Apps::app_render($app,(($available) ? 'install' : $mode));
}
return replace_macros(get_markup_template('myapps.tpl'), array(
@ -48,7 +50,7 @@ class Apps extends \Zotlabs\Web\Controller {
'$title' => t('Apps'),
'$apps' => $apps,
'$authed' => ((local_channel()) ? true : false),
'$manage' => t('Manage apps'),
'$manage' => (($available) ? '' : t('Manage apps')),
'$create' => (($mode == 'edit') ? t('Create new app') : '')
));

View File

@ -128,6 +128,7 @@ class Article_edit extends \Zotlabs\Web\Controller {
'$title' => t('Edit Article'),
'$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false),
'$id' => $itm[0]['id'],
'$cancel' => t('Cancel'),
'$editor' => $editor
));

View File

@ -128,6 +128,7 @@ class Card_edit extends \Zotlabs\Web\Controller {
'$title' => t('Edit Card'),
'$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false),
'$id' => $itm[0]['id'],
'$cancel' => t('Cancel'),
'$editor' => $editor
));

View File

@ -18,6 +18,9 @@ class Channel extends \Zotlabs\Web\Controller {
function init() {
if(in_array(substr($_GET['search'],0,1),[ '@', '!', '?']))
goaway('search' . '?f=&search=' . $_GET['search']);
$which = null;
if(argc() > 1)
$which = argv(1);
@ -82,7 +85,9 @@ class Channel extends \Zotlabs\Web\Controller {
$category = ((x($_REQUEST,'cat')) ? $_REQUEST['cat'] : '');
$hashtags = ((x($_REQUEST,'tag')) ? $_REQUEST['tag'] : '');
$order = ((x($_GET,'order')) ? notags($_GET['order']) : 'post');
$static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0);
$search = ((x($_GET,'search')) ? $_GET['search'] : EMPTY_STR);
$groups = array();
@ -118,9 +123,12 @@ class Channel extends \Zotlabs\Web\Controller {
$static = channel_manual_conv_update(\App::$profile['profile_uid']);
//$o .= profile_tabs($a, $is_owner, \App::$profile['channel_address']);
// $o .= common_friends_visitor_widget(\App::$profile['profile_uid']);
// search terms header
if($search) {
$o .= replace_macros(get_markup_template("section_title.tpl"),array(
'$title' => t('Search Results For:') . ' ' . htmlspecialchars($search, ENT_COMPAT,'UTF-8')
));
}
if($channel && $is_owner) {
$channel_acl = array(
@ -152,7 +160,8 @@ class Channel extends \Zotlabs\Web\Controller {
'editor_autocomplete' => true,
'bbco_autocomplete' => 'bbcode',
'bbcode' => true,
'jotnets' => true
'jotnets' => true,
'reset' => t('Reset form')
);
$o .= status_editor($a,$x);
@ -178,6 +187,19 @@ class Channel extends \Zotlabs\Web\Controller {
$simple_update = (($update) ? " AND item_unseen = 1 " : '');
if($search) {
$search = escape_tags($search);
if(strpos($search,'#') === 0) {
$sql_extra .= term_query('item',substr($search,1),TERM_HASHTAG,TERM_COMMUNITYTAG);
}
else {
$sql_extra .= sprintf(" AND item.body like '%s' ",
dbesc(protect_sprintf('%' . $search . '%'))
);
}
}
head_add_link([
'rel' => 'alternate',
'type' => 'application/json+oembed',
@ -228,11 +250,22 @@ class Channel extends \Zotlabs\Web\Controller {
if($datequery) {
$sql_extra2 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery))));
$order = 'post';
}
if($datequery2) {
$sql_extra2 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery2))));
}
if($datequery || $datequery2) {
$sql_extra2 .= " and item.item_thread_top != 0 ";
}
if($order === 'post')
$ordering = "created";
else
$ordering = "commented";
$itemspage = get_pconfig(local_channel(),'system','itemspage');
\App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20));
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']), intval(\App::$pager['start']));
@ -249,13 +282,13 @@ class Channel extends \Zotlabs\Web\Controller {
}
}
else {
$r = q("SELECT item.parent AS item_id FROM item
$r = q("SELECT DISTINCT item.parent AS item_id, $ordering FROM item
left join abook on ( item.author_xchan = abook.abook_xchan $abook_uids )
WHERE true and item.uid = %d AND item.item_thread_top = 1 $item_normal
WHERE true and item.uid = %d $item_normal
AND (abook.abook_blocked = 0 or abook.abook_flags is null)
AND item.item_wall = 1
$sql_extra $sql_extra2
ORDER BY created DESC, id $pager_sql ",
AND item.item_wall = 1 AND item.item_thread_top = 1
$sql_extra $sql_extra2
ORDER BY $ordering DESC $pager_sql ",
intval(\App::$profile['profile_uid'])
);
}
@ -264,7 +297,6 @@ class Channel extends \Zotlabs\Web\Controller {
$r = array();
}
}
if($r) {
$parents_str = ids_to_querystr($r,'item_id');
@ -280,7 +312,7 @@ class Channel extends \Zotlabs\Web\Controller {
xchan_query($items);
$items = fetch_post_tags($items, true);
$items = conv_sort($items,'created');
$items = conv_sort($items,$ordering);
if($load && $mid && (! count($items))) {
// This will happen if we don't have sufficient permissions
@ -323,9 +355,9 @@ class Channel extends \Zotlabs\Web\Controller {
'$fh' => '0',
'$static' => $static,
'$page' => ((\App::$pager['page'] != 1) ? \App::$pager['page'] : 1),
'$search' => '',
'$search' => $search,
'$xchan' => '',
'$order' => '',
'$order' => $order,
'$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0),
'$file' => '',
'$cats' => (($category) ? urlencode($category) : ''),
@ -371,12 +403,13 @@ class Channel extends \Zotlabs\Web\Controller {
}
}
$mode = (($search) ? 'search' : 'channel');
if($checkjs->disabled()) {
$o .= conversation($items,'channel',$update,'traditional');
$o .= conversation($items,$mode,$update,'traditional');
}
else {
$o .= conversation($items,'channel',$update,$page_mode);
$o .= conversation($items,$mode,$update,$page_mode);
}
if((! $update) || ($checkjs->disabled())) {

View File

@ -119,10 +119,10 @@ class Chatsvc extends \Zotlabs\Web\Controller {
$rv['xchan_network'] = 'unknown';
$rv['xchan_url'] = z_root();
$rv['xchan_hidden'] = 1;
$rv['xchan_photo_mimetype'] = 'image/jpeg';
$rv['xchan_photo_l'] = get_default_profile_photo(300);
$rv['xchan_photo_m'] = get_default_profile_photo(80);
$rv['xchan_photo_s'] = get_default_profile_photo(48);
$rv['xchan_photo_mimetype'] = 'image/png';
$rv['xchan_photo_l'] = z_root() . '/' . get_default_profile_photo(300);
$rv['xchan_photo_m'] = z_root() . '/' . get_default_profile_photo(80);
$rv['xchan_photo_s'] = z_root() . '/' . get_default_profile_photo(48);
}

View File

@ -35,11 +35,20 @@ class Cloud extends \Zotlabs\Web\Controller {
if (argc() > 1)
$which = argv(1);
if (argc() < 2 && intval(get_config('system','cloud_disable_siteroot'))) {
notice( t('Permission denied.') . EOL);
construct_page();
killme();
}
$profile = 0;
if ($which)
profile_load( $which, $profile);
$auth = new \Zotlabs\Storage\BasicAuth();
$ob_hash = get_observer_hash();

View File

@ -9,6 +9,7 @@ namespace Zotlabs\Module;
require_once('include/photo/photo_driver.php');
require_once('include/channel.php');
require_once('include/photos.php');
@ -84,10 +85,41 @@ class Cover_photo extends \Zotlabs\Web\Controller {
);
if($r) {
$base_image = $r[0];
$base_image['content'] = (($r[0]['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content']));
$max_thumb = intval(get_config('system','max_thumbnail',1600));
$iscaled = false;
if(intval($r[0]['height']) > $max_thumb || intval($r[0]['width']) > $max_thumb) {
$imagick_path = get_config('system','imagick_convert_path');
if($imagick_path && @file_exists($imagick_path) && intval($r[0]['os_storage'])) {
$fname = dbunescbin($r[0]['content']);
$tmp_name = $fname . '-001';
$newsize = photo_calculate_scale(array_merge(getimagesize($fname),['max' => $max_thumb]));
$cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $fname) . ' -resize ' . $newsize . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmp_name);
// logger('imagick thumbnail command: ' . $cmd);
for($x = 0; $x < 4; $x ++) {
exec($cmd);
if(file_exists($tmp_name)) {
break;
}
}
if(file_exists($tmp_name)) {
$base_image = $r[0];
$gis = getimagesize($tmp_name);
logger('gis: ' . print_r($gis,true));
$base_image['width'] = $gis[0];
$base_image['height'] = $gis[1];
$base_image['content'] = @file_get_contents($tmp_name);
$iscaled = true;
@unlink($tmp_name);
}
}
}
if(! $iscaled) {
$base_image = $r[0];
$base_image['content'] = (($r[0]['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content']));
}
$im = photo_factory($base_image['content'], $base_image['mimetype']);
if($im->is_valid()) {
@ -119,10 +151,10 @@ class Cover_photo extends \Zotlabs\Web\Controller {
intval(local_channel())
);
$orig_srcx = ( $r[0]['width'] / $scaled_width ) * $srcX;
$orig_srcy = ( $r[0]['height'] / $scaled_height ) * $srcY;
$orig_srcw = ( $srcW / $scaled_width ) * $r[0]['width'];
$orig_srch = ( $srcH / $scaled_height ) * $r[0]['height'];
$orig_srcx = ( $base_image['width'] / $scaled_width ) * $srcX;
$orig_srcy = ( $base_image['height'] / $scaled_height ) * $srcY;
$orig_srcw = ( $srcW / $scaled_width ) * $base_image['width'];
$orig_srch = ( $srcH / $scaled_height ) * $base_image['height'];
$im->cropImageRect(1200,435,$orig_srcx, $orig_srcy, $orig_srcw, $orig_srch);

View File

@ -257,7 +257,7 @@ class Dirsearch extends \Zotlabs\Web\Controller {
else {
$r = q("SELECT xchan.*, xprof.* from xchan left join xprof on xchan_hash = xprof_hash
where ( $logic $sql_extra ) $hub_query and xchan_network = 'zot' and xchan_hidden = 0 and xchan_orphan = 0 and xchan_deleted = 0
where ( $logic $sql_extra ) $hub_query and xchan_network = 'zot' and xchan_system = 0 and xchan_hidden = 0 and xchan_orphan = 0 and xchan_deleted = 0
$safesql $order $qlimit "
);

View File

@ -67,8 +67,7 @@ class Display extends \Zotlabs\Web\Controller {
'default_location' => $channel['channel_location'],
'nickname' => $channel['channel_address'],
'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
'acl' => populate_acl($channel_acl),
'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
'permissions' => $channel_acl,
'bang' => '',
'visitor' => true,
@ -78,7 +77,8 @@ class Display extends \Zotlabs\Web\Controller {
'editor_autocomplete' => true,
'bbco_autocomplete' => 'bbcode',
'bbcode' => true,
'jotnets' => true
'jotnets' => true,
'reset' => t('Reset form')
);
$o = '<div id="jot-popup">';

View File

@ -138,6 +138,7 @@ class Editblock extends \Zotlabs\Web\Controller {
'$title' => t('Edit Block'),
'$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false),
'$id' => $itm[0]['id'],
'$cancel' => t('Cancel'),
'$editor' => $editor
));

View File

@ -137,6 +137,7 @@ class Editlayout extends \Zotlabs\Web\Controller {
'$title' => t('Edit Layout'),
'$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false),
'$id' => $itm[0]['id'],
'$cancel' => t('Cancel'),
'$editor' => $editor
));

View File

@ -106,6 +106,7 @@ class Editpost extends \Zotlabs\Web\Controller {
$o .= replace_macros(get_markup_template('edpost_head.tpl'), array(
'$title' => t('Edit post'),
'$cancel' => t('Cancel'),
'$editor' => $editor
));

View File

@ -166,6 +166,7 @@ class Editwebpage extends \Zotlabs\Web\Controller {
'$title' => t('Edit Webpage'),
'$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false),
'$editor' => $editor,
'$cancel' => t('Cancel'),
'$id' => $itm[0]['id']
));

View File

@ -66,7 +66,7 @@ class Filestorage extends \Zotlabs\Web\Controller {
$perms = get_all_perms($owner, $ob_hash);
if(! $perms['view_storage']) {
if(! ($perms['view_storage'] || is_site_admin())){
notice( t('Permission denied.') . EOL);
return;
}
@ -75,15 +75,29 @@ class Filestorage extends \Zotlabs\Web\Controller {
// need to return for anyone other than the owner, despite the perms check for now.
$is_owner = (((local_channel()) && ($owner == local_channel())) ? true : false);
if(! $is_owner) {
if(! ($is_owner || is_site_admin())){
info( t('Permission Denied.') . EOL );
return;
}
if(argc() > 3 && argv(3) === 'delete') {
if(argc() > 4 && argv(4) === 'json')
$json_return = true;
$admin_delete = false;
if(! $perms['write_storage']) {
notice( t('Permission denied.') . EOL);
return;
if(is_site_admin()) {
$admin_delete = true;
}
else {
notice( t('Permission denied.') . EOL);
if($json_return)
json_return_and_die([ 'success' => false ]);
return;
}
}
$file = intval(argv(2));
@ -92,22 +106,31 @@ class Filestorage extends \Zotlabs\Web\Controller {
intval($owner)
);
if(! $r) {
if($json_return)
json_return_and_die([ 'success' => false ]);
notice( t('File not found.') . EOL);
goaway(z_root() . '/cloud/' . $which);
}
$f = $r[0];
$channel = \App::get_channel();
$channel = channelx_by_n($owner);
$url = get_cloud_url($channel['channel_id'], $channel['channel_address'], $f['hash']);
attach_delete($owner, $f['hash']);
$sync = attach_export_data($channel, $f['hash'], true);
if($sync) {
build_sync_packet($channel['channel_id'], array('file' => array($sync)));
if(! $admin_delete) {
$sync = attach_export_data($channel, $f['hash'], true);
if($sync) {
build_sync_packet($channel['channel_id'], array('file' => array($sync)));
}
}
if(json_return)
json_return_and_die([ 'success' => true ]);
goaway(dirname($url));
}

View File

@ -7,6 +7,17 @@ require_once('include/group.php');
class Group extends \Zotlabs\Web\Controller {
function init() {
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
return;
}
\App::$profile_uid = local_channel();
nav_set_selected('Privacy Groups');
}
function post() {
if(! local_channel()) {
@ -22,12 +33,10 @@ class Group extends \Zotlabs\Web\Controller {
$r = group_add(local_channel(),$name,$public);
if($r) {
info( t('Privacy group created.') . EOL );
$r = group_byname(local_channel(),$name);
if($r)
goaway(z_root() . '/group/' . $r);
}
else
notice( t('Could not create privacy group.') . EOL );
else {
notice( t('Could not create privacy group.') . EOL );
}
goaway(z_root() . '/group');
}
@ -74,30 +83,59 @@ class Group extends \Zotlabs\Web\Controller {
notice( t('Permission denied') . EOL);
return;
}
// Switch to text mode interface if we have more than 'n' contacts or group members
$switchtotext = get_pconfig(local_channel(),'system','groupedit_image_limit');
if($switchtotext === false)
$switchtotext = get_config('system','groupedit_image_limit');
if($switchtotext === false)
$switchtotext = 400;
$tpl = get_markup_template('group_edit.tpl');
$context = array('$submit' => t('Submit'));
if((argc() == 2) && (argv(1) === 'new')) {
return replace_macros($tpl, $context + array(
'$title' => t('Create a group of channels.'),
'$gname' => array('groupname',t('Privacy group name: '), '', ''),
'$gid' => 'new',
'$public' => array('public',t('Members are visible to other channels'), false, ''),
if((argc() == 1) || ((argc() == 2) && (argv(1) === 'new'))) {
$new = (((argc() == 2) && (argv(1) === 'new')) ? true : false);
$groups = q("SELECT id, gname FROM groups WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval(local_channel())
);
$i = 0;
foreach($groups as $group) {
$entries[$i]['name'] = $group['gname'];
$entries[$i]['id'] = $group['id'];
$entries[$i]['count'] = count(group_get_members($group['id']));
$i++;
}
$tpl = get_markup_template('privacy_groups.tpl');
$o = replace_macros($tpl, [
'$title' => t('Privacy Groups'),
'$add_new_label' => t('Add Group'),
'$new' => $new,
// new group form
'$gname' => array('groupname',t('Privacy group name')),
'$public' => array('public',t('Members are visible to other channels'), false),
'$form_security_token' => get_form_security_token("group_edit"),
));
'$submit' => t('Submit'),
// groups list
'$title' => t('Privacy Groups'),
'$name_label' => t('Name'),
'$count_label' => t('Members'),
'$entries' => $entries
]);
return $o;
}
$context = array('$submit' => t('Submit'));
$tpl = get_markup_template('group_edit.tpl');
if((argc() == 3) && (argv(1) === 'drop')) {
check_form_security_token_redirectOnErr('/group', 'group_drop', 't');
@ -172,22 +210,17 @@ class Group extends \Zotlabs\Web\Controller {
$preselected[] = $member['xchan_hash'];
}
}
$drop_tpl = get_markup_template('group_drop.tpl');
$drop_txt = replace_macros($drop_tpl, array(
'$id' => $group['id'],
'$delete' => t('Delete'),
'$form_security_token' => get_form_security_token("group_drop"),
));
$context = $context + array(
'$title' => t('Privacy group editor'),
'$title' => sprintf(t('Privacy Group: %s'), $group['gname']),
'$details_label' => t('Edit'),
'$gname' => array('groupname',t('Privacy group name: '),$group['gname'], ''),
'$gid' => $group['id'],
'$drop' => $drop_txt,
'$public' => array('public',t('Members are visible to other channels'), $group['visible'], ''),
'$form_security_token' => get_form_security_token('group_edit'),
'$form_security_token_edit' => get_form_security_token('group_edit'),
'$delete' => t('Delete Group'),
'$form_security_token_drop' => get_form_security_token("group_drop"),
);
}
@ -196,14 +229,14 @@ class Group extends \Zotlabs\Web\Controller {
return;
$groupeditor = array(
'label_members' => t('Members'),
'label_members' => t('Group members'),
'members' => array(),
'label_contacts' => t('All Connected Channels'),
'label_contacts' => t('Not in this group'),
'contacts' => array(),
);
$sec_token = addslashes(get_form_security_token('group_member_change'));
$textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : false);
$textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : 'card');
foreach($members as $member) {
if($member['xchan_url']) {
$member['archived'] = (intval($member['abook_archived']) ? true : false);
@ -219,7 +252,7 @@ class Group extends \Zotlabs\Web\Controller {
);
if(count($r)) {
$textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : false);
$textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : 'card');
foreach($r as $member) {
if(! in_array($member['xchan_hash'],$preselected)) {
$member['archived'] = (intval($member['abook_archived']) ? true : false);
@ -230,7 +263,7 @@ class Group extends \Zotlabs\Web\Controller {
}
$context['$groupeditor'] = $groupeditor;
$context['$desc'] = t('Click on a channel to add or remove.');
$context['$desc'] = t('Click a channel to toggle membership');
if($change) {
$tpl = get_markup_template('groupeditor.tpl');

View File

@ -9,7 +9,7 @@ require_once('include/conversation.php');
class Home extends \Zotlabs\Web\Controller {
function init() {
$ret = array();
call_hooks('home_init',$ret);
@ -89,11 +89,11 @@ class Home extends \Zotlabs\Web\Controller {
$sitename = get_config('system','sitename');
if($sitename)
$o .= '<h1 class="home-welcome">' . sprintf( t("Welcome to %s") ,$sitename) . '</h1>';
$o .= '<h1 class="home-welcome">' . sprintf( t('Welcome to %s') ,$sitename) . '</h1>';
$loginbox = get_config('system','login_on_homepage');
if(intval($loginbox) || $loginbox === false)
$o .= login((\App::$config['system']['register_policy'] == REGISTER_CLOSED) ? 0 : 1);
$o .= login(true);
return $o;

View File

@ -120,8 +120,7 @@ class Hq extends \Zotlabs\Web\Controller {
'default_location' => $channel['channel_location'],
'nickname' => $channel['channel_address'],
'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
'acl' => populate_acl($channel_acl),
'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
'permissions' => $channel_acl,
'bang' => '',
'visitor' => true,
@ -131,7 +130,8 @@ class Hq extends \Zotlabs\Web\Controller {
'editor_autocomplete' => true,
'bbco_autocomplete' => 'bbcode',
'bbcode' => true,
'jotnets' => true
'jotnets' => true,
'reset' => t('Reset form')
];
$o = replace_macros(get_markup_template("hq.tpl"),

View File

@ -6,6 +6,7 @@ require_once('include/zot.php');
require_once('include/channel.php');
require_once('include/import.php');
require_once('include/perm_upgrade.php');
require_once('library/urlify/URLify.php');
/**
@ -38,6 +39,7 @@ class Import extends \Zotlabs\Web\Controller {
$filename = basename($_FILES['filename']['name']);
$filesize = intval($_FILES['filename']['size']);
$filetype = $_FILES['filename']['type'];
$newname = trim(strtolower($_REQUEST['newname']));
// import channel from file
if($src) {
@ -146,7 +148,20 @@ class Import extends \Zotlabs\Web\Controller {
}
}
$channel = import_channel($data['channel'], $account_id, $seize);
if($newname) {
$x = false;
if(get_config('system','unicode_usernames')) {
$x = punify(mb_strtolower($newname));
}
if((! $x) || strlen($x) > 64) {
$x = strtolower(\URLify::transliterate($newname));
}
$newname = $x;
}
$channel = import_channel($data['channel'], $account_id, $seize, $newname);
}
else {
$moving = false;
@ -542,6 +557,7 @@ class Import extends \Zotlabs\Web\Controller {
'$make_primary' => [ 'make_primary', t('Make this hub my primary location'), false, '', [ t('No'), t('Yes') ] ],
'$moving' => [ 'moving', t('Move this channel (disable all previous locations)'), false, '', [ t('No'), t('Yes') ] ],
'$newname' => [ 'newname', t('Use this channel nickname instead of the one provided'), '', t('Leave blank to keep your existing channel nickname. You will be randomly assigned a similar nickname if either name is already allocated on this site.')],
'$pleasewait' => t('This process may take several minutes to complete. Please submit the form only once and leave this page open until finished.'),

View File

@ -113,7 +113,7 @@ class Invite extends \Zotlabs\Web\Controller {
$invite_code = autoname(8) . rand(1000,9999);
$nmessage = str_replace('$invite_code',$invite_code,$message);
$r = q("INSERT INTO register (hash,created) VALUES ('%s', '%s') ",
$r = q("INSERT INTO register (hash,created,uid,password,lang) VALUES ('%s', '%s',0,'','') ",
dbesc($invite_code),
dbesc(datetime_convert())
);

View File

@ -528,22 +528,12 @@ class Item extends \Zotlabs\Web\Controller {
// and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.)
// we may need virtual or template classes to implement the possible alternatives
// If we're sending a private top-level message with a single @-taggable channel as a recipient, @-tag it, if our pconfig is set.
if((! $parent) && (get_pconfig($profile_uid,'system','tagifonlyrecip')) && (substr_count($str_contact_allow,'<') == 1) && ($str_group_allow == '') && ($str_contact_deny == '') && ($str_group_deny == '')) {
$x = q("select abook_id, abconfig.v from abook left join abconfig on abook_xchan = abconfig.xchan and abook_channel = abconfig.chan and cat= 'their_perms' and abconfig.k = 'tag_deliver' and abconfig.v = 1 and abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc(str_replace(array('<','>'),array('',''),$str_contact_allow)),
intval($profile_uid)
);
if($x)
$body .= "\n\n@group+" . $x[0]['abook_id'] . "\n";
}
$body = cleanup_bbcode($body);
// Look for tags and linkify them
$results = linkify_tags($a, $body, ($uid) ? $uid : $profile_uid);
logger('linkify: ' . print_r($results,true));
if($results) {
// Set permissions based on tag replacements
@ -1084,24 +1074,36 @@ class Item extends \Zotlabs\Web\Controller {
if((argc() == 3) && (argv(1) === 'drop') && intval(argv(2))) {
require_once('include/items.php');
$i = q("select id, uid, author_xchan, owner_xchan, source_xchan, item_type from item where id = %d limit 1",
$i = q("select id, uid, item_origin, author_xchan, owner_xchan, source_xchan, item_type from item where id = %d limit 1",
intval(argv(2))
);
if($i) {
$can_delete = false;
$local_delete = false;
if(local_channel() && local_channel() == $i[0]['uid'])
if(local_channel() && local_channel() == $i[0]['uid']) {
$local_delete = true;
$sys = get_sys_channel();
if(is_site_admin() && $sys['channel_id'] == $i[0]['uid'])
$can_delete = true;
}
$ob_hash = get_observer_hash();
if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan']))
if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) {
$can_delete = true;
}
// The site admin can delete any post/item on the site.
// If the item originated on this site+channel the deletion will propagate downstream.
// Otherwise just the local copy is removed.
if(is_site_admin()) {
$local_delete = true;
if(intval($i[0]['item_origin']))
$can_delete = true;
}
if(! ($can_delete || $local_delete)) {
notice( t('Permission denied.') . EOL);
return;

View File

@ -55,10 +55,10 @@ class Linkinfo extends \Zotlabs\Web\Controller {
$h = explode("\n",$result['header']);
foreach ($h as $l) {
list($k,$v) = array_map("trim", explode(":", trim($l), 2));
$hdrs[$k] = $v;
$hdrs[strtolower($k)] = $v;
}
if (array_key_exists('Content-Type', $hdrs))
$type = $hdrs['Content-Type'];
if (array_key_exists('content-type', $hdrs))
$type = $hdrs['content-type'];
if($type) {
$zrl = is_matrix_url($url);
if(stripos($type,'image/') !== false) {
@ -82,6 +82,10 @@ class Linkinfo extends \Zotlabs\Web\Controller {
echo $br . '[audio]' . $url . '[/audio]' . $br;
killme();
}
if(strtolower($type) === 'application/pdf' || strtolower($type) === 'application/x-pdf') {
echo $br . '[embed]' . $url . '[/embed]' . $br;
killme();
}
}
}

View File

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

View File

@ -24,8 +24,6 @@ class Magic extends \Zotlabs\Web\Controller {
if($bdest)
$dest = hex2bin($bdest);
$dest = html_entity_decode($dest);
$parsed = parse_url($dest);
if(! $parsed) {
if($test) {
@ -145,6 +143,9 @@ class Magic extends \Zotlabs\Web\Controller {
if($owa) {
$dest = strip_zids($dest);
$dest = strip_query_param($dest,'f');
$headers = [];
$headers['Accept'] = 'application/x-zot+json' ;
$headers['X-Open-Web-Auth'] = random_string();

View File

@ -156,7 +156,7 @@ class Manage extends \Zotlabs\Web\Controller {
if($delegates) {
for($x = 0; $x < count($delegates); $x ++) {
$delegates[$x]['link'] = 'magic?f=&dest=' . urlencode($delegates[$x]['xchan_url'])
$delegates[$x]['link'] = 'magic?f=&bdest=' . bin2hex($delegates[$x]['xchan_url'])
. '&delegate=' . urlencode($delegates[$x]['xchan_addr']);
$delegates[$x]['channel_name'] = $delegates[$x]['xchan_name'];
$delegates[$x]['delegate'] = 1;

View File

@ -7,18 +7,36 @@ require_once('include/channel.php');
class Menu extends \Zotlabs\Web\Controller {
function init() {
if (array_key_exists('sys', $_REQUEST) && $_REQUEST['sys'] && is_site_admin()) {
if(argc() > 1 && argv(1) === 'sys' && is_site_admin()) {
$sys = get_sys_channel();
if ($sys && intval($sys['channel_id'])) {
if($sys && intval($sys['channel_id'])) {
\App::$is_sys = true;
}
}
if(argc() > 1)
$which = argv(1);
else
return;
profile_load($which);
}
function post() {
function post() {
$uid = local_channel();
if(! \App::$profile) {
return;
}
$which = argv(1);
$uid = \App::$profile['channel_id'];
if(array_key_exists('sys', $_REQUEST) && $_REQUEST['sys'] && is_site_admin()) {
$sys = get_sys_channel();
@ -43,7 +61,7 @@ class Menu extends \Zotlabs\Web\Controller {
if($r) {
menu_sync_packet($uid,get_observer_hash(),$menu_id);
//info( t('Menu updated.') . EOL);
goaway(z_root() . '/mitem/' . $menu_id . ((\App::$is_sys) ? '?f=&sys=1' : ''));
goaway(z_root() . '/mitem/' . $which . '/' . $menu_id . ((\App::$is_sys) ? '?f=&sys=1' : ''));
}
else
notice( t('Unable to update menu.'). EOL);
@ -54,7 +72,7 @@ class Menu extends \Zotlabs\Web\Controller {
menu_sync_packet($uid,get_observer_hash(),$r);
//info( t('Menu created.') . EOL);
goaway(z_root() . '/mitem/' . $r . ((\App::$is_sys) ? '?f=&sys=1' : ''));
goaway(z_root() . '/mitem/' . $which . '/' . $r . ((\App::$is_sys) ? '?f=&sys=1' : ''));
}
else
notice( t('Unable to create menu.'). EOL);
@ -67,27 +85,71 @@ class Menu extends \Zotlabs\Web\Controller {
function get() {
if(! \App::$profile) {
notice( t('Requested profile is not available.') . EOL );
\App::$error = 404;
return;
}
$which = argv(1);
$_SESSION['return_url'] = \App::$query_string;
$uid = local_channel();
if (\App::$is_sys && is_site_admin()) {
$owner = 0;
$channel = null;
$observer = \App::get_observer();
$channel = \App::get_channel();
if(\App::$is_sys && is_site_admin()) {
$sys = get_sys_channel();
$uid = intval($sys['channel_id']);
if($sys && intval($sys['channel_id'])) {
$uid = $owner = intval($sys['channel_id']);
$channel = $sys;
$observer = $sys;
}
}
if(! $uid) {
if(! $owner) {
// Figure out who the page owner is.
$r = channelx_by_nick($which);
if($r) {
$owner = intval($r['channel_id']);
}
}
$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
$perms = get_all_perms($owner,$ob_hash);
if(! $perms['write_pages']) {
notice( t('Permission denied.') . EOL);
return '';
return;
}
// Get the observer, check their permissions
$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
$perms = get_all_perms($owner,$ob_hash);
if(! $perms['write_pages']) {
notice( t('Permission denied.') . EOL);
return;
}
if(argc() == 2) {
if(argc() == 1) {
$channel = (($sys) ? $sys : \App::get_channel());
$channel = (($sys) ? $sys : channelx_by_n($owner));
// list menus
$x = menu_list($uid);
$x = menu_list($owner);
if($x) {
for($y = 0; $y < count($x); $y ++) {
$m = menu_fetch($x[$y]['menu_name'],$uid,get_observer_hash());
$m = menu_fetch($x[$y]['menu_name'],$owner,get_observer_hash());
if($m)
$x[$y]['element'] = '[element]' . base64url_encode(json_encode(menu_element($channel,$m))) . '[/element]';
$x[$y]['bookmark'] = (($x[$y]['menu_flags'] & MENU_BOOKMARK) ? true : false);
@ -100,6 +162,7 @@ class Menu extends \Zotlabs\Web\Controller {
'$menu_bookmark' => array('menu_bookmark', t('Allow Bookmarks'), 0 , t('Menu may be used to store saved bookmarks'), array(t('No'), t('Yes'))),
'$submit' => t('Submit and proceed'),
'$sys' => \App::$is_sys,
'$nick' => $which,
'$display' => 'none'
));
@ -119,6 +182,7 @@ class Menu extends \Zotlabs\Web\Controller {
'$hintdrop' => t('Delete this menu'),
'$hintcontent' => t('Edit menu contents'),
'$hintedit' => t('Edit this menu'),
'$nick' => $which,
'$sys' => \App::$is_sys
));
@ -126,19 +190,19 @@ class Menu extends \Zotlabs\Web\Controller {
}
if(argc() > 1) {
if(intval(argv(1))) {
if(argc() > 2) {
if(intval(argv(2))) {
if(argc() == 3 && argv(2) == 'drop') {
menu_sync_packet($uid,get_observer_hash(),intval(argv(1)),true);
$r = menu_delete_id(intval(argv(1)),$uid);
if(argc() == 4 && argv(3) == 'drop') {
menu_sync_packet($owner,get_observer_hash(),intval(argv(1)),true);
$r = menu_delete_id(intval(argv(2)),$owner);
if(!$r)
notice( t('Menu could not be deleted.'). EOL);
goaway(z_root() . '/menu' . ((\App::$is_sys) ? '?f=&sys=1' : ''));
goaway(z_root() . '/menu/' . $which . ((\App::$is_sys) ? '?f=&sys=1' : ''));
}
$m = menu_fetch_id(intval(argv(1)),$uid);
$m = menu_fetch_id(intval(argv(2)),$owner);
if(! $m) {
notice( t('Menu not found.') . EOL);
@ -148,14 +212,15 @@ class Menu extends \Zotlabs\Web\Controller {
$o = replace_macros(get_markup_template('menuedit.tpl'), array(
'$header' => t('Edit Menu'),
'$sys' => \App::$is_sys,
'$menu_id' => intval(argv(1)),
'$menu_edit_link' => 'mitem/' . intval(argv(1)) . ((\App::$is_sys) ? '?f=&sys=1' : ''),
'$menu_id' => intval(argv(2)),
'$menu_edit_link' => 'mitem/' . $which . '/' . intval(argv(1)) . ((\App::$is_sys) ? '?f=&sys=1' : ''),
'$hintedit' => t('Add or remove entries to this menu'),
'$editcontents' => t('Edit menu contents'),
'$menu_name' => array('menu_name', t('Menu name'), $m['menu_name'], t('Must be unique, only seen by you'), '*'),
'$menu_desc' => array('menu_desc', t('Menu title'), $m['menu_desc'], t('Menu title as seen by others'), ''),
'$menu_bookmark' => array('menu_bookmark', t('Allow bookmarks'), (($m['menu_flags'] & MENU_BOOKMARK) ? 1 : 0), t('Menu may be used to store saved bookmarks'), array(t('No'), t('Yes'))),
'$menu_system' => (($m['menu_flags'] & MENU_SYSTEM) ? 1 : 0),
'$nick' => $which,
'$submit' => t('Submit and proceed')
));

View File

@ -8,22 +8,25 @@ require_once('include/acl_selectors.php');
class Mitem extends \Zotlabs\Web\Controller {
function init() {
$uid = local_channel();
if(array_key_exists('sys',$_REQUEST) && $_REQUEST['sys'] && is_site_admin()) {
if(argc() > 1 && argv(1) === 'sys' && is_site_admin()) {
$sys = get_sys_channel();
$uid = intval($sys['channel_id']);
\App::$is_sys = true;
if($sys && intval($sys['channel_id'])) {
\App::$is_sys = true;
}
}
if(argc() > 1)
$which = argv(1);
else
return;
profile_load($which);
if(! $uid)
if(argc() < 3)
return;
if(argc() < 2)
return;
$m = menu_fetch_id(intval(argv(1)),$uid);
$m = menu_fetch_id(intval(argv(2)),\App::$profile['channel_id']);
if(! $m) {
notice( t('Menu not found.') . EOL);
return '';
@ -32,19 +35,27 @@ class Mitem extends \Zotlabs\Web\Controller {
}
function post() {
function post() {
$uid = local_channel();
if(\App::$is_sys && is_site_admin()) {
$sys = get_sys_channel();
$uid = intval($sys['channel_id']);
}
if(! $uid) {
if(! \App::$profile) {
return;
}
$which = argv(1);
$uid = \App::$profile['channel_id'];
if(array_key_exists('sys', $_REQUEST) && $_REQUEST['sys'] && is_site_admin()) {
$sys = get_sys_channel();
$uid = intval($sys['channel_id']);
\App::$is_sys = true;
}
if(! $uid)
return;
if(! \App::$data['menu'])
return;
@ -63,14 +74,14 @@ class Mitem extends \Zotlabs\Web\Controller {
$_REQUEST['mitem_flags'] |= MENU_ITEM_NEWWIN;
$mitem_id = ((argc() > 2) ? intval(argv(2)) : 0);
$mitem_id = ((argc() > 3) ? intval(argv(3)) : 0);
if($mitem_id) {
$_REQUEST['mitem_id'] = $mitem_id;
$r = menu_edit_item($_REQUEST['menu_id'],$uid,$_REQUEST);
if($r) {
menu_sync_packet($uid,get_observer_hash(),$_REQUEST['menu_id']);
//info( t('Menu element updated.') . EOL);
goaway(z_root() . '/mitem/' . $_REQUEST['menu_id'] . ((\App::$is_sys) ? '?f=&sys=1' : ''));
goaway(z_root() . '/mitem/' . $which . '/' . $_REQUEST['menu_id'] . ((\App::$is_sys) ? '?f=&sys=1' : ''));
}
else
notice( t('Unable to update menu element.') . EOL);
@ -82,10 +93,10 @@ class Mitem extends \Zotlabs\Web\Controller {
menu_sync_packet($uid,get_observer_hash(),$_REQUEST['menu_id']);
//info( t('Menu element added.') . EOL);
if($_REQUEST['submit']) {
goaway(z_root() . '/menu' . ((\App::$is_sys) ? '?f=&sys=1' : ''));
goaway(z_root() . '/menu/' . $which . ((\App::$is_sys) ? '?f=&sys=1' : ''));
}
if($_REQUEST['submit-more']) {
goaway(z_root() . '/mitem/' . $_REQUEST['menu_id'] . '?f=&display=block' . ((\App::$is_sys) ? '&sys=1' : '') );
goaway(z_root() . '/mitem/' . $which . '/' . $_REQUEST['menu_id'] . '?f=&display=block' . ((\App::$is_sys) ? '&sys=1' : '') );
}
}
else
@ -96,12 +107,15 @@ class Mitem extends \Zotlabs\Web\Controller {
}
function get() {
function get() {
$uid = local_channel();
$channel = \App::get_channel();
$owner = \App::$profile['channel_id'];
$channel = channelx_by_n($owner);
$observer = \App::get_observer();
$which = argv(1);
$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
if(\App::$is_sys && is_site_admin()) {
@ -116,15 +130,15 @@ class Mitem extends \Zotlabs\Web\Controller {
return '';
}
if(argc() < 2 || (! \App::$data['menu'])) {
if(argc() < 3 || (! \App::$data['menu'])) {
notice( t('Not found.') . EOL);
return '';
}
$m = menu_fetch(\App::$data['menu']['menu_name'],$uid,$ob_hash);
$m = menu_fetch(\App::$data['menu']['menu_name'],$owner,$ob_hash);
\App::$data['menu_item'] = $m;
$menu_list = menu_list($uid);
$menu_list = menu_list($owner);
foreach($menu_list as $menus) {
if($menus['menu_name'] != $m['menu']['menu_name'])
@ -135,10 +149,10 @@ class Mitem extends \Zotlabs\Web\Controller {
$lockstate = (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock');
if(argc() == 2) {
if(argc() == 3) {
$r = q("select * from menu_item where mitem_menu_id = %d and mitem_channel_id = %d order by mitem_order asc, mitem_desc asc",
intval(\App::$data['menu']['menu_id']),
intval($uid)
intval($owner)
);
if($_GET['display']) {
@ -167,6 +181,7 @@ class Mitem extends \Zotlabs\Web\Controller {
'$display' => $display,
'$lockstate' => $lockstate,
'$menu_names' => $menu_names,
'$nick' => $which,
'$sys' => \App::$is_sys
));
@ -187,40 +202,41 @@ class Mitem extends \Zotlabs\Web\Controller {
'$hintnew' => t('Add menu element'),
'$hintdrop' => t('Delete this menu item'),
'$hintedit' => t('Edit this menu item'),
'$nick' => $which,
));
return $o;
}
if(argc() > 2) {
if(intval(argv(2))) {
if(argc() > 3) {
if(intval(argv(3))) {
$m = q("select * from menu_item where mitem_id = %d and mitem_channel_id = %d limit 1",
intval(argv(2)),
intval($uid)
intval(argv(3)),
intval($owner)
);
if(! $m) {
notice( t('Menu item not found.') . EOL);
goaway(z_root() . '/menu'. ((\App::$is_sys) ? '?f=&sys=1' : ''));
goaway(z_root() . '/menu/'. $which . ((\App::$is_sys) ? '?f=&sys=1' : ''));
}
$mitem = $m[0];
$lockstate = (($mitem['allow_cid'] || $mitem['allow_gid'] || $mitem['deny_cid'] || $mitem['deny_gid']) ? 'lock' : 'unlock');
if(argc() == 4 && argv(3) == 'drop') {
menu_sync_packet($uid,get_observer_hash(),$mitem['mitem_menu_id']);
$r = menu_del_item($mitem['mitem_menu_id'], $uid, intval(argv(2)));
menu_sync_packet($uid,get_observer_hash(),$mitem['mitem_menu_id']);
if(argc() == 5 && argv(4) == 'drop') {
menu_sync_packet($owner,get_observer_hash(),$mitem['mitem_menu_id']);
$r = menu_del_item($mitem['mitem_menu_id'], $owner, intval(argv(3)));
menu_sync_packet($owner,get_observer_hash(),$mitem['mitem_menu_id']);
if($r)
info( t('Menu item deleted.') . EOL);
else
notice( t('Menu item could not be deleted.'). EOL);
goaway(z_root() . '/mitem/' . $mitem['mitem_menu_id'] . ((\App::$is_sys) ? '?f=&sys=1' : ''));
goaway(z_root() . '/mitem/' . $which . '/' . $mitem['mitem_menu_id'] . ((\App::$is_sys) ? '?f=&sys=1' : ''));
}
// edit menu item
@ -234,7 +250,7 @@ class Mitem extends \Zotlabs\Web\Controller {
'$allow_gid' => acl2json($mitem['allow_gid']),
'$deny_cid' => acl2json($mitem['deny_cid']),
'$deny_gid' => acl2json($mitem['deny_gid']),
'$mitem_id' => intval(argv(2)),
'$mitem_id' => intval(argv(3)),
'$mitem_desc' => array('mitem_desc', t('Link text'), $mitem['mitem_desc'], '','*'),
'$mitem_link' => array('mitem_link', t('Link or Submenu Target'), $mitem['mitem_link'], 'Enter URL of the link or select a menu name to create a submenu', '*', 'list="menu-names"'),
'$usezid' => array('usezid', t('Use magic-auth if available'), (($mitem['mitem_flags'] & MENU_ITEM_ZID) ? 1 : 0), '', array(t('No'), t('Yes'))),
@ -242,7 +258,8 @@ class Mitem extends \Zotlabs\Web\Controller {
'$mitem_order' => array('mitem_order', t('Order in list'),$mitem['mitem_order'],t('Higher numbers will sink to bottom of listing')),
'$submit' => t('Submit'),
'$lockstate' => $lockstate,
'$menu_names' => $menu_names
'$menu_names' => $menu_names,
'$nick' => $which
));
return $o;

View File

@ -15,6 +15,9 @@ class Network extends \Zotlabs\Web\Controller {
notice( t('Permission denied.') . EOL);
return;
}
if(in_array(substr($_GET['search'],0,1),[ '@', '!', '?']))
goaway('search' . '?f=&search=' . $_GET['search']);
if(count($_GET) < 2) {
$network_options = get_pconfig(local_channel(),'system','network_page_default');
@ -57,13 +60,26 @@ class Network extends \Zotlabs\Web\Controller {
$datequery = ((x($_GET,'dend') && is_a_date_arg($_GET['dend'])) ? notags($_GET['dend']) : '');
$datequery2 = ((x($_GET,'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : '');
$nouveau = ((x($_GET,'new')) ? intval($_GET['new']) : 0);
$static = ((x($_GET,'static')) ? intval($_GET['static']) : 0);
$gid = ((x($_GET,'gid')) ? intval($_GET['gid']) : 0);
$category = ((x($_REQUEST,'cat')) ? $_REQUEST['cat'] : '');
$hashtags = ((x($_REQUEST,'tag')) ? $_REQUEST['tag'] : '');
$verb = ((x($_REQUEST,'verb')) ? $_REQUEST['verb'] : '');
$order = get_pconfig(local_channel(), 'mod_network', 'order', 0);
switch($order) {
case 0:
$order = 'comment';
break;
case 1:
$order = 'post';
break;
case 2:
$nouveau = true;
break;
}
$search = (($_GET['search']) ? $_GET['search'] : '');
if($search) {
$_GET['netsearch'] = escape_tags($search);
@ -84,7 +100,7 @@ class Network extends \Zotlabs\Web\Controller {
}
if($datequery)
$_GET['order'] = 'post';
$order = 'post';
// filter by collection (e.g. group)
@ -110,12 +126,8 @@ class Network extends \Zotlabs\Web\Controller {
$default_cmin = ((feature_enabled(local_channel(),'affinity')) ? get_pconfig(local_channel(),'affinity','cmin',0) : (-1));
$default_cmax = ((feature_enabled(local_channel(),'affinity')) ? get_pconfig(local_channel(),'affinity','cmax',99) : (-1));
// if no tabs are selected, defaults to comments
$cid = ((x($_GET,'cid')) ? intval($_GET['cid']) : 0);
$star = ((x($_GET,'star')) ? intval($_GET['star']) : 0);
$order = ((x($_GET,'order')) ? notags($_GET['order']) : 'comment');
$liked = ((x($_GET,'liked')) ? intval($_GET['liked']) : 0);
$conv = ((x($_GET,'conv')) ? intval($_GET['conv']) : 0);
$spam = ((x($_GET,'spam')) ? intval($_GET['spam']) : 0);
@ -124,18 +136,21 @@ class Network extends \Zotlabs\Web\Controller {
$file = ((x($_GET,'file')) ? $_GET['file'] : '');
$xchan = ((x($_GET,'xchan')) ? $_GET['xchan'] : '');
$net = ((x($_GET,'net')) ? $_GET['net'] : '');
$pf = ((x($_GET,'pf')) ? $_GET['pf'] : '');
$deftag = '';
if(x($_GET,'search') || x($_GET,'file'))
if(x($_GET,'search') || $file || (!$pf && $cid))
$nouveau = true;
if($cid) {
$r = q("SELECT abook_xchan FROM abook WHERE abook_id = %d AND abook_channel = %d LIMIT 1",
$cid_r = q("SELECT abook.abook_xchan, xchan.xchan_addr, xchan.xchan_name, xchan.xchan_url, xchan.xchan_photo_s, xchan.xchan_pubforum from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d and abook_blocked = 0 limit 1",
intval($cid),
intval(local_channel())
);
if(! $r) {
if(! $cid_r) {
if($update) {
killme();
}
@ -143,14 +158,14 @@ class Network extends \Zotlabs\Web\Controller {
goaway(z_root() . '/network');
// NOTREACHED
}
if($_GET['pf'] === '1')
$deftag = '!' . t('forum') . '+' . intval($cid);
if($pf)
$deftag = '!{' . (($cid_r[0]['xchan_addr']) ? $cid_r[0]['xchan_addr'] : $cid_r[0]['xchan_url']) . '}';
else
$def_acl = [ 'allow_cid' => '<' . $r[0]['abook_xchan'] . '>', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ];
$def_acl = [ 'allow_cid' => '<' . $cid_r[0]['abook_xchan'] . '>', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ];
}
if(! $update) {
$tabs = network_tabs();
$tabs = ''; //network_tabs();
$o .= $tabs;
// search terms header
@ -185,7 +200,8 @@ class Network extends \Zotlabs\Web\Controller {
'editor_autocomplete' => true,
'bbco_autocomplete' => 'bbcode',
'bbcode' => true,
'jotnets' => true
'jotnets' => true,
'reset' => t('Reset form')
);
if($deftag)
$x['pretext'] = $deftag;
@ -218,17 +234,16 @@ class Network extends \Zotlabs\Web\Controller {
$contact_str = '';
$contacts = group_get_members($group);
if($contacts) {
foreach($contacts as $c) {
if($contact_str)
$contact_str .= ',';
$contact_str .= "'" . $c['xchan'] . "'";
}
$contact_str = ids_to_querystr($contacts,'xchan',true);
}
else {
$contact_str = ' 0 ';
info( t('Privacy group is empty'));
$contact_str = " '0' ";
if(! $update) {
info( t('Privacy group is empty'));
}
}
$item_thread_top = '';
$sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str )) or allow_gid like '" . protect_sprintf('%<' . dbesc($group_hash) . '>%') . "' ) and id = parent $item_normal ) ";
$x = group_rec_byhash(local_channel(), $group_hash);
@ -244,27 +259,31 @@ class Network extends \Zotlabs\Web\Controller {
$o .= $status_editor;
}
elseif($cid) {
$r = q("SELECT abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d and abook_blocked = 0 limit 1",
intval($cid),
intval(local_channel())
);
if($r) {
$item_thread_top = '';
$sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($r[0]['abook_xchan']) . "' or owner_xchan = '" . dbesc($r[0]['abook_xchan']) . "' ) $item_normal ) ";
$title = replace_macros(get_markup_template("section_title.tpl"),array(
'$title' => '<a href="' . zid($r[0]['xchan_url']) . '" ><img src="' . zid($r[0]['xchan_photo_s']) . '" alt="' . urlencode($r[0]['xchan_name']) . '" /></a> <a href="' . zid($r[0]['xchan_url']) . '" >' . $r[0]['xchan_name'] . '</a>'
));
$o = $tabs;
$o .= $title;
$o .= $status_editor;
}
else {
notice( t('Invalid connection.') . EOL);
goaway(z_root() . '/network');
elseif($cid_r) {
$item_thread_top = '';
if($load || $update) {
if(!$pf && $nouveau) {
$sql_extra = " AND author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ";
}
else {
$ttype = (($pf) ? TERM_FORUM : TERM_MENTION);
$p1 = q("SELECT DISTINCT parent FROM item WHERE uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' OR owner_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ) $item_normal ");
$p2 = q("SELECT oid AS parent FROM term WHERE uid = " . intval(local_channel()) . " AND ttype = $ttype AND term = '" . dbesc($cid_r[0]['xchan_name']) . "'");
$p_str = ids_to_querystr(array_merge($p1,$p2),'parent');
$sql_extra = " AND item.parent IN ( $p_str ) ";
}
}
$title = replace_macros(get_markup_template("section_title.tpl"),array(
'$title' => '<a href="' . zid($cid_r[0]['xchan_url']) . '" ><img src="' . zid($cid_r[0]['xchan_photo_s']) . '" alt="' . urlencode($cid_r[0]['xchan_name']) . '" /></a> <a href="' . zid($cid_r[0]['xchan_url']) . '" >' . $cid_r[0]['xchan_name'] . '</a>'
));
$o = $tabs;
$o .= $title;
$o .= $status_editor;
}
elseif($xchan) {
$r = q("select * from xchan where xchan_hash = '%s'",
@ -338,7 +357,8 @@ class Network extends \Zotlabs\Web\Controller {
'$mid' => '',
'$verb' => $verb,
'$net' => $net,
'$dbegin' => $datequery2
'$dbegin' => $datequery2,
'$pf' => (($pf) ? $pf : '0'),
));
}
@ -378,9 +398,15 @@ class Network extends \Zotlabs\Web\Controller {
if($conv) {
$item_thread_top = '';
$sql_extra .= sprintf(" AND parent IN (SELECT distinct(parent) from item where ( author_xchan like '%s' or item_mentionsme = 1 )) ",
dbesc(protect_sprintf($channel['channel_hash']))
);
if($nouveau) {
$sql_extra .= " AND author_xchan = '" . dbesc($channel['channel_hash']) . "' ";
}
else {
$sql_extra .= sprintf(" AND parent IN (SELECT distinct(parent) from item where ( author_xchan = '%s' or item_mentionsme = 1 )) ",
dbesc(protect_sprintf($channel['channel_hash']))
);
}
}
if($update && ! $load) {
@ -454,7 +480,7 @@ class Network extends \Zotlabs\Web\Controller {
if($nouveau && $load) {
// "New Item View" - show all items unthreaded in reverse created date order
$items = q("SELECT item.*, item.id AS item_id, received FROM item
$items = q("SELECT item.*, item.id AS item_id, created FROM item
left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids )
$net_query
WHERE true $uids $item_normal
@ -462,7 +488,7 @@ class Network extends \Zotlabs\Web\Controller {
$simple_update
$sql_extra $sql_options $sql_nets
$net_query2
ORDER BY item.received DESC $pager_sql "
ORDER BY item.created DESC $pager_sql "
);
require_once('include/items.php');
@ -476,12 +502,11 @@ class Network extends \Zotlabs\Web\Controller {
// Normal conversation view
if($order === 'post')
$ordering = "created";
$ordering = "created";
else
$ordering = "commented";
$ordering = "commented";
if($load) {
// Fetch a page full of parent items for this page
$r = q("SELECT item.parent AS item_id FROM item
left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids )
@ -562,6 +587,9 @@ class Network extends \Zotlabs\Web\Controller {
}
$mode = (($nouveau) ? 'network-new' : 'network');
if($search)
$mode = 'search';
$o .= conversation($items,$mode,$update,$page_mode);

View File

@ -41,7 +41,7 @@ class New_channel extends \Zotlabs\Web\Controller {
$test[] = legal_webbie($x);
// fullname plus random number
$test[] = legal_webbie($x) . mt_rand(1000,9999);
json_return_and_die(check_webbie($test));
}
@ -49,7 +49,10 @@ class New_channel extends \Zotlabs\Web\Controller {
require_once('library/urlify/URLify.php');
$result = array('error' => false, 'message' => '');
$n = trim($_REQUEST['nick']);
if(! $n) {
$n = trim($_REQUEST['name']);
}
$x = false;
if(get_config('system','unicode_usernames')) {
@ -58,9 +61,20 @@ class New_channel extends \Zotlabs\Web\Controller {
if((! $x) || strlen($x) > 64)
$x = strtolower(\URLify::transliterate($n));
$test = array();
// first name
if(strpos($x,' '))
$test[] = legal_webbie(substr($x,0,strpos($x,' ')));
if($test[0]) {
// first name plus first initial of last
$test[] = ((strpos($x,' ')) ? $test[0] . legal_webbie(trim(substr($x,strpos($x,' '),2))) : '');
// first name plus random number
$test[] = $test[0] . mt_rand(1000,9999);
}
$n = legal_webbie($x);
if(strlen($n)) {
$test[] = $n;
@ -124,7 +138,7 @@ class New_channel extends \Zotlabs\Web\Controller {
intval($aid)
);
if($r && (! intval($r[0]['total']))) {
$default_role = get_config('system','default_permissions_role');
$default_role = get_config('system','default_permissions_role','social');
}
$limit = account_service_class_fetch(get_account_id(),'total_identities');
@ -136,21 +150,35 @@ class New_channel extends \Zotlabs\Web\Controller {
$channel_usage_message = '';
}
}
$name_help = '<span id="name_help_loading" style="display:none">' . t('Loading') . '</span><span id="name_help_text">';
$name_help .= (($default_role)
? t('Your real name is recommended.')
: t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group"')
);
$name_help .= '</span>';
$nick_help = '<span id="nick_help_loading" style="display:none">' . t('Loading') . '</span><span id="nick_help_text">';
$nick_help .= t('This will be used to create a unique network address (like an email address).');
if(! get_config('system','unicode_usernames')) {
$nick_help .= ' ' . t('Allowed characters are a-z 0-9, - and _');
}
$nick_help .= '<span>';
$privacy_role = ((x($_REQUEST,'permissions_role')) ? $_REQUEST['permissions_role'] : "" );
$perm_roles = \Zotlabs\Access\PermissionRoles::roles();
if((get_account_techlevel() < 4) && $privacy_role !== 'custom')
unset($perm_roles[t('Other')]);
$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('Channel name'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), $name_help, "*");
$nickhub = '@' . \App::get_hostname();
$nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), sprintf( t('Your nickname will be used to create an easy to remember channel address e.g. nickname%s'), $nickhub), "*");
$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/member/member_guide#Channel_Permission_Roles" target="_blank">' . t('Read more about roles') . '</a>',$perm_roles);
$nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), $nick_help, "*");
$role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel permission role compatible with your usage needs and privacy requirements.') . '<br>' . '<a href="help/member/member_guide#Channel_Permission_Roles" target="_blank">' . t('Read more about channel permission roles') . '</a>',$perm_roles);
$o = replace_macros(get_markup_template('new_channel.tpl'), array(
'$title' => t('Create Channel'),
'$desc' => t('A channel is a unique network identity. It can represent a person (social network profile), a forum (group), a business or celebrity page, a newsfeed, and many other things. Channels can make connections with other channels to share information with each other.') . ' ' . t('The type of channel you create affects the basic privacy settings, the permissions that are granted to connections/friends, and also the channel\'s visibility across the network.'),
'$title' => t('Create a Channel'),
'$desc' => t('A channel is a unique network identity. It can represent a person (social network profile), a forum (group), a business or celebrity page, a newsfeed, and many other things.') ,
'$label_import' => t('or <a href="import">import an existing channel</a> from another location.'),
'$name' => $name,
'$role' => $role,

View File

@ -7,8 +7,8 @@ class Nojs extends \Zotlabs\Web\Controller {
function init() {
$n = ((argc() > 1) ? intval(argv(1)) : 1);
setcookie('jsdisabled', $n, 0, '/');
$p = $_GET['redir'];
$hasq = strpos($p,'?');
$p = hex2bin($_GET['redir']);
$hasq = strpbrk($p,'?&');
goaway(z_root() . (($p) ? '/' . $p : '') . (($hasq) ? '' : '?f=' ) . '&jsdisabled=' . $n);
}

View File

@ -41,8 +41,6 @@ class Notifications extends \Zotlabs\Web\Controller {
$notifications_available = 1;
foreach ($r as $rr) {
$x = strip_tags(bbcode($rr['msg']));
if(strpos($x,','))
$x = substr($x,strpos($x,',')+1);
$notif_content .= replace_macros(get_markup_template('notify.tpl'),array(
'$item_link' => z_root().'/notify/view/'. $rr['id'],
'$item_image' => $rr['photo'],

View File

@ -0,0 +1,23 @@
<?php
namespace Zotlabs\Module;
class Oauthinfo extends \Zotlabs\Web\Controller {
function init() {
$ret = [
'issuer' => z_root(),
'authorization_endpoint' => z_root() . '/authorize',
'token_endpoint' => z_root() . '/token',
'response_types_supported' => [ 'code', 'token', 'id_token', 'code id_token', 'token id_token' ]
];
json_return_and_die($ret);
}
}

View File

@ -4,6 +4,7 @@ namespace Zotlabs\Module;
require_once('include/security.php');
require_once('include/attach.php');
require_once('include/photo/photo_driver.php');
require_once('include/photos.php');
class Photo extends \Zotlabs\Web\Controller {
@ -13,7 +14,8 @@ class Photo extends \Zotlabs\Web\Controller {
$prvcachecontrol = false;
$streaming = null;
$channel = null;
$person = 0;
switch(argc()) {
case 4:
$person = argv(3);
@ -30,8 +32,8 @@ class Photo extends \Zotlabs\Web\Controller {
}
$observer_xchan = get_observer_hash();
$default = get_default_profile_photo();
$default = z_root() . '/' . get_default_profile_photo();
if(isset($type)) {
@ -45,11 +47,11 @@ class Photo extends \Zotlabs\Web\Controller {
case 'm':
$resolution = 5;
$default = get_default_profile_photo(80);
$default = z_root() . '/' . get_default_profile_photo(80);
break;
case 's':
$resolution = 6;
$default = get_default_profile_photo(48);
$default = z_root() . '/' . get_default_profile_photo(48);
break;
case 'l':
default:
@ -83,7 +85,7 @@ class Photo extends \Zotlabs\Web\Controller {
$data = file_get_contents($data);
}
if(! $data) {
$data = file_get_contents($default);
$data = fetch_image_from_url($default,$mimetype);
}
if(! $mimetype) {
$mimetype = 'image/png';
@ -135,6 +137,20 @@ class Photo extends \Zotlabs\Web\Controller {
$allowed = (-1);
if(intval($r[0]['photo_usage'])) {
$allowed = 1;
if(intval($r[0]['photo_usage']) === PHOTO_COVER)
if($resolution < PHOTO_RES_COVER_1200)
$allowed = (-1);
if(intval($r[0]['photo_usage']) === PHOTO_PROFILE)
if(! in_array($resolution,[4,5,6]))
$allowed = (-1);
}
if($allowed === (-1)) {
$allowed = attach_can_view($r[0]['uid'],$observer_xchan,$photo);
}
if(intval($r[0]['photo_usage'])) {
$allowed = 1;
if(intval($r[0]['photo_usage']) === PHOTO_COVER)
@ -166,13 +182,12 @@ class Photo extends \Zotlabs\Web\Controller {
}
else {
if(! $allowed) {
logger('mod_photo: forbidden. ' . \App::$query_string);
$observer = \App::get_observer();
logger('mod_photo: observer = ' . (($observer) ? $observer['xchan_addr'] : '(not authenticated)'));
$data = file_get_contents('images/nosign.png');
$mimetype = 'image/png';
$prvcachecontrol = true;
http_status_exit(403,'forbidden');
}
if(! $exists) {
http_status_exit(404,'not found');
}
}
}
}
@ -182,16 +197,13 @@ class Photo extends \Zotlabs\Web\Controller {
switch($resolution) {
case 4:
$data = file_get_contents(get_default_profile_photo());
$mimetype = 'image/png';
$data = fetch_image_from_url(z_root() . '/' . get_default_profile_photo(),$mimetype);
break;
case 5:
$data = file_get_contents(get_default_profile_photo(80));
$mimetype = 'image/png';
$data = fetch_image_from_url(z_root() . '/' . get_default_profile_photo(80),$mimetype);
break;
case 6:
$data = file_get_contents(get_default_profile_photo(48));
$mimetype = 'image/png';
$data = fetch_image_from_url(z_root() . '/' . get_default_profile_photo(48),$mimetype);
break;
default:
killme();

View File

@ -102,14 +102,7 @@ class Photos extends \Zotlabs\Web\Controller {
if($_REQUEST['dropalbum'] == t('Delete Album')) {
// This is dangerous because we combined file storage and photos into one interface
// This function will remove all photos from any directory with the same name since
// we have not passed the path value.
// The correct solution would be to use a full pathname from your storage root for 'album'
// We also need to prevent/block removing the storage root folder.
$folder_hash = '';
$r = q("select * from attach where is_dir = 1 and uid = %d and hash = '%s'",
@ -124,7 +117,8 @@ class Photos extends \Zotlabs\Web\Controller {
$res = array();
$admin_delete = false;
// get the list of photos we are about to delete
if(remote_channel() && (! local_channel())) {
@ -133,6 +127,10 @@ class Photos extends \Zotlabs\Web\Controller {
elseif(local_channel()) {
$str = photos_album_get_db_idstr(local_channel(),$album);
}
elseif(is_site_admin()) {
$str = photos_album_get_db_idstr_admin($page_owner_uid,$album);
$admin_delete = true;
}
else {
$str = null;
}
@ -145,7 +143,7 @@ class Photos extends \Zotlabs\Web\Controller {
);
if($r) {
foreach($r as $i) {
attach_delete($page_owner_uid, $i['resource_id'], 1 );
attach_delete($page_owner_uid, $i['resource_id'], true );
}
}
@ -158,12 +156,14 @@ class Photos extends \Zotlabs\Web\Controller {
// @FIXME do the same for the linked attach
if($folder_hash) {
attach_delete($page_owner_uid,$folder_hash, 1);
attach_delete($page_owner_uid, $folder_hash, true );
if(! $admin_delete) {
$sync = attach_export_data(\App::$data['channel'],$folder_hash, true);
$sync = attach_export_data(\App::$data['channel'],$folder_hash, true);
if($sync)
build_sync_packet($page_owner_uid,array('file' => array($sync)));
if($sync)
build_sync_packet($page_owner_uid,array('file' => array($sync)));
}
}
}
@ -181,17 +181,22 @@ class Photos extends \Zotlabs\Web\Controller {
$r = q("SELECT id, resource_id FROM photo WHERE ( xchan = '%s' or uid = %d ) AND resource_id = '%s' LIMIT 1",
dbesc($ob_hash),
intval(local_channel()),
dbesc(\App::$argv[2])
dbesc(argv(2))
);
if($r) {
attach_delete($page_owner_uid, $r[0]['resource_id'], 1 );
attach_delete($page_owner_uid, $r[0]['resource_id'], true );
$sync = attach_export_data(\App::$data['channel'],$r[0]['resource_id'], true);
if($sync)
build_sync_packet($page_owner_uid,array('file' => array($sync)));
}
elseif(is_site_admin()) {
// If the admin deletes a photo, don't sync
attach_delete($page_owner_uid, argv(2), true);
}
goaway(z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . $_SESSION['album_return']);
}

View File

@ -35,10 +35,12 @@ class Ping extends \Zotlabs\Web\Controller {
$result['birthdays_today'] = 0;
$result['all_events'] = 0;
$result['all_events_today'] = 0;
$result['notice'] = array();
$result['info'] = array();
$result['notice'] = [];
$result['info'] = [];
$result['pubs'] = 0;
$result['files'] = 0;
$result['forums'] = 0;
$result['forums_sub'] = [];
if(! $_SESSION['static_loadtime'])
$_SESSION['static_loadtime'] = datetime_convert();
@ -401,7 +403,7 @@ class Ping extends \Zotlabs\Web\Controller {
'notify_link' => z_root() . '/admin/accounts',
'name' => $rr['account_email'],
'url' => '',
'photo' => get_default_profile_photo(48),
'photo' => z_root() . '/' . get_default_profile_photo(48),
'when' => relative_date($rr['account_created']),
'hclass' => ('notify-unseen'),
'message' => t('requires approval')
@ -622,6 +624,58 @@ class Ping extends \Zotlabs\Web\Controller {
if(! ($vnotify & VNOTIFY_BIRTHDAY))
$result['birthdays'] = 0;
if($vnotify & VNOTIFY_FORUMS) {
$forums = get_forum_channels(local_channel());
if(! $forums) {
$result['forums'] = 0;
}
else {
$perms_sql = item_permissions_sql(local_channel()) . item_normal();
$fcount = count($forums);
$forums['total'] = 0;
for($x = 0; $x < $fcount; $x ++) {
$r = q("select sum(item_unseen) as unseen from item
where uid = %d and owner_xchan = '%s' and item_unseen = 1 $perms_sql ",
intval(local_channel()),
dbesc($forums[$x]['xchan_hash'])
);
if($r[0]['unseen']) {
$forums[$x]['notify_link'] = (($forums[$x]['private_forum']) ? $forums[$x]['xchan_url'] : z_root() . '/network/?f=&pf=1&cid=' . $forums[$x]['abook_id']);
$forums[$x]['name'] = $forums[$x]['xchan_name'];
$forums[$x]['url'] = $forums[$x]['xchan_url'];
$forums[$x]['photo'] = $forums[$x]['xchan_photo_s'];
$forums[$x]['unseen'] = $r[0]['unseen'];
$forums[$x]['private_forum'] = (($forums[$x]['private_forum']) ? 'lock' : '');
$forums[$x]['message'] = (($forums[$x]['private_forum']) ? t('Private forum') : t('Public forum'));
$forums['total'] = $forums['total'] + $r[0]['unseen'];
unset($forums[$x]['abook_id']);
unset($forums[$x]['xchan_hash']);
unset($forums[$x]['xchan_name']);
unset($forums[$x]['xchan_url']);
unset($forums[$x]['xchan_photo_s']);
//if($forums[$x]['private_forum'])
// unset($forums[$x]['private_forum']);
}
else {
unset($forums[$x]);
}
}
$result['forums'] = $forums['total'];
unset($forums['total']);
$result['forums_sub'] = $forums;
}
}
$x = json_encode($result);
$t8 = dba_timer();

View File

@ -66,8 +66,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
'default_location' => $channel['channel_location'],
'nickname' => $channel['channel_address'],
'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
'acl' => populate_acl($channel_acl),
'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
'permissions' => $channel_acl,
'bang' => '',
'visitor' => true,
@ -77,7 +76,8 @@ class Pubstream extends \Zotlabs\Web\Controller {
'editor_autocomplete' => true,
'bbco_autocomplete' => 'bbcode',
'bbcode' => true,
'jotnets' => true
'jotnets' => true,
'reset' => t('Reset form')
);
$o = '<div id="jot-popup">';

View File

@ -187,8 +187,8 @@ class Register extends \Zotlabs\Web\Controller {
$registration_is = '';
$other_sites = '';
if(get_config('system','register_policy') == REGISTER_CLOSED) {
if(get_config('system','directory_mode') == DIRECTORY_MODE_STANDALONE) {
if(intval(get_config('system','register_policy')) === REGISTER_CLOSED) {
if(intval(get_config('system','directory_mode')) === DIRECTORY_MODE_STANDALONE) {
notice( t('Registration on this hub is disabled.') . EOL);
return;
}
@ -197,10 +197,19 @@ class Register extends \Zotlabs\Web\Controller {
return $mod->get();
}
if(get_config('system','register_policy') == REGISTER_APPROVE) {
if(intval(get_config('system','register_policy')) == REGISTER_APPROVE) {
$registration_is = t('Registration on this hub is by approval only.');
$other_sites = t('<a href="pubsites">Register at another affiliated hub.</a>');
}
$invitations = false;
if(intval(get_config('system','invitation_only'))) {
$invitations = true;
$registration_is = t('Registration on this hub is by invitation only.');
$other_sites = t('<a href="pubsites">Register at another affiliated hub.</a>');
}
$max_dailies = intval(get_config('system','max_daily_registrations'));
if($max_dailies) {
@ -251,10 +260,10 @@ class Register extends \Zotlabs\Web\Controller {
$password = array('password', t('Choose a password'), '');
$password2 = array('password2', t('Please re-enter your password'), '');
$invite_code = array('invite_code', t('Please enter your invitation code'), ((x($_REQUEST,'invite_code')) ? strip_tags(trim($_REQUEST['invite_code'])) : ""));
$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('Your Name'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Real names are preferred.'));
$nickhub = '@' . str_replace(array('http://','https://','/'), '', get_config('system','baseurl'));
$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));
$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/member/member_guide#Account_Permission_Roles" target="_blank">' . t('Read more about roles') . '</a>',$perm_roles);
$role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel permission role for your usage needs and privacy requirements.') . ' <a href="help/member/member_guide#Channel_Permission_Roles" target="_blank">' . t('Read more about channel permission roles') . '</a>',$perm_roles);
$tos = array('tos', $label_tos, '', '', array(t('no'),t('yes')));
@ -270,8 +279,7 @@ class Register extends \Zotlabs\Web\Controller {
'$reg_is' => $registration_is,
'$registertext' => bbcode(get_config('system','register_text')),
'$other_sites' => $other_sites,
'$invitations' => get_config('system','invitation_only'),
'$invite_desc' => t('Membership on this site is by invitation only.'),
'$invitations' => $invitations,
'$invite_code' => $invite_code,
'$auto_create' => $auto_create,
'$name' => $name,

View File

@ -13,8 +13,7 @@ class Regmod extends \Zotlabs\Web\Controller {
if(! local_channel()) {
info( t('Please login.') . EOL);
$o .= '<br /><br />' . login((\App::$config['system']['register_policy'] == REGISTER_CLOSED) ? 0 : 1);
return $o;
return login();
}
if(! is_site_admin()) {

View File

@ -38,7 +38,7 @@ class Removeme extends \Zotlabs\Web\Controller {
}
$global_remove = intval($_POST['global']);
channel_remove(local_channel(),1 - $global_remove,true);
}
@ -56,12 +56,12 @@ class Removeme extends \Zotlabs\Web\Controller {
$tpl = get_markup_template('removeme.tpl');
$o .= replace_macros($tpl, array(
'$basedir' => z_root(),
'$hash' => $hash,
'$title' => t('Remove This Channel'),
'$desc' => array(t('WARNING: '), t('This channel will be completely removed from the network. '), t('This action is permanent and can not be undone!')),
'$passwd' => t('Please enter your password for verification:'),
'$global' => array('global', t('Remove this channel and all its clones from the network'), false, t('By default only the instance of the channel located on this hub will be removed from the network'), array(t('No'),t('Yes'))),
'$submit' => t('Remove Channel')
'$hash' => $hash,
'$title' => t('Remove This Channel'),
'$desc' => [ t('WARNING: '), t('This channel will be completely removed from the network. '), t('This action is permanent and can not be undone!') ],
'$passwd' => t('Please enter your password for verification:'),
'$global' => [ 'global', t('Remove this channel and all its clones from the network'), false, t('By default only the instance of the channel located on this hub will be removed from the network'), [ t('No'),t('Yes') ] ],
'$submit' => t('Remove Channel')
));
return $o;

View File

@ -17,8 +17,8 @@ class Rmagic extends \Zotlabs\Web\Controller {
if($r) {
if($r[0]['hubloc_url'] === z_root())
goaway(z_root() . '/login');
$dest = z_root() . '/' . str_replace(['rmagic','zid='],['','zid_='],\App::$query_string);
goaway($r[0]['hubloc_url'] . '/magic' . '?f=&owa=1&dest=' . $dest);
$dest = bin2hex(z_root() . '/' . str_replace(['rmagic','zid='],['','zid_='],\App::$query_string));
goaway($r[0]['hubloc_url'] . '/magic' . '?f=&owa=1&bdest=' . $dest);
}
}
}
@ -59,11 +59,11 @@ class Rmagic extends \Zotlabs\Web\Controller {
if($url) {
if($_SESSION['return_url'])
$dest = urlencode(z_root() . '/' . str_replace('zid=','zid_=',$_SESSION['return_url']));
$dest = bin2hex(z_root() . '/' . str_replace('zid=','zid_=',$_SESSION['return_url']));
else
$dest = urlencode(z_root() . '/' . str_replace([ 'rmagic', 'zid=' ] ,[ '', 'zid_='],\App::$query_string));
$dest = bin2hex(z_root() . '/' . str_replace([ 'rmagic', 'zid=' ] ,[ '', 'zid_='],\App::$query_string));
goaway($url . '/magic' . '?f=&owa=1&dest=' . $dest);
goaway($url . '/magic' . '?f=&owa=1&bdest=' . $dest);
}
}
}

View File

@ -142,6 +142,7 @@ class Rpost extends \Zotlabs\Web\Controller {
$o .= replace_macros(get_markup_template('edpost_head.tpl'), array(
'$title' => t('Edit post'),
'$cancel' => '',
'$editor' => $editor
));

View File

@ -21,6 +21,10 @@ class Channel {
$role = ((x($_POST,'permissions_role')) ? notags(trim($_POST['permissions_role'])) : '');
$oldrole = get_pconfig(local_channel(),'system','permissions_role');
// This mapping can be removed after 3.4 release
if($oldrole === 'social_party') {
$oldrole = 'social_federation';
}
if(($role != $oldrole) || ($role === 'custom')) {
@ -142,6 +146,7 @@ class Channel {
$unkmail = (((x($_POST,'unkmail')) && (intval($_POST['unkmail']) == 1)) ? 1: 0);
$cntunkmail = ((x($_POST,'cntunkmail')) ? intval($_POST['cntunkmail']) : 0);
$suggestme = ((x($_POST,'suggestme')) ? intval($_POST['suggestme']) : 0);
$autoperms = ((x($_POST,'autoperms')) ? intval($_POST['autoperms']) : 0);
$post_newfriend = (($_POST['post_newfriend'] == 1) ? 1: 0);
$post_joingroup = (($_POST['post_joingroup'] == 1) ? 1: 0);
@ -210,6 +215,8 @@ class Channel {
$vnotify += intval($_POST['vnotify13']);
if(x($_POST,'vnotify14'))
$vnotify += intval($_POST['vnotify14']);
if(x($_POST,'vnotify15'))
$vnotify += intval($_POST['vnotify15']);
$always_show_in_notices = x($_POST,'always_show_in_notices') ? 1 : 0;
@ -248,6 +255,7 @@ class Channel {
set_pconfig(local_channel(),'system','default_permcat',$defpermcat);
set_pconfig(local_channel(),'system','email_notify_host',$mailhost);
set_pconfig(local_channel(),'system','profile_assign',$profile_assign);
set_pconfig(local_channel(),'system','autoperms',$autoperms);
$r = q("update channel set channel_name = '%s', channel_pageflags = %d, channel_timezone = '%s', channel_location = '%s', channel_notifyflags = %d, channel_max_anon_mail = %d, channel_max_friend_req = %d, channel_expire_days = %d $set_perms where channel_id = %d",
dbesc($username),
@ -471,13 +479,25 @@ class Channel {
$permissions_role = get_pconfig(local_channel(),'system','permissions_role');
if(! $permissions_role)
$permissions_role = 'custom';
// compatibility mapping - can be removed after 3.4 release
if($permissions_role === 'social_party')
$permissions_role = 'social_federation';
if(in_array($permissions_role,['forum','repository']))
$autoperms = replace_macros(get_markup_template('field_checkbox.tpl'), [
'$field' => [ 'autoperms',t('Automatic membership approval'), ((get_pconfig(local_channel(),'system','autoperms')) ? 1 : 0), t('If enabled, connection requests will be approved without your interaction'), $yes_no ]]);
else
$autoperms = '<input type="hidden" name="autoperms" value="' . intval(get_pconfig(local_channel(),'system','autoperms')) . '" />';
$permissions_set = (($permissions_role != 'custom') ? true : false);
$perm_roles = \Zotlabs\Access\PermissionRoles::roles();
if((get_account_techlevel() < 4) && $permissions_role !== 'custom')
unset($perm_roles[t('Other')]);
$vnotify = get_pconfig(local_channel(),'system','vnotify');
$always_show_in_notices = get_pconfig(local_channel(),'system','always_show_in_notices');
if($vnotify === false)
@ -489,6 +509,7 @@ class Channel {
$disable_discover_tab = intval(get_config('system','disable_discover_tab',1)) == 1;
$site_firehose = intval(get_config('system','site_firehose',0)) == 1;
$o .= replace_macros($stpl,array(
'$ptitle' => t('Channel Settings'),
@ -545,7 +566,7 @@ class Channel {
'$unkmail' => $unkmail,
'$cntunkmail' => array('cntunkmail', t('Maximum private messages per day from unknown people:'), intval($channel['channel_max_anon_mail']) ,t("Useful to reduce spamming")),
'$autoperms' => $autoperms,
'$h_not' => t('Notification Settings'),
'$activity_options' => t('By default post a status message when:'),
'$post_newfriend' => array('post_newfriend', t('accepting a friend request'), $post_newfriend, '', $yes_no),
@ -580,6 +601,7 @@ class Channel {
'$vnotify12' => array('vnotify12', t('Unseen shared files'), ($vnotify & VNOTIFY_FILES), VNOTIFY_FILES, '', $yes_no),
'$vnotify13' => (($disable_discover_tab && !$site_firehose) ? array() : array('vnotify13', t('Unseen public activity'), ($vnotify & VNOTIFY_PUBS), VNOTIFY_PUBS, '', $yes_no)),
'$vnotify14' => array('vnotify14', t('Unseen likes and dislikes'), ($vnotify & VNOTIFY_LIKE), VNOTIFY_LIKE, '', $yes_no),
'$vnotify15' => array('vnotify15', t('Unseen forum posts'), ($vnotify & VNOTIFY_FORUMS), VNOTIFY_FORUMS, '', $yes_no),
'$mailhost' => [ 'mailhost', t('Email notification hub (hostname)'), get_pconfig(local_channel(),'system','email_notify_host',\App::get_hostname()), sprintf( t('If your channel is mirrored to multiple hubs, set this to your preferred location. This will prevent duplicate email notifications. Example: %s'),\App::get_hostname()) ],
'$always_show_in_notices' => array('always_show_in_notices', t('Show new wall posts, private messages and connections under Notices'), $always_show_in_notices, 1, '', $yes_no),

View File

@ -161,8 +161,8 @@ class Tokens {
'$me' => t('My Settings'),
'$perms' => $perms,
'$inherited' => t('inherited'),
'$notself' => 0,
'$self' => 1,
'$notself' => 1,
'$self' => 0,
'$permlbl' => t('Individual Permissions'),
'$permnote' => t('Some permissions may be inherited from your channel\'s <a href="settings"><strong>privacy settings</strong></a>, which have higher priority than individual settings. You can <strong>not</strong> change those settings here.'),
'$submit' => t('Submit')
@ -170,4 +170,4 @@ class Tokens {
return $o;
}
}
}

View File

@ -12,6 +12,9 @@ class Siteinfo extends \Zotlabs\Web\Controller {
}
function get() {
$federated = [];
call_hooks('federated_transports',$federated);
$siteinfo = replace_macros(get_markup_template('siteinfo.tpl'),
[
@ -27,6 +30,9 @@ class Siteinfo extends \Zotlabs\Web\Controller {
'$prj_name' => t('This site is powered by $Projectname'),
'$prj_transport' => t('Federated and decentralised networking and identity services provided by Zot'),
'$transport_link' => '<a href="https://zotlabs.com">https://zotlabs.com</a>',
'$additional_text' => t('Additional federated transport protocols:'),
'$additional_fed' => implode(',',$federated),
'$prj_version' => ((get_config('system','hidden_version_siteinfo')) ? '' : sprintf( t('Version %s'), \Zotlabs\Lib\System::get_project_version())),
'$prj_linktxt' => t('Project homepage'),
'$prj_srctxt' => t('Developer homepage'),

View File

@ -12,12 +12,13 @@ class Sources extends \Zotlabs\Web\Controller {
return '';
$source = intval($_REQUEST['source']);
$xchan = $_REQUEST['xchan'];
$xchan = escape_tags($_REQUEST['xchan']);
$abook = intval($_REQUEST['abook']);
$words = $_REQUEST['words'];
$words = escape_tags($_REQUEST['words']);
$resend = intval($_REQUEST['resend']);
$frequency = $_REQUEST['frequency'];
$name = $_REQUEST['name'];
$tags = $_REQUEST['tags'];
$name = escape_tags($_REQUEST['name']);
$tags = escape_tags($_REQUEST['tags']);
$channel = \App::get_channel();
@ -38,6 +39,8 @@ class Sources extends \Zotlabs\Web\Controller {
return;
}
set_abconfig(local_channel(),$xchan, 'system','rself',$resend);
if(! $source) {
$r = q("insert into source ( src_channel_id, src_channel_xchan, src_xchan, src_patt, src_tag )
values ( %d, '%s', '%s', '%s', '%s' ) ",
@ -69,7 +72,7 @@ class Sources extends \Zotlabs\Web\Controller {
}
function get() {
function get() {
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
return '';
@ -110,7 +113,7 @@ class Sources extends \Zotlabs\Web\Controller {
'$words' => array( 'words', t('Only import content with these words (one per line)'),'',t('Leave blank to import all public content')),
'$name' => array( 'name', t('Channel Name'), '', ''),
'$tags' => array('tags', t('Add the following categories to posts imported from this source (comma separated)'),'',t('Optional')),
'$resend' => [ 'resend', t('Resend posts with this channel as author'), 0, t('Copyrights may apply'), [ t('No'), t('Yes') ]],
'$submit' => t('Submit')
));
return $o;
@ -145,6 +148,8 @@ class Sources extends \Zotlabs\Web\Controller {
'$xchan' => $r[0]['src_xchan'],
'$abook' => $x[0]['abook_id'],
'$tags' => array('tags', t('Add the following categories to posts imported from this source (comma separated)'),$r[0]['src_tag'],t('Optional')),
'$resend' => [ 'resend', t('Resend posts with this channel as author'), get_abconfig(local_channel(), $r[0]['xchan_hash'],'system','rself'), t('Copyrights may apply'), [ t('No'), t('Yes') ]],
'$name' => array( 'name', t('Channel Name'), $r[0]['xchan_name'], ''),
'$submit' => t('Submit')
));

View File

@ -28,7 +28,7 @@ class Viewsrc extends \Zotlabs\Web\Controller {
$item_normal = item_normal();
if(local_channel() && $item_id) {
$r = q("select id, item_flags, mimetype, item_obscured, body from item where uid in (%d , %d) and id = %d $item_normal limit 1",
$r = q("select id, item_flags, mimetype, item_obscured, body, llink, plink from item where uid in (%d , %d) and id = %d $item_normal limit 1",
intval(local_channel()),
intval($sys['channel_id']),
intval($item_id)
@ -52,8 +52,11 @@ class Viewsrc extends \Zotlabs\Web\Controller {
}
if(is_ajax()) {
print '<div><i class="fa fa-pencil"> ' . t('Source of Item') . ' ' . $r[0]['id'] . '</i></div>';
echo $o;
echo '<div class="p-1">';
echo '<div>id: ' . $r[0]['id'] . ' | <a href="' . $r[0]['plink'] . '" target="_blank">plink</a> | <a href="' . $r[0]['llink'] . '" target="_blank">llink</a></div>';
echo '<hr>';
echo '<pre class="p-1">' . $o . '</pre>';
echo '</div>';
killme();
}

View File

@ -50,7 +50,15 @@ class Well_known extends \Zotlabs\Web\Controller {
$module = new \Zotlabs\Module\Hostxrd();
$module->init();
break;
case 'oauth-authorization-server':
\App::$argc -= 1;
array_shift(\App::$argv);
\App::$argv[0] = 'oauthinfo';
$module = new \Zotlabs\Module\Oauthinfo();
$module->init();
break;
case 'dnt-policy.txt':
echo file_get_contents('doc/dnt-policy.txt');
killme();

View File

@ -109,7 +109,8 @@ class Wfinger extends \Zotlabs\Web\Controller {
$aliases = array(
z_root() . (($pchan) ? '/pchan/' : '/channel/') . $r[0]['channel_address'],
z_root() . '/~' . $r[0]['channel_address']
z_root() . '/~' . $r[0]['channel_address'],
z_root() . '/@' . $r[0]['channel_address']
);
if($h) {

View File

@ -95,7 +95,7 @@ class Wiki extends \Zotlabs\Web\Controller {
$owner['channel_deny_gid'])
? 'lock' : 'unlock'
),
'acl' => populate_acl($owner_acl),
'acl' => populate_acl($owner_acl, false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_wiki')),
'allow_cid' => acl2json($owner_acl['allow_cid']),
'allow_gid' => acl2json($owner_acl['allow_gid']),
'deny_cid' => acl2json($owner_acl['deny_cid']),

View File

@ -253,11 +253,11 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic {
* @return void
*/
public function log() {
logger('channel_name ' . $this->channel_name, LOGGER_DATA);
logger('channel_id ' . $this->channel_id, LOGGER_DATA);
logger('channel_hash ' . $this->channel_hash, LOGGER_DATA);
logger('observer ' . $this->observer, LOGGER_DATA);
logger('owner_id ' . $this->owner_id, LOGGER_DATA);
logger('owner_nick ' . $this->owner_nick, LOGGER_DATA);
// logger('channel_name ' . $this->channel_name, LOGGER_DATA);
// logger('channel_id ' . $this->channel_id, LOGGER_DATA);
// logger('channel_hash ' . $this->channel_hash, LOGGER_DATA);
// logger('observer ' . $this->observer, LOGGER_DATA);
// logger('owner_id ' . $this->owner_id, LOGGER_DATA);
// logger('owner_nick ' . $this->owner_nick, LOGGER_DATA);
}
}

View File

@ -12,7 +12,7 @@ use Sabre\DAV;
*
* @extends \\Sabre\\DAV\\Browser\\Plugin
*
* @link http://github.com/redmatrix/hubzilla
* @link http://framagit.org/hubzilla/core/
* @license http://opensource.org/licenses/mit-license.php The MIT License (MIT)
*/
class Browser extends DAV\Browser\Plugin {
@ -241,7 +241,7 @@ class Browser extends DAV\Browser\Plugin {
// put the array for this file together
$ft['attachId'] = $this->findAttachIdByHash($attachHash);
$ft['fileStorageUrl'] = substr($fullPath, 0, strpos($fullPath, "cloud/")) . "filestorage/" . $this->auth->getCurrentUser();
$ft['fileStorageUrl'] = substr($fullPath, 0, strpos($fullPath, "cloud/")) . "filestorage/" . $this->auth->owner_nick;
$ft['icon'] = $icon;
$ft['photo_icon'] = $photo_icon;
$ft['attachIcon'] = (($size) ? $attachIcon : '');
@ -276,6 +276,8 @@ class Browser extends DAV\Browser\Plugin {
'$create' => t('Create'),
'$upload' => t('Add Files'),
'$is_owner' => $is_owner,
'$is_admin' => is_site_admin(),
'$admin_delete' => t('Admin Delete'),
'$parentpath' => $parentpath,
'$cpath' => bin2hex(\App::$query_string),
'$tiles' => intval($_SESSION['cloud_tiles']),
@ -331,6 +333,7 @@ class Browser extends DAV\Browser\Plugin {
$aclselect = null;
$lockstate = '';
$limit = 0;
if($this->auth->owner_id) {
$channel = channelx_by_n($this->auth->owner_id);
@ -341,10 +344,15 @@ class Browser extends DAV\Browser\Plugin {
$aclselect = ((local_channel() == $this->auth->owner_id) ? populate_acl($channel_acl,false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_storage')) : '');
}
// Storage and quota for the account (all channels of the owner of this directory)!
$limit = engr_units_to_bytes(service_class_fetch($this->auth->owner_id, 'attach_upload_limit'));
}
if((! $limit) && get_config('system','cloud_report_disksize')) {
$limit = engr_units_to_bytes(disk_free_space('store'));
}
// Storage and quota for the account (all channels of the owner of this directory)!
$limit = engr_units_to_bytes(service_class_fetch($owner, 'attach_upload_limit'));
$r = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d",
intval($this->auth->channel_account_id)
);

View File

@ -571,39 +571,6 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
return datetime_convert('UTC', 'UTC', $r[0]['edited'], 'U');
}
/**
* @brief Return quota usage.
*
* @fixme Should guests relly see the used/free values from filesystem of the
* complete store directory?
*
* @return array with used and free values in bytes.
*/
public function getQuotaInfo() {
// values from the filesystem of the complete <i>store/</i> directory
$limit = disk_total_space('store');
$free = disk_free_space('store');
if ($this->auth->owner_id) {
$c = q("select * from channel where channel_id = %d and channel_removed = 0 limit 1",
intval($this->auth->owner_id)
);
$ulimit = engr_units_to_bytes(service_class_fetch($c[0]['channel_id'], 'attach_upload_limit'));
$limit = (($ulimit) ? $ulimit : $limit);
$x = q("select sum(filesize) as total from attach where aid = %d",
intval($c[0]['channel_account_id'])
);
$free = (($x) ? $limit - $x[0]['total'] : 0);
}
return array(
$limit - $free,
$free
);
}
/**
* @brief Array with all Directory and File DAV\\Node items for the given path.
@ -719,6 +686,8 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
);
foreach ($r as $rr) {
if(\App::$module === 'cloud' && (strpos($rr['filename'],'.') === 0) && (! get_pconfig($channel_id,'system','show_dot_files')) )
continue;
// @FIXME I don't think we use revisions currently in attach structures.
// In case we see any in the wild provide a unique filename. This
@ -753,14 +722,13 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
function ChannelList(&$auth) {
$ret = array();
$r = q("SELECT channel_id, channel_address FROM channel WHERE channel_removed = 0
AND channel_system = 0 AND (channel_pageflags & %d) = 0",
$r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0",
intval(PAGE_HIDDEN)
);
if ($r) {
foreach ($r as $rr) {
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage')) {
if (perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) {
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);
@ -893,4 +861,48 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
return false;
}
public function getQuotaInfo() {
/**
* Returns the quota information
*
* This method MUST return an array with 2 values, the first being the total used space,
* the second the available space (in bytes)
*/
$used = 0;
$limit = 0;
$free = 0;
if ($this->auth->owner_id) {
$channel = channelx_by_n($this->auth->owner_id);
if($channel) {
$r = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d",
intval($channel['channel_account_id'])
);
$used = (($r) ? (float) $r[0]['total'] : 0);
$limit = (float) service_class_fetch($this->auth->owner_id, 'attach_upload_limit');
if($limit) {
// Don't let the result go negative
$free = (($limit > $used) ? $limit - $used : 0);
}
}
}
if(! $limit) {
$free = disk_free_space('store');
$used = disk_total_space('store') - $free;
}
// prevent integer overflow on 32-bit systems
if($used > (float) PHP_INT_MAX)
$used = PHP_INT_MAX;
if($free > (float) PHP_INT_MAX)
$free = PHP_INT_MAX;
return [ (int) $used, (int) $free ];
}
}

View File

@ -27,7 +27,7 @@ class Pdf {
$imagick_path = get_config('system','imagick_convert_path');
if($imagick_path && @file_exists($imagick_path)) {
$cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmpfile . '[0]') . ' -thumbnail ' . $width . 'x' . $height . ' ' . escapeshellarg(PROJECT_BASE . '/' . $outfile);
$cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmpfile . '[0]') . ' -resize ' . $width . 'x' . $height . ' ' . escapeshellarg(PROJECT_BASE . '/' . $outfile);
// logger('imagick thumbnail command: ' . $cmd);
for($x = 0; $x < 4; $x ++) {
exec($cmd);

View File

@ -46,7 +46,7 @@ class Video {
$imagick_path = get_config('system','imagick_convert_path');
if($imagick_path && @file_exists($imagick_path)) {
$cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmpfile . '[0]') . ' -thumbnail ' . $width . 'x' . $height . ' ' . escapeshellarg(PROJECT_BASE . '/' . $outfile);
$cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmpfile . '[0]') . ' -resize ' . $width . 'x' . $height . ' ' . escapeshellarg(PROJECT_BASE . '/' . $outfile);
// logger('imagick thumbnail command: ' . $cmd);
/** @scrutinizer ignore-unhandled */

View File

@ -17,9 +17,9 @@ class CheckJS {
else
$this->jsdisabled = 0;
if(! $this->jsdisabled) {
$page = urlencode(\App::$query_string);
$page = bin2hex(\App::$query_string);
if(! $this->jsdisabled) {
if($test) {
$this->jsdisabled = 1;
if(array_key_exists('jsdisabled',$_COOKIE))

View File

@ -0,0 +1,204 @@
<?php
namespace Zotlabs\Widget;
class Activity_filter {
function widget($arr) {
if(! local_channel())
return '';
$cmd = \App::$cmd;
$filter_active = false;
$tabs = [];
if(feature_enabled(local_channel(),'personal_tab')) {
if(x($_GET,'conv')) {
$conv_active = (($_GET['conv'] == 1) ? 'active' : '');
$filter_active = 'personal';
}
$tabs[] = [
'label' => t('Personal Posts'),
'icon' => 'user-circle',
'url' => z_root() . '/' . $cmd . '/?f=&conv=1',
'sel' => $conv_active,
'title' => t('Show posts that mention or involve me')
];
}
if(feature_enabled(local_channel(),'star_posts')) {
if(x($_GET,'star')) {
$starred_active = (($_GET['star'] == 1) ? 'active' : '');
$filter_active = 'star';
}
$tabs[] = [
'label' => t('Starred Posts'),
'icon' => 'star',
'url'=>z_root() . '/' . $cmd . '/?f=&star=1',
'sel'=>$starred_active,
'title' => t('Show posts that I have starred')
];
}
if(feature_enabled(local_channel(),'groups')) {
$groups = q("SELECT * FROM groups WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval(local_channel())
);
if($groups) {
foreach($groups as $g) {
if(x($_GET,'gid')) {
$group_active = (($_GET['gid'] == $g['id']) ? 'active' : '');
$filter_active = 'group';
}
$gsub[] = [
'label' => $g['gname'],
'icon' => '',
'url' => z_root() . '/' . $cmd . '/?f=&gid=' . $g['id'],
'sel' => $group_active,
'title' => sprintf(t('Show posts related to the %s privacy group'), $g['gname'])
];
}
$tabs[] = [
'id' => 'privacy_groups',
'label' => t('Privacy Groups'),
'icon' => 'users',
'url' => '#',
'sel' => (($filter_active == 'group') ? true : false),
'title' => t('Show my privacy groups'),
'sub' => $gsub
];
}
}
if(feature_enabled(local_channel(),'forums_tab')) {
$forums = get_forum_channels(local_channel());
if($forums) {
foreach($forums as $f) {
if(x($_GET,'pf') && x($_GET,'cid')) {
$forum_active = ((x($_GET,'pf') && $_GET['cid'] == $f['abook_id']) ? 'active' : '');
$filter_active = 'forums';
}
$fsub[] = [
'label' => $f['xchan_name'],
'img' => $f['xchan_photo_s'],
'url' => (($f['private_forum']) ? $f['xchan_url'] : z_root() . '/' . $cmd . '/?f=&pf=1&cid=' . $f['abook_id']),
'sel' => $forum_active,
'title' => t('Show posts to this forum'),
'lock' => (($f['private_forum']) ? 'lock' : '')
];
}
$tabs[] = [
'id' => 'forums',
'label' => t('Forums'),
'icon' => 'comments-o',
'url' => '#',
'sel' => (($filter_active == 'forums') ? true : false),
'title' => t('Show forums'),
'sub' => $fsub
];
}
}
if(feature_enabled(local_channel(),'filing')) {
$terms = q("select distinct term from term where uid = %d and ttype = %d order by term asc",
intval(local_channel()),
intval(TERM_FILE)
);
if($terms) {
foreach($terms as $t) {
if(x($_GET,'file')) {
$file_active = (($_GET['file'] == $t['term']) ? 'active' : '');
$filter_active = 'file';
}
$tsub[] = [
'label' => $t['term'],
'icon' => '',
'url' => z_root() . '/' . $cmd . '/?f=&file=' . $t['term'],
'sel' => $file_active,
'title' => sprintf(t('Show posts that I have filed to %s'), $t['term']),
];
}
$tabs[] = [
'id' => 'saved_folders',
'label' => t('Saved Folders'),
'icon' => 'folder',
'url' => '#',
'sel' => (($filter_active == 'file') ? true : false),
'title' => t('Show filed post categories'),
'sub' => $tsub
];
}
}
if(x($_GET,'search')) {
$filter_active = 'search';
$tabs[] = [
'label' => t('Search'),
'icon' => 'search',
'url' => z_root() . '/' . $cmd . '/?f=&search=' . $_GET['search'],
'sel' => 'active disabled',
'title' => t('Panel search')
];
}
$name = [];
if(feature_enabled(local_channel(),'name_tab')) {
if(x($_GET,'cid') && ! x($_GET,'pf')) {
$filter_active = 'name';
}
$name = [
'label' => x($_GET,'name') ? $_GET['name'] : t('Filter by name'),
'icon' => 'filter',
'url'=> z_root() . '/' . $cmd . '/',
'sel'=> $filter_active == 'name' ? 'is-valid' : '',
'title' => ''
];
}
$reset = [];
if($filter_active) {
$reset = [
'label' => '',
'icon' => 'remove',
'url'=> z_root() . '/' . $cmd,
'sel'=> '',
'title' => t('Remove active filter')
];
}
$arr = ['tabs' => $tabs];
call_hooks('network_tabs', $arr);
$o = '';
if($arr['tabs']) {
$content = replace_macros(get_markup_template('common_pills.tpl'), [
'$pills' => $arr['tabs']
]);
$o .= replace_macros(get_markup_template('activity_filter_widget.tpl'), [
'$title' => t('Activity Filters'),
'$reset' => $reset,
'$content' => $content,
'$name' => $name
]);
}
return $o;
}
}

View File

@ -0,0 +1,128 @@
<?php
namespace Zotlabs\Widget;
class Activity_order {
function widget($arr) {
if(! local_channel())
return '';
if(! feature_enabled(local_channel(),'order_tab')) {
set_pconfig(local_channel(), 'mod_network', 'order', 0);
return '';
}
$commentord_active = '';
$postord_active = '';
$unthreaded_active = '';
if(x($_GET, 'order')) {
switch($_GET['order']){
case 'post':
$postord_active = 'active';
set_pconfig(local_channel(), 'mod_network', 'order', 1);
break;
case 'comment':
$commentord_active = 'active';
set_pconfig(local_channel(), 'mod_network', 'order', 0);
break;
case 'unthreaded':
$unthreaded_active = 'active';
set_pconfig(local_channel(), 'mod_network', 'order', 2);
break;
default:
$commentord_active = 'active';
}
}
else {
$order = get_pconfig(local_channel(), 'mod_network', 'order', 0);
switch($order) {
case 0:
$commentord_active = 'active';
break;
case 1:
$postord_active = 'active';
break;
case 2:
$unthreaded_active = 'active';
break;
default:
$commentord_active = 'active';
}
}
// override order for search, filer and cid results
if(x($_GET,'search') || x($_GET,'file') || (! x($_GET,'pf') && x($_GET,'cid'))) {
$unthreaded_active = 'active';
$commentord_active = $postord_active = 'disabled';
}
$cmd = \App::$cmd;
$filter = '';
if(x($_GET,'cid'))
$filter .= '&cid=' . $_GET['cid'];
if(x($_GET,'gid'))
$filter .= '&gid=' . $_GET['gid'];
if(x($_GET,'star'))
$filter .= '&star=' . $_GET['star'];
if(x($_GET,'conv'))
$filter .= '&conv=' . $_GET['conv'];
if(x($_GET,'file'))
$filter .= '&file=' . $_GET['file'];
// tabs
$tabs = [];
$tabs[] = [
'label' => t('Commented Date'),
'icon' => '',
'url'=>z_root() . '/' . $cmd . '?f=&order=comment' . $filter,
'sel'=> $commentord_active,
'title' => t('Order by last commented date'),
];
$tabs[] = [
'label' => t('Posted Date'),
'icon' => '',
'url'=>z_root() . '/' . $cmd . '?f=&order=post' . $filter,
'sel'=> $postord_active,
'title' => t('Order by last posted date'),
];
$tabs[] = array(
'label' => t('Date Unthreaded'),
'icon' => '',
'url' => z_root() . '/' . $cmd . '?f=&order=unthreaded' . $filter,
'sel' => $unthreaded_active,
'title' => t('Order unthreaded by date'),
);
$arr = ['tabs' => $tabs];
call_hooks('network_tabs', $arr);
$o = '';
if($arr['tabs']) {
$content = replace_macros(get_markup_template('common_pills.tpl'), [
'$pills' => $arr['tabs'],
]);
$o = replace_macros(get_markup_template('common_widget.tpl'), [
'$title' => t('Activity Order'),
'$content' => $content,
]);
}
return $o;
}
}

View File

@ -24,7 +24,7 @@ class Admin {
'channels' => array(z_root() . '/admin/channels/', t('Channels'), 'channels'),
'security' => array(z_root() . '/admin/security/', t('Security'), 'security'),
'features' => array(z_root() . '/admin/features/', t('Features'), 'features'),
'plugins' => array(z_root() . '/admin/plugins/', t('Plugins'), 'plugins'),
'addons' => array(z_root() . '/admin/addons/', t('Addons'), 'addons'),
'themes' => array(z_root() . '/admin/themes/', t('Themes'), 'themes'),
'queue' => array(z_root() . '/admin/queue', t('Inspect queue'), 'queue'),
'profs' => array(z_root() . '/admin/profs', t('Profile Fields'), 'profs'),
@ -39,7 +39,7 @@ class Admin {
if($r) {
foreach ($r as $h){
$plugin = $h['aname'];
$plugins[] = array(z_root() . '/admin/plugins/' . $plugin, $plugin, 'plugin');
$plugins[] = array(z_root() . '/admin/addons/' . $plugin, $plugin, 'plugin');
// temp plugins with admin
\App::$plugins_admin[] = $plugin;
}
@ -53,7 +53,7 @@ class Admin {
$o .= replace_macros(get_markup_template('admin_aside.tpl'), array(
'$admin' => $aside,
'$admtxt' => t('Admin'),
'$plugadmtxt' => t('Plugin Features'),
'$plugadmtxt' => t('Addon Features'),
'$plugins' => $plugins,
'$logtxt' => t('Logs'),
'$logs' => $logs,

View File

@ -17,6 +17,9 @@ class Appcategories {
// Leaving this line which negates the effect of the two invalid lines prior
$srchurl = z_root() . '/apps';
if(argc() > 1 && argv(1) === 'available')
$srchurl .= '/available';
$terms = array();

View File

@ -0,0 +1,18 @@
<?php
namespace Zotlabs\Widget;
class Appstore {
function widget($arr) {
$store = ((argc() > 1 && argv(1) === 'available') ? 1 : 0);
return replace_macros(get_markup_template('appstore.tpl'), [
'$title' => t('App Collections'),
'$options' => [
[ z_root() . '/apps/available', t('Available Apps'), $store ],
[ z_root() . '/apps', t('Installed apps'), 1 - $store ]
]
]);
}
}

View File

@ -8,6 +8,9 @@ class Collections {
function widget($args) {
if(argc() < 2)
return;
$mode = ((array_key_exists('mode',$args)) ? $args['mode'] : 'conversation');
switch($mode) {
case 'conversation':

View File

@ -111,6 +111,17 @@ class Notifications {
'label' => t('Mark all notices seen')
]
];
$notifications[] = [
'type' => 'forums',
'icon' => 'comments-o',
'severity' => 'secondary',
'label' => t('Forums'),
'title' => t('Forums'),
'filter' => [
'name_label' => t('Filter by name')
]
];
}
if(local_channel() && is_site_admin()) {

View File

@ -105,7 +105,7 @@ class Settings_menu {
if(feature_enabled(local_channel(),'permcats')) {
$tabs[] = array(
'label' => t('Permission Groups'),
'label' => t('Permission Categories'),
'url' => z_root() . '/settings/permcats',
'selected' => ((argv(1) === 'permcats') ? 'active' : ''),
);

6
app/group.apd Normal file
View File

@ -0,0 +1,6 @@
version: 1
url: $baseurl/group
requires: local_channel
name: Privacy Groups
photo: icon:users
categories: Networking

View File

@ -50,7 +50,7 @@ require_once('include/attach.php');
require_once('include/bbcode.php');
define ( 'PLATFORM_NAME', 'hubzilla' );
define ( 'STD_VERSION', '3.4.2' );
define ( 'STD_VERSION', '3.6RC1' );
define ( 'ZOT_REVISION', '6.0a' );
@ -404,6 +404,7 @@ define ( 'VNOTIFY_REGISTER', 0x0400 );
define ( 'VNOTIFY_FILES', 0x0800 );
define ( 'VNOTIFY_PUBS', 0x1000 );
define ( 'VNOTIFY_LIKE', 0x2000 );
define ( 'VNOTIFY_FORUMS', 0x4000 );
@ -872,20 +873,21 @@ class App {
self::$path = $path;
}
set_include_path("include/self::$hostname" . PATH_SEPARATOR . get_include_path());
if((x($_SERVER,'QUERY_STRING')) && substr($_SERVER['QUERY_STRING'], 0, 2) === "q=") {
self::$query_string = escape_tags(substr($_SERVER['QUERY_STRING'], 2));
self::$query_string = str_replace(['<','>'],['&lt;','&gt;'],substr($_SERVER['QUERY_STRING'], 2));
// removing trailing / - maybe a nginx problem
if (substr(self::$query_string, 0, 1) == "/")
self::$query_string = substr(self::$query_string, 1);
// change the first & to ?
self::$query_string = preg_replace('/&/','?',self::$query_string,1);
}
if(x($_GET,'q'))
self::$cmd = escape_tags(trim($_GET['q'],'/\\'));
// unix style "homedir"
if(substr(self::$cmd, 0, 1) === '~')
if((substr(self::$cmd, 0, 1) === '~') || (substr(self::$cmd, 0, 1) === '@'))
self::$cmd = 'channel/' . substr(self::$cmd, 1);
/*
@ -1558,17 +1560,43 @@ function fix_system_urls($oldurl, $newurl) {
* @return string Parsed HTML code.
*/
function login($register = false, $form_id = 'main-login', $hiddens = false, $login_page = true) {
$o = '';
$reg = false;
$reglink = get_config('system', 'register_link');
if(! strlen($reglink))
$reglink = 'register';
$reg = array(
'title' => t('Create an account to access services and applications'),
'desc' => t('Register'),
'link' => (($register) ? $reglink : 'pubsites')
);
$o = '';
$reg = null;
// Here's the current description of how the register link works (2018-05-15)
// Register links are enabled on the site home page and login page and navbar.
// They are not shown by default on other pages which may require login.
// If the register link is enabled and registration is closed, the request is directed
// to /pubsites. If registration is allowed, /register is the default destination
// system.register_link can over-ride the default behaviour and redirect to an arbitrary
// webpage for paid/custom or organisational registrations, regardless of whether
// registration is allowed.
// system.register_link may or may not be the same destination as system.sellpage
// system.sellpage is the destination linked from the /pubsites page on other sites. If
// system.sellpage is not set, the 'register' link in /pubsites will go to 'register' on your
// site.
// If system.register_link is set to the word 'none', no registration link will be shown on
// your site.
$register_policy = get_config('system','register_policy');
$reglink = get_config('system', 'register_link', z_root() . '/' . ((intval($register_policy) === REGISTER_CLOSED) ? 'pubsites' : 'register'));
if($reglink !== 'none') {
$reg = [
'title' => t('Create an account to access services and applications'),
'desc' => t('Register'),
'link' => $reglink
];
}
$dest_url = z_root() . '/' . App::$query_string;
@ -1695,7 +1723,7 @@ function can_view_public_stream() {
if(observer_prohibited(true)) {
return false;
}
if(! (intval(get_config('system','open_pubstream',1)))) {
if(! get_observer_hash()) {
return false;
@ -2209,8 +2237,35 @@ function construct_page() {
if(App::get_scheme() === 'https' && App::$config['system']['transport_security_header'])
header("Strict-Transport-Security: max-age=31536000");
if(App::$config['system']['content_security_policy'])
header("Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'");
if(App::$config['system']['content_security_policy']) {
$cspsettings = Array (
'script-src' => Array ("'self'","'unsafe-inline'","'unsafe-eval'"),
'style-src' => Array ("'self'","'unsafe-inline'")
);
call_hooks('content_security_policy',$cspsettings);
// Legitimate CSP directives (cxref: https://content-security-policy.com/)
$validcspdirectives=Array(
"default-src", "script-src", "style-src",
"img-src", "connect-src", "font-src",
"object-src", "media-src", 'frame-src',
'sandbox', 'report-uri', 'child-src',
'form-action', 'frame-ancestors', 'plugin-types'
);
$cspheader = "Content-Security-Policy:";
foreach ($cspsettings as $cspdirective => $csp) {
if (!in_array($cspdirective,$validcspdirectives)) {
logger("INVALID CSP DIRECTIVE: ".$cspdirective,LOGGER_DEBUG);
continue;
}
$cspsettingsarray=array_unique($cspsettings[$cspdirective]);
$cspsetpolicy = implode(' ',$cspsettingsarray);
if ($cspsetpolicy) {
$cspheader .= " ".$cspdirective." ".$cspsetpolicy.";";
}
}
header($cspheader);
}
if(App::$config['system']['x_security_headers']) {
header("X-Frame-Options: SAMEORIGIN");
@ -2492,8 +2547,8 @@ function check_cron_broken() {
* @return boolean
*/
function observer_prohibited($allow_account = false) {
if($allow_account)
if($allow_account) {
return (((get_config('system', 'block_public')) && (! get_account_id()) && (! remote_channel())) ? true : false );
}
return (((get_config('system', 'block_public')) && (! local_channel()) && (! remote_channel())) ? true : false );
}

View File

@ -10,7 +10,7 @@
"SSO",
"ZOT"
],
"homepage" : "http://github.com/redmatrix/hubzilla",
"homepage" : "http://framagit.org/hubzilla/core/",
"license" : "MIT",
"authors" : [{
"name" : "Mike Macgirvin",
@ -18,8 +18,8 @@
}
],
"support" : {
"issues" : "https://github.com/redmatrix/hubzilla/issues",
"source" : "https://github.com/redmatrix/hubzilla"
"issues" : "https://framagit.org/hubzilla/core/issues",
"source" : "https://framagit.org/hubzilla/core/"
},
"require" : {
"php" : ">=5.5",
@ -40,13 +40,12 @@
"smarty/smarty": "~3.1"
},
"require-dev" : {
"php" : ">=7.0",
"phpunit/phpunit" : "~6.4.4",
"phpunit/phpunit" : "@stable",
"behat/behat" : "@stable",
"behat/mink-extension": "@stable",
"behat/mink-goutte-driver": "@stable",
"php-mock/php-mock-phpunit": "^2.0",
"phpunit/dbunit": "^3.0"
"php-mock/php-mock-phpunit": "@stable",
"phpunit/dbunit": "@stable"
},
"autoload" : {
"psr-4" : {

270
composer.lock generated
View File

@ -1,10 +1,10 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "516114a0fbd804e5234ebeacbac30376",
"content-hash": "ca5770d3c97cc1d0375413eeb61758ab",
"packages": [
{
"name": "bshaffer/oauth2-server-php",
@ -640,16 +640,16 @@
},
{
"name": "sabre/vobject",
"version": "4.1.5",
"version": "4.1.6",
"source": {
"type": "git",
"url": "https://github.com/sabre-io/vobject.git",
"reference": "0928660e92d46d2d24336a6db320636aa3a75414"
"reference": "122cacbdea2c6133ac04db86ec05854beef75adf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabre-io/vobject/zipball/0928660e92d46d2d24336a6db320636aa3a75414",
"reference": "0928660e92d46d2d24336a6db320636aa3a75414",
"url": "https://api.github.com/repos/sabre-io/vobject/zipball/122cacbdea2c6133ac04db86ec05854beef75adf",
"reference": "122cacbdea2c6133ac04db86ec05854beef75adf",
"shasum": ""
},
"require": {
@ -733,7 +733,7 @@
"xCal",
"xCard"
],
"time": "2018-03-08T21:06:39+00:00"
"time": "2018-04-20T07:22:50+00:00"
},
{
"name": "sabre/xml",
@ -863,16 +863,16 @@
},
{
"name": "smarty/smarty",
"version": "v3.1.31",
"version": "v3.1.32",
"source": {
"type": "git",
"url": "https://github.com/smarty-php/smarty.git",
"reference": "c7d42e4a327c402897dd587871434888fde1e7a9"
"reference": "ac9d4b587e5bf53381e21881820a9830765cb459"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/c7d42e4a327c402897dd587871434888fde1e7a9",
"reference": "c7d42e4a327c402897dd587871434888fde1e7a9",
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/ac9d4b587e5bf53381e21881820a9830765cb459",
"reference": "ac9d4b587e5bf53381e21881820a9830765cb459",
"shasum": ""
},
"require": {
@ -912,7 +912,7 @@
"keywords": [
"templating"
],
"time": "2016-12-14T21:57:25+00:00"
"time": "2018-04-24T14:53:33+00:00"
}
],
"packages-dev": [
@ -1118,27 +1118,27 @@
},
{
"name": "behat/mink-browserkit-driver",
"version": "v1.3.2",
"version": "1.3.3",
"source": {
"type": "git",
"url": "https://github.com/minkphp/MinkBrowserKitDriver.git",
"reference": "10e67fb4a295efcd62ea0bf16025a85ea19534fb"
"reference": "1b9a7ce903cfdaaec5fb32bfdbb26118343662eb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/minkphp/MinkBrowserKitDriver/zipball/10e67fb4a295efcd62ea0bf16025a85ea19534fb",
"reference": "10e67fb4a295efcd62ea0bf16025a85ea19534fb",
"url": "https://api.github.com/repos/minkphp/MinkBrowserKitDriver/zipball/1b9a7ce903cfdaaec5fb32bfdbb26118343662eb",
"reference": "1b9a7ce903cfdaaec5fb32bfdbb26118343662eb",
"shasum": ""
},
"require": {
"behat/mink": "^1.7.1@dev",
"php": ">=5.3.6",
"symfony/browser-kit": "~2.3|~3.0",
"symfony/dom-crawler": "~2.3|~3.0"
"symfony/browser-kit": "~2.3|~3.0|~4.0",
"symfony/dom-crawler": "~2.3|~3.0|~4.0"
},
"require-dev": {
"silex/silex": "~1.2",
"symfony/phpunit-bridge": "~2.7|~3.0"
"mink/driver-testsuite": "dev-master",
"symfony/http-kernel": "~2.3|~3.0|~4.0"
},
"type": "mink-driver",
"extra": {
@ -1170,7 +1170,7 @@
"browser",
"testing"
],
"time": "2016-03-05T08:59:47+00:00"
"time": "2018-05-02T09:25:31+00:00"
},
{
"name": "behat/mink-extension",
@ -1472,16 +1472,16 @@
},
{
"name": "guzzlehttp/guzzle",
"version": "6.3.0",
"version": "6.3.3",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699"
"reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699",
"reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba",
"reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba",
"shasum": ""
},
"require": {
@ -1491,7 +1491,7 @@
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "^4.0 || ^5.0",
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
"psr/log": "^1.0"
},
"suggest": {
@ -1500,7 +1500,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.2-dev"
"dev-master": "6.3-dev"
}
},
"autoload": {
@ -1533,7 +1533,7 @@
"rest",
"web service"
],
"time": "2017-06-22T18:50:49+00:00"
"time": "2018-04-22T15:46:56+00:00"
},
{
"name": "guzzlehttp/promises",
@ -1914,25 +1914,28 @@
},
{
"name": "php-mock/php-mock-phpunit",
"version": "2.0.1",
"version": "2.1.1",
"source": {
"type": "git",
"url": "https://github.com/php-mock/php-mock-phpunit.git",
"reference": "b42fc41ecb7538564067527f6c30b8854f149d32"
"reference": "ff1cc1d4e7478ce74221e05742588619bee84f69"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-mock/php-mock-phpunit/zipball/b42fc41ecb7538564067527f6c30b8854f149d32",
"reference": "b42fc41ecb7538564067527f6c30b8854f149d32",
"url": "https://api.github.com/repos/php-mock/php-mock-phpunit/zipball/ff1cc1d4e7478ce74221e05742588619bee84f69",
"reference": "ff1cc1d4e7478ce74221e05742588619bee84f69",
"shasum": ""
},
"require": {
"php": ">=7",
"php-mock/php-mock-integration": "^2",
"phpunit/phpunit": "^6 <6.5"
"phpunit/phpunit": "^6 || ^7"
},
"type": "library",
"autoload": {
"files": [
"autoload.php"
],
"psr-4": {
"phpmock\\phpunit\\": "classes/"
}
@ -1961,7 +1964,7 @@
"test",
"test double"
],
"time": "2017-12-02T09:49:02+00:00"
"time": "2018-04-06T13:54:43+00:00"
},
{
"name": "phpdocumentor/reflection-common",
@ -2111,23 +2114,23 @@
},
{
"name": "phpspec/prophecy",
"version": "1.7.5",
"version": "1.7.6",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401"
"reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401",
"reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
"reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
"sebastian/comparator": "^1.1|^2.0",
"sebastian/comparator": "^1.1|^2.0|^3.0",
"sebastian/recursion-context": "^1.0|^2.0|^3.0"
},
"require-dev": {
@ -2170,7 +2173,7 @@
"spy",
"stub"
],
"time": "2018-02-19T10:16:54+00:00"
"time": "2018-04-18T13:57:24+00:00"
},
{
"name": "phpunit/dbunit",
@ -2226,16 +2229,16 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "5.3.0",
"version": "5.3.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1"
"reference": "c89677919c5dd6d3b3852f230a663118762218ac"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/661f34d0bd3f1a7225ef491a70a020ad23a057a1",
"reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac",
"reference": "c89677919c5dd6d3b3852f230a663118762218ac",
"shasum": ""
},
"require": {
@ -2285,7 +2288,7 @@
"testing",
"xunit"
],
"time": "2017-12-06T09:29:45+00:00"
"time": "2018-04-06T15:36:58+00:00"
},
{
"name": "phpunit/php-file-iterator",
@ -2475,16 +2478,16 @@
},
{
"name": "phpunit/phpunit",
"version": "6.4.4",
"version": "6.5.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "562f7dc75d46510a4ed5d16189ae57fbe45a9932"
"reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/562f7dc75d46510a4ed5d16189ae57fbe45a9932",
"reference": "562f7dc75d46510a4ed5d16189ae57fbe45a9932",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4f21a3c6b97c42952fd5c2837bb354ec0199b97b",
"reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b",
"shasum": ""
},
"require": {
@ -2498,12 +2501,12 @@
"phar-io/version": "^1.0",
"php": "^7.0",
"phpspec/prophecy": "^1.7",
"phpunit/php-code-coverage": "^5.2.2",
"phpunit/php-file-iterator": "^1.4.2",
"phpunit/php-code-coverage": "^5.3",
"phpunit/php-file-iterator": "^1.4.3",
"phpunit/php-text-template": "^1.2.1",
"phpunit/php-timer": "^1.0.9",
"phpunit/phpunit-mock-objects": "^4.0.3",
"sebastian/comparator": "^2.0.2",
"phpunit/phpunit-mock-objects": "^5.0.5",
"sebastian/comparator": "^2.1",
"sebastian/diff": "^2.0",
"sebastian/environment": "^3.1",
"sebastian/exporter": "^3.1",
@ -2529,7 +2532,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.4.x-dev"
"dev-master": "6.5.x-dev"
}
},
"autoload": {
@ -2555,33 +2558,33 @@
"testing",
"xunit"
],
"time": "2017-11-08T11:26:09+00:00"
"time": "2018-04-10T11:38:34+00:00"
},
{
"name": "phpunit/phpunit-mock-objects",
"version": "4.0.4",
"version": "5.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
"reference": "2f789b59ab89669015ad984afa350c4ec577ade0"
"reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/2f789b59ab89669015ad984afa350c4ec577ade0",
"reference": "2f789b59ab89669015ad984afa350c4ec577ade0",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/33fd41a76e746b8fa96d00b49a23dadfa8334cdf",
"reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.5",
"php": "^7.0",
"phpunit/php-text-template": "^1.2.1",
"sebastian/exporter": "^3.0"
"sebastian/exporter": "^3.1"
},
"conflict": {
"phpunit/phpunit": "<6.0"
},
"require-dev": {
"phpunit/phpunit": "^6.0"
"phpunit/phpunit": "^6.5"
},
"suggest": {
"ext-soap": "*"
@ -2589,7 +2592,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.0.x-dev"
"dev-master": "5.0.x-dev"
}
},
"autoload": {
@ -2604,7 +2607,7 @@
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
@ -2614,7 +2617,7 @@
"mock",
"xunit"
],
"time": "2017-08-03T14:08:16+00:00"
"time": "2018-01-06T05:45:45+00:00"
},
{
"name": "psr/container",
@ -3276,16 +3279,16 @@
},
{
"name": "symfony/browser-kit",
"version": "v3.4.6",
"version": "v3.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/browser-kit.git",
"reference": "490f27762705c8489bd042fe3e9377a191dba9b4"
"reference": "840bb6f0d5b3701fd768b68adf7193c2d0f98f79"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/490f27762705c8489bd042fe3e9377a191dba9b4",
"reference": "490f27762705c8489bd042fe3e9377a191dba9b4",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/840bb6f0d5b3701fd768b68adf7193c2d0f98f79",
"reference": "840bb6f0d5b3701fd768b68adf7193c2d0f98f79",
"shasum": ""
},
"require": {
@ -3329,11 +3332,11 @@
],
"description": "Symfony BrowserKit Component",
"homepage": "https://symfony.com",
"time": "2018-01-03T07:37:34+00:00"
"time": "2018-03-19T22:32:39+00:00"
},
{
"name": "symfony/class-loader",
"version": "v3.4.6",
"version": "v3.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/class-loader.git",
@ -3389,16 +3392,16 @@
},
{
"name": "symfony/config",
"version": "v3.4.6",
"version": "v3.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/config.git",
"reference": "05e10567b529476a006b00746c5f538f1636810e"
"reference": "7c2a9d44f4433863e9bca682e7f03609234657f9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/config/zipball/05e10567b529476a006b00746c5f538f1636810e",
"reference": "05e10567b529476a006b00746c5f538f1636810e",
"url": "https://api.github.com/repos/symfony/config/zipball/7c2a9d44f4433863e9bca682e7f03609234657f9",
"reference": "7c2a9d44f4433863e9bca682e7f03609234657f9",
"shasum": ""
},
"require": {
@ -3448,20 +3451,20 @@
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com",
"time": "2018-02-14T10:03:57+00:00"
"time": "2018-03-19T22:32:39+00:00"
},
{
"name": "symfony/console",
"version": "v3.4.6",
"version": "v3.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "067339e9b8ec30d5f19f5950208893ff026b94f7"
"reference": "5b1fdfa8eb93464bcc36c34da39cedffef822cdf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/067339e9b8ec30d5f19f5950208893ff026b94f7",
"reference": "067339e9b8ec30d5f19f5950208893ff026b94f7",
"url": "https://api.github.com/repos/symfony/console/zipball/5b1fdfa8eb93464bcc36c34da39cedffef822cdf",
"reference": "5b1fdfa8eb93464bcc36c34da39cedffef822cdf",
"shasum": ""
},
"require": {
@ -3482,7 +3485,7 @@
"symfony/process": "~3.3|~4.0"
},
"suggest": {
"psr/log": "For using the console logger",
"psr/log-implementation": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/lock": "",
"symfony/process": ""
@ -3517,20 +3520,20 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2018-02-26T15:46:28+00:00"
"time": "2018-04-30T01:22:56+00:00"
},
{
"name": "symfony/css-selector",
"version": "v3.4.6",
"version": "v3.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
"reference": "544655f1fc078a9cd839fdda2b7b1e64627c826a"
"reference": "519a80d7c1d95c6cc0b67f686d15fe27c6910de0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/544655f1fc078a9cd839fdda2b7b1e64627c826a",
"reference": "544655f1fc078a9cd839fdda2b7b1e64627c826a",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/519a80d7c1d95c6cc0b67f686d15fe27c6910de0",
"reference": "519a80d7c1d95c6cc0b67f686d15fe27c6910de0",
"shasum": ""
},
"require": {
@ -3570,20 +3573,20 @@
],
"description": "Symfony CssSelector Component",
"homepage": "https://symfony.com",
"time": "2018-02-03T14:55:07+00:00"
"time": "2018-03-19T22:32:39+00:00"
},
{
"name": "symfony/debug",
"version": "v3.4.6",
"version": "v3.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "9b1071f86e79e1999b3d3675d2e0e7684268b9bc"
"reference": "1b95888cfd996484527cb41e8952d9a5eaf7454f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/9b1071f86e79e1999b3d3675d2e0e7684268b9bc",
"reference": "9b1071f86e79e1999b3d3675d2e0e7684268b9bc",
"url": "https://api.github.com/repos/symfony/debug/zipball/1b95888cfd996484527cb41e8952d9a5eaf7454f",
"reference": "1b95888cfd996484527cb41e8952d9a5eaf7454f",
"shasum": ""
},
"require": {
@ -3626,20 +3629,20 @@
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
"time": "2018-02-28T21:49:22+00:00"
"time": "2018-04-30T16:53:52+00:00"
},
{
"name": "symfony/dependency-injection",
"version": "v3.4.6",
"version": "v3.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/dependency-injection.git",
"reference": "12e901abc1cb0d637a0e5abe9923471361d96b07"
"reference": "54ff9d78b56429f9a1ac12e60bfb6d169c0468e3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/12e901abc1cb0d637a0e5abe9923471361d96b07",
"reference": "12e901abc1cb0d637a0e5abe9923471361d96b07",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/54ff9d78b56429f9a1ac12e60bfb6d169c0468e3",
"reference": "54ff9d78b56429f9a1ac12e60bfb6d169c0468e3",
"shasum": ""
},
"require": {
@ -3697,20 +3700,20 @@
],
"description": "Symfony DependencyInjection Component",
"homepage": "https://symfony.com",
"time": "2018-03-04T03:54:53+00:00"
"time": "2018-04-29T14:04:08+00:00"
},
{
"name": "symfony/dom-crawler",
"version": "v3.4.6",
"version": "v3.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
"reference": "2bb5d3101cc01f4fe580e536daf4f1959bc2d24d"
"reference": "1a4cffeb059226ff6bee9f48acb388faf674afff"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/2bb5d3101cc01f4fe580e536daf4f1959bc2d24d",
"reference": "2bb5d3101cc01f4fe580e536daf4f1959bc2d24d",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/1a4cffeb059226ff6bee9f48acb388faf674afff",
"reference": "1a4cffeb059226ff6bee9f48acb388faf674afff",
"shasum": ""
},
"require": {
@ -3753,20 +3756,20 @@
],
"description": "Symfony DomCrawler Component",
"homepage": "https://symfony.com",
"time": "2018-02-22T10:48:49+00:00"
"time": "2018-03-19T22:32:39+00:00"
},
{
"name": "symfony/event-dispatcher",
"version": "v3.4.6",
"version": "v3.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "58990682ac3fdc1f563b7e705452921372aad11d"
"reference": "fdd5abcebd1061ec647089c6c41a07ed60af09f8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/58990682ac3fdc1f563b7e705452921372aad11d",
"reference": "58990682ac3fdc1f563b7e705452921372aad11d",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/fdd5abcebd1061ec647089c6c41a07ed60af09f8",
"reference": "fdd5abcebd1061ec647089c6c41a07ed60af09f8",
"shasum": ""
},
"require": {
@ -3816,11 +3819,11 @@
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
"time": "2018-02-14T10:03:57+00:00"
"time": "2018-04-06T07:35:25+00:00"
},
{
"name": "symfony/filesystem",
"version": "v3.4.6",
"version": "v3.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
@ -3869,16 +3872,16 @@
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.7.0",
"version": "v1.8.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b"
"reference": "3296adf6a6454a050679cde90f95350ad604b171"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b",
"reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171",
"reference": "3296adf6a6454a050679cde90f95350ad604b171",
"shasum": ""
},
"require": {
@ -3890,7 +3893,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.7-dev"
"dev-master": "1.8-dev"
}
},
"autoload": {
@ -3924,20 +3927,20 @@
"portable",
"shim"
],
"time": "2018-01-30T19:27:44+00:00"
"time": "2018-04-26T10:06:28+00:00"
},
{
"name": "symfony/translation",
"version": "v3.4.6",
"version": "v3.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
"reference": "80e19eaf12cbb546ac40384e5c55c36306823e57"
"reference": "d4af50f46cd8171fd5c1cdebdb9a8bbcd8078c6c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/80e19eaf12cbb546ac40384e5c55c36306823e57",
"reference": "80e19eaf12cbb546ac40384e5c55c36306823e57",
"url": "https://api.github.com/repos/symfony/translation/zipball/d4af50f46cd8171fd5c1cdebdb9a8bbcd8078c6c",
"reference": "d4af50f46cd8171fd5c1cdebdb9a8bbcd8078c6c",
"shasum": ""
},
"require": {
@ -3958,7 +3961,7 @@
"symfony/yaml": "~3.4|~4.0"
},
"suggest": {
"psr/log": "To use logging capability in translator",
"psr/log-implementation": "To use logging capability in translator",
"symfony/config": "",
"symfony/yaml": ""
},
@ -3992,20 +3995,20 @@
],
"description": "Symfony Translation Component",
"homepage": "https://symfony.com",
"time": "2018-02-22T06:28:18+00:00"
"time": "2018-04-30T01:22:56+00:00"
},
{
"name": "symfony/yaml",
"version": "v3.4.6",
"version": "v3.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "6af42631dcf89e9c616242c900d6c52bd53bd1bb"
"reference": "033cfa61ef06ee0847e056e530201842b6e926c3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/6af42631dcf89e9c616242c900d6c52bd53bd1bb",
"reference": "6af42631dcf89e9c616242c900d6c52bd53bd1bb",
"url": "https://api.github.com/repos/symfony/yaml/zipball/033cfa61ef06ee0847e056e530201842b6e926c3",
"reference": "033cfa61ef06ee0847e056e530201842b6e926c3",
"shasum": ""
},
"require": {
@ -4050,7 +4053,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2018-02-16T09:50:28+00:00"
"time": "2018-04-08T08:21:29+00:00"
},
{
"name": "theseer/tokenizer",
@ -4094,16 +4097,16 @@
},
{
"name": "webmozart/assert",
"version": "1.2.0",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/webmozart/assert.git",
"reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f"
"reference": "0df1908962e7a3071564e857d86874dad1ef204a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f",
"reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f",
"url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a",
"reference": "0df1908962e7a3071564e857d86874dad1ef204a",
"shasum": ""
},
"require": {
@ -4140,15 +4143,18 @@
"check",
"validate"
],
"time": "2016-11-23T20:04:58+00:00"
"time": "2018-01-29T19:49:41+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"phpunit/phpunit": 0,
"behat/behat": 0,
"behat/mink-extension": 0,
"behat/mink-goutte-driver": 0
"behat/mink-goutte-driver": 0,
"php-mock/php-mock-phpunit": 0,
"phpunit/dbunit": 0
},
"prefer-stable": false,
"prefer-lowest": false,
@ -4160,7 +4166,5 @@
"ext-xml": "*",
"ext-openssl": "*"
},
"platform-dev": {
"php": ">=5.6 || >=7.0"
}
"platform-dev": []
}

View File

@ -1,11 +1,11 @@
[b]$Projectname on OpenShift[/b]
You will notice a new .openshift folder when you fetch from upstream, i.e. from [url=https://github.com/redmatrix/hubzilla.git]https://github.com/redmatrix/hubzilla.git[/url] , which contains a deploy script to set up Hubzilla on OpenShift with plugins and extra themes.
You will notice a new .openshift folder when you fetch from upstream, i.e. from [url=https://framagit.org/hubzilla/core.git]https://framagit.org/hubzilla/core.git[/url] , which contains a deploy script to set up Hubzilla on OpenShift with plugins and extra themes.
As of this writing, 2015-10-28, you do not have to pay for OpenShift on the Free plan, which gives you three gears at no cost. The Bronze plan gives you three gears at no cost too, but you can expand to 16 gears by paying, and this requires you to register your payment card. The three gears can give three instances of Hubzilla with one gear each, or you can combine two gears into one high-availability Hubzilla instance and one extra gear. The main difference to be aware of is this: gears on the Free plan will go into hibernation if left idle for too long, this does not happen on the Bronze plan.
Create an account on OpenShift, then use the registration e-mail and password to create your first Hubzilla instance. Install git and RedHat's command line tools - rhc - if you have not already done so. See for example https://developers.openshift.com/en/getting-started-debian-ubuntu.html on how to do this on Debian GNU/Linux, or in the menu on that page for other GNU/Linux distributions or other operating systems.
[code]rhc app-create your_app_name php-5.4 mysql-5.5 cron phpmyadmin --namespace your_domain --from-code https://github.com/redmatrix/hubzilla.git -l your@email.address -p your_account_password
[code]rhc app-create your_app_name php-5.4 mysql-5.5 cron phpmyadmin --namespace your_domain --from-code https://framagit.org/hubzilla/core.git -l your@email.address -p your_account_password
[/code]
Make a note of the database username and password OpenShift creates for your instance, and use these at [url=https://your_app_name-your_domain.rhcloud.com/]https://your_app_name-your_domain.rhcloud.com/[/url] to complete the setup. You MUST change server address from 127.0.0.1 to localhost.

View File

@ -4,7 +4,7 @@ Hubzilla - Community Server
===========================
<p align="center" markdown="1">
<em><a href="https://github.com/redmatrix/hubzilla/blob/master/install/INSTALL.txt">Installing Hubzilla</a></em>
<em><a href="https://framagit.org/hubzilla/core/blob/master/install/INSTALL.txt">Installing Hubzilla</a></em>
</p>

View File

@ -1,3 +1,9 @@
Privacy Policy
==============
#include doc/gdpr1.md;
Terms of Service
================

View File

@ -13,7 +13,7 @@ From the practical perspective of hub members who use the software, $Projectname
While all of these apps and services can be found in other software packages, only $Projectname allows you to set permissions for groups and individuals who may not even have accounts on your hub! In typical web apps, if you want to share things privately on the internet, the people you share with must have accounts on the server hosting your data; otherwise, there is no robust way for your server to [i]authenticate[/i] visitors to the site to know whether to grant them access. $Projectname solves this problem with an advanced system of [i]remote authentication[/i] that validates the identity of visitors by employing techniques that include public key cryptography.
[h3]Software Stack[/h3]
The $Projectname software stack is a relatively standard webserver application written primarily in PHP/MySQL and [url=https://github.com/redmatrix/hubzilla/blob/master/install/INSTALL.txt]requiring little more than a web server, a MySQL-compatible database, and the PHP scripting language[/url]. It is designed to be easily installable by those with basic website administration skills on typical shared hosting platforms with a broad range of computing hardware. It is also easily extended via plugins and themes and other third-party tools.
The $Projectname software stack is a relatively standard webserver application written primarily in PHP/MySQL and [url=https://framagit.org/hubzilla/core/blob/master/install/INSTALL.txt]requiring little more than a web server, a MySQL-compatible database, and the PHP scripting language[/url]. It is designed to be easily installable by those with basic website administration skills on typical shared hosting platforms with a broad range of computing hardware. It is also easily extended via plugins and themes and other third-party tools.
[h3]Glossary[/h3]
[dl terms="b"]

View File

@ -106,7 +106,7 @@ For these reasons we [b]strongly recommend[/b] that you do NOT install addons fr
We also recognise that some developers prefer working on their own and do not wish their code to be mingled with the project repository for a variety of reasons. These developers can ease troubleshooting and debugging by providing a README file in their respective code repository outlining the process for submitting patches and bug fixes. It is also recommended that these projects provide both a 'dev' (development) and 'master' (production) branch which tracks the current project branches of those names. This is because dev and master are often not compatible from the viewpoint of library interfaces. It is also highly recommended that your repository versions are tagged and moved forward within 24 hours of project releases. This is a major inconvenience for everybdy involved, and can present downtime for production sites while this process is being carried out; which is one more reason why we [b]strongly recommend[/b] that addons be submitted to the project addon repository and that you do NOT install such third-party addons.
[url=https://github.com/redmatrix/hubzilla-addons]https://github.com/redmatrix/hubzilla-addons[/url] Main project addon repository
[url=https://framagit.org/hubzilla/addons]https://framagit.org/hubzilla/addons[/url] Main project addon repository
[url=https://github.com/23n/red-addons]https://github.com/23n/red-addons[/url] Oliver's repository (mayan_places and flip)

View File

@ -10,7 +10,7 @@ Next, click the link to Register a new application. That brings up the new appli
Icon. I uploaded $Projectname icon located at this link, after saving it to my computer:
https://github.com/redmatrix/hubzilla/blob/master/images/rm-32.png
https://framagit.org/hubzilla/core/blob/master/images/rm-32.png
Name. Give the application an appropriate name. I called mine hubzilla. You might prefer r2g.

View File

@ -19,7 +19,7 @@ we welcome patches if you manage to get it working.
### Where to find more help
If you encounter problems or have issues not addressed in this documentation,
please let us know via the [Github issue
tracker](https://github.com/redmatrix/hubzilla/issues). Please be as clear as you
tracker](https://framagit.org/hubzilla/core/issues). Please be as clear as you
can about your operating environment and provide as much detail as possible
about any error messages you may see, so that we can prevent it from happening
in the future. Due to the large variety of operating systems and PHP platforms
@ -120,7 +120,7 @@ repository rather than to use a packaged tar or zip file. This makes the
software much easier to update. The Linux command to clone the repository
into a directory "mywebsite" would be:
git clone https://github.com/redmatrix/hubzilla.git mywebsite
git clone https://framagit.org/hubzilla/core.git mywebsite
and then you can pick up the latest changes at any time with:
@ -153,7 +153,7 @@ web-based administrative tools to function:
Navigate to your website. Then you should clone the addon repository (separately). We'll give this repository a nickname of 'hzaddons'. You can pull in other hubzilla addon repositories by giving them different nicknames::
cd mywebsite
util/add_addon_repo https://github.com/redmatrix/hubzilla-addons.git hzaddons
util/add_addon_repo https://framagit.org/hubzilla/addons.git hzaddons
##### Updating
For keeping the addon tree updated, you should be on your top level website directory and issue an update command for that repository::
@ -185,7 +185,7 @@ The installation script was originally designed for a small hardware server behi
1. `apt-get install git`
1. `mkdir -p /var/www/html`
1. `cd /var/www/html`
1. `git clone https://github.com/redmatrix/hubzilla.git .`
1. `git clone https://framagit.org/hubzilla/core.git .`
1. `nano .homeinstall/hubzilla-config.txt`
1. `cd .homeinstall/`
1. `./hubzilla-setup.sh`
@ -331,16 +331,6 @@ empty:
util/config system directory_server ""
### Upgrading from RedMatrix to $Projectname
#### How to migrate an individual channel from RedMatrix to $Projectname
1. Clone the channel by opening an account on a $Projectname hub and performing a basic import (not content) from the original RedMatrix hub. Give your new clone time to sync connections and settings.
1. Export individual channel content from your RedMatrix hub to a set of JSON text files using the red.hub/uexport tool. Do this in monthly increments if necessary.
1. Import the JSON data files sequentially in chronological order into the $Projectname clone using the new.hub/import_items tool.
1. Inform your Friendica and Diaspora contacts that your channel moves. They need to reconnect to your new address.
1. After successful import (check!) delete your channel on the old RedMatrix Server.
1. On the $Projectname server visit new.hub/locs and upgrade to your channel to a primary one. And when the old Redmatrix server is still listed delete them here as well. Press "Sync" to inform all other server in the grid.
### Administration
@ -396,7 +386,7 @@ To immediately clear out all the extra logging stuff you added. Use the informa
##### Rotating log files
1. Enable the **logrot** addon in the official [hubzilla-addons](https://github.com/redmatrix/hubzilla-addons) repo
1. Enable the **logrot** addon in the official [hubzilla-addons](https://framagit.org/hubzilla/addons) repo
1. Create a directory in your web root called `log` with webserver write permissions
1. Go to the **logrot** admin settings and enter this folder name as well as the max size and number of retained log files.
@ -407,6 +397,6 @@ When reporting issues, please try to provide as much detail as may be necessary
We encourage you to try to the best of your abilities to use these logs combined with the source code in your possession to troubleshoot issues and find their cause. The community is often able to help, but only you have access to your site logfiles and it is considered a security risk to share them.
If a code issue has been uncovered, please report it on the project bugtracker (https://github.com/redmatrix/hubzilla/issues). Again provide as much detail as possible to avoid us going back and forth asking questions about your configuration or how to duplicate the problem, so that we can get right to the problem and figure out what to do about it. You are also welcome to offer your own solutions and submit patches. In fact we encourage this as we are all volunteers and have little spare time available. The more people that help, the easier the workload for everybody. It's OK if your solution isn't perfect. Every little bit helps and perhaps we can improve on it.
If a code issue has been uncovered, please report it on the project bugtracker (https://framagit.org/hubzilla/core/issues). Again provide as much detail as possible to avoid us going back and forth asking questions about your configuration or how to duplicate the problem, so that we can get right to the problem and figure out what to do about it. You are also welcome to offer your own solutions and submit patches. In fact we encourage this as we are all volunteers and have little spare time available. The more people that help, the easier the workload for everybody. It's OK if your solution isn't perfect. Every little bit helps and perhaps we can improve on it.

View File

@ -1,133 +1,133 @@
[b]Red Twitter API[/b]
The &quot;basic&quot; Red web API is based on the Twitter API, as this provides instant compatibility with a huge number of third-party clients and applications without requiring any code changes on their part. It is also a super-set of the StatusNet version of the Twitter API, as this also has existing wide support.
Red has a lot more capability that isn't exposed in the Twitter interfaces or where we are forced to &quot;dumb-down&quot; the API functions to work with the primitive Twitter/StatusNet communications and privacy model. So we plan to extend the Twitter API in ways that will allow Red-specific clients to make full use of Red features without being crippled.
A dedicated Red API is also being developed to work with native data structures and permissions and which do not require translating to different privacy and permission models and storage formats. This will be described in other documents. The prefix for all of the native endpoints is 'api/red'.
Red provides multiple channels accesible via the same login account. With Red, any API function which requires authentication will accept a parameter &amp;channel={channel_nickname} - and will select that channel and make it current before executing the API command. By default, the default channel associated with an account is selected.
Red also provides an extended permission model. In the absence of any Red specific API calls to set permissions, they will be set to the default permissions settings which are associated with the current channel.
Red will probably never be able to support the Twitter 'api/friendships' functions fully because Red is not a social network and has no concept of &quot;friendships&quot; - it only recognises permissions to do stuff (or not do stuff as the case may be).
Legend: T= Twitter, S= StatusNet, F= Friendica, R= Red, ()=Not yet working, J= JSON only (XML formats deprecated)
Twitter API compatible functions:
api/account/verify_credentials T,S,F,R
api/statuses/update T,S,F,R
api/users/show T,S,F,R
api/statuses/home_timeline T,S,F,R
api/statuses/friends_timeline T,S,F,R
api/statuses/public_timeline T,S,F,R
api/statuses/show T,S,F,R
api/statuses/retweet T,S,F,R
api/statuses/destroy T,S,F,(R)
api/statuses/mentions T,S,F,(R)
api/statuses/replies T,S,F,(R)
api/statuses/user_timeline T,S,F,(R)
api/favorites T,S,F,R
api/account/rate_limit_status T,S,F,R
api/help/test T,S,F,R
api/statuses/friends T,S,F,R
api/statuses/followers T,S,F,R
api/friends/ids T,S,F,R
api/followers/ids T,S,F,R
api/direct_messages/new T,S,F,R
api/direct_messages/conversation T,S,F,R
api/direct_messages/all T,S,F,R
api/direct_messages/sent T,S,F,R
api/direct_messages T,S,F,R
api/oauth/request_token T,S,F,R
api/oauth/access_token T,S,F,R
api/favorites T,S,R
api/favorites/create T,S,R
api/favorites/destroy T,S,R
Twitter API functions supported by StatusNet but not currently by Friendica or Red
api/statuses/retweets_of_me T,S
api/friendships/create T,S
api/friendships/destroy T,S
api/friendships/exists T,S
api/friendships/show T,S
api/account/update_location T,S
api/account/update_profile_background_image T,S
api/account/update_profile_image T,S
api/blocks/create T,S
api/blocks/destroy T,S
Twitter API functions not currently supported by StatusNet
api/statuses/retweeted_to_me T
api/statuses/retweeted_by_me T
api/direct_messages/destroy T
api/account/end_session T,(R)
api/account/update_delivery_device T
api/notifications/follow T
api/notifications/leave T
api/blocks/exists T
api/blocks/blocking T
api/lists T
Statusnet compatible extensions to the Twitter API supported in both Friendica and Red
api/statusnet/version S,F,R
api/statusnet/config S,F,R
Friendica API extensions to the Twitter API supported in both Friendica and Red
api/statuses/mediap F,R
Red specific API extensions to the Twitter API not supported in Friendica
api/account/logout R
api/export/basic R,J
api/friendica/config R
api/red/config R
api/friendica/version R
api/red/version R
api/red/channel/export/basic R,J
api/red/channel/stream R,J (currently post only)
api/red/albums R,J
api/red/photos R,J (option album=xxxx)
Red proposed API extensions to the Twitter API
api/statuses/edit (R),J
api/statuses/permissions (R),J
api/statuses/permissions/update (R),J
api/statuses/ids (R),J # search for existing message_id before importing a foreign post
api/files/show (R),J
api/files/destroy (R),J
api/files/update (R),J
api/files/permissions (R),J
api/files/permissions/update (R),J
api/pages/show (R),J
api/pages/destroy (R),J
api/pages/update (R),J
api/pages/permissions (R),J
api/pages/permissions/update (R),J
api/events/show (R),J
api/events/update (R),J
api/events/permissions (R),J
api/events/permissions/update (R),J
api/events/destroy (R),J
api/photos/show (R),J
api/photos/update (R),J
api/photos/permissions (R),J
api/photos/permissions/update (R),J
api/albums/destroy (R),J
api/albums/show (R),J
api/albums/update (R),J
api/albums/permissions (R),J
api/albums/permissions/update (R),J
api/albums/destroy (R),J
api/friends/permissions (R),J
#include doc/macros/main_footer.bb;
[b]Red Twitter API[/b]
The &quot;basic&quot; Red web API is based on the Twitter API, as this provides instant compatibility with a huge number of third-party clients and applications without requiring any code changes on their part. It is also a super-set of the StatusNet version of the Twitter API, as this also has existing wide support.
Red has a lot more capability that isn't exposed in the Twitter interfaces or where we are forced to &quot;dumb-down&quot; the API functions to work with the primitive Twitter/StatusNet communications and privacy model. So we plan to extend the Twitter API in ways that will allow Red-specific clients to make full use of Red features without being crippled.
A dedicated Red API is also being developed to work with native data structures and permissions and which do not require translating to different privacy and permission models and storage formats. This will be described in other documents. The prefix for all of the native endpoints is 'api/red'.
Red provides multiple channels accesible via the same login account. With Red, any API function which requires authentication will accept a parameter &amp;channel={channel_nickname} - and will select that channel and make it current before executing the API command. By default, the default channel associated with an account is selected.
Red also provides an extended permission model. In the absence of any Red specific API calls to set permissions, they will be set to the default permissions settings which are associated with the current channel.
Red will probably never be able to support the Twitter 'api/friendships' functions fully because Red is not a social network and has no concept of &quot;friendships&quot; - it only recognises permissions to do stuff (or not do stuff as the case may be).
Legend: T= Twitter, S= StatusNet, F= Friendica, R= Red, ()=Not yet working, J= JSON only (XML formats deprecated)
Twitter API compatible functions:
api/account/verify_credentials T,S,F,R
api/statuses/update T,S,F,R
api/users/show T,S,F,R
api/statuses/home_timeline T,S,F,R
api/statuses/friends_timeline T,S,F,R
api/statuses/public_timeline T,S,F,R
api/statuses/show T,S,F,R
api/statuses/retweet T,S,F,R
api/statuses/destroy T,S,F,(R)
api/statuses/mentions T,S,F,(R)
api/statuses/replies T,S,F,(R)
api/statuses/user_timeline T,S,F,(R)
api/favorites T,S,F,R
api/account/rate_limit_status T,S,F,R
api/help/test T,S,F,R
api/statuses/friends T,S,F,R
api/statuses/followers T,S,F,R
api/friends/ids T,S,F,R
api/followers/ids T,S,F,R
api/direct_messages/new T,S,F,R
api/direct_messages/conversation T,S,F,R
api/direct_messages/all T,S,F,R
api/direct_messages/sent T,S,F,R
api/direct_messages T,S,F,R
api/oauth/request_token T,S,F,R
api/oauth/access_token T,S,F,R
api/favorites T,S,R
api/favorites/create T,S,R
api/favorites/destroy T,S,R
Twitter API functions supported by StatusNet but not currently by Friendica or Red
api/statuses/retweets_of_me T,S
api/friendships/create T,S
api/friendships/destroy T,S
api/friendships/exists T,S
api/friendships/show T,S
api/account/update_location T,S
api/account/update_profile_background_image T,S
api/account/update_profile_image T,S
api/blocks/create T,S
api/blocks/destroy T,S
Twitter API functions not currently supported by StatusNet
api/statuses/retweeted_to_me T
api/statuses/retweeted_by_me T
api/direct_messages/destroy T
api/account/end_session T,(R)
api/account/update_delivery_device T
api/notifications/follow T
api/notifications/leave T
api/blocks/exists T
api/blocks/blocking T
api/lists T
Statusnet compatible extensions to the Twitter API supported in both Friendica and Red
api/statusnet/version S,F,R
api/statusnet/config S,F,R
Friendica API extensions to the Twitter API supported in both Friendica and Red
api/statuses/mediap F,R
Red specific API extensions to the Twitter API not supported in Friendica
api/account/logout R
api/export/basic R,J
api/friendica/config R
api/red/config R
api/friendica/version R
api/red/version R
api/red/channel/export/basic R,J
api/red/channel/stream R,J (currently post only)
api/red/albums R,J
api/red/photos R,J (option album=xxxx)
Red proposed API extensions to the Twitter API
api/statuses/edit (R),J
api/statuses/permissions (R),J
api/statuses/permissions/update (R),J
api/statuses/ids (R),J # search for existing message_id before importing a foreign post
api/files/show (R),J
api/files/destroy (R),J
api/files/update (R),J
api/files/permissions (R),J
api/files/permissions/update (R),J
api/pages/show (R),J
api/pages/destroy (R),J
api/pages/update (R),J
api/pages/permissions (R),J
api/pages/permissions/update (R),J
api/events/show (R),J
api/events/update (R),J
api/events/permissions (R),J
api/events/permissions/update (R),J
api/events/destroy (R),J
api/photos/show (R),J
api/photos/update (R),J
api/photos/permissions (R),J
api/photos/permissions/update (R),J
api/albums/destroy (R),J
api/albums/show (R),J
api/albums/update (R),J
api/albums/permissions (R),J
api/albums/permissions/update (R),J
api/albums/destroy (R),J
api/friends/permissions (R),J
#include doc/macros/main_footer.bb;

View File

@ -23,7 +23,7 @@ If you get a blank white screen when doing something, this is almost always a co
At this point it might be worthwhile discussing the issue on one of the online forums. There may be several of these and some may be more suited to your spoken language. At this time, the 'Hubzilla Support' channel (support@gravizot.de) is the recommended forum for discussing bugs.
If community members with software engineering training/expertise can't help you right away, understand that they are volunteers and may have a lot of other work and demands on their time. At this point you need to file a bug report. You will need an account on github.com to do this. So register, and then visit https://github.com/redmatrix/hubzilla/issues . Create an issue here and provide all the same information that you provided online. Don't leave out anything.
If community members with software engineering training/expertise can't help you right away, understand that they are volunteers and may have a lot of other work and demands on their time. At this point you need to file a bug report. You will need an account on github.com to do this. So register, and then visit https://framagit.org/hubzilla/core/issues . Create an issue here and provide all the same information that you provided online. Don't leave out anything.
Then you wait. If it's a high profile issue, it may get fixed quickly. But nobody is in charge of fixing bugs. If it lingers without resolution, please spend some more time investigating the problem. Ask about anything you don't understand related to the behaviour. You will learn more about how the software works and quite possibly figure out why it isn't working now. Ultimately it is somebody in the community who is going to fix this and you are a member of the community; and this is how the open source process works.

View File

@ -5,9 +5,9 @@
[h3]Recursos Externs[/h3]
[zrl=[baseurl]/help/external-resource-links]Enllaços a Recursos Externs[/zrl]
[url=https://github.com/redmatrix/hubzilla]Lloc Web Principal[/url]
[url=https://framagit.org/hubzilla/core/]Lloc Web Principal[/url]
[url=https://github.com/redmatrix/hubzilla-addons]Complements del Lloc Web[/url]
[url=https://framagit.org/hubzilla/addons]Complements del Lloc Web[/url]
[url=[baseurl]/help/credits]Credits en $Projectname[/url]

View File

@ -1,37 +1,37 @@
[b]Profiles[/b]
$Projectname has unlimited profiles. You may use different profiles to show different &quot;sides of yourself&quot; to different audiences. This is different to having different channels. Different channels allow for completely different sets of information. You may have a channel for yourself, a channel for your sports team, a channel for your website, or whatever else. A profile allows for finely graded &quot;sides&quot; of each channel. For example, your default public profile might say &quot;Hello, I'm Fred, and I like laughing&quot;. You may show your close friends a profile that adds &quot;and I also enjoy dwarf tossing&quot;.
You always have a profile known as your &quot;default&quot; or &quot;public&quot; profile. This profile is always available to the general public and cannot be hidden (there may be rare exceptions on privately run or disconnected sites). You may, and probably should restrict the information you make available on your public profile.
That said, if you want other friends to be able to find you, it helps to have the following information in your public profile...
[ul][*]Your real name or at least a nickname everybody knows
[*]A photo of you
[*]Your location on the planet, at least to a country level.[/ul]
In addition, if you'd like to meet people that share some general interests with you, please take a moment and add some &quot;Keywords&quot; to your profile. Such as &quot;music, linux, photography&quot; or whatever. You can add as many keywords as you like.
To create an alternate profile, first go to [zrl=[baseurl]/settings/features]Settings &gt; Additional Features[/zrl] and enable &quot;Multiple Profiles&quot; there, otherwise you won't have the ability to use more than just your default profile.
Then select &quot;Edit Profiles&quot; from the menu of your $Projectname site. You may edit an existing profile, change the profile photo, add things to a profile or create a new profile. You may also create a &quot;clone&quot; of an existing profile if you only wish to change a few items but don't wish to enter all the information again. To do that, click on the profile you want to clone and choose &quot;Clone this profile&quot; there.
In the list of your profiles, you can also choose the contacts who can see a specific profile. Just click on &quot;Edit visibility&quot; next to the profile in question (only available for the profiles that are not your default profile) and then click on user images to add them to or remove them from the group of people who can see this profile.
Once a profile has been selected, when the person views your profile, they will see the private profile you have assigned. If they are not authenticated, they will see your public profile.
There is a setting which allows you to publish your profile to a directory and ensure that it can be found by others. You can change this setting on the &quot;Settings&quot; page.
If you do not wish to be found be people unless you give them your channel address, you may leave your profile unpublished.
[b]Keywords and Directory Search[/b]
On the directory page, you may search for people with published profiles. Currently, only the name field and the keywords are searched. You may also include such keywords in your default profile - which may be used to search for common interests with other members. Keywords are used in the channel suggestion tool and although they aren't visible in the directory, they are shown if people visit your profile page.
On your Connnections page and in the directory there is a link to &quot;Suggestions&quot; or &quot;Channel Suggestions&quot;, respectively. This will find channels who have matching and/or similar keywords. The more keywords you provide, the more relevant the search results that are returned. These are sorted by relevance.
See Also
[zrl=[baseurl]/help/AdvancedSearch]Advanced Searching[/zrl]
#include doc/macros/main_footer.bb;
[b]Profiles[/b]
$Projectname has unlimited profiles. You may use different profiles to show different &quot;sides of yourself&quot; to different audiences. This is different to having different channels. Different channels allow for completely different sets of information. You may have a channel for yourself, a channel for your sports team, a channel for your website, or whatever else. A profile allows for finely graded &quot;sides&quot; of each channel. For example, your default public profile might say &quot;Hello, I'm Fred, and I like laughing&quot;. You may show your close friends a profile that adds &quot;and I also enjoy dwarf tossing&quot;.
You always have a profile known as your &quot;default&quot; or &quot;public&quot; profile. This profile is always available to the general public and cannot be hidden (there may be rare exceptions on privately run or disconnected sites). You may, and probably should restrict the information you make available on your public profile.
That said, if you want other friends to be able to find you, it helps to have the following information in your public profile...
[ul][*]Your real name or at least a nickname everybody knows
[*]A photo of you
[*]Your location on the planet, at least to a country level.[/ul]
In addition, if you'd like to meet people that share some general interests with you, please take a moment and add some &quot;Keywords&quot; to your profile. Such as &quot;music, linux, photography&quot; or whatever. You can add as many keywords as you like.
To create an alternate profile, first go to [zrl=[baseurl]/settings/features]Settings &gt; Additional Features[/zrl] and enable &quot;Multiple Profiles&quot; there, otherwise you won't have the ability to use more than just your default profile.
Then select &quot;Edit Profiles&quot; from the menu of your $Projectname site. You may edit an existing profile, change the profile photo, add things to a profile or create a new profile. You may also create a &quot;clone&quot; of an existing profile if you only wish to change a few items but don't wish to enter all the information again. To do that, click on the profile you want to clone and choose &quot;Clone this profile&quot; there.
In the list of your profiles, you can also choose the contacts who can see a specific profile. Just click on &quot;Edit visibility&quot; next to the profile in question (only available for the profiles that are not your default profile) and then click on user images to add them to or remove them from the group of people who can see this profile.
Once a profile has been selected, when the person views your profile, they will see the private profile you have assigned. If they are not authenticated, they will see your public profile.
There is a setting which allows you to publish your profile to a directory and ensure that it can be found by others. You can change this setting on the &quot;Settings&quot; page.
If you do not wish to be found be people unless you give them your channel address, you may leave your profile unpublished.
[b]Keywords and Directory Search[/b]
On the directory page, you may search for people with published profiles. Currently, only the name field and the keywords are searched. You may also include such keywords in your default profile - which may be used to search for common interests with other members. Keywords are used in the channel suggestion tool and although they aren't visible in the directory, they are shown if people visit your profile page.
On your Connnections page and in the directory there is a link to &quot;Suggestions&quot; or &quot;Channel Suggestions&quot;, respectively. This will find channels who have matching and/or similar keywords. The more keywords you provide, the more relevant the search results that are returned. These are sorted by relevance.
See Also
[zrl=[baseurl]/help/AdvancedSearch]Advanced Searching[/zrl]
#include doc/macros/main_footer.bb;

View File

@ -55,7 +55,7 @@ Per més detalla, informació tècnica sobre Zot, clica sobre algún dels següe
- [url=https://github.com/friendica/red/wiki/zot]Especificació pel desenvolupament de Zot (en anglès)[/url]
- [url=https://github.com/redmatrix/hubzilla/blob/master/include/zot.php]Referència per la implementació de Zot en PHP (en anglès)[/url]
- [url=https://framagit.org/hubzilla/core/blob/master/include/zot.php]Referència per la implementació de Zot en PHP (en anglès)[/url]
#include doc/macros/main_footer.bb;

View File

@ -1,237 +1,237 @@
[b]Initial Indiegg pitch[/b]
[b][color= grey][size=20]What have we done, and what we hope to achieve[/size][/color][/b]
[b][color= grey][size=18]Single-click sign on, nomadic identity, censorship-resistance, privacy, self-hosting[/size][/color][/b]
We started $Projectname project by asking ourselves a few questions:
- Imagine if it was possible to just access the content of different web sites, without the need to enter usernames and passwords for every site. Such a feature would permit Single-Click user identification: the ability to access sites simply by clicking on links to remote sites.
Authentication just happens automagically behind the scenes. Forget about remembering multiple user names with multiple passwords when accessing different sites online.
We liked this idea and went ahead with coding it immediately. Today, single-click sign is in alpha state. It needs more love, which means a solid three months of full-time development efforts.
- Think of your Facebook, Twitter, WordPress, or any other website where you currently have an account. Now imagine being able to clone your account, to make an exact duplicate of it (with all of your friends, posts and settings), then export your cloned account into another server that is part of this communication network. After you're done, both of your accounts are synced from the time they were cloned. It doesn't matter where you log in (at your original location, or where you imported your clone). You see the same content, the same friends, posts, and account settings.
At that point, it is more appropriate to call your account an identity that is nomadic (it is not tied to one home, unless you choose to do so!).
It's 2013, our online presence no longer has to be tied to a single server, domain name or IP address. We should be able to clone and import our identities to other servers. In such a network, it should only matter who you are, not where you are.
We're very intrigued by the possibilities nomadic identities open up for freedom, censorship-resistance, and identity resilience. Consider the following scenarios:
-- Should a repressive government or corporation decide to delete your account, your cloned identity lives on, because it is located on another server, across the world, which is part of the same communication network. You can't be silenced!
-- What if there is a server meltdown, and your identity goes off line. No problem, you log into your clone and all is good.
-- Your server administrator can no longer afford to keep paying to support a free service (a labor love and principle, which all of us have participating in as system administrators of Friendica sites!). She notifies you that you must clone your account before the shutoff date. Rather than loose all your friends, and start from scratch by creating a new identity somewhere, you clone and move to another server.
We feel this is especially helpful for the free web, where administrators of FOSS community sites are often faced with difficult financial decisions. Since many of them rely on donations, sometimes servers have to be taken offline, when costs become prohibitive for the brave DIY souls running those server. Nomadic identities should relieve some of the pressures associated with such situations.
At the same time, we are also thinking of solutions that would make it possible for people running Red hubs to be financially sustainable. To that end, we're starting to implement service classes in our code, which would allow administrators to structure paid levels of service, if they choose to do so.
Today, nomadic identity is currently in alpha state. It also needs more love, which means a solid three months of full-time development efforts.
- Imagine a social network that is censorship-resistant, and privacy-respecting by design. It is not controlled by one mega-corporation, and where users cannot be easily censored by oppressive governments. So, in addition to nomadic identities, we are talking about decentralization, open source, freely software, that can run on any hardware that supports a database and a modern web browser. And we mean &quot;any hardware&quot;, from a self-hosted $35 Raspberry Pi, to the very latest Intel Xeon and AMD Bulldozer-powered server behemoths.
We've realized that privacy requires full control over content. We should be able to delete, backup and download all of our content, as well as associated account/identity information. To this end, we have already implemented the initial version of account export and backup.
Concerned about pages and pages of posts from months and years past? The solution should be simple: visit your settings page, specify that all content older than 7 days, with the exception of starred posts, should be automatically deleted. Done, the clutter is gone! (Consider also the privacy and anti-mass surveillance implications of this feature. PRISM disclosures have hinted that three-letter spying agencies around the world are recording all internet traffic and storing it for a few days at a time. We feel that automatic post expiration becomes a rather useful feature in this context, and implementing it is one of our near future priorities.)
[b][color= grey][size=18]The Affinity Slider and Access Control Lists[/size][/color][/b]
- What if the permissions and access control lists that help secure modern operating systems were extended into a communication network that lived on the internet? This means somebody could log into this network from their home site, and with the simple click of a few buttons dynamically sort who can have access to their online content on a very fine level: from restricting others from seeing your latest blog post, to sharing your bookmarks with the world.
We've coded the initial version of such a new feature. It is called the &quot;Affinity Slider&quot;, and in our very-alpha user interface it looks like this.
[img]https://friendicared.net/photo/b07b0262e3146325508b81a9d1ae4a1e-0.png[/img]
{INSERT SCREENSHOT OF A MATRIX PAGE}
Think of it as an easy way to filter content that you see, based on the degree of &quot;closeness&quot; to you. Move the slider to Friends, and only content coming from contacts you've tagged as friends is displayed on your home page. Uncluttering thousands of contacts, friends, RSS feeds, and other content should be a basic feature of modern communication on the web, but not at the expense of ease of use.
In addition to the Affinity Slider, we also have the ACL (Access Control List). Say you want to share something with only 5 of your contacts (a blog, two friends from college, and two forums). You click on the padlock, choose the recipients, and that's it. Only those identities will recieve their posts. Furthermore, the post will be encrypted via PKI (pulic key encryption) to help maintain privacy. In the age of PRISM, we don't know all the details on what's safe out there, but we still think that privacy by design should be automatically present, invisible to the user, and easy to use.
Attaching permissions to any data that lives on this network, potentially solves a great many headaches, while achieving simplicity in communication.
Think of it this way: the internet is nothing, but a bunch of permissions and a folder of data. You, the user controls the permissions and thus the data that is relevant to you.
[b][color= grey][size=20]The Matrix is Born![/size][/color][/b]
After asking and striving to answer a number of such questions, we realized that we were imagining a general purpose communication network with a number of unique, and potentially game-changing, features. We called it $Projectname and started thinking of it as an over-lay on top of the internet as it exists today; an operating system re-invented as a communication network, with its own permissions, access control lists, protocol, connectors to others services, and open-ended possibilities via its API. The sum of the matrix is greater than it's parts. We're not building website, but a way for websites to link together and grow into something that is unique and ever-changing, with autonomy and privacy.
It's a lot of work, for anyone. So far, we've got a team of a handful of volunteers, code geeks, brave early adopters, system administrators and other good people, willing to give the project a shot. We're motivated by our commitment to a free web, where privacy is built-in, and corporations don't have a stranglehold on our daily communication.
We need your help to finish it and release it to the world!
[b][color= grey][size=20]What have we written so far[/size][/color][/b]
As of the today, $Projectname is in developer preview (alpha) state. It is not ready for everyday use, but some of the initial set of core features are implemented (again, in alpha state). These include:
- Zot, the protocol powering the matrix
- Single-signon logins.
- Nomadic identities
- Basic content manipulation: creation, deletion, rudimentary handling of photos, and media files
- A bare-bones outline of the API and user documentation.
[b][color= grey][size=20]Our TO-DO List[/size][/color][/b]
However, in addition to finishing and polishing the above, there are a number of features that have to implemented to make $Projectname ready for daily use. If we meet our fundraising goal, we hope to dive into the following road map, by order of priority:
- A professionally designed user interface (UI), interface that is adaptive to any user level, from end users who want to use the Matrix as a social network, to tinkerers who will put together a customized blog using Comanche, to hackers who will develop and extend the matrix using a built-in code editor, that hooks to the API and the git.
- Comanche, our new markup language, similar to BBCode, with which to create elaborate and complex web pages by assembling them from a series of components - some of which are pre-built and others which can be defined on the fly. You can read more about it on our github wiki: https://github.com/friendica/red/wiki/Comanche
- A unique help system that lives in the matrix, but is not based on the principles of a search engine. We have some interesting ideas about decentralizing help documentation, without going down the road of distributed search engines. Here's a hint: We shouldn't be searching at all, we should just be filtering what's already there in new, and cunning ways.
- An appropriate logo, along with professionally done documentation system, both for our API, as well as users.
- WordPress-like single button software upgrades
- A built-in development environment, using an integrated web-based code editor such as Ace9
[b][color= grey][size=20]What will the money be used for[/size][/color][/b]
If we raise our targeted amount of funds, we plan to use it as follows:
1) Fund 6 months {OR WHATEVER} of full time work for our current core developers, Mike, Thomas, and Tobias {ANYONE ELSE?]
2) Pay a professional web developer to design an kick ass reference theme, along with a project logo.
3) {WHAT ELSE?}
[b][color= grey][size=20]Deadlines[/size][/color][/b]
[b]March, 2014: $Projectname Beta with the following features[/b]
- {LIST FEATURES}
[b][color= grey][size=20]Who We Are[/size][/color][/b]
Mike: {FILL IN BIO, reference Friendica, etc.}
Thomas: {bio blurb}
Tobias: {bio blurb}
Arto: {documentation, etc.}
{WHO ELSE? WE NEED A TEAM, AT LEAST 3-4 PEOPLE}
[b][color= grey][size=20]What Do I Get as a Supporter?[/size][/color][/b]
Our ability to reach 1.0 stable release depends on your generosity and support. We appreciate your help, regardless of the amount! Here's what we're thinking as far as different contribution levels go:
[b]$1: {CATCHY TAGLINE}[/b]
We'll list your name on our initial supporters list, a Hall of Fame of the matrix!
[b]$5:[/b]
[b]$10: [/b]
[b]$16: [/b]
You get one of your $Projectname t-shirts, as well as our undying gratitude.
[b]$32: [/b]
[b]$64 [/b]
[b]128 [/b]
[b]$256: [/b]
[b]$512: [/b]
[b]$1024 [/b]
[b]$2048[/b]
Each contributor at this level gets their own $Projectname virtual private server, installed, hosted and supported by us for a period of 1 year.
[b][color= grey][size=20]Why are we so excited about $Projectname?[/size][/color][/b]
{SOMETHING ABOUT THE POTENTIAL IMPACT OF RED, ITS INNOVATIONS, ETC&gt;
[b][color= grey][size=20]Other Ways to Help[/size][/color][/b]
We're a handful of volunteers, and we understand that not everyone can contribute by donating money. There are many other ways you can in getting the Matrix to version 1.0!
First, you can checkout our source code on github: https://github.com/redmatrix/hubzilla
Maybe you can dive in and help us out with some development.
Second, you can install the current developer preview on a server and start compiling bug reports.
Third, register at one of the public alpha Red hubs, and get a feel for what Red is trying to do!
Perhaps you're good at writing and documenting stuff. Grab an account at one of the public alphas and give us a hand.
[b][color= grey][size=20]Frequently Asked Questions[/size][/color][/b]
[b]1. Is Red a social network?[/b]
$Projectname is not a social network. We're thinking of it as a general purpose communication network, with sharing, and public/private communications built into the matrix.
[b]2. What is the difference between Red and Friendica?[/b]
What's the difference between a passport, and a postcard?
Friendica is really, really good at sending postcards. It can do all sorts of things with postcards. It can send them to your friends. It can send them to people you don't know. It can put them in an envelope and send them privately. It can run them through a photocopier and plaster them all over the internet. It can even take postcards in one language and convert them to many others so your friends who speak a different language can read them.
What Friendica can't do, is wave a postcard at somebody and expect them to believe that holding this postcard prove you are who you say you are. Sure, if you've been sending somebody postcards, they might accept that it is you in the picture, but somebody who has never heard of you will not accept ownership of a postcard as proof of identity.
$Projectname offers a passport.
You can still use it to send postcards. At the same time, when you wave your passport at somebody, they do accept it as proof of identity. No longer do you need to register at every single site you use. You already have an account - it's just not necessarily at our site - so we'll ask to see your passport instead.
Once you've proven your identity, a Red hub lets you use our services, as though you'd registered with directly, and we'd verified your credentials as would have happened in the olden days. These resources can, of course, be anything at all.
[b]2. Why did you choose PHP, instead of Ruby or Python?[/b]
The reference implementation is in PHP. We chose PHP, because it is available everywhere, and is easily configurable. We understand the debates between proponents and opponents of PHP, Ruby and Python. Nothing prevents implementations of Zot and the matrix in those languages. In fact, people on the matrix have already started developing a version of Red in Python [SOURCE?], and there is talk about future implementations in C (aiming for blazing native performance) and Java. It's free and open source, so we feel it's only a matter of time, once Red is initially completed.
[b]4. Other than PHP, what other technology does Red use?[/b]
We use MySQL as our database (this include any forks such as, MariaDB or Percona), and any modern webserver (Apache, nginx, etc.).
[b]5. How is the Affinity Slider different from Mozilla's Persona?[/b]
{COMPLETE}
[b]6. Does $Projectname use encryption? Details please![/b]
Yes, we do our best to use free and open source encryption libraries to help achieve privacy from general, mass surveillance.
Communication between web browsers and Red hubs is encrypted using SSL certificates.
Private communication on the matrix is protected by AES symmetric encryption, which is itself protected by RSA PKI (public key encryption). By default, we use AES-256-CBC, and our RSA keys are set to 4096-bits.
For more info on our initial implementation of encrypted communication, check out our source code at Github: https://github.com/friendica/red/blob/master/include/crypto.php
[b]7. What do you mean by decentralization? [/b]
[b]8. Can I build my own website with in $Projectname?[/b]
Yes. The short explanation: We've got this spiffy idea we're calling &quot;Comanche&quot;, which will allow non-programmers to build complete custom websites, and any such website will be able to connect to any other website or channel in the matrix. The goal of Comanche is to hide the technical complexities of communicating in the matrix, while encouraging people to use their creativity and put together their own unique presence on the matrix.
The longer explanation: Comanche is a markup language, similar to bbcode, with which to create elaborate and complex web pages by assembling them from a series of components - some of which are pre-built and others which can be defined on the fly. Comanche uses a Page Description Language file (&quot;.pdl&quot;, pronounced &quot;puddle&quot;) to create these pages. Bbcode is not a requirement; an XML PDL file could also be used. The tag delimiters would be different. Usage is the same.
Additional information is available on our Github project wiki: https://github.com/friendica/red/wiki/Comanche
Comanche is another one of our priorities for the next six months.
[b]9. Where can I see some technical description of Zot?[/b]
Our github wiki contains a number of high-level and technical descriptions of Zot, Comanche, and Red in general: https://github.com/friendica/red/wiki
[b]10. What happens if you raise more than {TARGETED NUMBER}?[/b]
Raising more than our initial goal of funds, will speed up our development efforts. More developers will be able to take time off from other jobs, and concentrate efforts on finishing Red.
[b]11 Can I make a contribution via Bitcoin?[/b]
{YES/NO}
[b]12. I have additional Questions[/]
Awesome. We'd be more than happy to chat. You can find us {HERE}
#include doc/macros/main_footer.bb;
[b]Initial Indiegg pitch[/b]
[b][color= grey][size=20]What have we done, and what we hope to achieve[/size][/color][/b]
[b][color= grey][size=18]Single-click sign on, nomadic identity, censorship-resistance, privacy, self-hosting[/size][/color][/b]
We started $Projectname project by asking ourselves a few questions:
- Imagine if it was possible to just access the content of different web sites, without the need to enter usernames and passwords for every site. Such a feature would permit Single-Click user identification: the ability to access sites simply by clicking on links to remote sites.
Authentication just happens automagically behind the scenes. Forget about remembering multiple user names with multiple passwords when accessing different sites online.
We liked this idea and went ahead with coding it immediately. Today, single-click sign is in alpha state. It needs more love, which means a solid three months of full-time development efforts.
- Think of your Facebook, Twitter, WordPress, or any other website where you currently have an account. Now imagine being able to clone your account, to make an exact duplicate of it (with all of your friends, posts and settings), then export your cloned account into another server that is part of this communication network. After you're done, both of your accounts are synced from the time they were cloned. It doesn't matter where you log in (at your original location, or where you imported your clone). You see the same content, the same friends, posts, and account settings.
At that point, it is more appropriate to call your account an identity that is nomadic (it is not tied to one home, unless you choose to do so!).
It's 2013, our online presence no longer has to be tied to a single server, domain name or IP address. We should be able to clone and import our identities to other servers. In such a network, it should only matter who you are, not where you are.
We're very intrigued by the possibilities nomadic identities open up for freedom, censorship-resistance, and identity resilience. Consider the following scenarios:
-- Should a repressive government or corporation decide to delete your account, your cloned identity lives on, because it is located on another server, across the world, which is part of the same communication network. You can't be silenced!
-- What if there is a server meltdown, and your identity goes off line. No problem, you log into your clone and all is good.
-- Your server administrator can no longer afford to keep paying to support a free service (a labor love and principle, which all of us have participating in as system administrators of Friendica sites!). She notifies you that you must clone your account before the shutoff date. Rather than loose all your friends, and start from scratch by creating a new identity somewhere, you clone and move to another server.
We feel this is especially helpful for the free web, where administrators of FOSS community sites are often faced with difficult financial decisions. Since many of them rely on donations, sometimes servers have to be taken offline, when costs become prohibitive for the brave DIY souls running those server. Nomadic identities should relieve some of the pressures associated with such situations.
At the same time, we are also thinking of solutions that would make it possible for people running Red hubs to be financially sustainable. To that end, we're starting to implement service classes in our code, which would allow administrators to structure paid levels of service, if they choose to do so.
Today, nomadic identity is currently in alpha state. It also needs more love, which means a solid three months of full-time development efforts.
- Imagine a social network that is censorship-resistant, and privacy-respecting by design. It is not controlled by one mega-corporation, and where users cannot be easily censored by oppressive governments. So, in addition to nomadic identities, we are talking about decentralization, open source, freely software, that can run on any hardware that supports a database and a modern web browser. And we mean &quot;any hardware&quot;, from a self-hosted $35 Raspberry Pi, to the very latest Intel Xeon and AMD Bulldozer-powered server behemoths.
We've realized that privacy requires full control over content. We should be able to delete, backup and download all of our content, as well as associated account/identity information. To this end, we have already implemented the initial version of account export and backup.
Concerned about pages and pages of posts from months and years past? The solution should be simple: visit your settings page, specify that all content older than 7 days, with the exception of starred posts, should be automatically deleted. Done, the clutter is gone! (Consider also the privacy and anti-mass surveillance implications of this feature. PRISM disclosures have hinted that three-letter spying agencies around the world are recording all internet traffic and storing it for a few days at a time. We feel that automatic post expiration becomes a rather useful feature in this context, and implementing it is one of our near future priorities.)
[b][color= grey][size=18]The Affinity Slider and Access Control Lists[/size][/color][/b]
- What if the permissions and access control lists that help secure modern operating systems were extended into a communication network that lived on the internet? This means somebody could log into this network from their home site, and with the simple click of a few buttons dynamically sort who can have access to their online content on a very fine level: from restricting others from seeing your latest blog post, to sharing your bookmarks with the world.
We've coded the initial version of such a new feature. It is called the &quot;Affinity Slider&quot;, and in our very-alpha user interface it looks like this.
[img]https://friendicared.net/photo/b07b0262e3146325508b81a9d1ae4a1e-0.png[/img]
{INSERT SCREENSHOT OF A MATRIX PAGE}
Think of it as an easy way to filter content that you see, based on the degree of &quot;closeness&quot; to you. Move the slider to Friends, and only content coming from contacts you've tagged as friends is displayed on your home page. Uncluttering thousands of contacts, friends, RSS feeds, and other content should be a basic feature of modern communication on the web, but not at the expense of ease of use.
In addition to the Affinity Slider, we also have the ACL (Access Control List). Say you want to share something with only 5 of your contacts (a blog, two friends from college, and two forums). You click on the padlock, choose the recipients, and that's it. Only those identities will recieve their posts. Furthermore, the post will be encrypted via PKI (pulic key encryption) to help maintain privacy. In the age of PRISM, we don't know all the details on what's safe out there, but we still think that privacy by design should be automatically present, invisible to the user, and easy to use.
Attaching permissions to any data that lives on this network, potentially solves a great many headaches, while achieving simplicity in communication.
Think of it this way: the internet is nothing, but a bunch of permissions and a folder of data. You, the user controls the permissions and thus the data that is relevant to you.
[b][color= grey][size=20]The Matrix is Born![/size][/color][/b]
After asking and striving to answer a number of such questions, we realized that we were imagining a general purpose communication network with a number of unique, and potentially game-changing, features. We called it $Projectname and started thinking of it as an over-lay on top of the internet as it exists today; an operating system re-invented as a communication network, with its own permissions, access control lists, protocol, connectors to others services, and open-ended possibilities via its API. The sum of the matrix is greater than it's parts. We're not building website, but a way for websites to link together and grow into something that is unique and ever-changing, with autonomy and privacy.
It's a lot of work, for anyone. So far, we've got a team of a handful of volunteers, code geeks, brave early adopters, system administrators and other good people, willing to give the project a shot. We're motivated by our commitment to a free web, where privacy is built-in, and corporations don't have a stranglehold on our daily communication.
We need your help to finish it and release it to the world!
[b][color= grey][size=20]What have we written so far[/size][/color][/b]
As of the today, $Projectname is in developer preview (alpha) state. It is not ready for everyday use, but some of the initial set of core features are implemented (again, in alpha state). These include:
- Zot, the protocol powering the matrix
- Single-signon logins.
- Nomadic identities
- Basic content manipulation: creation, deletion, rudimentary handling of photos, and media files
- A bare-bones outline of the API and user documentation.
[b][color= grey][size=20]Our TO-DO List[/size][/color][/b]
However, in addition to finishing and polishing the above, there are a number of features that have to implemented to make $Projectname ready for daily use. If we meet our fundraising goal, we hope to dive into the following road map, by order of priority:
- A professionally designed user interface (UI), interface that is adaptive to any user level, from end users who want to use the Matrix as a social network, to tinkerers who will put together a customized blog using Comanche, to hackers who will develop and extend the matrix using a built-in code editor, that hooks to the API and the git.
- Comanche, our new markup language, similar to BBCode, with which to create elaborate and complex web pages by assembling them from a series of components - some of which are pre-built and others which can be defined on the fly. You can read more about it on our github wiki: https://github.com/friendica/red/wiki/Comanche
- A unique help system that lives in the matrix, but is not based on the principles of a search engine. We have some interesting ideas about decentralizing help documentation, without going down the road of distributed search engines. Here's a hint: We shouldn't be searching at all, we should just be filtering what's already there in new, and cunning ways.
- An appropriate logo, along with professionally done documentation system, both for our API, as well as users.
- WordPress-like single button software upgrades
- A built-in development environment, using an integrated web-based code editor such as Ace9
[b][color= grey][size=20]What will the money be used for[/size][/color][/b]
If we raise our targeted amount of funds, we plan to use it as follows:
1) Fund 6 months {OR WHATEVER} of full time work for our current core developers, Mike, Thomas, and Tobias {ANYONE ELSE?]
2) Pay a professional web developer to design an kick ass reference theme, along with a project logo.
3) {WHAT ELSE?}
[b][color= grey][size=20]Deadlines[/size][/color][/b]
[b]March, 2014: $Projectname Beta with the following features[/b]
- {LIST FEATURES}
[b][color= grey][size=20]Who We Are[/size][/color][/b]
Mike: {FILL IN BIO, reference Friendica, etc.}
Thomas: {bio blurb}
Tobias: {bio blurb}
Arto: {documentation, etc.}
{WHO ELSE? WE NEED A TEAM, AT LEAST 3-4 PEOPLE}
[b][color= grey][size=20]What Do I Get as a Supporter?[/size][/color][/b]
Our ability to reach 1.0 stable release depends on your generosity and support. We appreciate your help, regardless of the amount! Here's what we're thinking as far as different contribution levels go:
[b]$1: {CATCHY TAGLINE}[/b]
We'll list your name on our initial supporters list, a Hall of Fame of the matrix!
[b]$5:[/b]
[b]$10: [/b]
[b]$16: [/b]
You get one of your $Projectname t-shirts, as well as our undying gratitude.
[b]$32: [/b]
[b]$64 [/b]
[b]128 [/b]
[b]$256: [/b]
[b]$512: [/b]
[b]$1024 [/b]
[b]$2048[/b]
Each contributor at this level gets their own $Projectname virtual private server, installed, hosted and supported by us for a period of 1 year.
[b][color= grey][size=20]Why are we so excited about $Projectname?[/size][/color][/b]
{SOMETHING ABOUT THE POTENTIAL IMPACT OF RED, ITS INNOVATIONS, ETC&gt;
[b][color= grey][size=20]Other Ways to Help[/size][/color][/b]
We're a handful of volunteers, and we understand that not everyone can contribute by donating money. There are many other ways you can in getting the Matrix to version 1.0!
First, you can checkout our source code on github: https://framagit.org/hubzilla/core/
Maybe you can dive in and help us out with some development.
Second, you can install the current developer preview on a server and start compiling bug reports.
Third, register at one of the public alpha Red hubs, and get a feel for what Red is trying to do!
Perhaps you're good at writing and documenting stuff. Grab an account at one of the public alphas and give us a hand.
[b][color= grey][size=20]Frequently Asked Questions[/size][/color][/b]
[b]1. Is Red a social network?[/b]
$Projectname is not a social network. We're thinking of it as a general purpose communication network, with sharing, and public/private communications built into the matrix.
[b]2. What is the difference between Red and Friendica?[/b]
What's the difference between a passport, and a postcard?
Friendica is really, really good at sending postcards. It can do all sorts of things with postcards. It can send them to your friends. It can send them to people you don't know. It can put them in an envelope and send them privately. It can run them through a photocopier and plaster them all over the internet. It can even take postcards in one language and convert them to many others so your friends who speak a different language can read them.
What Friendica can't do, is wave a postcard at somebody and expect them to believe that holding this postcard prove you are who you say you are. Sure, if you've been sending somebody postcards, they might accept that it is you in the picture, but somebody who has never heard of you will not accept ownership of a postcard as proof of identity.
$Projectname offers a passport.
You can still use it to send postcards. At the same time, when you wave your passport at somebody, they do accept it as proof of identity. No longer do you need to register at every single site you use. You already have an account - it's just not necessarily at our site - so we'll ask to see your passport instead.
Once you've proven your identity, a Red hub lets you use our services, as though you'd registered with directly, and we'd verified your credentials as would have happened in the olden days. These resources can, of course, be anything at all.
[b]2. Why did you choose PHP, instead of Ruby or Python?[/b]
The reference implementation is in PHP. We chose PHP, because it is available everywhere, and is easily configurable. We understand the debates between proponents and opponents of PHP, Ruby and Python. Nothing prevents implementations of Zot and the matrix in those languages. In fact, people on the matrix have already started developing a version of Red in Python [SOURCE?], and there is talk about future implementations in C (aiming for blazing native performance) and Java. It's free and open source, so we feel it's only a matter of time, once Red is initially completed.
[b]4. Other than PHP, what other technology does Red use?[/b]
We use MySQL as our database (this include any forks such as, MariaDB or Percona), and any modern webserver (Apache, nginx, etc.).
[b]5. How is the Affinity Slider different from Mozilla's Persona?[/b]
{COMPLETE}
[b]6. Does $Projectname use encryption? Details please![/b]
Yes, we do our best to use free and open source encryption libraries to help achieve privacy from general, mass surveillance.
Communication between web browsers and Red hubs is encrypted using SSL certificates.
Private communication on the matrix is protected by AES symmetric encryption, which is itself protected by RSA PKI (public key encryption). By default, we use AES-256-CBC, and our RSA keys are set to 4096-bits.
For more info on our initial implementation of encrypted communication, check out our source code at Github: https://github.com/friendica/red/blob/master/include/crypto.php
[b]7. What do you mean by decentralization? [/b]
[b]8. Can I build my own website with in $Projectname?[/b]
Yes. The short explanation: We've got this spiffy idea we're calling &quot;Comanche&quot;, which will allow non-programmers to build complete custom websites, and any such website will be able to connect to any other website or channel in the matrix. The goal of Comanche is to hide the technical complexities of communicating in the matrix, while encouraging people to use their creativity and put together their own unique presence on the matrix.
The longer explanation: Comanche is a markup language, similar to bbcode, with which to create elaborate and complex web pages by assembling them from a series of components - some of which are pre-built and others which can be defined on the fly. Comanche uses a Page Description Language file (&quot;.pdl&quot;, pronounced &quot;puddle&quot;) to create these pages. Bbcode is not a requirement; an XML PDL file could also be used. The tag delimiters would be different. Usage is the same.
Additional information is available on our Github project wiki: https://github.com/friendica/red/wiki/Comanche
Comanche is another one of our priorities for the next six months.
[b]9. Where can I see some technical description of Zot?[/b]
Our github wiki contains a number of high-level and technical descriptions of Zot, Comanche, and Red in general: https://github.com/friendica/red/wiki
[b]10. What happens if you raise more than {TARGETED NUMBER}?[/b]
Raising more than our initial goal of funds, will speed up our development efforts. More developers will be able to take time off from other jobs, and concentrate efforts on finishing Red.
[b]11 Can I make a contribution via Bitcoin?[/b]
{YES/NO}
[b]12. I have additional Questions[/]
Awesome. We'd be more than happy to chat. You can find us {HERE}
#include doc/macros/main_footer.bb;

View File

@ -1,20 +1,20 @@
[b]Checking your account quota usage (service limits usage)[/b]
Your hub might implement service class limits, assigning limits to the total size of file, photo, channels, top-level posts, etc., that can be created by an account holder for a specific service level.
Here's how you can quickly check how much of your assigned quota you're currently using:
[b]Check file storage quota levels[/b]
Visit the following URL in your browser:
[observer=1][observer.baseurl]/filestorage/[observer.webname][/observer]
[observer=0]example.com/filestorage/username[/observer]
[b]Check uploaded photos storage quota levels[/b]
[observer=1][observer.baseurl]/photos/[observer.webname][/observer]
[observer=0]example.com/photos/username[/observer]
Example:
[observer=1][observer.baseurl]/filestorage/[observer.webname][/observer]
[observer=0]example.com/filestorage/username[/observer]
#include doc/macros/main_footer.bb;
[b]Checking your account quota usage (service limits usage)[/b]
Your hub might implement service class limits, assigning limits to the total size of file, photo, channels, top-level posts, etc., that can be created by an account holder for a specific service level.
Here's how you can quickly check how much of your assigned quota you're currently using:
[b]Check file storage quota levels[/b]
Visit the following URL in your browser:
[observer=1][observer.baseurl]/filestorage/[observer.webname][/observer]
[observer=0]example.com/filestorage/username[/observer]
[b]Check uploaded photos storage quota levels[/b]
[observer=1][observer.baseurl]/photos/[observer.webname][/observer]
[observer=0]example.com/photos/username[/observer]
Example:
[observer=1][observer.baseurl]/filestorage/[observer.webname][/observer]
[observer=0]example.com/filestorage/username[/observer]
#include doc/macros/main_footer.bb;

View File

@ -1,261 +1,261 @@
[b]Comanche Page Description Language[/b]
Comanche is a markup language similar to bbcode with which to create elaborate and complex web pages by assembling them from a series of components - some of which are pre-built and others which can be defined on the fly. Comanche uses a Page Decription Language to create these pages.
Comanche primarily chooses what content will appear in various regions of the page. The various regions have names and these names can change depending on what layout template you choose.
[b]Page Templates[/b]
Currently there are five layout templates, unless your site provides additional layouts.
[code]
[b]default[/b]
The default template defines a &quot;nav&quot; region across the top, &quot;aside&quot; as a fixed width sidebar,
&quot;content&quot; for the main content region, and &quot;footer&quot; for a page footer.
[b]full[/b]
The full template defines the same as the default template with the exception that there is no &quot;aside&quot; region.
[b]choklet[/b]
The choklet template provides a number of fluid layout styles which can be specified by flavour:
(default flavour) - a two column layout similar to the "default" template, but more fluid
bannertwo - a two column layout with a banner region, compatible with the "default" template on small displays
three - three column layout (adds a "right_aside" region to the default template)
edgestwo - two column layout with fixed side margins
edgesthree - three column layout with fixed side margins
full - three column layout with fixed side margins and adds a "header" region beneath the navigation bar
[b]redable[/b] (sic)
A template for reading longer texts full screen (so without navigation bar). Three columns: aside, content and right_aside.
For maximum readability it is advised to only use the middle content column.
[b]zen[/b]
Gives you the freedom to do everything yourself. Just a blank page with a content region.
[/code]
To choose a layout template, use the 'template' tag.
[code]
[template]full[/template]
[/code]
To choose the "choklet" template with the "three" flavour:
[code]
[template=three]choklet[/template]
[/code]
The default template will be used if no other template is specified. The template can use any names it desires for content regions. You will be using 'region' tags to decide what content to place in the respective regions.
Three &quot;macros&quot; have been defined for your use.
[code]
$htmlhead - replaced with the site head content.
$nav - replaced with the site navigation bar content.
$content - replaced with the main page content.
[/code]
By default, $nav is placed in the &quot;nav&quot; page region and $content is placed in the &quot;content&quot; region. You only need to use these macros if you wish to re-arrange where these items appear, either to change the order or to move them to other regions.
To select a theme for your page, use the 'theme' tag.
[code]
[theme]suckerberg[/theme]
[/code]
This will select the theme named &quot;suckerberg&quot;. By default your channel's preferred theme will be used.
[code]
[theme=passion]suckerberg[/theme]
[/code]
This will select the theme named &quot;suckerberg&quot; and select the &quot;passion&quot; schema (theme variant). Alternatively it may be possible to use a condensed theme notation for this.
[code]
[theme]suckerberg:passion[/theme]
[/code]
The condensed notation isn't part of Comanche itself but is recognised by $Projectname platform as a theme specifier.
[b]Regions[/b]
Each region has a name, as noted above. You will specify the region of interest using a 'region' tag, which includes the name. Any content you wish placed in this region should be placed between the opening region tag and the closing tag.
[code]
[region=htmlhead]....content goes here....[/region]
[region=aside]....content goes here....[/region]
[region=nav]....content goes here....[/region]
[region=content]....content goes here....[/region]
[/code]
[b]CSS and Javascript[/b]
We have the possibility to include javascript and css libraries in the htmlhead region. At present we make use of jquery (js), bootstrap (css/js) and foundation (css/js).
This will overwrite the selected themes htmlhead.
[code]
[region=htmlhead]
[css]bootstrap[/css]
[js]jquery[/js]
[js]bootstrap[/js]
[/region]
[/code]
[b]Menus and Blocks[/b]
Your webpage creation tools allow you to create menus and blocks, in addition to page content. These provide a chunk of existing content to be placed in whatever regions and whatever order you specify. Each of these has a name which you define when the menu or block is created.
[code]
[menu]mymenu[/menu]
[/code]
This places the menu called &quot;mymenu&quot; at this location on the page, which must be inside a region.
[code]
[menu=horizontal]mymenu[/menu]
[/code]
This places the menu called &quot;mymenu&quot; at this location on the page, which must be inside a region. Additionally it applies the "horizontal" class to the menu. "horizontal" is defined in the redbasic theme. It may or may not be available in other themes.
[code]
[menu][var=wrap]none[/var]mymenu[/menu]
[/code]
The variable [var=wrap]none[/var] in a block removes the wrapping div element from the menu.
[code]
[block]contributors[/block]
[/code]
This places a block named &quot;contributors&quot; in this region.
[code]
[block=someclass]contributors[/block]
[/code]
This places a block named &quot;contributors&quot; in this region. Additionally it applies the &quot;someclass&quot; class to the block. This replaces the default block classes &quot;bblock widget&quot;.
[code]
[block][var=wrap]none[/var]contributors[/block]
[/code]
The variable [var=wrap]none[/var] in a block removes the wrapping div element from the block.
[b]Widgets[/b]
Widgets are executable apps provided by the system which you can place on your page. Some widgets take arguments which allows you to tailor the widget to your purpose. (TODO: list available widgets and arguments). The base system provides
[code]
profile - widget which duplicates the profile sidebar of your channel page. This widget takes no arguments
tagcloud - provides a tag cloud of categories
count - maximum number of category tags to list
[/code]
Widgets and arguments are specified with the 'widget' and 'var' tags.
[code]
[widget=recent_visitors][var=count]24[/var][/widget]
[/code]
This loads the &quot;recent_visitors&quot; widget and supplies it with the argument &quot;count&quot; set to &quot;24&quot;.
[b]Comments[/b]
The 'comment' tag is used to delimit comments. These comments will not appear on the rendered page.
[code]
[comment]This is a comment[/comment]
[/code]
[b]Conditional Execution[/b]
You can use an 'if' construct to make decisions. These are currently based on system configuration variable or the current observer.
[code]
[if $config.system.foo]
... the configuration variable system.foo evaluates to 'true'.
[else]
... the configuration variable system.foo evaluates to 'false'.
[/if]
[if $observer]
... this content will only be show to authenticated viewers
[/if]
[/code]
The 'else' clause is optional.
Several tests are supported besides boolean evaluation.
[code]
[if $config.system.foo == bar]
... the configuration variable system.foo is equal to the string 'bar'
[/if]
[if $config.system.foo != bar]
... the configuration variable system.foo is not equal to the string 'bar'
[/if]
[if $config.system.foo {} bar ]
... the configuration variable system.foo is a simple array containing a value 'bar'
[/if]
[if $config.system.foo {*} bar]
... the configuration variable system.foo is a simple array containing a key named 'bar'
[/if]
[/code]
[b]Complex Example[/b]
[code]
[comment]use an existing page template which provides a banner region plus 3 columns beneath it[/comment]
[template]3-column-with-header[/template]
[comment]Use the &quot;darknight&quot; theme[/comment]
[theme]darkknight[/theme]
[comment]Use the existing site navigation menu[/comment]
[region=nav]$nav[/region]
[region=side]
[comment]Use my chosen menu and a couple of widgets[/comment]
[menu]myfavouritemenu[/menu]
[widget=recent_visitors]
[var=count]24[/var]
[var=names_only]1[/var]
[/widget]
[widget=tagcloud][/widget]
[block]donate[/block]
[/region]
[region=middle]
[comment]Show the normal page content[/comment]
$content
[/region]
[region=right]
[comment]Show my condensed channel &quot;wall&quot; feed and allow interaction if the observer is allowed to interact[/comment]
[widget]channel[/widget]
[/region]
[/code]
#include doc/macros/main_footer.bb;
[b]Comanche Page Description Language[/b]
Comanche is a markup language similar to bbcode with which to create elaborate and complex web pages by assembling them from a series of components - some of which are pre-built and others which can be defined on the fly. Comanche uses a Page Decription Language to create these pages.
Comanche primarily chooses what content will appear in various regions of the page. The various regions have names and these names can change depending on what layout template you choose.
[b]Page Templates[/b]
Currently there are five layout templates, unless your site provides additional layouts.
[code]
[b]default[/b]
The default template defines a &quot;nav&quot; region across the top, &quot;aside&quot; as a fixed width sidebar,
&quot;content&quot; for the main content region, and &quot;footer&quot; for a page footer.
[b]full[/b]
The full template defines the same as the default template with the exception that there is no &quot;aside&quot; region.
[b]choklet[/b]
The choklet template provides a number of fluid layout styles which can be specified by flavour:
(default flavour) - a two column layout similar to the "default" template, but more fluid
bannertwo - a two column layout with a banner region, compatible with the "default" template on small displays
three - three column layout (adds a "right_aside" region to the default template)
edgestwo - two column layout with fixed side margins
edgesthree - three column layout with fixed side margins
full - three column layout with fixed side margins and adds a "header" region beneath the navigation bar
[b]redable[/b] (sic)
A template for reading longer texts full screen (so without navigation bar). Three columns: aside, content and right_aside.
For maximum readability it is advised to only use the middle content column.
[b]zen[/b]
Gives you the freedom to do everything yourself. Just a blank page with a content region.
[/code]
To choose a layout template, use the 'template' tag.
[code]
[template]full[/template]
[/code]
To choose the "choklet" template with the "three" flavour:
[code]
[template=three]choklet[/template]
[/code]
The default template will be used if no other template is specified. The template can use any names it desires for content regions. You will be using 'region' tags to decide what content to place in the respective regions.
Three &quot;macros&quot; have been defined for your use.
[code]
$htmlhead - replaced with the site head content.
$nav - replaced with the site navigation bar content.
$content - replaced with the main page content.
[/code]
By default, $nav is placed in the &quot;nav&quot; page region and $content is placed in the &quot;content&quot; region. You only need to use these macros if you wish to re-arrange where these items appear, either to change the order or to move them to other regions.
To select a theme for your page, use the 'theme' tag.
[code]
[theme]suckerberg[/theme]
[/code]
This will select the theme named &quot;suckerberg&quot;. By default your channel's preferred theme will be used.
[code]
[theme=passion]suckerberg[/theme]
[/code]
This will select the theme named &quot;suckerberg&quot; and select the &quot;passion&quot; schema (theme variant). Alternatively it may be possible to use a condensed theme notation for this.
[code]
[theme]suckerberg:passion[/theme]
[/code]
The condensed notation isn't part of Comanche itself but is recognised by $Projectname platform as a theme specifier.
[b]Regions[/b]
Each region has a name, as noted above. You will specify the region of interest using a 'region' tag, which includes the name. Any content you wish placed in this region should be placed between the opening region tag and the closing tag.
[code]
[region=htmlhead]....content goes here....[/region]
[region=aside]....content goes here....[/region]
[region=nav]....content goes here....[/region]
[region=content]....content goes here....[/region]
[/code]
[b]CSS and Javascript[/b]
We have the possibility to include javascript and css libraries in the htmlhead region. At present we make use of jquery (js), bootstrap (css/js) and foundation (css/js).
This will overwrite the selected themes htmlhead.
[code]
[region=htmlhead]
[css]bootstrap[/css]
[js]jquery[/js]
[js]bootstrap[/js]
[/region]
[/code]
[b]Menus and Blocks[/b]
Your webpage creation tools allow you to create menus and blocks, in addition to page content. These provide a chunk of existing content to be placed in whatever regions and whatever order you specify. Each of these has a name which you define when the menu or block is created.
[code]
[menu]mymenu[/menu]
[/code]
This places the menu called &quot;mymenu&quot; at this location on the page, which must be inside a region.
[code]
[menu=horizontal]mymenu[/menu]
[/code]
This places the menu called &quot;mymenu&quot; at this location on the page, which must be inside a region. Additionally it applies the "horizontal" class to the menu. "horizontal" is defined in the redbasic theme. It may or may not be available in other themes.
[code]
[menu][var=wrap]none[/var]mymenu[/menu]
[/code]
The variable [var=wrap]none[/var] in a block removes the wrapping div element from the menu.
[code]
[block]contributors[/block]
[/code]
This places a block named &quot;contributors&quot; in this region.
[code]
[block=someclass]contributors[/block]
[/code]
This places a block named &quot;contributors&quot; in this region. Additionally it applies the &quot;someclass&quot; class to the block. This replaces the default block classes &quot;bblock widget&quot;.
[code]
[block][var=wrap]none[/var]contributors[/block]
[/code]
The variable [var=wrap]none[/var] in a block removes the wrapping div element from the block.
[b]Widgets[/b]
Widgets are executable apps provided by the system which you can place on your page. Some widgets take arguments which allows you to tailor the widget to your purpose. (TODO: list available widgets and arguments). The base system provides
[code]
profile - widget which duplicates the profile sidebar of your channel page. This widget takes no arguments
tagcloud - provides a tag cloud of categories
count - maximum number of category tags to list
[/code]
Widgets and arguments are specified with the 'widget' and 'var' tags.
[code]
[widget=recent_visitors][var=count]24[/var][/widget]
[/code]
This loads the &quot;recent_visitors&quot; widget and supplies it with the argument &quot;count&quot; set to &quot;24&quot;.
[b]Comments[/b]
The 'comment' tag is used to delimit comments. These comments will not appear on the rendered page.
[code]
[comment]This is a comment[/comment]
[/code]
[b]Conditional Execution[/b]
You can use an 'if' construct to make decisions. These are currently based on system configuration variable or the current observer.
[code]
[if $config.system.foo]
... the configuration variable system.foo evaluates to 'true'.
[else]
... the configuration variable system.foo evaluates to 'false'.
[/if]
[if $observer]
... this content will only be show to authenticated viewers
[/if]
[/code]
The 'else' clause is optional.
Several tests are supported besides boolean evaluation.
[code]
[if $config.system.foo == bar]
... the configuration variable system.foo is equal to the string 'bar'
[/if]
[if $config.system.foo != bar]
... the configuration variable system.foo is not equal to the string 'bar'
[/if]
[if $config.system.foo {} bar ]
... the configuration variable system.foo is a simple array containing a value 'bar'
[/if]
[if $config.system.foo {*} bar]
... the configuration variable system.foo is a simple array containing a key named 'bar'
[/if]
[/code]
[b]Complex Example[/b]
[code]
[comment]use an existing page template which provides a banner region plus 3 columns beneath it[/comment]
[template]3-column-with-header[/template]
[comment]Use the &quot;darknight&quot; theme[/comment]
[theme]darkknight[/theme]
[comment]Use the existing site navigation menu[/comment]
[region=nav]$nav[/region]
[region=side]
[comment]Use my chosen menu and a couple of widgets[/comment]
[menu]myfavouritemenu[/menu]
[widget=recent_visitors]
[var=count]24[/var]
[var=names_only]1[/var]
[/widget]
[widget=tagcloud][/widget]
[block]donate[/block]
[/region]
[region=middle]
[comment]Show the normal page content[/comment]
$content
[/region]
[region=right]
[comment]Show my condensed channel &quot;wall&quot; feed and allow interaction if the observer is allowed to interact[/comment]
[widget]channel[/widget]
[/region]
[/code]
#include doc/macros/main_footer.bb;

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,14 +1,14 @@
<dl class="dl-horizontal">
<dt>General</dt>
<dd>This page manages which plugins (also known as <i>addons</i>) are installed.</dd>
<dd>This page manages which addons (also known as <i>plugins</i>) are installed.</dd>
<dt>Manage Repos</dt>
<dd>If your webserver has the necessary write permissions, you will see a button labeled <b>Manage Repos</b>,
which opens a control panel for managing what plugin <i>repositories</i> are installed. These repos are
stored in <span style="font-family: monospace;">extend/addon/[repo name]/</span>. The official Hubzilla
plugin repo can be added by entering the repo URL
<span style="font-family: monospace;">https://github.com/redmatrix/hubzilla-addons.git</span>
addon repo can be added by entering the repo URL
<span style="font-family: monospace;">https://framagit.org/hubzilla/addons.git</span>
and choosing a name for the repo such as <b>official</b>. You should see this repo in the list similar
to the following:
<br>
<img class="img-responsive" src="doc/context/en/admin/plugins/assets/addon_repo_gui_1.png"></dd>
</dl>
<img class="img-responsive" src="doc/context/en/admin/addons/assets/addon_repo_gui_1.png"></dd>
</dl>

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