diff options
322 files changed, 13778 insertions, 24832 deletions
@@ -1,20 +1,9 @@ -Copyright (c) 2010-2017 the Hubzilla Community +Copyright (c) 2010-2017 Mike Macgirvin All rights reserved. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. @@ -1,29 +1,7 @@ -![Hubzilla](images/hubzilla-banner.png) -Hubzilla - Community Server -=========================== +red +=== -<p align="center" markdown="1"> -<em><a href="https://github.com/redmatrix/hubzilla/blob/master/install/INSTALL.txt">Installing Hubzilla</a></em> -</p> +This is red. - -**What is Hubzilla?** - -Hubzilla is a general purpose communication server integrated with a web publishing system and a decentralised permission system. If this sounds like a bunch of technical mumbo-jumbo to you, just think of it as an independent platform for sharing stuff online. - -Hubzilla contains some social network bits, some cloud storage bits, some blog and forum bits, and some content management bits. These are all integrated within a common privacy framework - and it is all decentralised. - -Everything you publish or share can be restricted to those channels and people you wish to share them with; and these permissions work completely invisibly - even with channels on different servers or other communications services. - -Migration and live backups of your connections, settings, and everything you publish are built-in, so you never need worry about server failure. - -Hubzilla is completely decentralised and open source, for you modify or adapt to your needs and desires. Plugins, themes, and numerous configuration options extend the overall capabilities to do anything you can imagine. - - -**Who Are We?** - -The Hubzilla community consists of passionate volunteers creating an open source commons of decentralised services which are highly integrated and can rival the feature set of large centralised providers. We do our best to provide ethical software which places you in control of your online communications and privacy expectations. - - -[![Build Status](https://travis-ci.org/redmatrix/hubzilla.svg)](https://travis-ci.org/redmatrix/hubzilla) +![red](https://gitlab.com/macgirvin/red/raw/046e5e239fd28996f8c658900a83c33dbe0011ba/images/red-koala.png) diff --git a/Zotlabs/Access/Permissions.php b/Zotlabs/Access/Permissions.php index 74286934f..62c4af0ff 100644 --- a/Zotlabs/Access/Permissions.php +++ b/Zotlabs/Access/Permissions.php @@ -201,6 +201,7 @@ class Permissions { * * \e array \b perms Permission array * * \e int \b automatic 0 or 1 */ + static public function connect_perms($channel_id) { $my_perms = []; diff --git a/Zotlabs/Daemon/Importdoc.php b/Zotlabs/Daemon/Importdoc.php index 3109a5d86..0ca589e4a 100755 --- a/Zotlabs/Daemon/Importdoc.php +++ b/Zotlabs/Daemon/Importdoc.php @@ -21,12 +21,18 @@ class Importdoc { $files = glob("$d/$f"); if($files) { foreach($files as $fi) { - if($fi === 'doc/html') + if($fi === 'doc/html') { continue; - if(is_dir($fi)) + } + if(is_dir($fi)) { self::update_docs_dir("$fi/*"); - else - store_doc_file($fi); + } + else { + // don't update media content + if(strpos(z_mime_content_type($fi),'text') === 0) { + store_doc_file($fi); + } + } } } } diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php index 16246b081..20dd96ddd 100644 --- a/Zotlabs/Daemon/Notifier.php +++ b/Zotlabs/Daemon/Notifier.php @@ -64,8 +64,6 @@ require_once('include/bbcode.php'); * purge_all channel_id * expire channel_id * relay item_id (item was relayed to owner, we will deliver it as owner) - * single_activity item_id (deliver to a singleton network from the appropriate clone) - * single_mail mail_id (deliver to a singleton network from the appropriate clone) * location channel_id * request channel_id xchan_hash message_id * rating xlink_id @@ -105,7 +103,7 @@ class Notifier { $normal_mode = true; $packet_type = 'undefined'; - if($cmd === 'mail' || $cmd === 'single_mail') { + if($cmd === 'mail') { $normal_mode = false; $mail = true; $private = true; @@ -392,7 +390,6 @@ class Notifier { return; } } - } $walltowall = (($top_level_post && $channel['xchan_hash'] === $target_item['author_xchan']) ? true : false); @@ -409,7 +406,7 @@ class Notifier { if(! $recipients) return; -// logger('notifier: recipients: ' . print_r($recipients,true), LOGGER_NORMAL, LOG_DEBUG); + // logger('notifier: recipients: ' . print_r($recipients,true), LOGGER_NORMAL, LOG_DEBUG); $env_recips = (($private) ? array() : null); @@ -422,40 +419,39 @@ class Notifier { foreach($details as $d) { $recip_list[] = $d['xchan_addr'] . ' (' . $d['xchan_hash'] . ')'; - if($private) - $env_recips[] = array('guid' => $d['xchan_guid'],'guid_sig' => $d['xchan_guid_sig'],'hash' => $d['xchan_hash']); - - if($d['xchan_network'] === 'mail' && $normal_mode) { - $delivery_options = get_xconfig($d['xchan_hash'],'system','delivery_mode'); - if(! $delivery_options) - format_and_send_email($channel,$d,$target_item); + if($private) { + $env_recips[] = [ + 'guid' => $d['xchan_guid'], + 'guid_sig' => $d['xchan_guid_sig'], + 'hash' => $d['xchan_hash'] + ]; } } } - $narr = array( - 'channel' => $channel, - 'upstream' => $upstream, - 'env_recips' => $env_recips, - 'packet_recips' => $packet_recips, - 'recipients' => $recipients, - 'item' => $item, - 'target_item' => $target_item, + $narr = [ + 'channel' => $channel, + 'upstream' => $upstream, + 'env_recips' => $env_recips, + 'packet_recips' => $packet_recips, + 'recipients' => $recipients, + 'item' => $item, + 'target_item' => $target_item, 'top_level_post' => $top_level_post, - 'private' => $private, + 'private' => $private, 'relay_to_owner' => $relay_to_owner, - 'uplink' => $uplink, - 'cmd' => $cmd, - 'mail' => $mail, - 'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false), - 'location' => $location, - 'request' => $request, - 'normal_mode' => $normal_mode, - 'packet_type' => $packet_type, - 'walltowall' => $walltowall, - 'queued' => array() - ); + 'uplink' => $uplink, + 'cmd' => $cmd, + 'mail' => $mail, + 'single' => false, + 'location' => $location, + 'request' => $request, + 'normal_mode' => $normal_mode, + 'packet_type' => $packet_type, + 'walltowall' => $walltowall, + 'queued' => [] + ]; call_hooks('notifier_process', $narr); if($narr['queued']) { @@ -492,8 +488,6 @@ class Notifier { $hubs = $r; - - /** * Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey, * since it may have been a re-install which has not yet been detected and pruned. @@ -524,49 +518,47 @@ class Notifier { if($hub['hubloc_network'] == 'zot') { if(! in_array($hub['hubloc_sitekey'],$keys)) { $hublist[] = $hub['hubloc_host']; - $dhubs[] = $hub; - $keys[] = $hub['hubloc_sitekey']; + $dhubs[] = $hub; + $keys[] = $hub['hubloc_sitekey']; } } else { if(! in_array($hub['hubloc_url'],$urls)) { $hublist[] = $hub['hubloc_host']; - $dhubs[] = $hub; - $urls[] = $hub['hubloc_url']; + $dhubs[] = $hub; + $urls[] = $hub['hubloc_url']; } } } logger('notifier: will notify/deliver to these hubs: ' . print_r($hublist,true), LOGGER_DEBUG, LOG_DEBUG); - foreach($dhubs as $hub) { if($hub['hubloc_network'] !== 'zot') { - - $narr = array( - 'channel' => $channel, - 'upstream' => $upstream, - 'env_recips' => $env_recips, - 'packet_recips' => $packet_recips, - 'recipients' => $recipients, - 'item' => $item, - 'target_item' => $target_item, - 'hub' => $hub, + $narr = [ + 'channel' => $channel, + 'upstream' => $upstream, + 'env_recips' => $env_recips, + 'packet_recips' => $packet_recips, + 'recipients' => $recipients, + 'item' => $item, + 'target_item' => $target_item, + 'hub' => $hub, 'top_level_post' => $top_level_post, - 'private' => $private, + 'private' => $private, 'relay_to_owner' => $relay_to_owner, - 'uplink' => $uplink, - 'cmd' => $cmd, - 'mail' => $mail, - 'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false), - 'location' => $location, - 'request' => $request, - 'normal_mode' => $normal_mode, - 'packet_type' => $packet_type, - 'walltowall' => $walltowall, - 'queued' => array() - ); + 'uplink' => $uplink, + 'cmd' => $cmd, + 'mail' => $mail, + 'single' => false, + 'location' => $location, + 'request' => $request, + 'normal_mode' => $normal_mode, + 'packet_type' => $packet_type, + 'walltowall' => $walltowall, + 'queued' => [] + ]; call_hooks('notifier_hub',$narr); @@ -578,21 +570,6 @@ class Notifier { } - // singleton deliveries by definition 'not got zot'. - // Single deliveries are other federated networks (plugins) and we're essentially - // delivering only to those that have this site url in their abook_instance - // and only from within a sync operation. This means if you post from a clone, - // and a connection is connected to one of your other clones; assuming that hub - // is running it will receive a sync packet. On receipt of this sync packet it - // will invoke a delivery to those connections which are connected to just that - // hub instance. - - if($cmd === 'single_mail' || $cmd === 'single_activity') { - continue; - } - - // default: zot protocol - $hash = random_string(); $packet = null; @@ -618,14 +595,16 @@ class Notifier { else { $env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : ''); $packet = zot_build_packet($channel,'notify',$env,(($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'],$hash); - queue_insert(array( - 'hash' => $hash, - 'account_id' => $target_item['aid'], - 'channel_id' => $target_item['uid'], - 'posturl' => $hub['hubloc_callback'], - 'notify' => $packet, - 'msg' => json_encode($encoded_item) - )); + queue_insert( + [ + 'hash' => $hash, + 'account_id' => $target_item['aid'], + 'channel_id' => $target_item['uid'], + 'posturl' => $hub['hubloc_callback'], + 'notify' => $packet, + 'msg' => json_encode($encoded_item) + ] + ); // only create delivery reports for normal undeleted items if(is_array($target_item) && array_key_exists('postopts',$target_item) && (! $target_item['item_deleted']) && (! get_config('system','disable_dreport'))) { @@ -646,9 +625,9 @@ class Notifier { if($normal_mode) { $x = q("select * from hook where hook = 'notifier_normal'"); - if($x) - Master::Summon(array('Deliver_hooks',$target_item['id'])); - + if($x) { + Master::Summon( [ 'Deliver_hooks', $target_item['id'] ] ); + } } if($deliveries) diff --git a/Zotlabs/Extend/Hook.php b/Zotlabs/Extend/Hook.php index fef3ebe9b..c6f9ea850 100644 --- a/Zotlabs/Extend/Hook.php +++ b/Zotlabs/Extend/Hook.php @@ -40,6 +40,15 @@ class Hook { return $r; } + static public function register_array($file,$arr) { + if($arr) { + foreach($arr as $k => $v) { + self::register($k,$file,$v); + } + } + } + + static public function unregister($hook,$file,$function,$version = 1,$priority = 0) { if(is_array($function)) { $function = serialize($function); diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php index ed18ff3cb..68587df49 100644 --- a/Zotlabs/Lib/Apps.php +++ b/Zotlabs/Lib/Apps.php @@ -209,6 +209,7 @@ class Apps { static public function translate_system_apps(&$arr) { $apps = array( + 'Apps' => t('Apps'), 'Site Admin' => t('Site Admin'), 'Report Bug' => t('Report Bug'), 'View Bookmarks' => t('View Bookmarks'), @@ -664,11 +665,6 @@ class Apps { } - - - - - static public function app_decode($s) { $x = base64_decode(str_replace(array('<br />',"\r","\n",' '),array('','','',''),$s)); return json_decode($x,true); diff --git a/Zotlabs/Lib/Cache.php b/Zotlabs/Lib/Cache.php index f211269be..cea075659 100644 --- a/Zotlabs/Lib/Cache.php +++ b/Zotlabs/Lib/Cache.php @@ -9,10 +9,10 @@ namespace Zotlabs\Lib; class Cache { public static function get($key) { - $key = substr($key,0,254); + $hash = hash('whirlpool',$key); $r = q("SELECT v FROM cache WHERE k = '%s' limit 1", - dbesc($key) + dbesc($hash) ); if ($r) @@ -22,20 +22,20 @@ class Cache { public static function set($key,$value) { - $key = substr($key,0,254); + $hash = hash('whirlpool',$key); $r = q("SELECT * FROM cache WHERE k = '%s' limit 1", - dbesc($key) + dbesc($hash) ); if($r) { q("UPDATE cache SET v = '%s', updated = '%s' WHERE k = '%s'", dbesc($value), dbesc(datetime_convert()), - dbesc($key)); + dbesc($hash)); } else { q("INSERT INTO cache ( k, v, updated) VALUES ('%s','%s','%s')", - dbesc($key), + dbesc($hash), dbesc($value), dbesc(datetime_convert())); } diff --git a/Zotlabs/Lib/Config.php b/Zotlabs/Lib/Config.php index 5625a3f79..6e042feba 100644 --- a/Zotlabs/Lib/Config.php +++ b/Zotlabs/Lib/Config.php @@ -53,7 +53,7 @@ class Config { $dbvalue = ((is_array($value)) ? serialize($value) : $value); $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue); - if(get_config($family, $key) === false || (! self::get_from_storage($family, $key))) { + if(self::Get($family, $key) === false || (! self::get_from_storage($family, $key))) { $ret = q("INSERT INTO config ( cat, k, v ) VALUES ( '%s', '%s', '%s' ) ", dbesc($family), dbesc($key), diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index 90662ce84..9f3347d19 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -170,7 +170,7 @@ class Enotify { xchan_query($p); - $moderated = (($p[0]['item_blocked'] = ITEM_MODERATED) ? true : false); + $moderated = (($p[0]['item_blocked'] == ITEM_MODERATED) ? true : false); $item_post_type = item_post_type($p[0]); // $private = $p[0]['item_private']; diff --git a/Zotlabs/Lib/PConfig.php b/Zotlabs/Lib/PConfig.php index d70697fbc..25478e764 100644 --- a/Zotlabs/Lib/PConfig.php +++ b/Zotlabs/Lib/PConfig.php @@ -119,7 +119,7 @@ class PConfig { $dbvalue = ((is_array($value)) ? serialize($value) : $value); $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue); - if(get_pconfig($uid, $family, $key) === false) { + if(self::Get($uid, $family, $key) === false) { if(! array_key_exists($uid, \App::$config)) \App::$config[$uid] = array(); if(! array_key_exists($family, \App::$config[$uid])) diff --git a/Zotlabs/Lib/System.php b/Zotlabs/Lib/System.php index 306c90f4a..3d5b18506 100644 --- a/Zotlabs/Lib/System.php +++ b/Zotlabs/Lib/System.php @@ -54,12 +54,8 @@ class System { return 'https://github.com/redmatrix/hubzilla'; } - - static public function get_server_role() { - if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['server_role']) - return \App::$config['system']['server_role']; - return 'standard'; + return 'pro'; } static public function get_std_version() { @@ -72,11 +68,8 @@ class System { if(get_directory_realm() != DIRECTORY_REALM) return true; - - foreach(['hubzilla','zap'] as $t) { - if(stristr($p,$t)) - return true; - } + if(in_array(strtolower($p),['hubzilla','zap','red'])) + return true; return false; } } diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 917397686..72d8af4dd 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -251,8 +251,6 @@ class ThreadItem { ); } - $server_role = get_config('system','server_role'); - $has_bookmarks = false; if(is_array($item['term'])) { foreach($item['term'] as $t) { diff --git a/Zotlabs/Module/Admin.php b/Zotlabs/Module/Admin.php index 536d85dde..f2918dffc 100644 --- a/Zotlabs/Module/Admin.php +++ b/Zotlabs/Module/Admin.php @@ -91,10 +91,10 @@ class Admin extends \Zotlabs\Web\Controller { intval(ACCOUNT_BLOCKED) ); if ($r) { - $accounts['total'] = array('label' => t('# Accounts'), 'val' => $r[0]['total']); - $accounts['blocked'] = array('label' => t('# blocked accounts'), 'val' => $r[0]['blocked']); - $accounts['expired'] = array('label' => t('# expired accounts'), 'val' => $r[0]['expired']); - $accounts['expiring'] = array('label' => t('# expiring accounts'), 'val' => $r[0]['expiring']); + $accounts['total'] = array('label' => t('Accounts'), 'val' => $r[0]['total']); + $accounts['blocked'] = array('label' => t('Blocked accounts'), 'val' => $r[0]['blocked']); + $accounts['expired'] = array('label' => t('Expired accounts'), 'val' => $r[0]['expired']); + $accounts['expiring'] = array('label' => t('Expiring accounts'), 'val' => $r[0]['expiring']); } // pending registrations @@ -105,9 +105,9 @@ class Admin extends \Zotlabs\Web\Controller { $channels = array(); $r = q("SELECT COUNT(*) AS total, COUNT(CASE WHEN channel_primary = 1 THEN 1 ELSE NULL END) AS main, COUNT(CASE WHEN channel_primary = 0 THEN 1 ELSE NULL END) AS clones FROM channel WHERE channel_removed = 0"); if ($r) { - $channels['total'] = array('label' => t('# Channels'), 'val' => $r[0]['total']); - $channels['main'] = array('label' => t('# primary'), 'val' => $r[0]['main']); - $channels['clones'] = array('label' => t('# clones'), 'val' => $r[0]['clones']); + $channels['total'] = array('label' => t('Channels'), 'val' => $r[0]['total']); + $channels['main'] = array('label' => t('Primary'), 'val' => $r[0]['main']); + $channels['clones'] = array('label' => t('Clones'), 'val' => $r[0]['clones']); } // We can do better, but this is a quick queue status @@ -118,14 +118,11 @@ class Admin extends \Zotlabs\Web\Controller { // If no plugins active return 0, otherwise list of plugin names $plugins = (count(\App::$plugins) == 0) ? count(\App::$plugins) : \App::$plugins; + if(is_array($plugins)) + sort($plugins); + // Could be extended to provide also other alerts to the admin $alertmsg = ''; - // annoy admin about upcoming unsupported PHP version - if (version_compare(PHP_VERSION, '5.4', '<')) { - $alertmsg = 'Your PHP version ' . PHP_VERSION . ' will not be supported with the next major release of $Projectname. You are strongly urged to upgrade to a current version.' - . '<br>PHP 5.3 has reached its <a href="http://php.net/eol.php" class="alert-link">End of Life (EOL)</a> in August 2014.' - . ' A list about current PHP versions can be found <a href="http://php.net/supported-versions.php" class="alert-link">here</a>.'; - } $vmaster = get_repository_version('master'); $vdev = get_repository_version('dev'); diff --git a/Zotlabs/Module/Admin/Site.php b/Zotlabs/Module/Admin/Site.php index d05e70aa9..4c5b82e78 100644 --- a/Zotlabs/Module/Admin/Site.php +++ b/Zotlabs/Module/Admin/Site.php @@ -17,7 +17,6 @@ class Site { check_form_security_token_redirectOnErr('/admin/site', 'admin_site'); $sitename = ((x($_POST,'sitename')) ? notags(trim($_POST['sitename'])) : ''); - $server_role = ((x($_POST,'server_role')) ? notags(trim($_POST['server_role'])) : 'standard'); $banner = ((x($_POST,'banner')) ? trim($_POST['banner']) : false); @@ -68,7 +67,6 @@ class Site { if(array_key_exists('techlevel', $_POST)) $techlevel = intval($_POST['techlevel']); - set_config('system', 'server_role', $server_role); set_config('system', 'feed_contacts', $feed_contacts); set_config('system', 'delivery_interval', $delivery_interval); set_config('system', 'delivery_batch_count', $delivery_batch_count); @@ -254,12 +252,6 @@ class Site { // now invert the logic for the setting. $discover_tab = (1 - $discover_tab); - $server_roles = [ - 'basic' => t('Basic/Minimal Social Networking'), - 'standard' => t('Standard Configuration (default)'), - 'pro' => t('Professional') - ]; - $techlevels = [ '0' => t('Beginner/Basic'), '1' => t('Novice - not skilled but willing to learn'), @@ -286,8 +278,6 @@ class Site { // name, label, value, help string, extra data... '$sitename' => array('sitename', t("Site name"), htmlspecialchars(get_config('system','sitename'), ENT_QUOTES, 'UTF-8'),''), - '$server_role' => array('server_role', t("Server Configuration/Role"), get_config('system','server_role'),'',$server_roles), - '$techlevel' => [ 'techlevel', t('Site default technical skill level'), get_config('system','techlevel'), t('Used to provide a member experience matched to technical comfort level'), $techlevels ], '$techlock' => [ 'techlock', t('Lock the technical skill level setting'), get_config('system','techlevel_lock'), t('Members can set their own technical comfort level by default') ], diff --git a/Zotlabs/Module/Authorize.php b/Zotlabs/Module/Authorize.php new file mode 100644 index 000000000..06f66c456 --- /dev/null +++ b/Zotlabs/Module/Authorize.php @@ -0,0 +1,71 @@ +<?php + +namespace Zotlabs\Module; + + +class Authorize extends \Zotlabs\Web\Controller { + + + function get() { + + + // workaround for HTTP-auth in CGI mode + if (x($_SERVER, 'REDIRECT_REMOTE_USER')) { + $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)) ; + if(strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + } + + if (x($_SERVER, 'HTTP_AUTHORIZATION')) { + $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)) ; + if(strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + } + + + + + require_once('include/oauth2.php'); + + $request = \OAuth2\Request::createFromGlobals(); + $response = new \OAuth2\Response(); + + // validate the authorize request + if (! $oauth2_server->validateAuthorizeRequest($request, $response)) { + $response->send(); + killme(); + } + + // display an authorization form + if (empty($_POST)) { + + return ' +<form method="post"> + <label>Do You Authorize TestClient?</label><br /> + <input type="submit" name="authorized" value="yes"> + <input type="submit" name="authorized" value="no"> +</form>'; + } + + // print the authorization code if the user has authorized your client + $is_authorized = ($_POST['authorized'] === 'yes'); + $oauth2_server->handleAuthorizeRequest($request, $response, $is_authorized); + if ($is_authorized) { + // this is only here so that you get to see your code in the cURL request. Otherwise, + // we'd redirect back to the client + $code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=')+5, 40); + echo("SUCCESS! Authorization Code: $code"); + + } + + $response->send(); + killme(); + } + +}
\ No newline at end of file diff --git a/Zotlabs/Module/Block.php b/Zotlabs/Module/Block.php index e671730f6..d0fed44fe 100644 --- a/Zotlabs/Module/Block.php +++ b/Zotlabs/Module/Block.php @@ -3,8 +3,6 @@ namespace Zotlabs\Module; require_once('include/items.php'); require_once('include/conversation.php'); -require_once('include/page_widgets.php'); - class Block extends \Zotlabs\Web\Controller { diff --git a/Zotlabs/Module/Cdav.php b/Zotlabs/Module/Cdav.php new file mode 100644 index 000000000..f91dead04 --- /dev/null +++ b/Zotlabs/Module/Cdav.php @@ -0,0 +1,1202 @@ +<?php +namespace Zotlabs\Module; + +require_once('include/event.php'); + +class Cdav extends \Zotlabs\Web\Controller { + + function init() { + + if((argv(1) !== 'calendar') && (argv(1) !== 'addressbook')) { + + // workaround for HTTP-auth in CGI mode + if (x($_SERVER, 'REDIRECT_REMOTE_USER')) { + $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)) ; + if(strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + } + + if (x($_SERVER, 'HTTP_AUTHORIZATION')) { + $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)) ; + if(strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + } + + /** + * This server combines both CardDAV and CalDAV functionality into a single + * server. It is assumed that the server runs at the root of a HTTP domain (be + * that a domainname-based vhost or a specific TCP port. + * + * This example also assumes that you're using SQLite and the database has + * already been setup (along with the database tables). + * + * You may choose to use MySQL instead, just change the PDO connection + * statement. + */ + + /** + * UTC or GMT is easy to work with, and usually recommended for any + * application. + */ + date_default_timezone_set('UTC'); + + /** + * Make sure this setting is turned on and reflect the root url for your WebDAV + * server. + * + * This can be for example the root / or a complete path to your server script. + */ + + $baseUri = '/cdav/'; + + /** + * Database + * + */ + + $pdo = \DBA::$dba->db; + + // Autoloader + require_once 'vendor/autoload.php'; + + /** + * The backends. Yes we do really need all of them. + * + * This allows any developer to subclass just any of them and hook into their + * own backend systems. + */ + + $auth = new \Zotlabs\Storage\BasicAuth(); + $auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . 'CalDAV/CardDAV'); + + if (local_channel()) { + logger('loggedin'); + $channel = \App::get_channel(); + $auth->setCurrentUser($channel['channel_address']); + $auth->channel_id = $channel['channel_id']; + $auth->channel_hash = $channel['channel_hash']; + $auth->channel_account_id = $channel['channel_account_id']; + if($channel['channel_timezone']) + $auth->setTimezone($channel['channel_timezone']); + $auth->observer = $channel['channel_hash']; + } + + + $principalBackend = new \Sabre\DAVACL\PrincipalBackend\PDO($pdo); + $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo); + $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); + + /** + * The directory tree + * + * Basically this is an array which contains the 'top-level' directories in the + * WebDAV server. + */ + + $nodes = [ + // /principals + new \Sabre\CalDAV\Principal\Collection($principalBackend), + // /calendars + new \Sabre\CalDAV\CalendarRoot($principalBackend, $caldavBackend), + // /addressbook + new \Sabre\CardDAV\AddressBookRoot($principalBackend, $carddavBackend), + ]; + + // The object tree needs in turn to be passed to the server class + + $server = new \Sabre\DAV\Server($nodes); + + if(isset($baseUri)) + $server->setBaseUri($baseUri); + + // Plugins + $server->addPlugin(new \Sabre\DAV\Auth\Plugin($auth)); + //$server->addPlugin(new \Sabre\DAV\Browser\Plugin()); + $server->addPlugin(new \Sabre\DAV\Sync\Plugin()); + $server->addPlugin(new \Sabre\DAV\Sharing\Plugin()); + $server->addPlugin(new \Sabre\DAVACL\Plugin()); + + // CalDAV plugins + $server->addPlugin(new \Sabre\CalDAV\Plugin()); + $server->addPlugin(new \Sabre\CalDAV\SharingPlugin()); + //$server->addPlugin(new \Sabre\CalDAV\Schedule\Plugin()); + $server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin()); + + // CardDAV plugins + $server->addPlugin(new \Sabre\CardDAV\Plugin()); + $server->addPlugin(new \Sabre\CardDAV\VCFExportPlugin()); + + // And off we go! + $server->exec(); + + killme(); + + } + + } + + function post() { + if(! local_channel()) + return; + + $channel = \App::get_channel(); + $principalUri = 'principals/' . $channel['channel_hash']; + + if(!cdav_principal($principalUri)) + return; + + $pdo = \DBA::$dba->db; + + require_once 'vendor/autoload.php'; + + if(argc() == 2 && argv(1) === 'calendar') { + + $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); + $calendars = $caldavBackend->getCalendarsForUser($principalUri); + + //create new calendar + if($_REQUEST['{DAV:}displayname'] && $_REQUEST['create']) { + do { + $duplicate = false; + $calendarUri = random_string(40); + + $r = q("SELECT uri FROM calendarinstances WHERE principaluri = '%s' AND uri = '%s' LIMIT 1", + dbesc($principalUri), + dbesc($calendarUri) + ); + + if (count($r)) + $duplicate = true; + } while ($duplicate == true); + + $properties = [ + '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'], + '{http://apple.com/ns/ical/}calendar-color' => $_REQUEST['color'], + '{urn:ietf:params:xml:ns:caldav}calendar-description' => $channel['channel_name'] + ]; + + $id = $caldavBackend->createCalendar($principalUri, $calendarUri, $properties); + + // set new calendar to be visible + set_pconfig(local_channel(), 'cdav_calendar' , $id[0], 1); + } + + //create new calendar object via ajax request + if($_REQUEST['submit'] === 'create_event' && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) { + + $id = explode(':', $_REQUEST['target']); + + if(!cdav_perms($id[0],$calendars,true)) + return; + + $title = $_REQUEST['title']; + $dtstart = new \DateTime($_REQUEST['dtstart']); + if($_REQUEST['dtend']) + $dtend = new \DateTime($_REQUEST['dtend']); + $description = $_REQUEST['description']; + $location = $_REQUEST['location']; + + do { + $duplicate = false; + $objectUri = random_string(40) . '.ics'; + + $r = q("SELECT uri FROM calendarobjects WHERE calendarid = %s AND uri = '%s' LIMIT 1", + intval($id[0]), + dbesc($objectUri) + ); + + if (count($r)) + $duplicate = true; + } while ($duplicate == true); + + + $vcalendar = new \Sabre\VObject\Component\VCalendar([ + 'VEVENT' => [ + 'SUMMARY' => $title, + 'DTSTART' => $dtstart + ] + ]); + if($dtend) + $vcalendar->VEVENT->add('DTEND', $dtend); + if($description) + $vcalendar->VEVENT->add('DESCRIPTION', $description); + if($location) + $vcalendar->VEVENT->add('LOCATION', $location); + + $calendarData = $vcalendar->serialize(); + + $caldavBackend->createCalendarObject($id, $objectUri, $calendarData); + + killme(); + } + + //edit calendar name and color + if($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && $_REQUEST['id']) { + + $id = explode(':', $_REQUEST['id']); + + if(! cdav_perms($id[0],$calendars)) + return; + + $mutations = [ + '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'], + '{http://apple.com/ns/ical/}calendar-color' => $_REQUEST['color'] + ]; + + $patch = new \Sabre\DAV\PropPatch($mutations); + + $caldavBackend->updateCalendar($id, $patch); + + $patch->commit(); + + } + + //edit calendar object via ajax request + if($_REQUEST['submit'] === 'update_event' && $_REQUEST['uri'] && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) { + + $id = explode(':', $_REQUEST['target']); + + if(!cdav_perms($id[0],$calendars,true)) + return; + + $uri = $_REQUEST['uri']; + $title = $_REQUEST['title']; + $dtstart = new \DateTime($_REQUEST['dtstart']); + $dtend = $_REQUEST['dtend'] ? new \DateTime($_REQUEST['dtend']) : ''; + $description = $_REQUEST['description']; + $location = $_REQUEST['location']; + + $object = $caldavBackend->getCalendarObject($id, $uri); + + $vcalendar = \Sabre\VObject\Reader::read($object['calendardata']); + + if($title) + $vcalendar->VEVENT->SUMMARY = $title; + if($dtstart) + $vcalendar->VEVENT->DTSTART = $dtstart; + if($dtend) + $vcalendar->VEVENT->DTEND = $dtend; + else + unset($vcalendar->VEVENT->DTEND); + if($description) + $vcalendar->VEVENT->DESCRIPTION = $description; + if($location) + $vcalendar->VEVENT->LOCATION = $location; + + $calendarData = $vcalendar->serialize(); + + $caldavBackend->updateCalendarObject($id, $uri, $calendarData); + + killme(); + } + + //delete calendar object via ajax request + if($_REQUEST['delete'] && $_REQUEST['uri'] && $_REQUEST['target']) { + + $id = explode(':', $_REQUEST['target']); + + if(!cdav_perms($id[0],$calendars,true)) + return; + + $uri = $_REQUEST['uri']; + + $caldavBackend->deleteCalendarObject($id, $uri); + + killme(); + } + + //edit calendar object date/timeme via ajax request (drag and drop) + if($_REQUEST['update'] && $_REQUEST['id'] && $_REQUEST['uri']) { + + $id = [$_REQUEST['id'][0], $_REQUEST['id'][1]]; + + if(!cdav_perms($id[0],$calendars,true)) + return; + + $uri = $_REQUEST['uri']; + $dtstart = new \DateTime($_REQUEST['dtstart']); + $dtend = $_REQUEST['dtend'] ? new \DateTime($_REQUEST['dtend']) : ''; + + $object = $caldavBackend->getCalendarObject($id, $uri); + + $vcalendar = \Sabre\VObject\Reader::read($object['calendardata']); + + if($dtstart) { + $vcalendar->VEVENT->DTSTART = $dtstart; + } + if($dtend) { + $vcalendar->VEVENT->DTEND = $dtend; + } + else { + unset($vcalendar->VEVENT->DTEND); + } + + $calendarData = $vcalendar->serialize(); + + $caldavBackend->updateCalendarObject($id, $uri, $calendarData); + + killme(); + } + + //share a calendar - this only works on local system (with channels on the same server) + if($_REQUEST['sharee'] && $_REQUEST['share']) { + + $id = [intval($_REQUEST['calendarid']), intval($_REQUEST['instanceid'])]; + + if(! cdav_perms($id[0],$calendars)) + return; + + $hash = $_REQUEST['sharee']; + + $sharee_arr = channelx_by_hash($hash); + + $sharee = new \Sabre\DAV\Xml\Element\Sharee(); + + $sharee->href = 'mailto:' . $sharee_arr['channel_hash']; + $sharee->principal = 'principals/' . $sharee_arr['channel_address']; + $sharee->access = intval($_REQUEST['access']); + $sharee->properties = ['{DAV:}displayname' => $channel['channel_name']]; + + $caldavBackend->updateInvites($id, [$sharee]); + } + } + + if(argc() >= 2 && argv(1) === 'addressbook') { + + $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo); + $addressbooks = $carddavBackend->getAddressBooksForUser($principalUri); + + //create new addressbook + if($_REQUEST['{DAV:}displayname'] && $_REQUEST['create']) { + do { + $duplicate = false; + $addressbookUri = random_string(20); + + $r = q("SELECT uri FROM addressbooks WHERE principaluri = '%s' AND uri = '%s' LIMIT 1", + dbesc($principalUri), + dbesc($addressbookUri) + ); + + if (count($r)) + $duplicate = true; + } while ($duplicate == true); + + $properties = ['{DAV:}displayname' => $_REQUEST['{DAV:}displayname']]; + + $carddavBackend->createAddressBook($principalUri, $addressbookUri, $properties); + } + + //edit addressbook + if($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && intval($_REQUEST['id'])) { + + $id = $_REQUEST['id']; + + if(! cdav_perms($id,$addressbooks)) + return; + + $mutations = [ + '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'] + ]; + + $patch = new \Sabre\DAV\PropPatch($mutations); + + $carddavBackend->updateAddressBook($id, $patch); + + $patch->commit(); + } + + //create addressbook card + if($_REQUEST['create'] && $_REQUEST['target'] && $_REQUEST['fn']) { + $id = $_REQUEST['target']; + + do { + $duplicate = false; + $uri = random_string(40) . '.vcf'; + + $r = q("SELECT uri FROM cards WHERE addressbookid = %s AND uri = '%s' LIMIT 1", + intval($id), + dbesc($uri) + ); + + if (count($r)) + $duplicate = true; + } while ($duplicate == true); + + //TODO: this mostly duplictes the procedure in update addressbook card. should move this part to a function to avoid duplication + $fn = $_REQUEST['fn']; + + $vcard = new \Sabre\VObject\Component\VCard([ + 'FN' => $fn, + 'N' => array_reverse(explode(' ', $fn)) + ]); + + $org = $_REQUEST['org']; + if($org) { + $vcard->ORG = $org; + } + + $title = $_REQUEST['title']; + if($title) { + $vcard->TITLE = $title; + } + + $tel = $_REQUEST['tel']; + $tel_type = $_REQUEST['tel_type']; + if($tel) { + $i = 0; + foreach($tel as $item) { + if($item) { + $vcard->add('TEL', $item, ['type' => $tel_type[$i]]); + } + $i++; + } + } + + $email = $_REQUEST['email']; + $email_type = $_REQUEST['email_type']; + if($email) { + $i = 0; + foreach($email as $item) { + if($item) { + $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]); + } + $i++; + } + } + + $impp = $_REQUEST['impp']; + $impp_type = $_REQUEST['impp_type']; + if($impp) { + $i = 0; + foreach($impp as $item) { + if($item) { + $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]); + } + $i++; + } + } + + $url = $_REQUEST['url']; + $url_type = $_REQUEST['url_type']; + if($url) { + $i = 0; + foreach($url as $item) { + if($item) { + $vcard->add('URL', $item, ['type' => $url_type[$i]]); + } + $i++; + } + } + + $adr = $_REQUEST['adr']; + $adr_type = $_REQUEST['adr_type']; + + if($adr) { + $i = 0; + foreach($adr as $item) { + if($item) { + $vcard->add('ADR', $item, ['type' => $adr_type[$i]]); + } + $i++; + } + } + + $note = $_REQUEST['note']; + if($note) { + $vcard->NOTE = $note; + } + + $cardData = $vcard->serialize(); + + $carddavBackend->createCard($id, $uri, $cardData); + + } + + //edit addressbook card + if($_REQUEST['update'] && $_REQUEST['uri'] && $_REQUEST['target']) { + + $id = $_REQUEST['target']; + + if(!cdav_perms($id,$addressbooks)) + return; + + $uri = $_REQUEST['uri']; + + $object = $carddavBackend->getCard($id, $uri); + $vcard = \Sabre\VObject\Reader::read($object['carddata']); + + $fn = $_REQUEST['fn']; + if($fn) { + $vcard->FN = $fn; + $vcard->N = array_reverse(explode(' ', $fn)); + } + + $org = $_REQUEST['org']; + if($org) { + $vcard->ORG = $org; + } + else { + unset($vcard->ORG); + } + + $title = $_REQUEST['title']; + if($title) { + $vcard->TITLE = $title; + } + else { + unset($vcard->TITLE); + } + + $tel = $_REQUEST['tel']; + $tel_type = $_REQUEST['tel_type']; + if($tel) { + $i = 0; + unset($vcard->TEL); + foreach($tel as $item) { + if($item) { + $vcard->add('TEL', $item, ['type' => $tel_type[$i]]); + } + $i++; + } + } + else { + unset($vcard->TEL); + } + + $email = $_REQUEST['email']; + $email_type = $_REQUEST['email_type']; + if($email) { + $i = 0; + unset($vcard->EMAIL); + foreach($email as $item) { + if($item) { + $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]); + } + $i++; + } + } + else { + unset($vcard->EMAIL); + } + + $impp = $_REQUEST['impp']; + $impp_type = $_REQUEST['impp_type']; + if($impp) { + $i = 0; + unset($vcard->IMPP); + foreach($impp as $item) { + if($item) { + $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]); + } + $i++; + } + } + else { + unset($vcard->IMPP); + } + + $url = $_REQUEST['url']; + $url_type = $_REQUEST['url_type']; + if($url) { + $i = 0; + unset($vcard->URL); + foreach($url as $item) { + if($item) { + $vcard->add('URL', $item, ['type' => $url_type[$i]]); + } + $i++; + } + } + else { + unset($vcard->URL); + } + + $adr = $_REQUEST['adr']; + $adr_type = $_REQUEST['adr_type']; + if($adr) { + $i = 0; + unset($vcard->ADR); + foreach($adr as $item) { + if($item) { + $vcard->add('ADR', $item, ['type' => $adr_type[$i]]); + } + $i++; + } + } + else { + unset($vcard->ADR); + } + + $note = $_REQUEST['note']; + if($note) { + $vcard->NOTE = $note; + } + else { + unset($vcard->NOTE); + } + + $cardData = $vcard->serialize(); + + $carddavBackend->updateCard($id, $uri, $cardData); + } + + //delete addressbook card + if($_REQUEST['delete'] && $_REQUEST['uri'] && $_REQUEST['target']) { + + $id = $_REQUEST['target']; + + if(!cdav_perms($id,$addressbooks)) + return; + + $uri = $_REQUEST['uri']; + + $carddavBackend->deleteCard($id, $uri); + } + } + + //Import calendar or addressbook + if(($_FILES) && array_key_exists('userfile',$_FILES) && intval($_FILES['userfile']['size']) && $_REQUEST['target']) { + + $src = @file_get_contents($_FILES['userfile']['tmp_name']); + + if($src) { + + if($_REQUEST['c_upload']) { + $id = explode(':', $_REQUEST['target']); + $ext = 'ics'; + $table = 'calendarobjects'; + $column = 'calendarid'; + $objects = new \Sabre\VObject\Splitter\ICalendar($src); + $profile = \Sabre\VObject\Node::PROFILE_CALDAV; + $backend = new \Sabre\CalDAV\Backend\PDO($pdo); + } + + if($_REQUEST['a_upload']) { + $id[] = intval($_REQUEST['target']); + $ext = 'vcf'; + $table = 'cards'; + $column = 'addressbookid'; + $objects = new \Sabre\VObject\Splitter\VCard($src); + $profile = \Sabre\VObject\Node::PROFILE_CARDDAV; + $backend = new \Sabre\CardDAV\Backend\PDO($pdo); + } + + while ($object = $objects->getNext()) { + + if($_REQUEST['a_upload']) { + $object = $object->convert(\Sabre\VObject\Document::VCARD40); + } + + $ret = $object->validate($profile & \Sabre\VObject\Node::REPAIR); + + //level 3 Means that the document is invalid, + //level 2 means a warning. A warning means it's valid but it could cause interopability issues, + //level 1 means that there was a problem earlier, but the problem was automatically repaired. + + if($ret[0]['level'] < 3) { + do { + $duplicate = false; + $objectUri = random_string(40) . '.' . $ext; + + $r = q("SELECT uri FROM $table WHERE $column = %d AND uri = '%s' LIMIT 1", + dbesc($id[0]), + dbesc($objectUri) + ); + + if (count($r)) + $duplicate = true; + } while ($duplicate == true); + + if($_REQUEST['c_upload']) { + $backend->createCalendarObject($id, $objectUri, $object->serialize()); + } + + if($_REQUEST['a_upload']) { + $backend->createCard($id[0], $objectUri, $object->serialize()); + } + } + else { + if($_REQUEST['c_upload']) { + notice( '<strong>' . t('INVALID EVENT DISMISSED!') . '</strong>' . EOL . + '<strong>' . t('Summary: ') . '</strong>' . (($object->VEVENT->SUMMARY) ? $object->VEVENT->SUMMARY : t('Unknown')) . EOL . + '<strong>' . t('Date: ') . '</strong>' . (($object->VEVENT->DTSTART) ? $object->VEVENT->DTSTART : t('Unknown')) . EOL . + '<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL + ); + } + + if($_REQUEST['a_upload']) { + notice( '<strong>' . t('INVALID CARD DISMISSED!') . '</strong>' . EOL . + '<strong>' . t('Name: ') . '</strong>' . (($object->FN) ? $object->FN : t('Unknown')) . EOL . + '<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL + ); + } + } + } + } + @unlink($src); + } + } + + function get() { + + if(!local_channel()) + return; + + $channel = \App::get_channel(); + $principalUri = 'principals/' . $channel['channel_hash']; + + + if(!cdav_principal($principalUri)) { + $this->activate($channel); + if(!cdav_principal($principalUri)) { + return; + } + } + + $pdo = \DBA::$dba->db; + + require_once 'vendor/autoload.php'; + + head_add_css('cdav.css'); + + if(argv(1) === 'calendar') { + $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); + $calendars = $caldavBackend->getCalendarsForUser($principalUri); + } + + //Display calendar(s) here + if(argc() == 2 && argv(1) === 'calendar') { + + head_add_css('/library/fullcalendar/fullcalendar.css'); + head_add_css('cdav_calendar.css'); + + head_add_js('/library/moment/moment.min.js', 1); + head_add_js('/library/fullcalendar/fullcalendar.min.js', 1); + head_add_js('/library/fullcalendar/locale-all.js', 1); + + foreach($calendars as $calendar) { + $editable = (($calendar['share-access'] == 2) ? 'false' : 'true'); // false/true must be string since we're passing it to javascript + $color = (($calendar['{http://apple.com/ns/ical/}calendar-color']) ? $calendar['{http://apple.com/ns/ical/}calendar-color'] : '#3a87ad'); + $sharer = (($calendar['share-access'] == 3) ? $calendar['{urn:ietf:params:xml:ns:caldav}calendar-description'] : ''); + $switch = get_pconfig(local_channel(), 'cdav_calendar', $calendar['id'][0]); + if($switch) { + $sources .= '{ + url: \'/cdav/calendar/json/' . $calendar['id'][0] . '/' . $calendar['id'][1] . '\', + color: \'' . $color . '\' + }, '; + } + + if($calendar['share-access'] != 2) { + $writable_calendars[] = [ + 'displayname' => $calendar['{DAV:}displayname'], + 'sharer' => $sharer, + 'id' => $calendar['id'] + ]; + } + } + + $sources = rtrim($sources, ', '); + + $first_day = get_pconfig(local_channel(),'system','cal_first_day'); + $first_day = (($first_day) ? $first_day : 0); + + $title = ['title', t('Event title')]; + $dtstart = ['dtstart', t('Start date and time'), '', t('Example: YYYY-MM-DD HH:mm')]; + $dtend = ['dtend', t('End date and time'), '', t('Example: YYYY-MM-DD HH:mm')]; + $description = ['description', t('Description')]; + $location = ['location', t('Location')]; + + $o .= replace_macros(get_markup_template('cdav_calendar.tpl'), [ + '$sources' => $sources, + '$color' => $color, + '$lang' => \App::$language, + '$first_day' => $first_day, + '$prev' => t('Previous'), + '$next' => t('Next'), + '$today' => t('Today'), + '$month' => t('Month'), + '$week' => t('Week'), + '$day' => t('Day'), + '$list_month' => t('List month'), + '$list_week' => t('List week'), + '$list_day' => t('List day'), + '$title' => $title, + '$writable_calendars' => $writable_calendars, + '$dtstart' => $dtstart, + '$dtend' => $dtend, + '$description' => $description, + '$location' => $location, + '$more' => t('More'), + '$less' => t('Less'), + '$calendar_select_label' => t('Select calendar'), + '$delete' => t('Delete'), + '$delete_all' => t('Delete all'), + '$cancel' => t('Cancel'), + '$recurrence_warning' => t('Sorry! Editing of recurrent events is not yet implemented.') + ]); + + return $o; + + } + + //Provide json data for calendar + if(argc() == 5 && argv(1) === 'calendar' && argv(2) === 'json' && intval(argv(3)) && intval(argv(4))) { + + $id = [argv(3), argv(4)]; + + if(! cdav_perms($id[0],$calendars)) + killme(); + + if (x($_GET,'start')) + $start = new \DateTime($_GET['start']); + if (x($_GET,'end')) + $end = new \DateTime($_GET['end']); + + $filters['name'] = 'VCALENDAR'; + $filters['prop-filters'][0]['name'] = 'VEVENT'; + $filters['comp-filters'][0]['name'] = 'VEVENT'; + $filters['comp-filters'][0]['time-range']['start'] = $start; + $filters['comp-filters'][0]['time-range']['end'] = $end; + + $uris = $caldavBackend->calendarQuery($id, $filters); + if($uris) { + + $objects = $caldavBackend->getMultipleCalendarObjects($id, $uris); + + foreach($objects as $object) { + + $vcalendar = \Sabre\VObject\Reader::read($object['calendardata']); + + if(isset($vcalendar->VEVENT->RRULE)) + $vcalendar = $vcalendar->expand($start, $end); + + foreach($vcalendar->VEVENT as $vevent) { + $title = (string)$vevent->SUMMARY; + $dtstart = (string)$vevent->DTSTART; + $dtend = (string)$vevent->DTEND; + $description = (string)$vevent->DESCRIPTION; + $location = (string)$vevent->LOCATION; + + $rw = ((cdav_perms($id[0],$calendars,true)) ? true : false); + $recurrent = ((isset($vevent->{'RECURRENCE-ID'})) ? true : false); + + $editable = $rw ? true : false; + + if($recurrent) + $editable = false; + + $allDay = false; + + // allDay event rules + if(!strpos($dtstart, 'T') && !strpos($dtend, 'T')) + $allDay = true; + if(strpos($dtstart, 'T000000') && strpos($dtend, 'T000000')) + $allDay = true; + + $events[] = [ + 'calendar_id' => $id, + 'uri' => $object['uri'], + 'title' => $title, + 'start' => $dtstart, + 'end' => $dtend, + 'description' => $description, + 'location' => $location, + 'allDay' => $allDay, + 'editable' => $editable, + 'recurrent' => $recurrent, + 'rw' => $rw + ]; + } + } + json_return_and_die($events); + } + else { + killme(); + } + } + + //enable/disable calendars + if(argc() == 5 && argv(1) === 'calendar' && argv(2) === 'switch' && intval(argv(3)) && (argv(4) == 1 || argv(4) == 0)) { + $id = argv(3); + + if(! cdav_perms($id,$calendars)) + killme(); + + set_pconfig(local_channel(), 'cdav_calendar' , argv(3), argv(4)); + killme(); + } + + //drop calendar + if(argc() == 5 && argv(1) === 'calendar' && argv(2) === 'drop' && intval(argv(3)) && intval(argv(4))) { + $id = [argv(3), argv(4)]; + + if(! cdav_perms($id[0],$calendars)) + killme(); + + $caldavBackend->deleteCalendar($id); + killme(); + } + + //drop sharee + if(argc() == 6 && argv(1) === 'calendar' && argv(2) === 'dropsharee' && intval(argv(3)) && intval(argv(4))) { + + $id = [argv(3), argv(4)]; + $hash = argv(5); + + if(! cdav_perms($id[0],$calendars)) + killme(); + + $sharee_arr = channelx_by_hash($hash); + + $sharee = new \Sabre\DAV\Xml\Element\Sharee(); + + $sharee->href = 'mailto:' . $sharee_arr['channel_hash']; + $sharee->principal = 'principals/' . $sharee_arr['channel_address']; + $sharee->access = 4; + $caldavBackend->updateInvites($id, [$sharee]); + + killme(); + } + + + if(argv(1) === 'addressbook') { + $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo); + $addressbooks = $carddavBackend->getAddressBooksForUser($principalUri); + } + + //Display Adressbook here + if(argc() == 3 && argv(1) === 'addressbook' && intval(argv(2))) { + + $id = argv(2); + + $displayname = cdav_perms($id,$addressbooks); + + if(!$displayname) + return; + + head_add_css('cdav_addressbook.css'); + + $o = ''; + + $sabrecards = $carddavBackend->getCards($id); + foreach($sabrecards as $sabrecard) { + $uris[] = $sabrecard['uri']; + } + + if($uris) { + $objects = $carddavBackend->getMultipleCards($id, $uris); + + foreach($objects as $object) { + $vcard = \Sabre\VObject\Reader::read($object['carddata']); + + $photo = ''; + if($vcard->PHOTO) { + $photo_value = strtolower($vcard->PHOTO->getValueType()); // binary or uri + if($photo_value === 'binary') { + $photo_type = strtolower($vcard->PHOTO['TYPE']); // mime jpeg, png or gif + $photo = 'data:image/' . $photo_type . ';base64,' . base64_encode((string)$vcard->PHOTO); + } + else { + $url = parse_url((string)$vcard->PHOTO); + $photo = 'data:' . $url['path']; + } + } + + $fn = ''; + if($vcard->FN) { + $fn = (string)$vcard->FN; + } + + $org = ''; + if($vcard->ORG) { + $org = (string)$vcard->ORG; + } + + $title = ''; + if($vcard->TITLE) { + $title = (string)$vcard->TITLE; + } + + $tels = []; + if($vcard->TEL) { + foreach($vcard->TEL as $tel) { + $type = (($tel['TYPE']) ? translate_type((string)$tel['TYPE']) : ''); + $tels[] = [ + 'type' => $type, + 'nr' => (string)$tel + ]; + } + } + + $emails = []; + if($vcard->EMAIL) { + foreach($vcard->EMAIL as $email) { + $type = (($email['TYPE']) ? translate_type((string)$email['TYPE']) : ''); + $emails[] = [ + 'type' => $type, + 'address' => (string)$email + ]; + } + } + + $impps = []; + if($vcard->IMPP) { + foreach($vcard->IMPP as $impp) { + $type = (($impp['TYPE']) ? translate_type((string)$impp['TYPE']) : ''); + $impps[] = [ + 'type' => $type, + 'address' => (string)$impp + ]; + } + } + + $urls = []; + if($vcard->URL) { + foreach($vcard->URL as $url) { + $type = (($url['TYPE']) ? translate_type((string)$url['TYPE']) : ''); + $urls[] = [ + 'type' => $type, + 'address' => (string)$url + ]; + } + } + + $adrs = []; + if($vcard->ADR) { + foreach($vcard->ADR as $adr) { + $type = (($adr['TYPE']) ? translate_type((string)$adr['TYPE']) : ''); + $adrs[] = [ + 'type' => $type, + 'address' => $adr->getParts() + ]; + } + } + + $note = ''; + if($vcard->NOTE) { + $note = (string)$vcard->NOTE; + } + + $cards[] = [ + 'id' => $object['id'], + 'uri' => $object['uri'], + + 'photo' => $photo, + 'fn' => $fn, + 'org' => $org, + 'title' => $title, + 'tels' => $tels, + 'emails' => $emails, + 'impps' => $impps, + 'urls' => $urls, + 'adrs' => $adrs, + 'note' => $note + ]; + } + + usort($cards, function($a, $b) { return strcasecmp($a['fn'], $b['fn']); }); + } + + $o .= replace_macros(get_markup_template('cdav_addressbook.tpl'), [ + '$id' => $id, + '$cards' => $cards, + '$displayname' => $displayname, + '$name_label' => t('Name'), + '$org_label' => t('Organisation'), + '$title_label' => t('Title'), + '$tel_label' => t('Phone'), + '$email_label' => t('Email'), + '$impp_label' => t('Instant messenger'), + '$url_label' => t('Website'), + '$adr_label' => t('Address'), + '$note_label' => t('Note'), + '$mobile' => t('Mobile'), + '$home' => t('Home'), + '$work' => t('Work'), + '$other' => t('Other'), + '$add_card' => t('Add Contact'), + '$add_field' => t('Add Field'), + '$create' => t('Create'), + '$update' => t('Update'), + '$delete' => t('Delete'), + '$cancel' => t('Cancel'), + '$po_box' => t('P.O. Box'), + '$extra' => t('Additional'), + '$street' => t('Street'), + '$locality' => t('Locality'), + '$region' => t('Region'), + '$zip_code' => t('ZIP Code'), + '$country' => t('Country') + ]); + + return $o; + } + + //delete addressbook + if(argc() > 3 && argv(1) === 'addressbook' && argv(2) === 'drop' && intval(argv(3))) { + $id = argv(3); + + if(! cdav_perms($id,$addressbooks)) + return; + + $carddavBackend->deleteAddressBook($id); + killme(); + } + + } + + function activate($channel) { + + if(! $channel) + return; + + $uri = 'principals/' . $channel['channel_hash']; + + + $r = q("select * from principals where uri = '%s' limit 1", + dbesc($uri) + ); + if($r) { + $r = q("update principals set email = '%s', displayname = '%s' where uri = '%s' ", + dbesc($channel['xchan_addr']), + dbesc($channel['channel_name']), + dbesc($uri) + ); + } + else { + $r = q("insert into principals ( uri, email, displayname ) values('%s','%s','%s') ", + dbesc($uri), + dbesc($channel['xchan_addr']), + dbesc($channel['channel_name']) + ); + + //create default calendar + $r = q("insert into calendars (components) values('%s') ", + dbesc('VEVENT,VTODO') + ); + + $r = q("insert into calendarinstances (principaluri, displayname, uri, description, calendarcolor) values( '%s', '%s', '%s', '%s', '%s') ", + dbesc($uri), + dbesc(t('Default Calendar')), + dbesc('default'), + dbesc($channel['channel_name']), + dbesc('#3a87ad') + ); + + //create default addressbook + $r = q("insert into addressbooks (principaluri, displayname, uri) values('%s', '%s', '%s') ", + dbesc($uri), + dbesc(t('Default Addressbook')), + dbesc('default') + ); + } + } + + +} diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php index 98a1e6c88..51c937270 100644 --- a/Zotlabs/Module/Channel.php +++ b/Zotlabs/Module/Channel.php @@ -365,10 +365,10 @@ class Channel extends \Zotlabs\Web\Controller { if($checkjs->disabled()) { - $o .= conversation($a,$items,'channel',$update,'traditional'); + $o .= conversation($items,'channel',$update,'traditional'); } else { - $o .= conversation($a,$items,'channel',$update,$page_mode); + $o .= conversation($items,'channel',$update,$page_mode); } if((! $update) || ($checkjs->disabled())) { diff --git a/Zotlabs/Module/Chanview.php b/Zotlabs/Module/Chanview.php index 01ee74d5a..24ab9b022 100644 --- a/Zotlabs/Module/Chanview.php +++ b/Zotlabs/Module/Chanview.php @@ -102,27 +102,32 @@ class Chanview extends \Zotlabs\Web\Controller { } $is_zot = false; + $connected = false; if (\App::$poi) { $url = \App::$poi['xchan_url']; if(\App::$poi['xchan_network'] === 'zot') { $is_zot = true; } + if(local_channel()) { + $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s' limit 1", + intval(local_channel()), + dbesc(\App::$poi['xchan_hash']) + ); + if($c) + $connected = true; + } } - + // We will load the chanview template if it's a foreign network, // just so that we can provide a connect button along with a profile // photo. Chances are we can't load the remote profile into an iframe // because of cross-domain security headers. So provide a link to // the remote profile. - + // If we are already connected, just go to the profile. // Zot channels will usually have a connect link. - // If it isn't zot, 'pro' members won't be able to use the connect - // button as it is a foreign network so just send them to the remote - // profile. - - if($is_zot || \Zotlabs\Lib\System::get_server_role() === 'pro') { + if($is_zot || $connected) { if($is_zot && $observer) { $url = zid($url); } diff --git a/Zotlabs/Module/Cloud.php b/Zotlabs/Module/Cloud.php index 7370eeda3..75191a279 100644 --- a/Zotlabs/Module/Cloud.php +++ b/Zotlabs/Module/Cloud.php @@ -86,12 +86,13 @@ class Cloud extends \Zotlabs\Web\Controller { // require_once('\Zotlabs\Storage/QuotaPlugin.php'); // $server->addPlugin(new \Zotlabs\Storage\\QuotaPlugin($auth)); - ob_start(); +// ob_start(); // All we need to do now, is to fire up the server $server->exec(); - ob_end_flush(); - +// ob_end_flush(); + if($browser->build_page) + construct_page(); killme(); } diff --git a/Zotlabs/Module/Connections.php b/Zotlabs/Module/Connections.php index b079ae860..b3c5e8ee9 100644 --- a/Zotlabs/Module/Connections.php +++ b/Zotlabs/Module/Connections.php @@ -19,7 +19,7 @@ class Connections extends \Zotlabs\Web\Controller { } - function get() { + function get() { $sort_type = 0; $o = ''; @@ -63,8 +63,8 @@ class Connections extends \Zotlabs\Web\Controller { $hidden = true; break; case 'archived': - $search_flags = " and abook_archived = 1 "; - $head = t('Archived'); + $search_flags = " and ( abook_archived = 1 OR abook_not_here = 1) "; + $head = t('Archived/Unreachable'); $archived = true; break; case 'pending': @@ -168,10 +168,10 @@ class Connections extends \Zotlabs\Web\Controller { ), 'archived' => array( - 'label' => t('Archived'), + 'label' => t('Archived/Unreachable'), 'url' => z_root() . '/connections/archived', 'sel' => ($archived) ? 'active' : '', - 'title' => t('Only show archived connections'), + 'title' => t('Only show archived/unreachable connections'), ), 'hidden' => array( @@ -243,7 +243,8 @@ class Connections extends \Zotlabs\Web\Controller { ((intval($rr['abook_archived'])) ? t('Archived') : ''), ((intval($rr['abook_hidden'])) ? t('Hidden') : ''), ((intval($rr['abook_ignored'])) ? t('Ignored') : ''), - ((intval($rr['abook_blocked'])) ? t('Blocked') : '') + ((intval($rr['abook_blocked'])) ? t('Blocked') : ''), + ((intval($rr['abook_not_here'])) ? t('Not connected at this location') : '') ); foreach($status as $str) { @@ -257,11 +258,12 @@ class Connections extends \Zotlabs\Web\Controller { $contacts[] = array( 'img_hover' => sprintf( t('%1$s [%2$s]'),$rr['xchan_name'],$rr['xchan_url']), 'edit_hover' => t('Edit connection'), + 'edit' => t('Edit'), 'delete_hover' => t('Delete connection'), 'id' => $rr['abook_id'], 'thumb' => $rr['xchan_photo_m'], 'name' => $rr['xchan_name'], - 'classes' => (intval($rr['abook_archived']) ? 'archived' : ''), + 'classes' => ((intval($rr['abook_archived']) || intval($rr['abook_not_here'])) ? 'archived' : ''), 'link' => z_root() . '/connedit/' . $rr['abook_id'], 'deletelink' => z_root() . '/connedit/' . intval($rr['abook_id']) . '/drop', 'delete' => t('Delete'), diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php index 484e69b52..d301c2d45 100644 --- a/Zotlabs/Module/Connedit.php +++ b/Zotlabs/Module/Connedit.php @@ -842,6 +842,22 @@ class Connedit extends \Zotlabs\Web\Controller { } else $locstr = t('none'); + + $clone_warn = ''; + $clonable = (in_array($contact['xchan_network'],['zot','rss']) ? true : false); + if(! $clonable) { + $clone_warn = '<strong>'; + $clone_warn .= ((intval($contact['abook_not_here'])) + ? t('This connection is unreachable from this location.') + : t('This connection may be unreachable from other channel locations.') + ); + $clone_warn .= '</strong><br>' . t('Location independence is not supported by their network.'); + } + + + + if(intval($contact['abook_not_here']) && $unclonable) + $not_here = t('This connection is unreachable from this location. Location independence is not supported by their network.'); $o .= replace_macros($tpl, [ '$header' => (($self) ? t('Connection Default Permissions') : sprintf( t('Connection: %s'),$contact['xchan_name'])), @@ -856,6 +872,7 @@ class Connedit extends \Zotlabs\Web\Controller { '$addr_text' => t('This connection\'s primary address is'), '$loc_text' => t('Available locations:'), '$locstr' => $locstr, + '$unclonable' => $clone_warn, '$notself' => (($self) ? '' : '1'), '$self' => (($self) ? '1' : ''), '$autolbl' => t('The permissions indicated on this page will be applied to all new connections.'), diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php index 815672091..df3cb1e2b 100644 --- a/Zotlabs/Module/Display.php +++ b/Zotlabs/Module/Display.php @@ -308,12 +308,12 @@ class Display extends \Zotlabs\Web\Controller { if ($checkjs->disabled()) { - $o .= conversation($a, $items, 'display', $update, 'traditional'); + $o .= conversation($items, 'display', $update, 'traditional'); if ($items[0]['title']) \App::$page['title'] = $items[0]['title'] . " - " . \App::$page['title']; } else { - $o .= conversation($a, $items, 'display', $update, 'client'); + $o .= conversation($items, 'display', $update, 'client'); } if($updateable) { diff --git a/Zotlabs/Module/Editpost.php b/Zotlabs/Module/Editpost.php index 629bdd3fd..a54c42e7f 100644 --- a/Zotlabs/Module/Editpost.php +++ b/Zotlabs/Module/Editpost.php @@ -39,6 +39,11 @@ class Editpost extends \Zotlabs\Web\Controller { return; } + if($itm[0]['resource_type'] === 'photo' && $itm[0]['resource_id']) { + notice( t('Item is not editable') . EOL); + return; + } + if($itm[0]['resource_type'] === 'event' && $itm[0]['resource_id']) { goaway(z_root() . '/events/' . $itm[0]['resource_id'] . '?expandform=1'); } diff --git a/Zotlabs/Module/Hcard.php b/Zotlabs/Module/Hcard.php index 13097939e..912c84fd2 100644 --- a/Zotlabs/Module/Hcard.php +++ b/Zotlabs/Module/Hcard.php @@ -14,6 +14,8 @@ class Hcard extends \Zotlabs\Web\Controller { return; } + logger('hcard_request: ' . $which, LOGGER_DEBUG); + $profile = ''; $channel = \App::get_channel(); diff --git a/Zotlabs/Module/Help.php b/Zotlabs/Module/Help.php index e247416d9..0373a4aab 100644 --- a/Zotlabs/Module/Help.php +++ b/Zotlabs/Module/Help.php @@ -44,42 +44,42 @@ class Help extends \Zotlabs\Web\Controller { return $o; } - - - if(argc() > 2 && argv(argc()-2) === 'assets') { - $path = ''; - for($x = 1; $x < argc(); $x ++) { - if(strlen($path)) - $path .= '/'; - $path .= argv($x); - } - $realpath = 'doc/' . $path; - //Set the content-type header as appropriate - $imageInfo = getimagesize($realpath); - switch ($imageInfo[2]) { - case IMAGETYPE_JPEG: - header("Content-Type: image/jpeg"); - break; - case IMAGETYPE_GIF: - header("Content-Type: image/gif"); - break; - case IMAGETYPE_PNG: - header("Content-Type: image/png"); - break; - default: - break; - } - header("Content-Length: " . filesize($realpath)); + + + if(argc() > 2 && argv(argc()-2) === 'assets') { + $path = ''; + for($x = 1; $x < argc(); $x ++) { + if(strlen($path)) + $path .= '/'; + $path .= argv($x); + } + $realpath = 'doc/' . $path; + //Set the content-type header as appropriate + $imageInfo = getimagesize($realpath); + switch ($imageInfo[2]) { + case IMAGETYPE_JPEG: + header("Content-Type: image/jpeg"); + break; + case IMAGETYPE_GIF: + header("Content-Type: image/gif"); + break; + case IMAGETYPE_PNG: + header("Content-Type: image/png"); + break; + default: + break; + } + header("Content-Length: " . filesize($realpath)); - // dump the picture and stop the script - readfile($realpath); - killme(); - } + // dump the picture and stop the script + readfile($realpath); + killme(); + } $headings = [ - 'about' => t('About'), - 'member' => t('Members'), - 'admin' => t('Administrators'), + 'about' => t('About'), + 'member' => t('Members'), + 'admin' => t('Administrators'), 'developer' => t('Developers'), 'tutorials' => t('Tutorials') ]; @@ -87,13 +87,13 @@ class Help extends \Zotlabs\Web\Controller { if(array_key_exists(argv(1), $headings)) $heading = $headings[argv(1)]; - $content = get_help_content(); + $content = get_help_content(); return replace_macros(get_markup_template('help.tpl'), array( - '$title' => t('$Projectname Documentation'), + '$title' => t('$Projectname Documentation'), '$tocHeading' => t('Contents'), - '$content' => $content, - '$heading' => $heading + '$content' => $content, + '$heading' => $heading )); } diff --git a/Zotlabs/Module/Import.php b/Zotlabs/Module/Import.php index ce3fd469a..40ce8f6d1 100644 --- a/Zotlabs/Module/Import.php +++ b/Zotlabs/Module/Import.php @@ -121,8 +121,7 @@ class Import extends \Zotlabs\Web\Controller { $t = sprintf( t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1 ); notice($t); } - if(array_key_exists('server_role',$data['compatibility']) && $data['compatibility']['server_role'] == 'basic') - $moving = true; + } if($moving) @@ -333,6 +332,10 @@ class Import extends \Zotlabs\Web\Controller { $abook['abook_feed'] = (($abook['abook_flags'] & 0x0100 ) ? 1 : 0); } + if(array_key_exists('abook_instance',$abook) && $abook['abook_instance'] && strpos($abook['abook_instance'],z_root()) === false) { + $abook['abook_not_here'] = 1; + } + if($abook['abook_self']) { $role = get_pconfig($channel['channel_id'],'system','permissions_role'); if(($role === 'forum') || ($abook['abook_my_perms'] & PERMS_W_TAGWALL)) { diff --git a/Zotlabs/Module/Invite.php b/Zotlabs/Module/Invite.php index 6b6f80a31..927e7beae 100644 --- a/Zotlabs/Module/Invite.php +++ b/Zotlabs/Module/Invite.php @@ -49,7 +49,7 @@ class Invite extends \Zotlabs\Web\Controller { if(! $recip) continue; - if(! valid_email($recip)) { + if(! validate_email($recip)) { notice( sprintf( t('%s : Not a valid email address.'), $recip) . EOL); continue; } diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index 952ecf487..e96d4c669 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -818,7 +818,7 @@ class Item extends \Zotlabs\Web\Controller { $datarray['owner'] = $owner_xchan; $datarray['author'] = $observer; $datarray['attach'] = json_encode($datarray['attach']); - $o = conversation($a,array($datarray),'search',false,'preview'); + $o = conversation(array($datarray),'search',false,'preview'); // logger('preview: ' . $o, LOGGER_DEBUG); echo json_encode(array('preview' => $o)); killme(); diff --git a/Zotlabs/Module/Moderate.php b/Zotlabs/Module/Moderate.php index 92df58858..9af43420d 100644 --- a/Zotlabs/Module/Moderate.php +++ b/Zotlabs/Module/Moderate.php @@ -68,8 +68,7 @@ class Moderate extends \Zotlabs\Web\Controller { $items = array(); } - $o = conversation($a,$items,'moderate',false,'traditional'); - + $o = conversation($items,'moderate',false,'traditional'); return $o; } diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php index 1c7c70019..f2ad77dd7 100644 --- a/Zotlabs/Module/Network.php +++ b/Zotlabs/Module/Network.php @@ -551,7 +551,7 @@ class Network extends \Zotlabs\Web\Controller { $mode = (($nouveau) ? 'network-new' : 'network'); - $o .= conversation($a,$items,$mode,$update,$page_mode); + $o .= conversation($items,$mode,$update,$page_mode); if(($items) && (! $update)) $o .= alt_pager($a,count($items)); diff --git a/Zotlabs/Module/New_channel.php b/Zotlabs/Module/New_channel.php index 8e6fd1d37..cfd45e909 100644 --- a/Zotlabs/Module/New_channel.php +++ b/Zotlabs/Module/New_channel.php @@ -134,7 +134,7 @@ class New_channel extends \Zotlabs\Web\Controller { $name = array('name', t('Name or caption'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group"'), "*"); $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/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 role with your privacy requirements.') . ' <a href="help/member/member_guide#Account_Permission_Roles" target="_blank">' . t('Read more about roles') . '</a>',$perm_roles); $o = replace_macros(get_markup_template('new_channel.tpl'), array( '$title' => t('Create Channel'), diff --git a/Zotlabs/Module/Page.php b/Zotlabs/Module/Page.php index 7bc90c091..c142afe77 100644 --- a/Zotlabs/Module/Page.php +++ b/Zotlabs/Module/Page.php @@ -3,7 +3,6 @@ namespace Zotlabs\Module; require_once('include/items.php'); require_once('include/conversation.php'); -require_once('include/page_widgets.php'); class Page extends \Zotlabs\Web\Controller { diff --git a/Zotlabs/Module/Photo.php b/Zotlabs/Module/Photo.php index dc4ae670e..8a110f925 100644 --- a/Zotlabs/Module/Photo.php +++ b/Zotlabs/Module/Photo.php @@ -154,7 +154,9 @@ class Photo extends \Zotlabs\Web\Controller { intval($resolution) ); - if($r && $r[0]['photo_usage'] == PHOTO_COVER) + // viewing cover photos is allowed unless a plugin chooses to block it. + + if($r && intval($r[0]['photo_usage']) === PHOTO_COVER && $resolution >= PHOTO_RES_COVER_1200) $allowed = 1; $d = [ 'imgscale' => $resolution, 'resource_id' => $photo, 'photo' => $r, 'allowed' => $allowed ]; diff --git a/Zotlabs/Module/Poke.php b/Zotlabs/Module/Poke.php index cf8d83023..ea50e821a 100644 --- a/Zotlabs/Module/Poke.php +++ b/Zotlabs/Module/Poke.php @@ -41,7 +41,10 @@ class Poke extends \Zotlabs\Web\Controller { $activity = ACTIVITY_POKE . '#' . urlencode($verbs[$verb][0]); $contact_id = intval($_REQUEST['cid']); - if(! $contact_id) + + $xchan = trim($_REQUEST['xchan']); + + if(! ($contact_id || $xchan)) return; $parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : 0); @@ -49,13 +52,20 @@ class Poke extends \Zotlabs\Web\Controller { logger('poke: verb ' . $verb . ' contact ' . $contact_id, LOGGER_DEBUG); - $r = q("SELECT * FROM abook left join xchan on xchan_hash = abook_xchan where abook_id = %d and abook_channel = %d LIMIT 1", - intval($contact_id), - intval($uid) - ); - + if($contact_id) { + $r = q("SELECT * FROM abook left join xchan on xchan_hash = abook_xchan where abook_id = %d and abook_channel = %d LIMIT 1", + intval($contact_id), + intval($uid) + ); + } + if($xchan) { + $r = q("SELECT * FROM xchan where xchan_hash like ( '%s' ) LIMIT 1", + dbesc($xchan . '%') + ); + } + if(! $r) { - logger('poke: no target ' . $contact_id); + logger('poke: no target.'); return; } @@ -79,7 +89,7 @@ class Poke extends \Zotlabs\Web\Controller { $deny_gid = $r[0]['deny_gid']; } } - else { + elseif($contact_id) { $item_private = ((x($_GET,'private')) ? intval($_GET['private']) : 0); @@ -92,9 +102,11 @@ class Poke extends \Zotlabs\Web\Controller { $arr = array(); + + $arr['item_wall'] = 1; $arr['owner_xchan'] = (($parent_item) ? $parent_item['owner_xchan'] : $channel['channel_hash']); - $arr['parent_mid'] = (($parent_mid) ? $parent_mid : $mid); + $arr['parent_mid'] = (($parent_mid) ? $parent_mid : ''); $arr['title'] = ''; $arr['allow_cid'] = $allow_cid; $arr['allow_gid'] = $allow_gid; diff --git a/Zotlabs/Module/Pubstream.php b/Zotlabs/Module/Pubstream.php index 46210abb1..28c34425c 100644 --- a/Zotlabs/Module/Pubstream.php +++ b/Zotlabs/Module/Pubstream.php @@ -167,7 +167,7 @@ class Pubstream extends \Zotlabs\Web\Controller { // fake it $mode = ('network'); - $o .= conversation($a,$items,$mode,$update,$page_mode); + $o .= conversation($items,$mode,$update,$page_mode); if(($items) && (! $update)) $o .= alt_pager($a,count($items)); diff --git a/Zotlabs/Module/Register.php b/Zotlabs/Module/Register.php index 1d8944d8e..d4573156c 100644 --- a/Zotlabs/Module/Register.php +++ b/Zotlabs/Module/Register.php @@ -151,7 +151,7 @@ class Register extends \Zotlabs\Web\Controller { $new_channel = false; $next_page = 'new_channel'; - if(get_config('system','auto_channel_create') || get_config('system','server_role') == 'basic') { + if(get_config('system','auto_channel_create')) { $new_channel = auto_channel_create($result['account']['account_id']); if($new_channel['success']) { $channel_id = $new_channel['channel']['channel_id']; @@ -237,14 +237,12 @@ class Register extends \Zotlabs\Web\Controller { $name = array('name', t('Name or caption'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group"')); $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/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 role with your privacy requirements.') . ' <a href="help/member/member_guide#Account_Permission_Roles" target="_blank">' . t('Read more about roles') . '</a>',$perm_roles); $tos = array('tos', $label_tos, '', '', array(t('no'),t('yes'))); - $server_role = get_config('system','server_role'); - - $auto_create = (($server_role == 'basic') || (get_config('system','auto_channel_create')) ? true : false); - $default_role = (($server_role == 'basic') ? 'social' : get_config('system','default_permissions_role')); + $auto_create = (get_config('system','auto_channel_create') ? true : false); + $default_role = get_config('system','default_permissions_role'); require_once('include/bbcode.php'); diff --git a/Zotlabs/Module/Search.php b/Zotlabs/Module/Search.php index a78a023ff..2b949ebc7 100644 --- a/Zotlabs/Module/Search.php +++ b/Zotlabs/Module/Search.php @@ -225,7 +225,7 @@ class Search extends \Zotlabs\Web\Controller { else $o .= '<h2>' . sprintf( t('Search results for: %s'),htmlspecialchars($search, ENT_COMPAT,'UTF-8')) . '</h2>'; - $o .= conversation($a,$items,'search',$update,'client'); + $o .= conversation($items,'search',$update,'client'); $o .= '</div>'; diff --git a/Zotlabs/Module/Settings/Account.php b/Zotlabs/Module/Settings/Account.php index ec176797d..18890e89f 100644 --- a/Zotlabs/Module/Settings/Account.php +++ b/Zotlabs/Module/Settings/Account.php @@ -16,7 +16,7 @@ class Account { $account = \App::get_account(); if($email != $account['account_email']) { - if(! valid_email($email)) + if(! validate_email($email)) $errs[] = t('Not valid email.'); $adm = trim(get_config('system','admin_email')); if(($adm) && (strcasecmp($email,$adm) == 0)) { diff --git a/Zotlabs/Module/Settings/Channel.php b/Zotlabs/Module/Settings/Channel.php index 12ad25d51..3e6adcf8d 100644 --- a/Zotlabs/Module/Settings/Channel.php +++ b/Zotlabs/Module/Settings/Channel.php @@ -489,7 +489,6 @@ class Channel { '$h_prv' => t('Security and Privacy Settings'), '$permissions_set' => $permissions_set, - '$server_role' => \Zotlabs\Lib\System::get_server_role(), '$perms_set_msg' => t('Your permissions are already configured. Click to view/adjust'), '$hide_presence' => array('hide_presence', t('Hide my online presence'),$hide_presence, t('Prevents displaying in your profile that you are online'), $yes_no), diff --git a/Zotlabs/Module/Setup.php b/Zotlabs/Module/Setup.php index d4c31fd4e..e5b54cc5f 100644 --- a/Zotlabs/Module/Setup.php +++ b/Zotlabs/Module/Setup.php @@ -73,9 +73,6 @@ class Setup extends \Zotlabs\Web\Controller { $phpath = trim($_POST['phpath']); $adminmail = trim($_POST['adminmail']); $siteurl = trim($_POST['siteurl']); - $server_role = trim($_POST['server_role']); - if(! $server_role) - $server_role = 'standard'; // $siteurl should not have a trailing slash @@ -103,9 +100,6 @@ class Setup extends \Zotlabs\Web\Controller { $timezone = trim($_POST['timezone']); $adminmail = trim($_POST['adminmail']); $siteurl = trim($_POST['siteurl']); - $server_role = trim($_POST['server_role']); - if(! $server_role) - $server_role = 'standard'; if($siteurl != z_root()) { $test = z_fetch_url($siteurl."/setup/testrewrite"); @@ -134,7 +128,7 @@ class Setup extends \Zotlabs\Web\Controller { '$dbpass' => $dbpass, '$dbdata' => $dbdata, '$dbtype' => $dbtype, - '$server_role' => $server_role, + '$server_role' => 'pro', '$timezone' => $timezone, '$siteurl' => $siteurl, '$site_id' => random_string(), @@ -324,11 +318,6 @@ class Setup extends \Zotlabs\Web\Controller { $siteurl = trim($_POST['siteurl']); $timezone = ((x($_POST,'timezone')) ? ($_POST['timezone']) : 'America/Los_Angeles'); - $server_roles = [ - 'basic' => t('Basic/Minimal Social Networking'), - 'standard' => t('Standard Configuration (default)'), - 'pro' => t('Professional') - ]; $tpl = get_markup_template('install_settings.tpl'); $o .= replace_macros($tpl, array( @@ -348,8 +337,6 @@ class Setup extends \Zotlabs\Web\Controller { '$siteurl' => array('siteurl', t('Website URL'), z_root(), t('Please use SSL (https) URL if available.')), - '$server_role' => array('server_role', t("Server Configuration/Role"), 'standard','',$server_roles), - '$timezone' => array('timezone', t('Please select a default timezone for your website'), $timezone, '', get_timezones()), '$baseurl' => z_root(), diff --git a/Zotlabs/Module/Share.php b/Zotlabs/Module/Share.php index fcc2486ba..5c4811c59 100644 --- a/Zotlabs/Module/Share.php +++ b/Zotlabs/Module/Share.php @@ -76,7 +76,7 @@ class Share extends \Zotlabs\Web\Controller { $observer = \App::get_observer(); $parsed = $observer['xchan_url']; if($parsed) { - $post_url = $parsed['scheme'] . ':' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : '') + $post_url = $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : '') . '/rpost'; /** diff --git a/Zotlabs/Module/Token.php b/Zotlabs/Module/Token.php new file mode 100644 index 000000000..e0d9d74d7 --- /dev/null +++ b/Zotlabs/Module/Token.php @@ -0,0 +1,40 @@ +<?php + +namespace Zotlabs\Module; + + +class Token extends \Zotlabs\Web\Controller { + + + function get() { + + + // workaround for HTTP-auth in CGI mode + if (x($_SERVER, 'REDIRECT_REMOTE_USER')) { + $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)) ; + if(strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + } + + if (x($_SERVER, 'HTTP_AUTHORIZATION')) { + $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)) ; + if(strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + } + + + + + require_once('include/oauth2.php'); + $oauth2_server->handleTokenRequest(\OAuth2\Request::createFromGlobals())->send(); + + killme(); + } + +}
\ No newline at end of file diff --git a/Zotlabs/Module/Webpages.php b/Zotlabs/Module/Webpages.php index 641e84b70..d59fcdb9f 100644 --- a/Zotlabs/Module/Webpages.php +++ b/Zotlabs/Module/Webpages.php @@ -179,11 +179,8 @@ class Webpages extends \Zotlabs\Web\Controller { // so just list titles and an edit link. - /** @TODO - this should be replaced with pagelist_widget */ - $sql_extra = item_permissions_sql($owner); - $r = q("select * from iconfig left join item on iconfig.iid = item.id where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item_type = %d $sql_extra order by item.created desc", @@ -191,12 +188,6 @@ class Webpages extends \Zotlabs\Web\Controller { intval(ITEM_TYPE_WEBPAGE) ); -// $r = q("select * from item_id left join item on item_id.iid = item.id -// where item_id.uid = %d and service = 'WEBPAGE' and item_type = %d $sql_extra order by item.created desc", -// intval($owner), -// intval(ITEM_TYPE_WEBPAGE) -// ); - if(! $r) $x['pagetitle'] = 'home'; diff --git a/Zotlabs/Module/Wiki.php b/Zotlabs/Module/Wiki.php index 2f1fa01b7..85481754f 100644 --- a/Zotlabs/Module/Wiki.php +++ b/Zotlabs/Module/Wiki.php @@ -355,6 +355,7 @@ class Wiki extends \Zotlabs\Web\Controller { $html = Zlib\NativeWikiPage::convert_links(zidify_links(smilies(bbcode($content))),$wikiURL); } else { + $bb = Zlib\NativeWikiPage::bbcode($content); $x = new ZLib\MarkdownSoap($bb); $md = $x->clean(); diff --git a/Zotlabs/Module/Xrd.php b/Zotlabs/Module/Xrd.php index 7b36576e0..9630e9ab4 100644 --- a/Zotlabs/Module/Xrd.php +++ b/Zotlabs/Module/Xrd.php @@ -9,6 +9,7 @@ class Xrd extends \Zotlabs\Web\Controller { function init() { $uri = urldecode(notags(trim($_GET['uri']))); + $subject = $uri; logger('xrd: ' . $uri,LOGGER_DEBUG); $resource = $uri; @@ -30,13 +31,7 @@ class Xrd extends \Zotlabs\Web\Controller { ); if(! $r) killme(); - - $dspr = replace_macros(get_markup_template('xrd_diaspora.tpl'),array( - '$baseurl' => z_root(), - '$dspr_guid' => $r[0]['channel_guid'] . str_replace('.','',\App::get_hostname()), - '$dspr_key' => base64_encode(pemtorsa($r[0]['channel_pubkey'])) - )); - + $salmon_key = salmon_key($r[0]['channel_pubkey']); header('Access-Control-Allow-Origin: *'); @@ -49,11 +44,11 @@ class Xrd extends \Zotlabs\Web\Controller { if($aliases[$x] === $resource) unset($aliases[$x]); } - - + $o = replace_macros(get_markup_template('xrd_person.tpl'), array( '$nick' => $r[0]['channel_address'], '$accturi' => $resource, + '$subject' => $subject, '$aliases' => $aliases, '$profile_url' => z_root() . '/channel/' . $r[0]['channel_address'], '$hcard_url' => z_root() . '/hcard/' . $r[0]['channel_address'], @@ -61,12 +56,8 @@ class Xrd extends \Zotlabs\Web\Controller { '$zot_post' => z_root() . '/post/' . $r[0]['channel_address'], '$poco_url' => z_root() . '/poco/' . $r[0]['channel_address'], '$photo' => z_root() . '/photo/profile/l/' . $r[0]['channel_id'], - '$dspr' => $dspr, - // '$salmon' => z_root() . '/salmon/' . $r[0]['channel_address'], - // '$salmen' => z_root() . '/salmon/' . $r[0]['channel_address'] . '/mention', '$modexp' => 'data:application/magic-public-key,' . $salmon_key, '$subscribe' => z_root() . '/follow?url={uri}', - '$bigkey' => salmon_key($r[0]['channel_pubkey']) )); diff --git a/Zotlabs/Storage/Browser.php b/Zotlabs/Storage/Browser.php index 7162161ef..9dc393167 100644 --- a/Zotlabs/Storage/Browser.php +++ b/Zotlabs/Storage/Browser.php @@ -17,6 +17,7 @@ use Sabre\DAV; */ class Browser extends DAV\Browser\Plugin { + public $build_page = false; /** * @see set_writeable() * @see \\Sabre\\DAV\\Auth\\Backend\\BackendInterface @@ -257,7 +258,7 @@ class Browser extends DAV\Browser\Plugin { } } $this->server->httpResponse->setHeader('Content-Security-Policy', "script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'"); - construct_page(); + $this->build_page = true; } /** diff --git a/Zotlabs/Widget/Cdav.php b/Zotlabs/Widget/Cdav.php new file mode 100644 index 000000000..1b33668ad --- /dev/null +++ b/Zotlabs/Widget/Cdav.php @@ -0,0 +1,176 @@ +<?php + +namespace Zotlabs\Widget; + + + +class Cdav { + + function widget() { + if(!local_channel()) + return; + + $channel = \App::get_channel(); + $principalUri = 'principals/' . $channel['channel_hash']; + + if(!cdav_principal($principalUri)) + return; + + $pdo = \DBA::$dba->db; + + require_once 'vendor/autoload.php'; + + $o = ''; + + if(argc() == 2 && argv(1) === 'calendar') { + + $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); + + $sabrecals = $caldavBackend->getCalendarsForUser($principalUri); + + //TODO: we should probably also check for permission to send stream here + $local_channels = q("SELECT * FROM channel LEFT JOIN abook ON abook_xchan = channel_hash WHERE channel_system = 0 AND channel_removed = 0 AND channel_hash != '%s' AND abook_channel = %d", + dbesc($channel['channel_hash']), + intval($channel['channel_id']) + ); + + $sharee_options .= '<option value="">' . t('Select Channel') . '</option>' . "\r\n"; + foreach($local_channels as $local_channel) { + $sharee_options .= '<option value="' . $local_channel['channel_hash'] . '">' . $local_channel['channel_name'] . '</option>' . "\r\n"; + } + + $access_options = '<option value="3">' . t('Read-write') . '</option>' . "\r\n"; + $access_options .= '<option value="2">' . t('Read-only') . '</option>' . "\r\n"; + + //list calendars + foreach($sabrecals as $sabrecal) { + if($sabrecal['share-access'] == 1) + $access = ''; + if($sabrecal['share-access'] == 2) + $access = 'read'; + if($sabrecal['share-access'] == 3) + $access = 'read-write'; + + $invites = $caldavBackend->getInvites($sabrecal['id']); + + $json_source = '/cdav/calendar/json/' . $sabrecal['id'][0] . '/' . $sabrecal['id'][1]; + + $switch = get_pconfig(local_channel(), 'cdav_calendar', $sabrecal['id'][0]); + + $color = (($sabrecal['{http://apple.com/ns/ical/}calendar-color']) ? $sabrecal['{http://apple.com/ns/ical/}calendar-color'] : '#3a87ad'); + + $editable = (($sabrecal['share-access'] == 2) ? 'false' : 'true'); // false/true must be string since we're passing it to javascript + + $sharees = []; + $share_displayname = []; + foreach($invites as $invite) { + if(strpos($invite->href, 'mailto:') !== false) { + $sharee = channelx_by_hash(substr($invite->href, 7)); + $sharees[] = [ + 'name' => $sharee['channel_name'], + 'access' => (($invite->access == 3) ? ' (RW)' : ' (R)'), + 'hash' => $sharee['channel_hash'] + ]; + } + } + + if(!$access) { + $my_calendars[] = [ + 'ownernick' => $channel['channel_address'], + 'uri' => $sabrecal['uri'], + 'displayname' => $sabrecal['{DAV:}displayname'], + 'calendarid' => $sabrecal['id'][0], + 'instanceid' => $sabrecal['id'][1], + 'json_source' => $json_source, + 'color' => $color, + 'editable' => $editable, + 'switch' => $switch, + 'sharees' => $sharees + ]; + } + else { + $shared_calendars[] = [ + 'ownernick' => $channel['channel_address'], + 'uri' => $sabrecal['uri'], + 'displayname' => $sabrecal['{DAV:}displayname'], + 'calendarid' => $sabrecal['id'][0], + 'instanceid' => $sabrecal['id'][1], + 'json_source' => $json_source, + 'color' => $color, + 'editable' => $editable, + 'switch' => $switch, + 'sharer' => $sabrecal['{urn:ietf:params:xml:ns:caldav}calendar-description'], + 'access' => $access + ]; + } + + if(!$access || $access === 'read-write') { + $writable_calendars[] = [ + 'displayname' => ((!$access) ? $sabrecal['{DAV:}displayname'] : $share_displayname[0]), + 'id' => $sabrecal['id'] + ]; + } + } + + $o .= replace_macros(get_markup_template('cdav_widget_calendar.tpl'), [ + '$my_calendars_label' => t('My Calendars'), + '$my_calendars' => $my_calendars, + '$shared_calendars_label' => t('Shared Calendars'), + '$shared_calendars' => $shared_calendars, + '$sharee_options' => $sharee_options, + '$access_options' => $access_options, + '$share_label' => t('Share this calendar'), + '$share' => t('Share'), + '$edit_label' => t('Calendar name and color'), + '$edit' => t('Edit'), + '$create_label' => t('Create new calendar'), + '$create' => t('Create'), + '$create_placeholder' => t('Calendar Name'), + '$tools_label' => t('Calendar Tools'), + '$import_label' => t('Import calendar'), + '$import_placeholder' => t('Select a calendar to import to'), + '$upload' => t('Upload'), + '$writable_calendars' => $writable_calendars + ]); + + return $o; + + } + + if(argc() >= 2 && argv(1) === 'addressbook') { + + $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo); + + $sabreabooks = $carddavBackend->getAddressBooksForUser($principalUri); + + //list addressbooks + foreach($sabreabooks as $sabreabook) { + $addressbooks[] = [ + 'ownernick' => $channel['channel_address'], + 'uri' => $sabreabook['uri'], + 'displayname' => $sabreabook['{DAV:}displayname'], + 'id' => $sabreabook['id'] + + ]; + } + + $o .= replace_macros(get_markup_template('cdav_widget_addressbook.tpl'), [ + '$addressbooks_label' => t('Addressbooks'), + '$addressbooks' => $addressbooks, + '$edit_label' => t('Addressbook name'), + '$edit' => t('Edit'), + '$create_label' => t('Create new addressbook'), + '$create_placeholder' => t('Addressbook Name'), + '$create' => t('Create'), + '$tools_label' => t('Addressbook Tools'), + '$import_label' => t('Import addressbook'), + '$import_placeholder' => t('Select an addressbook to import to'), + '$upload' => t('Upload') + ]); + + return $o; + + } + + } +}
\ No newline at end of file diff --git a/Zotlabs/Widget/Conversations.php b/Zotlabs/Widget/Conversations.php index 27e517c02..4fd754f66 100644 --- a/Zotlabs/Widget/Conversations.php +++ b/Zotlabs/Widget/Conversations.php @@ -12,10 +12,6 @@ class Conversations { if(argc() > 1) { switch(argv(1)) { - case 'combined': - $mailbox = 'combined'; - $header = t('Conversations'); - break; case 'inbox': $mailbox = 'inbox'; $header = t('Received Messages'); @@ -58,7 +54,7 @@ class Conversations { 'body' => $rr['body'], 'date' => datetime_convert('UTC',date_default_timezone_get(),$rr['created'], 'c'), 'seen' => $rr['seen'], - 'selected' => ((argv(2)) ? (argv(2) == $rr['id']) : ($r[0]['id'] == $rr['id'])) + 'selected' => ((argc() == 2) ? (intval(argv(1)) == intval($rr['id'])) : ($r[0]['id'] == $rr['id'])) ); } @@ -71,4 +67,6 @@ class Conversations { } return $o; } + } + diff --git a/Zotlabs/Widget/Settings_menu.php b/Zotlabs/Widget/Settings_menu.php index 753390c23..c15ad0980 100644 --- a/Zotlabs/Widget/Settings_menu.php +++ b/Zotlabs/Widget/Settings_menu.php @@ -79,11 +79,13 @@ class Settings_menu { 'selected' => '' ); - $tabs[] = array( - 'label' => t('Connected apps'), - 'url' => z_root() . '/settings/oauth', - 'selected' => ((argv(1) === 'oauth') ? 'active' : ''), - ); + if(get_account_techlevel() > 0) { + $tabs[] = array( + 'label' => t('Connected apps'), + 'url' => z_root() . '/settings/oauth', + 'selected' => ((argv(1) === 'oauth') ? 'active' : ''), + ); + } if(get_account_techlevel() > 2) { $tabs[] = array( diff --git a/Zotlabs/Widget/Tasklist.php b/Zotlabs/Widget/Tasklist.php index 6f7a8aaed..3961eecce 100644 --- a/Zotlabs/Widget/Tasklist.php +++ b/Zotlabs/Widget/Tasklist.php @@ -8,8 +8,8 @@ class Tasklist { function widget($arr) { - if (! local_channel()) - return; + if (! local_channel()) + return; $o .= '<script>var tasksShowAll = 0; $(document).ready(function() { tasksFetch(); $("#tasklist-new-form").submit(function(event) { event.preventDefault(); $.post( "tasks/new", $("#tasklist-new-form").serialize(), function(data) { tasksFetch(); $("#tasklist-new-summary").val(""); } ); return false; } )});</script>'; $o .= '<script>function taskComplete(id) { $.post("tasks/complete/"+id, function(data) { tasksFetch();}); } diff --git a/app/apps.apd b/app/apps.apd new file mode 100644 index 000000000..c063f8f19 --- /dev/null +++ b/app/apps.apd @@ -0,0 +1,5 @@ +version: 2 +url: $baseurl/apps +name: Apps +photo: icon:bars +categories: System @@ -49,8 +49,8 @@ require_once('include/hubloc.php'); require_once('include/attach.php'); -define ( 'PLATFORM_NAME', 'hubzilla' ); -define ( 'STD_VERSION', '2.5.5' ); +define ( 'PLATFORM_NAME', 'red' ); +define ( 'STD_VERSION', '5.3' ); define ( 'ZOT_REVISION', '1.2' ); define ( 'DB_UPDATE_VERSION', 1191 ); @@ -82,7 +82,6 @@ define ( 'DIRECTORY_REALM', 'RED_GLOBAL'); define ( 'DIRECTORY_FALLBACK_MASTER', 'https://gravizot.de'); $DIRECTORY_FALLBACK_SERVERS = array( - //'https://hubzilla.site', 'https://hubzilla.zottel.net', 'https://my.federated.social', 'https://hubzilla.nl', @@ -162,14 +161,6 @@ define ( 'LOGGER_ALL', 4 ); /** - * Server roles - */ - -define ( 'SERVER_ROLE_BASIC', 0x0001 ); -define ( 'SERVER_ROLE_STANDARD', 0x0002 ); -define ( 'SERVER_ROLE_PRO', 0x0004 ); - -/** * registration policies */ @@ -600,29 +591,20 @@ function sys_boot() { $a->convert(); - if(defined('UNO')) { - if(UNO) - App::$config['system']['server_role'] = 'basic'; - else - App::$config['system']['server_role'] = 'standard'; - } - - if(! (array_key_exists('server_role',App::$config['system']) && App::$config['system']['server_role'])) - App::$config['system']['server_role'] = 'standard'; + App::$config['system']['server_role'] = 'pro'; App::$timezone = ((App::$config['system']['timezone']) ? App::$config['system']['timezone'] : 'UTC'); date_default_timezone_set(App::$timezone); if(! defined('DEFAULT_PLATFORM_ICON')) { - define( 'DEFAULT_PLATFORM_ICON', '/images/hz-32.png' ); + define( 'DEFAULT_PLATFORM_ICON', '/images/rm-32.png' ); } if(! defined('DEFAULT_NOTIFY_ICON')) { - define( 'DEFAULT_NOTIFY_ICON', '/images/hz-white-32.png' ); + define( 'DEFAULT_NOTIFY_ICON', '/images/rm-32.png' ); } - /* * Try to open the database; */ @@ -733,7 +715,6 @@ class miniApp { class App { public static $install = false; // true if we are installing the software - public static $role = 0; // server role (constant, not the string) public static $account = null; // account record of the logged-in account public static $channel = null; // channel record of the current channel of the logged-in account public static $observer = null; // xchan record of the page observer @@ -1008,36 +989,10 @@ class App { } } - public static function get_role() { - if(! self::$role) - return self::set_role(); - return self::$role; - } - - public static function set_role() { - $role_str = \Zotlabs\Lib\System::get_server_role(); - switch($role_str) { - case 'basic': - $role = SERVER_ROLE_BASIC; - break; - case 'pro': - $role = SERVER_ROLE_PRO; - break; - case 'standard': - default: - $role = SERVER_ROLE_STANDARD; - break; - } - self::$role = $role; - return $role; - } - - public static function get_scheme() { return self::$scheme; } - public static function get_hostname() { return self::$hostname; } @@ -1151,24 +1106,25 @@ class App { * since the code added by the modules frequently depends on it * being first */ - $tpl = get_markup_template('head.tpl'); - self::$page['htmlhead'] = replace_macros($tpl, array( - '$preload_images' => $preload_images, - '$user_scalable' => $user_scalable, - '$query' => urlencode(self::$query_string), - '$baseurl' => self::get_baseurl(), - '$local_channel' => local_channel(), - '$metas' => self::$meta->get(), - '$plugins' => $x['header'], - '$update_interval' => $interval, - 'osearch' => sprintf( t('Search %1$s (%2$s)','opensearch'), Zotlabs\Lib\System::get_site_name(), t('$Projectname','opensearch')), - '$head_css' => head_get_css(), - '$head_js' => head_get_js(), - '$linkrel' => head_get_links(), - '$js_strings' => js_strings(), - '$zid' => get_my_address(), - '$channel_id' => self::$profile['uid'], - )) . self::$page['htmlhead']; + + self::$page['htmlhead'] = replace_macros(get_markup_template('head.tpl'), + [ + '$preload_images' => $preload_images, + '$user_scalable' => $user_scalable, + '$query' => urlencode(self::$query_string), + '$baseurl' => self::get_baseurl(), + '$local_channel' => local_channel(), + '$metas' => self::$meta->get(), + '$plugins' => $x['header'], + '$update_interval' => $interval, + '$head_css' => head_get_css(), + '$head_js' => head_get_js(), + '$linkrel' => head_get_links(), + '$js_strings' => js_strings(), + '$zid' => get_my_address(), + '$channel_id' => self::$profile['uid'] + ] + ) . self::$page['htmlhead']; // always put main.js at the end self::$page['htmlhead'] .= head_get_main_js(); @@ -1181,11 +1137,13 @@ class App { * @param string $name */ public static function register_template_engine($class, $name = '') { - if ($name === ""){ - $v = get_class_vars( $class ); - if(x($v, "name")) $name = $v['name']; + if(! $name) { + $v = get_class_vars($class); + if(x($v, "name")) { + $name = $v['name']; + } } - if ($name === ""){ + if (! $name) { echo "template engine <tt>$class</tt> cannot be registered without a name.\n"; killme(); } @@ -1201,19 +1159,21 @@ class App { * @return object Template Engine instance */ public static function template_engine($name = ''){ - if ($name !== "") { + if($name !== '') { $template_engine = $name; - } else { + } + else { $template_engine = 'smarty3'; - if (x(self::$theme, 'template_engine')) { + if(x(self::$theme, 'template_engine')) { $template_engine = self::$theme['template_engine']; } } - if (isset(self::$template_engines[$template_engine])){ + if(isset(self::$template_engines[$template_engine])){ if(isset(self::$template_engine_instance[$template_engine])){ return self::$template_engine_instance[$template_engine]; - } else { + } + else { $class = self::$template_engines[$template_engine]; $obj = new $class; self::$template_engine_instance[$template_engine] = $obj; @@ -1221,7 +1181,8 @@ class App { } } - echo "template engine <tt>$template_engine</tt> is not registered!\n"; killme(); + echo "template engine <tt>$template_engine</tt> is not registered!\n"; + killme(); } /** @@ -2336,6 +2297,7 @@ function cert_bad_email() { ) ] ); + } diff --git a/doc/about/about_hubzilla.bb b/doc/about/about.bb index bf42446a7..b927e80c0 100644 --- a/doc/about/about_hubzilla.bb +++ b/doc/about/about.bb @@ -1,7 +1,7 @@ -[h3]What is Hubzilla?[/h3] +[h3]What is $Projectname?[/h3] $Projectname is a [b]free and open source[/b] set of web applications and services running on a special kind of web server, called a "hub", that can connect to other hubs in a decentralised network we like to call "the grid", providing sophisticated communications, identity, and access control services which work together seamlessly across domains and independent websites. It allows anybody to publicly or [b]privately[/b] publish content via "channels", which are the fundamental, cryptographically secured identities that provide authentication independently of the hubs which host them. This revolutionary liberation of online identity from individual servers and domains is called "nomadic identity", and it is powered by the Zot protocol, a new framework for decentralised access control with fine-grained, extensible permissions. -[h3]Right... so what is Hubzilla?[/h3] +[h3]Right... so what is $Projectname?[/h3] From the practical perspective of hub members who use the software, $Projectname offers a variety of familiar, integrated web apps and services, including: [ul] [li]social networking discussion threads[/li] @@ -15,14 +15,9 @@ While all of these apps and services can be found in other software packages, on [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. -[h3]Additional Resources and Links[/h3] -[list][*][url=http://hubzilla.org]Hubzilla project website[/url] -[*][url=https://github.com/redmatrix/hubzilla]Hubzilla core code repository[/url] -[*][url=https://github.com/redmatrix/hubzilla-addons]Hubzilla official addons repository[/url][/list] - [h3]Glossary[/h3] [dl terms="b"] -[*= hub] An instance of the Hubzilla software running on a standard web server +[*= hub] An instance of this software running on a standard web server [*= grid] The global network of hubs that exchange information with each other using the Zot protocol. diff --git a/doc/about/hubzilla_project.bb b/doc/about/project.bb index f9bc920f8..f9bc920f8 100644 --- a/doc/about/hubzilla_project.bb +++ b/doc/about/project.bb diff --git a/doc/addons.bb b/doc/addons.bb index 6fa9510f5..d49694030 100644 --- a/doc/addons.bb +++ b/doc/addons.bb @@ -23,7 +23,7 @@ [*] friendica - Friendica (DFRN) protocol. Under development. [*] frphotos - import photo albums from Friendica [*] gnusoc - GNU-Social (OStatus) protocol. Under development. -[*] hexit - headecimal conversion tool +[*] hexit - hexadecimal conversion tool [*] hubwall - send an admin email to all hub accounts [*] ijpost - crosspost to Insanejournal [*] irc - connect to IRC chatrooms diff --git a/doc/admin/administrator_guide.md b/doc/admin/administrator_guide.md index c233d8564..de64d5e8b 100644 --- a/doc/admin/administrator_guide.md +++ b/doc/admin/administrator_guide.md @@ -150,7 +150,7 @@ web-based administrative tools to function: #### Official addons ##### Installation -Navigate to your webThen 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:: +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 @@ -162,7 +162,7 @@ For keeping the addon tree updated, you should be on your top level website dire util/update_addon_repo hzaddons Create searchable representations of the online documentation. You may do this - any time that the documentation is updated : +any time that the documentation is updated : cd mywebsite util/importdoc @@ -196,59 +196,35 @@ The installation script was originally designed for a small hardware server behi 1. `service apache2 reload` 1. Open your domain with a browser and step throught the initial configuration of $Projectname. -### Server Roles +### Recommended Addons -$Projectname can be configured in many different ways. One of the configurations available at installation is to select a 'server role'. There are currently three server roles. We highly recommend that you use 'standard' unless you have special needs. +We recommend the following addons be installed on all public sites: + nsfw - hide inappropriate posts/comments + superblock - block content from offensive channels -#### Basic +### Federation Addons -The 'basic' server role is designed to be relatively simple, and it doesn't present options -or complicated features. The hub admin may configure additional features at a site level. -This role is designed for simple social networking and social network federation. Many features -which do not federate easily have been removed, including (and this is somewhat important) -"nomadic identity". You may move a channel to or from a basic server, but you may not clone -it. Once moved, it becomes read-only on the origination site. No updates of any kind will be -provided. It is recommended that after the move, the original channel be deleted - as it is -no longer useable. The data remains only in case there are issues making a copy of the data. +Several web communities have begun to converge using common protocols. The protocols involved are somewhat limited in their abilities. The GNU-Social protocol for instance offers no privacy modes, and the Diaspora protocol is somewhat restrictive in what kinds of communications are allowed. All comments must be signed in a very unique manner by the original author. The ActivityPub protocol is also being considered and may be supported at a future date. No other existing protocol supports nomadic location as used by this project. This presents some support challenges as some features work with some networks and don't work with others. Nevertheless the federation protocols allow connections to be made to a much larger community of people worldwide. They are provided as addons. -This role is supported by the hubzilla community. +> diaspora - The Diaspora Protocol used by Diaspora and Friendica. You should enable 'Diaspora Statistics' (statistics_json) first to enable all the available features. -#### Standard +> gnusoc - The GNU-Social Protocol, used by GNU-Social, Mastodon and several other communities. This addon requires you first install the 'pubsubhubbub' service (also an addon). +Each member of your site must choose whether or not to allow these protocols individually as they may conflict with several desirable core features and abilities of this software (such as channel migration and cloning). They do this from their 'Settings -> Feature/Addon Settings' page. The administrator may also set the following: -The 'standard' server role is recommended for most sites. All features of the software are -available to everybody unless locked by the hub administrator. Some features will not federate -easily with other networks, so there is often an increased support burden explaining why -sharing events with Diaspora (for instance) presents a different experience on that network. -Additionally any member can enable "advanced" or "expert" features, and these may be beyond -their technical skill level. This may also result in an increased support burden. + util/config system.diaspora_allowed 1 + util/config system.gnusoc_allowed 1 -This role is supported by the hubzilla community. +and enable these protocols automatically for all newly created channels. -#### Pro -The 'pro' server role is primarily designed for communities which want to present a uniform -experience and be relieved of many federation support issues. In this role there is -**no federation with other networks**. Additional features **may** be provided, such -as channel ratings, premium channels, and e-commerce. -By default a channel may set a "techlevel" appropriate to their technical skill. Higher -levels provide more features. Everybody starts with techlevel 0 (similar to the 'basic' -role) where all complicated features are hidden from view. Increasing the techlevel provides -more advanced or complex features. + -The hub admin may also lock individual channels or their entire site at a defined techlevel -which provides an installation with a selection of advanced features consistent with the -perceived technical skills of the members. For instance, a community for horse racing might -have a different techlevel than a community for Linux kernel developers. - -This role is not supported by the hubzilla community. ### Techlevels -Techlevels is a unique feature of Hubzilla 'pro'. It is not available in other server_roles, although it expands on the concepts introduced in $Projectname 'basic'. - We've implemented several different mechanisms in order to reduce the apparent complexity and learning curve presented to new members. At the same time, we do not wish to limit any functionality for people who are able to grasp some slightly advanced technical technical features. The first mechanism was to move several features to an optional 'Features' page where they could be enabled at will; with the default interface kept somewhat lean. The problem we had now is that the number of features began to grow dramatically, and the Feature page is daunting in possibilities. There are also features present which probably should not be available to all members, but may be extremely useful to those with technical backgrounds. @@ -257,8 +233,7 @@ The techlevels seeeks to remedy this by grouping features within different level When a new member registers, their account is provided a techlevel setting of 0. On the account settings page they may change this to any available level. A higher level opens more advanced features and possible interactions. -The account administrator may also lock a particular level, lock a maximum level, or change/re-arrange the features available to any level. Those with the minimum level are typically not very exploratory and are unlikely to discover the advanced modes. This is by design. Those that look around and desire more interactions will find them. In the absence of administrator defaults they may choose any level. As they look at the features available to the level in question, it is generally expected that they will discover some features are beyond their comprehension and it is hoped they will back off to a level where the interface and features are comfortable to their skill level. This is somewhat experimental at present and for that reason is not part of the 'standard' server role. The standard server role is preset to level '5', and the basic server role is preset to level '0', with no possibility of change. Members in these roles may find themselves overwhelmed or underwhelmed by the feature set and complexity. - +The account administrator may also lock a particular level, lock a maximum level, or change/re-arrange the features available to any level. Those with the minimum level are typically not very exploratory and are unlikely to discover the advanced modes. This is by design. Those that look around and desire more interactions will find them. In the absence of administrator defaults they may choose any level. As they look at the features available to the level in question, it is generally expected that they will discover some features are beyond their comprehension and it is hoped they will back off to a level where the interface and features are comfortable to their skill level. ### Service Classes diff --git a/doc/hook/legal_webbie.bb b/doc/hook/legal_webbie.bb new file mode 100644 index 000000000..8c7d32d56 --- /dev/null +++ b/doc/hook/legal_webbie.bb @@ -0,0 +1,10 @@ +[h2]legal_webbie[/h2] + +Called when validating a channel address. By default the valid characters are +a-z,0-9,-,_, and . Uppercase ASCII characters are folded to lower and any invalid characters are stripped. + +Some federated networks require more restrictive rules. + +The hook is called with an array [ 'input' => (supplied text), 'output' => (validated text) ] + +A plugin will generally perform a regex filter or text operation on 'input' and provide the results in 'output'.
\ No newline at end of file diff --git a/doc/hook/legal_webbie_text.bb b/doc/hook/legal_webbie_text.bb new file mode 100644 index 000000000..32c74c93b --- /dev/null +++ b/doc/hook/legal_webbie_text.bb @@ -0,0 +1,7 @@ +[h2]legal_webbie_text[/h2] + +Returns a string describing the text rules applied to legal_webbie(). + +Called with an array [ 'text' => (descriptive text describing text character limitations) ] + +A plugin should return the description of the allowed characters and operation performed in the 'legal_webbie' hook to assist people when creating a new channel.
\ No newline at end of file diff --git a/doc/hooklist.bb b/doc/hooklist.bb index a9ba73e97..da4d9596b 100644 --- a/doc/hooklist.bb +++ b/doc/hooklist.bb @@ -323,6 +323,12 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the [zrl=[baseurl]/help/hook/jot_tool]jot_tool[/zrl] Deprecated and possibly obsolete. Allows one to add action buttons to the post editor. +[zrl=[baseurl]/help/hook/legal_webbie]legal_webbie[/zrl] + Called to validate a channel address + +[zrl=[baseurl]/help/hook/legal_webbie_text]legal_webbie_text[/zrl] + Provides an explanation of text/character restrictions for legal_webbie() + [zrl=[baseurl]/help/hook/load_pdl]load_pdl[/zrl] Called when we load a PDL file or description diff --git a/doc/member/member_guide.bb b/doc/member/member_guide.bb index 3e5172c23..0a2d11a88 100644 --- a/doc/member/member_guide.bb +++ b/doc/member/member_guide.bb @@ -697,14 +697,8 @@ This places a block named "contributors" in this region. Additionally The variable [var=wrap]none[/var] in a block removes the wrapping div element from the block. [h4]Widgets[/h4] -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 +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. System widgets are listed [url=help/Widgets]here[/url]. Widgets can also ve created by plugins, themes, or your site administrator to provide additional functionality. -[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] diff --git a/doc/toc.html b/doc/toc.html index 78cc74979..9e34fc8d9 100644 --- a/doc/toc.html +++ b/doc/toc.html @@ -7,8 +7,8 @@ </div> <div id="about" class="doco-section"> <div class="flex-column"> - <a class="nav-link" href="/help/about/about_hubzilla">About Hubzilla</a> - <a class="nav-link" href="/help/about/hubzilla_project">Hubzilla project</a> + <a class="nav-link" href="/help/about/about">About</a> + <a class="nav-link" href="/help/about/project">Project</a> <a class="nav-link" href="/help/about/about_hub">About this hub</a> </div> </div> diff --git a/doc/tutorials/personal_channel.html b/doc/tutorials/personal_channel.html index f2ad87077..9dbc2aaec 100644 --- a/doc/tutorials/personal_channel.html +++ b/doc/tutorials/personal_channel.html @@ -6,7 +6,7 @@ to a personal channel in a natural way.</p> <h3 id="Create_a_new_channel">Create a new channel</h3> <p>When you log in for the first time after registering, you must create a channel. -(Alternatively you can load https://grid.reticu.li/new_channel)</p> +(Alternatively you can visit https://your_website/new_channel)</p> <p><img class="img-responsive" src="/help/tutorials/assets/c9a880cc82ffa1f7c2f460397bb083bf7dc2a2b8f065e64da598b45b4a2b.png" alt="image"></p> @@ -76,7 +76,7 @@ so you can specify exactly who can access this post.</p> <h3 id="Use_an_uploaded_image_as_a_channel_cover_photo">Use an uploaded image as a channel cover photo</h3> <p>One way to add some pizzazz your channel is to add a cover photo that visitors will -see when they load your channel page. Hubzilla's integrated cloud file system +see when they load your channel page. The integrated cloud file system allows you to choose an existing photo for this purpose.</p> <p>Visit your photos in the <strong>Photos</strong> app</p> @@ -99,9 +99,9 @@ channel page will fade in as you scroll down.</p> <h3 id="Make_a_connection">Make a connection</h3> -<p>Making connections between channels to share things is what Hubzilla is all about. +<p>Making connections between channels to share things is what social communications are all about. Making a connection is simple. If you do not already know how to reach a channel's home -page, you might try a directory search by opening the <strong>Directory</strong> link on the right +page, you might try a directory search by opening the <strong>Directory</strong> link from the menu on the right side of the top navbar.</p> <p><img class="img-responsive" src="/help/tutorials/assets/ef78bc6aa3fafebd46f353514c907b3fdfe019918fc5553bb3f31388a36f.png" alt="image"></p> @@ -160,4 +160,4 @@ editor by pressing the edit button beside the <strong>Delete</strong> button.</p <p><img class="img-responsive" src="/help/tutorials/assets/c4cad3e4c356dd2a227df79bd4dc6d47edf1b66ea243f005b6b452ec366b.png" alt="image"></p> -
\ No newline at end of file + diff --git a/images/red-koala.jpg b/images/red-koala.jpg Binary files differnew file mode 100644 index 000000000..4cbedd264 --- /dev/null +++ b/images/red-koala.jpg diff --git a/images/red-koala.png b/images/red-koala.png Binary files differnew file mode 100644 index 000000000..005a37fe2 --- /dev/null +++ b/images/red-koala.png diff --git a/images/red-koala.svg b/images/red-koala.svg new file mode 100644 index 000000000..f303b32dd --- /dev/null +++ b/images/red-koala.svg @@ -0,0 +1,151 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + width="744.09448" + height="1052.3622" + id="svg2" + inkscape:version="0.48.2 r9819" + sodipodi:docname="red-koala.svg"> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="640" + inkscape:window-height="480" + id="namedview26" + showgrid="false" + inkscape:zoom="0.50332378" + inkscape:cx="476.12273" + inkscape:cy="572.78569" + inkscape:window-x="38" + inkscape:window-y="616" + inkscape:window-maximized="0" + inkscape:current-layer="svg2" /> + <defs + id="defs4" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + id="layer1" + transform="translate(0.17560932,-0.17560932)"> + <path + d="" + id="path6167" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.08838835;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + <path + d="m 497.9857,1088.5424 c 0,-16.225 0.13752,-22.8625 0.30561,-14.75 0.16808,8.1125 0.16808,21.3875 0,29.5 -0.16809,8.1125 -0.30561,1.475 -0.30561,-14.75 z m 290.93182,18.5 c -0.002,-6.05 0.1606,-8.6539 0.36191,-5.7865 0.2013,2.8674 0.20315,7.8174 0.004,11 -0.19905,3.1826 -0.36376,0.8365 -0.36601,-5.2135 z m 17.08867,-37.5 c 0,-26.675 0.12889,-37.5875 0.28641,-24.25 0.15752,13.3375 0.15752,35.1625 0,48.5 -0.15752,13.3375 -0.28641,2.425 -0.28641,-24.25 z m 27.96202,27 c 0,-11.825 0.14466,-16.6625 0.32145,-10.75 0.1768,5.9125 0.1768,15.5875 0,21.5 -0.17679,5.9125 -0.32145,1.075 -0.32145,-10.75 z m -495.42476,10.5 c 1.29175,-1.375 2.57363,-2.5 2.84863,-2.5 0.275,0 -0.55688,1.125 -1.84863,2.5 -1.29175,1.375 -2.57363,2.5 -2.84863,2.5 -0.275,0 0.55688,-1.125 1.84863,-2.5 z m 68.27083,-7.1042 c 0.33229,-0.3322 1.19479,-0.3678 1.91667,-0.079 0.79773,0.3193 0.56078,0.5562 -0.60417,0.6042 -1.05416,0.043 -1.64479,-0.1929 -1.3125,-0.5252 z m 376.47917,-3.0581 c 0.6875,-0.2774 1.8125,-0.2774 2.5,0 0.6875,0.2774 0.125,0.5044 -1.25,0.5044 -1.375,0 -1.9375,-0.227 -1.25,-0.5044 z m -462.75,-2.8377 c 0.68469,-0.825 1.46989,-1.5 1.74489,-1.5 0.275,0 -0.0602,0.675 -0.74489,1.5 -0.68469,0.825 -1.46989,1.5 -1.74489,1.5 -0.275,0 0.0602,-0.675 0.74489,-1.5 z m 303.07895,-3.9167 c -0.0434,-1.0541 0.19293,-1.6447 0.52522,-1.3125 0.33229,0.3323 0.36781,1.1948 0.0789,1.9167 -0.31922,0.7977 -0.55618,0.5608 -0.60416,-0.6042 z m -281.80812,-4.1875 c 0.33229,-0.3322 1.19479,-0.3678 1.91667,-0.079 0.79773,0.3193 0.56078,0.5562 -0.60417,0.6042 -1.05416,0.043 -1.64479,-0.1929 -1.3125,-0.5252 z m 20.80812,-11.8125 c -0.0434,-1.0541 0.19292,-1.6447 0.52522,-1.3125 0.33229,0.3323 0.36781,1.1948 0.0789,1.9167 -0.31922,0.7977 -0.55618,0.5608 -0.60416,-0.6042 z m 0.0789,-7.5833 c 0,-1.375 0.22698,-1.9375 0.50439,-1.25 0.27741,0.6875 0.27741,1.8125 0,2.5 -0.27741,0.6875 -0.50439,0.125 -0.50439,-1.25 z m 477.84211,-13.5 c 0.68469,-0.825 1.46989,-1.5 1.74489,-1.5 0.275,0 -0.0602,0.675 -0.74489,1.5 -0.68469,0.825 -1.46989,1.5 -1.74489,1.5 -0.275,0 0.0602,-0.675 0.74489,-1.5 z m -588.60544,-20 c 0.002,-7.7 0.15853,-10.7178 0.34883,-6.7062 0.1903,4.0115 0.18902,10.3115 -0.003,14 -0.19189,3.6884 -0.34759,0.4062 -0.34603,-7.2938 z m 606,0 c 0.002,-7.7 0.15853,-10.7178 0.34883,-6.7062 0.1903,4.0115 0.18902,10.3115 -0.003,14 -0.19169,3.6884 -0.34739,0.4062 -0.34583,-7.2938 z m -585.39456,-1 c 1.29175,-1.375 2.57363,-2.5 2.84863,-2.5 0.275,0 -0.55688,1.125 -1.84863,2.5 -1.29175,1.375 -2.57363,2.5 -2.84863,2.5 -0.275,0 0.55688,-1.125 1.84863,-2.5 z m 454.75,-11.2322 c 2.3375,-0.2105 6.1625,-0.2105 8.5,0 2.3375,0.2105 0.425,0.3828 -4.25,0.3828 -4.675,0 -6.5875,-0.1723 -4.25,-0.3828 z m 43.96349,0 c 2.86742,-0.2013 7.81742,-0.2032 11,0 3.18258,0.1991 0.83651,0.3638 -5.21349,0.366 -6.05,0 -8.65393,-0.1606 -5.78651,-0.3619 z m 106.03651,-9.0063 c 3.9875,-0.1898 10.5125,-0.1898 14.5,0 3.9875,0.1898 0.725,0.3451 -7.25,0.3451 -7.975,0 -11.2375,-0.1553 -7.25,-0.3451 z M 454.81581,605.54241 c 0,-2.475 0.19502,-3.4875 0.43337,-2.25 0.23836,1.2375 0.23836,3.2625 0,4.5 -0.23835,1.2375 -0.43337,0.225 -0.43337,-2.25 z m -16.34805,-45.75 -2.42431,-2.75 2.75,2.42431 c 1.5125,1.33338 2.75,2.57088 2.75,2.75 0,0.78428 -0.8098,0.14598 -3.07569,-2.42431 z m 130.82569,-1.99507 c 5.0875,-0.18149 13.4125,-0.18149 18.5,0 5.0875,0.18149 0.925,0.32999 -9.25,0.32999 -10.175,0 -14.3375,-0.1485 -9.25,-0.32999 z m 159.5,-0.004 c 14.1625,-0.15649 37.3375,-0.15649 51.5,0 14.1625,0.15649 2.575,0.28452 -25.75,0.28452 -28.325,0 -39.9125,-0.12803 -25.75,-0.28452 z m 208.5,3e-5 c 13.8875,-0.15682 36.6125,-0.15682 50.5,0 13.88755,0.15682 2.525,0.28513 -25.25,0.28513 -27.775,0 -39.1375,-0.12831 -25.25,-0.28513 z M 388.81428,541.93824 c 0.33229,-0.33229 1.19479,-0.36781 1.91667,-0.0789 0.79773,0.31922 0.56078,0.55618 -0.60417,0.60416 -1.05416,0.0434 -1.64479,-0.19293 -1.3125,-0.52522 z" + id="path6242" + style="fill:#5f5b5b" + inkscape:connector-curvature="0" /> + <path + d="m 552.98651,1088.0424 c -4.5e-4,-16.5 0.13655,-23.3903 0.30444,-15.3118 0.16789,8.0785 0.16826,21.5785 8.2e-4,30 -0.16745,8.4215 -0.30481,1.8118 -0.30526,-14.6882 z m 54.80912,26 c -0.0111,-2.2 0.18461,-3.2177 0.4349,-2.2617 0.25029,0.9561 0.25937,2.7561 0.0202,4 -0.23919,1.244 -0.44398,0.4617 -0.45508,-1.7383 z m -105.25218,-86 c 0.68469,-0.825 1.46989,-1.5 1.74489,-1.5 0.275,0 -0.0602,0.675 -0.74489,1.5 -0.68469,0.825 -1.46989,1.5 -1.74489,1.5 -0.275,0 0.0602,-0.675 0.74489,-1.5 z m 41.40499,-0.75 -1.90499,-2.25 2.25,1.905 c 2.11444,1.7902 2.70524,2.595 1.90499,2.595 -0.18976,0 -1.20226,-1.0125 -2.25,-2.25 z m 117.86584,-7.3542 c 0.33229,-0.3322 1.19479,-0.3678 1.91667,-0.079 0.79773,0.3193 0.56078,0.5562 -0.60417,0.6042 -1.05416,0.043 -1.64479,-0.1929 -1.3125,-0.5252 z M 545.72943,857.7944 c 9.17729,-0.16487 24.47729,-0.16517 34,-6.6e-4 9.52271,0.16451 2.01402,0.29941 -16.68598,0.29977 -18.7,3.6e-4 -26.49131,-0.13424 -17.31402,-0.29911 z m 183.06402,-10e-4 c 14.1625,-0.15649 37.3375,-0.15649 51.5,0 14.1625,0.15649 2.575,0.28452 -25.75,0.28452 -28.325,0 -39.9125,-0.12803 -25.75,-0.28452 z m 208.5,3e-5 c 13.8875,-0.15682 36.6125,-0.15682 50.5,0 13.88745,0.15682 2.525,0.28513 -25.25,0.28513 -27.775,0 -39.1375,-0.12831 -25.25,-0.28513 z M 382.78179,541.85533 c 0.95609,-0.25029 2.75609,-0.25937 4,-0.0202 1.24391,0.23919 0.46166,0.44398 -1.73834,0.45508 -2.2,0.0111 -3.21775,-0.18461 -2.26166,-0.4349 z m 139.26166,-55.31292 c -1.5808,-1.65 -2.64918,-3 -2.37418,-3 0.275,0 1.79338,1.35 3.37418,3 1.5808,1.65 2.64918,3 2.37418,3 -0.275,0 -1.79338,-1.35 -3.37418,-3 z" + id="path6236" + style="fill:#292222" + inkscape:connector-curvature="0" /> + <g + id="g6312"> + <g + id="g6286"> + <g + transform="translate(43.475438,27.243334)" + id="g6190"> + <g + id="g6035" + style="stroke:#000000;stroke-width:0.69999999;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"> + <path + d="m 230.00007,643.07523 c -3.43799,-0.73575 -5.99718,-1.74825 -5.68708,-2.25 0.3101,-0.50175 0.12499,-0.91227 -0.41135,-0.91227 -1.48706,0 -8.54066,-7.1481 -10.08081,-10.21587 -0.74992,-1.49373 -1.69468,-2.51118 -2.09947,-2.26101 -0.40479,0.25017 -1.34946,-0.32769 -2.09928,-1.28413 -1.2337,-1.57367 -1.19694,-1.60851 0.38669,-0.36655 1.82477,1.43109 2.46942,0.24698 0.78342,-1.43902 -0.99993,-0.99993 -5.85993,-14.40317 -6.50264,-17.93342 -0.20026,-1.1 -0.42292,-2 -0.49479,-2 -0.80622,0 -0.75379,-10.80804 0.0645,-13.29479 0.5963,-1.81214 1.42743,-5.63714 1.84696,-8.5 1.01816,-6.94791 1.28046,-7.7525 3.17755,-9.74688 0.89375,-0.93958 1.79375,-2.12857 2,-2.64219 0.6726,-1.67498 11.51235,-9.31614 13.21587,-9.31614 0.91252,0 1.65913,-0.46973 1.65913,-1.04384 0,-0.57411 0.5625,-0.95313 1.25,-0.84228 0.6875,0.11086 2.03333,-0.14096 2.99074,-0.5596 0.9574,-0.41863 3.9949,-0.56502 6.75,-0.32531 2.75509,0.23972 5.00926,0.0613 5.00926,-0.39656 0,-0.45783 0.47656,-0.83241 1.05902,-0.83241 0.58246,0 0.79485,0.42742 0.47199,0.94983 -0.51182,0.82814 2.33166,3.05017 3.90325,3.05017 1.48687,0 0.34183,-2.0101 -1.18426,-2.07895 -0.9625,-0.0434 -1.2463,-0.28632 -0.63067,-0.53977 0.80908,-0.3331 0.75814,-1.5092 -0.1838,-4.2432 -1.6748,-4.86113 -1.58978,-22.34502 0.14495,-29.80756 0.72638,-3.12478 1.11621,-6.01227 0.86629,-6.41664 -0.45531,-0.73672 3.57389,-13.97353 4.53969,-14.91388 0.28245,-0.275 1.38572,-2.21316 2.45172,-4.30703 1.066,-2.09387 2.94358,-4.89187 4.17239,-6.21777 1.22881,-1.32591 2.51101,-3.28292 2.84934,-4.3489 0.7171,-2.25937 11.83409,-14.1263 13.23359,-14.1263 0.52178,0 3.06923,-2.03183 5.661,-4.51518 l 4.7123,-4.51517 -3.47612,-3.57925 c -1.91186,-1.96858 -3.94674,-3.28838 -4.52194,-2.93288 -0.58125,0.35923 -0.84131,0.068 -0.58544,-0.65558 0.60298,-1.70518 -1.691,-4.6672 -3.5363,-4.56613 -5.13701,0.28137 -7.97051,-0.4819 -10.09204,-2.71853 -1.29523,-1.3655 -2.7246,-2.4905 -3.17639,-2.5 -1.88718,-0.0397 -8.08561,-8.54966 -7.23261,-9.92984 0.31483,-0.50941 -0.10671,-1.60534 -0.93677,-2.43539 -0.83005,-0.83006 -1.50919,-2.11633 -1.50919,-2.85838 0,-0.74205 -0.7875,-2.06805 -1.75,-2.94666 -5.45757,-4.98188 -7.84532,-8.79242 -10.76413,-17.17818 -2.03246,-5.83926 -2.92733,-9.89511 -2.46426,-11.16883 0.39992,-1.1 0.3336,-2.75804 -0.14738,-3.68453 -1.00661,-1.93897 0.14895,-5.54804 3.06731,-9.57991 1.08904,-1.50456 2.22871,-4.91121 2.53261,-7.57033 0.30389,-2.65913 1.24741,-5.52965 2.0967,-6.37894 0.8493,-0.84929 1.31621,-2.13823 1.03759,-2.8643 -0.32214,-0.83947 0.021,-1.11767 0.94249,-0.76407 0.98287,0.37716 1.44907,-0.12181 1.44907,-1.55093 0,-1.2555 0.63987,-2.10699 1.58333,-2.10699 0.87084,0 1.39046,-0.5625 1.15471,-1.25 -0.62048,-1.80954 5.44327,-8.54821 9.59822,-10.66652 3.70647,-1.88967 7.8224,-1.93142 20.16374,-0.20452 3.3,0.46176 6.15761,0.70779 6.35024,0.54673 0.19263,-0.16106 2.79027,1.02727 5.77254,2.64074 2.98226,1.61346 6.06164,2.93357 6.84306,2.93357 0.78141,0 2.09306,0.95986 2.91478,2.13302 0.99008,1.41354 2.17361,1.95531 3.50876,1.60616 1.1081,-0.28978 2.16007,-0.0908 2.33771,0.44209 0.19299,0.57898 3.38657,0.2344 7.93498,-0.85616 5.60405,-1.34367 9.90949,-1.69322 16.32165,-1.32511 4.79031,0.275 8.94555,0.11745 9.23386,-0.35012 0.73918,-1.19874 13.76024,0.44069 18.84022,2.37209 1.43552,0.54579 3.03342,0.73067 3.55089,0.41085 0.51748,-0.31981 0.81721,-0.0717 0.66609,0.55133 -0.15113,0.62304 1.41272,1.72847 3.47522,2.45649 2.0625,0.72803 3.75,1.09661 3.75,0.81908 0,-0.27754 0.675,0.0556 1.5,0.74028 1.03636,0.8601 1.5,0.89795 1.5,0.12244 0,-0.61734 0.6794,-1.12244 1.50979,-1.12244 0.83038,0 2.28039,-0.9 3.22224,-2 0.94185,-1.1 2.43486,-2 3.3178,-2 0.88295,0 4.49544,-1.18497 8.02776,-2.63327 8.46052,-3.46892 14.63942,-3.97669 17.37205,-1.42762 1.1277,1.05195 3.3242,2.22889 4.88112,2.61544 1.55692,0.38654 3.06757,1.3199 3.35699,2.07413 0.28943,0.75422 1.12457,1.37132 1.85588,1.37132 0.75838,0 1.46428,1.353 1.64301,3.14915 0.1875,1.88431 1.11665,3.5913 2.31336,4.25 1.1,0.60547 2.22893,1.40174 2.50874,1.7695 0.2798,0.36775 2.0798,0.81775 4,1 2.27368,0.21579 3.50048,0.85448 3.51769,1.83135 0.0145,0.825 0.35938,2.03141 0.76631,2.6809 0.40694,0.6495 0.2487,1.48447 -0.35163,1.8555 -0.71159,0.43978 -0.31705,1.49898 1.13348,3.043 1.98819,2.11632 2.04669,2.43683 0.54968,3.01128 -1.38588,0.53182 -1.45495,0.90995 -0.39979,2.18872 1.03517,1.25456 1.03212,1.62774 -0.0162,1.98047 -0.99232,0.33388 -1.02188,0.75978 -0.12755,1.83738 0.73955,0.8911 0.82539,1.85868 0.23535,2.65275 -0.51086,0.6875 -0.88128,2.57782 -0.82317,4.20072 0.0581,1.6229 -0.67967,3.73606 -1.63952,4.69591 -1.26468,1.26468 -1.59142,2.69275 -1.1867,5.1867 0.42623,2.6266 0.078,3.92203 -1.47076,5.47076 -1.11608,1.11608 -1.77762,2.28087 -1.47008,2.58841 0.30755,0.30754 0.0263,1.20128 -0.62507,1.98609 -0.91938,1.10779 -0.89534,1.54346 0.1075,1.94803 0.83366,0.33632 0.93712,0.81408 0.29174,1.34725 -0.55,0.45437 -1.13902,1.72613 -1.30894,2.82613 -0.16991,1.1 -1.10266,3.125 -2.07278,4.5 -0.97011,1.375 -2.40344,3.9625 -3.18517,5.75 -1.03908,2.37593 -2.09527,3.27123 -3.92722,3.32895 -1.37824,0.0434 -1.94339,0.30592 -1.25589,0.58333 1.88994,0.76261 1.50594,2.12802 -1,3.55578 -1.2375,0.70507 -2.25,1.95694 -2.25,2.78194 0,0.825 -0.675,1.41017 -1.5,1.30038 -0.825,-0.1098 -2.43628,1.2402 -3.58062,3 -1.14434,1.75979 -2.61936,3.08295 -3.27782,2.94034 -1.08968,-0.23598 -1.45305,0.37488 -2.74933,4.6219 -0.32054,1.05021 -0.73669,1.0964 -1.81504,0.20145 -0.99034,-0.82192 -1.59437,-0.84529 -2.06734,-0.08 -0.44576,0.72125 -1.76948,0.40055 -3.97628,-0.96333 -3.11614,-1.92587 -7.17568,-1.86871 -5.96881,0.084 0.3043,0.49237 0.14557,0.89522 -0.35273,0.89522 -1.51282,0 -5.22477,3.65392 -4.47432,4.40437 0.38573,0.38574 -0.0725,0.40441 -1.01819,0.0415 -1.24342,-0.47714 -1.72376,-0.14568 -1.73483,1.19715 -0.0131,1.58573 -0.17028,1.63788 -1.07613,0.35699 -0.94295,-1.33333 -1.01588,-1.33333 -0.65636,0 0.22245,0.825 1.38171,1.6438 2.57613,1.81955 1.19442,0.17575 2.17167,0.73825 2.17167,1.25 0,0.51175 0.70156,0.93045 1.55902,0.93045 0.85746,0 1.31241,0.39901 1.01101,0.88669 -0.30141,0.48768 0.12204,1.44278 0.94098,2.12245 1.00214,0.8317 1.48899,0.87575 1.48899,0.13474 0,-1.50115 4.95297,0.59164 7.16029,3.02546 0.91316,1.00687 1.92566,1.83066 2.25,1.83066 1.34484,0 4.72208,4.29595 7.25599,9.22983 1.48864,2.89859 3.52272,6.34336 4.52017,7.65503 0.99745,1.31167 1.81355,3.07624 1.81355,3.92126 0,0.84502 0.72,2.33199 1.6,3.30438 0.88,0.97239 1.6,3.43675 1.6,5.47636 0,2.03962 0.76793,5.10446 1.70651,6.81077 0.93858,1.7063 1.61471,4.79182 1.50251,6.85671 -0.1122,2.06489 0.20721,4.00848 0.7098,4.3191 0.50259,0.31061 0.67661,0.94855 0.3867,1.41762 -0.2899,0.46908 -0.76403,3.92549 -1.05361,7.68091 -0.28959,3.75541 -0.71708,8.48392 -0.94998,10.50777 -0.2329,2.02386 0.003,3.82386 0.5249,4 0.52709,0.178 0.28756,1.5926 -0.53924,3.18457 -0.81817,1.57537 -1.48759,3.61274 -1.48759,4.52749 0,0.91475 -0.70052,2.66332 -1.5567,3.88569 -0.87255,1.24574 -1.0923,2.22251 -0.5,2.22251 0.58118,0 1.0567,-0.5051 1.0567,-1.12244 0,-0.792 0.42748,-0.76768 1.45201,0.0826 0.79861,0.66279 2.29858,0.93638 3.33327,0.60798 1.03469,-0.3284 3.81286,0.0844 6.17371,0.91738 2.36086,0.83296 6.23433,1.51447 8.60772,1.51447 2.37339,0 4.61956,0.49238 4.99149,1.09417 0.37193,0.60179 1.76406,0.88622 3.09363,0.63206 1.32956,-0.25417 2.23378,-0.27851 2.00937,-0.0541 -0.2244,0.22441 1.91928,2.75397 4.76374,5.62125 6.91688,6.97236 6.84708,6.79218 7.96086,20.54842 0.37147,4.58799 0.71492,8.63799 0.76322,9 0.0483,0.36201 0.0337,0.79697 -0.10711,1.1582 -0.80187,2.05678 -1.31054,4.99435 -1.34682,7.77778 -0.0235,1.80277 -0.41672,1.48669 -0.74391,2.14323 -0.15813,0.31731 0.25315,0.79264 -0.63886,0.98195 -0.37621,0.60872 -0.45106,0.16598 -0.58513,0.9003 -0.0521,0.28524 -0.25816,0.17907 -0.74263,0.68717 -0.43248,0.45357 -0.35784,-0.0516 -0.66596,0.89743 -0.31216,0.96149 -0.20602,0.77316 -0.22528,1.16979 -0.0334,0.68828 -0.15481,0.85715 0.19242,2.05829 0.143,0.49469 -0.42203,1.27822 -0.89555,2.24755 -0.88043,1.80233 -0.25484,1.80931 -2.10364,2.00505 -0.26599,0.0282 0.44276,-0.20257 -1.17031,0.10247 -0.97461,0.1843 -1.19198,1.67998 -0.96659,2.29972 0.22539,0.61973 -1.01695,0.42266 -2.90511,3.15273 -2.25936,3.26679 -3.52602,1.58301 -4.03544,3.64173 -0.54849,2.21667 0.58003,0.14982 -0.11326,1.62782 -1.05669,2.25269 -0.47931,1.15177 -0.88709,1.80055 0,0 -0.22285,0.54501 -0.88857,0.87087 -0.44625,0.21842 1.17998,-0.12796 -2.60139,0.47671 -0.63646,0.29734 -0.46202,-0.80807 -3.19227,1.72224 l -2.76552,2.563 -22.1305,-0.23761 c -15.88014,-0.1705 -23.06085,-0.62092 -25.42453,-1.59481 -1.81171,-0.74645 -3.73536,-1.08443 -4.27478,-0.75105 -0.53941,0.33338 -0.8571,0.0102 -0.70598,-0.71819 0.16117,-0.77676 -0.44879,-1.20284 -1.47522,-1.03049 -0.9625,0.16161 -1.75,-0.25089 -1.75,-0.91667 0,-0.66578 -0.27444,-0.93607 -0.60986,-0.60064 -0.78027,0.78026 -7.41837,-3.39567 -10.84536,-6.82266 -1.44854,-1.44854 -3.25963,-2.39353 -4.02464,-2.09997 -0.76501,0.29356 -1.5575,0.034 -1.76109,-0.57674 -0.20359,-0.61077 -1.78787,-1.11049 -3.52062,-1.11049 -1.73275,0 -2.90921,-0.39034 -2.61436,-0.86741 0.29485,-0.47708 -0.35864,-1.51606 -1.91518,-1.22854 -1.55654,0.28751 -11.53389,1.69766 -21.70889,2.05337 -14.52324,0.50772 -19.12609,-3.02326 -21.87373,-1.66976 -1.925,0.94825 -7.96545,6.36524 -12.49725,8.6425 -4.53181,2.27733 -8.72086,4.14055 -9.30903,4.14055 -0.58816,0 -0.1631,1.70754 0.17292,2.25124 0.3629,0.58718 -0.0858,0.72119 -1.10503,0.33006 -1.25638,-0.48212 -1.49674,-0.30375 -0.89743,0.66596 0.5495,0.88911 0.43265,1.08594 -0.3555,0.59884 -1.02239,-0.63187 -5.26154,0.26637 -10.13496,2.1475 -3.07686,1.18766 -31.55601,0.75877 -37.7587,-0.56864 z" + id="path3028" + style="fill:#ff0000;fill-opacity:1;stroke:#000000;stroke-width:0.69999999;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cssssssssssssssscsssssscssscsssssscsssssssssssssssssssscssssssscsscsccsssssssssscssssscscssssssssssccssssscssscscsssscssccssssscsssssssssssccsscssssssssssscsssssscsssasssssssscscscssscsscsscssssscsscssssc" /> + <path + d="m 335.35714,412.00504 c 7.82838,2.22626 13.55258,9.07397 16.11064,16.58597 1.77331,5.10242 2.2904,10.63429 1.66409,15.98751 -0.69791,5.10295 -3.46584,10.04442 -8.00784,12.65844 -7.35888,4.77106 -18.18995,4.75934 -24.65496,-1.57547 -4.82902,-5.00061 -6.04119,-12.54296 -4.81793,-19.19027 1.46182,-8.18673 6.2227,-15.59326 12.57325,-20.87012 2.41956,-1.79458 5.22351,-3.69025 8.38275,-3.41755" + id="path3800" + style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + <path + d="m 310.53571,412.36218 c -1.40641,-1.17116 -3.58861,-1.66135 -5.16196,-0.51893 -2.22395,1.52051 -3.19556,4.27879 -3.55744,6.84075 -0.33384,2.53795 0.27807,5.51425 2.44186,7.10488 1.90236,1.39111 4.56075,0.65579 6.25684,-0.72054 1.97274,-1.54803 3.35558,-4.07045 3.02805,-6.62562 0.37908,-2.01145 -0.015,-4.50186 -1.88689,-5.65872 -0.34622,-0.20237 -0.72717,-0.34426 -1.12046,-0.42182 z" + id="path3843" + style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + <path + d="m 362.32143,415.04075 c 1.82028,-0.2869 3.79491,0.35598 4.9485,1.82847 1.8159,2.28393 2.02126,5.56951 0.97481,8.2301 -0.74786,1.96459 -2.45847,3.56523 -4.53699,3.99866 -2.04621,0.51877 -4.27055,-0.27745 -5.67674,-1.81667 -2.21845,-2.35017 -3.09901,-6.10321 -1.64239,-9.07066 0.7981,-1.56589 2.2933,-2.80679 4.01266,-3.20954 0.63251,-0.12753 1.2939,-0.11857 1.92015,0.0396 z" + id="path3860" + style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + <path + d="m 313.21429,418.25504 c -0.65312,0.86871 -1.78813,1.29333 -2.8566,1.15862 -1.51532,-0.1724 -2.94976,-1.09631 -3.68229,-2.44106 -0.48041,-0.86232 -0.47858,-1.97724 0.0673,-2.80913 0.63734,-1.05476 1.94102,-1.71218 3.16653,-1.43208 1.54168,0.34032 2.74335,1.63795 3.2515,3.09573 0.26622,0.77734 0.31965,1.64275 0.0536,2.42792 z" + id="path3876" + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + <path + d="m 368.21429,421.46932 c -0.55015,0.72499 -1.45802,1.18031 -2.37461,1.09864 -1.30459,-0.10649 -2.47133,-0.95018 -3.16425,-2.03402 -0.49974,-0.77749 -0.73307,-1.82753 -0.25762,-2.67243 0.38894,-0.68396 1.10834,-1.14173 1.85648,-1.33873 0.96656,-0.2404 1.98591,0.18488 2.64956,0.89186 0.93289,0.98053 1.46507,2.36797 1.3435,3.72376 -0.012,0.11111 -0.0295,0.22166 -0.0531,0.33092 z" + id="path3895" + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + <path + d="m 303.04576,597.66727 c 0.89898,4.35249 2.17849,8.87576 1.08581,13.31695 -0.98289,3.59314 -0.74817,7.37439 -1.46656,11.01441 -0.0643,0.90932 -0.11707,1.84689 -0.50302,2.68838" + id="path6133" + style="fill:none;stroke:#000000;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + <path + d="m 349.51278,594.76308 c -1.58181,2.33253 -1.39144,5.56411 -3.53003,7.56876 -0.74878,3.62541 -0.71177,7.35102 -1.21455,11.00843 -0.10351,3.82135 -0.0162,7.71947 1.08376,11.4103" + id="path6143" + style="fill:none;stroke:#000000;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + </g> + <path + d="m 409.49059,562.817 c -6.67512,0.0141 -12.72539,2.68679 -18.37595,5.87319 -5.33515,2.18172 -7.45099,7.69796 -12.7301,9.94852 -4.12835,4.17446 -7.57404,7.9756 -11.12192,12.52392 -2.6138,5.46222 -7.29966,10.95705 -13.63968,6.46078 -4.52118,-3.54734 -10.14186,-6.62102 -12.94899,-11.82544 -2.65925,-5.83356 -3.26085,-12.84467 -1.90417,-19.32125 0.65245,-6.59597 4.3386,-12.21307 7.7841,-17.72679 2.52977,-5.2597 6.29469,-8.24419 7.64728,-13.87964 2.44434,-5.87935 2.40037,-12.09314 2.93216,-18.33486 0.0486,-2.55913 0.45478,-5.2273 -0.67574,-7.63532" + id="path6125" + style="fill:none;stroke:#000000;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + <path + d="m 247.99245,560.54416 c 6.76369,0.22082 13.24135,2.3829 18.17002,6.74782 3.36251,5.76075 8.86908,9.4273 12.13456,15.223 3.40989,5.65472 7.64278,11.01568 10.16352,16.76182 5.33282,4.95503 12.09713,-2.9069 18.35687,-2.90228 3.07966,-5.12791 6.1634,-10.09309 10.89959,-13.65497 3.57662,-4.51201 1.53442,-12.1972 3.96354,-17.84779 0.65412,-6.29983 -5.71452,-10.1283 -7.74494,-15.55479 -5.11189,-5.20658 -9.57769,-10.17315 -13.01542,-16.77188 -3.03275,-6.36273 -3.86358,-13.67482 -2.19127,-20.51204 1.29002,-1.18262 1.10017,-2.57287 1.53892,-3.89055" + id="path6127" + style="fill:none;stroke:#000000;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + <path + d="m 264.49757,451.68163 c -0.83348,-0.36325 -1.85626,-1.07502 -2.27284,-1.58172 -0.41658,-0.5067 -1.7802,-1.5663 -3.03026,-2.35468 -2.64376,-1.66732 -6.90902,-7.0392 -7.34147,-9.24618 -0.59726,-3.04812 -3.54506,-8.15921 -6.60743,-11.45641 -4.03542,-4.34485 -6.20805,-8.31132 -8.70689,-15.89577 -1.7921,-5.43936 -2.03866,-6.78071 -2.18289,-11.87582 l -0.1626,-5.74387 2.14733,-3.61858 c 1.49005,-2.51097 2.45643,-4.98256 3.15715,-8.07469 0.5554,-2.45086 1.46859,-5.37083 2.02932,-6.48881 l 1.01951,-2.0327 6.17741,-0.24014 c 3.39757,-0.13208 8.19146,-0.18277 10.65308,-0.11265 4.44806,0.12672 11.48416,1.5513 13.68386,2.77053 0.63259,0.35063 2.29197,1.25362 3.68752,2.00665 3.98522,2.1504 4.30748,2.61329 3.37531,4.84826 -0.42755,1.0251 -1.42299,2.54567 -2.2121,3.37904 -1.43662,1.51721 -3.05975,6.05037 -3.05975,8.54542 0,0.72538 -0.68185,2.52705 -1.51523,4.00371 -0.83337,1.47666 -1.51523,3.19279 -1.51523,3.81363 0,0.62083 -0.27818,1.62523 -0.61819,2.232 -0.58367,1.04162 -1.16789,5.63751 -2.41505,18.9987 -0.45164,4.83847 -0.70286,5.88848 -1.551,6.48254 -0.89587,0.62749 -0.97423,1.0664 -0.68253,3.8228 0.18125,1.71265 0.64492,3.6173 1.03039,4.23256 0.38547,0.61526 0.70085,2.16071 0.70085,3.43435 0,1.27363 0.31405,2.92943 0.69789,3.67957 0.38384,0.75013 0.85915,2.33434 1.05624,3.52046 0.19709,1.18612 0.69477,2.49301 1.10595,2.90419 0.66009,0.66009 0.40341,0.74529 -2.19266,0.72783 -1.61715,-0.0109 -3.62221,-0.31697 -4.45569,-0.68022 l 0,0 z" + id="path6163" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.35355338;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + <path + d="m 396.41236,460.39021 c -0.50626,-0.28797 -1.47514,-0.38438 -2.15306,-0.21422 -0.97746,0.24532 -5.45503,-1.12035 -6.703,-2.04444 -0.099,-0.0733 0.62934,-0.96678 1.61864,-1.98543 1.35515,-1.39535 1.87342,-2.4304 2.10166,-4.19725 0.16662,-1.28984 0.76652,-4.0498 1.3331,-6.13324 0.56659,-2.08344 1.5235,-5.60635 2.12647,-7.82868 0.85499,-3.15121 1.06501,-5.15235 0.95413,-9.09137 -0.24568,-8.72732 -0.64405,-14.10608 -1.12226,-15.15229 -0.25394,-0.55559 -0.53774,-2.64127 -0.63065,-4.63486 -0.11344,-2.43421 -0.43818,-3.92719 -0.98873,-4.54568 -0.58913,-0.66183 -0.91354,-2.41327 -1.15292,-6.22429 l -0.3331,-5.3033 1.6724,-2.61886 c 0.91982,-1.44037 2.52021,-3.145 3.55641,-3.78807 1.0362,-0.64307 2.0247,-1.58971 2.19666,-2.10365 0.17195,-0.51394 1.30987,-1.37556 2.5287,-1.9147 1.21883,-0.53915 2.45435,-1.42554 2.74561,-1.96975 0.39448,-0.73711 1.07253,-0.99386 2.65836,-1.00663 1.17084,-0.009 3.03794,-0.45628 4.14911,-0.99301 1.11116,-0.53674 2.62785,-0.98359 3.37041,-0.99302 0.79847,-0.0101 1.94627,-0.6133 2.80919,-1.47622 l 1.45909,-1.45909 1.98903,1.20358 c 1.09397,0.66197 3.29507,1.4616 4.89135,1.77697 2.77989,0.5492 2.9243,0.65506 3.42363,2.50943 0.28673,1.06482 0.376,2.51507 0.19837,3.22277 -0.23988,0.95577 0.0373,1.75897 1.07743,3.12273 1.2757,1.67252 1.32566,1.89062 0.56112,2.44967 -0.98074,0.71713 -1.09884,2.31355 -0.23507,3.17733 0.46889,0.46888 0.40779,0.74782 -0.2728,1.24548 -0.81374,0.59502 -0.81889,0.75778 -0.0714,2.25615 0.54968,1.10185 0.65784,1.90156 0.34048,2.51733 -0.25581,0.49636 -0.62128,2.15254 -0.81214,3.6804 -0.20022,1.60272 -0.86987,3.5746 -1.58291,4.66112 -1.00727,1.53485 -1.23588,2.52258 -1.23588,5.3396 0,3.05151 -0.17585,3.68879 -1.50118,5.4404 -0.82565,1.0912 -1.5075,2.3088 -1.51523,2.70576 -0.008,0.39697 -0.29148,1.48898 -0.63057,2.4267 -0.5085,1.40624 -0.49207,1.78186 0.0938,2.14394 0.51371,0.31749 0.56277,0.62439 0.17726,1.10883 -0.29318,0.36842 -0.80141,1.50347 -1.12941,2.52235 -0.54409,1.69015 -3.63547,7.55893 -5.93115,11.25991 -0.6016,0.96988 -1.5138,1.61512 -2.59487,1.83549 -2.15117,0.43849 -2.32413,0.65034 -1.54695,1.89481 0.56684,0.90765 0.47994,1.16021 -0.72534,2.10829 -2.14287,1.68558 -2.87911,2.52914 -2.87911,3.29881 0,0.39155 -0.57263,0.85563 -1.27252,1.03129 -0.69989,0.17566 -2.31849,1.5437 -3.59689,3.04008 -1.32232,1.5478 -2.7445,2.7207 -3.29893,2.7207 -0.65584,0 -1.22039,0.61945 -1.72618,1.89404 -1.49574,3.76925 -1.40087,3.64682 -2.39016,3.08409 l 0,0 z" + id="path6165" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.35355338;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + </g> + <path + d="m 327.4876,492.39499 c 2.2644,2.66632 6.07748,3.19909 8.63579,5.43274 2.86007,2.28019 6.66345,0.59268 9.87447,1.65009 3.09838,0.67486 5.93629,2.75922 9.39536,2.88839 3.32499,0.37833 6.55094,0.57956 9.53617,1.55177 2.6564,0.95363 5.25607,-2.99638 7.07288,-0.0245 3.26765,2.24544 7.81367,0.6425 11.58781,1.00892 3.32915,0.008 5.80304,-2.7396 9.17467,-2.25665 3.08744,-0.22194 6.69298,0.88515 9.12364,-1.39255 3.30181,0.0682 6.36091,-0.78244 9.0003,-2.76185 1.51143,-1.14436 3.49477,-0.47019 5.25963,-0.64998 0.0806,-1.61182 2.11123,-1.97141 2.85714,-3.21429" + id="path6159" + style="fill:none;stroke:#000000;stroke-width:0.69999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + inkscape:connector-curvature="0" /> + </g> + </g> + </g> +</svg> diff --git a/images/red-koala.xcf b/images/red-koala.xcf Binary files differnew file mode 100644 index 000000000..a95baf62c --- /dev/null +++ b/images/red-koala.xcf diff --git a/include/account.php b/include/account.php index 5e57d53a8..6c6fdece4 100644 --- a/include/account.php +++ b/include/account.php @@ -31,7 +31,7 @@ function check_account_email($email) { if(! strlen($email)) return $result; - if((! valid_email($email)) || (! validate_email($email))) + if(! validate_email($email)) $result['message'] .= t('Not a valid email address') . EOL; elseif(! allowed_email($email)) $result['message'] = t('Your email domain is not among those allowed on this site'); @@ -105,6 +105,33 @@ function account_total() { } +function account_store_lowlevel($arr) { + + $store = [ + 'account_parent' => ((array_key_exists('account_parent',$arr)) ? $arr['account_parent'] : '0'), + 'account_default_channel' => ((array_key_exists('account_default_channel',$arr)) ? $arr['account_default_channel'] : '0'), + 'account_salt' => ((array_key_exists('account_salt',$arr)) ? $arr['account_salt'] : ''), + 'account_password' => ((array_key_exists('account_password',$arr)) ? $arr['account_password'] : ''), + 'account_email' => ((array_key_exists('account_email',$arr)) ? $arr['account_email'] : ''), + 'account_external' => ((array_key_exists('account_external',$arr)) ? $arr['account_external'] : ''), + 'account_language' => ((array_key_exists('account_language',$arr)) ? $arr['account_language'] : 'en'), + 'account_created' => ((array_key_exists('account_created',$arr)) ? $arr['account_created'] : '0001-01-01 00:00:00'), + 'account_lastlog' => ((array_key_exists('account_lastlog',$arr)) ? $arr['account_lastlog'] : '0001-01-01 00:00:00'), + 'account_flags' => ((array_key_exists('account_flags',$arr)) ? $arr['account_flags'] : '0'), + 'account_roles' => ((array_key_exists('account_roles',$arr)) ? $arr['account_roles'] : '0'), + 'account_reset' => ((array_key_exists('account_reset',$arr)) ? $arr['account_reset'] : ''), + 'account_expires' => ((array_key_exists('account_expires',$arr)) ? $arr['account_expires'] : '0001-01-01 00:00:00'), + 'account_expire_notified' => ((array_key_exists('account_expire_notified',$arr)) ? $arr['account_expire_notified'] : '0001-01-01 00:00:00'), + 'account_service_class' => ((array_key_exists('account_service_class',$arr)) ? $arr['account_service_class'] : ''), + 'account_level' => ((array_key_exists('account_level',$arr)) ? $arr['account_level'] : '0'), + 'account_password_changed' => ((array_key_exists('account_password_changed',$arr)) ? $arr['account_password_changed'] : '0001-01-01 00:00:00') + ]; + + return create_table_from_array('account',$store); + +} + + function create_account($arr) { // Required: { email, password } @@ -177,21 +204,20 @@ function create_account($arr) { $salt = random_string(32); $password_encoded = hash('whirlpool', $salt . $password); - $r = q("INSERT INTO account - ( account_parent, account_salt, account_password, account_email, account_language, - account_created, account_flags, account_roles, account_level, account_expires, account_service_class ) - VALUES ( %d, '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', '%s' )", - intval($parent), - dbesc($salt), - dbesc($password_encoded), - dbesc($email), - dbesc(get_best_language()), - dbesc(datetime_convert()), - intval($flags), - intval($roles), - intval($techlevel), - dbesc($expires), - dbesc($default_service_class) + $r = account_store_lowlevel( + [ + 'account_parent' => intval($parent), + 'account_salt' => $salt, + 'account_password' => $password_encoded, + 'account_email' => $email, + 'account_language' => get_best_language(), + 'account_created' => datetime_convert(), + 'account_flags' => intval($flags), + 'account_roles' => intval($roles), + 'account_level' => intval($techlevel), + 'account_expires' => $expires, + 'account_service_class' => $default_service_class + ] ); if(! $r) { logger('create_account: DB INSERT failed.'); @@ -246,16 +272,18 @@ function verify_email_address($arr) { dbesc($arr['account']['account_language']) ); -//@fixme - get correct language template + push_lang(($arr['account']['account_language']) ? $arr['account']['account_language'] : 'en'); - $email_msg = replace_macros(get_intltext_template('register_verify_member.tpl'), array( - '$sitename' => get_config('system','sitename'), - '$siteurl' => z_root(), - '$email' => $arr['email'], - '$uid' => $arr['account']['account_id'], - '$hash' => $hash, - '$details' => $details - )); + $email_msg = replace_macros(get_intltext_template('register_verify_member.tpl'), + [ + '$sitename' => get_config('system','sitename'), + '$siteurl' => z_root(), + '$email' => $arr['email'], + '$uid' => $arr['account']['account_id'], + '$hash' => $hash, + '$details' => $details + ] + ); $res = z_mail( [ @@ -265,10 +293,12 @@ function verify_email_address($arr) { ] ); + pop_lang(); + if($res) $delivered ++; else - logger('send_reg_approval_email: failed to ' . $admin['email'] . 'account_id: ' . $arr['account']['account_id']); + logger('send_reg_approval_email: failed to account_id: ' . $arr['account']['account_id']); return $res; } @@ -354,9 +384,9 @@ function send_register_success_email($email,$password) { $res = z_mail( [ - 'toEmail' => $email, - 'messageSubject' => sprintf( t('Registration details for %s'), get_config('system','sitename')), - 'textVersion' => $email_msg, + 'toEmail' => $email, + 'messageSubject' => sprintf( t('Registration details for %s'), get_config('system','sitename')), + 'textVersion' => $email_msg, ] ); @@ -424,7 +454,7 @@ function account_allow($hash) { pop_lang(); - if(get_config('system','auto_channel_create') || get_config('system','server_role') === 'basic') + if(get_config('system','auto_channel_create')) auto_channel_create($register[0]['uid']); if ($res) { @@ -525,19 +555,13 @@ function account_approve($hash) { if(! $account) return $ret; - - - - if(get_config('system','auto_channel_create') || get_config('system','server_role') === 'basic') + if(get_config('system','auto_channel_create')) auto_channel_create($register[0]['uid']); else { $_SESSION['login_return_url'] = 'new_channel'; authenticate_success($account[0],null,true,true,false,true); } - - // info( t('Account verified. Please login.') . EOL ); - return true; } @@ -772,12 +796,6 @@ function upgrade_bool_message($bbcode = false) { function get_account_techlevel($account_id = 0) { - $role = \Zotlabs\Lib\System::get_server_role(); - if($role == 'basic') - return 0; - if($role == 'standard') - return 5; - if(! $account_id) { $x = \App::get_account(); } diff --git a/include/api.php b/include/api.php index 693967696..c91590070 100644 --- a/include/api.php +++ b/include/api.php @@ -194,15 +194,25 @@ require_once('include/api_zot.php'); else $redirect = trim($_REQUEST['redirect_uris']); $icon = trim($_REQUEST['logo_uri']); - $r = q("INSERT INTO clients (client_id, pw, clname, redirect_uri, icon, uid) - VALUES ('%s','%s','%s','%s','%s',%d)", - dbesc($key), - dbesc($secret), - dbesc($name), - dbesc($redirect), - dbesc($icon), - intval(0) - ); + if($oauth2) { + $r = q("INSERT INTO oauth_clients (client_id, client_secret, redirect_uri, grant_types, scope, user_id) + VALUES ( '%s', '%s', '%s', null, null, null ) ", + dbesc($key), + dbesc($secret), + dbesc($redirect) + ); + } + else { + $r = q("INSERT INTO clients (client_id, pw, clname, redirect_uri, icon, uid) + VALUES ('%s','%s','%s','%s','%s',%d)", + dbesc($key), + dbesc($secret), + dbesc($name), + dbesc($redirect), + dbesc($icon), + intval(0) + ); + } $ret['client_id'] = $key; $ret['client_secret'] = $secret; diff --git a/include/bbcode.php b/include/bbcode.php index f0ec15130..c408af35d 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -1231,6 +1231,7 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) $Text = preg_replace("/\[event\-start\](.*?)\[\/event\-start\]/ism",$sub,$Text); + $Text = preg_replace("/\[event\](.*?)\[\/event\]/ism",'',$Text); $Text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/ism",'',$Text); $Text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/ism",'',$Text); $Text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/ism",'',$Text); diff --git a/include/channel.php b/include/channel.php index e283ed940..49da57fd6 100644 --- a/include/channel.php +++ b/include/channel.php @@ -258,6 +258,7 @@ function create_identity($arr) { 'channel_system' => intval($system), 'channel_expire_days' => intval($expire), 'channel_timezone' => App::$timezone + ] ); @@ -1161,31 +1162,16 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa $location = $reddress = $pdesc = $gender = $marital = $homepage = False; } + if($profile['gender']) { + $profile['gender_icon'] = gender_icon($profile['gender']); + } + $firstname = ((strpos($profile['channel_name'],' ')) ? trim(substr($profile['channel_name'],0,strpos($profile['channel_name'],' '))) : $profile['channel_name']); $lastname = (($firstname === $profile['channel_name']) ? '' : trim(substr($profile['channel_name'],strlen($firstname)))); // @fixme move this to the diaspora plugin itself - if(plugin_is_installed('diaspora')) { - $diaspora = array( - 'podloc' => z_root(), - 'guid' => $profile['channel_guid'] . str_replace('.','',App::get_hostname()), - 'pubkey' => pemtorsa($profile['channel_pubkey']), - 'searchable' => (($block) ? 'false' : 'true'), - 'nickname' => $profile['channel_address'], - 'fullname' => $profile['channel_name'], - 'firstname' => $firstname, - 'lastname' => $lastname, - 'photo300' => z_root() . '/photo/profile/300/' . $profile['uid'] . '.jpg', - 'photo100' => z_root() . '/photo/profile/100/' . $profile['uid'] . '.jpg', - 'photo50' => z_root() . '/photo/profile/50/' . $profile['uid'] . '.jpg', - ); - } - else - $diaspora = ''; - - $contact_block = contact_block(); $channel_menu = false; @@ -1218,7 +1204,6 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa '$marital' => $marital, '$homepage' => $homepage, '$chanmenu' => $channel_menu, - '$diaspora' => $diaspora, '$reddress' => $reddress, '$rating' => '', '$contact_block' => $contact_block, @@ -1229,7 +1214,29 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa call_hooks('profile_sidebar', $arr); - return $o; + return $arr['entry']; + +} + +function gender_icon($gender) { + +// logger('gender: ' . $gender); + + // This can easily get throw off if the observer language is different + // than the channel owner language. + + if(strpos(strtolower($gender),strtolower(t('Female'))) !== false) + return 'venus'; + if(strpos(strtolower($gender),strtolower(t('Male'))) !== false) + return 'mars'; + if(strpos(strtolower($gender),strtolower(t('Trans'))) !== false) + return 'transgender'; + if(strpos(strtolower($gender),strtolower(t('Neuter'))) !== false) + return 'neuter'; + if(strpos(strtolower($gender),strtolower(t('Non-specific'))) !== false) + return 'genderless'; + + return ''; } @@ -1998,49 +2005,48 @@ function remote_login() { } - function channel_store_lowlevel($arr) { + $store = [ + 'channel_account_id' => ((array_key_exists('channel_account_id',$arr)) ? $arr['channel_account_id'] : '0'), + 'channel_primary' => ((array_key_exists('channel_primary',$arr)) ? $arr['channel_primary'] : '0'), + 'channel_name' => ((array_key_exists('channel_name',$arr)) ? $arr['channel_name'] : ''), + 'channel_address' => ((array_key_exists('channel_address',$arr)) ? $arr['channel_address'] : ''), + 'channel_guid' => ((array_key_exists('channel_guid',$arr)) ? $arr['channel_guid'] : ''), + 'channel_guid_sig' => ((array_key_exists('channel_guid_sig',$arr)) ? $arr['channel_guid_sig'] : ''), + 'channel_hash' => ((array_key_exists('channel_hash',$arr)) ? $arr['channel_hash'] : ''), + 'channel_timezone' => ((array_key_exists('channel_timezone',$arr)) ? $arr['channel_timezone'] : 'UTC'), + 'channel_location' => ((array_key_exists('channel_location',$arr)) ? $arr['channel_location'] : ''), + 'channel_theme' => ((array_key_exists('channel_theme',$arr)) ? $arr['channel_theme'] : ''), + 'channel_startpage' => ((array_key_exists('channel_startpage',$arr)) ? $arr['channel_startpage'] : ''), + 'channel_pubkey' => ((array_key_exists('channel_pubkey',$arr)) ? $arr['channel_pubkey'] : ''), + 'channel_prvkey' => ((array_key_exists('channel_prvkey',$arr)) ? $arr['channel_prvkey'] : ''), + 'channel_notifyflags' => ((array_key_exists('channel_notifyflags',$arr)) ? $arr['channel_notifyflags'] : '65535'), + 'channel_pageflags' => ((array_key_exists('channel_pageflags',$arr)) ? $arr['channel_pageflags'] : '0'), + 'channel_dirdate' => ((array_key_exists('channel_dirdate',$arr)) ? $arr['channel_dirdate'] : NULL_DATE), + 'channel_lastpost' => ((array_key_exists('channel_lastpost',$arr)) ? $arr['channel_lastpost'] : NULL_DATE), + 'channel_deleted' => ((array_key_exists('channel_deleted',$arr)) ? $arr['channel_deleted'] : NULL_DATE), + 'channel_max_anon_mail' => ((array_key_exists('channel_max_anon_mail',$arr)) ? $arr['channel_max_anon_mail'] : '10'), + 'channel_max_friend_req' => ((array_key_exists('channel_max_friend_req',$arr)) ? $arr['channel_max_friend_req'] : '10'), + 'channel_expire_days' => ((array_key_exists('channel_expire_days',$arr)) ? $arr['channel_expire_days'] : '0'), + 'channel_passwd_reset' => ((array_key_exists('channel_passwd_reset',$arr)) ? $arr['channel_passwd_reset'] : ''), + 'channel_default_group' => ((array_key_exists('channel_default_group',$arr)) ? $arr['channel_default_group'] : ''), + 'channel_allow_cid' => ((array_key_exists('channel_allow_cid',$arr)) ? $arr['channel_allow_cid'] : ''), + 'channel_allow_gid' => ((array_key_exists('channel_allow_gid',$arr)) ? $arr['channel_allow_gid'] : ''), + 'channel_deny_cid' => ((array_key_exists('channel_deny_cid',$arr)) ? $arr['channel_deny_cid'] : ''), + 'channel_deny_gid' => ((array_key_exists('channel_deny_gid',$arr)) ? $arr['channel_deny_gid'] : ''), + 'channel_removed' => ((array_key_exists('channel_removed',$arr)) ? $arr['channel_removed'] : '0'), + 'channel_system' => ((array_key_exists('channel_system',$arr)) ? $arr['channel_system'] : '0'), - $store = [ - 'channel_account_id' => ((array_key_exists('channel_account_id',$arr)) ? $arr['channel_account_id'] : '0'), - 'channel_primary' => ((array_key_exists('channel_primary',$arr)) ? $arr['channel_primary'] : '0'), - 'channel_name' => ((array_key_exists('channel_name',$arr)) ? $arr['channel_name'] : ''), - 'channel_address' => ((array_key_exists('channel_address',$arr)) ? $arr['channel_address'] : ''), - 'channel_guid' => ((array_key_exists('channel_guid',$arr)) ? $arr['channel_guid'] : ''), - 'channel_guid_sig' => ((array_key_exists('channel_guid_sig',$arr)) ? $arr['channel_guid_sig'] : ''), - 'channel_hash' => ((array_key_exists('channel_hash',$arr)) ? $arr['channel_hash'] : ''), - 'channel_timezone' => ((array_key_exists('channel_timezone',$arr)) ? $arr['channel_timezone'] : 'UTC'), - 'channel_location' => ((array_key_exists('channel_location',$arr)) ? $arr['channel_location'] : ''), - 'channel_theme' => ((array_key_exists('channel_theme',$arr)) ? $arr['channel_theme'] : ''), - 'channel_startpage' => ((array_key_exists('channel_startpage',$arr)) ? $arr['channel_startpage'] : ''), - 'channel_pubkey' => ((array_key_exists('channel_pubkey',$arr)) ? $arr['channel_pubkey'] : ''), - 'channel_prvkey' => ((array_key_exists('channel_prvkey',$arr)) ? $arr['channel_prvkey'] : ''), - 'channel_notifyflags' => ((array_key_exists('channel_notifyflags',$arr)) ? $arr['channel_notifyflags'] : '65535'), - 'channel_pageflags' => ((array_key_exists('channel_pageflags',$arr)) ? $arr['channel_pageflags'] : '0'), - 'channel_dirdate' => ((array_key_exists('channel_dirdate',$arr)) ? $arr['channel_dirdate'] : NULL_DATE), - 'channel_lastpost' => ((array_key_exists('channel_lastpost',$arr)) ? $arr['channel_lastpost'] : NULL_DATE), - 'channel_deleted' => ((array_key_exists('channel_deleted',$arr)) ? $arr['channel_deleted'] : NULL_DATE), - 'channel_max_anon_mail' => ((array_key_exists('channel_max_anon_mail',$arr)) ? $arr['channel_max_anon_mail'] : '10'), - 'channel_max_friend_req' => ((array_key_exists('channel_max_friend_req',$arr)) ? $arr['channel_max_friend_req'] : '10'), - 'channel_expire_days' => ((array_key_exists('channel_expire_days',$arr)) ? $arr['channel_expire_days'] : '0'), - 'channel_passwd_reset' => ((array_key_exists('channel_passwd_reset',$arr)) ? $arr['channel_passwd_reset'] : ''), - 'channel_default_group' => ((array_key_exists('channel_default_group',$arr)) ? $arr['channel_default_group'] : ''), - 'channel_allow_cid' => ((array_key_exists('channel_allow_cid',$arr)) ? $arr['channel_allow_cid'] : ''), - 'channel_allow_gid' => ((array_key_exists('channel_allow_gid',$arr)) ? $arr['channel_allow_gid'] : ''), - 'channel_deny_cid' => ((array_key_exists('channel_deny_cid',$arr)) ? $arr['channel_deny_cid'] : ''), - 'channel_deny_gid' => ((array_key_exists('channel_deny_gid',$arr)) ? $arr['channel_deny_gid'] : ''), - 'channel_removed' => ((array_key_exists('channel_removed',$arr)) ? $arr['channel_removed'] : '0'), - 'channel_system' => ((array_key_exists('channel_system',$arr)) ? $arr['channel_system'] : '0'), 'channel_moved' => ((array_key_exists('channel_moved',$arr)) ? $arr['channel_moved'] : ''), 'channel_password' => ((array_key_exists('channel_password',$arr)) ? $arr['channel_password'] : ''), 'channel_salt' => ((array_key_exists('channel_salt',$arr)) ? $arr['channel_salt'] : '') + ]; return create_table_from_array('channel',$store); } - function profile_store_lowlevel($arr) { $store = [ @@ -2322,6 +2328,7 @@ function channel_codeallowed($channel_id) { return true; return false; + } function anon_identity_init($reqvars) { @@ -2391,5 +2398,6 @@ function anon_identity_init($reqvars) { } return $x[0]; - } + + diff --git a/include/connections.php b/include/connections.php index 56457ea10..8df795190 100644 --- a/include/connections.php +++ b/include/connections.php @@ -634,8 +634,8 @@ function get_vcard_array($vc,$id) { 'address' => $adr->getParts() ]; $last_entry = end($adrs); - if($last_entry['address']) - array_walk($last_entry['address'],'array_escape_tags'); + if($last_entry && is_array($adrs[$last_entry]['address'])) + array_walk($adrs[$last_entry]['address'],'array_escape_tags'); } } diff --git a/include/conversation.php b/include/conversation.php index 2eac2adde..1c1a4479d 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -442,7 +442,6 @@ function is_edit_activity($item) { * figures out how to determine page owner and other contextual items * that are based on unique features of the calling module. * - * @param App &$a * @param array $items * @param string $mode * @param boolean $update @@ -450,7 +449,7 @@ function is_edit_activity($item) { * @param string $prepared_item * @return string */ -function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $prepared_item = '') { +function conversation($items, $mode, $update, $page_mode = 'traditional', $prepared_item = '') { $content_html = ''; $o = ''; diff --git a/include/dba/dba_driver.php b/include/dba/dba_driver.php index d362f58b2..4079bcaba 100755 --- a/include/dba/dba_driver.php +++ b/include/dba/dba_driver.php @@ -344,11 +344,8 @@ function q($sql) { if(\DBA::$dba && \DBA::$dba->connected) { $stmt = vsprintf($sql, $args); if($stmt === false) { - if(version_compare(PHP_VERSION, '5.4.0') >= 0) - db_logger('dba: vsprintf error: ' . - print_r(debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1), true),LOGGER_NORMAL,LOG_CRIT); - else - db_logger('dba: vsprintf error: ' . print_r(debug_backtrace(), true),LOGGER_NORMAL,LOG_CRIT); + db_logger('dba: vsprintf error: ' . + print_r(debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1), true),LOGGER_NORMAL,LOG_CRIT); } if(\DBA::$dba->debug) db_logger('Sql: ' . $stmt, LOGGER_DEBUG, LOG_INFO); @@ -445,6 +442,20 @@ function db_getfunc($f) { return $f; } +function db_load_file($f) { + // db errors should get logged to the logfile + $str = @file_get_contents($f); + $arr = explode(';', $str); + if($arr) { + foreach($arr as $a) { + if(strlen(trim($a))) { + $r = dbq(trim($a)); + } + } + } +} + + // The logger function may make DB calls internally to query the system logging parameters. // This can cause a recursion if database debugging is enabled. // So this function preserves the current database debugging state and then turns it off diff --git a/include/dba/dba_pdo.php b/include/dba/dba_pdo.php index f76e6cdd7..f119d8926 100755 --- a/include/dba/dba_pdo.php +++ b/include/dba/dba_pdo.php @@ -74,19 +74,19 @@ class dba_pdo extends dba_driver { return $result; } - if($this->debug) { - db_logger('dba_pdo: DEBUG: ' . printable($sql) . ' returned ' . count($result) . ' results.', LOGGER_NORMAL, LOG_INFO); - } - $r = array(); if($result) { foreach($result as $x) { $r[] = $x; } - if($this->debug) { - db_logger('dba_pdo: ' . printable(print_r($r,true)), LOGGER_NORMAL, LOG_INFO); - } } + + if($this->debug) { + db_logger('dba_pdo: DEBUG: ' . printable($sql) . ' returned ' . count($r) . ' results.', LOGGER_NORMAL, LOG_INFO); + db_logger('dba_pdo: ' . printable(print_r($r,true)), LOGGER_NORMAL, LOG_INFO); + } + + return (($this->error) ? false : $r); } diff --git a/include/event.php b/include/event.php index c57e52bc0..b56a5fb3e 100644 --- a/include/event.php +++ b/include/event.php @@ -210,6 +210,10 @@ function format_event_bbcode($ev) { $o = ''; + if($ev['event_vdata']) { + $o .= '[event]' . $ev['event_vdata'] . '[/event]'; + } + if($ev['summary']) $o .= '[event-summary]' . $ev['summary'] . '[/event-summary]'; @@ -1232,3 +1236,71 @@ function tasks_fetch($arr) { return $ret; } + +function cdav_principal($uri) { + $r = q("SELECT uri FROM principals WHERE uri = '%s' LIMIT 1", + dbesc($uri) + ); + + if($r[0]['uri'] === $uri) + return true; + else + return false; +} + +function cdav_perms($needle, $haystack, $check_rw = false) { + foreach ($haystack as $item) { + if($check_rw) { + if(is_array($item['id'])) { + if ($item['id'][0] == $needle && $item['share-access'] != 2) { + return $item['{DAV:}displayname']; + } + } + else { + if ($item['id'] == $needle && $item['share-access'] != 2) { + return $item['{DAV:}displayname']; + } + } + } + else { + if(is_array($item['id'])) { + if ($item['id'][0] == $needle) { + return $item['{DAV:}displayname']; + } + } + else { + if ($item['id'] == $needle) { + return $item['{DAV:}displayname']; + } + } + } + } + return false; +} + + +function translate_type($type) { + + if(!$type) + return; + + $type = strtoupper($type); + + $map = [ + 'CELL' => t('Mobile'), + 'HOME' => t('Home'), + 'HOME,VOICE' => t('Home, Voice'), + 'HOME,FAX' => t('Home, Fax'), + 'WORK' => t('Work'), + 'WORK,VOICE' => t('Work, Voice'), + 'WORK,FAX' => t('Work, Fax'), + 'OTHER' => t('Other') + ]; + + if (array_key_exists($type, $map)) { + return [$type, $map[$type]]; + } + else { + return [$type, t('Other') . ' (' . $type . ')']; + } +} diff --git a/include/features.php b/include/features.php index 0fc6fbc1d..f32dbe82e 100644 --- a/include/features.php +++ b/include/features.php @@ -45,10 +45,6 @@ function feature_level($feature,$def) { function get_features($filtered = true) { - $server_role = \Zotlabs\Lib\System::get_server_role(); - - if($server_role === 'basic' && $filtered) - return array(); $arr = [ @@ -424,16 +420,15 @@ function get_features($filtered = true) { ]; - if($server_role === 'pro') { - $arr['general'][] = [ - 'premium_channel', - t('Premium Channel'), - t('Allows you to set restrictions and terms on those that connect with your channel'), - false, - get_config('feature_lock','premium_channel'), - feature_level('premium_channel',4), - ]; - } + $arr['general'][] = [ + 'premium_channel', + t('Premium Channel'), + t('Allows you to set restrictions and terms on those that connect with your channel'), + false, + get_config('feature_lock','premium_channel'), + feature_level('premium_channel',4), + ]; + $techlevel = get_account_techlevel(); diff --git a/include/feedutils.php b/include/feedutils.php index 158ecb7a3..b64a98a7f 100644 --- a/include/feedutils.php +++ b/include/feedutils.php @@ -246,9 +246,17 @@ function get_atom_elements($feed, $item, &$author) { $found_author = $item->get_author(); if($found_author) { + if($rawauthor) { + if($rawauthor[0]['child'][NAMESPACE_POCO]['displayName'][0]['data']) + $author['full_name'] = unxmlify($rawauthor[0]['child'][NAMESPACE_POCO]['displayName'][0]['data']); + } $author['author_name'] = unxmlify($found_author->get_name()); $author['author_link'] = unxmlify($found_author->get_link()); $author['author_is_feed'] = false; + + $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author'); + logger('rawauthor: ' . print_r($rawauthor, true)); + } else { $author['author_name'] = unxmlify($feed->get_title()); @@ -305,12 +313,6 @@ function get_atom_elements($feed, $item, &$author) { $res['verb'] = unxmlify($rawverb[0]['data']); } - // translate OStatus unfollow to activity streams if it happened to get selected - - if((x($res,'verb')) && ($res['verb'] === 'http://ostatus.org/schema/1.0/unfollow')) { - $res['verb'] = ACTIVITY_UNFOLLOW; - } - // look for a photo. We should check media size and find the best one, // but for now let's just find any author photo @@ -393,6 +395,7 @@ function get_atom_elements($feed, $item, &$author) { if($rawcnv) { $ostatus_conversation = normalise_id(unxmlify($rawcnv[0]['attribs']['']['ref'])); set_iconfig($res,'ostatus','conversation',$ostatus_conversation,true); + logger('ostatus_conversation: ' . $ostatus_conversation, LOGGER_DATA, LOG_INFO); } $ostatus_protocol = (($ostatus_conversation) ? true : false); @@ -406,6 +409,21 @@ function get_atom_elements($feed, $item, &$author) { $res['app'] = strip_tags(unxmlify($apps[0]['attribs']['']['source'])); } + if($ostatus_protocol) { + + // translate OStatus unfollow to activity streams if it happened to get selected + + if((x($res,'verb')) && ($res['verb'] === 'http://ostatus.org/schema/1.0/unfollow')) { + $res['verb'] = ACTIVITY_UNFOLLOW; + } + + // And OStatus 'favorite' is pretty much what we call 'like' on other networks + + if((x($res,'verb')) && ($res['verb'] === ACTIVITY_FAVORITE)) { + $res['verb'] = ACTIVITY_LIKE; + } + } + /* * If there's a copy of the body content which is guaranteed to have survived mangling in transit, use it. */ @@ -603,10 +621,17 @@ function get_atom_elements($feed, $item, &$author) { if(! $type) $type = 'application/octet-stream'; - if(($ostatus_protocol) && (strpos($type,'image') === 0) && (strpos($res['body'],$link) === false) && (strpos($link,'http') === 0)) { - $res['body'] .= "\n\n" . '[img]' . $link . '[/img]'; + if($ostatus_protocol) { + if((strpos($type,'image') === 0) && (strpos($res['body'], ']' . $link . '[/img]') === false) && (strpos($link,'http') === 0)) { + $res['body'] .= "\n\n" . '[img]' . $link . '[/img]'; + } + if((strpos($type,'video') === 0) && (strpos($res['body'], ']' . $link . '[/video]') === false) && (strpos($link,'http') === 0)) { + $res['body'] .= "\n\n" . '[video]' . $link . '[/video]'; + } + if((strpos($type,'audio') === 0) && (strpos($res['body'], ']' . $link . '[/audio]') === false) && (strpos($link,'http') === 0)) { + $res['body'] .= "\n\n" . '[audio]' . $link . '[/audio]'; + } } - $res['attach'][] = array('href' => $link, 'length' => $len, 'type' => $type, 'title' => $title ); } } @@ -691,7 +716,7 @@ function get_atom_elements($feed, $item, &$author) { if(array_key_exists('verb',$res) && $res['verb'] === ACTIVITY_SHARE - && array_key_exists('obj_type',$res) && $res['obj_type'] === ACTIVITY_OBJ_NOTE) { + && array_key_exists('obj_type',$res) && in_array($res['obj_type'], [ ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_COMMENT, ACTIVITY_OBJ_ACTIVITY ] )) { feed_get_reshare($res,$item); } @@ -798,9 +823,15 @@ function feed_get_reshare(&$res,$item) { if(! $type) $type = 'application/octet-stream'; - if((strpos($type,'image') === 0) && (strpos($body,$link) === false) && (strpos($link,'http') === 0)) { + if((strpos($type,'image') === 0) && (strpos($body, ']' . $link . '[/img]') === false) && (strpos($link,'http') === 0)) { $body .= "\n\n" . '[img]' . $link . '[/img]'; } + if((strpos($type,'video') === 0) && (strpos($body, ']' . $link . '[/video]') === false) && (strpos($link,'http') === 0)) { + $body .= "\n\n" . '[video]' . $link . '[/video]'; + } + if((strpos($type,'audio') === 0) && (strpos($body, ']' . $link . '[/audio]') === false) && (strpos($link,'http') === 0)) { + $body .= "\n\n" . '[audio]' . $link . '[/audio]'; + } } } @@ -958,6 +989,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { foreach($items as $item) { $is_reply = false; + $parent_link = ''; logger('processing ' . $item->get_id(), LOGGER_DEBUG); @@ -966,6 +998,9 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { $is_reply = true; $parent_mid = normalise_id($rawthread[0]['attribs']['']['ref']); } + if(isset($rawthread[0]['attribs']['']['href'])) { + $parent_link = $rawthread[0]['attribs']['']['href']; + } if($is_reply) { @@ -995,7 +1030,16 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { $datarray['author_xchan'] = ''; if($author['author_link'] != $contact['xchan_url']) { - $x = import_author_unknown(array('name' => $author['author_name'],'url' => $author['author_link'],'photo' => array('src' => $author['author_photo']))); + $name = ''; + if($author['full_name']) { + $name = $author['full_name']; + if($author['author_name']) + $name .= ' (' . $author['author_name'] . ')'; + } + else { + $name = $author['author_name']; + } + $x = import_author_unknown(array('name' => $name,'url' => $author['author_link'],'photo' => array('src' => $author['author_photo']))); if($x) $datarray['author_xchan'] = $x; } @@ -1037,7 +1081,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { intval($importer['channel_id']) ); if($c) { - $pmid = $x[0]['parent_mid']; + $pmid = $c[0]['parent_mid']; $datarray['parent_mid'] = $pmid; } } @@ -1052,6 +1096,44 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { $datarray['parent_mid'] = $pmid; } } + if((! $pmid) && $parent_link !== '') { + $f = feed_conversation_fetch($importer,$contact,$parent_link); + if($f) { + // check both potential conversation parents again + if($conv_id) { + $c = q("select parent_mid from item left join iconfig on item.id = iconfig.iid where iconfig.cat = 'ostatus' and iconfig.k = 'conversation' and iconfig.v = '%s' and item.uid = %d order by item.id limit 1", + dbesc($conv_id), + intval($importer['channel_id']) + ); + if($c) { + $pmid = $c[0]['parent_mid']; + $datarray['parent_mid'] = $pmid; + } + } + if(! $pmid) { + $x = q("select parent_mid from item where mid = '%s' and uid = %d limit 1", + dbesc($parent_mid), + intval($importer['channel_id']) + ); + + if($x) { + $pmid = $x[0]['parent_mid']; + $datarray['parent_mid'] = $pmid; + } + } + } + + // the conversation parent might just be the post we are trying to import. + // check existence again in case it was just delivered. + + $r = q("SELECT id FROM item WHERE mid = '%s' AND uid = %d LIMIT 1", + dbesc($datarray['mid']), + intval($importer['channel_id']) + ); + if($r) { + continue; + } + } if(! $pmid) { @@ -1116,7 +1198,16 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { } if($author['author_link'] != $contact['xchan_url']) { - $x = import_author_unknown(array('name' => $author['author_name'],'url' => $author['author_link'],'photo' => array('src' => $author['author_photo']))); + $name = ''; + if($author['full_name']) { + $name = $author['full_name']; + if($author['author_name']) + $name .= ' (' . $author['author_name'] . ')'; + } + else { + $name = $author['author_name']; + } + $x = import_author_unknown(array('name' => $name,'url' => $author['author_link'],'photo' => array('src' => $author['author_photo']))); if($x) $datarray['author_xchan'] = $x; } @@ -1182,6 +1273,51 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { } } + +function feed_conversation_fetch($importer,$contact,$parent_link) { + + logger('parent_link: ' . $parent_link, LOGGER_DEBUG, LOG_INFO); + + $link = ''; + + // GNU-Social flavoured feeds + if(strpos($parent_link,'/notice/')) { + $link = str_replace('/notice/','/api/statuses/show/',$parent_link) . '.atom'; + } + + // Mastodon flavoured feeds + if(strpos($parent_link,'/users/') && strpos($parent_link,'/updates/')) { + $link = $parent_link . '.atom'; + } + + if(! $link) + return false; + + logger('fetching: ' . $link, LOGGER_DEBUG, LOG_INFO); + + $fetch = z_fetch_url($link); + + if(! $fetch['success']) + return false; + + $data = $fetch['body']; + + // We will probably receive an atom 'entry' and not an atom 'feed'. Unfortunately + // our parser is a bit strict about compliance so we'll insert just enough of a feed + // tag to trick it into believing it's a compliant feed. + + if(! strstr($data,'<feed')) { + $data = str_replace('<entry ','<feed xmlns="http://www.w3.org/2005/Atom"><entry ',$data); + $data .= '</feed>'; + } + + consume_feed($data,$importer,$contact,1); + consume_feed($data,$importer,$contact,2); + + return true; + +} + /** * @brief Normalise an id. * diff --git a/include/follow.php b/include/follow.php index 0d7c16aa3..2c2f5e209 100644 --- a/include/follow.php +++ b/include/follow.php @@ -226,12 +226,12 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) if($abook_instance) $abook_instance .= ','; $abook_instance .= z_root(); - } - $x = q("update abook set abook_instance = '%s' where abook_id = %d", - dbesc($abook_instance), - intval($r[0]['abook_id']) - ); + $x = q("update abook set abook_instance = '%s', abook_not_here = 0 where abook_id = %d", + dbesc($abook_instance), + intval($r[0]['abook_id']) + ); + } if(intval($r[0]['abook_pending'])) { $x = q("update abook set abook_pending = 0 where abook_id = %d", diff --git a/include/help.php b/include/help.php index e4725575d..4f9251b1b 100644 --- a/include/help.php +++ b/include/help.php @@ -57,7 +57,7 @@ function get_help_content($tocpath = false) { if(! $text) { $doctype = 'bbcode'; $text = load_doc_file('doc/main.bb'); - goaway('/help/about/about_hubzilla'); + goaway('/help/about/about'); \App::$page['title'] = t('Help'); } @@ -116,9 +116,11 @@ function load_doc_file($s) { $b = basename($s); $d = dirname($s); - $c = find_doc_file("$d/$lang/$b"); - if($c) - return $c; + if($dirname !== '-') { + $c = find_doc_file("$d/$lang/$b"); + if($c) + return $c; + } $c = find_doc_file($s); if($c) return $c; @@ -140,8 +142,8 @@ function find_doc_file($s) { */ function search_doc_files($s) { - $itemspage = get_pconfig(local_channel(),'system','itemspage'); - \App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); + + \App::set_pager_itemspage(60); $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']), intval(\App::$pager['start'])); $regexop = db_getfunc('REGEXP'); @@ -198,6 +200,7 @@ function doc_rank_sort($s1, $s2) { * * @return string */ + function load_context_help() { $path = App::$cmd; diff --git a/include/import.php b/include/import.php index faab29bc0..277d6618c 100644 --- a/include/import.php +++ b/include/import.php @@ -631,12 +631,6 @@ function import_items($channel, $items, $sync = false, $relocate = null) { fix_attached_file_permissions($channel,$item['author_xchan'],$item['body'],$item['allow_cid'],$item['allow_gid'],$item['deny_cid'],$item['deny_gid']); - if($sync && $item['item_wall']) { - // deliver singletons if we have any - if($item_result && $item_result['success']) { - Zotlabs\Daemon\Master::Summon( [ 'Notifier','single_activity',$item_result['item_id'] ]); - } - } } } } @@ -1010,9 +1004,6 @@ function import_mail($channel, $mails, $sync = false) { $m['aid'] = $channel['channel_account_id']; $m['uid'] = $channel['channel_id']; $mail_id = mail_store($m); - if($sync && $mail_id) { - Zotlabs\Daemon\Master::Summon(array('Notifier','single_mail',$mail_id)); - } } } } diff --git a/include/items.php b/include/items.php index 4a028be6e..b313193fb 100755 --- a/include/items.php +++ b/include/items.php @@ -8,6 +8,7 @@ use Zotlabs\Lib as Zlib; require_once('include/bbcode.php'); require_once('include/oembed.php'); require_once('include/crypto.php'); +require_once('include/message.php'); require_once('include/feedutils.php'); require_once('include/photo/photo_driver.php'); require_once('include/permissions.php'); @@ -260,8 +261,6 @@ function can_comment_on_post($observer_xchan, $item) { } if(strstr($item['comment_policy'],'network:') && strstr($item['comment_policy'],'red')) return true; - if(strstr($item['comment_policy'],'network:') && strstr($item['comment_policy'],'diaspora')) - return true; if(strstr($item['comment_policy'],'site:') && strstr($item['comment_policy'],App::get_hostname())) return true; @@ -599,11 +598,6 @@ function get_item_elements($x,$allow_code = false) { $arr['sig'] = (($x['signature']) ? htmlspecialchars($x['signature'], ENT_COMPAT,'UTF-8',false) : ''); - if(array_key_exists('diaspora_signature',$x) && is_array($x['diaspora_signature'])) - $x['diaspora_signature'] = json_encode($x['diaspora_signature']); - - $arr['diaspora_meta'] = (($x['diaspora_signature']) ? $x['diaspora_signature'] : ''); - $arr['obj'] = activity_sanitise($x['object']); $arr['target'] = activity_sanitise($x['target']); @@ -809,8 +803,10 @@ function import_author_xchan($x) { if((! array_key_exists('network', $x)) || ($x['network'] === 'zot')) { $y = import_author_zot($x); } - if(! $y) - $y = import_author_diaspora($x); + + // if we were told that it's a zot connection, don't probe/import anything else + if(array_key_exists('network',$x) && $x['network'] === 'zot') + return $y; if($x['network'] === 'rss') { $y = import_author_rss($x); @@ -821,36 +817,7 @@ function import_author_xchan($x) { } return($y); -} - -/** - * @brief Imports an author from Diaspora. - * - * @param array $x an associative array with - * * \e string \b address - * @return boolean|string false on error, otherwise xchan_hash of the new entry - */ -function import_author_diaspora($x) { - if(! $x['address']) - return false; - - $r = q("select * from xchan where xchan_addr = '%s' limit 1", - dbesc($x['address']) - ); - if($r) { - logger('in_cache: ' . $x['address'], LOGGER_DATA); - return $r[0]['xchan_hash']; - } - - if(discover_by_webbie($x['address'])) { - $r = q("select xchan_hash from xchan where xchan_addr = '%s' limit 1", - dbesc($x['address']) - ); - if($r) - return $r[0]['xchan_hash']; - } - return false; } /** @@ -862,6 +829,7 @@ function import_author_diaspora($x) { * * \e string \b guid * @return boolean|string */ + function import_author_rss($x) { if(! $x['url']) return false; @@ -909,6 +877,11 @@ function import_author_rss($x) { function import_author_unknown($x) { + $arr = [ 'author' => $x, 'result' => false ]; + call_hooks('import_author', $arr); + if($arr['result']) + return $arr['result']; + if(! $x['url']) return false; @@ -1068,17 +1041,7 @@ function encode_item($item,$mirror = false) { if($item['iconfig']) $x['meta'] = encode_item_meta($item['iconfig'],$mirror); - if($item['diaspora_meta']) { - $z = json_decode($item['diaspora_meta'],true); - if($z) { - if(is_array($z) && array_key_exists('iv',$z)) - $x['diaspora_signature'] = crypto_unencapsulate($z,$key); - else - $x['diaspora_signature'] = $z; - if(! is_array($z)) - logger('encode_item: diaspora meta is not an array: ' . print_r($z,true)); - } - } + logger('encode_item: ' . print_r($x,true), LOGGER_DATA); return $x; @@ -1359,7 +1322,6 @@ function encode_mail($item,$extended = false) { $x['message_parent'] = $item['parent_mid']; $x['created'] = $item['created']; $x['expires'] = $item['expires']; - $x['diaspora_meta'] = $item['diaspora_meta']; $x['title'] = $item['title']; $x['body'] = $item['body']; $x['from'] = encode_item_xchan($item['from']); @@ -1581,7 +1543,6 @@ function item_store($arr, $allow_exec = false, $deliver = true) { $arr['title'] = ((array_key_exists('title',$arr) && strlen($arr['title'])) ? trim($arr['title']) : ''); $arr['body'] = ((array_key_exists('body',$arr) && strlen($arr['body'])) ? trim($arr['body']) : ''); - $arr['diaspora_meta'] = ((x($arr,'diaspora_meta')) ? $arr['diaspora_meta'] : ''); $arr['allow_cid'] = ((x($arr,'allow_cid')) ? trim($arr['allow_cid']) : ''); $arr['allow_gid'] = ((x($arr,'allow_gid')) ? trim($arr['allow_gid']) : ''); $arr['deny_cid'] = ((x($arr,'deny_cid')) ? trim($arr['deny_cid']) : ''); @@ -2081,7 +2042,7 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) { $arr['changed'] = $orig[0]['changed']; $arr['route'] = ((array_key_exists('route',$arr)) ? trim($arr['route']) : $orig[0]['route']); - $arr['diaspora_meta'] = ((x($arr,'diaspora_meta')) ? $arr['diaspora_meta'] : $orig[0]['diaspora_meta']); + $arr['location'] = ((x($arr,'location')) ? notags(trim($arr['location'])) : $orig[0]['location']); $arr['coord'] = ((x($arr,'coord')) ? notags(trim($arr['coord'])) : $orig[0]['coord']); $arr['verb'] = ((x($arr,'verb')) ? notags(trim($arr['verb'])) : $orig[0]['verb']); @@ -2240,55 +2201,6 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) { -function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id, $walltowall = false) { - - // We won't be able to sign Diaspora comments for authenticated visitors - // - we don't have their private key - - // since Diaspora doesn't handle edits we can only do this for the original text and not update it. - - require_once('include/markdown.php'); - $signed_body = bb2diaspora_itembody($datarray,$walltowall); - - if($walltowall) { - logger('wall to wall comment',LOGGER_DEBUG); - // post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author. - $signed_body = "\n\n" - . '![' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_photo_m'] . ')' - . '[' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_url'] . ')' . "\n\n" - . $signed_body; - } - - logger('storing diaspora comment signature',LOGGER_DEBUG); - - $diaspora_handle = channel_reddress($channel); - - $signed_text = $datarray['mid'] . ';' . $parent_item['mid'] . ';' . $signed_body . ';' . $diaspora_handle; - - - if( $channel && $channel['channel_prvkey'] ) - $authorsig = base64_encode(rsa_sign($signed_text, $channel['channel_prvkey'], 'sha256')); - else - $authorsig = ''; - - $x = array('signer' => $diaspora_handle, 'body' => $signed_body, 'signed_text' => $signed_text, 'signature' => $authorsig); - - $y = json_encode($x); - - $r = q("update item set diaspora_meta = '%s' where id = %d", - dbesc($y), - intval($post_id) - ); - - - if(! $r) - logger('store_diaspora_comment_sig: DB write failed'); - - return; -} - - - function send_status_notifications($post_id,$item) { // only send notifications for comments @@ -3021,6 +2933,8 @@ function mail_store($arr) { return 0; } + $channel = channelx_by_n($arr['channel_id']); + if(! $arr['mail_obscured']) { if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false)) $arr['body'] = escape_tags($arr['body']); @@ -3051,11 +2965,34 @@ function mail_store($arr) { $arr['mail_flags'] = ((x($arr,'mail_flags')) ? intval($arr['mail_flags']) : 0 ); $arr['mail_raw'] = ((x($arr,'mail_raw')) ? intval($arr['mail_raw']) : 0 ); - if(! $arr['parent_mid']) { + + + if($arr['parent_mid']) { + $parent_item = q("select * from mail where mid = '%s' and channel_id = %d limit 1", + dbesc($arr['parent_mid']), + intval($arr['channel_id']) + ); + if(($parent_item) && (! $arr['conv_guid'])) { + $arr['conv_guid'] = $parent_item[0]['conv_guid']; + } + } + else { logger('mail_store: missing parent'); $arr['parent_mid'] = $arr['mid']; } + if($arr['from_xchan'] === $channel['channel_hash']) + $conversant = $arr['to_xchan']; + else + $conversant = $arr['from_xchan']; + + + if(! $arr['conv_guid']) { + $x = create_conversation($channel,$conversant,(($arr['title']) ? base64url_decode(str_rot47($arr['title'])) : '')); + $arr['conv_guid'] = (($x) ? $x['guid'] : ''); + } + + $r = q("SELECT id FROM mail WHERE mid = '%s' AND channel_id = %d LIMIT 1", dbesc($arr['mid']), intval($arr['channel_id']) @@ -3120,6 +3057,14 @@ function mail_store($arr) { Zlib\Enotify::submit($notif_params); } + if($arr['conv_guid']) { + $c = q("update conv set updated = '%s' where guid = '%s' and uid = %d", + dbesc(datetime_convert()), + dbesc($arr['conv_guid']), + intval($arr['channel_id']) + ); + } + call_hooks('post_mail_end',$arr); return $current_post; } diff --git a/include/markdown.php b/include/markdown.php index 3ade03971..5d3c4c7df 100644 --- a/include/markdown.php +++ b/include/markdown.php @@ -13,71 +13,6 @@ require_once("include/html2bbcode.php"); require_once("include/bbcode.php"); - - -function diaspora_mention_callback($matches) { - - $webbie = $matches[2] . '@' . $matches[3]; - $link = ''; - if($webbie) { - $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_addr = '%s' limit 1", - dbesc($webbie) - ); - if(! $r) { - $x = discover_by_webbie($webbie); - if($x) { - $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_addr = '%s' limit 1", - dbesc($webbie) - ); - } - } - if($r) - $link = $r[0]['xchan_url']; - } - if(! $link) - $link = 'https://' . $matches[3] . '/u/' . $matches[2]; - - if($r && $r[0]['hubloc_network'] === 'zot') - return '@[zrl=' . $link . ']' . trim($matches[1]) . ((substr($matches[0],-1,1) === '+') ? '+' : '') . '[/zrl]' ; - else - return '@[url=' . $link . ']' . trim($matches[1]) . ((substr($matches[0],-1,1) === '+') ? '+' : '') . '[/url]' ; - -} - -function diaspora_mention_callback2($matches) { - - $webbie = $matches[1] . '@' . $matches[2]; - $link = ''; - if($webbie) { - $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_addr = '%s' limit 1", - dbesc($webbie) - ); - if(! $r) { - $x = discover_by_webbie($webbie); - if($x) { - $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_addr = '%s' limit 1", - dbesc($webbie) - ); - } - } - if($r) - $link = $r[0]['xchan_url']; - } - - $name = (($r) ? $r[0]['xchan_name'] : $matches[1]); - - if(! $link) - $link = 'https://' . $matches[2] . '/u/' . $matches[1]; - - if($r && $r[0]['hubloc_network'] === 'zot') - return '@[zrl=' . $link . ']' . trim($name) . ((substr($matches[0],-1,1) === '+') ? '+' : '') . '[/zrl]' ; - else - return '@[url=' . $link . ']' . trim($name) . ((substr($matches[0],-1,1) === '+') ? '+' : '') . '[/url]' ; - -} - - - /** * @brief * @@ -90,28 +25,29 @@ function diaspora_mention_callback2($matches) { * @param boolean $use_zrl default false * @return string */ -function markdown_to_bb($s, $use_zrl = false) { - $s = str_replace("
","\r",$s); - $s = str_replace("
\n>","",$s); +function markdown_to_bb($s, $use_zrl = false, $options = []) { + if(is_array($s)) { btlogger('markdown_to_bb called with array. ' . print_r($s,true), LOGGER_NORMAL, LOG_WARNING); return ''; } + + $s = str_replace("
","\r",$s); + $s = str_replace("
\n>","",$s); + $s = html_entity_decode($s,ENT_COMPAT,'UTF-8'); // if empty link text replace with the url $s = preg_replace("/\[\]\((.*?)\)/ism",'[$1]($1)',$s); - // first try plustags + $x = [ 'text' => $s , 'zrl' => $use_zrl, 'options' => $options ]; - $s = preg_replace_callback('/\@\{(.+?)\; (.+?)\@(.+?)\}\+/','diaspora_mention_callback',$s); - $s = preg_replace_callback('/\@\{(.+?)\; (.+?)\@(.+?)\}/','diaspora_mention_callback',$s); + call_hooks('markdown_to_bb_init',$x); - $s = preg_replace_callback('/\@\{(.+?)\@(.+?)\}\+/','diaspora_mention_callback2',$s); - $s = preg_replace_callback('/\@\{(.+?)\@(.+?)\}/','diaspora_mention_callback2',$s); + $s = $x['text']; // Escaping the hash tags - doesn't always seem to work // $s = preg_replace('/\#([^\s\#])/','\\#$1',$s); @@ -126,9 +62,6 @@ function markdown_to_bb($s, $use_zrl = false) { $s = html2bbcode($s); - // protect the recycle symbol from turning into a tag, but without unescaping angles and naked ampersands - $s = str_replace('♲',html_entity_decode('♲',ENT_QUOTES,'UTF-8'),$s); - // Convert everything that looks like a link to a link if($use_zrl) { $s = str_replace(array('[img','/img]'),array('[zmg','/zmg]'),$s); @@ -150,283 +83,25 @@ function markdown_to_bb($s, $use_zrl = false) { } -function stripdcode_br_cb($s) { - return '[code]' . str_replace('<br />', "\n\t", $s[1]) . '[/code]'; -} - - -////////////////////// -// The following "diaspora_ul" and "diaspora_ol" are only appropriate for the -// pre-Markdownify conversion. If Markdownify isn't used, use the non-Markdownify -// versions below -////////////////////// -/* -function diaspora_ul($s) { - // Replace "[*]" followed by any number (including zero) of - // spaces by "* " to match Diaspora's list format - if( strpos($s[0], "[list]") === 0 ) - return '<ul class="listbullet" style="list-style-type: circle;">' . preg_replace("/\[\*\]( *)/", "* ", $s[1]) . '</ul>'; - elseif( strpos($s[0], "[ul]") === 0 ) - return '<ul class="listbullet" style="list-style-type: circle;">' . preg_replace("/\[\*\]( *)/", "* ", $s[1]) . '</ul>'; - else - return $s[0]; -} -function diaspora_ol($s) { - // A hack: Diaspora will create a properly-numbered ordered list even - // if you use '1.' for each element of the list, like: - // 1. First element - // 1. Second element - // 1. Third element - if( strpos($s[0], "[list=1]") === 0 ) - return '<ul class="listdecimal" style="list-style-type: decimal;">' . preg_replace("/\[\*\]( *)/", "1. ", $s[1]) . '</ul>'; - elseif( strpos($s[0], "[list=i]") === 0 ) - return '<ul class="listlowerroman" style="list-style-type: lower-roman;">' . preg_replace("/\[\*\]( *)/", "1. ", $s[1]) . '</ul>'; - elseif( strpos($s[0], "[list=I]") === 0 ) - return '<ul class="listupperroman" style="list-style-type: upper-roman;">' . preg_replace("/\[\*\]( *)/", "1. ", $s[1]) . '</ul>'; - elseif( strpos($s[0], "[list=a]") === 0 ) - return '<ul class="listloweralpha" style="list-style-type: lower-alpha;">' . preg_replace("/\[\*\]( *)/", "1. ", $s[1]) . '</ul>'; - elseif( strpos($s[0], "[list=A]") === 0 ) - return '<ul class="listupperalpha" style="list-style-type: upper-alpha;">' . preg_replace("/\[\*\]( *)/", "1. ", $s[1]) . '</ul>'; - elseif( strpos($s[0], "[ol]") === 0 ) - return '<ul class="listdecimal" style="list-style-type: decimal;">' . preg_replace("/\[\*\]( *)/", "1. ", $s[1]) . '</ul>'; - else - return $s[0]; -} -*/ +function bb_to_markdown($Text) { -////////////////////// -// Non-Markdownify versions of "diaspora_ol" and "diaspora_ul" -////////////////////// -/** - * @brief - * - * Replace "[\\*]" followed by any number (including zero) of - * spaces by "* " to match Diaspora's list format. - * - * @param string $s - * @return string - */ -function diaspora_ul($s) { - return preg_replace("/\[\\\\\*\]( *)/", "* ", $s[1]); -} + /* + * Transform #tags, strip off the [url] and replace spaces with underscore + */ -/** - * @brief - * - * A hack: Diaspora will create a properly-numbered ordered list even - * if you use '1.' for each element of the list, like: - * \code - * 1. First element - * 1. Second element - * 1. Third element - * \endcode - * @param string $s - * @return string - */ -function diaspora_ol($s) { - return preg_replace("/\[\\\\\*\]( *)/", "1. ", $s[1]); -} - -function bb2dmention_callback($match) { + $Text = preg_replace_callback('/#\[([zu])rl\=(\w+.*?)\](\w+.*?)\[\/[(zu)]rl\]/i', + create_function('$match', 'return \'#\'. str_replace(\' \', \'_\', $match[3]);'), $Text); - $r = q("select xchan_addr from xchan where xchan_url = '%s'", - dbesc($match[2]) - ); - - if($r) - return '@{' . $match[3] . ' ; ' . $r[0]['xchan_addr'] . '}'; - - return '@' . $match[3]; -} - - -function bb2diaspora_itemwallwall(&$item,$uplink = false) { - - // We will provide wallwall (embedded author on the Diaspora side) if - // 1. It is a wall-to-wall post - // 2. A comment arrived which has no Diaspora signature info - - - $wallwall = false; - $author_exists = true; - - if(! array_key_exists('author',$item)) { - $author_exists = false; - logger('bb2diaspora_itemwallwall: no author'); - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($item['author_xchan']) - ); - if($r) - $item['author'] = $r[0]; - } - - $has_meta = false; - if($item['diaspora_meta'] || get_iconfig($item,'diaspora','fields')) - $has_meta = true; - - if($item['author_xchan'] != $item['owner_xchan']) { - if($item['mid'] == $item['parent_mid']) - $wallwall = true; - else { - if(! $has_meta) { - $wallwall = true; - } - } - } - - if($uplink) - $wallwall = true; - - if(($wallwall) && (is_array($item['author'])) && $item['author']['xchan_url'] && $item['author']['xchan_name'] && $item['author']['xchan_photo_s']) { - logger('bb2diaspora_itemwallwall: wall to wall post',LOGGER_DEBUG); - // post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author. - $item['body'] = "\n\n" - . '[quote]' - . '[img]' . $item['author']['xchan_photo_s'] . '[/img]' - . ' ' - . '[url=' . $item['author']['xchan_url'] . '][b]' . $item['author']['xchan_name'] . '[/b][/url]' . "\n\n" - . $item['body'] - . '[/quote]'; - } - - // $item['author'] might cause a surprise further down the line if it wasn't expected to be here. - - if(! $author_exists) - unset($item['author']); -} - - -function bb2diaspora_itembody($item, $force_update = false, $have_channel = false, $uplink = false) { - - if(! get_iconfig($item,'diaspora','fields')) { - $force_update = true; - } - - $matches = array(); - - if(($item['diaspora_meta']) && (! $force_update)) { - $diaspora_meta = json_decode($item['diaspora_meta'],true); - if($diaspora_meta) { - if(array_key_exists('iv',$diaspora_meta)) { - $key = get_config('system','prvkey'); - $meta = json_decode(crypto_unencapsulate($diaspora_meta,$key),true); - } - else { - $meta = $diaspora_meta; - } - if($meta) { - logger('bb2diaspora_itembody: cached '); - $newitem = $item; - $newitem['body'] = $meta['body']; - return $newitem['body']; - } - } - } - - create_export_photo_body($item); - - $newitem = $item; - - if(array_key_exists('item_obscured',$item) && intval($item['item_obscured'])) { - $key = get_config('system','prvkey'); - $b = json_decode($item['body'],true); - // if called from diaspora_process_outbound, this decoding has already been done. - // Everything else that calls us will not yet be decoded. - if($b && is_array($b) && array_key_exists('iv',$b)) { - $newitem['title'] = (($item['title']) ? crypto_unencapsulate(json_decode($item['title'],true),$key) : ''); - $newitem['body'] = (($item['body']) ? crypto_unencapsulate(json_decode($item['body'],true),$key) : ''); - } - } - - if(! $have_channel) - bb2diaspora_itemwallwall($newitem,$uplink); - - $title = $newitem['title']; - $body = preg_replace('/\#\^http/i', 'http', $newitem['body']); - - // protect tags and mentions from hijacking - - if(intval(get_pconfig($item['uid'],'system','prevent_tag_hijacking'))) { - $new_tag = html_entity_decode('⋕',ENT_COMPAT,'UTF-8'); - $new_mention = html_entity_decode('@',ENT_COMPAT,'UTF-8'); - - // #-tags - $body = preg_replace('/\#\[url/i', $new_tag . '[url', $body); - $body = preg_replace('/\#\[zrl/i', $new_tag . '[zrl', $body); - // @-mentions - $body = preg_replace('/\@\!?\[url/i', $new_mention . '[url', $body); - $body = preg_replace('/\@\!?\[zrl/i', $new_mention . '[zrl', $body); - } - - // remove multiple newlines - do { - $oldbody = $body; - $body = str_replace("\n\n\n", "\n\n", $body); - } while ($oldbody != $body); - - $body = bb2diaspora($body); - - if(strlen($title)) - $body = "## " . $title . "\n\n" . $body; - - if($item['attach']) { - $cnt = preg_match_all('/href=\"(.*?)\"(.*?)title=\"(.*?)\"/ism', $item['attach'], $matches, PREG_SET_ORDER); - if($cnt) { - $body .= "\n" . t('Attachments:') . "\n"; - foreach($matches as $mtch) { - $body .= '[' . $mtch[3] . '](' . $mtch[1] . ')' . "\n"; - } - } - } - -// logger('bb2diaspora_itembody : ' . $body, LOGGER_DATA); - - return html_entity_decode($body); -} - -/** - * @brief Prepare bbcode for Diaspora. - * - * @hooks bb2diaspora - * * \e string The prepared text for diaspora. - * - * @param string $Text bbcode - * @param boolean $preserve_nl (default false) preserve new lines - * @param boolean $fordiaspora (default true, but unused) - * @return string - */ -function bb2diaspora($Text, $preserve_nl = false, $fordiaspora = true) { - - // Re-enabling the converter again. - // The bbcode parser now handles youtube-links (and the other stuff) correctly. - // Additionally the html code is now fixed so that lists are now working. - - // Transform #tags, strip off the [url] and replace spaces with underscore - $Text = preg_replace_callback('/#\[([zu])rl\=(\w+.*?)\](\w+.*?)\[\/[(zu)]rl\]/i', create_function('$match', - 'return \'#\'. str_replace(\' \', \'_\', $match[3]);' - ), $Text); $Text = preg_replace('/#\^\[([zu])rl\=(\w+.*?)\](\w+.*?)\[\/([zu])rl\]/i', '[$1rl=$2]$3[/$4rl]', $Text); - $Text = preg_replace_callback('/\@\!?\[([zu])rl\=(\w+.*?)\](\w+.*?)\[\/([zu])rl\]/i', 'bb2dmention_callback', $Text); - - // strip map tags, as the rendering is performed in bbcode() and the resulting output - // is not compatible with Diaspora (at least in the case of openstreetmap and probably - // due to the inclusion of an html iframe) - $Text = preg_replace("/\[map\=(.*?)\]/ism", '$1', $Text); - $Text = preg_replace("/\[map\](.*?)\[\/map\]/ism", '$1', $Text); - // Converting images with size parameters to simple images. Markdown doesn't know it. $Text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $Text); - // the following was added on 10-January-2012 due to an inability of Diaspora's - // new javascript markdown processor to handle links with images as the link "text" - // It is not optimal and may be removed if this ability is restored in the future - //if ($fordiaspora) - // $Text = preg_replace("/\[url\=([^\[\]]*)\]\s*\[img\](.*?)\[\/img\]\s*\[\/url\]/ism", - // "[url]$1[/url]\n[img]$2[/img]", $Text); + + call_hooks('bb_to_markdown_bb',$Text); // Convert it to HTML - don't try oembed $Text = bbcode($Text, $preserve_nl, false); @@ -435,9 +110,11 @@ function bb2diaspora($Text, $preserve_nl = false, $fordiaspora = true) { $Text = str_replace(array('<','>','&'),array('&_lt_;','&_gt_;','&_amp_;'),$Text); // Now convert HTML to Markdown + $Text = html2markdown($Text); // It also adds backslashes to our attempt at getting around the html entity preservation for some weird reason. + $Text = str_replace(array('&\\_lt\\_;','&\\_gt\\_;','&\\_amp\\_;'),array('<','>','&'),$Text); // If the text going into bbcode() has a plain URL in it, i.e. @@ -449,57 +126,18 @@ function bb2diaspora($Text, $preserve_nl = false, $fordiaspora = true) { // Remove empty zrl links $Text = preg_replace("/\[zrl\=\].*?\[\/zrl\]/is", "", $Text); - // Remove all unconverted tags - $Text = strip_tags($Text); + // escape all unconverted tags + $Text = escape_tags($Text); - // Remove any leading or trailing whitespace, as this will mess up - // the Diaspora signature verification and cause the item to disappear $Text = trim($Text); - call_hooks('bb2diaspora', $Text); + call_hooks('bb_to_markdown', $Text); return $Text; -} -function unescape_underscores_in_links($m) { - $y = str_replace('\\_','_', $m[2]); - return('[' . $m[1] . '](' . $y . ')'); } -function format_event_diaspora($ev) { - - if(! ((is_array($ev)) && count($ev))) - return ''; - - $bd_format = t('l F d, Y \@ g:i A') ; // Friday January 18, 2011 @ 8 AM - - $o = t('$Projectname event notification:') . "\n"; - $o .= '**' . (($ev['summary']) ? bb2diaspora($ev['summary']) : bb2diaspora($ev['desc'])) . '**' . "\n"; - - $o .= t('Starts:') . ' ' . '[' - . (($ev['adjust']) ? day_translate(datetime_convert('UTC', 'UTC', - $ev['start'] , $bd_format )) - : day_translate(datetime_convert('UTC', 'UTC', - $ev['start'] , $bd_format))) - . '](' . z_root() . '/localtime/?f=&time=' . urlencode(datetime_convert('UTC','UTC',$ev['start'])) . ")\n"; - - if(! $ev['nofinish']) - $o .= t('Finishes:') . ' ' . '[' - . (($ev['adjust']) ? day_translate(datetime_convert('UTC', 'UTC', - $ev['finish'] , $bd_format )) - : day_translate(datetime_convert('UTC', 'UTC', - $ev['finish'] , $bd_format ))) - . '](' . z_root() . '/localtime/?f=&time=' . urlencode(datetime_convert('UTC','UTC',$ev['finish'])) . ")\n"; - - if(strlen($ev['location'])) - $o .= t('Location:') . bb2diaspora($ev['location']) - . "\n"; - - $o .= "\n"; - - return $o; -} /** * @brief Convert a HTML text into Markdown. diff --git a/include/message.php b/include/message.php index 5458eeb0e..3f003e020 100644 --- a/include/message.php +++ b/include/message.php @@ -104,38 +104,9 @@ function send_message($uid = 0, $recipient = '', $body = '', $subject = '', $rep // create a new conversation - $conv_guid = random_string(); - - $recip = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($recipient) - ); - if($recip) - $recip_handle = $recip[0]['xchan_addr']; - - $sender_handle = channel_reddress($channel); - - $handles = $recip_handle . ';' . $sender_handle; - - if($subject) - $nsubject = str_rot47(base64url_encode($subject)); - - $r = q("insert into conv (uid,guid,creator,created,updated,subject,recips) values(%d, '%s', '%s', '%s', '%s', '%s', '%s') ", - intval(local_channel()), - dbesc($conv_guid), - dbesc($sender_handle), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($nsubject), - dbesc($handles) - ); - - $r = q("select * from conv where guid = '%s' and uid = %d limit 1", - dbesc($conv_guid), - intval(local_channel()) - ); - if($r) { - $retconv = $r[0]; - $retconv['subject'] = base64url_decode(str_rot47($retconv['subject'])); + $retconv = create_conversation($channel,$recipient,$subject); + if($retconv) { + $conv_guid = $retconv['guid']; } } @@ -146,7 +117,6 @@ function send_message($uid = 0, $recipient = '', $body = '', $subject = '', $rep ); if($r) { $retconv = $r[0]; - $retconv['subject'] = base64url_decode(str_rot47($retconv['subject'])); } } @@ -155,6 +125,12 @@ function send_message($uid = 0, $recipient = '', $body = '', $subject = '', $rep return $ret; } + $c = q("update conv set updated = '%s' where guid = '%s' and uid = %d", + dbesc(datetime_convert()), + dbesc($conv_guid), + intval(local_channel()) + ); + // generate a unique message_id do { @@ -284,6 +260,49 @@ function send_message($uid = 0, $recipient = '', $body = '', $subject = '', $rep } +function create_conversation($channel,$recipient,$subject) { + + // create a new conversation + + $conv_guid = random_string(); + + $recip = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($recipient) + ); + if($recip) + $recip_handle = $recip[0]['xchan_addr']; + + $sender_handle = channel_reddress($channel); + + $handles = $recip_handle . ';' . $sender_handle; + + if($subject) + $nsubject = str_rot47(base64url_encode($subject)); + + $r = q("insert into conv (uid,guid,creator,created,updated,subject,recips) values(%d, '%s', '%s', '%s', '%s', '%s', '%s') ", + intval($channel['channel_id']), + dbesc($conv_guid), + dbesc($sender_handle), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc($nsubject), + dbesc($handles) + ); + + $r = q("select * from conv where guid = '%s' and uid = %d limit 1", + dbesc($conv_guid), + intval($channel['channel_id']) + ); + + return $r[0]; + +} + + + + + + function private_messages_list($uid, $mailbox = '', $start = 0, $numitems = 0) { $where = ''; @@ -315,6 +334,8 @@ function private_messages_list($uid, $mailbox = '', $start = 0, $numitems = 0) { break; case 'combined': + default: + $parents = q("SELECT parent_mid FROM mail WHERE mid = parent_mid AND channel_id = %d ORDER BY created DESC", dbesc($local_channel) ); @@ -326,15 +347,21 @@ function private_messages_list($uid, $mailbox = '', $start = 0, $numitems = 0) { } + $r = null; + if($parents) { foreach($parents as $parent) { - $all[] = q("SELECT * FROM mail WHERE parent_mid = '%s' AND channel_id = %d ORDER BY created DESC", + $all = q("SELECT * FROM mail WHERE parent_mid = '%s' AND channel_id = %d ORDER BY created DESC limit 1", dbesc($parent['parent_mid']), dbesc($local_channel) ); + + if($all) { + foreach($all as $single) { + $r[] = $single; + } + } } - foreach($all as $single) - $r[] = $single[0]; } else { $r = q($sql); diff --git a/include/nav.php b/include/nav.php index 2eba2894c..b0533e4c7 100644 --- a/include/nav.php +++ b/include/nav.php @@ -65,8 +65,6 @@ EOT; //we could additionally use this to display important system notifications e.g. for updates )); - $server_role = get_config('system','server_role'); - $basic = (($server_role === 'basic') ? true : false); $techlevel = get_account_techlevel(); // nav links: array of array('href', 'text', 'extra css classes', 'title') @@ -97,7 +95,7 @@ EOT; if(local_channel()) { - if($chans && count($chans) > 1 && feature_enabled(local_channel(),'nav_channel_select') && (! $basic)) + if($chans && count($chans) > 1 && feature_enabled(local_channel(),'nav_channel_select')) $nav['channels'] = $chans; $nav['logout'] = ['logout',t('Logout'), "", t('End this session'),'logout_nav_btn']; @@ -105,7 +103,7 @@ EOT; // user menu $nav['usermenu'][] = ['profile/' . $channel['channel_address'], t('View Profile'), "", t('Your profile page'),'profile_nav_btn']; - if(feature_enabled(local_channel(),'multi_profiles') && (! $basic)) + if(feature_enabled(local_channel(),'multi_profiles')) $nav['usermenu'][] = ['profiles', t('Edit Profiles'),"", t('Manage/Edit profiles'),'profiles_nav_btn']; else $nav['usermenu'][] = ['profiles/' . $prof[0]['id'], t('Edit Profile'),"", t('Edit your profile'),'profiles_nav_btn']; @@ -201,8 +199,7 @@ EOT; $nav['all_events']['all']=array('events', t('View events'), "", ""); $nav['all_events']['mark'] = array('', t('Mark all events seen'), '',''); - if(! $basic) - $nav['manage'] = array('manage', t('Channel Manager'), "", t('Manage Your Channels'),'manage_nav_btn'); + $nav['manage'] = array('manage', t('Channel Manager'), "", t('Manage Your Channels'),'manage_nav_btn'); $nav['settings'] = array('settings', t('Settings'),"", t('Account/Channel Settings'),'settings_nav_btn'); diff --git a/include/network.php b/include/network.php index c03ca70f5..d3ccc498d 100644 --- a/include/network.php +++ b/include/network.php @@ -343,7 +343,7 @@ function z_post_url($url,$params, $redirects = 0, $opts = array()) { if (isset($url_parsed)) { curl_close($ch); if($http_code == 303) { - return z_fetch_url($newurl,false,$redirects++,$opts); + return z_fetch_url($newurl,false,++$redirects,$opts); } else { return z_post_url($newurl,$params,++$redirects,$opts); } @@ -397,31 +397,6 @@ function json_return_and_die($x, $content_type = 'application/json') { killme(); } - -/** - * @brief Generic XML return. - * - * Outputs a basic dfrn XML status structure to STDOUT, with a <status> variable - * of $st and an optional text <message> of $message and terminates the current - * process. - * - * @param string $st - * @param string $message - */ -function xml_status($st, $message = '') { - - $xml_message = ((strlen($message)) ? "\t<message>" . xmlify($message) . "</message>\r\n" : ''); - - if($st) - logger('Returning non_zero: ' . $st . " message=" . $message); - - header( "Content-type: text/xml" ); - echo '<?xml version="1.0" encoding="UTF-8"?>'."\r\n"; - echo "<result>\r\n\t<status>$st</status>\r\n$xml_message</result>\r\n"; - killme(); -} - - /** * @brief Send HTTP status header. * @@ -1007,39 +982,6 @@ function email_header_encode($in_str, $charset = 'UTF-8') { return $out_str; } -function email_send($addr, $subject, $headers, $item) { - //$headers .= 'MIME-Version: 1.0' . "\n"; - //$headers .= 'Content-Type: text/html; charset=UTF-8' . "\n"; - //$headers .= 'Content-Type: text/plain; charset=UTF-8' . "\n"; - //$headers .= 'Content-Transfer-Encoding: 8bit' . "\n\n"; - - $part = uniqid("", true); - - $html = prepare_body($item); - - $headers .= "Mime-Version: 1.0\n"; - $headers .= 'Content-Type: multipart/alternative; boundary="=_'.$part.'"'."\n\n"; - - $body = "\n--=_".$part."\n"; - $body .= "Content-Transfer-Encoding: 8bit\n"; - $body .= "Content-Type: text/plain; charset=utf-8; format=flowed\n\n"; - - $body .= html2plain($html)."\n"; - - $body .= "--=_".$part."\n"; - $body .= "Content-Transfer-Encoding: 8bit\n"; - $body .= "Content-Type: text/html; charset=utf-8\n\n"; - - $body .= '<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">'.$html."</body></html>\n"; - - $body .= "--=_".$part."--"; - - //$message = '<html><body>' . $html . '</body></html>'; - //$message = html2plain($html); - logger('notifier: email delivery to ' . $addr); - mail($addr, $subject, $body, $headers); -} - /** * @brief Creates an xchan entry for URL. * @@ -1056,10 +998,10 @@ function discover_by_url($url, $arr = null) { return false; $network = (($arr['network']) ? $arr['network'] : 'unknown'); - $name = (($arr['name']) ? $arr['name'] : 'unknown'); - $photo = (($arr['photo']) ? $arr['photo'] : ''); - $addr = (($arr['addr']) ? $arr['addr'] : ''); - $guid = $url; + $name = (($arr['name']) ? $arr['name'] : 'unknown'); + $photo = (($arr['photo']) ? $arr['photo'] : ''); + $addr = (($arr['addr']) ? $arr['addr'] : ''); + $guid = $url; } $profile = $url; @@ -1095,8 +1037,8 @@ function discover_by_url($url, $arr = null) { if($feed->error()) logger('scrape_feed: Error parsing XML: ' . $feed->error()); - $name = unxmlify(trim($feed->get_title())); - $photo = $feed->get_image_url(); + $name = unxmlify(trim($feed->get_title())); + $photo = $feed->get_image_url(); $author = $feed->get_author(); if($author) { @@ -1195,23 +1137,11 @@ function discover_by_url($url, $arr = null) { } function discover_by_webbie($webbie) { - require_once('library/HTML5/Parser.php'); - $result = array(); + $result = []; $network = null; - $diaspora = false; - $gnusoc = false; - $dfrn = false; - - $has_salmon = false; - $salmon_key = false; - $atom_feed = false; - $diaspora_base = ''; - $diaspora_guid = ''; - $diaspora_key = ''; - $webbie = strtolower($webbie); $x = webfinger_rfc7033($webbie,true); @@ -1237,21 +1167,6 @@ function discover_by_webbie($webbie) { } } } - if($link['rel'] == NAMESPACE_DFRN) { - $dfrn = $link['href']; - } - if($link['rel'] == 'magic-public-key') { - if(substr($link['href'],0,5) === 'data:') { - $salmon_key = convert_salmon_key($link['href']); - } - } - if($link['rel'] == 'salmon') { - $has_salmon = true; - $salmon = $link['href']; - } - if($link['rel'] == 'http://schemas.google.com/g/2010#updates-from') { - $atom_feed = $link['href']; - } } } } @@ -1263,275 +1178,9 @@ function discover_by_webbie($webbie) { if($arr['success']) return true; - $aliases = array(); - - // Now let's make some decisions on what we may need - // to obtain further info - - $probe_atom = false; - $probe_old = false; - $probe_hcard = false; - - $address = ''; - $location = ''; - $nickname = ''; - $fullname = ''; - $avatar = ''; - $pubkey = ''; - - if(is_array($x)) { - if(array_key_exists('address',$x)) - $address = $x['address']; - if(array_key_exists('location',$x)) - $location = $x['location']; - if(array_key_exists('nickname',$x)) - $nickname = $x['nickname']; - } - - if(! $x) - $probe_old = true; - - if((! $dfrn) && (! $has_salmon)) - $probe_old = true; - - if($probe_old) { - $y = old_webfinger($webbie); - if($y) { - logger('old_webfinger: ' . print_r($x,true)); - foreach($y as $link) { - if($link['@attributes']['rel'] === NAMESPACE_DFRN) - $dfrn = unamp($link['@attributes']['href']); - if($link['@attributes']['rel'] === 'salmon') - $notify = unamp($link['@attributes']['href']); - if($link['@attributes']['rel'] === NAMESPACE_FEED) - $poll = unamp($link['@attributes']['href']); - if($link['@attributes']['rel'] === 'http://microformats.org/profile/hcard') - $hcard = unamp($link['@attributes']['href']); - if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page') - $profile = unamp($link['@attributes']['href']); - if($link['@attributes']['rel'] === 'http://portablecontacts.net/spec/1.0') - $poco = unamp($link['@attributes']['href']); - if($link['@attributes']['rel'] === 'http://joindiaspora.com/seed_location') { - $diaspora_base = unamp($link['@attributes']['href']); - $diaspora = true; - } - if($link['@attributes']['rel'] === 'http://joindiaspora.com/guid') { - $diaspora_guid = unamp($link['@attributes']['href']); - $diaspora = true; - } - if($link['@attributes']['rel'] === 'diaspora-public-key') { - $diaspora_key = base64_decode(unamp($link['@attributes']['href'])); - if(strstr($diaspora_key,'RSA ')) - $pubkey = rsatopem($diaspora_key); - else - $pubkey = $diaspora_key; - $diaspora = true; - } - if($link['@attributes']['rel'] == 'magic-public-key') { - if(substr($link['@attributes']['href'],0,5) === 'data:') { - $salmon_key = convert_salmon_key($link['@attributes']['href']); - } - } - if($link['@attributes']['rel'] == 'salmon') { - $has_salmon = true; - $salmon = $link['@attributes']['href']; - } - - if($link['@attributes']['rel'] == 'http://schemas.google.com/g/2010#updates-from') { - $atom_feed = $link['@attributes']['href']; - } - if($link['@attributes']['rel'] === 'alias') { - $aliases[] = $link['@attributes']['href']; - } - if($link['@attributes']['rel'] === 'subject') { - $subject = $link['@attributes']['href']; - } - } - } - } - - if($subject || $aliases) { - if(strpos($webbie,'@')) { - $rhs = substr($webbie,strpos($webbie,'@')+1); - } - else { - $m = parse_url($webbie); - if($m) { - $rhs = $m['host'] . (($m['port']) ? ':' . $m['port'] : ''); - } - } - - $v = array('subject' => $subject,'aliases' => $aliases); - $address = find_webfinger_address($v,$rhs); - $location = find_webfinger_location($v,$rhs); - if($address) - $nickname = substr($address,0,strpos($address,'@')); - } - - if($salmon_key && $has_salmon && $atom_feed && (! $dfrn) && (! $diaspora)) { - $gnusoc = true; - $probe_atom = true; - } - - if(! $pubkey) - $pubkey = $salmon_key; - - if(($dfrn || $diaspora) && $hcard) - $probe_hcard = true; - - if(! $fullname) - $fullname = $nickname; - - if($probe_atom) { - $k = z_fetch_url($atom_feed); - if($k['success']) - $feed_meta = feed_meta($k['body']); - if($feed_meta) { - - // stash any discovered pubsubhubbub hubs in case we need to follow them - // this will save an expensive lookup later - - if($feed_meta['hubs'] && $address) { - set_xconfig($address,'system','push_hubs',$feed_meta['hubs']); - set_xconfig($address,'system','feed_url',$atom_feed); - } - if($feed_meta['author']['author_name']) { - $fullname = $feed_meta['author']['author_name']; - } - if(! $avatar) { - if($feed_meta['author']['author_photo']) - $avatar = $feed_meta['author']['author_photo']; - } - - // for GNU-social over-ride any url aliases we may have picked up in webfinger - // The author.uri element in the feed is likely to be more accurate - - if($gnusoc && $feed_meta['author']['author_uri']) - $location = $feed_meta['author']['author_uri']; - } - } - else { - if($probe_hcard) { - $vcard = scrape_vcard($hcard); - if($vcard) { - logger('vcard: ' . print_r($vcard,true), LOGGER_DATA); - if($vcard['fn']) - $fullname = $vcard['fn']; - if($vcard['photo'] && (strpos($vcard['photo'],'http') !== 0)) - $vcard['photo'] = $diaspora_base . '/' . $vcard['photo']; - if(($vcard['public_key']) && (! $pubkey)) { - $diaspora_key = $vcard['public_key']; - if(strstr($diaspora_key,'RSA ')) - $pubkey = rsatopem($diaspora_key); - else - $pubkey = $diaspora_key; - } - if(! $avatar) - $avatar = $vcard['photo']; - if($diaspora) { - if(($vcard['uid']) && (! $diaspora_guid)) - $diaspora_guid = $vcard['uid']; - if(($vcard['url']) && (! $diaspora_base)) - $diaspora_base = $vcard['url']; - } - } - } - } - - if(($profile) && (! $location)) - $location = $profile; - - if($location) { - $m = parse_url($location); - $base = $m['scheme'] . '://' . $m['host']; - $host = $m['host']; - } - - if($diaspora && $diaspora_base && $diaspora_guid) { - if($dfrn) - $network = 'friendica-over-diaspora'; - else - $network = 'diaspora'; - - $base = trim($diaspora_base, '/'); - $notify = $base . '/receive'; - } - else { - if($gnusoc) { - $network = 'gnusoc'; - $notify = $salmon; - } - } - - logger('network: ' . $network); - logger('address: ' . $address); - logger('fullname: ' . $fullname); - logger('pubkey: ' . $pubkey); - logger('location: ' . $location); - - // if we have everything we need, let's create the records - - if($network && $address && $fullname && $pubkey && $location) { - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($address) - ); - if($r) { - $r = q("update xchan set xchan_name = '%s', xchan_network = '%s', xchan_name_date = '%s' where xchan_hash = '%s'", - dbesc($fullname), - dbesc($network), - dbesc(datetime_convert()), - dbesc($address) - ); - } - else { - $r = xchan_store_lowlevel( - [ - 'xchan_hash' => $address, - 'xchan_guid' => (($diaspora_guid) ? $diaspora_guid : $location), - 'xchan_pubkey' => $pubkey, - 'xchan_addr' => $address, - 'xchan_url' => $location, - 'xchan_name' => $fullname, - 'xchan_name_date' => datetime_convert(), - 'xchan_network' => $network - ] - ); - } - - $r = q("select * from hubloc where hubloc_hash = '%s' limit 1", - dbesc($address) - ); - - if(! $r) { - $r = hubloc_store_lowlevel( - [ - 'hubloc_guid' => (($diaspora_guid) ? $diaspora_guid : $location), - 'hubloc_hash' => $address, - 'hubloc_addr' => $address, - 'hubloc_network' => $network, - 'hubloc_url' => $base, - 'hubloc_host' => $host, - 'hubloc_callback' => $notify, - 'hubloc_updated' => datetime_convert(), - 'hubloc_primary' => 1 - ] - ); - } - $photos = import_xchan_photo($avatar,$address); - $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", - dbescdate(datetime_convert()), - dbesc($photos[0]), - dbesc($photos[1]), - dbesc($photos[2]), - dbesc($photos[3]), - dbesc($address) - ); - return true; - } return false; -} - +} function webfinger_rfc7033($webbie,$zot = false) { @@ -1557,105 +1206,22 @@ function webfinger_rfc7033($webbie,$zot = false) { // and results in a 406 (Not Acceptable) response, and will also incorrectly produce an XML // document if you use 'application/jrd+json, */*'. We could set this to application/jrd+json, // but some test webfinger servers may not explicitly set the content type and they would be - // blocked. The best compromise until Mastodon is fixed is to remove the Accept header which is - // accomplished by setting it to nothing. + // blocked. The best compromise until Mastodon is fixed is to remove the Accept header which is + // accomplished by setting it to nothing. $counter = 0; - $s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?f=&resource=' . $resource . (($zot) ? '&zot=1' : ''), + $s = z_fetch_url('https://' . $rhs . '/.well-known/webfinger?f=&resource=' . $resource . (($zot) ? '&zot=1' : ''), false, $counter, [ 'headers' => [ 'Accept:' ] ]); if($s['success']) { $j = json_decode($s['body'],true); - - // We could have a number of URL aliases and webbies - // make an executive decision about the most likely "best" of each - // by comparing against some examples from known networks we're likely to encounter. - // Otherwise we have to store every alias that we may ever encounter and - // validate every URL we ever find against every possible alias - - /** - * @FIXME pump.io is going to be a real bugger since it doesn't return - * subject or aliases or provide lookup by url - */ - - $j['address'] = find_webfinger_address($j,$rhs); - $j['location'] = find_webfinger_location($j,$rhs); - if($j['address']) - $j['nickname'] = substr($j['address'],0,strpos($j['address'],'@')); + return($j); } - else - return false; - - return($j); -} -function find_webfinger_address($j,$rhs) { - if(is_array($j) && ($j)) { - if(strpos($j['subject'],'acct:') !== false && strpos($j['subject'],'@' . $rhs)) - return str_replace('acct:','',$j['subject']); - if($j['aliases']) { - foreach($j['aliases'] as $alias) { - if(strpos($alias,'acct:') !== false && strpos($alias,'@' . $rhs)) { - return str_replace('acct:','',$alias); - } - } - } - } - return ''; -} - - -function find_webfinger_location($j,$rhs) { - if(is_array($j) && ($j)) { - if(strpos($j['subject'],'http') === 0) { - $x = match_webfinger_location($j['subject'],$rhs); - if($x) - return $x; - } - if($j['aliases']) { - foreach($j['aliases'] as $alias) { - if(strpos($alias,'http') === 0) { - $x = match_webfinger_location($alias,$rhs); - if($x) - return($x); - } - } - } - } - return ''; -} - -/** - * @brief Match the webfinger location for the different networks. - * - * @param string $s The string to search in - * @param string $h The host - * @return string - */ -function match_webfinger_location($s, $h) { - - // GNU-social and the older StatusNet - the $host/user/123 form doesn't work - if(preg_match('|' . $h . '/index.php/user/([0-9]*?)$|', $s)) - return $s; - // Redmatrix / hubzilla - if(preg_match('|' . $h . '/channel/|', $s)) - return $s; - // Friendica - if(preg_match('|' . $h . '/profile/|', $s)) - return $s; - - $arr = array('test' => $s, 'host' => $h, 'success' => false); - call_hooks('match_webfinger_location', $arr); - if($arr['success']) - return $s; + return false; - return ''; } - - - - function old_webfinger($webbie) { $host = ''; @@ -1723,9 +1289,6 @@ function fetch_xrd_links($url) { if ((! $xml) || (! stristr($xml,'<xrd'))) return array(); - // fix diaspora's bad xml - $xml = str_replace(array('href="','"/>'),array('href="','"/>'),$xml); - $h = parse_xml_string($xml); if(! $h) return array(); @@ -1765,89 +1328,13 @@ function fetch_xrd_links($url) { } -function scrape_vcard($url) { - - $ret = array(); - - logger('url=' . $url); - - $x = z_fetch_url($url); - if(! $x['success']) - return $ret; - - $s = $x['body']; - - if(! $s) - return $ret; - - $headers = $x['header']; - $lines = explode("\n",$headers); - if(count($lines)) { - foreach($lines as $line) { - // don't try and run feeds through the html5 parser - if(stristr($line,'content-type:') && ((stristr($line,'application/atom+xml')) || (stristr($line,'application/rss+xml')))) - return ret; - } - } - - try { - $dom = HTML5_Parser::parse($s); - } catch (DOMException $e) { - logger('Parse error: ' . $e); - } - - if(! $dom) - return $ret; - - // Pull out hCard profile elements - - $largest_photo = 0; - - $items = $dom->getElementsByTagName('*'); - foreach($items as $item) { - if(attribute_contains($item->getAttribute('class'), 'vcard')) { - $level2 = $item->getElementsByTagName('*'); - foreach($level2 as $x) { - if(attribute_contains($x->getAttribute('id'),'pod_location')) - $ret['pod_location'] = $x->textContent; - if(attribute_contains($x->getAttribute('class'),'fn')) - $ret['fn'] = $x->textContent; - if(attribute_contains($x->getAttribute('class'),'uid')) - $ret['uid'] = $x->textContent; - if(attribute_contains($x->getAttribute('class'),'nickname')) - $ret['nick'] = $x->textContent; - if(attribute_contains($x->getAttribute('class'),'searchable')) - $ret['searchable'] = $x->textContent; - if(attribute_contains($x->getAttribute('class'),'key')) - $ret['public_key'] = $x->textContent; - if(attribute_contains($x->getAttribute('class'),'given_name')) - $ret['given_name'] = $x->textContent; - if(attribute_contains($x->getAttribute('class'),'family_name')) - $ret['family_name'] = $x->textContent; - if(attribute_contains($x->getAttribute('class'),'url')) - $ret['url'] = $x->textContent; - - if((attribute_contains($x->getAttribute('class'),'photo')) - || (attribute_contains($x->getAttribute('class'),'avatar'))) { - $size = intval($x->getAttribute('width')); - if(($size > $largest_photo) || (! $largest_photo)) { - $ret['photo'] = $x->getAttribute('src'); - $largest_photo = $size; - } - } - } - } - } - - return $ret; -} - /** * @brief * * @param string $url The URL to scrape * @return array */ + function scrape_feed($url) { require_once('library/HTML5/Parser.php'); @@ -1941,112 +1428,6 @@ function scrape_feed($url) { -function service_plink($contact, $guid) { - - $plink = ''; - - $m = parse_url($contact['xchan_url']); - if($m) { - $url = $m['scheme'] . '://' . $m['host'] . (($m['port']) ? ':' . $m['port'] : ''); - } - else - $url = 'https://' . substr($contact['xchan_addr'],strpos($contact['xchan_addr'],'@')+1); - - $handle = substr($contact['xchan_addr'], 0, strpos($contact['xchan_addr'],'@')); - - if($contact['xchan_network'] === 'diaspora') - $plink = $url . '/posts/' . $guid; - if($contact['xchan_network'] === 'friendica-over-diaspora') - $plink = $url . '/display/' . $handle . '/' . $guid; - if($contact['xchan_network'] === 'zot') - $plink = $url . '/channel/' . $handle . '?f=&mid=' . $guid; - - return $plink; -} - - -function format_and_send_email($sender,$xchan,$item) { - - $title = $item['title']; - $body = $item['body']; - - $textversion = strip_tags(html_entity_decode(bbcode(str_replace(array("\\r", "\\n"), array( "", "\n"), $body)),ENT_QUOTES,'UTF-8')); - - $htmlversion = bbcode(str_replace(array("\\r","\\n"), array("","<br />\n"),$body)); - - $banner = t('$Projectname Notification'); - $product = t('$projectname'); // PLATFORM_NAME; - $siteurl = z_root(); - $thanks = t('Thank You,'); - $sitename = get_config('system', 'sitename'); - $site_admin = sprintf( t('%s Administrator'), $sitename); - - // load the template for private message notifications - $tpl = get_markup_template('email_notify_html.tpl'); - $email_html_body = replace_macros($tpl, array( - '$banner' => $banner, - '$notify_icon' => Zotlabs\Lib\System::get_notify_icon(), - '$product' => $product, - '$preamble' => '', - '$sitename' => $sitename, - '$siteurl' => $siteurl, - '$source_name' => $sender['xchan_name'], - '$source_link' => $sender['xchan_url'], - '$source_photo' => $sender['xchan_photo_m'], - '$username' => $xchan['xchan_name'], - '$hsitelink' => $datarray['hsitelink'], /// @FIXME $datarray is undefined - '$hitemlink' => $datarray['hitemlink'], /// @FIXME $datarray is undefined - '$thanks' => $thanks, - '$site_admin' => $site_admin, - '$title' => $title, - '$htmlversion' => $htmlversion, - )); - - // load the template for private message notifications - $tpl = get_markup_template('email_notify_text.tpl'); - $email_text_body = replace_macros($tpl, array( - '$banner' => $banner, - '$product' => $product, - '$preamble' => '', - '$sitename' => $sitename, - '$siteurl' => $siteurl, - '$source_name' => $sender['xchan_name'], - '$source_link' => $sender['xchan_url'], - '$source_photo' => $sender['xchan_photo_m'], - '$username' => $xchan['xchan_name'], - '$hsitelink' => $datarray['hsitelink'], - '$hitemlink' => $datarray['hitemlink'], - '$thanks' => $thanks, - '$site_admin' => $site_admin, - '$title' => $title, - '$textversion' => $textversion - )); - - $sender_name = t('Administrator'); - - $hostname = App::get_hostname(); - if(strpos($hostname, ':')) - $hostname = substr($hostname,0,strpos($hostname,':')); - - $sender_email = get_config('system', 'reply_address'); - if(! $sender_email) - $sender_email = 'noreply' . '@' . $hostname; - - // use the EmailNotification library to send the message - - Zotlabs\Lib\Enotify::send(array( - 'fromName' => $product, - 'fromEmail' => $sender_email, - 'replyTo' => $sender_email, - 'toEmail' => str_replace('mailto:','',$xchan['xchan_addr']), - 'messageSubject' => (($title) ? $title : t('No Subject')), - 'htmlVersion' => $email_html_body, - 'textVersion' => $email_text_body, - 'additionalMailHeader' => '', - )); -} - - function do_delivery($deliveries) { if(! (is_array($deliveries) && count($deliveries))) @@ -2160,33 +1541,33 @@ function get_site_info() { } - $data = Array( - 'version' => $version, - 'version_tag' => $tag, - 'server_role' => Zotlabs\Lib\System::get_server_role(), - 'commit' => $commit, - 'url' => z_root(), - 'plugins' => $visible_plugins, - 'register_policy' => $register_policy[get_config('system','register_policy')], - 'invitation_only' => intval(get_config('system','invitation_only')), - 'directory_mode' => $directory_mode[get_config('system','directory_mode')], - 'language' => get_config('system','language'), - 'rss_connections' => intval(get_config('system','feed_contacts')), - 'expiration' => $site_expire, + $data = [ + 'url' => z_root(), + 'platform' => Zotlabs\Lib\System::get_platform_name(), + 'site_name' => (($site_name) ? $site_name : ''), + 'version' => $version, + 'version_tag' => $tag, + 'server_role' => Zotlabs\Lib\System::get_server_role(), + 'commit' => $commit, + 'plugins' => $visible_plugins, + 'register_policy' => $register_policy[get_config('system','register_policy')], + 'invitation_only' => intval(get_config('system','invitation_only')), + 'directory_mode' => $directory_mode[get_config('system','directory_mode')], + 'language' => get_config('system','language'), + 'rss_connections' => intval(get_config('system','feed_contacts')), + 'expiration' => $site_expire, 'default_service_restrictions' => $service_class, - 'locked_features' => $locked_features, - 'admin' => $admin, - 'site_name' => (($site_name) ? $site_name : ''), - 'platform' => Zotlabs\Lib\System::get_platform_name(), - 'dbdriver' => DBA::$dba->getdriver(), - 'lastpoll' => get_config('system','lastpoll'), - 'info' => (($site_info) ? $site_info : ''), - 'channels_total' => $channels_total_stat, - 'channels_active_halfyear' => $channels_active_halfyear_stat, - 'channels_active_monthly' => $channels_active_monthly_stat, - 'local_posts' => $local_posts_stat, - 'hide_in_statistics' => $hide_in_statistics - ); + 'locked_features' => $locked_features, + 'admin' => $admin, + 'dbdriver' => DBA::$dba->getdriver(), + 'lastpoll' => get_config('system','lastpoll'), + 'info' => (($site_info) ? $site_info : ''), + 'channels_total' => $channels_total_stat, + 'channels_active_halfyear' => $channels_active_halfyear_stat, + 'channels_active_monthly' => $channels_active_monthly_stat, + 'local_posts' => $local_posts_stat, + 'hide_in_statistics' => $hide_in_statistics + ]; return $data; } @@ -2412,3 +1793,106 @@ function probe_api_path($host) { return ''; } + + +function scrape_vcard($url) { + + require_once('library/HTML5/Parser.php'); + + $ret = array(); + + logger('url=' . $url); + + $x = z_fetch_url($url); + if(! $x['success']) + return $ret; + + $s = $x['body']; + + if(! $s) + return $ret; + + $headers = $x['header']; + $lines = explode("\n",$headers); + if(count($lines)) { + foreach($lines as $line) { + // don't try and run feeds through the html5 parser + if(stristr($line,'content-type:') && ((stristr($line,'application/atom+xml')) || (stristr($line,'application/rss+xml')))) + return ret; + } + } + + try { + $dom = HTML5_Parser::parse($s); + } catch (DOMException $e) { + logger('Parse error: ' . $e); + } + + if(! $dom) + return $ret; + + // Pull out hCard profile elements + + $largest_photo = 0; + + $items = $dom->getElementsByTagName('*'); + foreach($items as $item) { + if(attribute_contains($item->getAttribute('class'), 'vcard')) { + $level2 = $item->getElementsByTagName('*'); + foreach($level2 as $x) { + if(attribute_contains($x->getAttribute('id'),'pod_location')) + $ret['pod_location'] = $x->textContent; + if(attribute_contains($x->getAttribute('class'),'fn')) + $ret['fn'] = $x->textContent; + if(attribute_contains($x->getAttribute('class'),'uid')) + $ret['uid'] = $x->textContent; + if(attribute_contains($x->getAttribute('class'),'nickname')) + $ret['nick'] = $x->textContent; + if(attribute_contains($x->getAttribute('class'),'searchable')) + $ret['searchable'] = $x->textContent; + if(attribute_contains($x->getAttribute('class'),'key')) + $ret['public_key'] = $x->textContent; + if(attribute_contains($x->getAttribute('class'),'given_name')) + $ret['given_name'] = $x->textContent; + if(attribute_contains($x->getAttribute('class'),'family_name')) + $ret['family_name'] = $x->textContent; + if(attribute_contains($x->getAttribute('class'),'url')) + $ret['url'] = $x->textContent; + + if((attribute_contains($x->getAttribute('class'),'photo')) + || (attribute_contains($x->getAttribute('class'),'avatar'))) { + $size = intval($x->getAttribute('width')); + if(($size > $largest_photo) || (! $largest_photo)) { + $ret['photo'] = $x->getAttribute('src'); + $largest_photo = $size; + } + } + } + } + } + + return $ret; +} + +function service_plink($contact, $guid) { + + $plink = ''; + + $m = parse_url($contact['xchan_url']); + if($m) { + $url = $m['scheme'] . '://' . $m['host'] . (($m['port']) ? ':' . $m['port'] : ''); + } + else { + $url = 'https://' . substr($contact['xchan_addr'],strpos($contact['xchan_addr'],'@')+1); + } + + $handle = substr($contact['xchan_addr'], 0, strpos($contact['xchan_addr'],'@')); + + $plink = $url . '/channel/' . $handle . '?f=&mid=' . $guid; + + $x = [ 'xchan' => $contact, 'guid' => $guid, '$url' => $url, 'plink' => $plink ]; + call_hooks('service_plink', $x); + + return $x['plink']; +} + diff --git a/include/oauth2.php b/include/oauth2.php new file mode 100644 index 000000000..3a71a651d --- /dev/null +++ b/include/oauth2.php @@ -0,0 +1,23 @@ +<?php + +/* + $storage = new OAuth2\Storage\Pdo(\DBA::$dba->db); + $config = [ + 'use_openid_connect' => true, + 'issuer' => \Zotlabs\Lib\System::get_site_name() + ]; + + $oauth2_server = new OAuth2\Server($storage,$config); + + $oauth2_server->addGrantType(new OAuth2\GrantType\ClientCredentials($storage)); + $oauth2_server->addGrantType(new OAuth2\GrantType\AuthorizationCode($storage)); + + $keyStorage = new OAuth2\Storage\Memory( [ + 'keys' => [ + 'public_key' => get_config('system','pubkey'), + 'private_key' => get_config('system','prvkey') + ] + ]); + + $oauth2_server->addStorage($keyStorage,'public_key'); +*/
\ No newline at end of file diff --git a/include/page_widgets.php b/include/page_widgets.php deleted file mode 100644 index 3270de4a3..000000000 --- a/include/page_widgets.php +++ /dev/null @@ -1,52 +0,0 @@ -<?php - -// A basic toolbar for observers with write_pages permissions - -function writepages_widget ($who,$which) { - return replace_macros(get_markup_template('write_pages.tpl'), array( - '$new' => t('New Page'), - '$newurl' => "webpages/$who", - '$edit' => t('Edit'), - '$editurl' => "editwebpage/$who/$which" - )); -} - - - -// Chan is channel_id, $which is channel_address - we'll need to pass observer later too. - -function pagelist_widget ($owner,$which) { - - $r = q("select * from iconfig left join item on iconfig.iid = item.id where item_id.uid = %d - and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' order by item.created desc", - intval($owner) - ); - - $pages = null; - - if($r) { - $pages = array(); - foreach($r as $rr) { - $pages[$rr['iid']][] = array('url' => $rr['iid'],'pagetitle' => $rr['v'],'title' => $rr['title'],'created' => datetime_convert('UTC',date_default_timezone_get(),$rr['created']),'edited' => datetime_convert('UTC',date_default_timezone_get(),$rr['edited'])); - } - } - - //Build the base URL for edit links - $url = z_root() . "/editwebpage/" . $which; - // This isn't pretty, but it works. Until I figure out what to do with the UI, it's Good Enough(TM). - return $o . replace_macros(get_markup_template("webpagelist.tpl"), array( - '$baseurl' => $url, - '$edit' => t('Edit'), - '$pages' => $pages, - '$channel' => $which, - '$view' => t('View'), - '$preview' => t('Preview'), - '$actions_txt' => t('Actions'), - '$pagelink_txt' => t('Page Link'), - '$title_txt' => t('Title'), - '$created_txt' => t('Created'), - '$edited_txt' => t('Edited') - - )); - -} diff --git a/include/permissions.php b/include/permissions.php index f719394c5..f97142fab 100644 --- a/include/permissions.php +++ b/include/permissions.php @@ -7,61 +7,11 @@ require_once('include/security.php'); * * This file conntains functions to check and work with permissions. * - * Most of this file is obsolete and has been superceded by extensible permissions in v1.12; it is left here - * for reference and because we haven't yet checked that all functions have been replaced and are available - * elsewhere (typically Zotlabs/Access/*). */ /** - * @brief Return an array with all available permissions. - * - * These are channel specific permissions. - * The list of available permissions can get manipulated by the <i>hook</i> - * <b>global_permissions</b>. - * - * @return array associative array containing all permissions - */ -function get_perms() { - -// thinking about making element[2] a bitmask instead of boolean so that we can provide a list of applicable selections -// for any given permission. Currently we use the boolean to disallow write access to "everybody", but we also want to be -// able to handle troublesome settings such as allowing channel_w_stream to anybody in the network. You can allow it, but -// there's no way to implement sending it. - - $global_perms = array( - // Read only permissions - 'view_stream' => array('channel_r_stream', intval(PERMS_R_STREAM), true, t('Can view my normal stream and posts'), ''), - 'view_profile' => array('channel_r_profile', intval(PERMS_R_PROFILE), true, t('Can view my default channel profile'), ''), - 'view_contacts' => array('channel_r_abook', intval(PERMS_R_ABOOK), true, t('Can view my connections'), ''), - 'view_storage' => array('channel_r_storage', intval(PERMS_R_STORAGE), true, t('Can view my file storage and photos'), ''), - 'view_pages' => array('channel_r_pages', intval(PERMS_R_PAGES), true, t('Can view my webpages'), ''), - - // Write permissions - 'send_stream' => array('channel_w_stream', intval(PERMS_W_STREAM), false, t('Can send me their channel stream and posts'), ''), - 'post_wall' => array('channel_w_wall', intval(PERMS_W_WALL), false, t('Can post on my channel page ("wall")'), ''), - 'post_comments' => array('channel_w_comment', intval(PERMS_W_COMMENT), false, t('Can comment on or like my posts'), ''), - 'post_mail' => array('channel_w_mail', intval(PERMS_W_MAIL), false, t('Can send me private mail messages'), ''), - 'post_like' => array('channel_w_like', intval(PERMS_W_LIKE), false, t('Can like/dislike stuff'), t('Profiles and things other than posts/comments')), - - 'tag_deliver' => array('channel_w_tagwall', intval(PERMS_W_TAGWALL), false, t('Can forward to all my channel contacts via post @mentions'), t('Advanced - useful for creating group forum channels')), - 'chat' => array('channel_w_chat', intval(PERMS_W_CHAT), false, t('Can chat with me (when available)'), t('')), - 'write_storage' => array('channel_w_storage', intval(PERMS_W_STORAGE), false, t('Can write to my file storage and photos'), ''), - 'write_pages' => array('channel_w_pages', intval(PERMS_W_PAGES), false, t('Can edit my webpages'), ''), - - 'republish' => array('channel_a_republish', intval(PERMS_A_REPUBLISH), false, t('Can source my public posts in derived channels'), t('Somewhat advanced - very useful in open communities')), - - 'delegate' => array('channel_a_delegate', intval(PERMS_A_DELEGATE), false, t('Can administer my channel resources'), t('Extremely advanced. Leave this alone unless you know what you are doing')), - ); - $ret = array('global_permissions' => $global_perms); - call_hooks('global_permissions', $ret); - - return $ret['global_permissions']; -} - - -/** * get_all_perms($uid,$observer_xchan) * * @param int $uid The channel_id associated with the resource owner @@ -297,7 +247,6 @@ function get_all_perms($uid, $observer_xchan, $internal_use = true) { * * Checks if the given observer with the hash $observer_xchan has permission * $permission on channel_id $uid. - * $permission is one defined in get_perms(); * * @param int $uid The channel_id associated with the resource owner * @param string $observer_xchan The xchan_hash representing the observer @@ -465,7 +414,7 @@ function perm_is_allowed($uid, $observer_xchan, $permission) { function get_all_api_perms($uid,$api) { - $global_perms = get_perms(); + $global_perms = \Zotlabs\Access\Permissions::Perms(); $ret = array(); @@ -568,6 +517,7 @@ function site_default_perms() { 'view_contacts' => PERMS_PUBLIC, 'view_storage' => PERMS_PUBLIC, 'view_pages' => PERMS_PUBLIC, + 'view_wiki' => PERMS_PUBLIC, 'send_stream' => PERMS_SPECIFIC, 'post_wall' => PERMS_SPECIFIC, 'post_comments' => PERMS_SPECIFIC, @@ -576,16 +526,15 @@ function site_default_perms() { 'chat' => PERMS_SPECIFIC, 'write_storage' => PERMS_SPECIFIC, 'write_pages' => PERMS_SPECIFIC, + 'write_wiki' => PERMS_SPECIFIC, 'delegate' => PERMS_SPECIFIC, 'post_like' => PERMS_NETWORK ); - $global_perms = get_perms(); + $global_perms = \Zotlabs\Access\Permissions::Perms(); foreach($global_perms as $perm => $v) { - $x = get_config('default_perms', $perm); - if($x === false) - $x = $typical[$perm]; + $x = get_config('default_perms', $perm, $typical[$perm]); $ret[$perm] = $x; } @@ -593,362 +542,3 @@ function site_default_perms() { } -/** - * @brief Return an array of all permissions for this role. - * - * Given a string for the channel role ('social','forum', etc) - * return an array of all permission fields pre-filled for this role. - * This includes the channel permission scope indicators (anything beginning with 'channel_') as well as - * * perms_auto: true or false to create auto-permissions for this channel - * * perms_follow: The permissions to apply when initiating a connection request to another channel - * * perms_accept: The permissions to apply when accepting a connection request from another channel (not automatic) - * * default_collection: true or false to make the default ACL include the channel's default collection - * * directory_publish: true or false to publish this channel in the directory - * Any attributes may be extended (new roles defined) and modified (specific permissions altered) by plugins - * - * @param string $role - * @return array - */ -function get_role_perms($role) { - - $ret = array(); - - $ret['role'] = $role; - - switch($role) { - case 'social': - $ret['perms_auto'] = false; - $ret['default_collection'] = false; - $ret['directory_publish'] = true; - $ret['online'] = true; - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_contacts', 'view_storage', - 'view_pages', 'send_stream', 'post_wall', 'post_comments', - 'post_mail', 'chat', 'post_like', 'republish' ]; - $ret['limits'] = [ - 'view_stream' => PERMS_PUBLIC, - 'view_profile' => PERMS_PUBLIC, - 'view_contacts' => PERMS_PUBLIC, - 'view_storage' => PERMS_PUBLIC, - 'view_pages' => PERMS_PUBLIC, - 'send_stream' => PERMS_SPECIFIC, - 'post_wall' => PERMS_SPECIFIC, - 'post_comments' => PERMS_SPECIFIC, - 'post_mail' => PERMS_SPECIFIC, - 'post_like' => PERMS_SPECIFIC, - 'tag_deliver' => PERMS_SPECIFIC, - 'chat' => PERMS_SPECIFIC, - 'write_storage' => PERMS_SPECIFIC, - 'write_pages' => PERMS_SPECIFIC, - 'republish' => PERMS_SPECIFIC, - 'delegate' => PERMS_SPECIFIC - ]; - - break; - - case 'social_restricted': - $ret['perms_auto'] = false; - $ret['default_collection'] = true; - $ret['directory_publish'] = true; - $ret['online'] = true; - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_contacts', 'view_storage', - 'view_pages', 'send_stream', 'post_wall', 'post_comments', - 'post_mail', 'chat', 'post_like' ]; - $ret['limits'] = [ - 'view_stream' => PERMS_PUBLIC, - 'view_profile' => PERMS_PUBLIC, - 'view_contacts' => PERMS_PUBLIC, - 'view_storage' => PERMS_PUBLIC, - 'view_pages' => PERMS_PUBLIC, - 'send_stream' => PERMS_SPECIFIC, - 'post_wall' => PERMS_SPECIFIC, - 'post_comments' => PERMS_SPECIFIC, - 'post_mail' => PERMS_SPECIFIC, - 'post_like' => PERMS_SPECIFIC, - 'tag_deliver' => PERMS_SPECIFIC, - 'chat' => PERMS_SPECIFIC, - 'write_storage' => PERMS_SPECIFIC, - 'write_pages' => PERMS_SPECIFIC, - 'republish' => PERMS_SPECIFIC, - 'delegate' => PERMS_SPECIFIC - ]; - - - break; - - case 'social_private': - $ret['perms_auto'] = false; - $ret['default_collection'] = true; - $ret['directory_publish'] = false; - $ret['online'] = false; - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_contacts', 'view_storage', - 'view_pages', 'send_stream', 'post_wall', 'post_comments', - 'post_mail', 'post_like' ]; - $ret['limits'] = [ - 'view_stream' => PERMS_PUBLIC, - 'view_profile' => PERMS_PUBLIC, - 'view_contacts' => PERMS_SPECIFIC, - 'view_storage' => PERMS_SPECIFIC, - 'view_pages' => PERMS_PUBLIC, - 'send_stream' => PERMS_SPECIFIC, - 'post_wall' => PERMS_SPECIFIC, - 'post_comments' => PERMS_SPECIFIC, - 'post_mail' => PERMS_SPECIFIC, - 'post_like' => PERMS_SPECIFIC, - 'tag_deliver' => PERMS_SPECIFIC, - 'chat' => PERMS_SPECIFIC, - 'write_storage' => PERMS_SPECIFIC, - 'write_pages' => PERMS_SPECIFIC, - 'republish' => PERMS_SPECIFIC, - 'delegate' => PERMS_SPECIFIC - ]; - - break; - - case 'forum': - $ret['perms_auto'] = true; - $ret['default_collection'] = false; - $ret['directory_publish'] = true; - $ret['online'] = false; - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_contacts', 'view_storage', - 'view_pages', 'post_wall', 'post_comments', 'tag_deliver', - 'post_mail', 'post_like' , 'republish', 'chat' ]; - $ret['limits'] = [ - 'view_stream' => PERMS_PUBLIC, - 'view_profile' => PERMS_PUBLIC, - 'view_contacts' => PERMS_PUBLIC, - 'view_storage' => PERMS_PUBLIC, - 'view_pages' => PERMS_PUBLIC, - 'send_stream' => PERMS_SPECIFIC, - 'post_wall' => PERMS_SPECIFIC, - 'post_comments' => PERMS_SPECIFIC, - 'post_mail' => PERMS_SPECIFIC, - 'post_like' => PERMS_SPECIFIC, - 'tag_deliver' => PERMS_SPECIFIC, - 'chat' => PERMS_SPECIFIC, - 'write_storage' => PERMS_SPECIFIC, - 'write_pages' => PERMS_SPECIFIC, - 'republish' => PERMS_SPECIFIC, - 'delegate' => PERMS_SPECIFIC - ]; - - break; - - case 'forum_restricted': - $ret['perms_auto'] = false; - $ret['default_collection'] = true; - $ret['directory_publish'] = true; - $ret['online'] = false; - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_contacts', 'view_storage', - 'view_pages', 'post_wall', 'post_comments', 'tag_deliver', - 'post_mail', 'post_like' , 'chat' ]; - $ret['limits'] = [ - 'view_stream' => PERMS_PUBLIC, - 'view_profile' => PERMS_PUBLIC, - 'view_contacts' => PERMS_PUBLIC, - 'view_storage' => PERMS_PUBLIC, - 'view_pages' => PERMS_PUBLIC, - 'send_stream' => PERMS_SPECIFIC, - 'post_wall' => PERMS_SPECIFIC, - 'post_comments' => PERMS_SPECIFIC, - 'post_mail' => PERMS_SPECIFIC, - 'post_like' => PERMS_SPECIFIC, - 'tag_deliver' => PERMS_SPECIFIC, - 'chat' => PERMS_SPECIFIC, - 'write_storage' => PERMS_SPECIFIC, - 'write_pages' => PERMS_SPECIFIC, - 'republish' => PERMS_SPECIFIC, - 'delegate' => PERMS_SPECIFIC - ]; - - break; - - case 'forum_private': - $ret['perms_auto'] = false; - $ret['default_collection'] = true; - $ret['directory_publish'] = false; - $ret['online'] = false; - - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_contacts', 'view_storage', - 'view_pages', 'post_wall', 'post_comments', - 'post_mail', 'post_like' , 'chat' ]; - $ret['limits'] = [ - 'view_stream' => PERMS_PUBLIC, - 'view_profile' => PERMS_SPECIFIC, - 'view_contacts' => PERMS_SPECIFIC, - 'view_storage' => PERMS_SPECIFIC, - 'view_pages' => PERMS_SPECIFIC, - 'send_stream' => PERMS_SPECIFIC, - 'post_wall' => PERMS_SPECIFIC, - 'post_comments' => PERMS_SPECIFIC, - 'post_mail' => PERMS_SPECIFIC, - 'post_like' => PERMS_SPECIFIC, - 'tag_deliver' => PERMS_SPECIFIC, - 'chat' => PERMS_SPECIFIC, - 'write_storage' => PERMS_SPECIFIC, - 'write_pages' => PERMS_SPECIFIC, - 'republish' => PERMS_SPECIFIC, - 'delegate' => PERMS_SPECIFIC - ]; - - break; - - case 'feed': - $ret['perms_auto'] = true; - $ret['default_collection'] = false; - $ret['directory_publish'] = true; - $ret['online'] = false; - - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_contacts', 'view_storage', - 'view_pages', 'send_stream', 'post_wall', 'post_comments', - 'post_mail', 'post_like' , 'republish' ]; - $ret['limits'] = [ - 'view_stream' => PERMS_PUBLIC, - 'view_profile' => PERMS_PUBLIC, - 'view_contacts' => PERMS_PUBLIC, - 'view_storage' => PERMS_PUBLIC, - 'view_pages' => PERMS_PUBLIC, - 'send_stream' => PERMS_SPECIFIC, - 'post_wall' => PERMS_SPECIFIC, - 'post_comments' => PERMS_SPECIFIC, - 'post_mail' => PERMS_SPECIFIC, - 'post_like' => PERMS_SPECIFIC, - 'tag_deliver' => PERMS_SPECIFIC, - 'chat' => PERMS_SPECIFIC, - 'write_storage' => PERMS_SPECIFIC, - 'write_pages' => PERMS_SPECIFIC, - 'republish' => PERMS_SPECIFIC, - 'delegate' => PERMS_SPECIFIC - ]; - - break; - - case 'feed_restricted': - $ret['perms_auto'] = false; - $ret['default_collection'] = true; - $ret['directory_publish'] = false; - $ret['online'] = false; - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_contacts', 'view_storage', - 'view_pages', 'send_stream', 'post_wall', 'post_comments', - 'post_mail', 'post_like' , 'republish' ]; - $ret['limits'] = [ - 'view_stream' => PERMS_PUBLIC, - 'view_profile' => PERMS_PUBLIC, - 'view_contacts' => PERMS_PUBLIC, - 'view_storage' => PERMS_PUBLIC, - 'view_pages' => PERMS_PUBLIC, - 'send_stream' => PERMS_SPECIFIC, - 'post_wall' => PERMS_SPECIFIC, - 'post_comments' => PERMS_SPECIFIC, - 'post_mail' => PERMS_SPECIFIC, - 'post_like' => PERMS_SPECIFIC, - 'tag_deliver' => PERMS_SPECIFIC, - 'chat' => PERMS_SPECIFIC, - 'write_storage' => PERMS_SPECIFIC, - 'write_pages' => PERMS_SPECIFIC, - 'republish' => PERMS_SPECIFIC, - 'delegate' => PERMS_SPECIFIC - ]; - - break; - - case 'soapbox': - $ret['perms_auto'] = true; - $ret['default_collection'] = false; - $ret['directory_publish'] = true; - $ret['online'] = false; - - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_contacts', 'view_storage', - 'view_pages', 'post_like' , 'republish' ]; - - $ret['limits'] = [ - 'view_stream' => PERMS_PUBLIC, - 'view_profile' => PERMS_PUBLIC, - 'view_contacts' => PERMS_PUBLIC, - 'view_storage' => PERMS_PUBLIC, - 'view_pages' => PERMS_PUBLIC, - 'send_stream' => PERMS_SPECIFIC, - 'post_wall' => PERMS_SPECIFIC, - 'post_comments' => PERMS_SPECIFIC, - 'post_mail' => PERMS_SPECIFIC, - 'post_like' => PERMS_SPECIFIC, - 'tag_deliver' => PERMS_SPECIFIC, - 'chat' => PERMS_SPECIFIC, - 'write_storage' => PERMS_SPECIFIC, - 'write_pages' => PERMS_SPECIFIC, - 'republish' => PERMS_SPECIFIC, - 'delegate' => PERMS_SPECIFIC - ]; - - break; - - case 'repository': - $ret['perms_auto'] = true; - $ret['default_collection'] = false; - $ret['directory_publish'] = true; - $ret['online'] = false; - - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_contacts', 'view_storage', - 'view_pages', 'write_storage', 'write_pages', 'post_wall', 'post_comments', 'tag_deliver', - 'post_mail', 'post_like' , 'republish', 'chat' ]; - $ret['limits'] = [ - 'view_stream' => PERMS_PUBLIC, - 'view_profile' => PERMS_PUBLIC, - 'view_contacts' => PERMS_PUBLIC, - 'view_storage' => PERMS_PUBLIC, - 'view_pages' => PERMS_PUBLIC, - 'send_stream' => PERMS_SPECIFIC, - 'post_wall' => PERMS_SPECIFIC, - 'post_comments' => PERMS_SPECIFIC, - 'post_mail' => PERMS_SPECIFIC, - 'post_like' => PERMS_SPECIFIC, - 'tag_deliver' => PERMS_SPECIFIC, - 'chat' => PERMS_SPECIFIC, - 'write_storage' => PERMS_SPECIFIC, - 'write_pages' => PERMS_SPECIFIC, - 'republish' => PERMS_SPECIFIC, - 'delegate' => PERMS_SPECIFIC - ]; - - - break; - - default: - break; - } - - $x = get_config('system','role_perms'); - // let system settings over-ride any or all - if($x && is_array($x) && array_key_exists($role,$x)) - $ret = array_merge($ret,$x[$role]); - - call_hooks('get_role_perms',$ret); - - return $ret; -} - -/** - * @brief Returns a list or roles, grouped by type. - * - * @return string Returns an array of roles, grouped by type - */ -function get_roles() { - $roles = array( - t('Social Networking') => array('social' => t('Social - Mostly Public'), 'social_restricted' => t('Social - Restricted'), 'social_private' => t('Social - Private')), - t('Community Forum') => array('forum' => t('Forum - Mostly Public'), 'forum_restricted' => t('Forum - Restricted'), 'forum_private' => t('Forum - Private')), - t('Feed Republish') => array('feed' => t('Feed - Mostly Public'), 'feed_restricted' => t('Feed - Restricted')), - t('Special Purpose') => array('soapbox' => t('Special - Celebrity/Soapbox'), 'repository' => t('Special - Group Repository')), - t('Other') => array('custom' => t('Custom/Expert Mode')) - ); - - return $roles; -} diff --git a/include/photo/photo_driver.php b/include/photo/photo_driver.php index eb61578e1..f47a9c878 100644 --- a/include/photo/photo_driver.php +++ b/include/photo/photo_driver.php @@ -495,12 +495,22 @@ function guess_image_type($filename, $headers = '') { } } - if(is_null($type)) { + if(is_null($type) && (strpos($filename,'http') === false)) { $size = getimagesize($filename); $ph = photo_factory(''); $types = $ph->supportedTypes(); $type = ((array_key_exists($size['mime'], $types)) ? $size['mime'] : 'image/jpeg'); } + if(is_null($type)) { + if(strpos(strtolower($filename),'jpg') !== false) + $type = 'image/jpeg'; + elseif(strpos(strtolower($filename),'jpeg') !== false) + $type = 'image/jpeg'; + elseif(strpos(strtolower($filename),'gif') !== false) + $type = 'image/gif'; + elseif(strpos(strtolower($filename),'png') !== false) + $type = 'image/png'; + } } logger('Photo: guess_image_type: type = ' . $type, LOGGER_DEBUG); diff --git a/include/photos.php b/include/photos.php index de5e08646..c3260d18c 100644 --- a/include/photos.php +++ b/include/photos.php @@ -17,6 +17,7 @@ require_once('include/text.php'); * @param array $args * @return array */ + function photo_upload($channel, $observer, $args) { $ret = array('success' => false); @@ -28,9 +29,6 @@ function photo_upload($channel, $observer, $args) { return $ret; } - -//call_hooks('photo_upload_begin', $args); - /* * Determine the album to use */ @@ -90,8 +88,6 @@ function photo_upload($channel, $observer, $args) { } else { $f = array('src' => '', 'filename' => '', 'filesize' => 0, 'type' => ''); -// call_hooks('photo_upload_file',$f); - if (x($f,'src') && x($f,'filesize')) { $src = $f['src']; $filename = $f['filename']; @@ -369,37 +365,37 @@ function photo_upload($channel, $observer, $args) { else { $mid = item_message_id(); - $arr = array(); + $arr = [ + 'aid' => $account_id, + 'uid' => $channel_id, + 'mid' => $mid, + 'parent_mid' => $mid, + 'item_hidden' => $item_hidden, + 'resource_type' => 'photo', + 'resource_id' => $photo_hash, + 'owner_xchan' => $channel['channel_hash'], + 'author_xchan' => $observer['xchan_hash'], + 'title' => $title, + 'allow_cid' => $ac['allow_cid'], + 'allow_gid' => $ac['allow_gid'], + 'deny_cid' => $ac['deny_cid'], + 'deny_gid' => $ac['deny_gid'], + 'verb' => ACTIVITY_POST, + 'obj_type' => ACTIVITY_OBJ_PHOTO, + 'obj' => json_encode($object), + 'tgt_type' => ACTIVITY_OBJ_ALBUM, + 'target' => json_encode($target), + 'item_wall' => $visible, + 'item_origin' => 1, + 'item_thread_top' => 1, + 'item_private' => intval($acl->is_private()), + 'body' => $summary + ]; - if($lat && $lon) - $arr['coord'] = $lat . ' ' . $lon; - - $arr['aid'] = $account_id; - $arr['uid'] = $channel_id; - $arr['mid'] = $mid; - $arr['parent_mid'] = $mid; - $arr['item_hidden'] = $item_hidden; - $arr['resource_type'] = 'photo'; - $arr['resource_id'] = $photo_hash; - $arr['owner_xchan'] = $channel['channel_hash']; - $arr['author_xchan'] = $observer['xchan_hash']; - $arr['title'] = $title; - $arr['allow_cid'] = $ac['allow_cid']; - $arr['allow_gid'] = $ac['allow_gid']; - $arr['deny_cid'] = $ac['deny_cid']; - $arr['deny_gid'] = $ac['deny_gid']; - $arr['verb'] = ACTIVITY_POST; - $arr['obj_type'] = ACTIVITY_OBJ_PHOTO; - $arr['obj'] = json_encode($object); - $arr['tgt_type'] = ACTIVITY_OBJ_ALBUM; - $arr['target'] = json_encode($target); - $arr['item_wall'] = 1; - $arr['item_origin'] = 1; - $arr['item_thread_top'] = 1; - $arr['item_private'] = intval($acl->is_private()); $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']); - $arr['body'] = $summary; + if($lat && $lon) + $arr['coord'] = $lat . ' ' . $lon; // this one is tricky because the item and the photo have the same permissions, those of the photo. // Use the channel read_stream permissions to get the correct public_policy for the item and recalculate the @@ -446,6 +442,7 @@ function photo_upload($channel, $observer, $args) { * * \e boolean \b success * * \e array \b albums */ + function photos_albums_list($channel, $observer, $sort_key = 'display_path', $direction = 'asc') { $channel_id = $channel['channel_id']; @@ -545,6 +542,7 @@ function photos_album_widget($channelx,$observer,$sortkey = 'display_path',$dire * @param string $album default empty * @return boolean|array */ + function photos_list_photos($channel, $observer, $album = '') { $channel_id = $channel['channel_id']; @@ -584,7 +582,10 @@ function photos_list_photos($channel, $observer, $album = '') { * @param string $album name of the album * @return boolean */ + + function photos_album_exists($channel_id, $observer_hash, $album) { + $sql_extra = permissions_sql($channel_id,$observer_hash); $r = q("SELECT folder, hash, is_dir, filename, os_path, display_path FROM attach WHERE hash = '%s' AND is_dir = 1 AND uid = %d $sql_extra limit 1", @@ -605,6 +606,7 @@ function photos_album_exists($channel_id, $observer_hash, $album) { * @param string $newname The new name of the album * @return bool|array */ + function photos_album_rename($channel_id, $oldname, $newname) { return q("UPDATE photo SET album = '%s' WHERE album = '%s' AND uid = %d", dbesc($newname), @@ -623,6 +625,7 @@ function photos_album_rename($channel_id, $oldname, $newname) { * @param string $remote_xchan * @return string|boolean */ + function photos_album_get_db_idstr($channel_id, $album, $remote_xchan = '') { if($remote_xchan) { @@ -659,6 +662,7 @@ function photos_album_get_db_idstr($channel_id, $album, $remote_xchan = '') { * @param boolean $visible default false * @return int item_id */ + function photos_create_item($channel, $creator_hash, $photo, $visible = false) { // Create item container @@ -714,7 +718,7 @@ function getGps($exifCoord, $hemi) { function getGpstimestamp($exifCoord) { - $hours = count($exifCoord) > 0 ? gps2Num($exifCoord[0]) : 0; + $hours = count($exifCoord) > 0 ? gps2Num($exifCoord[0]) : 0; $minutes = count($exifCoord) > 1 ? gps2Num($exifCoord[1]) : 0; $seconds = count($exifCoord) > 2 ? gps2Num($exifCoord[2]) : 0; diff --git a/include/socgraph.php b/include/socgraph.php index 9a6245d01..a5b5d1378 100644 --- a/include/socgraph.php +++ b/include/socgraph.php @@ -122,7 +122,7 @@ function poco_load($xchan = '', $url = null) { $profile_url = $url['value']; continue; } - if($url['type'] == 'zot' || $url['type'] == 'diaspora' || $url['type'] == 'friendica') { + if($url['type'] == 'zot') { $network = $url['type']; $address = str_replace('acct:' , '', $url['value']); continue; @@ -163,12 +163,6 @@ function poco_load($xchan = '', $url = null) { continue; } } - else { - $x = import_author_diaspora(array('address' => $address)); - if(! $x) { - continue; - } - } } else { continue; @@ -493,8 +487,6 @@ function poco($a,$extended = false) { if($fields_ret['urls']) { $entry['urls'] = array(array('value' => $rr['xchan_url'], 'type' => 'profile')); $network = $rr['xchan_network']; - if(strpos($network,'friendica') !== false) - $network = 'friendica'; if($rr['xchan_addr']) $entry['urls'][] = array('value' => 'acct:' . $rr['xchan_addr'], 'type' => $network); } diff --git a/include/text.php b/include/text.php index c633ba62a..5af4f1b67 100644 --- a/include/text.php +++ b/include/text.php @@ -648,12 +648,8 @@ function logger($msg, $level = LOGGER_NORMAL, $priority = LOG_INFO) { $where = ''; - // We require > 5.4 but leave the version check so that install issues (including version) can be logged - - if(version_compare(PHP_VERSION, '5.4.0') >= 0) { - $stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); - $where = basename($stack[0]['file']) . ':' . $stack[0]['line'] . ':' . $stack[1]['function'] . ': '; - } + $stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + $where = basename($stack[0]['file']) . ':' . $stack[0]['line'] . ':' . $stack[1]['function'] . ': '; $s = datetime_convert() . ':' . log_priority_str($priority) . ':' . session_id() . ':' . $where . $msg . PHP_EOL; $pluginfo = array('filename' => $logfile, 'loglevel' => $level, 'message' => $s,'priority' => $priority, 'logged' => false); @@ -687,16 +683,14 @@ function btlogger($msg, $level = LOGGER_NORMAL, $priority = LOG_INFO) { @file_put_contents(BTLOGGER_DEBUG_FILE, $s, FILE_APPEND); } - if(version_compare(PHP_VERSION, '5.4.0') >= 0) { - $stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); - if($stack) { - for($x = 1; $x < count($stack); $x ++) { - $s = 'stack: ' . basename($stack[$x]['file']) . ':' . $stack[$x]['line'] . ':' . $stack[$x]['function'] . '()'; - logger($s,$level, $priority); + $stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + if($stack) { + for($x = 1; $x < count($stack); $x ++) { + $s = 'stack: ' . basename($stack[$x]['file']) . ':' . $stack[$x]['line'] . ':' . $stack[$x]['function'] . '()'; + logger($s,$level, $priority); - if(file_exists(BTLOGGER_DEBUG_FILE) && is_writable(BTLOGGER_DEBUG_FILE)) { - @file_put_contents(BTLOGGER_DEBUG_FILE, $s . PHP_EOL, FILE_APPEND); - } + if(file_exists(BTLOGGER_DEBUG_FILE) && is_writable(BTLOGGER_DEBUG_FILE)) { + @file_put_contents(BTLOGGER_DEBUG_FILE, $s . PHP_EOL, FILE_APPEND); } } } @@ -751,10 +745,10 @@ function dlogger($msg, $level = 0) { return; $where = ''; - if(version_compare(PHP_VERSION, '5.4.0') >= 0) { - $stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); - $where = basename($stack[0]['file']) . ':' . $stack[0]['line'] . ':' . $stack[1]['function'] . ': '; - } + + $stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + $where = basename($stack[0]['file']) . ':' . $stack[0]['line'] . ':' . $stack[1]['function'] . ': '; + @file_put_contents($logfile, datetime_convert() . ':' . session_id() . ' ' . $where . $msg . PHP_EOL, FILE_APPEND); } @@ -1042,19 +1036,6 @@ function searchbox($s,$id='search-box',$url='/search',$save = false) { )); } -function valid_email_regex($x){ - if(preg_match('/^[_a-zA-Z0-9\-\+]+(\.[_a-zA-Z0-9\-\+]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+$/',$x)) - return true; - return false; -} - -function valid_email($x){ - if(get_config('system','disable_email_validation')) - return true; - - return valid_email_regex($x); -} - /** * @brief Replace naked text hyperlink with HTML formatted hyperlink. * @@ -1199,8 +1180,7 @@ function list_smilies($default_only = false) { ':coffee', ':facepalm', ':like', - ':dislike', - ':hubzilla' + ':dislike' ); $icons = array( @@ -1234,8 +1214,7 @@ function list_smilies($default_only = false) { '<img class="smiley" src="' . z_root() . '/images/emoticons/coffee.gif" alt=":coffee" />', '<img class="smiley" src="' . z_root() . '/images/emoticons/smiley-facepalm.gif" alt=":facepalm" />', '<img class="smiley" src="' . z_root() . '/images/emoticons/like.gif" alt=":like" />', - '<img class="smiley" src="' . z_root() . '/images/emoticons/dislike.gif" alt=":dislike" />', - '<img class="smiley" src="' . z_root() . '/images/hz-16.png" alt=":hubzilla" />', + '<img class="smiley" src="' . z_root() . '/images/emoticons/dislike.gif" alt=":dislike" />' ); @@ -2008,23 +1987,44 @@ function legal_webbie($s) { if(! strlen($s)) return ''; - $x = $s; - do { - $s = $x; - $x = preg_replace('/^([^a-z])(.*?)/',"$2",$s); - } while($x != $s); + // WARNING: This regex will not work in a federated environment. + // You will probably want something like + // preg_replace('/([^a-z0-9\_])/','',strtolower($s)); + + $r = preg_replace('/([^a-z0-9\-\_\.])/','',strtolower($s)); + + $x = [ 'input' => $s, 'output' => $r ]; + call_hooks('legal_webbie',$x); + return $x['output']; + +} + +function legal_webbie_text() { + + // WARNING: This will not work in a federated environment. + + $s = t('a-z, 0-9, -, _, and . only'); + + $x = [ 'text' => $s ]; + call_hooks('legal_webbie_text',$x); + return $x['text']; - return preg_replace('/([^a-z0-9\-\_])/','',$x); } + + + function check_webbie($arr) { + + // These names conflict with the CalDAV server + $taken = [ 'principals', 'addressbooks', 'calendars' ]; + $reservechan = get_config('system','reserved_channels'); - if(strlen($reservechan)) - $taken = explode(',', $reservechan); - else - $taken = array('principals','addressbooks','calendars'); + if(strlen($reservechan)) { + $taken = array_merge($taken,explode(',', $reservechan)); + } $str = ''; if(count($arr)) { @@ -2274,13 +2274,13 @@ function design_tools() { $who = $channel['channel_address']; return replace_macros(get_markup_template('design_tools.tpl'), array( - '$title' => t('Design Tools'), - '$who' => $who, - '$sys' => $sys, + '$title' => t('Design Tools'), + '$who' => $who, + '$sys' => $sys, '$blocks' => t('Blocks'), - '$menus' => t('Menus'), + '$menus' => t('Menus'), '$layout' => t('Layouts'), - '$pages' => t('Pages') + '$pages' => t('Pages') )); } @@ -2301,21 +2301,21 @@ function website_portation_tools() { } return replace_macros(get_markup_template('website_portation_tools.tpl'), array( - '$title' => t('Import'), - '$import_label' => t('Import website...'), - '$import_placeholder' => t('Select folder to import'), - '$file_upload_text' => t('Import from a zipped folder:'), - '$file_import_text' => t('Import from cloud files:'), - '$desc' => t('/cloud/channel/path/to/folder'), - '$hint' => t('Enter path to website files'), - '$select' => t('Select folder'), - '$export_label' => t('Export website...'), - '$file_download_text' => t('Export to a zip file'), - '$filename_desc' => t('website.zip'), - '$filename_hint' => t('Enter a name for the zip file.'), - '$cloud_export_text' => t('Export to cloud files'), - '$cloud_export_desc' => t('/path/to/export/folder'), - '$cloud_export_hint' => t('Enter a path to a cloud files destination.'), + '$title' => t('Import'), + '$import_label' => t('Import website...'), + '$import_placeholder' => t('Select folder to import'), + '$file_upload_text' => t('Import from a zipped folder:'), + '$file_import_text' => t('Import from cloud files:'), + '$desc' => t('/cloud/channel/path/to/folder'), + '$hint' => t('Enter path to website files'), + '$select' => t('Select folder'), + '$export_label' => t('Export website...'), + '$file_download_text' => t('Export to a zip file'), + '$filename_desc' => t('website.zip'), + '$filename_hint' => t('Enter a name for the zip file.'), + '$cloud_export_text' => t('Export to cloud files'), + '$cloud_export_desc' => t('/path/to/export/folder'), + '$cloud_export_hint' => t('Enter a path to a cloud files destination.'), '$cloud_export_select' => t('Specify folder'), )); } @@ -3022,7 +3022,8 @@ function array2XML($obj, $array) { if(is_array($value)) { $node = $obj->addChild($key); array2XML($node, $value); - } else { + } + else { $obj->addChild($key, htmlspecialchars($value)); } } diff --git a/include/zot.php b/include/zot.php index 748fe7b99..a8aecc6fa 100644 --- a/include/zot.php +++ b/include/zot.php @@ -2237,9 +2237,6 @@ function check_location_move($sender_hash,$locations) { if(! $locations) return; - if(get_config('system','server_role') !== 'basic') - return; - if(count($locations) != 1) return; @@ -2935,8 +2932,6 @@ function import_site($arr, $pubkey) { function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { - if(get_config('system','server_role') === 'basic') - return; logger('build_sync_packet'); @@ -3086,8 +3081,6 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { function process_channel_sync_delivery($sender, $arr, $deliveries) { - if(get_config('system','server_role') === 'basic') - return; require_once('include/import.php'); @@ -3289,6 +3282,11 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { if(! array_key_exists('abook_xchan',$clean)) continue; + if(array_key_exists('abook_instance',$clean) && $clean['abook_instance'] && strpos($clean['abook_instance'],z_root()) === false) { + $clean['abook_not_here'] = 1; + } + + $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", dbesc($clean['abook_xchan']), intval($channel['channel_id']) @@ -3586,6 +3584,14 @@ function import_author_zot($x) { $hash = make_xchan_hash($x['guid'],$x['guid_sig']); + // also - this function may get passed a profile url as 'url' and zot_refresh wants a hubloc_url (site baseurl), + // so deconstruct the url (if we have one) and rebuild it with just the baseurl components. + + if(array_key_exists('url',$x)) { + $m = parse_url($x['url']); + $desturl = $m['scheme'] . '://' . $m['host']; + } + $r1 = q("select hubloc_url, hubloc_updated, site_dead from hubloc left join site on hubloc_url = site_url where hubloc_guid = '%s' and hubloc_guid_sig = '%s' and hubloc_primary = 1 limit 1", dbesc($x['guid']), @@ -3627,14 +3633,16 @@ function import_author_zot($x) { ); if($r) { logger('found another site that is not dead: ' . $r[0]['hubloc_url'], LOGGER_DEBUG,LOG_INFO); - $x['url'] = $r[0]['hubloc_url']; + $desturl = $r[0]['hubloc_url']; } else { return $hash; } } - $them = array('hubloc_url' => $x['url'], 'xchan_guid' => $x['guid'], 'xchan_guid_sig' => $x['guid_sig']); + + + $them = array('hubloc_url' => $desturl, 'xchan_guid' => $x['guid'], 'xchan_guid_sig' => $x['guid_sig']); if(zot_refresh($them)) return $hash; @@ -3921,6 +3929,7 @@ function zotinfo($arr) { $ret['photo_updated'] = $e['xchan_photo_date']; $ret['url'] = $e['xchan_url']; $ret['connections_url']= (($e['xchan_connurl']) ? $e['xchan_connurl'] : z_root() . '/poco/' . $e['channel_address']); + $ret['follow_url'] = $e['xchan_follow']; $ret['target'] = $ztarget; $ret['target_sig'] = $zsig; $ret['searchable'] = $searchable; @@ -3928,19 +3937,22 @@ function zotinfo($arr) { $ret['public_forum'] = $public_forum; if($deleted) $ret['deleted'] = $deleted; + if(intval($e['channel_removed'])) $ret['deleted_locally'] = true; + + // premium or other channel desiring some contact with potential followers before connecting. // This is a template - %s will be replaced with the follow_url we discover for the return channel. - if($special_channel) - $ret['connect_url'] = z_root() . '/connect/' . $e['channel_address']; - + if($special_channel) { + $ret['connect_url'] = (($e['xchan_connpage']) ? $e['xchan_connpage'] : z_root() . '/connect/' . $e['channel_address']); + } // This is a template for our follow url, %s will be replaced with a webbie - $ret['follow_url'] = z_root() . '/follow?f=&url=%s'; - + if(! $ret['follow_url']) + $ret['follow_url'] = z_root() . '/follow?f=&url=%s'; $permissions = get_all_perms($e['channel_id'],$ztarget_hash,false); diff --git a/install/htconfig.sample.php b/install/htconfig.sample.php index f37b3dc79..07725e3f4 100755 --- a/install/htconfig.sample.php +++ b/install/htconfig.sample.php @@ -44,14 +44,6 @@ App::$config['system']['sitename'] = "Hubzilla"; App::$config['system']['location_hash'] = 'if the auto install failed, put a unique random string here'; -// Choices are 'basic', 'standard', and 'pro'. -// basic sets up the sevrer for basic social networking and removes "complicated" features -// standard provides most desired features except e-commerce -// pro gives you access to everything, but removes cross-platform federation/emulation - -App::$config['system']['server_role'] = 'standard'; - - // These lines set additional security headers to be sent with all responses // You may wish to set transport_security_header to 0 if your server already sends // this header. content_security_policy may need to be disabled if you wish to diff --git a/install/schema_mysql.sql b/install/schema_mysql.sql index 3ef65f454..6938050cf 100644 --- a/install/schema_mysql.sql +++ b/install/schema_mysql.sql @@ -43,8 +43,6 @@ CREATE TABLE IF NOT EXISTS `abook` ( KEY `abook_account` (`abook_account`), KEY `abook_channel` (`abook_channel`), KEY `abook_xchan` (`abook_xchan`), - KEY `abook_my_perms` (`abook_my_perms`), - KEY `abook_their_perms` (`abook_their_perms`), KEY `abook_closeness` (`abook_closeness`), KEY `abook_created` (`abook_created`), KEY `abook_updated` (`abook_updated`), @@ -147,8 +145,8 @@ CREATE TABLE IF NOT EXISTS `app` ( CREATE TABLE IF NOT EXISTS `atoken` ( `atoken_id` int(11) NOT NULL AUTO_INCREMENT, - `atoken_aid` int(11) NOT NULL DEFAULT 0, - `atoken_uid` int(11) NOT NULL DEFAULT 0, + `atoken_aid` int(11) NOT NULL DEFAULT 0 , + `atoken_uid` int(11) NOT NULL DEFAULT 0 , `atoken_name` char(191) NOT NULL DEFAULT '', `atoken_token` char(191) NOT NULL DEFAULT '', `atoken_expires` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', @@ -165,13 +163,13 @@ CREATE TABLE IF NOT EXISTS `attach` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `aid` int(10) unsigned NOT NULL DEFAULT 0 , `uid` int(10) unsigned NOT NULL DEFAULT 0 , - `hash` char(64) NOT NULL DEFAULT '', - `creator` char(128) NOT NULL DEFAULT '', + `hash` char(191) NOT NULL DEFAULT '', + `creator` char(191) NOT NULL DEFAULT '', `filename` char(191) NOT NULL DEFAULT '', - `filetype` char(64) NOT NULL DEFAULT '', + `filetype` char(191) NOT NULL DEFAULT '', `filesize` int(10) unsigned NOT NULL DEFAULT 0 , `revision` int(10) unsigned NOT NULL DEFAULT 0 , - `folder` char(64) NOT NULL DEFAULT '', + `folder` char(191) NOT NULL DEFAULT '', `flags` int(10) unsigned NOT NULL DEFAULT 0 , `is_dir` tinyint(1) NOT NULL DEFAULT 0 , `is_photo` tinyint(1) NOT NULL DEFAULT 0 , @@ -223,14 +221,14 @@ CREATE TABLE IF NOT EXISTS `cal` ( `cal_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `cal_aid` int(10) unsigned NOT NULL DEFAULT 0 , `cal_uid` int(10) unsigned NOT NULL DEFAULT 0 , - `cal_hash` varchar(255) NOT NULL DEFAULT '', - `cal_name` varchar(255) NOT NULL DEFAULT '', - `uri` varchar(255) NOT NULL DEFAULT '', - `logname` varchar(255) NOT NULL DEFAULT '', - `pass` varchar(255) NOT NULL DEFAULT '', - `ctag` varchar(255) NOT NULL DEFAULT '', - `synctoken` varchar(255) NOT NULL DEFAULT '', - `cal_types` varchar(255) NOT NULL DEFAULT '', + `cal_hash` varchar(191) NOT NULL DEFAULT '', + `cal_name` varchar(191) NOT NULL DEFAULT '', + `uri` varchar(191) NOT NULL DEFAULT '', + `logname` varchar(191) NOT NULL DEFAULT '', + `pass` varchar(191) NOT NULL DEFAULT '', + `ctag` varchar(191) NOT NULL DEFAULT '', + `synctoken` varchar(191) NOT NULL DEFAULT '', + `cal_types` varchar(191) NOT NULL DEFAULT '', PRIMARY KEY (`cal_id`), KEY `cal_aid` (`cal_aid`), KEY `cal_uid` (`cal_uid`), @@ -289,8 +287,8 @@ CREATE TABLE IF NOT EXISTS `channel` ( `channel_removed` tinyint(1) NOT NULL DEFAULT 0 , `channel_system` tinyint(1) NOT NULL DEFAULT 0 , `channel_moved` char(191) NOT NULL DEFAULT '', - `channel_password` varchar(255) NOT NULL, - `channel_salt` varchar(255) NOT NULL, + `channel_password` varchar(191) NOT NULL, + `channel_salt` varchar(191) NOT NULL, PRIMARY KEY (`channel_id`), KEY `channel_address` (`channel_address`), KEY `channel_account_id` (`channel_account_id`), @@ -304,29 +302,11 @@ CREATE TABLE IF NOT EXISTS `channel` ( KEY `channel_max_anon_mail` (`channel_max_anon_mail`), KEY `channel_max_friend_req` (`channel_max_friend_req`), KEY `channel_default_gid` (`channel_default_group`), - KEY `channel_r_stream` (`channel_r_stream`), - KEY `channel_r_profile` (`channel_r_profile`), - KEY `channel_r_photos` (`channel_r_photos`), - KEY `channel_r_abook` (`channel_r_abook`), - KEY `channel_w_stream` (`channel_w_stream`), - KEY `channel_w_wall` (`channel_w_wall`), - KEY `channel_w_tagwall` (`channel_w_tagwall`), - KEY `channel_w_comment` (`channel_w_comment`), - KEY `channel_w_mail` (`channel_w_mail`), - KEY `channel_w_photos` (`channel_w_photos`), - KEY `channel_w_chat` (`channel_w_chat`), KEY `channel_guid` (`channel_guid`), KEY `channel_hash` (`channel_hash`), KEY `channel_expire_days` (`channel_expire_days`), - KEY `channel_a_delegate` (`channel_a_delegate`), - KEY `channel_r_storage` (`channel_r_storage`), - KEY `channel_w_storage` (`channel_w_storage`), - KEY `channel_r_pages` (`channel_r_pages`), - KEY `channel_w_pages` (`channel_w_pages`), KEY `channel_deleted` (`channel_deleted`), - KEY `channel_a_republish` (`channel_a_republish`), KEY `channel_dirdate` (`channel_dirdate`), - KEY `channel_w_like` (`channel_w_like`), KEY `channel_removed` (`channel_removed`), KEY `channel_system` (`channel_system`), KEY `channel_lastpost` (`channel_lastpost`), @@ -381,8 +361,8 @@ CREATE TABLE IF NOT EXISTS `chatroom` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE IF NOT EXISTS `clients` ( - `client_id` varchar(20) NOT NULL DEFAULT '', - `pw` varchar(20) NOT NULL DEFAULT '', + `client_id` varchar(191) NOT NULL DEFAULT '', + `pw` varchar(191) NOT NULL DEFAULT '', `redirect_uri` varchar(200) NOT NULL DEFAULT '', `clname` text, `icon` text, @@ -541,6 +521,7 @@ CREATE TABLE IF NOT EXISTS `hubloc` ( PRIMARY KEY (`hubloc_id`), KEY `hubloc_url` (`hubloc_url`), KEY `hubloc_guid` (`hubloc_guid`), + KEY `hubloc_hash` (`hubloc_hash`), KEY `hubloc_flags` (`hubloc_flags`), KEY `hubloc_connect` (`hubloc_connect`), KEY `hubloc_host` (`hubloc_host`), @@ -731,13 +712,13 @@ CREATE TABLE IF NOT EXISTS `item_id` ( CREATE TABLE IF NOT EXISTS `likes` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `channel_id` int(10) unsigned NOT NULL DEFAULT 0 , - `liker` char(128) NOT NULL DEFAULT '', - `likee` char(128) NOT NULL DEFAULT '', + `liker` char(191) NOT NULL DEFAULT '', + `likee` char(191) NOT NULL DEFAULT '', `iid` int(11) unsigned NOT NULL DEFAULT 0 , `i_mid` char(191) NOT NULL DEFAULT '', `verb` char(191) NOT NULL DEFAULT '', `target_type` char(191) NOT NULL DEFAULT '', - `target_id` char(128) NOT NULL DEFAULT '', + `target_id` char(191) NOT NULL DEFAULT '', `target` mediumtext NOT NULL, PRIMARY KEY (`id`), KEY `liker` (`liker`), @@ -831,7 +812,7 @@ CREATE TABLE IF NOT EXISTS `menu_item` ( CREATE TABLE IF NOT EXISTS `notify` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `hash` char(64) NOT NULL DEFAULT '', + `hash` char(191) NOT NULL DEFAULT '', `xname` char(191) NOT NULL DEFAULT '', `url` char(191) NOT NULL DEFAULT '', `photo` char(191) NOT NULL DEFAULT '', @@ -1219,9 +1200,9 @@ CREATE TABLE IF NOT EXISTS `term` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE IF NOT EXISTS `tokens` ( - `id` varchar(40) NOT NULL DEFAULT '', + `id` varchar(191) NOT NULL DEFAULT '', `secret` text NOT NULL, - `client_id` varchar(20) NOT NULL DEFAULT '', + `client_id` varchar(191) NOT NULL DEFAULT '', `expires` bigint(20) unsigned NOT NULL DEFAULT 0 , `auth_scope` varchar(512) NOT NULL DEFAULT '', `uid` int(11) NOT NULL DEFAULT 0 , @@ -1233,7 +1214,7 @@ CREATE TABLE IF NOT EXISTS `tokens` ( CREATE TABLE IF NOT EXISTS `updates` ( `ud_id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `ud_hash` char(128) NOT NULL DEFAULT '', + `ud_hash` char(191) NOT NULL DEFAULT '', `ud_guid` char(191) NOT NULL DEFAULT '', `ud_date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', `ud_last` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', @@ -1423,3 +1404,174 @@ CREATE TABLE IF NOT EXISTS `xtag` ( KEY `xtag_hash` (`xtag_hash`), KEY `xtag_flags` (`xtag_flags`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE if not exists addressbooks ( + id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + principaluri VARBINARY(255), + displayname VARCHAR(255), + uri VARBINARY(200), + description TEXT, + synctoken INT(11) UNSIGNED NOT NULL DEFAULT '1', + UNIQUE(principaluri(100), uri(100)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE if not exists cards ( + id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + addressbookid INT(11) UNSIGNED NOT NULL, + carddata MEDIUMBLOB, + uri VARBINARY(200), + lastmodified INT(11) UNSIGNED, + etag VARBINARY(32), + size INT(11) UNSIGNED NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE if not exists addressbookchanges ( + id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + uri VARBINARY(200) NOT NULL, + synctoken INT(11) UNSIGNED NOT NULL, + addressbookid INT(11) UNSIGNED NOT NULL, + operation TINYINT(1) NOT NULL, + INDEX addressbookid_synctoken (addressbookid, synctoken) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE if not exists calendarobjects ( + id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + calendardata MEDIUMBLOB, + uri VARBINARY(200), + calendarid INTEGER UNSIGNED NOT NULL, + lastmodified INT(11) UNSIGNED, + etag VARBINARY(32), + size INT(11) UNSIGNED NOT NULL, + componenttype VARBINARY(8), + firstoccurence INT(11) UNSIGNED, + lastoccurence INT(11) UNSIGNED, + uid VARBINARY(200), + UNIQUE(calendarid, uri), + INDEX calendarid_time (calendarid, firstoccurence) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE if not exists calendars ( + id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + synctoken INTEGER UNSIGNED NOT NULL DEFAULT '1', + components VARBINARY(21) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE if not exists calendarinstances ( + id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + calendarid INTEGER UNSIGNED NOT NULL, + principaluri VARBINARY(100), + access TINYINT(1) NOT NULL DEFAULT '1' COMMENT '1 = owner, 2 = read, 3 = readwrite', + displayname VARCHAR(100), + uri VARBINARY(200), + description TEXT, + calendarorder INT(11) UNSIGNED NOT NULL DEFAULT '0', + calendarcolor VARBINARY(10), + timezone TEXT, + transparent TINYINT(1) NOT NULL DEFAULT '0', + share_href VARBINARY(100), + share_displayname VARCHAR(100), + share_invitestatus TINYINT(1) NOT NULL DEFAULT '2' COMMENT '1 = noresponse, 2 = accepted, 3 = declined, 4 = invalid', + UNIQUE(principaluri, uri), + UNIQUE(calendarid, principaluri), + UNIQUE(calendarid, share_href) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE if not exists calendarchanges ( + id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + uri VARBINARY(200) NOT NULL, + synctoken INT(11) UNSIGNED NOT NULL, + calendarid INT(11) UNSIGNED NOT NULL, + operation TINYINT(1) NOT NULL, + INDEX calendarid_synctoken (calendarid, synctoken) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE if not exists calendarsubscriptions ( + id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + uri VARBINARY(200) NOT NULL, + principaluri VARBINARY(100) NOT NULL, + source TEXT, + displayname VARCHAR(100), + refreshrate VARCHAR(10), + calendarorder INT(11) UNSIGNED NOT NULL DEFAULT '0', + calendarcolor VARBINARY(10), + striptodos TINYINT(1) NULL, + stripalarms TINYINT(1) NULL, + stripattachments TINYINT(1) NULL, + lastmodified INT(11) UNSIGNED, + UNIQUE(principaluri, uri) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE if not exists schedulingobjects ( + id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + principaluri VARBINARY(255), + calendardata MEDIUMBLOB, + uri VARBINARY(200), + lastmodified INT(11) UNSIGNED, + etag VARBINARY(32), + size INT(11) UNSIGNED NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE if not exists locks ( + id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + owner VARCHAR(100), + timeout INTEGER UNSIGNED, + created INTEGER, + token VARBINARY(100), + scope TINYINT, + depth TINYINT, + uri VARBINARY(1000), + INDEX(token), + INDEX(uri(100)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE if not exists principals ( + id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + uri VARBINARY(200) NOT NULL, + email VARBINARY(80), + displayname VARCHAR(80), + UNIQUE(uri) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE if not exists groupmembers ( + id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + principal_id INTEGER UNSIGNED NOT NULL, + member_id INTEGER UNSIGNED NOT NULL, + UNIQUE(principal_id, member_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE if not exists propertystorage ( + id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + path VARBINARY(1024) NOT NULL, + name VARBINARY(100) NOT NULL, + valuetype INT UNSIGNED, + value MEDIUMBLOB +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE UNIQUE INDEX path_property ON propertystorage (path(600), name(100)); + +CREATE TABLE if not exists users ( + id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + username VARBINARY(50), + digesta1 VARBINARY(32), + UNIQUE(username) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE if not exists calendarinstances ( + id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + calendarid INTEGER UNSIGNED NOT NULL, + principaluri VARBINARY(100), + access TINYINT(1) NOT NULL DEFAULT '1' COMMENT '1 = owner, 2 = read, 3 = readwrite', + displayname VARCHAR(100), + uri VARBINARY(200), + description TEXT, + calendarorder INT(11) UNSIGNED NOT NULL DEFAULT '0', + calendarcolor VARBINARY(10), + timezone TEXT, + transparent TINYINT(1) NOT NULL DEFAULT '0', + share_href VARBINARY(100), + share_displayname VARCHAR(100), + share_invitestatus TINYINT(1) NOT NULL DEFAULT '2' COMMENT '1 = noresponse, 2 = accepted, 3 = declined, 4 = invalid', + UNIQUE(principaluri, uri), + UNIQUE(calendarid, principaluri), + UNIQUE(calendarid, share_href) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/install/schema_postgres.sql b/install/schema_postgres.sql index e171d9baf..0249d447a 100644 --- a/install/schema_postgres.sql +++ b/install/schema_postgres.sql @@ -1,6 +1,6 @@ CREATE TABLE "abconfig" ( "id" serial NOT NULL, - "chan" bigint NOT NULL DEFAULT 0, + "chan" bigint NOT NULL DEFAULT '0', "xchan" text NOT NULL, "cat" text NOT NULL, "k" text NOT NULL, @@ -16,23 +16,21 @@ CREATE TABLE "abook" ( "abook_account" bigint NOT NULL, "abook_channel" bigint NOT NULL, "abook_xchan" text NOT NULL DEFAULT '', - "abook_my_perms" bigint NOT NULL DEFAULT 0, - "abook_their_perms" bigint NOT NULL DEFAULT 0, - "abook_closeness" numeric(3) NOT NULL DEFAULT 99, + "abook_closeness" numeric(3) NOT NULL DEFAULT '99', "abook_created" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "abook_updated" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "abook_connected" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "abook_dob" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', - "abook_flags" bigint NOT NULL DEFAULT 0 , - "abook_blocked" smallint NOT NULL DEFAULT 0 , - "abook_ignored" smallint NOT NULL DEFAULT 0 , - "abook_hidden" smallint NOT NULL DEFAULT 0 , - "abook_archived" smallint NOT NULL DEFAULT 0 , - "abook_pending" smallint NOT NULL DEFAULT 0 , - "abook_unconnected" smallint NOT NULL DEFAULT 0 , - "abook_self" smallint NOT NULL DEFAULT 0 , - "abook_feed" smallint NOT NULL DEFAULT 0 , - "abook_not_here" smallint NOT NULL DEFAULT 0 , + "abook_flags" bigint NOT NULL DEFAULT '0', + "abook_blocked" smallint NOT NULL DEFAULT '0', + "abook_ignored" smallint NOT NULL DEFAULT '0', + "abook_hidden" smallint NOT NULL DEFAULT '0', + "abook_archived" smallint NOT NULL DEFAULT '0', + "abook_pending" smallint NOT NULL DEFAULT '0', + "abook_unconnected" smallint NOT NULL DEFAULT '0', + "abook_self" smallint NOT NULL DEFAULT '0', + "abook_feed" smallint NOT NULL DEFAULT '0', + "abook_not_here" smallint NOT NULL DEFAULT '0', "abook_profile" varchar(64) NOT NULL DEFAULT '', "abook_incl" TEXT NOT NULL DEFAULT '', "abook_excl" TEXT NOT NULL DEFAULT '', @@ -42,8 +40,6 @@ CREATE TABLE "abook" ( create index "abook_account" on abook ("abook_account"); create index "abook_channel" on abook ("abook_channel"); create index "abook_xchan" on abook ("abook_xchan"); - create index "abook_my_perms" on abook ("abook_my_perms"); - create index "abook_their_perms" on abook ("abook_their_perms"); create index "abook_closeness" on abook ("abook_closeness"); create index "abook_created" on abook ("abook_created"); create index "abook_updated" on abook ("abook_updated"); @@ -64,8 +60,8 @@ CREATE TABLE "abook" ( CREATE TABLE "account" ( "account_id" serial NOT NULL, - "account_parent" bigint NOT NULL DEFAULT 0 , - "account_default_channel" bigint NOT NULL DEFAULT 0 , + "account_parent" bigint NOT NULL DEFAULT '0', + "account_default_channel" bigint NOT NULL DEFAULT '0', "account_salt" varchar(32) NOT NULL DEFAULT '', "account_password" text NOT NULL DEFAULT '', "account_email" text NOT NULL DEFAULT '', @@ -73,13 +69,13 @@ CREATE TABLE "account" ( "account_language" varchar(16) NOT NULL DEFAULT 'en', "account_created" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "account_lastlog" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', - "account_flags" bigint NOT NULL DEFAULT 0 , - "account_roles" bigint NOT NULL DEFAULT 0 , + "account_flags" bigint NOT NULL DEFAULT '0', + "account_roles" bigint NOT NULL DEFAULT '0', "account_reset" text NOT NULL DEFAULT '', "account_expires" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "account_expire_notified" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "account_service_class" varchar(32) NOT NULL DEFAULT '', - "account_level" bigint NOT NULL DEFAULT 0 , + "account_level" bigint NOT NULL DEFAULT '0', "account_password_changed" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', PRIMARY KEY ("account_id") ); @@ -97,11 +93,11 @@ create index "account_password_changed" on account ("account_password_changed") CREATE TABLE "addon" ( "id" serial NOT NULL, "aname" text NOT NULL, - "version" text NOT NULL DEFAULT 0 , - "installed" numeric(1) NOT NULL DEFAULT 0 , - "hidden" numeric(1) NOT NULL DEFAULT 0 , - "tstamp" numeric(20) NOT NULL DEFAULT 0 , - "plugin_admin" numeric(1) NOT NULL DEFAULT 0 , + "version" text NOT NULL DEFAULT '0', + "installed" numeric(1) NOT NULL DEFAULT '0', + "hidden" numeric(1) NOT NULL DEFAULT '0', + "tstamp" numeric(20) NOT NULL DEFAULT '0', + "plugin_admin" numeric(1) NOT NULL DEFAULT '0', PRIMARY KEY ("id") ); create index "addon_hidden_idx" on addon ("hidden"); @@ -117,13 +113,13 @@ CREATE TABLE "app" ( "app_url" text NOT NULL DEFAULT '', "app_photo" text NOT NULL DEFAULT '', "app_version" text NOT NULL DEFAULT '', - "app_channel" bigint NOT NULL DEFAULT 0 , + "app_channel" bigint NOT NULL DEFAULT '0', "app_addr" text NOT NULL DEFAULT '', "app_price" text NOT NULL DEFAULT '', "app_page" text NOT NULL DEFAULT '', "app_requires" text NOT NULL DEFAULT '', - "app_deleted" smallint NOT NULL DEFAULT 0 , - "app_system" smallint NOT NULL DEFAULT 0 , + "app_deleted" smallint NOT NULL DEFAULT '0', + "app_system" smallint NOT NULL DEFAULT '0', "app_plugin" text NOT NULL DEFAULT '', "app_created" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "app_edited" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', @@ -158,19 +154,19 @@ create index atoken_expires on atoken (atoken_expires); CREATE TABLE "attach" ( "id" serial NOT NULL, - "aid" bigint NOT NULL DEFAULT 0 , - "uid" bigint NOT NULL DEFAULT 0 , + "aid" bigint NOT NULL DEFAULT '0', + "uid" bigint NOT NULL DEFAULT '0', "hash" varchar(64) NOT NULL DEFAULT '', "creator" varchar(128) NOT NULL DEFAULT '', "filename" text NOT NULL DEFAULT '', "filetype" varchar(64) NOT NULL DEFAULT '', - "filesize" bigint NOT NULL DEFAULT 0 , - "revision" bigint NOT NULL DEFAULT 0 , + "filesize" bigint NOT NULL DEFAULT '0', + "revision" bigint NOT NULL DEFAULT '0', "folder" varchar(64) NOT NULL DEFAULT '', - "flags" bigint NOT NULL DEFAULT 0 , - "is_dir" smallint NOT NULL DEFAULT 0 , - "is_photo" smallint NOT NULL DEFAULT 0 , - "os_storage" smallint NOT NULL DEFAULT 0 , + "flags" bigint NOT NULL DEFAULT '0', + "is_dir" smallint NOT NULL DEFAULT '0', + "is_photo" smallint NOT NULL DEFAULT '0', + "os_storage" smallint NOT NULL DEFAULT '0', "os_path" text NOT NULL, "display_path" text NOT NULL, "content" bytea NOT NULL, @@ -214,8 +210,8 @@ CREATE TABLE "cache" ( ); CREATE TABLE "cal" ( "cal_id" serial NOT NULL, - "cal_aid" bigint NOT NULL DEFAULT 0 , - "cal_uid" bigint NOT NULL DEFAULT 0 , + "cal_aid" bigint NOT NULL DEFAULT '0', + "cal_uid" bigint NOT NULL DEFAULT '0', "cal_hash" text NOT NULL, "cal_name" text NOT NULL, "uri" text NOT NULL, @@ -223,7 +219,7 @@ CREATE TABLE "cal" ( "pass" text NOT NULL, "ctag" text NOT NULL, "synctoken" text NOT NULL, - "cal_types" text NOT NULL DEFAULT 0 , + "cal_types" text NOT NULL DEFAULT '0', PRIMARY KEY ("cal_id") ); create index "cal_hash_idx" on cal ("cal_hash"); @@ -234,8 +230,8 @@ create index "cal_uid_idx" on cal ("cal_uid"); CREATE TABLE "channel" ( "channel_id" serial NOT NULL, - "channel_account_id" bigint NOT NULL DEFAULT 0 , - "channel_primary" numeric(1) NOT NULL DEFAULT 0 , + "channel_account_id" bigint NOT NULL DEFAULT '0', + "channel_primary" numeric(1) NOT NULL DEFAULT '0', "channel_name" text NOT NULL DEFAULT '', "channel_address" text NOT NULL DEFAULT '', "channel_guid" text NOT NULL DEFAULT '', @@ -247,40 +243,22 @@ CREATE TABLE "channel" ( "channel_startpage" text NOT NULL DEFAULT '', "channel_pubkey" text NOT NULL, "channel_prvkey" text NOT NULL, - "channel_notifyflags" bigint NOT NULL DEFAULT 65535, - "channel_pageflags" bigint NOT NULL DEFAULT 0 , + "channel_notifyflags" bigint NOT NULL DEFAULT '65535', + "channel_pageflags" bigint NOT NULL DEFAULT '0', "channel_dirdate" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "channel_lastpost" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "channel_deleted" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', - "channel_max_anon_mail" bigint NOT NULL DEFAULT 10, - "channel_max_friend_req" bigint NOT NULL DEFAULT 10, - "channel_expire_days" bigint NOT NULL DEFAULT 0 , + "channel_max_anon_mail" bigint NOT NULL DEFAULT '10', + "channel_max_friend_req" bigint NOT NULL DEFAULT '10', + "channel_expire_days" bigint NOT NULL DEFAULT '0', "channel_passwd_reset" text NOT NULL DEFAULT '', "channel_default_group" text NOT NULL DEFAULT '', "channel_allow_cid" text , "channel_allow_gid" text , "channel_deny_cid" text , "channel_deny_gid" text , - "channel_r_stream" bigint NOT NULL DEFAULT 0, - "channel_r_profile" bigint NOT NULL DEFAULT 0, - "channel_r_photos" bigint NOT NULL DEFAULT 0, - "channel_r_abook" bigint NOT NULL DEFAULT 0, - "channel_w_stream" bigint NOT NULL DEFAULT 0, - "channel_w_wall" bigint NOT NULL DEFAULT 0, - "channel_w_tagwall" bigint NOT NULL DEFAULT 0, - "channel_w_comment" bigint NOT NULL DEFAULT 0, - "channel_w_mail" bigint NOT NULL DEFAULT 0, - "channel_w_photos" bigint NOT NULL DEFAULT 0, - "channel_w_chat" bigint NOT NULL DEFAULT 0, - "channel_a_delegate" bigint NOT NULL DEFAULT 0 , - "channel_r_storage" bigint NOT NULL DEFAULT 0, - "channel_w_storage" bigint NOT NULL DEFAULT 0, - "channel_r_pages" bigint NOT NULL DEFAULT 0, - "channel_w_pages" bigint NOT NULL DEFAULT 0, - "channel_a_republish" bigint NOT NULL DEFAULT 0, - "channel_w_like" bigint NOT NULL DEFAULT 0, - "channel_removed" smallint NOT NULL DEFAULT 0 , - "channel_system" smallint NOT NULL DEFAULT 0 , + "channel_removed" smallint NOT NULL DEFAULT '0', + "channel_system" smallint NOT NULL DEFAULT '0', "channel_moved" text NOT NULL DEFAULT '', "channel_password" varchar(255) NOT NULL, "channel_salt" varchar(255) NOT NULL, @@ -298,28 +276,10 @@ create index "channel_pageflags" on channel ("channel_pageflags"); create index "channel_max_anon_mail" on channel ("channel_max_anon_mail"); create index "channel_max_friend_req" on channel ("channel_max_friend_req"); create index "channel_default_gid" on channel ("channel_default_group"); -create index "channel_r_stream" on channel ("channel_r_stream"); -create index "channel_r_profile" on channel ("channel_r_profile"); -create index "channel_r_photos" on channel ("channel_r_photos"); -create index "channel_r_abook" on channel ("channel_r_abook"); -create index "channel_w_stream" on channel ("channel_w_stream"); -create index "channel_w_wall" on channel ("channel_w_wall"); -create index "channel_w_tagwall" on channel ("channel_w_tagwall"); -create index "channel_w_comment" on channel ("channel_w_comment"); -create index "channel_w_mail" on channel ("channel_w_mail"); -create index "channel_w_photos" on channel ("channel_w_photos"); -create index "channel_w_chat" on channel ("channel_w_chat"); create index "channel_guid" on channel ("channel_guid"); create index "channel_hash" on channel ("channel_hash"); create index "channel_expire_days" on channel ("channel_expire_days"); -create index "channel_a_delegate" on channel ("channel_a_delegate"); -create index "channel_r_storage" on channel ("channel_r_storage"); -create index "channel_w_storage" on channel ("channel_w_storage"); -create index "channel_r_pages" on channel ("channel_r_pages"); -create index "channel_w_pages" on channel ("channel_w_pages"); create index "channel_deleted" on channel ("channel_deleted"); -create index "channel_a_republish" on channel ("channel_a_republish"); -create index "channel_w_like" on channel ("channel_w_like"); create index "channel_dirdate" on channel ("channel_dirdate"); create index "channel_lastpost" on channel ("channel_lastpost"); create index "channel_removed" on channel ("channel_removed"); @@ -327,7 +287,7 @@ create index "channel_system" on channel ("channel_system"); create index "channel_moved" on channel ("channel_moved"); CREATE TABLE "chat" ( "chat_id" serial NOT NULL, - "chat_room" bigint NOT NULL DEFAULT 0 , + "chat_room" bigint NOT NULL DEFAULT '0', "chat_xchan" text NOT NULL DEFAULT '', "chat_text" text NOT NULL, "created" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', @@ -338,7 +298,7 @@ create index "chat_xchan_idx" on chat ("chat_xchan"); create index "chat_created_idx" on chat ("created"); CREATE TABLE "chatpresence" ( "cp_id" serial NOT NULL, - "cp_room" bigint NOT NULL DEFAULT 0 , + "cp_room" bigint NOT NULL DEFAULT '0', "cp_xchan" text NOT NULL DEFAULT '', "cp_last" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "cp_status" text NOT NULL, @@ -352,12 +312,12 @@ create index "cp_status" on chatpresence ("cp_status"); CREATE TABLE "chatroom" ( "cr_id" serial NOT NULL, - "cr_aid" bigint NOT NULL DEFAULT 0 , - "cr_uid" bigint NOT NULL DEFAULT 0 , + "cr_aid" bigint NOT NULL DEFAULT '0', + "cr_uid" bigint NOT NULL DEFAULT '0', "cr_name" text NOT NULL DEFAULT '', "cr_created" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "cr_edited" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', - "cr_expire" bigint NOT NULL DEFAULT 0 , + "cr_expire" bigint NOT NULL DEFAULT '0', "allow_cid" text NOT NULL, "allow_gid" text NOT NULL, "deny_cid" text NOT NULL, @@ -376,7 +336,7 @@ CREATE TABLE "clients" ( "redirect_uri" varchar(200) NOT NULL, "clname" text, "icon" text, - "uid" bigint NOT NULL DEFAULT 0 , + "uid" bigint NOT NULL DEFAULT '0', PRIMARY KEY ("client_id") ); CREATE TABLE "config" ( @@ -403,7 +363,7 @@ create index "conv_updated_idx" on conv ("updated"); CREATE TABLE IF NOT EXISTS "dreport" ( "dreport_id" serial NOT NULL, - "dreport_channel" int NOT NULL DEFAULT 0 , + "dreport_channel" int NOT NULL DEFAULT '0', "dreport_mid" varchar(255) NOT NULL DEFAULT '', "dreport_site" varchar(255) NOT NULL DEFAULT '', "dreport_recip" varchar(255) NOT NULL DEFAULT '', @@ -423,9 +383,9 @@ create index "dreport_channel" on dreport ("dreport_channel"); CREATE TABLE "event" ( "id" serial NOT NULL, - "aid" bigint NOT NULL DEFAULT 0 , + "aid" bigint NOT NULL DEFAULT '0', "uid" bigint NOT NULL, - "cal_id" bigint NOT NULL DEFAULT 0 , + "cal_id" bigint NOT NULL DEFAULT '0', "event_xchan" text NOT NULL DEFAULT '', "event_hash" text NOT NULL DEFAULT '', "created" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', @@ -436,19 +396,19 @@ CREATE TABLE "event" ( "description" text NOT NULL, "location" text NOT NULL, "etype" text NOT NULL, - "nofinish" numeric(1) NOT NULL DEFAULT 0 , - "adjust" numeric(1) NOT NULL DEFAULT 1, - "dismissed" numeric(1) NOT NULL DEFAULT 0 , + "nofinish" numeric(1) NOT NULL DEFAULT '0', + "adjust" numeric(1) NOT NULL DEFAULT '1', + "dismissed" numeric(1) NOT NULL DEFAULT '0', "allow_cid" text NOT NULL, "allow_gid" text NOT NULL, "deny_cid" text NOT NULL, "deny_gid" text NOT NULL, "event_status" varchar(255) NOT NULL DEFAULT '', "event_status_date" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', - "event_percent" smallint NOT NULL DEFAULT 0 , + "event_percent" smallint NOT NULL DEFAULT '0', "event_repeat" text NOT NULL, - "event_sequence" smallint NOT NULL DEFAULT 0 , - "event_priority" smallint NOT NULL DEFAULT 0 , + "event_sequence" smallint NOT NULL DEFAULT '0', + "event_priority" smallint NOT NULL DEFAULT '0', "event_vdata" text NOT NULL, PRIMARY KEY ("id") ); @@ -482,8 +442,8 @@ CREATE TABLE "groups" ( "id" serial NOT NULL, "hash" text NOT NULL DEFAULT '', "uid" bigint NOT NULL, - "visible" numeric(1) NOT NULL DEFAULT 0 , - "deleted" numeric(1) NOT NULL DEFAULT 0 , + "visible" numeric(1) NOT NULL DEFAULT '0', + "deleted" numeric(1) NOT NULL DEFAULT '0', "gname" text NOT NULL, PRIMARY KEY ("id") @@ -498,8 +458,8 @@ CREATE TABLE "hook" ( "hook" text NOT NULL, "file" text NOT NULL, "fn" text NOT NULL, - "priority" smallint NOT NULL DEFAULT 0 , - "hook_version" smallint NOT NULL DEFAULT 0 , + "priority" smallint NOT NULL DEFAULT '0', + "hook_version" smallint NOT NULL DEFAULT '0', PRIMARY KEY ("id") ); @@ -514,8 +474,8 @@ CREATE TABLE "hubloc" ( "hubloc_hash" text NOT NULL, "hubloc_addr" text NOT NULL DEFAULT '', "hubloc_network" text NOT NULL DEFAULT '', - "hubloc_flags" bigint NOT NULL DEFAULT 0 , - "hubloc_status" bigint NOT NULL DEFAULT 0 , + "hubloc_flags" bigint NOT NULL DEFAULT '0', + "hubloc_status" bigint NOT NULL DEFAULT '0', "hubloc_url" text NOT NULL DEFAULT '', "hubloc_url_sig" text NOT NULL DEFAULT '', "hubloc_host" text NOT NULL DEFAULT '', @@ -524,10 +484,10 @@ CREATE TABLE "hubloc" ( "hubloc_sitekey" text NOT NULL DEFAULT '', "hubloc_updated" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "hubloc_connected" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', - "hubloc_primary" smallint NOT NULL DEFAULT 0 , - "hubloc_orphancheck" smallint NOT NULL DEFAULT 0 , - "hubloc_error" smallint NOT NULL DEFAULT 0 , - "hubloc_deleted" smallint NOT NULL DEFAULT 0 , + "hubloc_primary" smallint NOT NULL DEFAULT '0', + "hubloc_orphancheck" smallint NOT NULL DEFAULT '0', + "hubloc_error" smallint NOT NULL DEFAULT '0', + "hubloc_deleted" smallint NOT NULL DEFAULT '0', PRIMARY KEY ("hubloc_id") ); create index "hubloc_url" on hubloc ("hubloc_url"); @@ -546,11 +506,11 @@ create index "hubloc_error" on hubloc ("hubloc_error"); create index "hubloc_deleted" on hubloc ("hubloc_deleted"); CREATE TABLE "iconfig" ( "id" serial NOT NULL, - "iid" bigint NOT NULL DEFAULT 0 , + "iid" bigint NOT NULL DEFAULT '0', "cat" text NOT NULL DEFAULT '', "k" text NOT NULL DEFAULT '', "v" text NOT NULL DEFAULT '', - "sharing" int NOT NULL DEFAULT 0 , + "sharing" int NOT NULL DEFAULT '0', PRIMARY KEY("id") ); create index "iconfig_iid" on iconfig ("iid"); @@ -577,9 +537,9 @@ create index "issue_component" on issue ("issue_component"); CREATE TABLE "item" ( "id" serial NOT NULL, "mid" text NOT NULL DEFAULT '', - "aid" bigint NOT NULL DEFAULT 0 , - "uid" bigint NOT NULL DEFAULT 0 , - "parent" bigint NOT NULL DEFAULT 0 , + "aid" bigint NOT NULL DEFAULT '0', + "uid" bigint NOT NULL DEFAULT '0', + "parent" bigint NOT NULL DEFAULT '0', "parent_mid" text NOT NULL DEFAULT '', "thr_parent" text NOT NULL DEFAULT '', "created" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', @@ -598,7 +558,7 @@ CREATE TABLE "item" ( "html" text NOT NULL, "app" text NOT NULL DEFAULT '', "lang" varchar(64) NOT NULL DEFAULT '', - "revision" bigint NOT NULL DEFAULT 0 , + "revision" bigint NOT NULL DEFAULT '0', "verb" text NOT NULL DEFAULT '', "obj_type" text NOT NULL DEFAULT '', "obj" text NOT NULL, @@ -613,7 +573,6 @@ CREATE TABLE "item" ( "resource_type" varchar(16) NOT NULL DEFAULT '', "attach" text NOT NULL, "sig" text NOT NULL DEFAULT '', - "diaspora_meta" text NOT NULL DEFAULT '', "location" text NOT NULL DEFAULT '', "coord" text NOT NULL DEFAULT '', "public_policy" text NOT NULL DEFAULT '', @@ -622,32 +581,32 @@ CREATE TABLE "item" ( "allow_gid" text NOT NULL, "deny_cid" text NOT NULL, "deny_gid" text NOT NULL, - "item_restrict" bigint NOT NULL DEFAULT 0 , - "item_flags" bigint NOT NULL DEFAULT 0 , - "item_private" numeric(4) NOT NULL DEFAULT 0 , - "item_unseen" smallint NOT NULL DEFAULT 0 , - "item_wall" smallint NOT NULL DEFAULT 0 , - "item_origin" smallint NOT NULL DEFAULT 0 , - "item_starred" smallint NOT NULL DEFAULT 0 , - "item_uplink" smallint NOT NULL DEFAULT 0 , - "item_consensus" smallint NOT NULL DEFAULT 0 , - "item_thread_top" smallint NOT NULL DEFAULT 0 , - "item_notshown" smallint NOT NULL DEFAULT 0 , - "item_nsfw" smallint NOT NULL DEFAULT 0 , - "item_relay" smallint NOT NULL DEFAULT 0 , - "item_mentionsme" smallint NOT NULL DEFAULT 0 , - "item_nocomment" smallint NOT NULL DEFAULT 0 , - "item_obscured" smallint NOT NULL DEFAULT 0 , - "item_verified" smallint NOT NULL DEFAULT 0 , - "item_retained" smallint NOT NULL DEFAULT 0 , - "item_rss" smallint NOT NULL DEFAULT 0 , - "item_deleted" smallint NOT NULL DEFAULT 0 , - "item_type" int NOT NULL DEFAULT 0 , - "item_hidden" smallint NOT NULL DEFAULT 0 , - "item_unpublished" smallint NOT NULL DEFAULT 0 , - "item_delayed" smallint NOT NULL DEFAULT 0 , - "item_pending_remove" smallint NOT NULL DEFAULT 0 , - "item_blocked" smallint NOT NULL DEFAULT 0 , + "item_restrict" bigint NOT NULL DEFAULT '0', + "item_flags" bigint NOT NULL DEFAULT '0', + "item_private" numeric(4) NOT NULL DEFAULT '0', + "item_unseen" smallint NOT NULL DEFAULT '0', + "item_wall" smallint NOT NULL DEFAULT '0', + "item_origin" smallint NOT NULL DEFAULT '0', + "item_starred" smallint NOT NULL DEFAULT '0', + "item_uplink" smallint NOT NULL DEFAULT '0', + "item_consensus" smallint NOT NULL DEFAULT '0', + "item_thread_top" smallint NOT NULL DEFAULT '0', + "item_notshown" smallint NOT NULL DEFAULT '0', + "item_nsfw" smallint NOT NULL DEFAULT '0', + "item_relay" smallint NOT NULL DEFAULT '0', + "item_mentionsme" smallint NOT NULL DEFAULT '0', + "item_nocomment" smallint NOT NULL DEFAULT '0', + "item_obscured" smallint NOT NULL DEFAULT '0', + "item_verified" smallint NOT NULL DEFAULT '0', + "item_retained" smallint NOT NULL DEFAULT '0', + "item_rss" smallint NOT NULL DEFAULT '0', + "item_deleted" smallint NOT NULL DEFAULT '0', + "item_type" int NOT NULL DEFAULT '0', + "item_hidden" smallint NOT NULL DEFAULT '0', + "item_unpublished" smallint NOT NULL DEFAULT '0', + "item_delayed" smallint NOT NULL DEFAULT '0', + "item_pending_remove" smallint NOT NULL DEFAULT '0', + "item_blocked" smallint NOT NULL DEFAULT '0', "item_search_vector" tsvector, PRIMARY KEY ("id") ); @@ -725,10 +684,10 @@ create index "itemid_service" on item_id ("service"); create index "itemid_iid" on item_id ("iid"); CREATE TABLE "likes" ( "id" serial NOT NULL, - "channel_id" bigint NOT NULL DEFAULT 0 , + "channel_id" bigint NOT NULL DEFAULT '0', "liker" varchar(128) NOT NULL DEFAULT '', "likee" varchar(128) NOT NULL DEFAULT '', - "iid" bigint NOT NULL DEFAULT 0 , + "iid" bigint NOT NULL DEFAULT '0', "i_mid" varchar(255) NOT NULL DEFAULT '', "verb" text NOT NULL DEFAULT '', "target_type" text NOT NULL DEFAULT '', @@ -746,27 +705,27 @@ create index "likes_target_type" on likes ("target_type"); create index "likes_target_id" on likes ("target_id"); CREATE TABLE "mail" ( "id" serial NOT NULL, - "convid" bigint NOT NULL DEFAULT 0 , + "convid" bigint NOT NULL DEFAULT '0', "conv_guid" text NOT NULL, - "mail_flags" bigint NOT NULL DEFAULT 0 , + "mail_flags" bigint NOT NULL DEFAULT '0', "from_xchan" text NOT NULL DEFAULT '', "to_xchan" text NOT NULL DEFAULT '', - "account_id" bigint NOT NULL DEFAULT 0 , - "channel_id" bigint NOT NULL DEFAULT 0 , - "mail_mimetype" varchar(64) NOT NULL DEFAULT 'text/bbcode', + "account_id" bigint NOT NULL DEFAULT '0', + "channel_id" bigint NOT NULL DEFAULT '0', + "mail_mimetype" varchar(64) NOT NULL DEFAULT '0', "title" text NOT NULL, "body" text NOT NULL, "sig" text NOT NULL, "attach" text NOT NULL DEFAULT '', "mid" text NOT NULL, "parent_mid" text NOT NULL, - "mail_deleted" smallint NOT NULL DEFAULT 0 , - "mail_replied" smallint NOT NULL DEFAULT 0 , - "mail_isreply" smallint NOT NULL DEFAULT 0 , - "mail_seen" smallint NOT NULL DEFAULT 0 , - "mail_recalled" smallint NOT NULL DEFAULT 0 , - "mail_obscured" smallint NOT NULL DEFAULT 0 , - "mail_raw" smallint NOT NULL DEFAULT 0 , + "mail_deleted" smallint NOT NULL DEFAULT '0', + "mail_replied" smallint NOT NULL DEFAULT '0', + "mail_isreply" smallint NOT NULL DEFAULT '0', + "mail_seen" smallint NOT NULL DEFAULT '0', + "mail_recalled" smallint NOT NULL DEFAULT '0', + "mail_obscured" smallint NOT NULL DEFAULT '0', + "mail_raw" smallint NOT NULL DEFAULT '0', "created" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "expires" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', PRIMARY KEY ("id") @@ -790,10 +749,10 @@ create index "mail_recalled" on mail ("mail_recalled"); create index "mail_obscured" on mail ("mail_obscured"); CREATE TABLE "menu" ( "menu_id" serial NOT NULL, - "menu_channel_id" bigint NOT NULL DEFAULT 0 , + "menu_channel_id" bigint NOT NULL DEFAULT '0', "menu_name" text NOT NULL DEFAULT '', "menu_desc" text NOT NULL DEFAULT '', - "menu_flags" bigint NOT NULL DEFAULT 0 , + "menu_flags" bigint NOT NULL DEFAULT '0', "menu_created" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "menu_edited" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', PRIMARY KEY ("menu_id") @@ -807,14 +766,14 @@ CREATE TABLE "menu_item" ( "mitem_id" serial NOT NULL, "mitem_link" text NOT NULL DEFAULT '', "mitem_desc" text NOT NULL DEFAULT '', - "mitem_flags" bigint NOT NULL DEFAULT 0 , + "mitem_flags" bigint NOT NULL DEFAULT '0', "allow_cid" text NOT NULL, "allow_gid" text NOT NULL, "deny_cid" text NOT NULL, "deny_gid" text NOT NULL, "mitem_channel_id" bigint NOT NULL, - "mitem_menu_id" bigint NOT NULL DEFAULT 0 , - "mitem_order" bigint NOT NULL DEFAULT 0 , + "mitem_menu_id" bigint NOT NULL DEFAULT '0', + "mitem_order" bigint NOT NULL DEFAULT '0', PRIMARY KEY ("mitem_id") ); @@ -833,7 +792,7 @@ CREATE TABLE "notify" ( "uid" bigint NOT NULL, "link" text NOT NULL, "parent" text NOT NULL DEFAULT '', - "seen" numeric(1) NOT NULL DEFAULT 0 , + "seen" numeric(1) NOT NULL DEFAULT '0', "ntype" bigint NOT NULL, "verb" text NOT NULL, "otype" varchar(16) NOT NULL, @@ -882,18 +841,18 @@ create index "obj_quantity" on obj ("obj_quantity"); CREATE TABLE "outq" ( "outq_hash" text NOT NULL, - "outq_account" bigint NOT NULL DEFAULT 0 , - "outq_channel" bigint NOT NULL DEFAULT 0 , + "outq_account" bigint NOT NULL DEFAULT '0', + "outq_channel" bigint NOT NULL DEFAULT '0', "outq_driver" varchar(32) NOT NULL DEFAULT '', "outq_posturl" text NOT NULL DEFAULT '', - "outq_async" numeric(1) NOT NULL DEFAULT 0 , - "outq_delivered" numeric(1) NOT NULL DEFAULT 0 , + "outq_async" numeric(1) NOT NULL DEFAULT '0', + "outq_delivered" numeric(1) NOT NULL DEFAULT '0', "outq_created" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "outq_updated" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "outq_scheduled" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "outq_notify" text NOT NULL, "outq_msg" text NOT NULL, - "outq_priority" smallint NOT NULL DEFAULT 0 , + "outq_priority" smallint NOT NULL DEFAULT '0', PRIMARY KEY ("outq_hash") ); create index "outq_account" on outq ("outq_account"); @@ -908,7 +867,7 @@ create index "outq_priority" on outq ("outq_priority"); CREATE TABLE "pconfig" ( "id" serial NOT NULL, - "uid" bigint NOT NULL DEFAULT 0 , + "uid" bigint NOT NULL DEFAULT '0', "cat" text NOT NULL, "k" text NOT NULL, "v" text NOT NULL, @@ -918,7 +877,7 @@ CREATE TABLE "pconfig" ( CREATE TABLE "photo" ( "id" serial NOT NULL, - "aid" bigint NOT NULL DEFAULT 0 , + "aid" bigint NOT NULL DEFAULT '0', "uid" bigint NOT NULL, "xchan" text NOT NULL DEFAULT '', "resource_id" text NOT NULL, @@ -931,16 +890,16 @@ CREATE TABLE "photo" ( "mimetype" varchar(128) NOT NULL DEFAULT 'image/jpeg', "height" numeric(6) NOT NULL, "width" numeric(6) NOT NULL, - "filesize" bigint NOT NULL DEFAULT 0 , + "filesize" bigint NOT NULL DEFAULT '0', "content" bytea NOT NULL, - "imgscale" numeric(3) NOT NULL DEFAULT 0 , - "profile" numeric(1) NOT NULL DEFAULT 0 , - "photo_usage" smallint NOT NULL DEFAULT 0 , - "is_nsfw" smallint NOT NULL DEFAULT 0 , - "os_storage" smallint NOT NULL DEFAULT 0 , + "imgscale" numeric(3) NOT NULL DEFAULT '0', + "profile" numeric(1) NOT NULL DEFAULT '0', + "photo_usage" smallint NOT NULL DEFAULT '0', + "is_nsfw" smallint NOT NULL DEFAULT '0', + "os_storage" smallint NOT NULL DEFAULT '0', "os_path" text NOT NULL, "display_path" text NOT NULL, - "photo_flags" bigint NOT NULL DEFAULT 0 , + "photo_flags" bigint NOT NULL DEFAULT '0', "allow_cid" text NOT NULL, "allow_gid" text NOT NULL, "deny_cid" text NOT NULL, @@ -963,10 +922,10 @@ create index "photo_os_storage" on photo ("os_storage"); CREATE TABLE "poll" ( "poll_id" serial NOT NULL, - "poll_channel" bigint NOT NULL DEFAULT 0 , + "poll_channel" bigint NOT NULL DEFAULT '0', "poll_desc" text NOT NULL, - "poll_flags" bigint NOT NULL DEFAULT 0 , - "poll_votes" bigint NOT NULL DEFAULT 0 , + "poll_flags" bigint NOT NULL DEFAULT '0', + "poll_votes" bigint NOT NULL DEFAULT '0', PRIMARY KEY ("poll_id") ); @@ -975,10 +934,10 @@ create index "poll_flags" on poll ("poll_flags"); create index "poll_votes" on poll ("poll_votes"); CREATE TABLE "poll_elm" ( "pelm_id" serial NOT NULL, - "pelm_poll" bigint NOT NULL DEFAULT 0 , + "pelm_poll" bigint NOT NULL DEFAULT '0', "pelm_desc" text NOT NULL, - "pelm_flags" bigint NOT NULL DEFAULT 0 , - "pelm_result" float NOT NULL DEFAULT 0 , + "pelm_flags" bigint NOT NULL DEFAULT '0', + "pelm_result" float NOT NULL DEFAULT '0', PRIMARY KEY ("pelm_id") ); create index "pelm_poll" on poll_elm ("pelm_poll"); @@ -996,7 +955,7 @@ CREATE TABLE "profdef" ( create index "profdef_field_name" on profdef ("field_name"); CREATE TABLE "profext" ( "id" serial NOT NULL, - "channel_id" bigint NOT NULL DEFAULT 0 , + "channel_id" bigint NOT NULL DEFAULT '0', "hash" text NOT NULL DEFAULT '', "k" text NOT NULL DEFAULT '', "v" text NOT NULL, @@ -1009,11 +968,11 @@ create index "profext_k" on profext ("k"); CREATE TABLE "profile" ( "id" serial NOT NULL, "profile_guid" varchar(64) NOT NULL DEFAULT '', - "aid" bigint NOT NULL DEFAULT 0 , + "aid" bigint NOT NULL DEFAULT '0', "uid" bigint NOT NULL, "profile_name" text NOT NULL, - "is_default" numeric(1) NOT NULL DEFAULT 0 , - "hide_friends" numeric(1) NOT NULL DEFAULT 0 , + "is_default" numeric(1) NOT NULL DEFAULT '0', + "hide_friends" numeric(1) NOT NULL DEFAULT '0', "fullname" text NOT NULL, "pdesc" text NOT NULL DEFAULT '', "chandesc" text NOT NULL DEFAULT '', @@ -1050,7 +1009,7 @@ CREATE TABLE "profile" ( "homepage" text NOT NULL DEFAULT '', "photo" text NOT NULL, "thumb" text NOT NULL, - "publish" numeric(1) NOT NULL DEFAULT 0 , + "publish" numeric(1) NOT NULL DEFAULT '0', "profile_vcard" text NOT NULL DEFAULT '', PRIMARY KEY ("id"), UNIQUE ("profile_guid","uid") @@ -1072,7 +1031,7 @@ create index "profile_guid" on profile ("profile_guid"); CREATE TABLE "profile_check" ( "id" serial NOT NULL, "uid" bigint NOT NULL, - "cid" bigint NOT NULL DEFAULT 0 , + "cid" bigint NOT NULL DEFAULT '0', "dfrn_id" text NOT NULL, "sec" text NOT NULL, "expire" bigint NOT NULL, @@ -1107,8 +1066,8 @@ create index "session_sid" on session ("sid"); create index "session_expire" on session ("expire"); CREATE TABLE "shares" ( "share_id" serial NOT NULL, - "share_type" bigint NOT NULL DEFAULT 0 , - "share_target" bigint NOT NULL DEFAULT 0 , + "share_type" bigint NOT NULL DEFAULT '0', + "share_target" bigint NOT NULL DEFAULT '0', "share_xchan" text NOT NULL DEFAULT '', PRIMARY KEY ("share_id") ); @@ -1118,8 +1077,8 @@ create index "share_xchan" on shares ("share_xchan"); CREATE TABLE "sign" ( "id" serial NOT NULL, - "iid" bigint NOT NULL DEFAULT 0 , - "retract_iid" bigint NOT NULL DEFAULT 0 , + "iid" bigint NOT NULL DEFAULT '0', + "retract_iid" bigint NOT NULL DEFAULT '0', "signed_text" text NOT NULL, "signature" text NOT NULL, "signer" text NOT NULL, @@ -1130,19 +1089,19 @@ create index "sign_retract_iid" on "sign" ("retract_iid"); CREATE TABLE "site" ( "site_url" text NOT NULL, - "site_access" bigint NOT NULL DEFAULT 0 , - "site_flags" bigint NOT NULL DEFAULT 0 , + "site_access" bigint NOT NULL DEFAULT '0', + "site_flags" bigint NOT NULL DEFAULT '0', "site_update" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "site_pull" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "site_sync" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "site_directory" text NOT NULL DEFAULT '', - "site_register" bigint NOT NULL DEFAULT 0 , + "site_register" bigint NOT NULL DEFAULT '0', "site_sellpage" text NOT NULL DEFAULT '', "site_location" text NOT NULL DEFAULT '', "site_realm" text NOT NULL DEFAULT '', - "site_valid" smallint NOT NULL DEFAULT 0 , - "site_dead" smallint NOT NULL DEFAULT 0 , - "site_type" smallint NOT NULL DEFAULT 0 , + "site_valid" smallint NOT NULL DEFAULT '0', + "site_dead" smallint NOT NULL DEFAULT '0', + "site_type" smallint NOT NULL DEFAULT '0', "site_project" text NOT NULL DEFAULT '', "site_version" text NOT NULL DEFAULT '', "site_crypto" text NOT NULL DEFAULT '', @@ -1162,7 +1121,7 @@ create index "site_project" on site ("site_project"); CREATE TABLE "source" ( "src_id" serial NOT NULL, - "src_channel_id" bigint NOT NULL DEFAULT 0 , + "src_channel_id" bigint NOT NULL DEFAULT '0', "src_channel_xchan" text NOT NULL DEFAULT '', "src_xchan" text NOT NULL DEFAULT '', "src_patt" text NOT NULL DEFAULT '', @@ -1182,8 +1141,8 @@ CREATE TABLE "sys_perms" ( ); CREATE TABLE "term" ( "tid" serial NOT NULL, - "aid" bigint NOT NULL DEFAULT 0 , - "uid" bigint NOT NULL DEFAULT 0 , + "aid" bigint NOT NULL DEFAULT '0', + "uid" bigint NOT NULL DEFAULT '0', "oid" bigint NOT NULL, "otype" numeric(3) NOT NULL, "ttype" numeric(3) NOT NULL, @@ -1222,7 +1181,7 @@ CREATE TABLE "updates" ( "ud_guid" text NOT NULL DEFAULT '', "ud_date" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "ud_last" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', - "ud_flags" bigint NOT NULL DEFAULT 0 , + "ud_flags" bigint NOT NULL DEFAULT '0', "ud_addr" text NOT NULL DEFAULT '', PRIMARY KEY ("ud_id") ); @@ -1234,7 +1193,7 @@ create index "ud_addr" on updates ("ud_addr"); create index "ud_last" on updates ("ud_last"); CREATE TABLE "verify" ( "id" serial NOT NULL, - "channel" bigint NOT NULL DEFAULT 0 , + "channel" bigint NOT NULL DEFAULT '0', "vtype" varchar(32) NOT NULL DEFAULT '', "token" text NOT NULL DEFAULT '', "meta" text NOT NULL DEFAULT '', @@ -1248,8 +1207,8 @@ create index "verify_meta" on verify ("meta"); create index "verify_created" on verify ("created"); CREATE TABLE "vote" ( "vote_id" serial NOT NULL, - "vote_poll" bigint NOT NULL DEFAULT 0 , - "vote_element" bigint NOT NULL DEFAULT 0 , + "vote_poll" bigint NOT NULL DEFAULT '0', + "vote_element" bigint NOT NULL DEFAULT '0', "vote_result" text NOT NULL, "vote_xchan" text NOT NULL DEFAULT '', PRIMARY KEY ("vote_id"), @@ -1274,16 +1233,16 @@ CREATE TABLE "xchan" ( "xchan_name" text NOT NULL DEFAULT '', "xchan_network" text NOT NULL DEFAULT '', "xchan_instance_url" text NOT NULL DEFAULT '', - "xchan_flags" bigint NOT NULL DEFAULT 0 , + "xchan_flags" bigint NOT NULL DEFAULT '0', "xchan_photo_date" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', "xchan_name_date" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', - "xchan_hidden" smallint NOT NULL DEFAULT 0 , - "xchan_orphan" smallint NOT NULL DEFAULT 0 , - "xchan_censored" smallint NOT NULL DEFAULT 0 , - "xchan_selfcensored" smallint NOT NULL DEFAULT 0 , - "xchan_system" smallint NOT NULL DEFAULT 0 , - "xchan_pubforum" smallint NOT NULL DEFAULT 0 , - "xchan_deleted" smallint NOT NULL DEFAULT 0 , + "xchan_hidden" smallint NOT NULL DEFAULT '0', + "xchan_orphan" smallint NOT NULL DEFAULT '0', + "xchan_censored" smallint NOT NULL DEFAULT '0', + "xchan_selfcensored" smallint NOT NULL DEFAULT '0', + "xchan_system" smallint NOT NULL DEFAULT '0', + "xchan_pubforum" smallint NOT NULL DEFAULT '0', + "xchan_deleted" smallint NOT NULL DEFAULT '0', PRIMARY KEY ("xchan_hash") ); create index "xchan_guid" on xchan ("xchan_guid"); @@ -1328,7 +1287,7 @@ create index "xconfig_cat" on xconfig ("cat"); create index "xconfig_k" on xconfig ("k"); CREATE TABLE "xign" ( "id" serial NOT NULL, - "uid" bigint NOT NULL DEFAULT 0 , + "uid" bigint NOT NULL DEFAULT '0', "xchan" text NOT NULL DEFAULT '', PRIMARY KEY ("id") ); @@ -1338,10 +1297,10 @@ CREATE TABLE "xlink" ( "xlink_id" serial NOT NULL, "xlink_xchan" text NOT NULL DEFAULT '', "xlink_link" text NOT NULL DEFAULT '', - "xlink_rating" bigint NOT NULL DEFAULT 0 , + "xlink_rating" bigint NOT NULL DEFAULT '0', "xlink_rating_text" TEXT NOT NULL DEFAULT '', "xlink_updated" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', - "xlink_static" numeric(1) NOT NULL DEFAULT 0 , + "xlink_static" numeric(1) NOT NULL DEFAULT '0', "xlink_sig" text NOT NULL DEFAULT '', PRIMARY KEY ("xlink_id") ); @@ -1353,7 +1312,7 @@ create index "xlink_static" on xlink ("xlink_static"); CREATE TABLE "xperm" ( "xp_id" serial NOT NULL, "xp_client" varchar( 20 ) NOT NULL DEFAULT '', - "xp_channel" bigint NOT NULL DEFAULT 0 , + "xp_channel" bigint NOT NULL DEFAULT '0', "xp_perm" varchar( 64 ) NOT NULL DEFAULT '', PRIMARY KEY ("xp_id") ); @@ -1362,7 +1321,7 @@ create index "xp_channel" on xperm ("xp_channel"); create index "xp_perm" on xperm ("xp_perm"); CREATE TABLE "xprof" ( "xprof_hash" text NOT NULL, - "xprof_age" numeric(3) NOT NULL DEFAULT 0 , + "xprof_age" numeric(3) NOT NULL DEFAULT '0', "xprof_desc" text NOT NULL DEFAULT '', "xprof_dob" varchar(12) NOT NULL DEFAULT '', "xprof_gender" text NOT NULL DEFAULT '', @@ -1393,7 +1352,7 @@ CREATE TABLE "xtag" ( "xtag_id" serial NOT NULL, "xtag_hash" text NOT NULL, "xtag_term" text NOT NULL DEFAULT '', - "xtag_flags" bigint NOT NULL DEFAULT 0 , + "xtag_flags" bigint NOT NULL DEFAULT '0', PRIMARY KEY ("xtag_id") ); create index "xtag_term" on xtag ("xtag_term"); diff --git a/library/blueimp_upload/.gitignore b/library/blueimp_upload/.gitignore deleted file mode 100644 index 29a41a8c4..000000000 --- a/library/blueimp_upload/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.DS_Store -*.pyc -node_modules diff --git a/library/blueimp_upload/.jshintrc b/library/blueimp_upload/.jshintrc deleted file mode 100644 index 4ad82e664..000000000 --- a/library/blueimp_upload/.jshintrc +++ /dev/null @@ -1,81 +0,0 @@ -{ - "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.) - "camelcase" : true, // true: Identifiers must be in camelCase - "curly" : true, // true: Require {} for every new block or scope - "eqeqeq" : true, // true: Require triple equals (===) for comparison - "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty() - "immed" : true, // true: Require immediate invocations to be wrapped in parens - // e.g. `(function () { } ());` - "indent" : 4, // {int} Number of spaces to use for indentation - "latedef" : true, // true: Require variables/functions to be defined before being used - "newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()` - "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` - "noempty" : true, // true: Prohibit use of empty blocks - "nonew" : true, // true: Prohibit use of constructors for side-effects (without assignment) - "plusplus" : false, // true: Prohibit use of `++` & `--` - "quotmark" : "single", // Quotation mark consistency: - // false : do nothing (default) - // true : ensure whatever is used is consistent - // "single" : require single quotes - // "double" : require double quotes - "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) - "unused" : true, // true: Require all defined variables be used - "strict" : true, // true: Requires all functions run in ES5 Strict Mode - "trailing" : true, // true: Prohibit trailing whitespaces - "maxparams" : false, // {int} Max number of formal params allowed per function - "maxdepth" : false, // {int} Max depth of nested blocks (within functions) - "maxstatements" : false, // {int} Max number statements per function - "maxcomplexity" : false, // {int} Max cyclomatic complexity per function - "maxlen" : false, // {int} Max number of characters per line - - // Relaxing - "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) - "boss" : false, // true: Tolerate assignments where comparisons would be expected - "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. - "eqnull" : false, // true: Tolerate use of `== null` - "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) - "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`) - "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) - // (ex: `for each`, multiple try/catch, function expression…) - "evil" : false, // true: Tolerate use of `eval` and `new Function()` - "expr" : false, // true: Tolerate `ExpressionStatement` as Programs - "funcscope" : false, // true: Tolerate defining variables inside control statements" - "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict') - "iterator" : false, // true: Tolerate using the `__iterator__` property - "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block - "laxbreak" : false, // true: Tolerate possibly unsafe line breakings - "laxcomma" : false, // true: Tolerate comma-first style coding - "loopfunc" : false, // true: Tolerate functions being defined in loops - "multistr" : false, // true: Tolerate multi-line strings - "proto" : false, // true: Tolerate using the `__proto__` property - "scripturl" : false, // true: Tolerate script-targeted URLs - "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment - "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` - "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation - "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` - "validthis" : false, // true: Tolerate using this in a non-constructor function - - // Environments - "browser" : false, // Web Browser (window, document, etc) - "couch" : false, // CouchDB - "devel" : false, // Development/debugging (alert, confirm, etc) - "dojo" : false, // Dojo Toolkit - "jquery" : false, // jQuery - "mootools" : false, // MooTools - "node" : false, // Node.js - "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) - "prototypejs" : false, // Prototype and Scriptaculous - "rhino" : false, // Rhino - "worker" : false, // Web Workers - "wsh" : false, // Windows Scripting Host - "yui" : false, // Yahoo User Interface - - // Legacy - "nomen" : true, // true: Prohibit dangling `_` in variables - "onevar" : true, // true: Allow only one `var` statement per function - "passfail" : false, // true: Stop on first error - "white" : true, // true: Check against strict whitespace and indentation rules - - // Custom Globals - "globals" : {} // additional predefined global variables -} diff --git a/library/blueimp_upload/CONTRIBUTING.md b/library/blueimp_upload/CONTRIBUTING.md index b8708f8b6..e182f9b37 100644 --- a/library/blueimp_upload/CONTRIBUTING.md +++ b/library/blueimp_upload/CONTRIBUTING.md @@ -1,42 +1,15 @@ -# Issue Guidelines +Please follow these pull request guidelines: -The issues tracker should only be used for **bugs** or **feature requests**. - -Please post **support requests** and **general discussions** about this project to the [support forum](https://groups.google.com/d/forum/jquery-fileupload). - -## Bugs - -Please follow these guidelines before reporting a bug: - -1. **Update to the latest version** — Check if you can reproduce the issue with the latest version from the `master` branch. - -2. **Use the GitHub issue search** — check if the issue has already been reported. If it has been, please comment on the existing issue. - -3. **Isolate the demonstrable problem** — Try to reproduce the problem with the [Demo](https://blueimp.github.io/jQuery-File-Upload/) or with a reduced test case that includes the least amount of code necessary to reproduce the problem. - -4. **Provide a means to reproduce the problem** — Please provide as much details as possible, e.g. server information, browser and operating system versions, steps to reproduce the problem. If possible, provide a link to your reduced test case, e.g. via [JSFiddle](http://jsfiddle.net/). - - -## Feature requests - -Please follow the bug guidelines above for feature requests, i.e. update to the latest version and search for exising issues before posting a new request. - -Generally, feature requests might be accepted if the implementation would benefit a broader use case or the project could be considered incomplete without that feature. - -If you need help integrating this project into another framework, please post your request to the [support forum](https://groups.google.com/d/forum/jquery-fileupload). - -## Pull requests - -[Pull requests](https://help.github.com/articles/using-pull-requests) are welcome and the preferred way of accepting code contributions. +1. Update your fork to the latest upstream version. -However, if you add a server-side upload handler implementation for another framework, please continue to maintain this version in your own fork without sending a pull request. You are welcome to add a link and possibly documentation about your implementation to the [Wiki](https://github.com/blueimp/jQuery-File-Upload/wiki). +2. Follow the coding conventions of the original source files (indentation, spaces, brackets layout). -Please follow these guidelines before sending a pull request: +3. Code changes must pass JSHint validation with the `.jshintrc` settings of this project. -1. Update your fork to the latest upstream version. +4. Code changes must pass the QUnit tests defined in the `test` folder. -2. Follow the coding conventions of the original repository. Changes to one of the JavaScript source files are required to pass the [JSHint](http://www.jshint.com/) validation tool. +5. New features should be covered by accompanying QUnit tests. -3. Keep your commits as atomar as possible, i.e. create a new commit for every single bug fix or feature added. +6. Keep your commits as atomic as possible, i.e. create a new commit for every single bug fix or feature added. -4. Always add meaningfull commit messages. +7. Always add meaningful commit messages. diff --git a/library/blueimp_upload/Gruntfile.js b/library/blueimp_upload/Gruntfile.js deleted file mode 100644 index dcdb5d57a..000000000 --- a/library/blueimp_upload/Gruntfile.js +++ /dev/null @@ -1,37 +0,0 @@ -/* - * jQuery File Upload Gruntfile - * https://github.com/blueimp/jQuery-File-Upload - * - * Copyright 2013, Sebastian Tschan - * https://blueimp.net - * - * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT - */ - -/*global module */ - -module.exports = function (grunt) { - 'use strict'; - - grunt.initConfig({ - jshint: { - options: { - jshintrc: '.jshintrc' - }, - all: [ - 'Gruntfile.js', - 'js/cors/*.js', - 'js/*.js', - 'server/node/server.js', - 'test/test.js' - ] - } - }); - - grunt.loadNpmTasks('grunt-contrib-jshint'); - grunt.loadNpmTasks('grunt-bump-build-git'); - grunt.registerTask('test', ['jshint']); - grunt.registerTask('default', ['test']); - -}; diff --git a/library/blueimp_upload/LICENSE b/library/blueimp_upload/LICENSE new file mode 100644 index 000000000..0ecca3e8c --- /dev/null +++ b/library/blueimp_upload/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 jQuery-File-Upload Authors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/library/blueimp_upload/README.md b/library/blueimp_upload/README.md index 3aa33de42..56785b847 100644 --- a/library/blueimp_upload/README.md +++ b/library/blueimp_upload/README.md @@ -11,17 +11,6 @@ Supports cross-domain, chunked and resumable file uploads and client-side image * [How to setup the plugin on your website](https://github.com/blueimp/jQuery-File-Upload/wiki/Setup) * [How to use only the basic plugin (minimal setup guide).](https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin) -## Support - -* **[Support Forum](https://groups.google.com/d/forum/jquery-fileupload)** -**Support requests** and **general discussions** about the File Upload plugin can be posted to the official -[Support Forum](https://groups.google.com/d/forum/jquery-fileupload). -If your question is not directly related to the File Upload plugin, you might have a better chance to get a reply by posting to [Stack Overflow](http://stackoverflow.com/questions/tagged/blueimp+jquery+file-upload). - -* Bugs and Feature requests -**Bugs** and **Feature requests** can be reported using the [issues tracker](https://github.com/blueimp/jQuery-File-Upload/issues). -Please read the [issue guidelines](https://github.com/blueimp/jQuery-File-Upload/blob/master/CONTRIBUTING.md) before posting. - ## Features * **Multiple file upload:** Allows to select multiple files at once and upload them simultaneously. @@ -60,28 +49,18 @@ Please read the [issue guidelines](https://github.com/blueimp/jQuery-File-Upload ### Mandatory requirements * [jQuery](https://jquery.com/) v. 1.6+ -* [jQuery UI widget factory](https://api.jqueryui.com/jQuery.widget/) v. 1.9+ (included) -* [jQuery Iframe Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.iframe-transport.js) (included) - -The jQuery UI widget factory is a requirement for the basic File Upload plugin, but very lightweight without any other dependencies from the jQuery UI suite. - -The jQuery Iframe Transport is required for [browsers without XHR file upload support](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support). +* [jQuery UI widget factory](https://api.jqueryui.com/jQuery.widget/) v. 1.9+ (included): Required for the basic File Upload plugin, but very lightweight without any other dependencies from the jQuery UI suite. +* [jQuery Iframe Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.iframe-transport.js) (included): Required for [browsers without XHR file upload support](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support). ### Optional requirements -* [JavaScript Templates engine](https://github.com/blueimp/JavaScript-Templates) v. 2.5.4+ -* [JavaScript Load Image library](https://github.com/blueimp/JavaScript-Load-Image) v. 1.13.0+ -* [JavaScript Canvas to Blob polyfill](https://github.com/blueimp/JavaScript-Canvas-to-Blob) v. 2.1.1+ -* [blueimp Gallery](https://github.com/blueimp/Gallery) v. 2.15.1+ -* [Bootstrap CSS framework](http://getbootstrap.com/) v. 3.2.0+ +* [JavaScript Templates engine](https://github.com/blueimp/JavaScript-Templates) v. 2.5.4+: Used to render the selected and uploaded files for the Basic Plus UI and jQuery UI versions. +* [JavaScript Load Image library](https://github.com/blueimp/JavaScript-Load-Image) v. 1.13.0+: Required for the image previews and resizing functionality. +* [JavaScript Canvas to Blob polyfill](https://github.com/blueimp/JavaScript-Canvas-to-Blob) v. 2.1.1+:Required for the image previews and resizing functionality. +* [blueimp Gallery](https://github.com/blueimp/Gallery) v. 2.15.1+: Used to display the uploaded images in a lightbox. +* [Bootstrap](http://getbootstrap.com/) v. 3.2.0+ * [Glyphicons](http://glyphicons.com/) -The JavaScript Templates engine is used to render the selected and uploaded files for the Basic Plus UI and jQuery UI versions. - -The JavaScript Load Image library and JavaScript Canvas to Blob polyfill are required for the image previews and resizing functionality. - -The blueimp Gallery is used to display the uploaded images in a lightbox. - -The user interface of all versions except the jQuery UI version is built with Twitter's [Bootstrap](http://getbootstrap.com/) framework and icons from [Glyphicons](http://glyphicons.com/). +The user interface of all versions except the jQuery UI version is built with [Bootstrap](http://getbootstrap.com/) and icons from [Glyphicons](http://glyphicons.com/). ### Cross-domain requirements [Cross-domain File Uploads](https://github.com/blueimp/jQuery-File-Upload/wiki/Cross-domain-uploads) using the [Iframe Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.iframe-transport.js) require a redirect back to the origin server to retrieve the upload results. The [example implementation](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/main.js) makes use of [result.html](https://github.com/blueimp/jQuery-File-Upload/blob/master/cors/result.html) as a static redirect page for the origin server. @@ -89,6 +68,10 @@ The user interface of all versions except the jQuery UI version is built with Tw The repository also includes the [jQuery XDomainRequest Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/cors/jquery.xdr-transport.js), which enables limited cross-domain AJAX requests in Microsoft Internet Explorer 8 and 9 (IE 10 supports cross-domain XHR requests). The XDomainRequest object allows GET and POST requests only and doesn't support file uploads. It is used on the [Demo](https://blueimp.github.io/jQuery-File-Upload/) to delete uploaded files from the cross-domain demo file upload service. +### Custom Backends + +You can add support for various backends by adhering to the specification [outlined here](https://github.com/blueimp/jQuery-File-Upload/wiki/JSON-Response). + ## Browsers ### Desktop browsers @@ -110,14 +93,15 @@ The File Upload plugin has been tested with and supports the following mobile br * Opera Mobile 12.0+ ### Supported features -For a detailed overview of the features supported by each browser version please have a look at the [Extended browser support information](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support). +For a detailed overview of the features supported by each browser version, please have a look at the [Extended browser support information](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support). -## License -Released under the [MIT license](http://www.opensource.org/licenses/MIT). +## Contributing +**Bug fixes** and **new features** can be proposed using [pull requests](https://github.com/blueimp/jQuery-File-Upload/pulls). +Please read the [contribution guidelines](https://github.com/blueimp/jQuery-File-Upload/blob/master/CONTRIBUTING.md) before submitting a pull request. -## Donations -jQuery File Upload is free software, but you can donate to support the developer, Sebastian Tschan: - -Flattr: [![Flattr](https://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/thing/286433/jQuery-File-Upload-Plugin) +## Support +This project is actively maintained, but there is no official support channel. +If you have a question that another developer might help you with, please post to [Stack Overflow](http://stackoverflow.com/questions/tagged/blueimp+jquery+file-upload) and tag your question with `blueimp jquery file upload`. -PayPal: [![PayPal](https://www.paypalobjects.com/WEBSCR-640-20110429-1/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=PYWYSYP77KL54) +## License +Released under the [MIT license](https://opensource.org/licenses/MIT). diff --git a/library/blueimp_upload/angularjs.html b/library/blueimp_upload/angularjs.html index 2a3ca2007..4858c8600 100644 --- a/library/blueimp_upload/angularjs.html +++ b/library/blueimp_upload/angularjs.html @@ -1,14 +1,14 @@ <!DOCTYPE HTML> <!-- /* - * jQuery File Upload Plugin AngularJS Demo 2.2.0 + * jQuery File Upload Plugin AngularJS Demo * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ --> <html lang="en"> @@ -157,9 +157,9 @@ </div> <div class="panel-body"> <ul> - <li>The maximum file size for uploads in this demo is <strong>5 MB</strong> (default file size is unlimited).</li> + <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li> <li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li> - <li>Uploaded files will be deleted automatically after <strong>5 minutes</strong> (demo setting).</li> + <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li> <li>You can <strong>drag & drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li> <li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li> <li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li> @@ -177,8 +177,8 @@ <a class="play-pause"></a> <ol class="indicator"></ol> </div> -<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> -<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> +<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> +<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script> <!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included --> <script src="js/vendor/jquery.ui.widget.js"></script> <!-- The Load Image plugin is included for the preview images and image resizing functionality --> @@ -207,5 +207,5 @@ <script src="js/jquery.fileupload-angular.js"></script> <!-- The main application script --> <script src="js/app.js"></script> -</body> +</body> </html> diff --git a/library/blueimp_upload/basic-plus.html b/library/blueimp_upload/basic-plus.html index 59b73b60c..9e5c2321f 100644 --- a/library/blueimp_upload/basic-plus.html +++ b/library/blueimp_upload/basic-plus.html @@ -1,14 +1,14 @@ <!DOCTYPE HTML> <!-- /* - * jQuery File Upload Plugin Basic Plus Demo 1.4.0 + * jQuery File Upload Plugin Basic Plus Demo * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ --> <html lang="en"> @@ -86,9 +86,9 @@ </div> <div class="panel-body"> <ul> - <li>The maximum file size for uploads in this demo is <strong>5 MB</strong> (default file size is unlimited).</li> + <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li> <li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li> - <li>Uploaded files will be deleted automatically after <strong>5 minutes</strong> (demo setting).</li> + <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li> <li>You can <strong>drag & drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li> <li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li> <li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li> @@ -96,7 +96,7 @@ </div> </div> </div> -<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> +<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included --> <script src="js/vendor/jquery.ui.widget.js"></script> <!-- The Load Image plugin is included for the preview images and image resizing functionality --> @@ -150,7 +150,7 @@ $(function () { dataType: 'json', autoUpload: false, acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i, - maxFileSize: 5000000, // 5 MB + maxFileSize: 999000, // Enable image resizing, except for Android and Opera, // which actually support image resizing, but fail to // send Blob objects via XHR requests: @@ -222,5 +222,5 @@ $(function () { .parent().addClass($.support.fileInput ? undefined : 'disabled'); }); </script> -</body> +</body> </html> diff --git a/library/blueimp_upload/basic.html b/library/blueimp_upload/basic.html index f248f4d80..c0df639b4 100644 --- a/library/blueimp_upload/basic.html +++ b/library/blueimp_upload/basic.html @@ -1,14 +1,14 @@ <!DOCTYPE HTML> <!-- /* - * jQuery File Upload Plugin Basic Demo 1.3.0 + * jQuery File Upload Plugin Basic Demo * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ --> <html lang="en"> @@ -86,17 +86,17 @@ </div> <div class="panel-body"> <ul> - <li>The maximum file size for uploads in this demo is <strong>5 MB</strong> (default file size is unlimited).</li> + <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li> <li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li> - <li>Uploaded files will be deleted automatically after <strong>5 minutes</strong> (demo setting).</li> + <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li> <li>You can <strong>drag & drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li> <li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li> - <li>Built with Twitter's <a href="http://twitter.github.com/bootstrap/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li> + <li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li> </ul> </div> </div> </div> -<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> +<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included --> <script src="js/vendor/jquery.ui.widget.js"></script> <!-- The Iframe Transport is required for browsers without support for XHR file uploads --> @@ -132,5 +132,5 @@ $(function () { .parent().addClass($.support.fileInput ? undefined : 'disabled'); }); </script> -</body> +</body> </html> diff --git a/library/blueimp_upload/blueimp-file-upload.jquery.json b/library/blueimp_upload/blueimp-file-upload.jquery.json deleted file mode 100644 index d6d8c911c..000000000 --- a/library/blueimp_upload/blueimp-file-upload.jquery.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "name": "blueimp-file-upload", - "version": "9.8.0", - "title": "jQuery File Upload", - "author": { - "name": "Sebastian Tschan", - "url": "https://blueimp.net" - }, - "licenses": [ - { - "type": "MIT", - "url": "http://www.opensource.org/licenses/MIT" - } - ], - "dependencies": { - "jquery": ">=1.6" - }, - "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.", - "keywords": [ - "jquery", - "file", - "upload", - "widget", - "multiple", - "selection", - "drag", - "drop", - "progress", - "preview", - "cross-domain", - "cross-site", - "chunk", - "resume", - "gae", - "go", - "python", - "php", - "bootstrap" - ], - "homepage": "https://github.com/blueimp/jQuery-File-Upload", - "docs": "https://github.com/blueimp/jQuery-File-Upload/wiki", - "demo": "https://blueimp.github.io/jQuery-File-Upload/", - "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues", - "maintainers": [ - { - "name": "Sebastian Tschan", - "url": "https://blueimp.net" - } - ] -} diff --git a/library/blueimp_upload/bower-version-update.js b/library/blueimp_upload/bower-version-update.js new file mode 100755 index 000000000..09ce3927e --- /dev/null +++ b/library/blueimp_upload/bower-version-update.js @@ -0,0 +1,16 @@ +#!/usr/bin/env node + +'use strict'; + +var path = require('path'); +var packageJSON = require(path.join(__dirname, 'package.json')); +var bowerFile = path.join(__dirname, 'bower.json'); +var bowerJSON = require('bower-json').parse( + require(bowerFile), + {normalize: true} +); +bowerJSON.version = packageJSON.version; +require('fs').writeFileSync( + bowerFile, + JSON.stringify(bowerJSON, null, 2) + '\n' +); diff --git a/library/blueimp_upload/bower.json b/library/blueimp_upload/bower.json index c0d3d3259..90c74c792 100644 --- a/library/blueimp_upload/bower.json +++ b/library/blueimp_upload/bower.json @@ -1,8 +1,8 @@ { "name": "blueimp-file-upload", - "version": "9.8.0", + "version": "9.18.0", "title": "jQuery File Upload", - "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.", + "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images.", "keywords": [ "jquery", "file", @@ -40,12 +40,7 @@ "url": "git://github.com/blueimp/jQuery-File-Upload.git" }, "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues", - "licenses": [ - { - "type": "MIT", - "url": "http://www.opensource.org/licenses/MIT" - } - ], + "license": "MIT", "dependencies": { "jquery": ">=1.6", "blueimp-tmpl": ">=2.5.4", @@ -53,23 +48,7 @@ "blueimp-canvas-to-blob": ">=2.1.1" }, "main": [ - "css/jquery.fileupload.css", - "css/jquery.fileupload-ui.css", - "css/jquery.fileupload-noscript.css", - "css/jquery.fileupload-ui-noscript.css", - "js/cors/jquery.postmessage-transport.js", - "js/cors/jquery.xdr-transport.js", - "js/vendor/jquery.ui.widget.js", - "js/jquery.fileupload.js", - "js/jquery.fileupload-process.js", - "js/jquery.fileupload-validate.js", - "js/jquery.fileupload-image.js", - "js/jquery.fileupload-audio.js", - "js/jquery.fileupload-video.js", - "js/jquery.fileupload-ui.js", - "js/jquery.fileupload-jquery-ui.js", - "js/jquery.fileupload-angular.js", - "js/jquery.iframe-transport.js" + "js/jquery.fileupload.js" ], "ignore": [ "/*.*", diff --git a/library/blueimp_upload/cors/postmessage.html b/library/blueimp_upload/cors/postmessage.html index 3d1448f08..6db288cf9 100644 --- a/library/blueimp_upload/cors/postmessage.html +++ b/library/blueimp_upload/cors/postmessage.html @@ -1,14 +1,14 @@ <!DOCTYPE HTML> <!-- /* - * jQuery File Upload Plugin postMessage API 1.2.1 + * jQuery File Upload Plugin postMessage API * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ --> <html lang="en"> @@ -72,4 +72,4 @@ $(window).on('message', function (e) { }); </script> </body> -</html>
\ No newline at end of file +</html> diff --git a/library/blueimp_upload/cors/result.html b/library/blueimp_upload/cors/result.html index 225131495..e3d629814 100644 --- a/library/blueimp_upload/cors/result.html +++ b/library/blueimp_upload/cors/result.html @@ -1,14 +1,14 @@ <!DOCTYPE HTML> <!-- /* - * jQuery Iframe Transport Plugin Redirect Page 2.0.1 + * jQuery Iframe Transport Plugin Redirect Page * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ --> <html lang="en"> diff --git a/library/blueimp_upload/css/demo-ie8.css b/library/blueimp_upload/css/demo-ie8.css index 262493d08..e0e8ea9b0 100644 --- a/library/blueimp_upload/css/demo-ie8.css +++ b/library/blueimp_upload/css/demo-ie8.css @@ -1,13 +1,13 @@ @charset "UTF-8"; /* - * jQuery File Upload Demo CSS Fixes for IE<9 1.0.0 + * jQuery File Upload Demo CSS Fixes for IE<9 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ .navigation { diff --git a/library/blueimp_upload/css/demo.css b/library/blueimp_upload/css/demo.css index 2b4d43934..d7d524df5 100644 --- a/library/blueimp_upload/css/demo.css +++ b/library/blueimp_upload/css/demo.css @@ -1,13 +1,13 @@ @charset "UTF-8"; /* - * jQuery File Upload Demo CSS 1.1.0 + * jQuery File Upload Demo CSS * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ body { diff --git a/library/blueimp_upload/css/jquery.fileupload-noscript.css b/library/blueimp_upload/css/jquery.fileupload-noscript.css index 64d728fc3..2409bfb0a 100644 --- a/library/blueimp_upload/css/jquery.fileupload-noscript.css +++ b/library/blueimp_upload/css/jquery.fileupload-noscript.css @@ -1,20 +1,20 @@ @charset "UTF-8"; /* - * jQuery File Upload Plugin NoScript CSS 1.2.0 + * jQuery File Upload Plugin NoScript CSS * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ .fileinput-button input { position: static; opacity: 1; filter: none; - font-size: inherit; + font-size: inherit !important; direction: inherit; } .fileinput-button span { diff --git a/library/blueimp_upload/css/jquery.fileupload-ui-noscript.css b/library/blueimp_upload/css/jquery.fileupload-ui-noscript.css index 87f110cdb..30651acf0 100644 --- a/library/blueimp_upload/css/jquery.fileupload-ui-noscript.css +++ b/library/blueimp_upload/css/jquery.fileupload-ui-noscript.css @@ -1,13 +1,13 @@ @charset "UTF-8"; /* - * jQuery File Upload UI Plugin NoScript CSS 8.8.5 + * jQuery File Upload UI Plugin NoScript CSS * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2012, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ .fileinput-button i, diff --git a/library/blueimp_upload/css/jquery.fileupload-ui.css b/library/blueimp_upload/css/jquery.fileupload-ui.css index 76fb376de..9e36c42c5 100644 --- a/library/blueimp_upload/css/jquery.fileupload-ui.css +++ b/library/blueimp_upload/css/jquery.fileupload-ui.css @@ -1,13 +1,13 @@ @charset "UTF-8"; /* - * jQuery File Upload UI Plugin CSS 9.0.0 + * jQuery File Upload UI Plugin CSS * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ .fileupload-buttonbar .btn, diff --git a/library/blueimp_upload/css/jquery.fileupload.css b/library/blueimp_upload/css/jquery.fileupload.css index fb6044d34..8ae3b09d4 100644 --- a/library/blueimp_upload/css/jquery.fileupload.css +++ b/library/blueimp_upload/css/jquery.fileupload.css @@ -1,18 +1,19 @@ @charset "UTF-8"; /* - * jQuery File Upload Plugin CSS 1.3.0 + * jQuery File Upload Plugin CSS * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ .fileinput-button { position: relative; overflow: hidden; + display: inline-block; } .fileinput-button input { position: absolute; @@ -21,7 +22,7 @@ margin: 0; opacity: 0; -ms-filter: 'alpha(opacity=0)'; - font-size: 200px; + font-size: 200px !important; direction: ltr; cursor: pointer; } diff --git a/library/blueimp_upload/css/style.css b/library/blueimp_upload/css/style.css index b2c60a6f1..3aee25689 100644 --- a/library/blueimp_upload/css/style.css +++ b/library/blueimp_upload/css/style.css @@ -1,13 +1,13 @@ @charset "UTF-8"; /* - * jQuery File Upload Plugin CSS Example 8.8.2 + * jQuery File Upload Plugin CSS Example * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ body { diff --git a/library/blueimp_upload/index.html b/library/blueimp_upload/index.html index f92f04aab..2a8dc1521 100644 --- a/library/blueimp_upload/index.html +++ b/library/blueimp_upload/index.html @@ -1,14 +1,14 @@ <!DOCTYPE HTML> <!-- /* - * jQuery File Upload Plugin Demo 9.1.0 + * jQuery File Upload Plugin Demo * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ --> <html lang="en"> @@ -121,9 +121,9 @@ </div> <div class="panel-body"> <ul> - <li>The maximum file size for uploads in this demo is <strong>5 MB</strong> (default file size is unlimited).</li> + <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li> <li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li> - <li>Uploaded files will be deleted automatically after <strong>5 minutes</strong> (demo setting).</li> + <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li> <li>You can <strong>drag & drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li> <li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li> <li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li> @@ -216,7 +216,7 @@ </tr> {% } %} </script> -<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> +<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included --> <script src="js/vendor/jquery.ui.widget.js"></script> <!-- The Templates plugin is included to render the upload/download listings --> @@ -251,5 +251,5 @@ <!--[if (gte IE 8)&(lt IE 10)]> <script src="js/cors/jquery.xdr-transport.js"></script> <![endif]--> -</body> +</body> </html> diff --git a/library/blueimp_upload/jquery-ui.html b/library/blueimp_upload/jquery-ui.html index d61ee5233..83fe9acd1 100644 --- a/library/blueimp_upload/jquery-ui.html +++ b/library/blueimp_upload/jquery-ui.html @@ -1,14 +1,14 @@ <!DOCTYPE HTML> <!-- /* - * jQuery File Upload Plugin jQuery UI Demo 9.1.0 + * jQuery File Upload Plugin jQuery UI Demo * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ --> <html lang="en"> @@ -127,9 +127,9 @@ <br> <h3>Demo Notes</h3> <ul> - <li>The maximum file size for uploads in this demo is <strong>5 MB</strong> (default file size is unlimited).</li> + <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li> <li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li> - <li>Uploaded files will be deleted automatically after <strong>5 minutes</strong> (demo setting).</li> + <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li> <li>You can <strong>drag & drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li> <li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li> <li>Built with <a href="https://jqueryui.com">jQuery UI</a>.</li> @@ -199,8 +199,8 @@ </tr> {% } %} </script> -<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> -<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js"></script> +<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> +<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script> <!-- The Templates plugin is included to render the upload/download listings --> <script src="//blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script> <!-- The Load Image plugin is included for the preview images and image resizing functionality --> @@ -246,5 +246,5 @@ $('#theme-switcher').change(function () { <!--[if (gte IE 8)&(lt IE 10)]> <script src="js/cors/jquery.xdr-transport.js"></script> <![endif]--> -</body> +</body> </html> diff --git a/library/blueimp_upload/js/app.js b/library/blueimp_upload/js/app.js index 47b4f923b..e6b7bce3e 100644 --- a/library/blueimp_upload/js/app.js +++ b/library/blueimp_upload/js/app.js @@ -1,18 +1,18 @@ /* - * jQuery File Upload Plugin Angular JS Example 1.2.1 + * jQuery File Upload Plugin Angular JS Example * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ /* global window, angular */ -(function () { +;(function () { 'use strict'; var isOnGitHub = window.location.hostname === 'blueimp.github.io', @@ -37,7 +37,7 @@ // send Blob objects via XHR requests: disableImageResize: /Android(?!.*Chrome)|Opera/ .test(window.navigator.userAgent), - maxFileSize: 5000000, + maxFileSize: 999000, acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i }); } diff --git a/library/blueimp_upload/js/cors/jquery.postmessage-transport.js b/library/blueimp_upload/js/cors/jquery.postmessage-transport.js index 2b4851e67..2a0c38cb6 100644 --- a/library/blueimp_upload/js/cors/jquery.postmessage-transport.js +++ b/library/blueimp_upload/js/cors/jquery.postmessage-transport.js @@ -1,21 +1,24 @@ /* - * jQuery postMessage Transport Plugin 1.1.1 + * jQuery postMessage Transport Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ -/* global define, window, document */ +/* global define, require, window, document */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define(['jquery'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory(require('jquery')); } else { // Browser globals: factory(window.jQuery); @@ -61,6 +64,12 @@ loc = $('<a>').prop('href', options.postMessage)[0], target = loc.protocol + '//' + loc.host, xhrUpload = options.xhr().upload; + // IE always includes the port for the host property of a link + // element, but not in the location.host or origin property for the + // default http port 80 and https port 443, so we strip it: + if (/^(http:\/\/.+:80)|(https:\/\/.+:443)$/.test(target)) { + target = target.replace(/:(80|443)$/, ''); + } return { send: function (_, completeCallback) { counter += 1; diff --git a/library/blueimp_upload/js/cors/jquery.xdr-transport.js b/library/blueimp_upload/js/cors/jquery.xdr-transport.js index 0044cc2d5..a4e2699c6 100644 --- a/library/blueimp_upload/js/cors/jquery.xdr-transport.js +++ b/library/blueimp_upload/js/cors/jquery.xdr-transport.js @@ -1,24 +1,27 @@ /* - * jQuery XDomainRequest Transport Plugin 1.1.3 + * jQuery XDomainRequest Transport Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT * * Based on Julian Aubourg's ajaxHooks xdr.js: * https://github.com/jaubourg/ajaxHooks/ */ -/* global define, window, XDomainRequest */ +/* global define, require, window, XDomainRequest */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define(['jquery'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory(require('jquery')); } else { // Browser globals: factory(window.jQuery); diff --git a/library/blueimp_upload/js/jquery.fileupload-angular.js b/library/blueimp_upload/js/jquery.fileupload-angular.js index e4ef3926b..1c2055276 100644 --- a/library/blueimp_upload/js/jquery.fileupload-angular.js +++ b/library/blueimp_upload/js/jquery.fileupload-angular.js @@ -1,18 +1,18 @@ /* - * jQuery File Upload AngularJS Plugin 2.2.0 + * jQuery File Upload AngularJS Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ -/* global define, angular */ +/* global define, angular, require */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -24,6 +24,16 @@ './jquery.fileupload-video', './jquery.fileupload-validate' ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('angular'), + require('./jquery.fileupload-image'), + require('./jquery.fileupload-audio'), + require('./jquery.fileupload-video'), + require('./jquery.fileupload-validate') + ); } else { factory(); } @@ -91,7 +101,7 @@ angular.forEach(data.files, function (file) { filesCopy.push(file); }); - scope.$apply(function () { + scope.$parent.$applyAsync(function () { addFileMethods(scope, data); var method = scope.option('prependFiles') ? 'unshift' : 'push'; @@ -100,7 +110,7 @@ data.process(function () { return scope.process(data); }).always(function () { - scope.$apply(function () { + scope.$parent.$applyAsync(function () { addFileMethods(scope, data); scope.replace(filesCopy, data.files); }); @@ -112,12 +122,6 @@ } }); }, - progress: function (e, data) { - if (e.isDefaultPrevented()) { - return false; - } - data.scope.$apply(); - }, done: function (e, data) { if (e.isDefaultPrevented()) { return false; @@ -197,8 +201,8 @@ // The FileUploadController initializes the fileupload widget and // provides scope methods to control the File Upload functionality: .controller('FileUploadController', [ - '$scope', '$element', '$attrs', '$window', 'fileUpload', - function ($scope, $element, $attrs, $window, fileUpload) { + '$scope', '$element', '$attrs', '$window', 'fileUpload','$q', + function ($scope, $element, $attrs, $window, fileUpload, $q) { var uploadMethods = { progress: function () { return $element.fileupload('progress'); @@ -260,19 +264,21 @@ $scope.applyOnQueue = function (method) { var list = this.queue.slice(0), i, - file; + file, + promises = []; for (i = 0; i < list.length; i += 1) { file = list[i]; if (file[method]) { - file[method](); + promises.push(file[method]()); } } + return $q.all(promises); }; $scope.submit = function () { - this.applyOnQueue('$submit'); + return this.applyOnQueue('$submit'); }; $scope.cancel = function () { - this.applyOnQueue('$cancel'); + return this.applyOnQueue('$cancel'); }; // Add upload methods to the scope: angular.extend($scope, uploadMethods); @@ -320,9 +326,11 @@ 'fileuploadprocessalways', 'fileuploadprocessstop' ].join(' '), function (e, data) { - if ($scope.$emit(e.type, data).defaultPrevented) { - e.preventDefault(); - } + $scope.$parent.$applyAsync(function () { + if ($scope.$emit(e.type, data).defaultPrevented) { + e.preventDefault(); + } + }); }).on('remove', function () { // Remove upload methods from the scope, // when the widget is removed: diff --git a/library/blueimp_upload/js/jquery.fileupload-audio.js b/library/blueimp_upload/js/jquery.fileupload-audio.js index 575800e82..a25377619 100644 --- a/library/blueimp_upload/js/jquery.fileupload-audio.js +++ b/library/blueimp_upload/js/jquery.fileupload-audio.js @@ -1,18 +1,18 @@ /* - * jQuery File Upload Audio Preview Plugin 1.0.3 + * jQuery File Upload Audio Preview Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ -/* global define, window, document */ +/* global define, require, window, document */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -21,6 +21,13 @@ 'load-image', './jquery.fileupload-process' ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('blueimp-load-image/js/load-image'), + require('./jquery.fileupload-process') + ); } else { // Browser globals: factory( diff --git a/library/blueimp_upload/js/jquery.fileupload-image.js b/library/blueimp_upload/js/jquery.fileupload-image.js index 5bb7026ae..65fc6d7b8 100644 --- a/library/blueimp_upload/js/jquery.fileupload-image.js +++ b/library/blueimp_upload/js/jquery.fileupload-image.js @@ -1,18 +1,18 @@ /* - * jQuery File Upload Image Preview & Resize Plugin 1.7.2 + * jQuery File Upload Image Preview & Resize Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ -/* global define, window, Blob */ +/* global define, require, window, Blob */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -20,11 +20,22 @@ 'jquery', 'load-image', 'load-image-meta', + 'load-image-scale', 'load-image-exif', - 'load-image-ios', 'canvas-to-blob', './jquery.fileupload-process' ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('blueimp-load-image/js/load-image'), + require('blueimp-load-image/js/load-image-meta'), + require('blueimp-load-image/js/load-image-scale'), + require('blueimp-load-image/js/load-image-exif'), + require('blueimp-canvas-to-blob'), + require('./jquery.fileupload-process') + ); } else { // Browser globals: factory( @@ -236,7 +247,7 @@ blob.name = file.name; } else if (file.name) { blob.name = file.name.replace( - /\..+$/, + /\.\w+$/, '.' + blob.type.substr(6) ); } diff --git a/library/blueimp_upload/js/jquery.fileupload-jquery-ui.js b/library/blueimp_upload/js/jquery.fileupload-jquery-ui.js index af0a00b1e..7b136b379 100755..100644 --- a/library/blueimp_upload/js/jquery.fileupload-jquery-ui.js +++ b/library/blueimp_upload/js/jquery.fileupload-jquery-ui.js @@ -1,22 +1,31 @@ /* - * jQuery File Upload jQuery UI Plugin 8.7.1 + * jQuery File Upload jQuery UI Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ -/* global define, window */ +/* global define, require, window */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: - define(['jquery', './jquery.fileupload-ui'], factory); + define([ + 'jquery', + './jquery.fileupload-ui' + ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('./jquery.fileupload-ui') + ); } else { // Browser globals: factory(window.jQuery); diff --git a/library/blueimp_upload/js/jquery.fileupload-process.js b/library/blueimp_upload/js/jquery.fileupload-process.js index 8a6b929a6..638f0d26b 100644 --- a/library/blueimp_upload/js/jquery.fileupload-process.js +++ b/library/blueimp_upload/js/jquery.fileupload-process.js @@ -1,18 +1,18 @@ /* - * jQuery File Upload Processing Plugin 1.3.0 + * jQuery File Upload Processing Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2012, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ -/* global define, window */ +/* global define, require, window */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -20,6 +20,12 @@ 'jquery', './jquery.fileupload' ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('./jquery.fileupload') + ); } else { // Browser globals: factory( @@ -81,7 +87,7 @@ settings ); }; - chain = chain.pipe(func, settings.always && func); + chain = chain.then(func, settings.always && func); }); chain .done(function () { @@ -148,7 +154,7 @@ }; opts.index = index; that._processing += 1; - that._processingQueue = that._processingQueue.pipe(func, func) + that._processingQueue = that._processingQueue.then(func, func) .always(function () { that._processing -= 1; if (that._processing === 0) { diff --git a/library/blueimp_upload/js/jquery.fileupload-ui.js b/library/blueimp_upload/js/jquery.fileupload-ui.js index 62cf9aa38..83e7449e6 100644 --- a/library/blueimp_upload/js/jquery.fileupload-ui.js +++ b/library/blueimp_upload/js/jquery.fileupload-ui.js @@ -1,29 +1,38 @@ /* - * jQuery File Upload User Interface Plugin 9.6.0 + * jQuery File Upload User Interface Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ -/* global define, window */ +/* global define, require, window */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define([ 'jquery', - 'tmpl', + 'blueimp-tmpl', './jquery.fileupload-image', './jquery.fileupload-audio', './jquery.fileupload-video', './jquery.fileupload-validate' ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('blueimp-tmpl'), + require('./jquery.fileupload-image'), + require('./jquery.fileupload-video'), + require('./jquery.fileupload-validate') + ); } else { // Browser globals: factory( @@ -62,10 +71,10 @@ // The expected data type of the upload response, sets the dataType // option of the $.ajax upload requests: dataType: 'json', - + // Error and info messages: messages: { - unknownError: 'Unknown error' + unknownError: 'Unknown error' }, // Function returning the current number of files, diff --git a/library/blueimp_upload/js/jquery.fileupload-validate.js b/library/blueimp_upload/js/jquery.fileupload-validate.js index f93a18fa2..eebeb3733 100644 --- a/library/blueimp_upload/js/jquery.fileupload-validate.js +++ b/library/blueimp_upload/js/jquery.fileupload-validate.js @@ -1,17 +1,17 @@ /* - * jQuery File Upload Validation Plugin 1.1.2 + * jQuery File Upload Validation Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ -/* global define, window */ +/* global define, require, window */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -19,6 +19,12 @@ 'jquery', './jquery.fileupload-process' ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('./jquery.fileupload-process') + ); } else { // Browser globals: factory( @@ -33,7 +39,7 @@ { action: 'validate', // Always trigger this action, - // even if the previous action was rejected: + // even if the previous action was rejected: always: true, // Options taken from the global options map: acceptFileTypes: '@', diff --git a/library/blueimp_upload/js/jquery.fileupload-video.js b/library/blueimp_upload/js/jquery.fileupload-video.js index 3764b27a2..aedcec2ba 100644 --- a/library/blueimp_upload/js/jquery.fileupload-video.js +++ b/library/blueimp_upload/js/jquery.fileupload-video.js @@ -1,18 +1,18 @@ /* - * jQuery File Upload Video Preview Plugin 1.0.3 + * jQuery File Upload Video Preview Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ -/* global define, window, document */ +/* global define, require, window, document */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -21,6 +21,13 @@ 'load-image', './jquery.fileupload-process' ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('blueimp-load-image/js/load-image'), + require('./jquery.fileupload-process') + ); } else { // Browser globals: factory( diff --git a/library/blueimp_upload/js/jquery.fileupload.js b/library/blueimp_upload/js/jquery.fileupload.js index a4cfdc0ac..5ff151b53 100644 --- a/library/blueimp_upload/js/jquery.fileupload.js +++ b/library/blueimp_upload/js/jquery.fileupload.js @@ -1,25 +1,31 @@ /* - * jQuery File Upload Plugin 5.42.0 + * jQuery File Upload Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ -/* global define, window, document, location, Blob, FormData */ +/* global define, require, window, document, location, Blob, FormData */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define([ 'jquery', - 'jquery.ui.widget' + 'jquery-ui/ui/widget' ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('./vendor/jquery.ui.widget') + ); } else { // Browser globals: factory(window.jQuery); @@ -271,7 +277,8 @@ // The following are jQuery ajax settings required for the file uploads: processData: false, contentType: false, - cache: false + cache: false, + timeout: 0 }, // A list of options that require reinitializing event listeners and/or @@ -645,7 +652,7 @@ data.process = function (resolveFunc, rejectFunc) { if (resolveFunc || rejectFunc) { data._processQueue = this._processQueue = - (this._processQueue || getPromise([this])).pipe( + (this._processQueue || getPromise([this])).then( function () { if (data.errorThrown) { return $.Deferred() @@ -653,7 +660,7 @@ } return getPromise(arguments); } - ).pipe(resolveFunc, rejectFunc); + ).then(resolveFunc, rejectFunc); } return this._processQueue || getPromise([this]); }; @@ -938,9 +945,9 @@ if (this.options.limitConcurrentUploads > 1) { slot = $.Deferred(); this._slots.push(slot); - pipe = slot.pipe(send); + pipe = slot.then(send); } else { - this._sequence = this._sequence.pipe(send, send); + this._sequence = this._sequence.then(send, send); pipe = this._sequence; } // Return the piped Promise object, enhanced with an abort method, @@ -977,7 +984,10 @@ fileSet, i, j = 0; - if (limitSize && (!filesLength || files[0].size === undefined)) { + if (!filesLength) { + return false; + } + if (limitSize && files[0].size === undefined) { limitSize = undefined; } if (!(options.singleFileUploads || limit || limitSize) || @@ -1036,13 +1046,19 @@ _replaceFileInput: function (data) { var input = data.fileInput, - inputClone = input.clone(true); + inputClone = input.clone(true), + restoreFocus = input.is(document.activeElement); // Add a reference for the new cloned file input to the data argument: data.fileInputClone = inputClone; $('<form></form>').append(inputClone)[0].reset(); // Detaching allows to insert the fileInput on another form // without loosing the file input value: input.after(inputClone).detach(); + // If the fileInput had focus before it was detached, + // restore focus to the inputClone. + if (restoreFocus) { + inputClone.focus(); + } // Avoid memory leaks with the detached file input: $.cleanData(input.unbind('remove')); // Replace the original file input element in the fileInput @@ -1064,6 +1080,8 @@ _handleFileTreeEntry: function (entry, path) { var that = this, dfd = $.Deferred(), + entries = [], + dirReader, errorHandler = function (e) { if (e && !e.entry) { e.entry = entry; @@ -1091,8 +1109,7 @@ readEntries(); } }, errorHandler); - }, - dirReader, entries = []; + }; path = path || ''; if (entry.isFile) { if (entry._file) { @@ -1123,7 +1140,7 @@ $.map(entries, function (entry) { return that._handleFileTreeEntry(entry, path); }) - ).pipe(function () { + ).then(function () { return Array.prototype.concat.apply( [], arguments @@ -1192,7 +1209,7 @@ return $.when.apply( $, $.map(fileInput, this._getSingleFileInputFiles) - ).pipe(function () { + ).then(function () { return Array.prototype.concat.apply( [], arguments @@ -1295,6 +1312,10 @@ this._off(this.options.fileInput, 'change'); }, + _destroy: function () { + this._destroyEventHandlers(); + }, + _setOption: function (key, value) { var reinit = $.inArray(key, this._specialOptions) !== -1; if (reinit) { @@ -1338,15 +1359,19 @@ _initDataAttributes: function () { var that = this, options = this.options, - clone = $(this.element[0].cloneNode(false)); + data = this.element.data(); // Initialize options set via HTML5 data-attributes: $.each( - clone.data(), - function (key, value) { - var dataAttributeName = 'data-' + - // Convert camelCase to hyphen-ated key: - key.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); - if (clone.attr(dataAttributeName)) { + this.element[0].attributes, + function (index, attr) { + var key = attr.name.toLowerCase(), + value; + if (/^data-/.test(key)) { + // Convert hyphen-ated key to camelCase: + key = key.slice(5).replace(/-[a-z]/g, function (str) { + return str.charAt(1).toUpperCase(); + }); + value = data[key]; if (that._isRegExpOption(key, value)) { value = that._getRegExp(value); } diff --git a/library/blueimp_upload/js/jquery.iframe-transport.js b/library/blueimp_upload/js/jquery.iframe-transport.js index 8d64b591b..8d25c4641 100644 --- a/library/blueimp_upload/js/jquery.iframe-transport.js +++ b/library/blueimp_upload/js/jquery.iframe-transport.js @@ -1,21 +1,24 @@ /* - * jQuery Iframe Transport Plugin 1.8.2 + * jQuery Iframe Transport Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ -/* global define, window, document */ +/* global define, require, window, document, JSON */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define(['jquery'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory(require('jquery')); } else { // Browser globals: factory(window.jQuery); @@ -24,7 +27,14 @@ 'use strict'; // Helper variable to create unique names for the transport iframes: - var counter = 0; + var counter = 0, + jsonAPI = $, + jsonParse = 'parseJSON'; + + if ('JSON' in window && 'parse' in JSON) { + jsonAPI = JSON; + jsonParse = 'parse'; + } // The iframe transport accepts four additional options: // options.fileInput: a jQuery collection of file input fields @@ -194,7 +204,7 @@ return iframe && $(iframe[0].body).text(); }, 'iframe json': function (iframe) { - return iframe && $.parseJSON($(iframe[0].body).text()); + return iframe && jsonAPI[jsonParse]($(iframe[0].body).text()); }, 'iframe html': function (iframe) { return iframe && $(iframe[0].body).html(); diff --git a/library/blueimp_upload/js/main.js b/library/blueimp_upload/js/main.js index 8f57967a3..0403682e7 100644 --- a/library/blueimp_upload/js/main.js +++ b/library/blueimp_upload/js/main.js @@ -1,12 +1,12 @@ /* - * jQuery File Upload Plugin JS Example 8.9.1 + * jQuery File Upload Plugin JS Example * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ /* global $, window */ @@ -40,7 +40,7 @@ $(function () { // send Blob objects via XHR requests: disableImageResize: /Android(?!.*Chrome)|Opera/ .test(window.navigator.userAgent), - maxFileSize: 5000000, + maxFileSize: 999000, acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i }); // Upload server status check for browsers with CORS support: diff --git a/library/blueimp_upload/js/vendor/jquery.ui.widget.js b/library/blueimp_upload/js/vendor/jquery.ui.widget.js index 7899e6bb3..e08df3fd0 100644 --- a/library/blueimp_upload/js/vendor/jquery.ui.widget.js +++ b/library/blueimp_upload/js/vendor/jquery.ui.widget.js @@ -1,13 +1,19 @@ -/*! jQuery UI - v1.11.1 - 2014-09-17 +/*! jQuery UI - v1.11.4+CommonJS - 2015-08-28 * http://jqueryui.com * Includes: widget.js -* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */ +* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ (function( factory ) { if ( typeof define === "function" && define.amd ) { // AMD. Register as an anonymous module. define([ "jquery" ], factory ); + + } else if ( typeof exports === "object" ) { + + // Node/CommonJS + factory( require( "jquery" ) ); + } else { // Browser globals @@ -15,10 +21,10 @@ } }(function( $ ) { /*! - * jQuery UI Widget 1.11.1 + * jQuery UI Widget 1.11.4 * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * @@ -42,7 +48,7 @@ $.cleanData = (function( orig ) { } // http://bugs.jquery.com/ticket/8235 - } catch( e ) {} + } catch ( e ) {} } orig( elems ); }; @@ -196,11 +202,6 @@ $.widget.bridge = function( name, object ) { args = widget_slice.call( arguments, 1 ), returnValue = this; - // allow multiple hashes to be passed on init - options = !isMethodCall && args.length ? - $.widget.extend.apply( null, [ options ].concat(args) ) : - options; - if ( isMethodCall ) { this.each(function() { var methodValue, @@ -225,6 +226,12 @@ $.widget.bridge = function( name, object ) { } }); } else { + + // Allow multiple hashes to be passed on init + if ( args.length ) { + options = $.widget.extend.apply( null, [ options ].concat(args) ); + } + this.each(function() { var instance = $.data( this, fullName ); if ( instance ) { @@ -260,10 +267,6 @@ $.Widget.prototype = { this.element = $( element ); this.uuid = widget_uuid++; this.eventNamespace = "." + this.widgetName + this.uuid; - this.options = $.widget.extend( {}, - this.options, - this._getCreateOptions(), - options ); this.bindings = $(); this.hoverable = $(); @@ -286,6 +289,11 @@ $.Widget.prototype = { this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); } + this.options = $.widget.extend( {}, + this.options, + this._getCreateOptions(), + options ); + this._create(); this._trigger( "create", null, this._getCreateEventData() ); this._init(); @@ -448,8 +456,14 @@ $.Widget.prototype = { }, _off: function( element, eventName ) { - eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; + eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + + this.eventNamespace; element.unbind( eventName ).undelegate( eventName ); + + // Clear the stack to avoid memory leaks (#10056) + this.bindings = $( this.bindings.not( element ).get() ); + this.focusable = $( this.focusable.not( element ).get() ); + this.hoverable = $( this.hoverable.not( element ).get() ); }, _delay: function( handler, delay ) { diff --git a/library/blueimp_upload/package.json b/library/blueimp_upload/package.json index 880574aa7..ed4d33681 100644 --- a/library/blueimp_upload/package.json +++ b/library/blueimp_upload/package.json @@ -1,8 +1,8 @@ { "name": "blueimp-file-upload", - "version": "9.8.0", + "version": "9.18.0", "title": "jQuery File Upload", - "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.", + "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.", "keywords": [ "jquery", "file", @@ -29,26 +29,27 @@ "name": "Sebastian Tschan", "url": "https://blueimp.net" }, - "maintainers": [ - { - "name": "Sebastian Tschan", - "url": "https://blueimp.net" - } - ], "repository": { "type": "git", "url": "git://github.com/blueimp/jQuery-File-Upload.git" }, - "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues", - "licenses": [ - { - "type": "MIT", - "url": "http://www.opensource.org/licenses/MIT" - } - ], + "license": "MIT", + "optionalDependencies": { + "blueimp-canvas-to-blob": "3.5.0", + "blueimp-load-image": "2.12.2", + "blueimp-tmpl": "3.6.0" + }, "devDependencies": { - "grunt": "~0.4.5", - "grunt-bump-build-git": "~1.1.1", - "grunt-contrib-jshint": "~0.10.0" - } + "bower-json": "0.8.1", + "jshint": "2.9.3" + }, + "scripts": { + "bower-version-update": "./bower-version-update.js", + "lint": "jshint *.js js/*.js js/cors/*.js", + "test": "npm run lint", + "preversion": "npm test", + "version": "npm run bower-version-update && git add bower.json", + "postversion": "git push --tags origin master && npm publish" + }, + "main": "js/jquery.fileupload.js" } diff --git a/library/blueimp_upload/server/gae-go/app/main.go b/library/blueimp_upload/server/gae-go/app/main.go index 03af0b1d2..a92d128c0 100644 --- a/library/blueimp_upload/server/gae-go/app/main.go +++ b/library/blueimp_upload/server/gae-go/app/main.go @@ -1,59 +1,90 @@ /* - * jQuery File Upload Plugin GAE Go Example 3.2.0 + * jQuery File Upload Plugin GAE Go Example * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ package app import ( - "appengine" - "appengine/blobstore" - "appengine/image" - "appengine/taskqueue" + "bufio" "bytes" "encoding/json" "fmt" + "github.com/disintegration/gift" + "golang.org/x/net/context" + "google.golang.org/appengine" + "google.golang.org/appengine/memcache" + "hash/crc32" + "image" + "image/gif" + "image/jpeg" + "image/png" "io" "log" "mime/multipart" "net/http" "net/url" + "path/filepath" "regexp" "strings" - "time" ) const ( - WEBSITE = "https://blueimp.github.io/jQuery-File-Upload/" - MIN_FILE_SIZE = 1 // bytes - MAX_FILE_SIZE = 5000000 // bytes + WEBSITE = "https://blueimp.github.io/jQuery-File-Upload/" + MIN_FILE_SIZE = 1 // bytes + // Max file size is memcache limit (1MB) minus key size minus overhead: + MAX_FILE_SIZE = 999000 // bytes IMAGE_TYPES = "image/(gif|p?jpeg|(x-)?png)" ACCEPT_FILE_TYPES = IMAGE_TYPES + THUMB_MAX_WIDTH = 80 + THUMB_MAX_HEIGHT = 80 EXPIRATION_TIME = 300 // seconds - THUMBNAIL_PARAM = "=s80" + // If empty, only allow redirects to the referer protocol+host. + // Set to a regexp string for custom pattern matching: + REDIRECT_ALLOW_TARGET = "" ) var ( imageTypes = regexp.MustCompile(IMAGE_TYPES) acceptFileTypes = regexp.MustCompile(ACCEPT_FILE_TYPES) + thumbSuffix = "." + fmt.Sprint(THUMB_MAX_WIDTH) + "x" + + fmt.Sprint(THUMB_MAX_HEIGHT) ) +func escape(s string) string { + return strings.Replace(url.QueryEscape(s), "+", "%20", -1) +} + +func extractKey(r *http.Request) string { + // Use RequestURI instead of r.URL.Path, as we need the encoded form: + path := strings.Split(r.RequestURI, "?")[0] + // Also adjust double encoded slashes: + return strings.Replace(path[1:], "%252F", "%2F", -1) +} + +func check(err error) { + if err != nil { + panic(err) + } +} + type FileInfo struct { - Key appengine.BlobKey `json:"-"` - Url string `json:"url,omitempty"` - ThumbnailUrl string `json:"thumbnailUrl,omitempty"` - Name string `json:"name"` - Type string `json:"type"` - Size int64 `json:"size"` - Error string `json:"error,omitempty"` - DeleteUrl string `json:"deleteUrl,omitempty"` - DeleteType string `json:"deleteType,omitempty"` + Key string `json:"-"` + ThumbnailKey string `json:"-"` + Url string `json:"url,omitempty"` + ThumbnailUrl string `json:"thumbnailUrl,omitempty"` + Name string `json:"name"` + Type string `json:"type"` + Size int64 `json:"size"` + Error string `json:"error,omitempty"` + DeleteUrl string `json:"deleteUrl,omitempty"` + DeleteType string `json:"deleteType,omitempty"` } func (fi *FileInfo) ValidateType() (valid bool) { @@ -75,50 +106,58 @@ func (fi *FileInfo) ValidateSize() (valid bool) { return false } -func (fi *FileInfo) CreateUrls(r *http.Request, c appengine.Context) { +func (fi *FileInfo) CreateUrls(r *http.Request, c context.Context) { u := &url.URL{ Scheme: r.URL.Scheme, Host: appengine.DefaultVersionHostname(c), Path: "/", } uString := u.String() - fi.Url = uString + escape(string(fi.Key)) + "/" + - escape(string(fi.Name)) - fi.DeleteUrl = fi.Url + "?delete=true" + fi.Url = uString + fi.Key + fi.DeleteUrl = fi.Url fi.DeleteType = "DELETE" - if imageTypes.MatchString(fi.Type) { - servingUrl, err := image.ServingURL( - c, - fi.Key, - &image.ServingURLOptions{ - Secure: strings.HasSuffix(u.Scheme, "s"), - Size: 0, - Crop: false, - }, - ) - check(err) - fi.ThumbnailUrl = servingUrl.String() + THUMBNAIL_PARAM + if fi.ThumbnailKey != "" { + fi.ThumbnailUrl = uString + fi.ThumbnailKey } } -func check(err error) { - if err != nil { - panic(err) - } -} - -func escape(s string) string { - return strings.Replace(url.QueryEscape(s), "+", "%20", -1) +func (fi *FileInfo) SetKey(checksum uint32) { + fi.Key = escape(string(fi.Type)) + "/" + + escape(fmt.Sprint(checksum)) + "/" + + escape(string(fi.Name)) } -func delayedDelete(c appengine.Context, fi *FileInfo) { - if key := string(fi.Key); key != "" { - task := &taskqueue.Task{ - Path: "/" + escape(key) + "/-", - Method: "DELETE", - Delay: time.Duration(EXPIRATION_TIME) * time.Second, +func (fi *FileInfo) createThumb(buffer *bytes.Buffer, c context.Context) { + if imageTypes.MatchString(fi.Type) { + src, _, err := image.Decode(bytes.NewReader(buffer.Bytes())) + check(err) + filter := gift.New(gift.ResizeToFit( + THUMB_MAX_WIDTH, + THUMB_MAX_HEIGHT, + gift.LanczosResampling, + )) + dst := image.NewNRGBA(filter.Bounds(src.Bounds())) + filter.Draw(dst, src) + buffer.Reset() + bWriter := bufio.NewWriter(buffer) + switch fi.Type { + case "image/jpeg", "image/pjpeg": + err = jpeg.Encode(bWriter, dst, nil) + case "image/gif": + err = gif.Encode(bWriter, dst, nil) + default: + err = png.Encode(bWriter, dst) + } + check(err) + bWriter.Flush() + thumbnailKey := fi.Key + thumbSuffix + filepath.Ext(fi.Name) + item := &memcache.Item{ + Key: thumbnailKey, + Value: buffer.Bytes(), } - taskqueue.Add(c, task, "") + err = memcache.Set(c, item) + check(err) + fi.ThumbnailKey = thumbnailKey } } @@ -136,24 +175,26 @@ func handleUpload(r *http.Request, p *multipart.Part) (fi *FileInfo) { fi.Error = rec.(error).Error() } }() + var buffer bytes.Buffer + hash := crc32.NewIEEE() + mw := io.MultiWriter(&buffer, hash) lr := &io.LimitedReader{R: p, N: MAX_FILE_SIZE + 1} + _, err := io.Copy(mw, lr) + check(err) + fi.Size = MAX_FILE_SIZE + 1 - lr.N + if !fi.ValidateSize() { + return + } + fi.SetKey(hash.Sum32()) + item := &memcache.Item{ + Key: fi.Key, + Value: buffer.Bytes(), + } context := appengine.NewContext(r) - w, err := blobstore.Create(context, fi.Type) - defer func() { - w.Close() - fi.Size = MAX_FILE_SIZE + 1 - lr.N - fi.Key, err = w.Key() - check(err) - if !fi.ValidateSize() { - err := blobstore.Delete(context, fi.Key) - check(err) - return - } - delayedDelete(context, fi) - fi.CreateUrls(r, context) - }() + err = memcache.Set(context, item) check(err) - _, err = io.Copy(w, lr) + fi.createThumb(&buffer, context) + fi.CreateUrls(r, context) return } @@ -183,49 +224,70 @@ func handleUploads(r *http.Request) (fileInfos []*FileInfo) { return } +func validateRedirect(r *http.Request, redirect string) bool { + if redirect != "" { + var redirectAllowTarget *regexp.Regexp + if REDIRECT_ALLOW_TARGET != "" { + redirectAllowTarget = regexp.MustCompile(REDIRECT_ALLOW_TARGET) + } else { + referer := r.Referer() + if referer == "" { + return false + } + refererUrl, err := url.Parse(referer) + if err != nil { + return false + } + redirectAllowTarget = regexp.MustCompile("^" + regexp.QuoteMeta( + refererUrl.Scheme+"://"+refererUrl.Host+"/", + )) + } + return redirectAllowTarget.MatchString(redirect) + } + return false +} + func get(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/" { http.Redirect(w, r, WEBSITE, http.StatusFound) return } - parts := strings.Split(r.URL.Path, "/") + // Use RequestURI instead of r.URL.Path, as we need the encoded form: + key := extractKey(r) + parts := strings.Split(key, "/") if len(parts) == 3 { - if key := parts[1]; key != "" { - blobKey := appengine.BlobKey(key) - bi, err := blobstore.Stat(appengine.NewContext(r), blobKey) - if err == nil { - w.Header().Add("X-Content-Type-Options", "nosniff") - if !imageTypes.MatchString(bi.ContentType) { - w.Header().Add("Content-Type", "application/octet-stream") - w.Header().Add( - "Content-Disposition", - fmt.Sprintf("attachment; filename=\"%s\"", parts[2]), - ) - } - w.Header().Add( - "Cache-Control", - fmt.Sprintf("public,max-age=%d", EXPIRATION_TIME), - ) - blobstore.Send(w, blobKey) - return + context := appengine.NewContext(r) + item, err := memcache.Get(context, key) + if err == nil { + w.Header().Add("X-Content-Type-Options", "nosniff") + contentType, _ := url.QueryUnescape(parts[0]) + if !imageTypes.MatchString(contentType) { + contentType = "application/octet-stream" } + w.Header().Add("Content-Type", contentType) + w.Header().Add( + "Cache-Control", + fmt.Sprintf("public,max-age=%d", EXPIRATION_TIME), + ) + w.Write(item.Value) + return } } http.Error(w, "404 Not Found", http.StatusNotFound) } func post(w http.ResponseWriter, r *http.Request) { - result := make(map[string][]*FileInfo, 1) - result["files"] = handleUploads(r) + result := make(map[string][]*FileInfo, 1) + result["files"] = handleUploads(r) b, err := json.Marshal(result) check(err) - if redirect := r.FormValue("redirect"); redirect != "" { - if strings.Contains(redirect, "%s") { - redirect = fmt.Sprintf( - redirect, - escape(string(b)), - ) - } + if redirect := r.FormValue("redirect"); validateRedirect(r, redirect) { + if strings.Contains(redirect, "%s") { + redirect = fmt.Sprintf( + redirect, + escape(string(b)), + ) + } http.Redirect(w, r, redirect, http.StatusFound) return } @@ -238,27 +300,30 @@ func post(w http.ResponseWriter, r *http.Request) { } func delete(w http.ResponseWriter, r *http.Request) { - parts := strings.Split(r.URL.Path, "/") - if len(parts) != 3 { - return - } - result := make(map[string]bool, 1) - if key := parts[1]; key != "" { - c := appengine.NewContext(r) - blobKey := appengine.BlobKey(key) - err := blobstore.Delete(c, blobKey) - check(err) - err = image.DeleteServingURL(c, blobKey) + key := extractKey(r) + parts := strings.Split(key, "/") + if len(parts) == 3 { + result := make(map[string]bool, 1) + context := appengine.NewContext(r) + err := memcache.Delete(context, key) + if err == nil { + result[key] = true + contentType, _ := url.QueryUnescape(parts[0]) + if imageTypes.MatchString(contentType) { + thumbnailKey := key + thumbSuffix + filepath.Ext(parts[2]) + err := memcache.Delete(context, thumbnailKey) + if err == nil { + result[thumbnailKey] = true + } + } + } + w.Header().Set("Content-Type", "application/json") + b, err := json.Marshal(result) check(err) - result[key] = true - } - jsonType := "application/json" - if strings.Index(r.Header.Get("Accept"), jsonType) != -1 { - w.Header().Set("Content-Type", jsonType) + fmt.Fprintln(w, string(b)) + } else { + http.Error(w, "405 Method not allowed", http.StatusMethodNotAllowed) } - b, err := json.Marshal(result) - check(err) - fmt.Fprintln(w, string(b)) } func handle(w http.ResponseWriter, r *http.Request) { @@ -267,15 +332,15 @@ func handle(w http.ResponseWriter, r *http.Request) { w.Header().Add("Access-Control-Allow-Origin", "*") w.Header().Add( "Access-Control-Allow-Methods", - "OPTIONS, HEAD, GET, POST, PUT, DELETE", + "OPTIONS, HEAD, GET, POST, DELETE", ) w.Header().Add( "Access-Control-Allow-Headers", "Content-Type, Content-Range, Content-Disposition", ) switch r.Method { - case "OPTIONS": - case "HEAD": + case "OPTIONS", "HEAD": + return case "GET": get(w, r) case "POST": diff --git a/library/blueimp_upload/server/gae-python/app.yaml b/library/blueimp_upload/server/gae-python/app.yaml index 5fe123f59..764449b74 100644 --- a/library/blueimp_upload/server/gae-python/app.yaml +++ b/library/blueimp_upload/server/gae-python/app.yaml @@ -4,8 +4,9 @@ runtime: python27 api_version: 1 threadsafe: true -builtins: -- deferred: on +libraries: +- name: PIL + version: latest handlers: - url: /(favicon\.ico|robots\.txt) diff --git a/library/blueimp_upload/server/gae-python/main.py b/library/blueimp_upload/server/gae-python/main.py index 6276be6a0..1955ac00a 100644 --- a/library/blueimp_upload/server/gae-python/main.py +++ b/library/blueimp_upload/server/gae-python/main.py @@ -1,49 +1,57 @@ # -*- coding: utf-8 -*- # -# jQuery File Upload Plugin GAE Python Example 2.2.0 +# jQuery File Upload Plugin GAE Python Example # https://github.com/blueimp/jQuery-File-Upload # # Copyright 2011, Sebastian Tschan # https://blueimp.net # # Licensed under the MIT license: -# http://www.opensource.org/licenses/MIT +# https://opensource.org/licenses/MIT # -from __future__ import with_statement -from google.appengine.api import files, images -from google.appengine.ext import blobstore, deferred -from google.appengine.ext.webapp import blobstore_handlers +from google.appengine.api import memcache, images import json +import os import re import urllib import webapp2 +DEBUG=os.environ.get('SERVER_SOFTWARE', '').startswith('Dev') WEBSITE = 'https://blueimp.github.io/jQuery-File-Upload/' MIN_FILE_SIZE = 1 # bytes -MAX_FILE_SIZE = 5000000 # bytes +# Max file size is memcache limit (1MB) minus key size minus overhead: +MAX_FILE_SIZE = 999000 # bytes IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)') ACCEPT_FILE_TYPES = IMAGE_TYPES -THUMBNAIL_MODIFICATOR = '=s80' # max width / height +THUMB_MAX_WIDTH = 80 +THUMB_MAX_HEIGHT = 80 +THUMB_SUFFIX = '.'+str(THUMB_MAX_WIDTH)+'x'+str(THUMB_MAX_HEIGHT)+'.png' EXPIRATION_TIME = 300 # seconds +# If set to None, only allow redirects to the referer protocol+host. +# Set to a regexp for custom pattern matching against the redirect value: +REDIRECT_ALLOW_TARGET = None + +class CORSHandler(webapp2.RequestHandler): + def cors(self): + headers = self.response.headers + headers['Access-Control-Allow-Origin'] = '*' + headers['Access-Control-Allow-Methods'] =\ + 'OPTIONS, HEAD, GET, POST, DELETE' + headers['Access-Control-Allow-Headers'] =\ + 'Content-Type, Content-Range, Content-Disposition' + def initialize(self, request, response): + super(CORSHandler, self).initialize(request, response) + self.cors() -def cleanup(blob_keys): - blobstore.delete(blob_keys) - - -class UploadHandler(webapp2.RequestHandler): + def json_stringify(self, obj): + return json.dumps(obj, separators=(',', ':')) - def initialize(self, request, response): - super(UploadHandler, self).initialize(request, response) - self.response.headers['Access-Control-Allow-Origin'] = '*' - self.response.headers[ - 'Access-Control-Allow-Methods' - ] = 'OPTIONS, HEAD, GET, POST, PUT, DELETE' - self.response.headers[ - 'Access-Control-Allow-Headers' - ] = 'Content-Type, Content-Range, Content-Disposition' + def options(self, *args, **kwargs): + pass +class UploadHandler(CORSHandler): def validate(self, file): if file['size'] < MIN_FILE_SIZE: file['error'] = 'File is too small' @@ -55,6 +63,20 @@ class UploadHandler(webapp2.RequestHandler): return True return False + def validate_redirect(self, redirect): + if redirect: + if REDIRECT_ALLOW_TARGET: + return REDIRECT_ALLOW_TARGET.match(redirect) + referer = self.request.headers['referer'] + if referer: + from urlparse import urlparse + parts = urlparse(referer) + redirect_allow_target = '^' + re.escape( + parts.scheme + '://' + parts.netloc + '/' + ) + return re.match(redirect_allow_target, redirect) + return False + def get_file_size(self, file): file.seek(0, 2) # Seek to the end of the file size = file.tell() # Get the position of EOF @@ -62,64 +84,58 @@ class UploadHandler(webapp2.RequestHandler): return size def write_blob(self, data, info): - blob = files.blobstore.create( - mime_type=info['type'], - _blobinfo_uploaded_filename=info['name'] - ) - with files.open(blob, 'a') as f: - f.write(data) - files.finalize(blob) - return files.blobstore.get_blob_key(blob) + key = urllib.quote(info['type'].encode('utf-8'), '') +\ + '/' + str(hash(data)) +\ + '/' + urllib.quote(info['name'].encode('utf-8'), '') + try: + memcache.set(key, data, time=EXPIRATION_TIME) + except: #Failed to add to memcache + return (None, None) + thumbnail_key = None + if IMAGE_TYPES.match(info['type']): + try: + img = images.Image(image_data=data) + img.resize( + width=THUMB_MAX_WIDTH, + height=THUMB_MAX_HEIGHT + ) + thumbnail_data = img.execute_transforms() + thumbnail_key = key + THUMB_SUFFIX + memcache.set( + thumbnail_key, + thumbnail_data, + time=EXPIRATION_TIME + ) + except: #Failed to resize Image or add to memcache + thumbnail_key = None + return (key, thumbnail_key) def handle_upload(self): results = [] - blob_keys = [] for name, fieldStorage in self.request.POST.items(): if type(fieldStorage) is unicode: continue result = {} - result['name'] = re.sub( - r'^.*\\', - '', - fieldStorage.filename - ) + result['name'] = urllib.unquote(fieldStorage.filename) result['type'] = fieldStorage.type result['size'] = self.get_file_size(fieldStorage.file) if self.validate(result): - blob_key = str( - self.write_blob(fieldStorage.value, result) + key, thumbnail_key = self.write_blob( + fieldStorage.value, + result ) - blob_keys.append(blob_key) - result['deleteType'] = 'DELETE' - result['deleteUrl'] = self.request.host_url +\ - '/?key=' + urllib.quote(blob_key, '') - if (IMAGE_TYPES.match(result['type'])): - try: - result['url'] = images.get_serving_url( - blob_key, - secure_url=self.request.host_url.startswith( - 'https' - ) - ) - result['thumbnailUrl'] = result['url'] +\ - THUMBNAIL_MODIFICATOR - except: # Could not get an image serving url - pass - if not 'url' in result: - result['url'] = self.request.host_url +\ - '/' + blob_key + '/' + urllib.quote( - result['name'].encode('utf-8'), '') + if key is not None: + result['url'] = self.request.host_url + '/' + key + result['deleteUrl'] = result['url'] + result['deleteType'] = 'DELETE' + if thumbnail_key is not None: + result['thumbnailUrl'] = self.request.host_url +\ + '/' + thumbnail_key + else: + result['error'] = 'Failed to store uploaded file.' results.append(result) - deferred.defer( - cleanup, - blob_keys, - _countdown=EXPIRATION_TIME - ) return results - def options(self): - pass - def head(self): pass @@ -130,9 +146,9 @@ class UploadHandler(webapp2.RequestHandler): if (self.request.get('_method') == 'DELETE'): return self.delete() result = {'files': self.handle_upload()} - s = json.dumps(result, separators=(',', ':')) + s = self.json_stringify(result) redirect = self.request.get('redirect') - if redirect: + if self.validate_redirect(redirect): return self.redirect(str( redirect.replace('%s', urllib.quote(s, ''), 1) )) @@ -140,31 +156,49 @@ class UploadHandler(webapp2.RequestHandler): self.response.headers['Content-Type'] = 'application/json' self.response.write(s) - def delete(self): - key = self.request.get('key') or '' - blobstore.delete(key) - s = json.dumps({key: True}, separators=(',', ':')) +class FileHandler(CORSHandler): + def normalize(self, str): + return urllib.quote(urllib.unquote(str), '') + + def get(self, content_type, data_hash, file_name): + content_type = self.normalize(content_type) + file_name = self.normalize(file_name) + key = content_type + '/' + data_hash + '/' + file_name + data = memcache.get(key) + if data is None: + return self.error(404) + # Prevent browsers from MIME-sniffing the content-type: + self.response.headers['X-Content-Type-Options'] = 'nosniff' + content_type = urllib.unquote(content_type) + if not IMAGE_TYPES.match(content_type): + # Force a download dialog for non-image types: + content_type = 'application/octet-stream' + elif file_name.endswith(THUMB_SUFFIX): + content_type = 'image/png' + self.response.headers['Content-Type'] = content_type + # Cache for the expiration time: + self.response.headers['Cache-Control'] = 'public,max-age=%d' \ + % EXPIRATION_TIME + self.response.write(data) + + def delete(self, content_type, data_hash, file_name): + content_type = self.normalize(content_type) + file_name = self.normalize(file_name) + key = content_type + '/' + data_hash + '/' + file_name + result = {key: memcache.delete(key)} + content_type = urllib.unquote(content_type) + if IMAGE_TYPES.match(content_type): + thumbnail_key = key + THUMB_SUFFIX + result[thumbnail_key] = memcache.delete(thumbnail_key) if 'application/json' in self.request.headers.get('Accept'): self.response.headers['Content-Type'] = 'application/json' + s = self.json_stringify(result) self.response.write(s) - -class DownloadHandler(blobstore_handlers.BlobstoreDownloadHandler): - def get(self, key, filename): - if not blobstore.get(key): - self.error(404) - else: - # Prevent browsers from MIME-sniffing the content-type: - self.response.headers['X-Content-Type-Options'] = 'nosniff' - # Cache for the expiration time: - self.response.headers['Cache-Control'] = 'public,max-age=%d' % EXPIRATION_TIME - # Send the file forcing a download dialog: - self.send_blob(key, save_as=filename, content_type='application/octet-stream') - app = webapp2.WSGIApplication( [ ('/', UploadHandler), - ('/([^/]+)/([^/]+)', DownloadHandler) + ('/(.+)/([^/]+)/([^/]+)', FileHandler) ], - debug=True + debug=DEBUG ) diff --git a/library/blueimp_upload/server/node/.gitignore b/library/blueimp_upload/server/node/.gitignore deleted file mode 100644 index 9daa8247d..000000000 --- a/library/blueimp_upload/server/node/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.DS_Store -node_modules diff --git a/library/blueimp_upload/server/node/package.json b/library/blueimp_upload/server/node/package.json deleted file mode 100644 index dd38c50ca..000000000 --- a/library/blueimp_upload/server/node/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "blueimp-file-upload-node", - "version": "2.1.0", - "title": "jQuery File Upload Node.js example", - "description": "Node.js implementation example of a file upload handler for jQuery File Upload.", - "keywords": [ - "file", - "upload", - "cross-domain", - "cross-site", - "node" - ], - "homepage": "https://github.com/blueimp/jQuery-File-Upload", - "author": { - "name": "Sebastian Tschan", - "url": "https://blueimp.net" - }, - "maintainers": [ - { - "name": "Sebastian Tschan", - "url": "https://blueimp.net" - } - ], - "repository": { - "type": "git", - "url": "git://github.com/blueimp/jQuery-File-Upload.git" - }, - "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues", - "licenses": [ - { - "type": "MIT", - "url": "http://www.opensource.org/licenses/MIT" - } - ], - "dependencies": { - "formidable": ">=1.0.11", - "node-static": ">=0.6.5", - "imagemagick": ">=0.1.3" - }, - "main": "server.js" -} diff --git a/library/blueimp_upload/server/node/public/files/.gitignore b/library/blueimp_upload/server/node/public/files/.gitignore deleted file mode 100644 index d6b7ef32c..000000000 --- a/library/blueimp_upload/server/node/public/files/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/library/blueimp_upload/server/node/server.js b/library/blueimp_upload/server/node/server.js deleted file mode 100755 index 808d6ffe1..000000000 --- a/library/blueimp_upload/server/node/server.js +++ /dev/null @@ -1,292 +0,0 @@ -#!/usr/bin/nodejs -/* - * jQuery File Upload Plugin Node.js Example 2.1.2 - * https://github.com/blueimp/jQuery-File-Upload - * - * Copyright 2012, Sebastian Tschan - * https://blueimp.net - * - * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT - */ - -/* jshint nomen:false */ -/* global require, __dirname, unescape, console */ - -(function (port) { - 'use strict'; - var path = require('path'), - fs = require('fs'), - // Since Node 0.8, .existsSync() moved from path to fs: - _existsSync = fs.existsSync || path.existsSync, - formidable = require('formidable'), - nodeStatic = require('node-static'), - imageMagick = require('imagemagick'), - options = { - tmpDir: __dirname + '/tmp', - publicDir: __dirname + '/public', - uploadDir: __dirname + '/public/files', - uploadUrl: '/files/', - maxPostSize: 11000000000, // 11 GB - minFileSize: 1, - maxFileSize: 10000000000, // 10 GB - acceptFileTypes: /.+/i, - // Files not matched by this regular expression force a download dialog, - // to prevent executing any scripts in the context of the service domain: - inlineFileTypes: /\.(gif|jpe?g|png)$/i, - imageTypes: /\.(gif|jpe?g|png)$/i, - imageVersions: { - 'thumbnail': { - width: 80, - height: 80 - } - }, - accessControl: { - allowOrigin: '*', - allowMethods: 'OPTIONS, HEAD, GET, POST, PUT, DELETE', - allowHeaders: 'Content-Type, Content-Range, Content-Disposition' - }, - /* Uncomment and edit this section to provide the service via HTTPS: - ssl: { - key: fs.readFileSync('/Applications/XAMPP/etc/ssl.key/server.key'), - cert: fs.readFileSync('/Applications/XAMPP/etc/ssl.crt/server.crt') - }, - */ - nodeStatic: { - cache: 3600 // seconds to cache served files - } - }, - utf8encode = function (str) { - return unescape(encodeURIComponent(str)); - }, - fileServer = new nodeStatic.Server(options.publicDir, options.nodeStatic), - nameCountRegexp = /(?:(?: \(([\d]+)\))?(\.[^.]+))?$/, - nameCountFunc = function (s, index, ext) { - return ' (' + ((parseInt(index, 10) || 0) + 1) + ')' + (ext || ''); - }, - FileInfo = function (file) { - this.name = file.name; - this.size = file.size; - this.type = file.type; - this.deleteType = 'DELETE'; - }, - UploadHandler = function (req, res, callback) { - this.req = req; - this.res = res; - this.callback = callback; - }, - serve = function (req, res) { - res.setHeader( - 'Access-Control-Allow-Origin', - options.accessControl.allowOrigin - ); - res.setHeader( - 'Access-Control-Allow-Methods', - options.accessControl.allowMethods - ); - res.setHeader( - 'Access-Control-Allow-Headers', - options.accessControl.allowHeaders - ); - var handleResult = function (result, redirect) { - if (redirect) { - res.writeHead(302, { - 'Location': redirect.replace( - /%s/, - encodeURIComponent(JSON.stringify(result)) - ) - }); - res.end(); - } else { - res.writeHead(200, { - 'Content-Type': req.headers.accept - .indexOf('application/json') !== -1 ? - 'application/json' : 'text/plain' - }); - res.end(JSON.stringify(result)); - } - }, - setNoCacheHeaders = function () { - res.setHeader('Pragma', 'no-cache'); - res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate'); - res.setHeader('Content-Disposition', 'inline; filename="files.json"'); - }, - handler = new UploadHandler(req, res, handleResult); - switch (req.method) { - case 'OPTIONS': - res.end(); - break; - case 'HEAD': - case 'GET': - if (req.url === '/') { - setNoCacheHeaders(); - if (req.method === 'GET') { - handler.get(); - } else { - res.end(); - } - } else { - fileServer.serve(req, res); - } - break; - case 'POST': - setNoCacheHeaders(); - handler.post(); - break; - case 'DELETE': - handler.destroy(); - break; - default: - res.statusCode = 405; - res.end(); - } - }; - fileServer.respond = function (pathname, status, _headers, files, stat, req, res, finish) { - // Prevent browsers from MIME-sniffing the content-type: - _headers['X-Content-Type-Options'] = 'nosniff'; - if (!options.inlineFileTypes.test(files[0])) { - // Force a download dialog for unsafe file extensions: - _headers['Content-Type'] = 'application/octet-stream'; - _headers['Content-Disposition'] = 'attachment; filename="' + - utf8encode(path.basename(files[0])) + '"'; - } - nodeStatic.Server.prototype.respond - .call(this, pathname, status, _headers, files, stat, req, res, finish); - }; - FileInfo.prototype.validate = function () { - if (options.minFileSize && options.minFileSize > this.size) { - this.error = 'File is too small'; - } else if (options.maxFileSize && options.maxFileSize < this.size) { - this.error = 'File is too big'; - } else if (!options.acceptFileTypes.test(this.name)) { - this.error = 'Filetype not allowed'; - } - return !this.error; - }; - FileInfo.prototype.safeName = function () { - // Prevent directory traversal and creating hidden system files: - this.name = path.basename(this.name).replace(/^\.+/, ''); - // Prevent overwriting existing files: - while (_existsSync(options.uploadDir + '/' + this.name)) { - this.name = this.name.replace(nameCountRegexp, nameCountFunc); - } - }; - FileInfo.prototype.initUrls = function (req) { - if (!this.error) { - var that = this, - baseUrl = (options.ssl ? 'https:' : 'http:') + - '//' + req.headers.host + options.uploadUrl; - this.url = this.deleteUrl = baseUrl + encodeURIComponent(this.name); - Object.keys(options.imageVersions).forEach(function (version) { - if (_existsSync( - options.uploadDir + '/' + version + '/' + that.name - )) { - that[version + 'Url'] = baseUrl + version + '/' + - encodeURIComponent(that.name); - } - }); - } - }; - UploadHandler.prototype.get = function () { - var handler = this, - files = []; - fs.readdir(options.uploadDir, function (err, list) { - list.forEach(function (name) { - var stats = fs.statSync(options.uploadDir + '/' + name), - fileInfo; - if (stats.isFile() && name[0] !== '.') { - fileInfo = new FileInfo({ - name: name, - size: stats.size - }); - fileInfo.initUrls(handler.req); - files.push(fileInfo); - } - }); - handler.callback({files: files}); - }); - }; - UploadHandler.prototype.post = function () { - var handler = this, - form = new formidable.IncomingForm(), - tmpFiles = [], - files = [], - map = {}, - counter = 1, - redirect, - finish = function () { - counter -= 1; - if (!counter) { - files.forEach(function (fileInfo) { - fileInfo.initUrls(handler.req); - }); - handler.callback({files: files}, redirect); - } - }; - form.uploadDir = options.tmpDir; - form.on('fileBegin', function (name, file) { - tmpFiles.push(file.path); - var fileInfo = new FileInfo(file); - fileInfo.safeName(); - map[path.basename(file.path)] = fileInfo; - files.push(fileInfo); - }).on('field', function (name, value) { - if (name === 'redirect') { - redirect = value; - } - }).on('file', function (name, file) { - var fileInfo = map[path.basename(file.path)]; - fileInfo.size = file.size; - if (!fileInfo.validate()) { - fs.unlink(file.path); - return; - } - fs.renameSync(file.path, options.uploadDir + '/' + fileInfo.name); - if (options.imageTypes.test(fileInfo.name)) { - Object.keys(options.imageVersions).forEach(function (version) { - counter += 1; - var opts = options.imageVersions[version]; - imageMagick.resize({ - width: opts.width, - height: opts.height, - srcPath: options.uploadDir + '/' + fileInfo.name, - dstPath: options.uploadDir + '/' + version + '/' + - fileInfo.name - }, finish); - }); - } - }).on('aborted', function () { - tmpFiles.forEach(function (file) { - fs.unlink(file); - }); - }).on('error', function (e) { - console.log(e); - }).on('progress', function (bytesReceived) { - if (bytesReceived > options.maxPostSize) { - handler.req.connection.destroy(); - } - }).on('end', finish).parse(handler.req); - }; - UploadHandler.prototype.destroy = function () { - var handler = this, - fileName; - if (handler.req.url.slice(0, options.uploadUrl.length) === options.uploadUrl) { - fileName = path.basename(decodeURIComponent(handler.req.url)); - if (fileName[0] !== '.') { - fs.unlink(options.uploadDir + '/' + fileName, function (ex) { - Object.keys(options.imageVersions).forEach(function (version) { - fs.unlink(options.uploadDir + '/' + version + '/' + fileName); - }); - handler.callback({success: !ex}); - }); - return; - } - } - handler.callback({success: false}); - }; - if (options.ssl) { - require('https').createServer(options.ssl, serve).listen(port); - } else { - require('http').createServer(serve).listen(port); - } -}(8888)); diff --git a/library/blueimp_upload/server/node/tmp/.gitignore b/library/blueimp_upload/server/node/tmp/.gitignore deleted file mode 100644 index e69de29bb..000000000 --- a/library/blueimp_upload/server/node/tmp/.gitignore +++ /dev/null diff --git a/library/blueimp_upload/server/php/Dockerfile b/library/blueimp_upload/server/php/Dockerfile new file mode 100644 index 000000000..ca88d3d0d --- /dev/null +++ b/library/blueimp_upload/server/php/Dockerfile @@ -0,0 +1,38 @@ +FROM php:7.0-apache + +# Enable the Apache Headers module: +RUN ln -s /etc/apache2/mods-available/headers.load \ + /etc/apache2/mods-enabled/headers.load + +# Enable the Apache Rewrite module: +RUN ln -s /etc/apache2/mods-available/rewrite.load \ + /etc/apache2/mods-enabled/rewrite.load + +# Install GD, Imagick and ImageMagick as image conversion options: +RUN DEBIAN_FRONTEND=noninteractive \ + apt-get update && apt-get install -y --no-install-recommends \ + libpng-dev \ + libjpeg-dev \ + libmagickwand-dev \ + imagemagick \ + && pecl install \ + imagick \ + && docker-php-ext-enable \ + imagick \ + && docker-php-ext-configure \ + gd --with-jpeg-dir=/usr/include/ \ + && docker-php-ext-install \ + gd \ + # Uninstall obsolete packages: + && apt-get autoremove -y \ + libpng-dev \ + libjpeg-dev \ + libmagickwand-dev \ + # Remove obsolete files: + && apt-get clean \ + && rm -rf \ + /tmp/* \ + /usr/share/doc/* \ + /var/cache/* \ + /var/lib/apt/lists/* \ + /var/tmp/* diff --git a/library/blueimp_upload/server/php/UploadHandler.php b/library/blueimp_upload/server/php/UploadHandler.php index fb77be1d0..1380d4739 100755 --- a/library/blueimp_upload/server/php/UploadHandler.php +++ b/library/blueimp_upload/server/php/UploadHandler.php @@ -1,13 +1,13 @@ <?php /* - * jQuery File Upload Plugin PHP Class 8.1.0 + * jQuery File Upload Plugin PHP Class * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ class UploadHandler @@ -40,11 +40,13 @@ class UploadHandler protected $image_objects = array(); - function __construct($options = null, $initialize = true, $error_messages = null) { + public function __construct($options = null, $initialize = true, $error_messages = null) { + $this->response = array(); $this->options = array( - 'script_url' => $this->get_full_url().'/', + 'script_url' => $this->get_full_url().'/'.$this->basename($this->get_server_var('SCRIPT_NAME')), 'upload_dir' => dirname($this->get_server_var('SCRIPT_FILENAME')).'/files/', 'upload_url' => $this->get_full_url().'/files/', + 'input_stream' => 'php://input', 'user_dirs' => false, 'mkdir_mode' => 0755, 'param_name' => 'files', @@ -67,6 +69,14 @@ class UploadHandler 'Content-Range', 'Content-Disposition' ), + // By default, allow redirects to the referer protocol+host: + 'redirect_allow_target' => '/^'.preg_quote( + parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_SCHEME) + .'://' + .parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_HOST) + .'/', // Trailing slash to not match subdomains by mistake + '/' // preg_quote delimiter param + ).'/', // Enable to provide file downloads via GET requests to the PHP script: // 1. Set to 1 to download files via readfile method through PHP // 2. Set to 2 to send a X-Sendfile header for lighttpd/Apache @@ -147,7 +157,8 @@ class UploadHandler 'max_width' => 80, 'max_height' => 80 ) - ) + ), + 'print_response' => true ); if ($options) { $this->options = $options + $this->options; @@ -167,15 +178,15 @@ class UploadHandler $this->head(); break; case 'GET': - $this->get(); + $this->get($this->options['print_response']); break; case 'PATCH': case 'PUT': case 'POST': - $this->post(); + $this->post($this->options['print_response']); break; case 'DELETE': - $this->delete(); + $this->delete($this->options['print_response']); break; default: $this->header('HTTP/1.1 405 Method Not Allowed'); @@ -300,7 +311,7 @@ class UploadHandler $this->get_upload_path($file_name) ); $file->url = $this->get_download_url($file->name); - foreach($this->options['image_versions'] as $version => $options) { + foreach ($this->options['image_versions'] as $version => $options) { if (!empty($version)) { if (is_file($this->get_upload_path($file_name, $version))) { $file->{$version.'Url'} = $this->get_download_url( @@ -332,14 +343,15 @@ class UploadHandler } protected function get_error_message($error) { - return array_key_exists($error, $this->error_messages) ? + return isset($this->error_messages[$error]) ? $this->error_messages[$error] : $error; } - function get_config_bytes($val) { + public function get_config_bytes($val) { $val = trim($val); $last = strtolower($val[strlen($val)-1]); - switch($last) { + $val = (int)$val; + switch ($last) { case 'g': $val *= 1024; case 'm': @@ -355,9 +367,9 @@ class UploadHandler $file->error = $this->get_error_message($error); return false; } - $content_length = $this->fix_integer_overflow(intval( - $this->get_server_var('CONTENT_LENGTH') - )); + $content_length = $this->fix_integer_overflow( + (int)$this->get_server_var('CONTENT_LENGTH') + ); $post_max_size = $this->get_config_bytes(ini_get('post_max_size')); if ($post_max_size && ($content_length > $post_max_size)) { $file->error = $this->get_error_message('post_max_size'); @@ -398,6 +410,21 @@ class UploadHandler if (($max_width || $max_height || $min_width || $min_height) && preg_match($this->options['image_file_types'], $file->name)) { list($img_width, $img_height) = $this->get_image_size($uploaded_file); + + // If we are auto rotating the image by default, do the checks on + // the correct orientation + if ( + @$this->options['image_versions']['']['auto_orient'] && + function_exists('exif_read_data') && + ($exif = @exif_read_data($uploaded_file)) && + (((int) @$exif['Orientation']) >= 5) + ) { + $tmp = $img_width; + $img_width = $img_height; + $img_height = $tmp; + unset($tmp); + } + } if (!empty($img_width)) { if ($max_width && $img_width > $max_width) { @@ -421,7 +448,7 @@ class UploadHandler } protected function upcount_name_callback($matches) { - $index = isset($matches[1]) ? intval($matches[1]) + 1 : 1; + $index = isset($matches[1]) ? ((int)$matches[1]) + 1 : 1; $ext = isset($matches[2]) ? $matches[2] : ''; return ' ('.$index.')'.$ext; } @@ -441,8 +468,8 @@ class UploadHandler $name = $this->upcount_name($name); } // Keep an existing filename if this is part of a chunked upload: - $uploaded_bytes = $this->fix_integer_overflow(intval($content_range[1])); - while(is_file($this->get_upload_path($name))) { + $uploaded_bytes = $this->fix_integer_overflow((int)$content_range[1]); + while (is_file($this->get_upload_path($name))) { if ($uploaded_bytes === $this->get_file_size( $this->get_upload_path($name))) { break; @@ -461,7 +488,7 @@ class UploadHandler } if ($this->options['correct_image_extensions'] && function_exists('exif_imagetype')) { - switch(@exif_imagetype($file_path)){ + switch (@exif_imagetype($file_path)){ case IMAGETYPE_JPEG: $extensions = array('jpg', 'jpeg'); break; @@ -491,7 +518,7 @@ class UploadHandler // Remove path information and dots around the filename, to prevent uploading // into different directories or replacing hidden system files. // Also remove control characters and spaces (\x00..\x20) around the filename: - $name = trim(basename(stripslashes($name)), ".\x00..\x20"); + $name = trim($this->basename(stripslashes($name)), ".\x00..\x20"); // Use a timestamp for empty filenames: if (!$name) { $name = str_replace('.', '-', microtime(true)); @@ -515,10 +542,6 @@ class UploadHandler ); } - protected function handle_form_data($file, $index) { - // Handle form data, e.g. $_REQUEST['description'][$index] - } - protected function get_scaled_image_file_paths($file_name, $version) { $file_path = $this->get_upload_path($file_name); if (!empty($version)) { @@ -601,7 +624,7 @@ class UploadHandler if ($exif === false) { return false; } - $orientation = intval(@$exif['Orientation']); + $orientation = (int)@$exif['Orientation']; if ($orientation < 2 || $orientation > 8) { return false; } @@ -825,7 +848,7 @@ class UploadHandler $this->get_scaled_image_file_paths($file_name, $version); $image = $this->imagick_get_image_object( $file_path, - !empty($options['no_cache']) + !empty($options['crop']) || !empty($options['no_cache']) ); if ($image->getImageFormat() === 'GIF') { // Handle animated GIFs: @@ -955,7 +978,7 @@ class UploadHandler return $dimensions; } return false; - } catch (Exception $e) { + } catch (\Exception $e) { error_log($e->getMessage()); } } @@ -965,7 +988,7 @@ class UploadHandler exec($cmd, $output, $error); if (!$error && !empty($output)) { // image.jpg JPEG 1920x1080 1920x1080+0+0 8-bit sRGB 465KB 0.000u 0:00.000 - $infos = preg_split('/\s+/', $output[0]); + $infos = preg_split('/\s+/', substr($output[0], strlen($file_path))); $dimensions = preg_split('/x/', $infos[2]); return $dimensions; } @@ -1008,7 +1031,7 @@ class UploadHandler protected function handle_image_file($file_path, $file) { $failed_versions = array(); - foreach($this->options['image_versions'] as $version => $options) { + foreach ($this->options['image_versions'] as $version => $options) { if ($this->create_scaled_image($file->name, $version, $options)) { if (!empty($version)) { $file->{$version.'Url'} = $this->get_download_url( @@ -1024,7 +1047,7 @@ class UploadHandler } if (count($failed_versions)) { $file->error = $this->get_error_message('image_resize') - .' ('.implode($failed_versions,', ').')'; + .' ('.implode($failed_versions, ', ').')'; } // Free memory: $this->destroy_image_object($file_path); @@ -1035,7 +1058,7 @@ class UploadHandler $file = new \stdClass(); $file->name = $this->get_file_name($uploaded_file, $name, $size, $type, $error, $index, $content_range); - $file->size = $this->fix_integer_overflow(intval($size)); + $file->size = $this->fix_integer_overflow((int)$size); $file->type = $type; if ($this->validate($uploaded_file, $file, $error, $index)) { $this->handle_form_data($file, $index); @@ -1061,7 +1084,7 @@ class UploadHandler // Non-multipart uploads (PUT method support) file_put_contents( $file_path, - fopen('php://input', 'r'), + fopen($this->options['input_stream'], 'r'), $append_file ? FILE_APPEND : 0 ); } @@ -1102,41 +1125,33 @@ class UploadHandler protected function body($str) { echo $str; } - + protected function header($str) { header($str); } + protected function get_upload_data($id) { + return @$_FILES[$id]; + } + + protected function get_post_param($id) { + return @$_POST[$id]; + } + + protected function get_query_param($id) { + return @$_GET[$id]; + } + protected function get_server_var($id) { - return isset($_SERVER[$id]) ? $_SERVER[$id] : ''; + return @$_SERVER[$id]; } - protected function generate_response($content, $print_response = true) { - if ($print_response) { - $json = json_encode($content); - $redirect = isset($_REQUEST['redirect']) ? - stripslashes($_REQUEST['redirect']) : null; - if ($redirect) { - $this->header('Location: '.sprintf($redirect, rawurlencode($json))); - return; - } - $this->head(); - if ($this->get_server_var('HTTP_CONTENT_RANGE')) { - $files = isset($content[$this->options['param_name']]) ? - $content[$this->options['param_name']] : null; - if ($files && is_array($files) && is_object($files[0]) && $files[0]->size) { - $this->header('Range: 0-'.( - $this->fix_integer_overflow(intval($files[0]->size)) - 1 - )); - } - } - $this->body($json); - } - return $content; + protected function handle_form_data($file, $index) { + // Handle form data, e.g. $_POST['description'][$index] } protected function get_version_param() { - return isset($_GET['version']) ? basename(stripslashes($_GET['version'])) : null; + return $this->basename(stripslashes($this->get_query_param('version'))); } protected function get_singular_param_name() { @@ -1145,14 +1160,16 @@ class UploadHandler protected function get_file_name_param() { $name = $this->get_singular_param_name(); - return isset($_REQUEST[$name]) ? basename(stripslashes($_REQUEST[$name])) : null; + return $this->basename(stripslashes($this->get_query_param($name))); } protected function get_file_names_params() { - $params = isset($_REQUEST[$this->options['param_name']]) ? - $_REQUEST[$this->options['param_name']] : array(); + $params = $this->get_query_param($this->options['param_name']); + if (!$params) { + return null; + } foreach ($params as $key => $value) { - $params[$key] = basename(stripslashes($value)); + $params[$key] = $this->basename(stripslashes($value)); } return $params; } @@ -1232,6 +1249,34 @@ class UploadHandler .implode(', ', $this->options['access_control_allow_headers'])); } + public function generate_response($content, $print_response = true) { + $this->response = $content; + if ($print_response) { + $json = json_encode($content); + $redirect = stripslashes($this->get_post_param('redirect')); + if ($redirect && preg_match($this->options['redirect_allow_target'], $redirect)) { + $this->header('Location: '.sprintf($redirect, rawurlencode($json))); + return; + } + $this->head(); + if ($this->get_server_var('HTTP_CONTENT_RANGE')) { + $files = isset($content[$this->options['param_name']]) ? + $content[$this->options['param_name']] : null; + if ($files && is_array($files) && is_object($files[0]) && $files[0]->size) { + $this->header('Range: 0-'.( + $this->fix_integer_overflow((int)$files[0]->size) - 1 + )); + } + } + $this->body($json); + } + return $content; + } + + public function get_response () { + return $this->response; + } + public function head() { $this->header('Pragma: no-cache'); $this->header('Cache-Control: no-store, no-cache, must-revalidate'); @@ -1245,7 +1290,7 @@ class UploadHandler } public function get($print_response = true) { - if ($print_response && isset($_GET['download'])) { + if ($print_response && $this->get_query_param('download')) { return $this->download(); } $file_name = $this->get_file_name_param(); @@ -1262,58 +1307,59 @@ class UploadHandler } public function post($print_response = true) { - if (isset($_REQUEST['_method']) && $_REQUEST['_method'] === 'DELETE') { + if ($this->get_query_param('_method') === 'DELETE') { return $this->delete($print_response); } - $upload = isset($_FILES[$this->options['param_name']]) ? - $_FILES[$this->options['param_name']] : null; + $upload = $this->get_upload_data($this->options['param_name']); // Parse the Content-Disposition header, if available: - $file_name = $this->get_server_var('HTTP_CONTENT_DISPOSITION') ? + $content_disposition_header = $this->get_server_var('HTTP_CONTENT_DISPOSITION'); + $file_name = $content_disposition_header ? rawurldecode(preg_replace( '/(^[^"]+")|("$)/', '', - $this->get_server_var('HTTP_CONTENT_DISPOSITION') + $content_disposition_header )) : null; // Parse the Content-Range header, which has the following form: // Content-Range: bytes 0-524287/2000000 - $content_range = $this->get_server_var('HTTP_CONTENT_RANGE') ? - preg_split('/[^0-9]+/', $this->get_server_var('HTTP_CONTENT_RANGE')) : null; + $content_range_header = $this->get_server_var('HTTP_CONTENT_RANGE'); + $content_range = $content_range_header ? + preg_split('/[^0-9]+/', $content_range_header) : null; $size = $content_range ? $content_range[3] : null; $files = array(); - if ($upload && is_array($upload['tmp_name'])) { - // param_name is an array identifier like "files[]", - // $_FILES is a multi-dimensional array: - foreach ($upload['tmp_name'] as $index => $value) { + if ($upload) { + if (is_array($upload['tmp_name'])) { + // param_name is an array identifier like "files[]", + // $upload is a multi-dimensional array: + foreach ($upload['tmp_name'] as $index => $value) { + $files[] = $this->handle_file_upload( + $upload['tmp_name'][$index], + $file_name ? $file_name : $upload['name'][$index], + $size ? $size : $upload['size'][$index], + $upload['type'][$index], + $upload['error'][$index], + $index, + $content_range + ); + } + } else { + // param_name is a single object identifier like "file", + // $upload is a one-dimensional array: $files[] = $this->handle_file_upload( - $upload['tmp_name'][$index], - $file_name ? $file_name : $upload['name'][$index], - $size ? $size : $upload['size'][$index], - $upload['type'][$index], - $upload['error'][$index], - $index, + isset($upload['tmp_name']) ? $upload['tmp_name'] : null, + $file_name ? $file_name : (isset($upload['name']) ? + $upload['name'] : null), + $size ? $size : (isset($upload['size']) ? + $upload['size'] : $this->get_server_var('CONTENT_LENGTH')), + isset($upload['type']) ? + $upload['type'] : $this->get_server_var('CONTENT_TYPE'), + isset($upload['error']) ? $upload['error'] : null, + null, $content_range ); } - } else { - // param_name is a single object identifier like "file", - // $_FILES is a one-dimensional array: - $files[] = $this->handle_file_upload( - isset($upload['tmp_name']) ? $upload['tmp_name'] : null, - $file_name ? $file_name : (isset($upload['name']) ? - $upload['name'] : null), - $size ? $size : (isset($upload['size']) ? - $upload['size'] : $this->get_server_var('CONTENT_LENGTH')), - isset($upload['type']) ? - $upload['type'] : $this->get_server_var('CONTENT_TYPE'), - isset($upload['error']) ? $upload['error'] : null, - null, - $content_range - ); } - return $this->generate_response( - array($this->options['param_name'] => $files), - $print_response - ); + $response = array($this->options['param_name'] => $files); + return $this->generate_response($response, $print_response); } public function delete($print_response = true) { @@ -1322,11 +1368,11 @@ class UploadHandler $file_names = array($this->get_file_name_param()); } $response = array(); - foreach($file_names as $file_name) { + foreach ($file_names as $file_name) { $file_path = $this->get_upload_path($file_name); $success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path); if ($success) { - foreach($this->options['image_versions'] as $version => $options) { + foreach ($this->options['image_versions'] as $version => $options) { if (!empty($version)) { $file = $this->get_upload_path($file_name, $version); if (is_file($file)) { @@ -1340,4 +1386,8 @@ class UploadHandler return $this->generate_response($response, $print_response); } + protected function basename($filepath, $suffix = null) { + $splited = preg_split('/\//', rtrim ($filepath, '/ ')); + return substr(basename('X'.$splited[count($splited)-1], $suffix), 1); + } } diff --git a/library/blueimp_upload/server/php/docker-compose.yml b/library/blueimp_upload/server/php/docker-compose.yml new file mode 100644 index 000000000..691ea9caa --- /dev/null +++ b/library/blueimp_upload/server/php/docker-compose.yml @@ -0,0 +1,6 @@ +apache: + build: ./ + ports: + - "80:80" + volumes: + - "../../:/var/www/html" diff --git a/library/blueimp_upload/server/php/files/.htaccess b/library/blueimp_upload/server/php/files/.htaccess index 56689f0bb..6f454afb9 100644 --- a/library/blueimp_upload/server/php/files/.htaccess +++ b/library/blueimp_upload/server/php/files/.htaccess @@ -1,8 +1,16 @@ -# The following directives force the content-type application/octet-stream -# and force browsers to display a download dialog for non-image files. -# This prevents the execution of script files in the context of the website: +# To enable the Headers module, execute the following command and reload Apache: +# sudo a2enmod headers + +# The following directives prevent the execution of script files +# in the context of the website. +# They also force the content-type application/octet-stream and +# force browsers to display a download dialog for non-image files. +SetHandler default-handler ForceType application/octet-stream Header set Content-Disposition attachment + +# The following unsets the forced type and Content-Disposition headers +# for known image files: <FilesMatch "(?i)\.(gif|jpe?g|png)$"> ForceType none Header unset Content-Disposition diff --git a/library/blueimp_upload/server/php/index.php b/library/blueimp_upload/server/php/index.php index 3ae1295ef..6caabb710 100644 --- a/library/blueimp_upload/server/php/index.php +++ b/library/blueimp_upload/server/php/index.php @@ -1,13 +1,13 @@ <?php /* - * jQuery File Upload Plugin PHP Example 5.14 + * jQuery File Upload Plugin PHP Example * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ error_reporting(E_ALL | E_STRICT); diff --git a/library/blueimp_upload/test/index.html b/library/blueimp_upload/test/index.html index a04e53433..4a9a6f328 100644 --- a/library/blueimp_upload/test/index.html +++ b/library/blueimp_upload/test/index.html @@ -1,14 +1,14 @@ <!DOCTYPE HTML> <!-- /* - * jQuery File Upload Plugin Test 9.1.0 + * jQuery File Upload Plugin Test * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ --> <html lang="en"> @@ -20,7 +20,7 @@ <meta charset="utf-8"> <title>jQuery File Upload Plugin Test</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> -<link rel="stylesheet" href="http://codeorigin.jquery.com/qunit/qunit-1.14.0.css"> +<link rel="stylesheet" href="//codeorigin.jquery.com/qunit/qunit-1.14.0.css"> </head> <body> <h1 id="qunit-header">jQuery File Upload Plugin Test</h1> @@ -36,20 +36,20 @@ <div class="col-lg-7"> <!-- The fileinput-button span is used to style the file input field as button --> <span class="btn btn-success fileinput-button"> - <i class="fa-plus fa fa-inverse"></i> + <i class="icon-plus icon-white"></i> <span>Add files...</span> <input type="file" name="files[]" multiple> </span> <button type="submit" class="btn btn-primary start"> - <i class="fa-arrow-circle-o-up fa fa-inverse"></i> + <i class="icon-upload icon-white"></i> <span>Start upload</span> </button> <button type="reset" class="btn btn-warning cancel"> - <i class="fa-ban fa fa-inverse"></i> + <i class="icon-ban-circle icon-white"></i> <span>Cancel upload</span> </button> <button type="button" class="btn btn-danger delete"> - <i class="fa-trash-o fa fa-inverse"></i> + <i class="icon-trash icon-white"></i> <span>Delete</span> </button> <input type="checkbox" class="toggle"> @@ -168,5 +168,5 @@ window.testUIWidget = $.blueimp.fileupload; </script> <script src="//code.jquery.com/qunit/qunit-1.15.0.js"></script> <script src="test.js"></script> -</body> +</body> </html> diff --git a/library/blueimp_upload/test/test.js b/library/blueimp_upload/test/test.js index 72d08d99e..452127567 100644 --- a/library/blueimp_upload/test/test.js +++ b/library/blueimp_upload/test/test.js @@ -1,12 +1,12 @@ /* - * jQuery File Upload Plugin Test 9.4.0 + * jQuery File Upload Plugin Test * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ /* global $, QUnit, window, document, expect, module, test, asyncTest, start, ok, strictEqual, notStrictEqual */ @@ -83,7 +83,7 @@ $(function () { }); test('Paste zone initialization', function () { - ok($('#fileupload').fileupload() + ok($('#fileupload').fileupload({pasteZone: document}) .fileupload('option', 'pasteZone').length); }); @@ -98,6 +98,7 @@ $(function () { } }, fu = $('#fileupload').fileupload({ + pasteZone: document, dragover: function () { ok(true, 'Triggers dragover callback'); return false; @@ -135,6 +136,7 @@ $(function () { } }, options = { + pasteZone: document, dragover: function () { ok(true, 'Triggers dragover callback'); return false; @@ -178,6 +180,7 @@ $(function () { } }, fu = $('#fileupload').fileupload({ + pasteZone: document, dragover: function () { ok(true, 'Triggers dragover callback'); return false; @@ -221,6 +224,7 @@ $(function () { } }, fu = $('#fileupload').fileupload({ + pasteZone: document, dragover: function () { ok(true, 'Triggers dragover callback'); return false; diff --git a/library/oauth2/.gitignore b/library/oauth2/.gitignore deleted file mode 100644 index c43a667d4..000000000 --- a/library/oauth2/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Test Files # -test/config/test.sqlite -vendor -composer.lock -.idea diff --git a/library/oauth2/.travis.yml b/library/oauth2/.travis.yml deleted file mode 100644 index dd4aae4a6..000000000 --- a/library/oauth2/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -language: php -sudo: false -cache: - directories: - - $HOME/.composer/cache - - vendor -php: -- 5.3 -- 5.4 -- 5.5 -- 5.6 -- 7 -- hhvm -env: - global: - - SKIP_MONGO_TESTS=1 - - secure: Bc5ZqvZ1YYpoPZNNuU2eCB8DS6vBYrAdfBtTenBs5NSxzb+Vjven4kWakbzaMvZjb/Ib7Uph7DGuOtJXpmxnvBXPLd707LZ89oFWN/yqQlZKCcm8iErvJCB5XL+/ONHj2iPdR242HJweMcat6bMCwbVWoNDidjtWMH0U2mYFy3M= - - secure: R3bXlymyFiY2k2jf7+fv/J8i34wtXTkmD4mCr5Ps/U+vn9axm2VtvR2Nj+r7LbRjn61gzFE/xIVjYft/wOyBOYwysrfriydrnRVS0owh6y+7EyOyQWbRX11vVQMf8o31QCQE5BY58V5AJZW3MjoOL0FVlTgySJiJvdw6Pv18v+E= -services: -- mongodb -- redis-server -- cassandra -before_install: -- phpenv config-rm xdebug.ini || return 0 -install: -- composer install --no-interaction -before_script: -- psql -c 'create database oauth2_server_php;' -U postgres -after_script: -- php test/cleanup.php diff --git a/library/oauth2/CHANGELOG.md b/library/oauth2/CHANGELOG.md deleted file mode 100644 index 03d925e06..000000000 --- a/library/oauth2/CHANGELOG.md +++ /dev/null @@ -1,152 +0,0 @@ -CHANGELOG for 1.x -================= - -This changelog references the relevant changes (bug and security fixes) done -in 1.x minor versions. - -To see the files changed for a given bug, go to https://github.com/bshaffer/oauth2-server-php/issues/### where ### is the bug number -To get the diff between two versions, go to https://github.com/bshaffer/oauth2-server-php/compare/v1.0...v1.1 -To get the diff for a specific change, go to https://github.com/bshaffer/oauth2-server-php/commit/XXX where XXX is the change hash - -* 1.8.0 (2015-09-18) - - PR: https://github.com/bshaffer/oauth2-server-php/pull/643 - - * bug #594 - adds jti - * bug #598 - fixes lifetime configurations for JWTs - * bug #634 - fixes travis builds, upgrade to containers - * bug #586 - support for revoking tokens - * bug #636 - Adds FirebaseJWT bridge - * bug #639 - Mongo HHVM compatibility - -* 1.7.0 (2015-04-23) - - PR: https://github.com/bshaffer/oauth2-server-php/pull/572 - - * bug #500 - PDO fetch mode changed from FETCH_BOTH to FETCH_ASSOC - * bug #508 - Case insensitive for Bearer token header name ba716d4 - * bug #512 - validateRedirectUri is now public - * bug #530 - Add PublicKeyInterface, UserClaimsInterface to Cassandra Storage - * bug #505 - DynamoDB storage fixes - * bug #556 - adds "code id_token" return type to openid connect - * bug #563 - Include "issuer" config key for JwtAccessToken - * bug #564 - Fixes JWT vulnerability - * bug #571 - Added unset_refresh_token_after_use option - -* 1.6 (2015-01-16) - - PR: https://github.com/bshaffer/oauth2-server-php/pull/496 - - * bug 437 - renames CryptoToken to JwtAccessToken / use_crypto_tokens to use_jwt_access_tokens - * bug 447 - Adds a Couchbase storage implementation - * bug 460 - Rename JWT claims to match spec - * bug 470 - order does not matter for multi-valued response types - * bug 471 - Make validateAuthorizeRequest available for POST in addition to GET - * bug 475 - Adds JTI table definitiion - * bug 481 - better randomness for generating access tokens - * bug 480 - Use hash_equals() for signature verification (prevents remote timing attacks) - * bugs 489, 491, 498 - misc other fixes - -* 1.5 (2014-08-27) - - PR: https://github.com/bshaffer/oauth2-server-php/pull/446 - - * bug #399 - Add DynamoDB Support - * bug #404 - renamed error name for malformed/expired tokens - * bug #412 - Openid connect: fixes for claims with more than one scope / Add support for the prompt parameter ('consent' and 'none') - * bug #411 - fixes xml output - * bug #413 - fixes invalid format error - * bug #401 - fixes code standards / whitespace - * bug #354 - bundles PDO SQL with the library - * [BC] bug #397 - refresh tokens should not be encrypted - * bug #423 - makes "scope" optional for refresh token storage - -* 1.4 (2014-06-12) - - PR: https://github.com/bshaffer/oauth2-server-php/pull/392 - - * bug #189 Storage\PDO - allows DSN string in constructor - * bug #233 Bearer Tokens - allows token in request body for PUT requests - * bug #346 Fixes open_basedir warning - * bug #351 Adds OpenID Connect support - * bug #355 Adds php 5.6 and HHVM to travis.ci testing - * [BC] bug #358 Adds `getQuerystringIdentifier()` to the GrantType interface - * bug #363 Encryption\JWT - Allows for subclassing JWT Headers - * bug #349 Bearer Tokens - adds requestHasToken method for when access tokens are optional - * bug #301 Encryption\JWT - fixes urlSafeB64Encode(): ensures newlines are replaced as expected - * bug #323 ResourceController - client_id is no longer required to be returned when calling getAccessToken - * bug #367 Storage\PDO - adds Postgres support - * bug #368 Access Tokens - use mcrypt_create_iv or openssl_random_pseudo_bytes to create token string - * bug #376 Request - allows case insensitive headers - * bug #384 Storage\PDO - can pass in PDO options in constructor of PDO storage - * misc fixes #361, #292, #373, #374, #379, #396 -* 1.3 (2014-02-27) - - PR: https://github.com/bshaffer/oauth2-server-php/pull/325 - - * bug #311 adds cassandra storage - * bug #298 fixes response code for user credentials grant type - * bug #318 adds 'use_crypto_tokens' config to Server class for better DX - * [BC] bug #320 pass client_id to getDefaultScope - * bug #324 better feedback when running tests - * bug #335 adds support for non-expiring refresh tokens - * bug #333 fixes Pdo storage for getClientKey - * bug #336 fixes Redis storage for expireAuthorizationCode - -* 1.2 (2014-01-03) - - PR: https://github.com/bshaffer/oauth2-server-php/pull/288 - - * bug #285 changed response header from 200 to 401 when empty token received - * bug #286 adds documentation and links to spec for not including error messages when no token is supplied - * bug #280 ensures PHP warnings do not get thrown as a result of an invalid argument to $jwt->decode() - * bug #279 predis wrong number of arguments - * bug #277 Securing JS WebApp client secret w/ password grant type - -* 1.1 (2013-12-17) - - PR: https://github.com/bshaffer/oauth2-server-php/pull/276 - - * bug #278 adds refresh token configuration to Server class - * bug #274 Supplying a null client_id and client_secret grants API access - * bug #244 [MongoStorage] More detailed implementation info - * bug #268 Implement jti for JWT Bearer tokens to prevent replay attacks. - * bug #266 Removing unused argument to getAccessTokenData - * bug #247 Make Bearer token type consistent - * bug #253 Fixing CryptoToken refresh token lifetime - * bug #246 refactors public key logic to be more intuitive - * bug #245 adds support for JSON crypto tokens - * bug #230 Remove unused columns in oauth_clients - * bug #215 makes Redis Scope Storage obey the same paradigm as PDO - * bug #228 removes scope group - * bug #227 squelches open basedir restriction error - * bug #223 Updated docblocks for RefreshTokenInterface.php - * bug #224 Adds protected properties - * bug #217 Implement ScopeInterface for PDO, Redis - -* 1.0 (2013-08-12) - - * bug #203 Add redirect\_status_code config param for AuthorizeController - * bug #205 ensures unnecessary ? is not set when ** bug - * bug #204 Fixed call to LogicException - * bug #202 Add explode to checkRestrictedGrant in PDO Storage - * bug #197 adds support for 'false' default scope ** bug - * bug #192 reference errors and adds tests - * bug #194 makes some appropriate properties ** bug - * bug #191 passes config to HttpBasic - * bug #190 validates client credentials before ** bug - * bug #171 Fix wrong redirect following authorization step - * bug #187 client_id is now passed to getDefaultScope(). - * bug #176 Require refresh_token in getRefreshToken response - * bug #174 make user\_id not required for refresh_token grant - * bug #173 Duplication in JwtBearer Grant - * bug #168 user\_id not required for authorization_code grant - * bug #133 hardens default security for user object - * bug #163 allows redirect\_uri on authorization_code to be NULL in docs example - * bug #162 adds getToken on ResourceController for convenience - * bug #161 fixes fatal error - * bug #163 Invalid redirect_uri handling - * bug #156 user\_id in OAuth2\_Storage_AuthorizationCodeInterface::getAuthorizationCode() response - * bug #157 Fix for extending access and refresh tokens - * bug #154 ResponseInterface: getParameter method is used in the library but not defined in the interface - * bug #148 Add more detail to examples in Readme.md diff --git a/library/oauth2/LICENSE b/library/oauth2/LICENSE deleted file mode 100644 index d7ece8467..000000000 --- a/library/oauth2/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License - -Copyright (c) 2014 Brent Shaffer - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/library/oauth2/README.md b/library/oauth2/README.md deleted file mode 100644 index 4ceda6cf9..000000000 --- a/library/oauth2/README.md +++ /dev/null @@ -1,8 +0,0 @@ -oauth2-server-php -================= - -[![Build Status](https://travis-ci.org/bshaffer/oauth2-server-php.svg?branch=develop)](https://travis-ci.org/bshaffer/oauth2-server-php) - -[![Total Downloads](https://poser.pugx.org/bshaffer/oauth2-server-php/downloads.png)](https://packagist.org/packages/bshaffer/oauth2-server-php) - -View the [complete documentation](http://bshaffer.github.io/oauth2-server-php-docs/)
\ No newline at end of file diff --git a/library/oauth2/phpunit.xml b/library/oauth2/phpunit.xml deleted file mode 100644 index e36403f0a..000000000 --- a/library/oauth2/phpunit.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<phpunit backupGlobals="false" - backupStaticAttributes="false" - colors="true" - convertErrorsToExceptions="true" - convertNoticesToExceptions="true" - convertWarningsToExceptions="true" - processIsolation="false" - stopOnFailure="false" - syntaxCheck="false" - bootstrap="test/bootstrap.php" -> - <testsuites> - <testsuite name="Oauth2 Test Suite"> - <directory>./test/OAuth2/</directory> - </testsuite> - </testsuites> - - <filter> - <whitelist> - <directory suffix=".php">./src/OAuth2/</directory> - </whitelist> - </filter> -</phpunit> diff --git a/library/oauth2/src/OAuth2/Autoloader.php b/library/oauth2/src/OAuth2/Autoloader.php deleted file mode 100644 index ecfb6ba75..000000000 --- a/library/oauth2/src/OAuth2/Autoloader.php +++ /dev/null @@ -1,48 +0,0 @@ -<?php - -namespace OAuth2; - -/** - * Autoloads OAuth2 classes - * - * @author Brent Shaffer <bshafs at gmail dot com> - * @license MIT License - */ -class Autoloader -{ - private $dir; - - public function __construct($dir = null) - { - if (is_null($dir)) { - $dir = dirname(__FILE__).'/..'; - } - $this->dir = $dir; - } - /** - * Registers OAuth2\Autoloader as an SPL autoloader. - */ - public static function register($dir = null) - { - ini_set('unserialize_callback_func', 'spl_autoload_call'); - spl_autoload_register(array(new self($dir), 'autoload')); - } - - /** - * Handles autoloading of classes. - * - * @param string $class A class name. - * - * @return boolean Returns true if the class has been loaded - */ - public function autoload($class) - { - if (0 !== strpos($class, 'OAuth2')) { - return; - } - - if (file_exists($file = $this->dir.'/'.str_replace('\\', '/', $class).'.php')) { - require $file; - } - } -} diff --git a/library/oauth2/src/OAuth2/ClientAssertionType/ClientAssertionTypeInterface.php b/library/oauth2/src/OAuth2/ClientAssertionType/ClientAssertionTypeInterface.php deleted file mode 100644 index 29c7171b5..000000000 --- a/library/oauth2/src/OAuth2/ClientAssertionType/ClientAssertionTypeInterface.php +++ /dev/null @@ -1,15 +0,0 @@ -<?php - -namespace OAuth2\ClientAssertionType; - -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -/** - * Interface for all OAuth2 Client Assertion Types - */ -interface ClientAssertionTypeInterface -{ - public function validateRequest(RequestInterface $request, ResponseInterface $response); - public function getClientId(); -} diff --git a/library/oauth2/src/OAuth2/ClientAssertionType/HttpBasic.php b/library/oauth2/src/OAuth2/ClientAssertionType/HttpBasic.php deleted file mode 100644 index 0ecb7e18d..000000000 --- a/library/oauth2/src/OAuth2/ClientAssertionType/HttpBasic.php +++ /dev/null @@ -1,123 +0,0 @@ -<?php - -namespace OAuth2\ClientAssertionType; - -use OAuth2\Storage\ClientCredentialsInterface; -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -/** - * Validate a client via Http Basic authentication - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -class HttpBasic implements ClientAssertionTypeInterface -{ - private $clientData; - - protected $storage; - protected $config; - - /** - * @param OAuth2\Storage\ClientCredentialsInterface $clientStorage REQUIRED Storage class for retrieving client credentials information - * @param array $config OPTIONAL Configuration options for the server - * <code> - * $config = array( - * 'allow_credentials_in_request_body' => true, // whether to look for credentials in the POST body in addition to the Authorize HTTP Header - * 'allow_public_clients' => true // if true, "public clients" (clients without a secret) may be authenticated - * ); - * </code> - */ - public function __construct(ClientCredentialsInterface $storage, array $config = array()) - { - $this->storage = $storage; - $this->config = array_merge(array( - 'allow_credentials_in_request_body' => true, - 'allow_public_clients' => true, - ), $config); - } - - public function validateRequest(RequestInterface $request, ResponseInterface $response) - { - if (!$clientData = $this->getClientCredentials($request, $response)) { - return false; - } - - if (!isset($clientData['client_id'])) { - throw new \LogicException('the clientData array must have "client_id" set'); - } - - if (!isset($clientData['client_secret']) || $clientData['client_secret'] == '') { - if (!$this->config['allow_public_clients']) { - $response->setError(400, 'invalid_client', 'client credentials are required'); - - return false; - } - - if (!$this->storage->isPublicClient($clientData['client_id'])) { - $response->setError(400, 'invalid_client', 'This client is invalid or must authenticate using a client secret'); - - return false; - } - } elseif ($this->storage->checkClientCredentials($clientData['client_id'], $clientData['client_secret']) === false) { - $response->setError(400, 'invalid_client', 'The client credentials are invalid'); - - return false; - } - - $this->clientData = $clientData; - - return true; - } - - public function getClientId() - { - return $this->clientData['client_id']; - } - - /** - * Internal function used to get the client credentials from HTTP basic - * auth or POST data. - * - * According to the spec (draft 20), the client_id can be provided in - * the Basic Authorization header (recommended) or via GET/POST. - * - * @return - * A list containing the client identifier and password, for example - * @code - * return array( - * "client_id" => CLIENT_ID, // REQUIRED the client id - * "client_secret" => CLIENT_SECRET, // OPTIONAL the client secret (may be omitted for public clients) - * ); - * @endcode - * - * @see http://tools.ietf.org/html/rfc6749#section-2.3.1 - * - * @ingroup oauth2_section_2 - */ - public function getClientCredentials(RequestInterface $request, ResponseInterface $response = null) - { - if (!is_null($request->headers('PHP_AUTH_USER')) && !is_null($request->headers('PHP_AUTH_PW'))) { - return array('client_id' => $request->headers('PHP_AUTH_USER'), 'client_secret' => $request->headers('PHP_AUTH_PW')); - } - - if ($this->config['allow_credentials_in_request_body']) { - // Using POST for HttpBasic authorization is not recommended, but is supported by specification - if (!is_null($request->request('client_id'))) { - /** - * client_secret can be null if the client's password is an empty string - * @see http://tools.ietf.org/html/rfc6749#section-2.3.1 - */ - - return array('client_id' => $request->request('client_id'), 'client_secret' => $request->request('client_secret')); - } - } - - if ($response) { - $message = $this->config['allow_credentials_in_request_body'] ? ' or body' : ''; - $response->setError(400, 'invalid_client', 'Client credentials were not found in the headers'.$message); - } - - return null; - } -} diff --git a/library/oauth2/src/OAuth2/Controller/AuthorizeController.php b/library/oauth2/src/OAuth2/Controller/AuthorizeController.php deleted file mode 100644 index a9a722587..000000000 --- a/library/oauth2/src/OAuth2/Controller/AuthorizeController.php +++ /dev/null @@ -1,388 +0,0 @@ -<?php - -namespace OAuth2\Controller; - -use OAuth2\Storage\ClientInterface; -use OAuth2\ScopeInterface; -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; -use OAuth2\Scope; - -/** - * @see OAuth2\Controller\AuthorizeControllerInterface - */ -class AuthorizeController implements AuthorizeControllerInterface -{ - private $scope; - private $state; - private $client_id; - private $redirect_uri; - private $response_type; - - protected $clientStorage; - protected $responseTypes; - protected $config; - protected $scopeUtil; - - /** - * @param OAuth2\Storage\ClientInterface $clientStorage REQUIRED Instance of OAuth2\Storage\ClientInterface to retrieve client information - * @param array $responseTypes OPTIONAL Array of OAuth2\ResponseType\ResponseTypeInterface objects. Valid array - * keys are "code" and "token" - * @param array $config OPTIONAL Configuration options for the server - * <code> - * $config = array( - * 'allow_implicit' => false, // if the controller should allow the "implicit" grant type - * 'enforce_state' => true // if the controller should require the "state" parameter - * 'require_exact_redirect_uri' => true, // if the controller should require an exact match on the "redirect_uri" parameter - * 'redirect_status_code' => 302, // HTTP status code to use for redirect responses - * ); - * </code> - * @param OAuth2\ScopeInterface $scopeUtil OPTIONAL Instance of OAuth2\ScopeInterface to validate the requested scope - */ - public function __construct(ClientInterface $clientStorage, array $responseTypes = array(), array $config = array(), ScopeInterface $scopeUtil = null) - { - $this->clientStorage = $clientStorage; - $this->responseTypes = $responseTypes; - $this->config = array_merge(array( - 'allow_implicit' => false, - 'enforce_state' => true, - 'require_exact_redirect_uri' => true, - 'redirect_status_code' => 302, - ), $config); - - if (is_null($scopeUtil)) { - $scopeUtil = new Scope(); - } - $this->scopeUtil = $scopeUtil; - } - - public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null) - { - if (!is_bool($is_authorized)) { - throw new \InvalidArgumentException('Argument "is_authorized" must be a boolean. This method must know if the user has granted access to the client.'); - } - - // We repeat this, because we need to re-validate. The request could be POSTed - // by a 3rd-party (because we are not internally enforcing NONCEs, etc) - if (!$this->validateAuthorizeRequest($request, $response)) { - return; - } - - // If no redirect_uri is passed in the request, use client's registered one - if (empty($this->redirect_uri)) { - $clientData = $this->clientStorage->getClientDetails($this->client_id); - $registered_redirect_uri = $clientData['redirect_uri']; - } - - // the user declined access to the client's application - if ($is_authorized === false) { - $redirect_uri = $this->redirect_uri ?: $registered_redirect_uri; - $this->setNotAuthorizedResponse($request, $response, $redirect_uri, $user_id); - - return; - } - - // build the parameters to set in the redirect URI - if (!$params = $this->buildAuthorizeParameters($request, $response, $user_id)) { - return; - } - - $authResult = $this->responseTypes[$this->response_type]->getAuthorizeResponse($params, $user_id); - - list($redirect_uri, $uri_params) = $authResult; - - if (empty($redirect_uri) && !empty($registered_redirect_uri)) { - $redirect_uri = $registered_redirect_uri; - } - - $uri = $this->buildUri($redirect_uri, $uri_params); - - // return redirect response - $response->setRedirect($this->config['redirect_status_code'], $uri); - } - - protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null) - { - $error = 'access_denied'; - $error_message = 'The user denied access to your application'; - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->state, $error, $error_message); - } - - /* - * We have made this protected so this class can be extended to add/modify - * these parameters - */ - protected function buildAuthorizeParameters($request, $response, $user_id) - { - // @TODO: we should be explicit with this in the future - $params = array( - 'scope' => $this->scope, - 'state' => $this->state, - 'client_id' => $this->client_id, - 'redirect_uri' => $this->redirect_uri, - 'response_type' => $this->response_type, - ); - - return $params; - } - - public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response) - { - // Make sure a valid client id was supplied (we can not redirect because we were unable to verify the URI) - if (!$client_id = $request->query('client_id', $request->request('client_id'))) { - // We don't have a good URI to use - $response->setError(400, 'invalid_client', "No client id supplied"); - - return false; - } - - // Get client details - if (!$clientData = $this->clientStorage->getClientDetails($client_id)) { - $response->setError(400, 'invalid_client', 'The client id supplied is invalid'); - - return false; - } - - $registered_redirect_uri = isset($clientData['redirect_uri']) ? $clientData['redirect_uri'] : ''; - - // Make sure a valid redirect_uri was supplied. If specified, it must match the clientData URI. - // @see http://tools.ietf.org/html/rfc6749#section-3.1.2 - // @see http://tools.ietf.org/html/rfc6749#section-4.1.2.1 - // @see http://tools.ietf.org/html/rfc6749#section-4.2.2.1 - if ($supplied_redirect_uri = $request->query('redirect_uri', $request->request('redirect_uri'))) { - // validate there is no fragment supplied - $parts = parse_url($supplied_redirect_uri); - if (isset($parts['fragment']) && $parts['fragment']) { - $response->setError(400, 'invalid_uri', 'The redirect URI must not contain a fragment'); - - return false; - } - - // validate against the registered redirect uri(s) if available - if ($registered_redirect_uri && !$this->validateRedirectUri($supplied_redirect_uri, $registered_redirect_uri)) { - $response->setError(400, 'redirect_uri_mismatch', 'The redirect URI provided is missing or does not match', '#section-3.1.2'); - - return false; - } - $redirect_uri = $supplied_redirect_uri; - } else { - // use the registered redirect_uri if none has been supplied, if possible - if (!$registered_redirect_uri) { - $response->setError(400, 'invalid_uri', 'No redirect URI was supplied or stored'); - - return false; - } - - if (count(explode(' ', $registered_redirect_uri)) > 1) { - $response->setError(400, 'invalid_uri', 'A redirect URI must be supplied when multiple redirect URIs are registered', '#section-3.1.2.3'); - - return false; - } - $redirect_uri = $registered_redirect_uri; - } - - // Select the redirect URI - $response_type = $request->query('response_type', $request->request('response_type')); - - // for multiple-valued response types - make them alphabetical - if (false !== strpos($response_type, ' ')) { - $types = explode(' ', $response_type); - sort($types); - $response_type = ltrim(implode(' ', $types)); - } - - $state = $request->query('state', $request->request('state')); - - // type and client_id are required - if (!$response_type || !in_array($response_type, $this->getValidResponseTypes())) { - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_request', 'Invalid or missing response type', null); - - return false; - } - - if ($response_type == self::RESPONSE_TYPE_AUTHORIZATION_CODE) { - if (!isset($this->responseTypes['code'])) { - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unsupported_response_type', 'authorization code grant type not supported', null); - - return false; - } - if (!$this->clientStorage->checkRestrictedGrantType($client_id, 'authorization_code')) { - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unauthorized_client', 'The grant type is unauthorized for this client_id', null); - - return false; - } - if ($this->responseTypes['code']->enforceRedirect() && !$redirect_uri) { - $response->setError(400, 'redirect_uri_mismatch', 'The redirect URI is mandatory and was not supplied'); - - return false; - } - } else { - if (!$this->config['allow_implicit']) { - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unsupported_response_type', 'implicit grant type not supported', null); - - return false; - } - if (!$this->clientStorage->checkRestrictedGrantType($client_id, 'implicit')) { - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unauthorized_client', 'The grant type is unauthorized for this client_id', null); - - return false; - } - } - - // validate requested scope if it exists - $requestedScope = $this->scopeUtil->getScopeFromRequest($request); - - if ($requestedScope) { - // restrict scope by client specific scope if applicable, - // otherwise verify the scope exists - $clientScope = $this->clientStorage->getClientScope($client_id); - if ((empty($clientScope) && !$this->scopeUtil->scopeExists($requestedScope)) - || (!empty($clientScope) && !$this->scopeUtil->checkScope($requestedScope, $clientScope))) { - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_scope', 'An unsupported scope was requested', null); - - return false; - } - } else { - // use a globally-defined default scope - $defaultScope = $this->scopeUtil->getDefaultScope($client_id); - - if (false === $defaultScope) { - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_client', 'This application requires you specify a scope parameter', null); - - return false; - } - - $requestedScope = $defaultScope; - } - - // Validate state parameter exists (if configured to enforce this) - if ($this->config['enforce_state'] && !$state) { - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, null, 'invalid_request', 'The state parameter is required'); - - return false; - } - - // save the input data and return true - $this->scope = $requestedScope; - $this->state = $state; - $this->client_id = $client_id; - // Only save the SUPPLIED redirect URI (@see http://tools.ietf.org/html/rfc6749#section-4.1.3) - $this->redirect_uri = $supplied_redirect_uri; - $this->response_type = $response_type; - - return true; - } - - /** - * Build the absolute URI based on supplied URI and parameters. - * - * @param $uri An absolute URI. - * @param $params Parameters to be append as GET. - * - * @return - * An absolute URI with supplied parameters. - * - * @ingroup oauth2_section_4 - */ - private function buildUri($uri, $params) - { - $parse_url = parse_url($uri); - - // Add our params to the parsed uri - foreach ($params as $k => $v) { - if (isset($parse_url[$k])) { - $parse_url[$k] .= "&" . http_build_query($v, '', '&'); - } else { - $parse_url[$k] = http_build_query($v, '', '&'); - } - } - - // Put humpty dumpty back together - return - ((isset($parse_url["scheme"])) ? $parse_url["scheme"] . "://" : "") - . ((isset($parse_url["user"])) ? $parse_url["user"] - . ((isset($parse_url["pass"])) ? ":" . $parse_url["pass"] : "") . "@" : "") - . ((isset($parse_url["host"])) ? $parse_url["host"] : "") - . ((isset($parse_url["port"])) ? ":" . $parse_url["port"] : "") - . ((isset($parse_url["path"])) ? $parse_url["path"] : "") - . ((isset($parse_url["query"]) && !empty($parse_url['query'])) ? "?" . $parse_url["query"] : "") - . ((isset($parse_url["fragment"])) ? "#" . $parse_url["fragment"] : "") - ; - } - - protected function getValidResponseTypes() - { - return array( - self::RESPONSE_TYPE_ACCESS_TOKEN, - self::RESPONSE_TYPE_AUTHORIZATION_CODE, - ); - } - - /** - * Internal method for validating redirect URI supplied - * - * @param string $inputUri The submitted URI to be validated - * @param string $registeredUriString The allowed URI(s) to validate against. Can be a space-delimited string of URIs to - * allow for multiple URIs - * - * @see http://tools.ietf.org/html/rfc6749#section-3.1.2 - */ - protected function validateRedirectUri($inputUri, $registeredUriString) - { - if (!$inputUri || !$registeredUriString) { - return false; // if either one is missing, assume INVALID - } - - $registered_uris = explode(' ', $registeredUriString); - foreach ($registered_uris as $registered_uri) { - if ($this->config['require_exact_redirect_uri']) { - // the input uri is validated against the registered uri using exact match - if (strcmp($inputUri, $registered_uri) === 0) { - return true; - } - } else { - $registered_uri_length = strlen($registered_uri); - if ($registered_uri_length === 0) { - return false; - } - - // the input uri is validated against the registered uri using case-insensitive match of the initial string - // i.e. additional query parameters may be applied - if (strcasecmp(substr($inputUri, 0, $registered_uri_length), $registered_uri) === 0) { - return true; - } - } - } - - return false; - } - - /** - * Convenience methods to access the parameters derived from the validated request - */ - - public function getScope() - { - return $this->scope; - } - - public function getState() - { - return $this->state; - } - - public function getClientId() - { - return $this->client_id; - } - - public function getRedirectUri() - { - return $this->redirect_uri; - } - - public function getResponseType() - { - return $this->response_type; - } -} diff --git a/library/oauth2/src/OAuth2/Controller/AuthorizeControllerInterface.php b/library/oauth2/src/OAuth2/Controller/AuthorizeControllerInterface.php deleted file mode 100644 index fa07ae8d2..000000000 --- a/library/oauth2/src/OAuth2/Controller/AuthorizeControllerInterface.php +++ /dev/null @@ -1,43 +0,0 @@ -<?php - -namespace OAuth2\Controller; - -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -/** - * This controller is called when a user should be authorized - * by an authorization server. As OAuth2 does not handle - * authorization directly, this controller ensures the request is valid, but - * requires the application to determine the value of $is_authorized - * - * ex: - * > $user_id = $this->somehowDetermineUserId(); - * > $is_authorized = $this->somehowDetermineUserAuthorization(); - * > $response = new OAuth2\Response(); - * > $authorizeController->handleAuthorizeRequest( - * > OAuth2\Request::createFromGlobals(), - * > $response, - * > $is_authorized, - * > $user_id); - * > $response->send(); - * - */ -interface AuthorizeControllerInterface -{ - /** - * List of possible authentication response types. - * The "authorization_code" mechanism exclusively supports 'code' - * and the "implicit" mechanism exclusively supports 'token'. - * - * @var string - * @see http://tools.ietf.org/html/rfc6749#section-4.1.1 - * @see http://tools.ietf.org/html/rfc6749#section-4.2.1 - */ - const RESPONSE_TYPE_AUTHORIZATION_CODE = 'code'; - const RESPONSE_TYPE_ACCESS_TOKEN = 'token'; - - public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null); - - public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response); -} diff --git a/library/oauth2/src/OAuth2/Controller/ResourceController.php b/library/oauth2/src/OAuth2/Controller/ResourceController.php deleted file mode 100644 index e8588188f..000000000 --- a/library/oauth2/src/OAuth2/Controller/ResourceController.php +++ /dev/null @@ -1,111 +0,0 @@ -<?php - -namespace OAuth2\Controller; - -use OAuth2\TokenType\TokenTypeInterface; -use OAuth2\Storage\AccessTokenInterface; -use OAuth2\ScopeInterface; -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; -use OAuth2\Scope; - -/** - * @see OAuth2\Controller\ResourceControllerInterface - */ -class ResourceController implements ResourceControllerInterface -{ - private $token; - - protected $tokenType; - protected $tokenStorage; - protected $config; - protected $scopeUtil; - - public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, $config = array(), ScopeInterface $scopeUtil = null) - { - $this->tokenType = $tokenType; - $this->tokenStorage = $tokenStorage; - - $this->config = array_merge(array( - 'www_realm' => 'Service', - ), $config); - - if (is_null($scopeUtil)) { - $scopeUtil = new Scope(); - } - $this->scopeUtil = $scopeUtil; - } - - public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null) - { - $token = $this->getAccessTokenData($request, $response); - - // Check if we have token data - if (is_null($token)) { - return false; - } - - /** - * Check scope, if provided - * If token doesn't have a scope, it's null/empty, or it's insufficient, then throw 403 - * @see http://tools.ietf.org/html/rfc6750#section-3.1 - */ - if ($scope && (!isset($token["scope"]) || !$token["scope"] || !$this->scopeUtil->checkScope($scope, $token["scope"]))) { - $response->setError(403, 'insufficient_scope', 'The request requires higher privileges than provided by the access token'); - $response->addHttpHeaders(array( - 'WWW-Authenticate' => sprintf('%s realm="%s", scope="%s", error="%s", error_description="%s"', - $this->tokenType->getTokenType(), - $this->config['www_realm'], - $scope, - $response->getParameter('error'), - $response->getParameter('error_description') - ) - )); - - return false; - } - - // allow retrieval of the token - $this->token = $token; - - return (bool) $token; - } - - public function getAccessTokenData(RequestInterface $request, ResponseInterface $response) - { - // Get the token parameter - if ($token_param = $this->tokenType->getAccessTokenParameter($request, $response)) { - // Get the stored token data (from the implementing subclass) - // Check we have a well formed token - // Check token expiration (expires is a mandatory paramter) - if (!$token = $this->tokenStorage->getAccessToken($token_param)) { - $response->setError(401, 'invalid_token', 'The access token provided is invalid'); - } elseif (!isset($token["expires"]) || !isset($token["client_id"])) { - $response->setError(401, 'malformed_token', 'Malformed token (missing "expires")'); - } elseif (time() > $token["expires"]) { - $response->setError(401, 'expired_token', 'The access token provided has expired'); - } else { - return $token; - } - } - - $authHeader = sprintf('%s realm="%s"', $this->tokenType->getTokenType(), $this->config['www_realm']); - - if ($error = $response->getParameter('error')) { - $authHeader = sprintf('%s, error="%s"', $authHeader, $error); - if ($error_description = $response->getParameter('error_description')) { - $authHeader = sprintf('%s, error_description="%s"', $authHeader, $error_description); - } - } - - $response->addHttpHeaders(array('WWW-Authenticate' => $authHeader)); - - return null; - } - - // convenience method to allow retrieval of the token - public function getToken() - { - return $this->token; - } -} diff --git a/library/oauth2/src/OAuth2/Controller/ResourceControllerInterface.php b/library/oauth2/src/OAuth2/Controller/ResourceControllerInterface.php deleted file mode 100644 index 611421935..000000000 --- a/library/oauth2/src/OAuth2/Controller/ResourceControllerInterface.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php - -namespace OAuth2\Controller; - -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -/** - * This controller is called when a "resource" is requested. - * call verifyResourceRequest in order to determine if the request - * contains a valid token. - * - * ex: - * > if (!$resourceController->verifyResourceRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response())) { - * > $response->send(); // authorization failed - * > die(); - * > } - * > return json_encode($resource); // valid token! Send the stuff! - * - */ -interface ResourceControllerInterface -{ - public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null); - - public function getAccessTokenData(RequestInterface $request, ResponseInterface $response); -} diff --git a/library/oauth2/src/OAuth2/Controller/TokenController.php b/library/oauth2/src/OAuth2/Controller/TokenController.php deleted file mode 100644 index 42dab892f..000000000 --- a/library/oauth2/src/OAuth2/Controller/TokenController.php +++ /dev/null @@ -1,278 +0,0 @@ -<?php - -namespace OAuth2\Controller; - -use OAuth2\ResponseType\AccessTokenInterface; -use OAuth2\ClientAssertionType\ClientAssertionTypeInterface; -use OAuth2\GrantType\GrantTypeInterface; -use OAuth2\ScopeInterface; -use OAuth2\Scope; -use OAuth2\Storage\ClientInterface; -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -/** - * @see OAuth2\Controller\TokenControllerInterface - */ -class TokenController implements TokenControllerInterface -{ - protected $accessToken; - protected $grantTypes; - protected $clientAssertionType; - protected $scopeUtil; - protected $clientStorage; - - public function __construct(AccessTokenInterface $accessToken, ClientInterface $clientStorage, array $grantTypes = array(), ClientAssertionTypeInterface $clientAssertionType = null, ScopeInterface $scopeUtil = null) - { - if (is_null($clientAssertionType)) { - foreach ($grantTypes as $grantType) { - if (!$grantType instanceof ClientAssertionTypeInterface) { - throw new \InvalidArgumentException('You must supply an instance of OAuth2\ClientAssertionType\ClientAssertionTypeInterface or only use grant types which implement OAuth2\ClientAssertionType\ClientAssertionTypeInterface'); - } - } - } - $this->clientAssertionType = $clientAssertionType; - $this->accessToken = $accessToken; - $this->clientStorage = $clientStorage; - foreach ($grantTypes as $grantType) { - $this->addGrantType($grantType); - } - - if (is_null($scopeUtil)) { - $scopeUtil = new Scope(); - } - $this->scopeUtil = $scopeUtil; - } - - public function handleTokenRequest(RequestInterface $request, ResponseInterface $response) - { - if ($token = $this->grantAccessToken($request, $response)) { - // @see http://tools.ietf.org/html/rfc6749#section-5.1 - // server MUST disable caching in headers when tokens are involved - $response->setStatusCode(200); - $response->addParameters($token); - $response->addHttpHeaders(array( - 'Cache-Control' => 'no-store', - 'Pragma' => 'no-cache', - 'Content-Type' => 'application/json' - )); - } - } - - /** - * Grant or deny a requested access token. - * This would be called from the "/token" endpoint as defined in the spec. - * You can call your endpoint whatever you want. - * - * @param $request - RequestInterface - * Request object to grant access token - * - * @throws InvalidArgumentException - * @throws LogicException - * - * @see http://tools.ietf.org/html/rfc6749#section-4 - * @see http://tools.ietf.org/html/rfc6749#section-10.6 - * @see http://tools.ietf.org/html/rfc6749#section-4.1.3 - * - * @ingroup oauth2_section_4 - */ - public function grantAccessToken(RequestInterface $request, ResponseInterface $response) - { - if (strtolower($request->server('REQUEST_METHOD')) != 'post') { - $response->setError(405, 'invalid_request', 'The request method must be POST when requesting an access token', '#section-3.2'); - $response->addHttpHeaders(array('Allow' => 'POST')); - - return null; - } - - /** - * Determine grant type from request - * and validate the request for that grant type - */ - if (!$grantTypeIdentifier = $request->request('grant_type')) { - $response->setError(400, 'invalid_request', 'The grant type was not specified in the request'); - - return null; - } - - if (!isset($this->grantTypes[$grantTypeIdentifier])) { - /* TODO: If this is an OAuth2 supported grant type that we have chosen not to implement, throw a 501 Not Implemented instead */ - $response->setError(400, 'unsupported_grant_type', sprintf('Grant type "%s" not supported', $grantTypeIdentifier)); - - return null; - } - - $grantType = $this->grantTypes[$grantTypeIdentifier]; - - /** - * Retrieve the client information from the request - * ClientAssertionTypes allow for grant types which also assert the client data - * in which case ClientAssertion is handled in the validateRequest method - * - * @see OAuth2\GrantType\JWTBearer - * @see OAuth2\GrantType\ClientCredentials - */ - if (!$grantType instanceof ClientAssertionTypeInterface) { - if (!$this->clientAssertionType->validateRequest($request, $response)) { - return null; - } - $clientId = $this->clientAssertionType->getClientId(); - } - - /** - * Retrieve the grant type information from the request - * The GrantTypeInterface object handles all validation - * If the object is an instance of ClientAssertionTypeInterface, - * That logic is handled here as well - */ - if (!$grantType->validateRequest($request, $response)) { - return null; - } - - if ($grantType instanceof ClientAssertionTypeInterface) { - $clientId = $grantType->getClientId(); - } else { - // validate the Client ID (if applicable) - if (!is_null($storedClientId = $grantType->getClientId()) && $storedClientId != $clientId) { - $response->setError(400, 'invalid_grant', sprintf('%s doesn\'t exist or is invalid for the client', $grantTypeIdentifier)); - - return null; - } - } - - /** - * Validate the client can use the requested grant type - */ - if (!$this->clientStorage->checkRestrictedGrantType($clientId, $grantTypeIdentifier)) { - $response->setError(400, 'unauthorized_client', 'The grant type is unauthorized for this client_id'); - - return false; - } - - /** - * Validate the scope of the token - * - * requestedScope - the scope specified in the token request - * availableScope - the scope associated with the grant type - * ex: in the case of the "Authorization Code" grant type, - * the scope is specified in the authorize request - * - * @see http://tools.ietf.org/html/rfc6749#section-3.3 - */ - - $requestedScope = $this->scopeUtil->getScopeFromRequest($request); - $availableScope = $grantType->getScope(); - - if ($requestedScope) { - // validate the requested scope - if ($availableScope) { - if (!$this->scopeUtil->checkScope($requestedScope, $availableScope)) { - $response->setError(400, 'invalid_scope', 'The scope requested is invalid for this request'); - - return null; - } - } else { - // validate the client has access to this scope - if ($clientScope = $this->clientStorage->getClientScope($clientId)) { - if (!$this->scopeUtil->checkScope($requestedScope, $clientScope)) { - $response->setError(400, 'invalid_scope', 'The scope requested is invalid for this client'); - - return false; - } - } elseif (!$this->scopeUtil->scopeExists($requestedScope)) { - $response->setError(400, 'invalid_scope', 'An unsupported scope was requested'); - - return null; - } - } - } elseif ($availableScope) { - // use the scope associated with this grant type - $requestedScope = $availableScope; - } else { - // use a globally-defined default scope - $defaultScope = $this->scopeUtil->getDefaultScope($clientId); - - // "false" means default scopes are not allowed - if (false === $defaultScope) { - $response->setError(400, 'invalid_scope', 'This application requires you specify a scope parameter'); - - return null; - } - - $requestedScope = $defaultScope; - } - - return $grantType->createAccessToken($this->accessToken, $clientId, $grantType->getUserId(), $requestedScope); - } - - /** - * addGrantType - * - * @param grantType - OAuth2\GrantTypeInterface - * the grant type to add for the specified identifier - * @param identifier - string - * a string passed in as "grant_type" in the response that will call this grantType - */ - public function addGrantType(GrantTypeInterface $grantType, $identifier = null) - { - if (is_null($identifier) || is_numeric($identifier)) { - $identifier = $grantType->getQuerystringIdentifier(); - } - - $this->grantTypes[$identifier] = $grantType; - } - - public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response) - { - if ($this->revokeToken($request, $response)) { - $response->setStatusCode(200); - $response->addParameters(array('revoked' => true)); - } - } - - /** - * Revoke a refresh or access token. Returns true on success and when tokens are invalid - * - * Note: invalid tokens do not cause an error response since the client - * cannot handle such an error in a reasonable way. Moreover, the - * purpose of the revocation request, invalidating the particular token, - * is already achieved. - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return bool|null - */ - public function revokeToken(RequestInterface $request, ResponseInterface $response) - { - if (strtolower($request->server('REQUEST_METHOD')) != 'post') { - $response->setError(405, 'invalid_request', 'The request method must be POST when revoking an access token', '#section-3.2'); - $response->addHttpHeaders(array('Allow' => 'POST')); - - return null; - } - - $token_type_hint = $request->request('token_type_hint'); - if (!in_array($token_type_hint, array(null, 'access_token', 'refresh_token'), true)) { - $response->setError(400, 'invalid_request', 'Token type hint must be either \'access_token\' or \'refresh_token\''); - - return null; - } - - $token = $request->request('token'); - if ($token === null) { - $response->setError(400, 'invalid_request', 'Missing token parameter to revoke'); - - return null; - } - - // @todo remove this check for v2.0 - if (!method_exists($this->accessToken, 'revokeToken')) { - $class = get_class($this->accessToken); - throw new \RuntimeException("AccessToken {$class} does not implement required revokeToken method"); - } - - $this->accessToken->revokeToken($token, $token_type_hint); - - return true; - } -} diff --git a/library/oauth2/src/OAuth2/Controller/TokenControllerInterface.php b/library/oauth2/src/OAuth2/Controller/TokenControllerInterface.php deleted file mode 100644 index 72d72570f..000000000 --- a/library/oauth2/src/OAuth2/Controller/TokenControllerInterface.php +++ /dev/null @@ -1,32 +0,0 @@ -<?php - -namespace OAuth2\Controller; - -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -/** - * This controller is called when a token is being requested. - * it is called to handle all grant types the application supports. - * It also validates the client's credentials - * - * ex: - * > $tokenController->handleTokenRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response()); - * > $response->send(); - * - */ -interface TokenControllerInterface -{ - /** - * handleTokenRequest - * - * @param $request - * OAuth2\RequestInterface - The current http request - * @param $response - * OAuth2\ResponseInterface - An instance of OAuth2\ResponseInterface to contain the response data - * - */ - public function handleTokenRequest(RequestInterface $request, ResponseInterface $response); - - public function grantAccessToken(RequestInterface $request, ResponseInterface $response); -} diff --git a/library/oauth2/src/OAuth2/Encryption/EncryptionInterface.php b/library/oauth2/src/OAuth2/Encryption/EncryptionInterface.php deleted file mode 100644 index 2d336c664..000000000 --- a/library/oauth2/src/OAuth2/Encryption/EncryptionInterface.php +++ /dev/null @@ -1,11 +0,0 @@ -<?php - -namespace OAuth2\Encryption; - -interface EncryptionInterface -{ - public function encode($payload, $key, $algorithm = null); - public function decode($payload, $key, $algorithm = null); - public function urlSafeB64Encode($data); - public function urlSafeB64Decode($b64); -} diff --git a/library/oauth2/src/OAuth2/Encryption/FirebaseJwt.php b/library/oauth2/src/OAuth2/Encryption/FirebaseJwt.php deleted file mode 100644 index 1b527e0a0..000000000 --- a/library/oauth2/src/OAuth2/Encryption/FirebaseJwt.php +++ /dev/null @@ -1,47 +0,0 @@ -<?php - -namespace OAuth2\Encryption; - -/** - * Bridge file to use the firebase/php-jwt package for JWT encoding and decoding. - * @author Francis Chuang <francis.chuang@gmail.com> - */ -class FirebaseJwt implements EncryptionInterface -{ - public function __construct() - { - if (!class_exists('\JWT')) { - throw new \ErrorException('firebase/php-jwt must be installed to use this feature. You can do this by running "composer require firebase/php-jwt"'); - } - } - - public function encode($payload, $key, $alg = 'HS256', $keyId = null) - { - return \JWT::encode($payload, $key, $alg, $keyId); - } - - public function decode($jwt, $key = null, $allowedAlgorithms = null) - { - try { - - //Maintain BC: Do not verify if no algorithms are passed in. - if (!$allowedAlgorithms) { - $key = null; - } - - return (array)\JWT::decode($jwt, $key, $allowedAlgorithms); - } catch (\Exception $e) { - return false; - } - } - - public function urlSafeB64Encode($data) - { - return \JWT::urlsafeB64Encode($data); - } - - public function urlSafeB64Decode($b64) - { - return \JWT::urlsafeB64Decode($b64); - } -} diff --git a/library/oauth2/src/OAuth2/Encryption/Jwt.php b/library/oauth2/src/OAuth2/Encryption/Jwt.php deleted file mode 100644 index ee576e643..000000000 --- a/library/oauth2/src/OAuth2/Encryption/Jwt.php +++ /dev/null @@ -1,173 +0,0 @@ -<?php - -namespace OAuth2\Encryption; - -/** - * @link https://github.com/F21/jwt - * @author F21 - */ -class Jwt implements EncryptionInterface -{ - public function encode($payload, $key, $algo = 'HS256') - { - $header = $this->generateJwtHeader($payload, $algo); - - $segments = array( - $this->urlSafeB64Encode(json_encode($header)), - $this->urlSafeB64Encode(json_encode($payload)) - ); - - $signing_input = implode('.', $segments); - - $signature = $this->sign($signing_input, $key, $algo); - $segments[] = $this->urlsafeB64Encode($signature); - - return implode('.', $segments); - } - - public function decode($jwt, $key = null, $allowedAlgorithms = true) - { - if (!strpos($jwt, '.')) { - return false; - } - - $tks = explode('.', $jwt); - - if (count($tks) != 3) { - return false; - } - - list($headb64, $payloadb64, $cryptob64) = $tks; - - if (null === ($header = json_decode($this->urlSafeB64Decode($headb64), true))) { - return false; - } - - if (null === $payload = json_decode($this->urlSafeB64Decode($payloadb64), true)) { - return false; - } - - $sig = $this->urlSafeB64Decode($cryptob64); - - if ((bool) $allowedAlgorithms) { - if (!isset($header['alg'])) { - return false; - } - - // check if bool arg supplied here to maintain BC - if (is_array($allowedAlgorithms) && !in_array($header['alg'], $allowedAlgorithms)) { - return false; - } - - if (!$this->verifySignature($sig, "$headb64.$payloadb64", $key, $header['alg'])) { - return false; - } - } - - return $payload; - } - - private function verifySignature($signature, $input, $key, $algo = 'HS256') - { - // use constants when possible, for HipHop support - switch ($algo) { - case'HS256': - case'HS384': - case'HS512': - return $this->hash_equals( - $this->sign($input, $key, $algo), - $signature - ); - - case 'RS256': - return openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA256') ? OPENSSL_ALGO_SHA256 : 'sha256') === 1; - - case 'RS384': - return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'sha384') === 1; - - case 'RS512': - return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512') === 1; - - default: - throw new \InvalidArgumentException("Unsupported or invalid signing algorithm."); - } - } - - private function sign($input, $key, $algo = 'HS256') - { - switch ($algo) { - case 'HS256': - return hash_hmac('sha256', $input, $key, true); - - case 'HS384': - return hash_hmac('sha384', $input, $key, true); - - case 'HS512': - return hash_hmac('sha512', $input, $key, true); - - case 'RS256': - return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA256') ? OPENSSL_ALGO_SHA256 : 'sha256'); - - case 'RS384': - return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'sha384'); - - case 'RS512': - return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512'); - - default: - throw new \Exception("Unsupported or invalid signing algorithm."); - } - } - - private function generateRSASignature($input, $key, $algo) - { - if (!openssl_sign($input, $signature, $key, $algo)) { - throw new \Exception("Unable to sign data."); - } - - return $signature; - } - - public function urlSafeB64Encode($data) - { - $b64 = base64_encode($data); - $b64 = str_replace(array('+', '/', "\r", "\n", '='), - array('-', '_'), - $b64); - - return $b64; - } - - public function urlSafeB64Decode($b64) - { - $b64 = str_replace(array('-', '_'), - array('+', '/'), - $b64); - - return base64_decode($b64); - } - - /** - * Override to create a custom header - */ - protected function generateJwtHeader($payload, $algorithm) - { - return array( - 'typ' => 'JWT', - 'alg' => $algorithm, - ); - } - - protected function hash_equals($a, $b) - { - if (function_exists('hash_equals')) { - return hash_equals($a, $b); - } - $diff = strlen($a) ^ strlen($b); - for ($i = 0; $i < strlen($a) && $i < strlen($b); $i++) { - $diff |= ord($a[$i]) ^ ord($b[$i]); - } - - return $diff === 0; - } -} diff --git a/library/oauth2/src/OAuth2/GrantType/AuthorizationCode.php b/library/oauth2/src/OAuth2/GrantType/AuthorizationCode.php deleted file mode 100644 index e8995204c..000000000 --- a/library/oauth2/src/OAuth2/GrantType/AuthorizationCode.php +++ /dev/null @@ -1,100 +0,0 @@ -<?php - -namespace OAuth2\GrantType; - -use OAuth2\Storage\AuthorizationCodeInterface; -use OAuth2\ResponseType\AccessTokenInterface; -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -/** - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -class AuthorizationCode implements GrantTypeInterface -{ - protected $storage; - protected $authCode; - - /** - * @param OAuth2\Storage\AuthorizationCodeInterface $storage REQUIRED Storage class for retrieving authorization code information - */ - public function __construct(AuthorizationCodeInterface $storage) - { - $this->storage = $storage; - } - - public function getQuerystringIdentifier() - { - return 'authorization_code'; - } - - public function validateRequest(RequestInterface $request, ResponseInterface $response) - { - if (!$request->request('code')) { - $response->setError(400, 'invalid_request', 'Missing parameter: "code" is required'); - - return false; - } - - $code = $request->request('code'); - if (!$authCode = $this->storage->getAuthorizationCode($code)) { - $response->setError(400, 'invalid_grant', 'Authorization code doesn\'t exist or is invalid for the client'); - - return false; - } - - /* - * 4.1.3 - ensure that the "redirect_uri" parameter is present if the "redirect_uri" parameter was included in the initial authorization request - * @uri - http://tools.ietf.org/html/rfc6749#section-4.1.3 - */ - if (isset($authCode['redirect_uri']) && $authCode['redirect_uri']) { - if (!$request->request('redirect_uri') || urldecode($request->request('redirect_uri')) != $authCode['redirect_uri']) { - $response->setError(400, 'redirect_uri_mismatch', "The redirect URI is missing or do not match", "#section-4.1.3"); - - return false; - } - } - - if (!isset($authCode['expires'])) { - throw new \Exception('Storage must return authcode with a value for "expires"'); - } - - if ($authCode["expires"] < time()) { - $response->setError(400, 'invalid_grant', "The authorization code has expired"); - - return false; - } - - if (!isset($authCode['code'])) { - $authCode['code'] = $code; // used to expire the code after the access token is granted - } - - $this->authCode = $authCode; - - return true; - } - - public function getClientId() - { - return $this->authCode['client_id']; - } - - public function getScope() - { - return isset($this->authCode['scope']) ? $this->authCode['scope'] : null; - } - - public function getUserId() - { - return isset($this->authCode['user_id']) ? $this->authCode['user_id'] : null; - } - - public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) - { - $token = $accessToken->createAccessToken($client_id, $user_id, $scope); - $this->storage->expireAuthorizationCode($this->authCode['code']); - - return $token; - } -} diff --git a/library/oauth2/src/OAuth2/GrantType/ClientCredentials.php b/library/oauth2/src/OAuth2/GrantType/ClientCredentials.php deleted file mode 100644 index f953e4e8d..000000000 --- a/library/oauth2/src/OAuth2/GrantType/ClientCredentials.php +++ /dev/null @@ -1,67 +0,0 @@ -<?php - -namespace OAuth2\GrantType; - -use OAuth2\ClientAssertionType\HttpBasic; -use OAuth2\ResponseType\AccessTokenInterface; -use OAuth2\Storage\ClientCredentialsInterface; - -/** - * @author Brent Shaffer <bshafs at gmail dot com> - * - * @see OAuth2\ClientAssertionType_HttpBasic - */ -class ClientCredentials extends HttpBasic implements GrantTypeInterface -{ - private $clientData; - - public function __construct(ClientCredentialsInterface $storage, array $config = array()) - { - /** - * The client credentials grant type MUST only be used by confidential clients - * - * @see http://tools.ietf.org/html/rfc6749#section-4.4 - */ - $config['allow_public_clients'] = false; - - parent::__construct($storage, $config); - } - - public function getQuerystringIdentifier() - { - return 'client_credentials'; - } - - public function getScope() - { - $this->loadClientData(); - - return isset($this->clientData['scope']) ? $this->clientData['scope'] : null; - } - - public function getUserId() - { - $this->loadClientData(); - - return isset($this->clientData['user_id']) ? $this->clientData['user_id'] : null; - } - - public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) - { - /** - * Client Credentials Grant does NOT include a refresh token - * - * @see http://tools.ietf.org/html/rfc6749#section-4.4.3 - */ - $includeRefreshToken = false; - - return $accessToken->createAccessToken($client_id, $user_id, $scope, $includeRefreshToken); - } - - private function loadClientData() - { - if (!$this->clientData) { - $this->clientData = $this->storage->getClientDetails($this->getClientId()); - } - } -} diff --git a/library/oauth2/src/OAuth2/GrantType/GrantTypeInterface.php b/library/oauth2/src/OAuth2/GrantType/GrantTypeInterface.php deleted file mode 100644 index 98489e9c1..000000000 --- a/library/oauth2/src/OAuth2/GrantType/GrantTypeInterface.php +++ /dev/null @@ -1,20 +0,0 @@ -<?php - -namespace OAuth2\GrantType; - -use OAuth2\ResponseType\AccessTokenInterface; -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -/** - * Interface for all OAuth2 Grant Types - */ -interface GrantTypeInterface -{ - public function getQuerystringIdentifier(); - public function validateRequest(RequestInterface $request, ResponseInterface $response); - public function getClientId(); - public function getUserId(); - public function getScope(); - public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope); -} diff --git a/library/oauth2/src/OAuth2/GrantType/JwtBearer.php b/library/oauth2/src/OAuth2/GrantType/JwtBearer.php deleted file mode 100644 index bb11a6954..000000000 --- a/library/oauth2/src/OAuth2/GrantType/JwtBearer.php +++ /dev/null @@ -1,226 +0,0 @@ -<?php - -namespace OAuth2\GrantType; - -use OAuth2\ClientAssertionType\ClientAssertionTypeInterface; -use OAuth2\Storage\JwtBearerInterface; -use OAuth2\Encryption\Jwt; -use OAuth2\Encryption\EncryptionInterface; -use OAuth2\ResponseType\AccessTokenInterface; -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -/** - * The JWT bearer authorization grant implements JWT (JSON Web Tokens) as a grant type per the IETF draft. - * - * @see http://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-04#section-4 - * - * @author F21 - * @author Brent Shaffer <bshafs at gmail dot com> - */ -class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface -{ - private $jwt; - - protected $storage; - protected $audience; - protected $jwtUtil; - protected $allowedAlgorithms; - - /** - * Creates an instance of the JWT bearer grant type. - * - * @param OAuth2\Storage\JWTBearerInterface|JwtBearerInterface $storage A valid storage interface that implements storage hooks for the JWT bearer grant type. - * @param string $audience The audience to validate the token against. This is usually the full URI of the OAuth token requests endpoint. - * @param EncryptionInterface|OAuth2\Encryption\JWT $jwtUtil OPTONAL The class used to decode, encode and verify JWTs. - * @param array $config - */ - public function __construct(JwtBearerInterface $storage, $audience, EncryptionInterface $jwtUtil = null, array $config = array()) - { - $this->storage = $storage; - $this->audience = $audience; - - if (is_null($jwtUtil)) { - $jwtUtil = new Jwt(); - } - - $this->config = array_merge(array( - 'allowed_algorithms' => array('RS256', 'RS384', 'RS512') - ), $config); - - $this->jwtUtil = $jwtUtil; - - $this->allowedAlgorithms = $this->config['allowed_algorithms']; - } - - /** - * Returns the grant_type get parameter to identify the grant type request as JWT bearer authorization grant. - * - * @return - * The string identifier for grant_type. - * - * @see OAuth2\GrantType\GrantTypeInterface::getQuerystringIdentifier() - */ - public function getQuerystringIdentifier() - { - return 'urn:ietf:params:oauth:grant-type:jwt-bearer'; - } - - /** - * Validates the data from the decoded JWT. - * - * @return - * TRUE if the JWT request is valid and can be decoded. Otherwise, FALSE is returned. - * - * @see OAuth2\GrantType\GrantTypeInterface::getTokenData() - */ - public function validateRequest(RequestInterface $request, ResponseInterface $response) - { - if (!$request->request("assertion")) { - $response->setError(400, 'invalid_request', 'Missing parameters: "assertion" required'); - - return null; - } - - // Store the undecoded JWT for later use - $undecodedJWT = $request->request('assertion'); - - // Decode the JWT - $jwt = $this->jwtUtil->decode($request->request('assertion'), null, false); - - if (!$jwt) { - $response->setError(400, 'invalid_request', "JWT is malformed"); - - return null; - } - - // ensure these properties contain a value - // @todo: throw malformed error for missing properties - $jwt = array_merge(array( - 'scope' => null, - 'iss' => null, - 'sub' => null, - 'aud' => null, - 'exp' => null, - 'nbf' => null, - 'iat' => null, - 'jti' => null, - 'typ' => null, - ), $jwt); - - if (!isset($jwt['iss'])) { - $response->setError(400, 'invalid_grant', "Invalid issuer (iss) provided"); - - return null; - } - - if (!isset($jwt['sub'])) { - $response->setError(400, 'invalid_grant', "Invalid subject (sub) provided"); - - return null; - } - - if (!isset($jwt['exp'])) { - $response->setError(400, 'invalid_grant', "Expiration (exp) time must be present"); - - return null; - } - - // Check expiration - if (ctype_digit($jwt['exp'])) { - if ($jwt['exp'] <= time()) { - $response->setError(400, 'invalid_grant', "JWT has expired"); - - return null; - } - } else { - $response->setError(400, 'invalid_grant', "Expiration (exp) time must be a unix time stamp"); - - return null; - } - - // Check the not before time - if ($notBefore = $jwt['nbf']) { - if (ctype_digit($notBefore)) { - if ($notBefore > time()) { - $response->setError(400, 'invalid_grant', "JWT cannot be used before the Not Before (nbf) time"); - - return null; - } - } else { - $response->setError(400, 'invalid_grant', "Not Before (nbf) time must be a unix time stamp"); - - return null; - } - } - - // Check the audience if required to match - if (!isset($jwt['aud']) || ($jwt['aud'] != $this->audience)) { - $response->setError(400, 'invalid_grant', "Invalid audience (aud)"); - - return null; - } - - // Check the jti (nonce) - // @see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-13#section-4.1.7 - if (isset($jwt['jti'])) { - $jti = $this->storage->getJti($jwt['iss'], $jwt['sub'], $jwt['aud'], $jwt['exp'], $jwt['jti']); - - //Reject if jti is used and jwt is still valid (exp parameter has not expired). - if ($jti && $jti['expires'] > time()) { - $response->setError(400, 'invalid_grant', "JSON Token Identifier (jti) has already been used"); - - return null; - } else { - $this->storage->setJti($jwt['iss'], $jwt['sub'], $jwt['aud'], $jwt['exp'], $jwt['jti']); - } - } - - // Get the iss's public key - // @see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06#section-4.1.1 - if (!$key = $this->storage->getClientKey($jwt['iss'], $jwt['sub'])) { - $response->setError(400, 'invalid_grant', "Invalid issuer (iss) or subject (sub) provided"); - - return null; - } - - // Verify the JWT - if (!$this->jwtUtil->decode($undecodedJWT, $key, $this->allowedAlgorithms)) { - $response->setError(400, 'invalid_grant', "JWT failed signature verification"); - - return null; - } - - $this->jwt = $jwt; - - return true; - } - - public function getClientId() - { - return $this->jwt['iss']; - } - - public function getUserId() - { - return $this->jwt['sub']; - } - - public function getScope() - { - return null; - } - - /** - * Creates an access token that is NOT associated with a refresh token. - * If a subject (sub) the name of the user/account we are accessing data on behalf of. - * - * @see OAuth2\GrantType\GrantTypeInterface::createAccessToken() - */ - public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) - { - $includeRefreshToken = false; - - return $accessToken->createAccessToken($client_id, $user_id, $scope, $includeRefreshToken); - } -} diff --git a/library/oauth2/src/OAuth2/GrantType/RefreshToken.php b/library/oauth2/src/OAuth2/GrantType/RefreshToken.php deleted file mode 100644 index e55385222..000000000 --- a/library/oauth2/src/OAuth2/GrantType/RefreshToken.php +++ /dev/null @@ -1,111 +0,0 @@ -<?php - -namespace OAuth2\GrantType; - -use OAuth2\Storage\RefreshTokenInterface; -use OAuth2\ResponseType\AccessTokenInterface; -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -/** - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -class RefreshToken implements GrantTypeInterface -{ - private $refreshToken; - - protected $storage; - protected $config; - - /** - * @param OAuth2\Storage\RefreshTokenInterface $storage REQUIRED Storage class for retrieving refresh token information - * @param array $config OPTIONAL Configuration options for the server - * <code> - * $config = array( - * 'always_issue_new_refresh_token' => true, // whether to issue a new refresh token upon successful token request - * 'unset_refresh_token_after_use' => true // whether to unset the refresh token after after using - * ); - * </code> - */ - public function __construct(RefreshTokenInterface $storage, $config = array()) - { - $this->config = array_merge(array( - 'always_issue_new_refresh_token' => false, - 'unset_refresh_token_after_use' => true - ), $config); - - // to preserve B.C. with v1.6 - // @see https://github.com/bshaffer/oauth2-server-php/pull/580 - // @todo - remove in v2.0 - if (isset($config['always_issue_new_refresh_token']) && !isset($config['unset_refresh_token_after_use'])) { - $this->config['unset_refresh_token_after_use'] = $config['always_issue_new_refresh_token']; - } - - $this->storage = $storage; - } - - public function getQuerystringIdentifier() - { - return 'refresh_token'; - } - - public function validateRequest(RequestInterface $request, ResponseInterface $response) - { - if (!$request->request("refresh_token")) { - $response->setError(400, 'invalid_request', 'Missing parameter: "refresh_token" is required'); - - return null; - } - - if (!$refreshToken = $this->storage->getRefreshToken($request->request("refresh_token"))) { - $response->setError(400, 'invalid_grant', 'Invalid refresh token'); - - return null; - } - - if ($refreshToken['expires'] > 0 && $refreshToken["expires"] < time()) { - $response->setError(400, 'invalid_grant', 'Refresh token has expired'); - - return null; - } - - // store the refresh token locally so we can delete it when a new refresh token is generated - $this->refreshToken = $refreshToken; - - return true; - } - - public function getClientId() - { - return $this->refreshToken['client_id']; - } - - public function getUserId() - { - return isset($this->refreshToken['user_id']) ? $this->refreshToken['user_id'] : null; - } - - public function getScope() - { - return isset($this->refreshToken['scope']) ? $this->refreshToken['scope'] : null; - } - - public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) - { - /* - * It is optional to force a new refresh token when a refresh token is used. - * However, if a new refresh token is issued, the old one MUST be expired - * @see http://tools.ietf.org/html/rfc6749#section-6 - */ - $issueNewRefreshToken = $this->config['always_issue_new_refresh_token']; - $unsetRefreshToken = $this->config['unset_refresh_token_after_use']; - $token = $accessToken->createAccessToken($client_id, $user_id, $scope, $issueNewRefreshToken); - - if ($unsetRefreshToken) { - $this->storage->unsetRefreshToken($this->refreshToken['refresh_token']); - } - - return $token; - } -} diff --git a/library/oauth2/src/OAuth2/GrantType/UserCredentials.php b/library/oauth2/src/OAuth2/GrantType/UserCredentials.php deleted file mode 100644 index f165538ba..000000000 --- a/library/oauth2/src/OAuth2/GrantType/UserCredentials.php +++ /dev/null @@ -1,83 +0,0 @@ -<?php - -namespace OAuth2\GrantType; - -use OAuth2\Storage\UserCredentialsInterface; -use OAuth2\ResponseType\AccessTokenInterface; -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -/** - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -class UserCredentials implements GrantTypeInterface -{ - private $userInfo; - - protected $storage; - - /** - * @param OAuth2\Storage\UserCredentialsInterface $storage REQUIRED Storage class for retrieving user credentials information - */ - public function __construct(UserCredentialsInterface $storage) - { - $this->storage = $storage; - } - - public function getQuerystringIdentifier() - { - return 'password'; - } - - public function validateRequest(RequestInterface $request, ResponseInterface $response) - { - if (!$request->request("password") || !$request->request("username")) { - $response->setError(400, 'invalid_request', 'Missing parameters: "username" and "password" required'); - - return null; - } - - if (!$this->storage->checkUserCredentials($request->request("username"), $request->request("password"))) { - $response->setError(401, 'invalid_grant', 'Invalid username and password combination'); - - return null; - } - - $userInfo = $this->storage->getUserDetails($request->request("username")); - - if (empty($userInfo)) { - $response->setError(400, 'invalid_grant', 'Unable to retrieve user information'); - - return null; - } - - if (!isset($userInfo['user_id'])) { - throw new \LogicException("you must set the user_id on the array returned by getUserDetails"); - } - - $this->userInfo = $userInfo; - - return true; - } - - public function getClientId() - { - return null; - } - - public function getUserId() - { - return $this->userInfo['user_id']; - } - - public function getScope() - { - return isset($this->userInfo['scope']) ? $this->userInfo['scope'] : null; - } - - public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) - { - return $accessToken->createAccessToken($client_id, $user_id, $scope); - } -} diff --git a/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeController.php b/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeController.php deleted file mode 100644 index c9b5c6af7..000000000 --- a/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeController.php +++ /dev/null @@ -1,106 +0,0 @@ -<?php - -namespace OAuth2\OpenID\Controller; - -use OAuth2\Controller\AuthorizeController as BaseAuthorizeController; -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -/** - * @see OAuth2\Controller\AuthorizeControllerInterface - */ -class AuthorizeController extends BaseAuthorizeController implements AuthorizeControllerInterface -{ - private $nonce; - - protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null) - { - $prompt = $request->query('prompt', 'consent'); - if ($prompt == 'none') { - if (is_null($user_id)) { - $error = 'login_required'; - $error_message = 'The user must log in'; - } else { - $error = 'interaction_required'; - $error_message = 'The user must grant access to your application'; - } - } else { - $error = 'consent_required'; - $error_message = 'The user denied access to your application'; - } - - $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->getState(), $error, $error_message); - } - - protected function buildAuthorizeParameters($request, $response, $user_id) - { - if (!$params = parent::buildAuthorizeParameters($request, $response, $user_id)) { - return; - } - - // Generate an id token if needed. - if ($this->needsIdToken($this->getScope()) && $this->getResponseType() == self::RESPONSE_TYPE_AUTHORIZATION_CODE) { - $params['id_token'] = $this->responseTypes['id_token']->createIdToken($this->getClientId(), $user_id, $this->nonce); - } - - // add the nonce to return with the redirect URI - $params['nonce'] = $this->nonce; - - return $params; - } - - public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response) - { - if (!parent::validateAuthorizeRequest($request, $response)) { - return false; - } - - $nonce = $request->query('nonce'); - - // Validate required nonce for "id_token" and "id_token token" - if (!$nonce && in_array($this->getResponseType(), array(self::RESPONSE_TYPE_ID_TOKEN, self::RESPONSE_TYPE_ID_TOKEN_TOKEN))) { - $response->setError(400, 'invalid_nonce', 'This application requires you specify a nonce parameter'); - - return false; - } - - $this->nonce = $nonce; - - return true; - } - - protected function getValidResponseTypes() - { - return array( - self::RESPONSE_TYPE_ACCESS_TOKEN, - self::RESPONSE_TYPE_AUTHORIZATION_CODE, - self::RESPONSE_TYPE_ID_TOKEN, - self::RESPONSE_TYPE_ID_TOKEN_TOKEN, - self::RESPONSE_TYPE_CODE_ID_TOKEN, - ); - } - - /** - * Returns whether the current request needs to generate an id token. - * - * ID Tokens are a part of the OpenID Connect specification, so this - * method checks whether OpenID Connect is enabled in the server settings - * and whether the openid scope was requested. - * - * @param $request_scope - * A space-separated string of scopes. - * - * @return - * TRUE if an id token is needed, FALSE otherwise. - */ - public function needsIdToken($request_scope) - { - // see if the "openid" scope exists in the requested scope - return $this->scopeUtil->checkScope('openid', $request_scope); - } - - public function getNonce() - { - return $this->nonce; - } -} diff --git a/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php b/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php deleted file mode 100644 index 1e231d844..000000000 --- a/library/oauth2/src/OAuth2/OpenID/Controller/AuthorizeControllerInterface.php +++ /dev/null @@ -1,10 +0,0 @@ -<?php - -namespace OAuth2\OpenID\Controller; - -interface AuthorizeControllerInterface -{ - const RESPONSE_TYPE_ID_TOKEN = 'id_token'; - const RESPONSE_TYPE_ID_TOKEN_TOKEN = 'id_token token'; - const RESPONSE_TYPE_CODE_ID_TOKEN = 'code id_token'; -} diff --git a/library/oauth2/src/OAuth2/OpenID/Controller/UserInfoController.php b/library/oauth2/src/OAuth2/OpenID/Controller/UserInfoController.php deleted file mode 100644 index 30cb942d0..000000000 --- a/library/oauth2/src/OAuth2/OpenID/Controller/UserInfoController.php +++ /dev/null @@ -1,58 +0,0 @@ -<?php - -namespace OAuth2\OpenID\Controller; - -use OAuth2\Scope; -use OAuth2\TokenType\TokenTypeInterface; -use OAuth2\Storage\AccessTokenInterface; -use OAuth2\OpenID\Storage\UserClaimsInterface; -use OAuth2\Controller\ResourceController; -use OAuth2\ScopeInterface; -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -/** - * @see OAuth2\Controller\UserInfoControllerInterface - */ -class UserInfoController extends ResourceController implements UserInfoControllerInterface -{ - private $token; - - protected $tokenType; - protected $tokenStorage; - protected $userClaimsStorage; - protected $config; - protected $scopeUtil; - - public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, UserClaimsInterface $userClaimsStorage, $config = array(), ScopeInterface $scopeUtil = null) - { - $this->tokenType = $tokenType; - $this->tokenStorage = $tokenStorage; - $this->userClaimsStorage = $userClaimsStorage; - - $this->config = array_merge(array( - 'www_realm' => 'Service', - ), $config); - - if (is_null($scopeUtil)) { - $scopeUtil = new Scope(); - } - $this->scopeUtil = $scopeUtil; - } - - public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response) - { - if (!$this->verifyResourceRequest($request, $response, 'openid')) { - return; - } - - $token = $this->getToken(); - $claims = $this->userClaimsStorage->getUserClaims($token['user_id'], $token['scope']); - // The sub Claim MUST always be returned in the UserInfo Response. - // http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse - $claims += array( - 'sub' => $token['user_id'], - ); - $response->addParameters($claims); - } -} diff --git a/library/oauth2/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php b/library/oauth2/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php deleted file mode 100644 index a89049d49..000000000 --- a/library/oauth2/src/OAuth2/OpenID/Controller/UserInfoControllerInterface.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php - -namespace OAuth2\OpenID\Controller; - -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -/** - * This controller is called when the user claims for OpenID Connect's - * UserInfo endpoint should be returned. - * - * ex: - * > $response = new OAuth2\Response(); - * > $userInfoController->handleUserInfoRequest( - * > OAuth2\Request::createFromGlobals(), - * > $response; - * > $response->send(); - * - */ -interface UserInfoControllerInterface -{ - public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response); -} diff --git a/library/oauth2/src/OAuth2/OpenID/GrantType/AuthorizationCode.php b/library/oauth2/src/OAuth2/OpenID/GrantType/AuthorizationCode.php deleted file mode 100644 index 8ed1edc26..000000000 --- a/library/oauth2/src/OAuth2/OpenID/GrantType/AuthorizationCode.php +++ /dev/null @@ -1,33 +0,0 @@ -<?php - -namespace OAuth2\OpenID\GrantType; - -use OAuth2\GrantType\AuthorizationCode as BaseAuthorizationCode; -use OAuth2\ResponseType\AccessTokenInterface; - -/** - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -class AuthorizationCode extends BaseAuthorizationCode -{ - public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) - { - $includeRefreshToken = true; - if (isset($this->authCode['id_token'])) { - // OpenID Connect requests include the refresh token only if the - // offline_access scope has been requested and granted. - $scopes = explode(' ', trim($scope)); - $includeRefreshToken = in_array('offline_access', $scopes); - } - - $token = $accessToken->createAccessToken($client_id, $user_id, $scope, $includeRefreshToken); - if (isset($this->authCode['id_token'])) { - $token['id_token'] = $this->authCode['id_token']; - } - - $this->storage->expireAuthorizationCode($this->authCode['code']); - - return $token; - } -} diff --git a/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php deleted file mode 100644 index 8971954c5..000000000 --- a/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCode.php +++ /dev/null @@ -1,60 +0,0 @@ -<?php - -namespace OAuth2\OpenID\ResponseType; - -use OAuth2\ResponseType\AuthorizationCode as BaseAuthorizationCode; -use OAuth2\OpenID\Storage\AuthorizationCodeInterface as AuthorizationCodeStorageInterface; - -/** - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -class AuthorizationCode extends BaseAuthorizationCode implements AuthorizationCodeInterface -{ - public function __construct(AuthorizationCodeStorageInterface $storage, array $config = array()) - { - parent::__construct($storage, $config); - } - - public function getAuthorizeResponse($params, $user_id = null) - { - // build the URL to redirect to - $result = array('query' => array()); - - $params += array('scope' => null, 'state' => null, 'id_token' => null); - - $result['query']['code'] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope'], $params['id_token']); - - if (isset($params['state'])) { - $result['query']['state'] = $params['state']; - } - - return array($params['redirect_uri'], $result); - } - - /** - * Handle the creation of the authorization code. - * - * @param $client_id - * Client identifier related to the authorization code - * @param $user_id - * User ID associated with the authorization code - * @param $redirect_uri - * An absolute URI to which the authorization server will redirect the - * user-agent to when the end-user authorization step is completed. - * @param $scope - * (optional) Scopes to be stored in space-separated string. - * @param $id_token - * (optional) The OpenID Connect id_token. - * - * @see http://tools.ietf.org/html/rfc6749#section-4 - * @ingroup oauth2_section_4 - */ - public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null, $id_token = null) - { - $code = $this->generateAuthorizationCode(); - $this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope, $id_token); - - return $code; - } -} diff --git a/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php deleted file mode 100644 index ea4779255..000000000 --- a/library/oauth2/src/OAuth2/OpenID/ResponseType/AuthorizationCodeInterface.php +++ /dev/null @@ -1,27 +0,0 @@ -<?php - -namespace OAuth2\OpenID\ResponseType; - -use OAuth2\ResponseType\AuthorizationCodeInterface as BaseAuthorizationCodeInterface; - -/** - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface -{ - /** - * Handle the creation of the authorization code. - * - * @param $client_id Client identifier related to the authorization code - * @param $user_id User ID associated with the authorization code - * @param $redirect_uri An absolute URI to which the authorization server will redirect the - * user-agent to when the end-user authorization step is completed. - * @param $scope OPTIONAL Scopes to be stored in space-separated string. - * @param $id_token OPTIONAL The OpenID Connect id_token. - * - * @see http://tools.ietf.org/html/rfc6749#section-4 - * @ingroup oauth2_section_4 - */ - public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null, $id_token = null); -} diff --git a/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdToken.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdToken.php deleted file mode 100644 index ac7764d6c..000000000 --- a/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdToken.php +++ /dev/null @@ -1,24 +0,0 @@ -<?php - -namespace OAuth2\OpenID\ResponseType; - -class CodeIdToken implements CodeIdTokenInterface -{ - protected $authCode; - protected $idToken; - - public function __construct(AuthorizationCodeInterface $authCode, IdTokenInterface $idToken) - { - $this->authCode = $authCode; - $this->idToken = $idToken; - } - - public function getAuthorizeResponse($params, $user_id = null) - { - $result = $this->authCode->getAuthorizeResponse($params, $user_id); - $resultIdToken = $this->idToken->getAuthorizeResponse($params, $user_id); - $result[1]['query']['id_token'] = $resultIdToken[1]['fragment']['id_token']; - - return $result; - } -} diff --git a/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php deleted file mode 100644 index 629adcca8..000000000 --- a/library/oauth2/src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php +++ /dev/null @@ -1,9 +0,0 @@ -<?php - -namespace OAuth2\OpenID\ResponseType; - -use OAuth2\ResponseType\ResponseTypeInterface; - -interface CodeIdTokenInterface extends ResponseTypeInterface -{ -} diff --git a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdToken.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/IdToken.php deleted file mode 100644 index 97777fbf2..000000000 --- a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdToken.php +++ /dev/null @@ -1,124 +0,0 @@ -<?php - -namespace OAuth2\OpenID\ResponseType; - -use OAuth2\Encryption\EncryptionInterface; -use OAuth2\Encryption\Jwt; -use OAuth2\Storage\PublicKeyInterface; -use OAuth2\OpenID\Storage\UserClaimsInterface; - -class IdToken implements IdTokenInterface -{ - protected $userClaimsStorage; - protected $publicKeyStorage; - protected $config; - protected $encryptionUtil; - - public function __construct(UserClaimsInterface $userClaimsStorage, PublicKeyInterface $publicKeyStorage, array $config = array(), EncryptionInterface $encryptionUtil = null) - { - $this->userClaimsStorage = $userClaimsStorage; - $this->publicKeyStorage = $publicKeyStorage; - if (is_null($encryptionUtil)) { - $encryptionUtil = new Jwt(); - } - $this->encryptionUtil = $encryptionUtil; - - if (!isset($config['issuer'])) { - throw new \LogicException('config parameter "issuer" must be set'); - } - $this->config = array_merge(array( - 'id_lifetime' => 3600, - ), $config); - } - - public function getAuthorizeResponse($params, $userInfo = null) - { - // build the URL to redirect to - $result = array('query' => array()); - $params += array('scope' => null, 'state' => null, 'nonce' => null); - - // create the id token. - list($user_id, $auth_time) = $this->getUserIdAndAuthTime($userInfo); - $userClaims = $this->userClaimsStorage->getUserClaims($user_id, $params['scope']); - - $id_token = $this->createIdToken($params['client_id'], $userInfo, $params['nonce'], $userClaims, null); - $result["fragment"] = array('id_token' => $id_token); - if (isset($params['state'])) { - $result["fragment"]["state"] = $params['state']; - } - - return array($params['redirect_uri'], $result); - } - - public function createIdToken($client_id, $userInfo, $nonce = null, $userClaims = null, $access_token = null) - { - // pull auth_time from user info if supplied - list($user_id, $auth_time) = $this->getUserIdAndAuthTime($userInfo); - - $token = array( - 'iss' => $this->config['issuer'], - 'sub' => $user_id, - 'aud' => $client_id, - 'iat' => time(), - 'exp' => time() + $this->config['id_lifetime'], - 'auth_time' => $auth_time, - ); - - if ($nonce) { - $token['nonce'] = $nonce; - } - - if ($userClaims) { - $token += $userClaims; - } - - if ($access_token) { - $token['at_hash'] = $this->createAtHash($access_token, $client_id); - } - - return $this->encodeToken($token, $client_id); - } - - protected function createAtHash($access_token, $client_id = null) - { - // maps HS256 and RS256 to sha256, etc. - $algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id); - $hash_algorithm = 'sha' . substr($algorithm, 2); - $hash = hash($hash_algorithm, $access_token, true); - $at_hash = substr($hash, 0, strlen($hash) / 2); - - return $this->encryptionUtil->urlSafeB64Encode($at_hash); - } - - protected function encodeToken(array $token, $client_id = null) - { - $private_key = $this->publicKeyStorage->getPrivateKey($client_id); - $algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id); - - return $this->encryptionUtil->encode($token, $private_key, $algorithm); - } - - private function getUserIdAndAuthTime($userInfo) - { - $auth_time = null; - - // support an array for user_id / auth_time - if (is_array($userInfo)) { - if (!isset($userInfo['user_id'])) { - throw new \LogicException('if $user_id argument is an array, user_id index must be set'); - } - - $auth_time = isset($userInfo['auth_time']) ? $userInfo['auth_time'] : null; - $user_id = $userInfo['user_id']; - } else { - $user_id = $userInfo; - } - - if (is_null($auth_time)) { - $auth_time = time(); - } - - // userInfo is a scalar, and so this is the $user_id. Auth Time is null - return array($user_id, $auth_time); - } -} diff --git a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php deleted file mode 100644 index 0bd2f8391..000000000 --- a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenInterface.php +++ /dev/null @@ -1,29 +0,0 @@ -<?php - -namespace OAuth2\OpenID\ResponseType; - -use OAuth2\ResponseType\ResponseTypeInterface; - -interface IdTokenInterface extends ResponseTypeInterface -{ - /** - * Create the id token. - * - * If Authorization Code Flow is used, the id_token is generated when the - * authorization code is issued, and later returned from the token endpoint - * together with the access_token. - * If the Implicit Flow is used, the token and id_token are generated and - * returned together. - * - * @param string $client_id The client id. - * @param string $user_id The user id. - * @param string $nonce OPTIONAL The nonce. - * @param string $userClaims OPTIONAL Claims about the user. - * @param string $access_token OPTIONAL The access token, if known. - * - * @return string The ID Token represented as a JSON Web Token (JWT). - * - * @see http://openid.net/specs/openid-connect-core-1_0.html#IDToken - */ - public function createIdToken($client_id, $userInfo, $nonce = null, $userClaims = null, $access_token = null); -} diff --git a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenToken.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenToken.php deleted file mode 100644 index f0c59799b..000000000 --- a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenToken.php +++ /dev/null @@ -1,27 +0,0 @@ -<?php - -namespace OAuth2\OpenID\ResponseType; - -use OAuth2\ResponseType\AccessTokenInterface; - -class IdTokenToken implements IdTokenTokenInterface -{ - protected $accessToken; - protected $idToken; - - public function __construct(AccessTokenInterface $accessToken, IdTokenInterface $idToken) - { - $this->accessToken = $accessToken; - $this->idToken = $idToken; - } - - public function getAuthorizeResponse($params, $user_id = null) - { - $result = $this->accessToken->getAuthorizeResponse($params, $user_id); - $access_token = $result[1]['fragment']['access_token']; - $id_token = $this->idToken->createIdToken($params['client_id'], $user_id, $params['nonce'], null, $access_token); - $result[1]['fragment']['id_token'] = $id_token; - - return $result; - } -} diff --git a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php b/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php deleted file mode 100644 index ac13e2032..000000000 --- a/library/oauth2/src/OAuth2/OpenID/ResponseType/IdTokenTokenInterface.php +++ /dev/null @@ -1,9 +0,0 @@ -<?php - -namespace OAuth2\OpenID\ResponseType; - -use OAuth2\ResponseType\ResponseTypeInterface; - -interface IdTokenTokenInterface extends ResponseTypeInterface -{ -} diff --git a/library/oauth2/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php b/library/oauth2/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php deleted file mode 100644 index 51dd867ec..000000000 --- a/library/oauth2/src/OAuth2/OpenID/Storage/AuthorizationCodeInterface.php +++ /dev/null @@ -1,37 +0,0 @@ -<?php - -namespace OAuth2\OpenID\Storage; - -use OAuth2\Storage\AuthorizationCodeInterface as BaseAuthorizationCodeInterface; -/** - * Implement this interface to specify where the OAuth2 Server - * should get/save authorization codes for the "Authorization Code" - * grant type - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface -{ - /** - * Take the provided authorization code values and store them somewhere. - * - * This function should be the storage counterpart to getAuthCode(). - * - * If storage fails for some reason, we're not currently checking for - * any sort of success/failure, so you should bail out of the script - * and provide a descriptive fail message. - * - * Required for OAuth2::GRANT_TYPE_AUTH_CODE. - * - * @param $code authorization code to be stored. - * @param $client_id client identifier to be stored. - * @param $user_id user identifier to be stored. - * @param string $redirect_uri redirect URI(s) to be stored in a space-separated string. - * @param int $expires expiration to be stored as a Unix timestamp. - * @param string $scope OPTIONAL scopes to be stored in space-separated string. - * @param string $id_token OPTIONAL the OpenID Connect id_token. - * - * @ingroup oauth2_section_4 - */ - public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null); -} diff --git a/library/oauth2/src/OAuth2/OpenID/Storage/UserClaimsInterface.php b/library/oauth2/src/OAuth2/OpenID/Storage/UserClaimsInterface.php deleted file mode 100644 index f230bef9e..000000000 --- a/library/oauth2/src/OAuth2/OpenID/Storage/UserClaimsInterface.php +++ /dev/null @@ -1,38 +0,0 @@ -<?php - -namespace OAuth2\OpenID\Storage; - -/** - * Implement this interface to specify where the OAuth2 Server - * should retrieve user claims for the OpenID Connect id_token. - */ -interface UserClaimsInterface -{ - // valid scope values to pass into the user claims API call - const VALID_CLAIMS = 'profile email address phone'; - - // fields returned for the claims above - const PROFILE_CLAIM_VALUES = 'name family_name given_name middle_name nickname preferred_username profile picture website gender birthdate zoneinfo locale updated_at'; - const EMAIL_CLAIM_VALUES = 'email email_verified'; - const ADDRESS_CLAIM_VALUES = 'formatted street_address locality region postal_code country'; - const PHONE_CLAIM_VALUES = 'phone_number phone_number_verified'; - - /** - * Return claims about the provided user id. - * - * Groups of claims are returned based on the requested scopes. No group - * is required, and no claim is required. - * - * @param $user_id - * The id of the user for which claims should be returned. - * @param $scope - * The requested scope. - * Scopes with matching claims: profile, email, address, phone. - * - * @return - * An array in the claim => value format. - * - * @see http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims - */ - public function getUserClaims($user_id, $scope); -} diff --git a/library/oauth2/src/OAuth2/Request.php b/library/oauth2/src/OAuth2/Request.php deleted file mode 100644 index c92cee821..000000000 --- a/library/oauth2/src/OAuth2/Request.php +++ /dev/null @@ -1,213 +0,0 @@ -<?php - -namespace OAuth2; - -/** - * OAuth2\Request - * This class is taken from the Symfony2 Framework and is part of the Symfony package. - * See Symfony\Component\HttpFoundation\Request (https://github.com/symfony/symfony) - */ -class Request implements RequestInterface -{ - public $attributes; - public $request; - public $query; - public $server; - public $files; - public $cookies; - public $headers; - public $content; - - /** - * Constructor. - * - * @param array $query The GET parameters - * @param array $request The POST parameters - * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...) - * @param array $cookies The COOKIE parameters - * @param array $files The FILES parameters - * @param array $server The SERVER parameters - * @param string $content The raw body data - * - * @api - */ - public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null, array $headers = null) - { - $this->initialize($query, $request, $attributes, $cookies, $files, $server, $content, $headers); - } - - /** - * Sets the parameters for this request. - * - * This method also re-initializes all properties. - * - * @param array $query The GET parameters - * @param array $request The POST parameters - * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...) - * @param array $cookies The COOKIE parameters - * @param array $files The FILES parameters - * @param array $server The SERVER parameters - * @param string $content The raw body data - * - * @api - */ - public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null, array $headers = null) - { - $this->request = $request; - $this->query = $query; - $this->attributes = $attributes; - $this->cookies = $cookies; - $this->files = $files; - $this->server = $server; - $this->content = $content; - $this->headers = is_null($headers) ? $this->getHeadersFromServer($this->server) : $headers; - } - - public function query($name, $default = null) - { - return isset($this->query[$name]) ? $this->query[$name] : $default; - } - - public function request($name, $default = null) - { - return isset($this->request[$name]) ? $this->request[$name] : $default; - } - - public function server($name, $default = null) - { - return isset($this->server[$name]) ? $this->server[$name] : $default; - } - - public function headers($name, $default = null) - { - $headers = array_change_key_case($this->headers); - $name = strtolower($name); - - return isset($headers[$name]) ? $headers[$name] : $default; - } - - public function getAllQueryParameters() - { - return $this->query; - } - - /** - * Returns the request body content. - * - * @param Boolean $asResource If true, a resource will be returned - * - * @return string|resource The request body content or a resource to read the body stream. - */ - public function getContent($asResource = false) - { - if (false === $this->content || (true === $asResource && null !== $this->content)) { - throw new \LogicException('getContent() can only be called once when using the resource return type.'); - } - - if (true === $asResource) { - $this->content = false; - - return fopen('php://input', 'rb'); - } - - if (null === $this->content) { - $this->content = file_get_contents('php://input'); - } - - return $this->content; - } - - private function getHeadersFromServer($server) - { - $headers = array(); - foreach ($server as $key => $value) { - if (0 === strpos($key, 'HTTP_')) { - $headers[substr($key, 5)] = $value; - } - // CONTENT_* are not prefixed with HTTP_ - elseif (in_array($key, array('CONTENT_LENGTH', 'CONTENT_MD5', 'CONTENT_TYPE'))) { - $headers[$key] = $value; - } - } - - if (isset($server['PHP_AUTH_USER'])) { - $headers['PHP_AUTH_USER'] = $server['PHP_AUTH_USER']; - $headers['PHP_AUTH_PW'] = isset($server['PHP_AUTH_PW']) ? $server['PHP_AUTH_PW'] : ''; - } else { - /* - * php-cgi under Apache does not pass HTTP Basic user/pass to PHP by default - * For this workaround to work, add this line to your .htaccess file: - * RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] - * - * A sample .htaccess file: - * RewriteEngine On - * RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] - * RewriteCond %{REQUEST_FILENAME} !-f - * RewriteRule ^(.*)$ app.php [QSA,L] - */ - - $authorizationHeader = null; - if (isset($server['HTTP_AUTHORIZATION'])) { - $authorizationHeader = $server['HTTP_AUTHORIZATION']; - } elseif (isset($server['REDIRECT_HTTP_AUTHORIZATION'])) { - $authorizationHeader = $server['REDIRECT_HTTP_AUTHORIZATION']; - } elseif (function_exists('apache_request_headers')) { - $requestHeaders = (array) apache_request_headers(); - - // Server-side fix for bug in old Android versions (a nice side-effect of this fix means we don't care about capitalization for Authorization) - $requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders)); - - if (isset($requestHeaders['Authorization'])) { - $authorizationHeader = trim($requestHeaders['Authorization']); - } - } - - if (null !== $authorizationHeader) { - $headers['AUTHORIZATION'] = $authorizationHeader; - // Decode AUTHORIZATION header into PHP_AUTH_USER and PHP_AUTH_PW when authorization header is basic - if (0 === stripos($authorizationHeader, 'basic')) { - $exploded = explode(':', base64_decode(substr($authorizationHeader, 6))); - if (count($exploded) == 2) { - list($headers['PHP_AUTH_USER'], $headers['PHP_AUTH_PW']) = $exploded; - } - } - } - } - - // PHP_AUTH_USER/PHP_AUTH_PW - if (isset($headers['PHP_AUTH_USER'])) { - $headers['AUTHORIZATION'] = 'Basic '.base64_encode($headers['PHP_AUTH_USER'].':'.$headers['PHP_AUTH_PW']); - } - - return $headers; - } - - /** - * Creates a new request with values from PHP's super globals. - * - * @return Request A new request - * - * @api - */ - public static function createFromGlobals() - { - $class = get_called_class(); - $request = new $class($_GET, $_POST, array(), $_COOKIE, $_FILES, $_SERVER); - - $contentType = $request->server('CONTENT_TYPE', ''); - $requestMethod = $request->server('REQUEST_METHOD', 'GET'); - if (0 === strpos($contentType, 'application/x-www-form-urlencoded') - && in_array(strtoupper($requestMethod), array('PUT', 'DELETE')) - ) { - parse_str($request->getContent(), $data); - $request->request = $data; - } elseif (0 === strpos($contentType, 'application/json') - && in_array(strtoupper($requestMethod), array('POST', 'PUT', 'DELETE')) - ) { - $data = json_decode($request->getContent(), true); - $request->request = $data; - } - - return $request; - } -} diff --git a/library/oauth2/src/OAuth2/RequestInterface.php b/library/oauth2/src/OAuth2/RequestInterface.php deleted file mode 100644 index 8a70d5fad..000000000 --- a/library/oauth2/src/OAuth2/RequestInterface.php +++ /dev/null @@ -1,16 +0,0 @@ -<?php - -namespace OAuth2; - -interface RequestInterface -{ - public function query($name, $default = null); - - public function request($name, $default = null); - - public function server($name, $default = null); - - public function headers($name, $default = null); - - public function getAllQueryParameters(); -} diff --git a/library/oauth2/src/OAuth2/Response.php b/library/oauth2/src/OAuth2/Response.php deleted file mode 100644 index d8eabe79e..000000000 --- a/library/oauth2/src/OAuth2/Response.php +++ /dev/null @@ -1,369 +0,0 @@ -<?php - -namespace OAuth2; - -/** - * Class to handle OAuth2 Responses in a graceful way. Use this interface - * to output the proper OAuth2 responses. - * - * @see OAuth2\ResponseInterface - * - * This class borrows heavily from the Symfony2 Framework and is part of the symfony package - * @see Symfony\Component\HttpFoundation\Request (https://github.com/symfony/symfony) - */ -class Response implements ResponseInterface -{ - public $version; - protected $statusCode = 200; - protected $statusText; - protected $parameters = array(); - protected $httpHeaders = array(); - - public static $statusTexts = array( - 100 => 'Continue', - 101 => 'Switching Protocols', - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 307 => 'Temporary Redirect', - 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', - 418 => 'I\'m a teapot', - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported', - ); - - public function __construct($parameters = array(), $statusCode = 200, $headers = array()) - { - $this->setParameters($parameters); - $this->setStatusCode($statusCode); - $this->setHttpHeaders($headers); - $this->version = '1.1'; - } - - /** - * Converts the response object to string containing all headers and the response content. - * - * @return string The response with headers and content - */ - public function __toString() - { - $headers = array(); - foreach ($this->httpHeaders as $name => $value) { - $headers[$name] = (array) $value; - } - - return - sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n". - $this->getHttpHeadersAsString($headers)."\r\n". - $this->getResponseBody(); - } - - /** - * Returns the build header line. - * - * @param string $name The header name - * @param string $value The header value - * - * @return string The built header line - */ - protected function buildHeader($name, $value) - { - return sprintf("%s: %s\n", $name, $value); - } - - public function getStatusCode() - { - return $this->statusCode; - } - - public function setStatusCode($statusCode, $text = null) - { - $this->statusCode = (int) $statusCode; - if ($this->isInvalid()) { - throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $statusCode)); - } - - $this->statusText = false === $text ? '' : (null === $text ? self::$statusTexts[$this->statusCode] : $text); - } - - public function getStatusText() - { - return $this->statusText; - } - - public function getParameters() - { - return $this->parameters; - } - - public function setParameters(array $parameters) - { - $this->parameters = $parameters; - } - - public function addParameters(array $parameters) - { - $this->parameters = array_merge($this->parameters, $parameters); - } - - public function getParameter($name, $default = null) - { - return isset($this->parameters[$name]) ? $this->parameters[$name] : $default; - } - - public function setParameter($name, $value) - { - $this->parameters[$name] = $value; - } - - public function setHttpHeaders(array $httpHeaders) - { - $this->httpHeaders = $httpHeaders; - } - - public function setHttpHeader($name, $value) - { - $this->httpHeaders[$name] = $value; - } - - public function addHttpHeaders(array $httpHeaders) - { - $this->httpHeaders = array_merge($this->httpHeaders, $httpHeaders); - } - - public function getHttpHeaders() - { - return $this->httpHeaders; - } - - public function getHttpHeader($name, $default = null) - { - return isset($this->httpHeaders[$name]) ? $this->httpHeaders[$name] : $default; - } - - public function getResponseBody($format = 'json') - { - switch ($format) { - case 'json': - return json_encode($this->parameters); - case 'xml': - // this only works for single-level arrays - $xml = new \SimpleXMLElement('<response/>'); - foreach ($this->parameters as $key => $param) { - $xml->addChild($key, $param); - } - - return $xml->asXML(); - } - - throw new \InvalidArgumentException(sprintf('The format %s is not supported', $format)); - - } - - public function send($format = 'json') - { - // headers have already been sent by the developer - if (headers_sent()) { - return; - } - - switch ($format) { - case 'json': - $this->setHttpHeader('Content-Type', 'application/json'); - break; - case 'xml': - $this->setHttpHeader('Content-Type', 'text/xml'); - break; - } - // status - header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)); - - foreach ($this->getHttpHeaders() as $name => $header) { - header(sprintf('%s: %s', $name, $header)); - } - echo $this->getResponseBody($format); - } - - public function setError($statusCode, $error, $errorDescription = null, $errorUri = null) - { - $parameters = array( - 'error' => $error, - 'error_description' => $errorDescription, - ); - - if (!is_null($errorUri)) { - if (strlen($errorUri) > 0 && $errorUri[0] == '#') { - // we are referencing an oauth bookmark (for brevity) - $errorUri = 'http://tools.ietf.org/html/rfc6749' . $errorUri; - } - $parameters['error_uri'] = $errorUri; - } - - $httpHeaders = array( - 'Cache-Control' => 'no-store' - ); - - $this->setStatusCode($statusCode); - $this->addParameters($parameters); - $this->addHttpHeaders($httpHeaders); - - if (!$this->isClientError() && !$this->isServerError()) { - throw new \InvalidArgumentException(sprintf('The HTTP status code is not an error ("%s" given).', $statusCode)); - } - } - - public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null) - { - if (empty($url)) { - throw new \InvalidArgumentException('Cannot redirect to an empty URL.'); - } - - $parameters = array(); - - if (!is_null($state)) { - $parameters['state'] = $state; - } - - if (!is_null($error)) { - $this->setError(400, $error, $errorDescription, $errorUri); - } - $this->setStatusCode($statusCode); - $this->addParameters($parameters); - - if (count($this->parameters) > 0) { - // add parameters to URL redirection - $parts = parse_url($url); - $sep = isset($parts['query']) && count($parts['query']) > 0 ? '&' : '?'; - $url .= $sep . http_build_query($this->parameters); - } - - $this->addHttpHeaders(array('Location' => $url)); - - if (!$this->isRedirection()) { - throw new \InvalidArgumentException(sprintf('The HTTP status code is not a redirect ("%s" given).', $statusCode)); - } - } - - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html - /** - * @return Boolean - * - * @api - */ - public function isInvalid() - { - return $this->statusCode < 100 || $this->statusCode >= 600; - } - - /** - * @return Boolean - * - * @api - */ - public function isInformational() - { - return $this->statusCode >= 100 && $this->statusCode < 200; - } - - /** - * @return Boolean - * - * @api - */ - public function isSuccessful() - { - return $this->statusCode >= 200 && $this->statusCode < 300; - } - - /** - * @return Boolean - * - * @api - */ - public function isRedirection() - { - return $this->statusCode >= 300 && $this->statusCode < 400; - } - - /** - * @return Boolean - * - * @api - */ - public function isClientError() - { - return $this->statusCode >= 400 && $this->statusCode < 500; - } - - /** - * @return Boolean - * - * @api - */ - public function isServerError() - { - return $this->statusCode >= 500 && $this->statusCode < 600; - } - - /* - * Functions from Symfony2 HttpFoundation - output pretty header - */ - private function getHttpHeadersAsString($headers) - { - if (count($headers) == 0) { - return ''; - } - - $max = max(array_map('strlen', array_keys($headers))) + 1; - $content = ''; - ksort($headers); - foreach ($headers as $name => $values) { - foreach ($values as $value) { - $content .= sprintf("%-{$max}s %s\r\n", $this->beautifyHeaderName($name).':', $value); - } - } - - return $content; - } - - private function beautifyHeaderName($name) - { - return preg_replace_callback('/\-(.)/', array($this, 'beautifyCallback'), ucfirst($name)); - } - - private function beautifyCallback($match) - { - return '-'.strtoupper($match[1]); - } -} diff --git a/library/oauth2/src/OAuth2/ResponseInterface.php b/library/oauth2/src/OAuth2/ResponseInterface.php deleted file mode 100644 index c99b5f7d1..000000000 --- a/library/oauth2/src/OAuth2/ResponseInterface.php +++ /dev/null @@ -1,24 +0,0 @@ -<?php - -namespace OAuth2; - -/** - * Interface which represents an object response. Meant to handle and display the proper OAuth2 Responses - * for errors and successes - * - * @see OAuth2\Response - */ -interface ResponseInterface -{ - public function addParameters(array $parameters); - - public function addHttpHeaders(array $httpHeaders); - - public function setStatusCode($statusCode); - - public function setError($statusCode, $name, $description = null, $uri = null); - - public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null); - - public function getParameter($name); -} diff --git a/library/oauth2/src/OAuth2/ResponseType/AccessToken.php b/library/oauth2/src/OAuth2/ResponseType/AccessToken.php deleted file mode 100644 index b235ad0c5..000000000 --- a/library/oauth2/src/OAuth2/ResponseType/AccessToken.php +++ /dev/null @@ -1,194 +0,0 @@ -<?php - -namespace OAuth2\ResponseType; - -use OAuth2\Storage\AccessTokenInterface as AccessTokenStorageInterface; -use OAuth2\Storage\RefreshTokenInterface; - -/** - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -class AccessToken implements AccessTokenInterface -{ - protected $tokenStorage; - protected $refreshStorage; - protected $config; - - /** - * @param OAuth2\Storage\AccessTokenInterface $tokenStorage REQUIRED Storage class for saving access token information - * @param OAuth2\Storage\RefreshTokenInterface $refreshStorage OPTIONAL Storage class for saving refresh token information - * @param array $config OPTIONAL Configuration options for the server - * <code> - * $config = array( - * 'token_type' => 'bearer', // token type identifier - * 'access_lifetime' => 3600, // time before access token expires - * 'refresh_token_lifetime' => 1209600, // time before refresh token expires - * ); - * </endcode> - */ - public function __construct(AccessTokenStorageInterface $tokenStorage, RefreshTokenInterface $refreshStorage = null, array $config = array()) - { - $this->tokenStorage = $tokenStorage; - $this->refreshStorage = $refreshStorage; - - $this->config = array_merge(array( - 'token_type' => 'bearer', - 'access_lifetime' => 3600, - 'refresh_token_lifetime' => 1209600, - ), $config); - } - - public function getAuthorizeResponse($params, $user_id = null) - { - // build the URL to redirect to - $result = array('query' => array()); - - $params += array('scope' => null, 'state' => null); - - /* - * a refresh token MUST NOT be included in the fragment - * - * @see http://tools.ietf.org/html/rfc6749#section-4.2.2 - */ - $includeRefreshToken = false; - $result["fragment"] = $this->createAccessToken($params['client_id'], $user_id, $params['scope'], $includeRefreshToken); - - if (isset($params['state'])) { - $result["fragment"]["state"] = $params['state']; - } - - return array($params['redirect_uri'], $result); - } - - /** - * Handle the creation of access token, also issue refresh token if supported / desirable. - * - * @param $client_id client identifier related to the access token. - * @param $user_id user ID associated with the access token - * @param $scope OPTIONAL scopes to be stored in space-separated string. - * @param bool $includeRefreshToken if true, a new refresh_token will be added to the response - * - * @see http://tools.ietf.org/html/rfc6749#section-5 - * @ingroup oauth2_section_5 - */ - public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true) - { - $token = array( - "access_token" => $this->generateAccessToken(), - "expires_in" => $this->config['access_lifetime'], - "token_type" => $this->config['token_type'], - "scope" => $scope - ); - - $this->tokenStorage->setAccessToken($token["access_token"], $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope); - - /* - * Issue a refresh token also, if we support them - * - * Refresh Tokens are considered supported if an instance of OAuth2\Storage\RefreshTokenInterface - * is supplied in the constructor - */ - if ($includeRefreshToken && $this->refreshStorage) { - $token["refresh_token"] = $this->generateRefreshToken(); - $expires = 0; - if ($this->config['refresh_token_lifetime'] > 0) { - $expires = time() + $this->config['refresh_token_lifetime']; - } - $this->refreshStorage->setRefreshToken($token['refresh_token'], $client_id, $user_id, $expires, $scope); - } - - return $token; - } - - /** - * Generates an unique access token. - * - * Implementing classes may want to override this function to implement - * other access token generation schemes. - * - * @return - * An unique access token. - * - * @ingroup oauth2_section_4 - */ - protected function generateAccessToken() - { - if (function_exists('mcrypt_create_iv')) { - $randomData = mcrypt_create_iv(20, MCRYPT_DEV_URANDOM); - if ($randomData !== false && strlen($randomData) === 20) { - return bin2hex($randomData); - } - } - if (function_exists('openssl_random_pseudo_bytes')) { - $randomData = openssl_random_pseudo_bytes(20); - if ($randomData !== false && strlen($randomData) === 20) { - return bin2hex($randomData); - } - } - if (@file_exists('/dev/urandom')) { // Get 100 bytes of random data - $randomData = file_get_contents('/dev/urandom', false, null, 0, 20); - if ($randomData !== false && strlen($randomData) === 20) { - return bin2hex($randomData); - } - } - // Last resort which you probably should just get rid of: - $randomData = mt_rand() . mt_rand() . mt_rand() . mt_rand() . microtime(true) . uniqid(mt_rand(), true); - - return substr(hash('sha512', $randomData), 0, 40); - } - - /** - * Generates an unique refresh token - * - * Implementing classes may want to override this function to implement - * other refresh token generation schemes. - * - * @return - * An unique refresh. - * - * @ingroup oauth2_section_4 - * @see OAuth2::generateAccessToken() - */ - protected function generateRefreshToken() - { - return $this->generateAccessToken(); // let's reuse the same scheme for token generation - } - - /** - * Handle the revoking of refresh tokens, and access tokens if supported / desirable - * RFC7009 specifies that "If the server is unable to locate the token using - * the given hint, it MUST extend its search across all of its supported token types" - * - * @param $token - * @param null $tokenTypeHint - * @return boolean - */ - public function revokeToken($token, $tokenTypeHint = null) - { - if ($tokenTypeHint == 'refresh_token') { - if ($this->refreshStorage && $revoked = $this->refreshStorage->unsetRefreshToken($token)) { - return true; - } - } - - /** @TODO remove in v2 */ - if (!method_exists($this->tokenStorage, 'unsetAccessToken')) { - throw new \RuntimeException( - sprintf('Token storage %s must implement unsetAccessToken method', get_class($this->tokenStorage) - )); - } - - $revoked = $this->tokenStorage->unsetAccessToken($token); - - // if a typehint is supplied and fails, try other storages - // @see https://tools.ietf.org/html/rfc7009#section-2.1 - if (!$revoked && $tokenTypeHint != 'refresh_token') { - if ($this->refreshStorage) { - $revoked = $this->refreshStorage->unsetRefreshToken($token); - } - } - - return $revoked; - } -} diff --git a/library/oauth2/src/OAuth2/ResponseType/AccessTokenInterface.php b/library/oauth2/src/OAuth2/ResponseType/AccessTokenInterface.php deleted file mode 100644 index 4bd3928d8..000000000 --- a/library/oauth2/src/OAuth2/ResponseType/AccessTokenInterface.php +++ /dev/null @@ -1,34 +0,0 @@ -<?php - -namespace OAuth2\ResponseType; - -/** - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -interface AccessTokenInterface extends ResponseTypeInterface -{ - /** - * Handle the creation of access token, also issue refresh token if supported / desirable. - * - * @param $client_id client identifier related to the access token. - * @param $user_id user ID associated with the access token - * @param $scope OPTONAL scopes to be stored in space-separated string. - * @param bool $includeRefreshToken if true, a new refresh_token will be added to the response - * - * @see http://tools.ietf.org/html/rfc6749#section-5 - * @ingroup oauth2_section_5 - */ - public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true); - - /** - * Handle the revoking of refresh tokens, and access tokens if supported / desirable - * - * @param $token - * @param $tokenTypeHint - * @return mixed - * - * @todo v2.0 include this method in interface. Omitted to maintain BC in v1.x - */ - //public function revokeToken($token, $tokenTypeHint); -} diff --git a/library/oauth2/src/OAuth2/ResponseType/AuthorizationCode.php b/library/oauth2/src/OAuth2/ResponseType/AuthorizationCode.php deleted file mode 100644 index 6a305fd75..000000000 --- a/library/oauth2/src/OAuth2/ResponseType/AuthorizationCode.php +++ /dev/null @@ -1,100 +0,0 @@ -<?php - -namespace OAuth2\ResponseType; - -use OAuth2\Storage\AuthorizationCodeInterface as AuthorizationCodeStorageInterface; - -/** - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -class AuthorizationCode implements AuthorizationCodeInterface -{ - protected $storage; - protected $config; - - public function __construct(AuthorizationCodeStorageInterface $storage, array $config = array()) - { - $this->storage = $storage; - $this->config = array_merge(array( - 'enforce_redirect' => false, - 'auth_code_lifetime' => 30, - ), $config); - } - - public function getAuthorizeResponse($params, $user_id = null) - { - // build the URL to redirect to - $result = array('query' => array()); - - $params += array('scope' => null, 'state' => null); - - $result['query']['code'] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope']); - - if (isset($params['state'])) { - $result['query']['state'] = $params['state']; - } - - return array($params['redirect_uri'], $result); - } - - /** - * Handle the creation of the authorization code. - * - * @param $client_id - * Client identifier related to the authorization code - * @param $user_id - * User ID associated with the authorization code - * @param $redirect_uri - * An absolute URI to which the authorization server will redirect the - * user-agent to when the end-user authorization step is completed. - * @param $scope - * (optional) Scopes to be stored in space-separated string. - * - * @see http://tools.ietf.org/html/rfc6749#section-4 - * @ingroup oauth2_section_4 - */ - public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null) - { - $code = $this->generateAuthorizationCode(); - $this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope); - - return $code; - } - - /** - * @return - * TRUE if the grant type requires a redirect_uri, FALSE if not - */ - public function enforceRedirect() - { - return $this->config['enforce_redirect']; - } - - /** - * Generates an unique auth code. - * - * Implementing classes may want to override this function to implement - * other auth code generation schemes. - * - * @return - * An unique auth code. - * - * @ingroup oauth2_section_4 - */ - protected function generateAuthorizationCode() - { - $tokenLen = 40; - if (function_exists('mcrypt_create_iv')) { - $randomData = mcrypt_create_iv(100, MCRYPT_DEV_URANDOM); - } elseif (function_exists('openssl_random_pseudo_bytes')) { - $randomData = openssl_random_pseudo_bytes(100); - } elseif (@file_exists('/dev/urandom')) { // Get 100 bytes of random data - $randomData = file_get_contents('/dev/urandom', false, null, 0, 100) . uniqid(mt_rand(), true); - } else { - $randomData = mt_rand() . mt_rand() . mt_rand() . mt_rand() . microtime(true) . uniqid(mt_rand(), true); - } - - return substr(hash('sha512', $randomData), 0, $tokenLen); - } -} diff --git a/library/oauth2/src/OAuth2/ResponseType/AuthorizationCodeInterface.php b/library/oauth2/src/OAuth2/ResponseType/AuthorizationCodeInterface.php deleted file mode 100644 index df777e221..000000000 --- a/library/oauth2/src/OAuth2/ResponseType/AuthorizationCodeInterface.php +++ /dev/null @@ -1,30 +0,0 @@ -<?php - -namespace OAuth2\ResponseType; - -/** - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -interface AuthorizationCodeInterface extends ResponseTypeInterface -{ - /** - * @return - * TRUE if the grant type requires a redirect_uri, FALSE if not - */ - public function enforceRedirect(); - - /** - * Handle the creation of the authorization code. - * - * @param $client_id client identifier related to the authorization code - * @param $user_id user id associated with the authorization code - * @param $redirect_uri an absolute URI to which the authorization server will redirect the - * user-agent to when the end-user authorization step is completed. - * @param $scope OPTIONAL scopes to be stored in space-separated string. - * - * @see http://tools.ietf.org/html/rfc6749#section-4 - * @ingroup oauth2_section_4 - */ - public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null); -} diff --git a/library/oauth2/src/OAuth2/ResponseType/JwtAccessToken.php b/library/oauth2/src/OAuth2/ResponseType/JwtAccessToken.php deleted file mode 100644 index 3942fe41e..000000000 --- a/library/oauth2/src/OAuth2/ResponseType/JwtAccessToken.php +++ /dev/null @@ -1,124 +0,0 @@ -<?php - -namespace OAuth2\ResponseType; - -use OAuth2\Encryption\EncryptionInterface; -use OAuth2\Encryption\Jwt; -use OAuth2\Storage\AccessTokenInterface as AccessTokenStorageInterface; -use OAuth2\Storage\RefreshTokenInterface; -use OAuth2\Storage\PublicKeyInterface; -use OAuth2\Storage\Memory; - -/** - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -class JwtAccessToken extends AccessToken -{ - protected $publicKeyStorage; - protected $encryptionUtil; - - /** - * @param $config - * - store_encrypted_token_string (bool true) - * whether the entire encrypted string is stored, - * or just the token ID is stored - */ - public function __construct(PublicKeyInterface $publicKeyStorage = null, AccessTokenStorageInterface $tokenStorage = null, RefreshTokenInterface $refreshStorage = null, array $config = array(), EncryptionInterface $encryptionUtil = null) - { - $this->publicKeyStorage = $publicKeyStorage; - $config = array_merge(array( - 'store_encrypted_token_string' => true, - 'issuer' => '' - ), $config); - if (is_null($tokenStorage)) { - // a pass-thru, so we can call the parent constructor - $tokenStorage = new Memory(); - } - if (is_null($encryptionUtil)) { - $encryptionUtil = new Jwt(); - } - $this->encryptionUtil = $encryptionUtil; - parent::__construct($tokenStorage, $refreshStorage, $config); - } - - /** - * Handle the creation of access token, also issue refresh token if supported / desirable. - * - * @param $client_id - * Client identifier related to the access token. - * @param $user_id - * User ID associated with the access token - * @param $scope - * (optional) Scopes to be stored in space-separated string. - * @param bool $includeRefreshToken - * If true, a new refresh_token will be added to the response - * - * @see http://tools.ietf.org/html/rfc6749#section-5 - * @ingroup oauth2_section_5 - */ - public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true) - { - // token to encrypt - $expires = time() + $this->config['access_lifetime']; - $id = $this->generateAccessToken(); - $jwtAccessToken = array( - 'id' => $id, // for BC (see #591) - 'jti' => $id, - 'iss' => $this->config['issuer'], - 'aud' => $client_id, - 'sub' => $user_id, - 'exp' => $expires, - 'iat' => time(), - 'token_type' => $this->config['token_type'], - 'scope' => $scope - ); - - /* - * Encode the token data into a single access_token string - */ - $access_token = $this->encodeToken($jwtAccessToken, $client_id); - - /* - * Save the token to a secondary storage. This is implemented on the - * OAuth2\Storage\JwtAccessToken side, and will not actually store anything, - * if no secondary storage has been supplied - */ - $token_to_store = $this->config['store_encrypted_token_string'] ? $access_token : $jwtAccessToken['id']; - $this->tokenStorage->setAccessToken($token_to_store, $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope); - - // token to return to the client - $token = array( - 'access_token' => $access_token, - 'expires_in' => $this->config['access_lifetime'], - 'token_type' => $this->config['token_type'], - 'scope' => $scope - ); - - /* - * Issue a refresh token also, if we support them - * - * Refresh Tokens are considered supported if an instance of OAuth2\Storage\RefreshTokenInterface - * is supplied in the constructor - */ - if ($includeRefreshToken && $this->refreshStorage) { - $refresh_token = $this->generateRefreshToken(); - $expires = 0; - if ($this->config['refresh_token_lifetime'] > 0) { - $expires = time() + $this->config['refresh_token_lifetime']; - } - $this->refreshStorage->setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope); - $token['refresh_token'] = $refresh_token; - } - - return $token; - } - - protected function encodeToken(array $token, $client_id = null) - { - $private_key = $this->publicKeyStorage->getPrivateKey($client_id); - $algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id); - - return $this->encryptionUtil->encode($token, $private_key, $algorithm); - } -} diff --git a/library/oauth2/src/OAuth2/ResponseType/ResponseTypeInterface.php b/library/oauth2/src/OAuth2/ResponseType/ResponseTypeInterface.php deleted file mode 100644 index f8e26a5b0..000000000 --- a/library/oauth2/src/OAuth2/ResponseType/ResponseTypeInterface.php +++ /dev/null @@ -1,8 +0,0 @@ -<?php - -namespace OAuth2\ResponseType; - -interface ResponseTypeInterface -{ - public function getAuthorizeResponse($params, $user_id = null); -} diff --git a/library/oauth2/src/OAuth2/Scope.php b/library/oauth2/src/OAuth2/Scope.php deleted file mode 100644 index c44350bfd..000000000 --- a/library/oauth2/src/OAuth2/Scope.php +++ /dev/null @@ -1,103 +0,0 @@ -<?php - -namespace OAuth2; - -use OAuth2\Storage\Memory; -use OAuth2\Storage\ScopeInterface as ScopeStorageInterface; - -/** -* @see OAuth2\ScopeInterface -*/ -class Scope implements ScopeInterface -{ - protected $storage; - - /** - * @param mixed @storage - * Either an array of supported scopes, or an instance of OAuth2\Storage\ScopeInterface - */ - public function __construct($storage = null) - { - if (is_null($storage) || is_array($storage)) { - $storage = new Memory((array) $storage); - } - - if (!$storage instanceof ScopeStorageInterface) { - throw new \InvalidArgumentException("Argument 1 to OAuth2\Scope must be null, an array, or instance of OAuth2\Storage\ScopeInterface"); - } - - $this->storage = $storage; - } - - /** - * Check if everything in required scope is contained in available scope. - * - * @param $required_scope - * A space-separated string of scopes. - * - * @return - * TRUE if everything in required scope is contained in available scope, - * and FALSE if it isn't. - * - * @see http://tools.ietf.org/html/rfc6749#section-7 - * - * @ingroup oauth2_section_7 - */ - public function checkScope($required_scope, $available_scope) - { - $required_scope = explode(' ', trim($required_scope)); - $available_scope = explode(' ', trim($available_scope)); - - return (count(array_diff($required_scope, $available_scope)) == 0); - } - - /** - * Check if the provided scope exists in storage. - * - * @param $scope - * A space-separated string of scopes. - * - * @return - * TRUE if it exists, FALSE otherwise. - */ - public function scopeExists($scope) - { - // Check reserved scopes first. - $scope = explode(' ', trim($scope)); - $reservedScope = $this->getReservedScopes(); - $nonReservedScopes = array_diff($scope, $reservedScope); - if (count($nonReservedScopes) == 0) { - return true; - } else { - // Check the storage for non-reserved scopes. - $nonReservedScopes = implode(' ', $nonReservedScopes); - - return $this->storage->scopeExists($nonReservedScopes); - } - } - - public function getScopeFromRequest(RequestInterface $request) - { - // "scope" is valid if passed in either POST or QUERY - return $request->request('scope', $request->query('scope')); - } - - public function getDefaultScope($client_id = null) - { - return $this->storage->getDefaultScope($client_id); - } - - /** - * Get reserved scopes needed by the server. - * - * In case OpenID Connect is used, these scopes must include: - * 'openid', offline_access'. - * - * @return - * An array of reserved scopes. - */ - public function getReservedScopes() - { - return array('openid', 'offline_access'); - } -} diff --git a/library/oauth2/src/OAuth2/ScopeInterface.php b/library/oauth2/src/OAuth2/ScopeInterface.php deleted file mode 100644 index 5b60f9aee..000000000 --- a/library/oauth2/src/OAuth2/ScopeInterface.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php - -namespace OAuth2; - -use OAuth2\Storage\ScopeInterface as ScopeStorageInterface; - -/** - * Class to handle scope implementation logic - * - * @see OAuth2\Storage\ScopeInterface - */ -interface ScopeInterface extends ScopeStorageInterface -{ - /** - * Check if everything in required scope is contained in available scope. - * - * @param $required_scope - * A space-separated string of scopes. - * - * @return - * TRUE if everything in required scope is contained in available scope, - * and FALSE if it isn't. - * - * @see http://tools.ietf.org/html/rfc6749#section-7 - * - * @ingroup oauth2_section_7 - */ - public function checkScope($required_scope, $available_scope); - - /** - * Return scope info from request - * - * @param OAuth2\RequestInterface - * Request object to check - * - * @return - * string representation of requested scope - */ - public function getScopeFromRequest(RequestInterface $request); -} diff --git a/library/oauth2/src/OAuth2/Server.php b/library/oauth2/src/OAuth2/Server.php deleted file mode 100644 index 171a4f069..000000000 --- a/library/oauth2/src/OAuth2/Server.php +++ /dev/null @@ -1,832 +0,0 @@ -<?php - -namespace OAuth2; - -use OAuth2\Controller\ResourceControllerInterface; -use OAuth2\Controller\ResourceController; -use OAuth2\OpenID\Controller\UserInfoControllerInterface; -use OAuth2\OpenID\Controller\UserInfoController; -use OAuth2\OpenID\Controller\AuthorizeController as OpenIDAuthorizeController; -use OAuth2\OpenID\ResponseType\AuthorizationCode as OpenIDAuthorizationCodeResponseType; -use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; -use OAuth2\OpenID\GrantType\AuthorizationCode as OpenIDAuthorizationCodeGrantType; -use OAuth2\Controller\AuthorizeControllerInterface; -use OAuth2\Controller\AuthorizeController; -use OAuth2\Controller\TokenControllerInterface; -use OAuth2\Controller\TokenController; -use OAuth2\ClientAssertionType\ClientAssertionTypeInterface; -use OAuth2\ClientAssertionType\HttpBasic; -use OAuth2\ResponseType\ResponseTypeInterface; -use OAuth2\ResponseType\AuthorizationCode as AuthorizationCodeResponseType; -use OAuth2\ResponseType\AccessToken; -use OAuth2\ResponseType\JwtAccessToken; -use OAuth2\OpenID\ResponseType\CodeIdToken; -use OAuth2\OpenID\ResponseType\IdToken; -use OAuth2\OpenID\ResponseType\IdTokenToken; -use OAuth2\TokenType\TokenTypeInterface; -use OAuth2\TokenType\Bearer; -use OAuth2\GrantType\GrantTypeInterface; -use OAuth2\GrantType\UserCredentials; -use OAuth2\GrantType\ClientCredentials; -use OAuth2\GrantType\RefreshToken; -use OAuth2\GrantType\AuthorizationCode; -use OAuth2\Storage\JwtAccessToken as JwtAccessTokenStorage; -use OAuth2\Storage\JwtAccessTokenInterface; - -/** -* Server class for OAuth2 -* This class serves as a convience class which wraps the other Controller classes -* -* @see OAuth2\Controller\ResourceController -* @see OAuth2\Controller\AuthorizeController -* @see OAuth2\Controller\TokenController -*/ -class Server implements ResourceControllerInterface, - AuthorizeControllerInterface, - TokenControllerInterface, - UserInfoControllerInterface -{ - // misc properties - protected $response; - protected $config; - protected $storages; - - // servers - protected $authorizeController; - protected $tokenController; - protected $resourceController; - protected $userInfoController; - - // config classes - protected $grantTypes; - protected $responseTypes; - protected $tokenType; - protected $scopeUtil; - protected $clientAssertionType; - - protected $storageMap = array( - 'access_token' => 'OAuth2\Storage\AccessTokenInterface', - 'authorization_code' => 'OAuth2\Storage\AuthorizationCodeInterface', - 'client_credentials' => 'OAuth2\Storage\ClientCredentialsInterface', - 'client' => 'OAuth2\Storage\ClientInterface', - 'refresh_token' => 'OAuth2\Storage\RefreshTokenInterface', - 'user_credentials' => 'OAuth2\Storage\UserCredentialsInterface', - 'user_claims' => 'OAuth2\OpenID\Storage\UserClaimsInterface', - 'public_key' => 'OAuth2\Storage\PublicKeyInterface', - 'jwt_bearer' => 'OAuth2\Storage\JWTBearerInterface', - 'scope' => 'OAuth2\Storage\ScopeInterface', - ); - - protected $responseTypeMap = array( - 'token' => 'OAuth2\ResponseType\AccessTokenInterface', - 'code' => 'OAuth2\ResponseType\AuthorizationCodeInterface', - 'id_token' => 'OAuth2\OpenID\ResponseType\IdTokenInterface', - 'id_token token' => 'OAuth2\OpenID\ResponseType\IdTokenTokenInterface', - 'code id_token' => 'OAuth2\OpenID\ResponseType\CodeIdTokenInterface', - ); - - /** - * @param mixed $storage (array or OAuth2\Storage) - single object or array of objects implementing the - * required storage types (ClientCredentialsInterface and AccessTokenInterface as a minimum) - * @param array $config specify a different token lifetime, token header name, etc - * @param array $grantTypes An array of OAuth2\GrantType\GrantTypeInterface to use for granting access tokens - * @param array $responseTypes Response types to use. array keys should be "code" and and "token" for - * Access Token and Authorization Code response types - * @param OAuth2\TokenType\TokenTypeInterface $tokenType The token type object to use. Valid token types are "bearer" and "mac" - * @param OAuth2\ScopeInterface $scopeUtil The scope utility class to use to validate scope - * @param OAuth2\ClientAssertionType\ClientAssertionTypeInterface $clientAssertionType The method in which to verify the client identity. Default is HttpBasic - * - * @ingroup oauth2_section_7 - */ - public function __construct($storage = array(), array $config = array(), array $grantTypes = array(), array $responseTypes = array(), TokenTypeInterface $tokenType = null, ScopeInterface $scopeUtil = null, ClientAssertionTypeInterface $clientAssertionType = null) - { - $storage = is_array($storage) ? $storage : array($storage); - $this->storages = array(); - foreach ($storage as $key => $service) { - $this->addStorage($service, $key); - } - - // merge all config values. These get passed to our controller objects - $this->config = array_merge(array( - 'use_jwt_access_tokens' => false, - 'store_encrypted_token_string' => true, - 'use_openid_connect' => false, - 'id_lifetime' => 3600, - 'access_lifetime' => 3600, - 'www_realm' => 'Service', - 'token_param_name' => 'access_token', - 'token_bearer_header_name' => 'Bearer', - 'enforce_state' => true, - 'require_exact_redirect_uri' => true, - 'allow_implicit' => false, - 'allow_credentials_in_request_body' => true, - 'allow_public_clients' => true, - 'always_issue_new_refresh_token' => false, - 'unset_refresh_token_after_use' => true, - ), $config); - - foreach ($grantTypes as $key => $grantType) { - $this->addGrantType($grantType, $key); - } - - foreach ($responseTypes as $key => $responseType) { - $this->addResponseType($responseType, $key); - } - - $this->tokenType = $tokenType; - $this->scopeUtil = $scopeUtil; - $this->clientAssertionType = $clientAssertionType; - - if ($this->config['use_openid_connect']) { - $this->validateOpenIdConnect(); - } - } - - public function getAuthorizeController() - { - if (is_null($this->authorizeController)) { - $this->authorizeController = $this->createDefaultAuthorizeController(); - } - - return $this->authorizeController; - } - - public function getTokenController() - { - if (is_null($this->tokenController)) { - $this->tokenController = $this->createDefaultTokenController(); - } - - return $this->tokenController; - } - - public function getResourceController() - { - if (is_null($this->resourceController)) { - $this->resourceController = $this->createDefaultResourceController(); - } - - return $this->resourceController; - } - - public function getUserInfoController() - { - if (is_null($this->userInfoController)) { - $this->userInfoController = $this->createDefaultUserInfoController(); - } - - return $this->userInfoController; - } - - /** - * every getter deserves a setter - */ - public function setAuthorizeController(AuthorizeControllerInterface $authorizeController) - { - $this->authorizeController = $authorizeController; - } - - /** - * every getter deserves a setter - */ - public function setTokenController(TokenControllerInterface $tokenController) - { - $this->tokenController = $tokenController; - } - - /** - * every getter deserves a setter - */ - public function setResourceController(ResourceControllerInterface $resourceController) - { - $this->resourceController = $resourceController; - } - - /** - * every getter deserves a setter - */ - public function setUserInfoController(UserInfoControllerInterface $userInfoController) - { - $this->userInfoController = $userInfoController; - } - - /** - * Return claims about the authenticated end-user. - * This would be called from the "/UserInfo" endpoint as defined in the spec. - * - * @param $request - OAuth2\RequestInterface - * Request object to grant access token - * - * @param $response - OAuth2\ResponseInterface - * Response object containing error messages (failure) or user claims (success) - * - * @throws InvalidArgumentException - * @throws LogicException - * - * @see http://openid.net/specs/openid-connect-core-1_0.html#UserInfo - */ - public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response = null) - { - $this->response = is_null($response) ? new Response() : $response; - $this->getUserInfoController()->handleUserInfoRequest($request, $this->response); - - return $this->response; - } - - /** - * Grant or deny a requested access token. - * This would be called from the "/token" endpoint as defined in the spec. - * Obviously, you can call your endpoint whatever you want. - * - * @param $request - OAuth2\RequestInterface - * Request object to grant access token - * - * @param $response - OAuth2\ResponseInterface - * Response object containing error messages (failure) or access token (success) - * - * @throws InvalidArgumentException - * @throws LogicException - * - * @see http://tools.ietf.org/html/rfc6749#section-4 - * @see http://tools.ietf.org/html/rfc6749#section-10.6 - * @see http://tools.ietf.org/html/rfc6749#section-4.1.3 - * - * @ingroup oauth2_section_4 - */ - public function handleTokenRequest(RequestInterface $request, ResponseInterface $response = null) - { - $this->response = is_null($response) ? new Response() : $response; - $this->getTokenController()->handleTokenRequest($request, $this->response); - - return $this->response; - } - - public function grantAccessToken(RequestInterface $request, ResponseInterface $response = null) - { - $this->response = is_null($response) ? new Response() : $response; - $value = $this->getTokenController()->grantAccessToken($request, $this->response); - - return $value; - } - - /** - * Handle a revoke token request - * This would be called from the "/revoke" endpoint as defined in the draft Token Revocation spec - * - * @see https://tools.ietf.org/html/rfc7009#section-2 - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return Response|ResponseInterface - */ - public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response = null) - { - $this->response = is_null($response) ? new Response() : $response; - $this->getTokenController()->handleRevokeRequest($request, $this->response); - - return $this->response; - } - - /** - * Redirect the user appropriately after approval. - * - * After the user has approved or denied the resource request the - * authorization server should call this function to redirect the user - * appropriately. - * - * @param $request - * The request should have the follow parameters set in the querystring: - * - response_type: The requested response: an access token, an - * authorization code, or both. - * - client_id: The client identifier as described in Section 2. - * - redirect_uri: An absolute URI to which the authorization server - * will redirect the user-agent to when the end-user authorization - * step is completed. - * - scope: (optional) The scope of the resource request expressed as a - * list of space-delimited strings. - * - state: (optional) An opaque value used by the client to maintain - * state between the request and callback. - * @param $is_authorized - * TRUE or FALSE depending on whether the user authorized the access. - * @param $user_id - * Identifier of user who authorized the client - * - * @see http://tools.ietf.org/html/rfc6749#section-4 - * - * @ingroup oauth2_section_4 - */ - public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null) - { - $this->response = $response; - $this->getAuthorizeController()->handleAuthorizeRequest($request, $this->response, $is_authorized, $user_id); - - return $this->response; - } - - /** - * Pull the authorization request data out of the HTTP request. - * - The redirect_uri is OPTIONAL as per draft 20. But your implementation can enforce it - * by setting $config['enforce_redirect'] to true. - * - The state is OPTIONAL but recommended to enforce CSRF. Draft 21 states, however, that - * CSRF protection is MANDATORY. You can enforce this by setting the $config['enforce_state'] to true. - * - * The draft specifies that the parameters should be retrieved from GET, override the Response - * object to change this - * - * @return - * The authorization parameters so the authorization server can prompt - * the user for approval if valid. - * - * @see http://tools.ietf.org/html/rfc6749#section-4.1.1 - * @see http://tools.ietf.org/html/rfc6749#section-10.12 - * - * @ingroup oauth2_section_3 - */ - public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response = null) - { - $this->response = is_null($response) ? new Response() : $response; - $value = $this->getAuthorizeController()->validateAuthorizeRequest($request, $this->response); - - return $value; - } - - public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response = null, $scope = null) - { - $this->response = is_null($response) ? new Response() : $response; - $value = $this->getResourceController()->verifyResourceRequest($request, $this->response, $scope); - - return $value; - } - - public function getAccessTokenData(RequestInterface $request, ResponseInterface $response = null) - { - $this->response = is_null($response) ? new Response() : $response; - $value = $this->getResourceController()->getAccessTokenData($request, $this->response); - - return $value; - } - - public function addGrantType(GrantTypeInterface $grantType, $identifier = null) - { - if (!is_string($identifier)) { - $identifier = $grantType->getQuerystringIdentifier(); - } - - $this->grantTypes[$identifier] = $grantType; - - // persist added grant type down to TokenController - if (!is_null($this->tokenController)) { - $this->getTokenController()->addGrantType($grantType, $identifier); - } - } - - /** - * Set a storage object for the server - * - * @param $storage - * An object implementing one of the Storage interfaces - * @param $key - * If null, the storage is set to the key of each storage interface it implements - * - * @see storageMap - */ - public function addStorage($storage, $key = null) - { - // if explicitly set to a valid key, do not "magically" set below - if (isset($this->storageMap[$key])) { - if (!is_null($storage) && !$storage instanceof $this->storageMap[$key]) { - throw new \InvalidArgumentException(sprintf('storage of type "%s" must implement interface "%s"', $key, $this->storageMap[$key])); - } - $this->storages[$key] = $storage; - - // special logic to handle "client" and "client_credentials" strangeness - if ($key === 'client' && !isset($this->storages['client_credentials'])) { - if ($storage instanceof \OAuth2\Storage\ClientCredentialsInterface) { - $this->storages['client_credentials'] = $storage; - } - } elseif ($key === 'client_credentials' && !isset($this->storages['client'])) { - if ($storage instanceof \OAuth2\Storage\ClientInterface) { - $this->storages['client'] = $storage; - } - } - } elseif (!is_null($key) && !is_numeric($key)) { - throw new \InvalidArgumentException(sprintf('unknown storage key "%s", must be one of [%s]', $key, implode(', ', array_keys($this->storageMap)))); - } else { - $set = false; - foreach ($this->storageMap as $type => $interface) { - if ($storage instanceof $interface) { - $this->storages[$type] = $storage; - $set = true; - } - } - - if (!$set) { - throw new \InvalidArgumentException(sprintf('storage of class "%s" must implement one of [%s]', get_class($storage), implode(', ', $this->storageMap))); - } - } - } - - public function addResponseType(ResponseTypeInterface $responseType, $key = null) - { - $key = $this->normalizeResponseType($key); - - if (isset($this->responseTypeMap[$key])) { - if (!$responseType instanceof $this->responseTypeMap[$key]) { - throw new \InvalidArgumentException(sprintf('responseType of type "%s" must implement interface "%s"', $key, $this->responseTypeMap[$key])); - } - $this->responseTypes[$key] = $responseType; - } elseif (!is_null($key) && !is_numeric($key)) { - throw new \InvalidArgumentException(sprintf('unknown responseType key "%s", must be one of [%s]', $key, implode(', ', array_keys($this->responseTypeMap)))); - } else { - $set = false; - foreach ($this->responseTypeMap as $type => $interface) { - if ($responseType instanceof $interface) { - $this->responseTypes[$type] = $responseType; - $set = true; - } - } - - if (!$set) { - throw new \InvalidArgumentException(sprintf('Unknown response type %s. Please implement one of [%s]', get_class($responseType), implode(', ', $this->responseTypeMap))); - } - } - } - - public function getScopeUtil() - { - if (!$this->scopeUtil) { - $storage = isset($this->storages['scope']) ? $this->storages['scope'] : null; - $this->scopeUtil = new Scope($storage); - } - - return $this->scopeUtil; - } - - /** - * every getter deserves a setter - */ - public function setScopeUtil($scopeUtil) - { - $this->scopeUtil = $scopeUtil; - } - - protected function createDefaultAuthorizeController() - { - if (!isset($this->storages['client'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientInterface to use the authorize server"); - } - if (0 == count($this->responseTypes)) { - $this->responseTypes = $this->getDefaultResponseTypes(); - } - if ($this->config['use_openid_connect'] && !isset($this->responseTypes['id_token'])) { - $this->responseTypes['id_token'] = $this->createDefaultIdTokenResponseType(); - if ($this->config['allow_implicit']) { - $this->responseTypes['id_token token'] = $this->createDefaultIdTokenTokenResponseType(); - } - } - - $config = array_intersect_key($this->config, array_flip(explode(' ', 'allow_implicit enforce_state require_exact_redirect_uri'))); - - if ($this->config['use_openid_connect']) { - return new OpenIDAuthorizeController($this->storages['client'], $this->responseTypes, $config, $this->getScopeUtil()); - } - - return new AuthorizeController($this->storages['client'], $this->responseTypes, $config, $this->getScopeUtil()); - } - - protected function createDefaultTokenController() - { - if (0 == count($this->grantTypes)) { - $this->grantTypes = $this->getDefaultGrantTypes(); - } - - if (is_null($this->clientAssertionType)) { - // see if HttpBasic assertion type is requred. If so, then create it from storage classes. - foreach ($this->grantTypes as $grantType) { - if (!$grantType instanceof ClientAssertionTypeInterface) { - if (!isset($this->storages['client_credentials'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientCredentialsInterface to use the token server"); - } - $config = array_intersect_key($this->config, array_flip(explode(' ', 'allow_credentials_in_request_body allow_public_clients'))); - $this->clientAssertionType = new HttpBasic($this->storages['client_credentials'], $config); - break; - } - } - } - - if (!isset($this->storages['client'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\ClientInterface to use the token server"); - } - - $accessTokenResponseType = $this->getAccessTokenResponseType(); - - return new TokenController($accessTokenResponseType, $this->storages['client'], $this->grantTypes, $this->clientAssertionType, $this->getScopeUtil()); - } - - protected function createDefaultResourceController() - { - if ($this->config['use_jwt_access_tokens']) { - // overwrites access token storage with crypto token storage if "use_jwt_access_tokens" is set - if (!isset($this->storages['access_token']) || !$this->storages['access_token'] instanceof JwtAccessTokenInterface) { - $this->storages['access_token'] = $this->createDefaultJwtAccessTokenStorage(); - } - } elseif (!isset($this->storages['access_token'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\AccessTokenInterface or use JwtAccessTokens to use the resource server"); - } - - if (!$this->tokenType) { - $this->tokenType = $this->getDefaultTokenType(); - } - - $config = array_intersect_key($this->config, array('www_realm' => '')); - - return new ResourceController($this->tokenType, $this->storages['access_token'], $config, $this->getScopeUtil()); - } - - protected function createDefaultUserInfoController() - { - if ($this->config['use_jwt_access_tokens']) { - // overwrites access token storage with crypto token storage if "use_jwt_access_tokens" is set - if (!isset($this->storages['access_token']) || !$this->storages['access_token'] instanceof JwtAccessTokenInterface) { - $this->storages['access_token'] = $this->createDefaultJwtAccessTokenStorage(); - } - } elseif (!isset($this->storages['access_token'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\AccessTokenInterface or use JwtAccessTokens to use the UserInfo server"); - } - - if (!isset($this->storages['user_claims'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\OpenID\Storage\UserClaimsInterface to use the UserInfo server"); - } - - if (!$this->tokenType) { - $this->tokenType = $this->getDefaultTokenType(); - } - - $config = array_intersect_key($this->config, array('www_realm' => '')); - - return new UserInfoController($this->tokenType, $this->storages['access_token'], $this->storages['user_claims'], $config, $this->getScopeUtil()); - } - - protected function getDefaultTokenType() - { - $config = array_intersect_key($this->config, array_flip(explode(' ', 'token_param_name token_bearer_header_name'))); - - return new Bearer($config); - } - - protected function getDefaultResponseTypes() - { - $responseTypes = array(); - - if ($this->config['allow_implicit']) { - $responseTypes['token'] = $this->getAccessTokenResponseType(); - } - - if ($this->config['use_openid_connect']) { - $responseTypes['id_token'] = $this->getIdTokenResponseType(); - if ($this->config['allow_implicit']) { - $responseTypes['id_token token'] = $this->getIdTokenTokenResponseType(); - } - } - - if (isset($this->storages['authorization_code'])) { - $config = array_intersect_key($this->config, array_flip(explode(' ', 'enforce_redirect auth_code_lifetime'))); - if ($this->config['use_openid_connect']) { - if (!$this->storages['authorization_code'] instanceof OpenIDAuthorizationCodeInterface) { - throw new \LogicException("Your authorization_code storage must implement OAuth2\OpenID\Storage\AuthorizationCodeInterface to work when 'use_openid_connect' is true"); - } - $responseTypes['code'] = new OpenIDAuthorizationCodeResponseType($this->storages['authorization_code'], $config); - $responseTypes['code id_token'] = new CodeIdToken($responseTypes['code'], $responseTypes['id_token']); - } else { - $responseTypes['code'] = new AuthorizationCodeResponseType($this->storages['authorization_code'], $config); - } - } - - if (count($responseTypes) == 0) { - throw new \LogicException("You must supply an array of response_types in the constructor or implement a OAuth2\Storage\AuthorizationCodeInterface storage object or set 'allow_implicit' to true and implement a OAuth2\Storage\AccessTokenInterface storage object"); - } - - return $responseTypes; - } - - protected function getDefaultGrantTypes() - { - $grantTypes = array(); - - if (isset($this->storages['user_credentials'])) { - $grantTypes['password'] = new UserCredentials($this->storages['user_credentials']); - } - - if (isset($this->storages['client_credentials'])) { - $config = array_intersect_key($this->config, array('allow_credentials_in_request_body' => '')); - $grantTypes['client_credentials'] = new ClientCredentials($this->storages['client_credentials'], $config); - } - - if (isset($this->storages['refresh_token'])) { - $config = array_intersect_key($this->config, array_flip(explode(' ', 'always_issue_new_refresh_token unset_refresh_token_after_use'))); - $grantTypes['refresh_token'] = new RefreshToken($this->storages['refresh_token'], $config); - } - - if (isset($this->storages['authorization_code'])) { - if ($this->config['use_openid_connect']) { - if (!$this->storages['authorization_code'] instanceof OpenIDAuthorizationCodeInterface) { - throw new \LogicException("Your authorization_code storage must implement OAuth2\OpenID\Storage\AuthorizationCodeInterface to work when 'use_openid_connect' is true"); - } - $grantTypes['authorization_code'] = new OpenIDAuthorizationCodeGrantType($this->storages['authorization_code']); - } else { - $grantTypes['authorization_code'] = new AuthorizationCode($this->storages['authorization_code']); - } - } - - if (count($grantTypes) == 0) { - throw new \LogicException("Unable to build default grant types - You must supply an array of grant_types in the constructor"); - } - - return $grantTypes; - } - - protected function getAccessTokenResponseType() - { - if (isset($this->responseTypes['token'])) { - return $this->responseTypes['token']; - } - - if ($this->config['use_jwt_access_tokens']) { - return $this->createDefaultJwtAccessTokenResponseType(); - } - - return $this->createDefaultAccessTokenResponseType(); - } - - protected function getIdTokenResponseType() - { - if (isset($this->responseTypes['id_token'])) { - return $this->responseTypes['id_token']; - } - - return $this->createDefaultIdTokenResponseType(); - } - - protected function getIdTokenTokenResponseType() - { - if (isset($this->responseTypes['id_token token'])) { - return $this->responseTypes['id_token token']; - } - - return $this->createDefaultIdTokenTokenResponseType(); - } - - /** - * For Resource Controller - */ - protected function createDefaultJwtAccessTokenStorage() - { - if (!isset($this->storages['public_key'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use crypto tokens"); - } - $tokenStorage = null; - if (!empty($this->config['store_encrypted_token_string']) && isset($this->storages['access_token'])) { - $tokenStorage = $this->storages['access_token']; - } - // wrap the access token storage as required. - return new JwtAccessTokenStorage($this->storages['public_key'], $tokenStorage); - } - - /** - * For Authorize and Token Controllers - */ - protected function createDefaultJwtAccessTokenResponseType() - { - if (!isset($this->storages['public_key'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use crypto tokens"); - } - - $tokenStorage = null; - if (isset($this->storages['access_token'])) { - $tokenStorage = $this->storages['access_token']; - } - - $refreshStorage = null; - if (isset($this->storages['refresh_token'])) { - $refreshStorage = $this->storages['refresh_token']; - } - - $config = array_intersect_key($this->config, array_flip(explode(' ', 'store_encrypted_token_string issuer access_lifetime refresh_token_lifetime'))); - - return new JwtAccessToken($this->storages['public_key'], $tokenStorage, $refreshStorage, $config); - } - - protected function createDefaultAccessTokenResponseType() - { - if (!isset($this->storages['access_token'])) { - throw new \LogicException("You must supply a response type implementing OAuth2\ResponseType\AccessTokenInterface, or a storage object implementing OAuth2\Storage\AccessTokenInterface to use the token server"); - } - - $refreshStorage = null; - if (isset($this->storages['refresh_token'])) { - $refreshStorage = $this->storages['refresh_token']; - } - - $config = array_intersect_key($this->config, array_flip(explode(' ', 'access_lifetime refresh_token_lifetime'))); - $config['token_type'] = $this->tokenType ? $this->tokenType->getTokenType() : $this->getDefaultTokenType()->getTokenType(); - - return new AccessToken($this->storages['access_token'], $refreshStorage, $config); - } - - protected function createDefaultIdTokenResponseType() - { - if (!isset($this->storages['user_claims'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\OpenID\Storage\UserClaimsInterface to use openid connect"); - } - if (!isset($this->storages['public_key'])) { - throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use openid connect"); - } - - $config = array_intersect_key($this->config, array_flip(explode(' ', 'issuer id_lifetime'))); - - return new IdToken($this->storages['user_claims'], $this->storages['public_key'], $config); - } - - protected function createDefaultIdTokenTokenResponseType() - { - return new IdTokenToken($this->getAccessTokenResponseType(), $this->getIdTokenResponseType()); - } - - protected function validateOpenIdConnect() - { - $authCodeGrant = $this->getGrantType('authorization_code'); - if (!empty($authCodeGrant) && !$authCodeGrant instanceof OpenIDAuthorizationCodeGrantType) { - throw new \InvalidArgumentException('You have enabled OpenID Connect, but supplied a grant type that does not support it.'); - } - } - - protected function normalizeResponseType($name) - { - // for multiple-valued response types - make them alphabetical - if (!empty($name) && false !== strpos($name, ' ')) { - $types = explode(' ', $name); - sort($types); - $name = implode(' ', $types); - } - - return $name; - } - - public function getResponse() - { - return $this->response; - } - - public function getStorages() - { - return $this->storages; - } - - public function getStorage($name) - { - return isset($this->storages[$name]) ? $this->storages[$name] : null; - } - - public function getGrantTypes() - { - return $this->grantTypes; - } - - public function getGrantType($name) - { - return isset($this->grantTypes[$name]) ? $this->grantTypes[$name] : null; - } - - public function getResponseTypes() - { - return $this->responseTypes; - } - - public function getResponseType($name) - { - // for multiple-valued response types - make them alphabetical - $name = $this->normalizeResponseType($name); - - return isset($this->responseTypes[$name]) ? $this->responseTypes[$name] : null; - } - - public function getTokenType() - { - return $this->tokenType; - } - - public function getClientAssertionType() - { - return $this->clientAssertionType; - } - - public function setConfig($name, $value) - { - $this->config[$name] = $value; - } - - public function getConfig($name, $default = null) - { - return isset($this->config[$name]) ? $this->config[$name] : $default; - } -} diff --git a/library/oauth2/src/OAuth2/Storage/AccessTokenInterface.php b/library/oauth2/src/OAuth2/Storage/AccessTokenInterface.php deleted file mode 100644 index 1819158af..000000000 --- a/library/oauth2/src/OAuth2/Storage/AccessTokenInterface.php +++ /dev/null @@ -1,64 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -/** - * Implement this interface to specify where the OAuth2 Server - * should get/save access tokens - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -interface AccessTokenInterface -{ - /** - * Look up the supplied oauth_token from storage. - * - * We need to retrieve access token data as we create and verify tokens. - * - * @param $oauth_token - * oauth_token to be check with. - * - * @return - * An associative array as below, and return NULL if the supplied oauth_token - * is invalid: - * - expires: Stored expiration in unix timestamp. - * - client_id: (optional) Stored client identifier. - * - user_id: (optional) Stored user identifier. - * - scope: (optional) Stored scope values in space-separated string. - * - id_token: (optional) Stored id_token (if "use_openid_connect" is true). - * - * @ingroup oauth2_section_7 - */ - public function getAccessToken($oauth_token); - - /** - * Store the supplied access token values to storage. - * - * We need to store access token data as we create and verify tokens. - * - * @param $oauth_token oauth_token to be stored. - * @param $client_id client identifier to be stored. - * @param $user_id user identifier to be stored. - * @param int $expires expiration to be stored as a Unix timestamp. - * @param string $scope OPTIONAL Scopes to be stored in space-separated string. - * - * @ingroup oauth2_section_4 - */ - public function setAccessToken($oauth_token, $client_id, $user_id, $expires, $scope = null); - - /** - * Expire an access token. - * - * This is not explicitly required in the spec, but if defined in a draft RFC for token - * revoking (RFC 7009) https://tools.ietf.org/html/rfc7009 - * - * @param $access_token - * Access token to be expired. - * - * @return BOOL true if an access token was unset, false if not - * @ingroup oauth2_section_6 - * - * @todo v2.0 include this method in interface. Omitted to maintain BC in v1.x - */ - //public function unsetAccessToken($access_token); -} diff --git a/library/oauth2/src/OAuth2/Storage/AuthorizationCodeInterface.php b/library/oauth2/src/OAuth2/Storage/AuthorizationCodeInterface.php deleted file mode 100644 index 3beb0e437..000000000 --- a/library/oauth2/src/OAuth2/Storage/AuthorizationCodeInterface.php +++ /dev/null @@ -1,86 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -/** - * Implement this interface to specify where the OAuth2 Server - * should get/save authorization codes for the "Authorization Code" - * grant type - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -interface AuthorizationCodeInterface -{ - /** - * The Authorization Code grant type supports a response type of "code". - * - * @var string - * @see http://tools.ietf.org/html/rfc6749#section-1.4.1 - * @see http://tools.ietf.org/html/rfc6749#section-4.2 - */ - const RESPONSE_TYPE_CODE = "code"; - - /** - * Fetch authorization code data (probably the most common grant type). - * - * Retrieve the stored data for the given authorization code. - * - * Required for OAuth2::GRANT_TYPE_AUTH_CODE. - * - * @param $code - * Authorization code to be check with. - * - * @return - * An associative array as below, and NULL if the code is invalid - * @code - * return array( - * "client_id" => CLIENT_ID, // REQUIRED Stored client identifier - * "user_id" => USER_ID, // REQUIRED Stored user identifier - * "expires" => EXPIRES, // REQUIRED Stored expiration in unix timestamp - * "redirect_uri" => REDIRECT_URI, // REQUIRED Stored redirect URI - * "scope" => SCOPE, // OPTIONAL Stored scope values in space-separated string - * ); - * @endcode - * - * @see http://tools.ietf.org/html/rfc6749#section-4.1 - * - * @ingroup oauth2_section_4 - */ - public function getAuthorizationCode($code); - - /** - * Take the provided authorization code values and store them somewhere. - * - * This function should be the storage counterpart to getAuthCode(). - * - * If storage fails for some reason, we're not currently checking for - * any sort of success/failure, so you should bail out of the script - * and provide a descriptive fail message. - * - * Required for OAuth2::GRANT_TYPE_AUTH_CODE. - * - * @param string $code Authorization code to be stored. - * @param mixed $client_id Client identifier to be stored. - * @param mixed $user_id User identifier to be stored. - * @param string $redirect_uri Redirect URI(s) to be stored in a space-separated string. - * @param int $expires Expiration to be stored as a Unix timestamp. - * @param string $scope OPTIONAL Scopes to be stored in space-separated string. - * - * @ingroup oauth2_section_4 - */ - public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null); - - /** - * once an Authorization Code is used, it must be exipired - * - * @see http://tools.ietf.org/html/rfc6749#section-4.1.2 - * - * The client MUST NOT use the authorization code - * more than once. If an authorization code is used more than - * once, the authorization server MUST deny the request and SHOULD - * revoke (when possible) all tokens previously issued based on - * that authorization code - * - */ - public function expireAuthorizationCode($code); -} diff --git a/library/oauth2/src/OAuth2/Storage/Cassandra.php b/library/oauth2/src/OAuth2/Storage/Cassandra.php deleted file mode 100644 index 602e8a058..000000000 --- a/library/oauth2/src/OAuth2/Storage/Cassandra.php +++ /dev/null @@ -1,480 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -use phpcassa\ColumnFamily; -use phpcassa\ColumnSlice; -use phpcassa\Connection\ConnectionPool; -use OAuth2\OpenID\Storage\UserClaimsInterface; -use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; - -/** - * Cassandra storage for all storage types - * - * To use, install "thobbs/phpcassa" via composer - * <code> - * composer require thobbs/phpcassa:dev-master - * </code> - * - * Once this is done, instantiate the - * <code> - * $cassandra = new \phpcassa\Connection\ConnectionPool('oauth2_server', array('127.0.0.1:9160')); - * </code> - * - * Then, register the storage client: - * <code> - * $storage = new OAuth2\Storage\Cassandra($cassandra); - * $storage->setClientDetails($client_id, $client_secret, $redirect_uri); - * </code> - * - * @see test/lib/OAuth2/Storage/Bootstrap::getCassandraStorage - */ -class Cassandra implements AuthorizationCodeInterface, - AccessTokenInterface, - ClientCredentialsInterface, - UserCredentialsInterface, - RefreshTokenInterface, - JwtBearerInterface, - ScopeInterface, - PublicKeyInterface, - UserClaimsInterface, - OpenIDAuthorizationCodeInterface -{ - - private $cache; - - /* The cassandra client */ - protected $cassandra; - - /* Configuration array */ - protected $config; - - /** - * Cassandra Storage! uses phpCassa - * - * @param \phpcassa\ConnectionPool $cassandra - * @param array $config - */ - public function __construct($connection = array(), array $config = array()) - { - if ($connection instanceof ConnectionPool) { - $this->cassandra = $connection; - } else { - if (!is_array($connection)) { - throw new \InvalidArgumentException('First argument to OAuth2\Storage\Cassandra must be an instance of phpcassa\Connection\ConnectionPool or a configuration array'); - } - $connection = array_merge(array( - 'keyspace' => 'oauth2', - 'servers' => null, - ), $connection); - - $this->cassandra = new ConnectionPool($connection['keyspace'], $connection['servers']); - } - - $this->config = array_merge(array( - // cassandra config - 'column_family' => 'auth', - - // key names - 'client_key' => 'oauth_clients:', - 'access_token_key' => 'oauth_access_tokens:', - 'refresh_token_key' => 'oauth_refresh_tokens:', - 'code_key' => 'oauth_authorization_codes:', - 'user_key' => 'oauth_users:', - 'jwt_key' => 'oauth_jwt:', - 'scope_key' => 'oauth_scopes:', - 'public_key_key' => 'oauth_public_keys:', - ), $config); - } - - protected function getValue($key) - { - if (isset($this->cache[$key])) { - return $this->cache[$key]; - } - $cf = new ColumnFamily($this->cassandra, $this->config['column_family']); - - try { - $value = $cf->get($key, new ColumnSlice("", "")); - $value = array_shift($value); - } catch (\cassandra\NotFoundException $e) { - return false; - } - - return json_decode($value, true); - } - - protected function setValue($key, $value, $expire = 0) - { - $this->cache[$key] = $value; - - $cf = new ColumnFamily($this->cassandra, $this->config['column_family']); - - $str = json_encode($value); - if ($expire > 0) { - try { - $seconds = $expire - time(); - // __data key set as C* requires a field, note: max TTL can only be 630720000 seconds - $cf->insert($key, array('__data' => $str), null, $seconds); - } catch (\Exception $e) { - return false; - } - } else { - try { - // __data key set as C* requires a field - $cf->insert($key, array('__data' => $str)); - } catch (\Exception $e) { - return false; - } - } - - return true; - } - - protected function expireValue($key) - { - unset($this->cache[$key]); - - $cf = new ColumnFamily($this->cassandra, $this->config['column_family']); - - if ($cf->get_count($key) > 0) { - try { - // __data key set as C* requires a field - $cf->remove($key, array('__data')); - } catch (\Exception $e) { - return false; - } - - return true; - } - - return false; - } - - /* AuthorizationCodeInterface */ - public function getAuthorizationCode($code) - { - return $this->getValue($this->config['code_key'] . $code); - } - - public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) - { - return $this->setValue( - $this->config['code_key'] . $authorization_code, - compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'), - $expires - ); - } - - public function expireAuthorizationCode($code) - { - $key = $this->config['code_key'] . $code; - unset($this->cache[$key]); - - return $this->expireValue($key); - } - - /* UserCredentialsInterface */ - public function checkUserCredentials($username, $password) - { - if ($user = $this->getUser($username)) { - return $this->checkPassword($user, $password); - } - - return false; - } - - // plaintext passwords are bad! Override this for your application - protected function checkPassword($user, $password) - { - return $user['password'] == $this->hashPassword($password); - } - - // use a secure hashing algorithm when storing passwords. Override this for your application - protected function hashPassword($password) - { - return sha1($password); - } - - public function getUserDetails($username) - { - return $this->getUser($username); - } - - public function getUser($username) - { - if (!$userInfo = $this->getValue($this->config['user_key'] . $username)) { - return false; - } - - // the default behavior is to use "username" as the user_id - return array_merge(array( - 'user_id' => $username, - ), $userInfo); - } - - public function setUser($username, $password, $first_name = null, $last_name = null) - { - $password = $this->hashPassword($password); - - return $this->setValue( - $this->config['user_key'] . $username, - compact('username', 'password', 'first_name', 'last_name') - ); - } - - /* ClientCredentialsInterface */ - public function checkClientCredentials($client_id, $client_secret = null) - { - if (!$client = $this->getClientDetails($client_id)) { - return false; - } - - return isset($client['client_secret']) - && $client['client_secret'] == $client_secret; - } - - public function isPublicClient($client_id) - { - if (!$client = $this->getClientDetails($client_id)) { - return false; - } - - return empty($client['client_secret']);; - } - - /* ClientInterface */ - public function getClientDetails($client_id) - { - return $this->getValue($this->config['client_key'] . $client_id); - } - - public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) - { - return $this->setValue( - $this->config['client_key'] . $client_id, - compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id') - ); - } - - public function checkRestrictedGrantType($client_id, $grant_type) - { - $details = $this->getClientDetails($client_id); - if (isset($details['grant_types'])) { - $grant_types = explode(' ', $details['grant_types']); - - return in_array($grant_type, (array) $grant_types); - } - - // if grant_types are not defined, then none are restricted - return true; - } - - /* RefreshTokenInterface */ - public function getRefreshToken($refresh_token) - { - return $this->getValue($this->config['refresh_token_key'] . $refresh_token); - } - - public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) - { - return $this->setValue( - $this->config['refresh_token_key'] . $refresh_token, - compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'), - $expires - ); - } - - public function unsetRefreshToken($refresh_token) - { - return $this->expireValue($this->config['refresh_token_key'] . $refresh_token); - } - - /* AccessTokenInterface */ - public function getAccessToken($access_token) - { - return $this->getValue($this->config['access_token_key'].$access_token); - } - - public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) - { - return $this->setValue( - $this->config['access_token_key'].$access_token, - compact('access_token', 'client_id', 'user_id', 'expires', 'scope'), - $expires - ); - } - - public function unsetAccessToken($access_token) - { - return $this->expireValue($this->config['access_token_key'] . $access_token); - } - - /* ScopeInterface */ - public function scopeExists($scope) - { - $scope = explode(' ', $scope); - - $result = $this->getValue($this->config['scope_key'].'supported:global'); - - $supportedScope = explode(' ', (string) $result); - - return (count(array_diff($scope, $supportedScope)) == 0); - } - - public function getDefaultScope($client_id = null) - { - if (is_null($client_id) || !$result = $this->getValue($this->config['scope_key'].'default:'.$client_id)) { - $result = $this->getValue($this->config['scope_key'].'default:global'); - } - - return $result; - } - - public function setScope($scope, $client_id = null, $type = 'supported') - { - if (!in_array($type, array('default', 'supported'))) { - throw new \InvalidArgumentException('"$type" must be one of "default", "supported"'); - } - - if (is_null($client_id)) { - $key = $this->config['scope_key'].$type.':global'; - } else { - $key = $this->config['scope_key'].$type.':'.$client_id; - } - - return $this->setValue($key, $scope); - } - - /*JWTBearerInterface */ - public function getClientKey($client_id, $subject) - { - if (!$jwt = $this->getValue($this->config['jwt_key'] . $client_id)) { - return false; - } - - if (isset($jwt['subject']) && $jwt['subject'] == $subject ) { - return $jwt['key']; - } - - return null; - } - - public function setClientKey($client_id, $key, $subject = null) - { - return $this->setValue($this->config['jwt_key'] . $client_id, array( - 'key' => $key, - 'subject' => $subject - )); - } - - /*ScopeInterface */ - public function getClientScope($client_id) - { - if (!$clientDetails = $this->getClientDetails($client_id)) { - return false; - } - - if (isset($clientDetails['scope'])) { - return $clientDetails['scope']; - } - - return null; - } - - public function getJti($client_id, $subject, $audience, $expiration, $jti) - { - //TODO: Needs cassandra implementation. - throw new \Exception('getJti() for the Cassandra driver is currently unimplemented.'); - } - - public function setJti($client_id, $subject, $audience, $expiration, $jti) - { - //TODO: Needs cassandra implementation. - throw new \Exception('setJti() for the Cassandra driver is currently unimplemented.'); - } - - /* PublicKeyInterface */ - public function getPublicKey($client_id = '') - { - $public_key = $this->getValue($this->config['public_key_key'] . $client_id); - if (is_array($public_key)) { - return $public_key['public_key']; - } - $public_key = $this->getValue($this->config['public_key_key']); - if (is_array($public_key)) { - return $public_key['public_key']; - } - } - - public function getPrivateKey($client_id = '') - { - $public_key = $this->getValue($this->config['public_key_key'] . $client_id); - if (is_array($public_key)) { - return $public_key['private_key']; - } - $public_key = $this->getValue($this->config['public_key_key']); - if (is_array($public_key)) { - return $public_key['private_key']; - } - } - - public function getEncryptionAlgorithm($client_id = null) - { - $public_key = $this->getValue($this->config['public_key_key'] . $client_id); - if (is_array($public_key)) { - return $public_key['encryption_algorithm']; - } - $public_key = $this->getValue($this->config['public_key_key']); - if (is_array($public_key)) { - return $public_key['encryption_algorithm']; - } - - return 'RS256'; - } - - /* UserClaimsInterface */ - public function getUserClaims($user_id, $claims) - { - $userDetails = $this->getUserDetails($user_id); - if (!is_array($userDetails)) { - return false; - } - - $claims = explode(' ', trim($claims)); - $userClaims = array(); - - // for each requested claim, if the user has the claim, set it in the response - $validClaims = explode(' ', self::VALID_CLAIMS); - foreach ($validClaims as $validClaim) { - if (in_array($validClaim, $claims)) { - if ($validClaim == 'address') { - // address is an object with subfields - $userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails); - } else { - $userClaims = array_merge($userClaims, $this->getUserClaim($validClaim, $userDetails)); - } - } - } - - return $userClaims; - } - - protected function getUserClaim($claim, $userDetails) - { - $userClaims = array(); - $claimValuesString = constant(sprintf('self::%s_CLAIM_VALUES', strtoupper($claim))); - $claimValues = explode(' ', $claimValuesString); - - foreach ($claimValues as $value) { - if ($value == 'email_verified') { - $userClaims[$value] = $userDetails[$value]=='true' ? true : false; - } else { - $userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null; - } - } - - return $userClaims; - } - -} diff --git a/library/oauth2/src/OAuth2/Storage/ClientCredentialsInterface.php b/library/oauth2/src/OAuth2/Storage/ClientCredentialsInterface.php deleted file mode 100644 index 3318c6966..000000000 --- a/library/oauth2/src/OAuth2/Storage/ClientCredentialsInterface.php +++ /dev/null @@ -1,49 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -/** - * Implement this interface to specify how the OAuth2 Server - * should verify client credentials - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -interface ClientCredentialsInterface extends ClientInterface -{ - - /** - * Make sure that the client credentials is valid. - * - * @param $client_id - * Client identifier to be check with. - * @param $client_secret - * (optional) If a secret is required, check that they've given the right one. - * - * @return - * TRUE if the client credentials are valid, and MUST return FALSE if it isn't. - * @endcode - * - * @see http://tools.ietf.org/html/rfc6749#section-3.1 - * - * @ingroup oauth2_section_3 - */ - public function checkClientCredentials($client_id, $client_secret = null); - - /** - * Determine if the client is a "public" client, and therefore - * does not require passing credentials for certain grant types - * - * @param $client_id - * Client identifier to be check with. - * - * @return - * TRUE if the client is public, and FALSE if it isn't. - * @endcode - * - * @see http://tools.ietf.org/html/rfc6749#section-2.3 - * @see https://github.com/bshaffer/oauth2-server-php/issues/257 - * - * @ingroup oauth2_section_2 - */ - public function isPublicClient($client_id); -} diff --git a/library/oauth2/src/OAuth2/Storage/ClientInterface.php b/library/oauth2/src/OAuth2/Storage/ClientInterface.php deleted file mode 100644 index 09a5bffc1..000000000 --- a/library/oauth2/src/OAuth2/Storage/ClientInterface.php +++ /dev/null @@ -1,66 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -/** - * Implement this interface to specify where the OAuth2 Server - * should retrieve client information - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -interface ClientInterface -{ - /** - * Get client details corresponding client_id. - * - * OAuth says we should store request URIs for each registered client. - * Implement this function to grab the stored URI for a given client id. - * - * @param $client_id - * Client identifier to be check with. - * - * @return array - * Client details. The only mandatory key in the array is "redirect_uri". - * This function MUST return FALSE if the given client does not exist or is - * invalid. "redirect_uri" can be space-delimited to allow for multiple valid uris. - * <code> - * return array( - * "redirect_uri" => REDIRECT_URI, // REQUIRED redirect_uri registered for the client - * "client_id" => CLIENT_ID, // OPTIONAL the client id - * "grant_types" => GRANT_TYPES, // OPTIONAL an array of restricted grant types - * "user_id" => USER_ID, // OPTIONAL the user identifier associated with this client - * "scope" => SCOPE, // OPTIONAL the scopes allowed for this client - * ); - * </code> - * - * @ingroup oauth2_section_4 - */ - public function getClientDetails($client_id); - - /** - * Get the scope associated with this client - * - * @return - * STRING the space-delineated scope list for the specified client_id - */ - public function getClientScope($client_id); - - /** - * Check restricted grant types of corresponding client identifier. - * - * If you want to restrict clients to certain grant types, override this - * function. - * - * @param $client_id - * Client identifier to be check with. - * @param $grant_type - * Grant type to be check with - * - * @return - * TRUE if the grant type is supported by this client identifier, and - * FALSE if it isn't. - * - * @ingroup oauth2_section_4 - */ - public function checkRestrictedGrantType($client_id, $grant_type); -} diff --git a/library/oauth2/src/OAuth2/Storage/CouchbaseDB.php b/library/oauth2/src/OAuth2/Storage/CouchbaseDB.php deleted file mode 100755 index 1eb55f027..000000000 --- a/library/oauth2/src/OAuth2/Storage/CouchbaseDB.php +++ /dev/null @@ -1,331 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; - -/** - * Simple Couchbase storage for all storage types - * - * This class should be extended or overridden as required - * - * NOTE: Passwords are stored in plaintext, which is never - * a good idea. Be sure to override this for your application - * - * @author Tom Park <tom@raucter.com> - */ -class CouchbaseDB implements AuthorizationCodeInterface, - AccessTokenInterface, - ClientCredentialsInterface, - UserCredentialsInterface, - RefreshTokenInterface, - JwtBearerInterface, - OpenIDAuthorizationCodeInterface -{ - protected $db; - protected $config; - - public function __construct($connection, $config = array()) - { - if ($connection instanceof \Couchbase) { - $this->db = $connection; - } else { - if (!is_array($connection) || !is_array($connection['servers'])) { - throw new \InvalidArgumentException('First argument to OAuth2\Storage\CouchbaseDB must be an instance of Couchbase or a configuration array containing a server array'); - } - - $this->db = new \Couchbase($connection['servers'], (!isset($connection['username'])) ? '' : $connection['username'], (!isset($connection['password'])) ? '' : $connection['password'], $connection['bucket'], false); - } - - $this->config = array_merge(array( - 'client_table' => 'oauth_clients', - 'access_token_table' => 'oauth_access_tokens', - 'refresh_token_table' => 'oauth_refresh_tokens', - 'code_table' => 'oauth_authorization_codes', - 'user_table' => 'oauth_users', - 'jwt_table' => 'oauth_jwt', - ), $config); - } - - // Helper function to access couchbase item by type: - protected function getObjectByType($name,$id) - { - return json_decode($this->db->get($this->config[$name].'-'.$id),true); - } - - // Helper function to set couchbase item by type: - protected function setObjectByType($name,$id,$array) - { - $array['type'] = $name; - - return $this->db->set($this->config[$name].'-'.$id,json_encode($array)); - } - - // Helper function to delete couchbase item by type, wait for persist to at least 1 node - protected function deleteObjectByType($name,$id) - { - $this->db->delete($this->config[$name].'-'.$id,"",1); - } - - /* ClientCredentialsInterface */ - public function checkClientCredentials($client_id, $client_secret = null) - { - if ($result = $this->getObjectByType('client_table',$client_id)) { - return $result['client_secret'] == $client_secret; - } - - return false; - } - - public function isPublicClient($client_id) - { - if (!$result = $this->getObjectByType('client_table',$client_id)) { - return false; - } - - return empty($result['client_secret']); - } - - /* ClientInterface */ - public function getClientDetails($client_id) - { - $result = $this->getObjectByType('client_table',$client_id); - - return is_null($result) ? false : $result; - } - - public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) - { - if ($this->getClientDetails($client_id)) { - - $this->setObjectByType('client_table',$client_id, array( - 'client_id' => $client_id, - 'client_secret' => $client_secret, - 'redirect_uri' => $redirect_uri, - 'grant_types' => $grant_types, - 'scope' => $scope, - 'user_id' => $user_id, - )); - } else { - $this->setObjectByType('client_table',$client_id, array( - 'client_id' => $client_id, - 'client_secret' => $client_secret, - 'redirect_uri' => $redirect_uri, - 'grant_types' => $grant_types, - 'scope' => $scope, - 'user_id' => $user_id, - )); - } - - return true; - } - - public function checkRestrictedGrantType($client_id, $grant_type) - { - $details = $this->getClientDetails($client_id); - if (isset($details['grant_types'])) { - $grant_types = explode(' ', $details['grant_types']); - - return in_array($grant_type, $grant_types); - } - - // if grant_types are not defined, then none are restricted - return true; - } - - /* AccessTokenInterface */ - public function getAccessToken($access_token) - { - $token = $this->getObjectByType('access_token_table',$access_token); - - return is_null($token) ? false : $token; - } - - public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) - { - // if it exists, update it. - if ($this->getAccessToken($access_token)) { - $this->setObjectByType('access_token_table',$access_token, array( - 'access_token' => $access_token, - 'client_id' => $client_id, - 'expires' => $expires, - 'user_id' => $user_id, - 'scope' => $scope - )); - } else { - $this->setObjectByType('access_token_table',$access_token, array( - 'access_token' => $access_token, - 'client_id' => $client_id, - 'expires' => $expires, - 'user_id' => $user_id, - 'scope' => $scope - )); - } - - return true; - } - - /* AuthorizationCodeInterface */ - public function getAuthorizationCode($code) - { - $code = $this->getObjectByType('code_table',$code); - - return is_null($code) ? false : $code; - } - - public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) - { - // if it exists, update it. - if ($this->getAuthorizationCode($code)) { - $this->setObjectByType('code_table',$code, array( - 'authorization_code' => $code, - 'client_id' => $client_id, - 'user_id' => $user_id, - 'redirect_uri' => $redirect_uri, - 'expires' => $expires, - 'scope' => $scope, - 'id_token' => $id_token, - )); - } else { - $this->setObjectByType('code_table',$code,array( - 'authorization_code' => $code, - 'client_id' => $client_id, - 'user_id' => $user_id, - 'redirect_uri' => $redirect_uri, - 'expires' => $expires, - 'scope' => $scope, - 'id_token' => $id_token, - )); - } - - return true; - } - - public function expireAuthorizationCode($code) - { - $this->deleteObjectByType('code_table',$code); - - return true; - } - - /* UserCredentialsInterface */ - public function checkUserCredentials($username, $password) - { - if ($user = $this->getUser($username)) { - return $this->checkPassword($user, $password); - } - - return false; - } - - public function getUserDetails($username) - { - if ($user = $this->getUser($username)) { - $user['user_id'] = $user['username']; - } - - return $user; - } - - /* RefreshTokenInterface */ - public function getRefreshToken($refresh_token) - { - $token = $this->getObjectByType('refresh_token_table',$refresh_token); - - return is_null($token) ? false : $token; - } - - public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) - { - $this->setObjectByType('refresh_token_table',$refresh_token, array( - 'refresh_token' => $refresh_token, - 'client_id' => $client_id, - 'user_id' => $user_id, - 'expires' => $expires, - 'scope' => $scope - )); - - return true; - } - - public function unsetRefreshToken($refresh_token) - { - $this->deleteObjectByType('refresh_token_table',$refresh_token); - - return true; - } - - // plaintext passwords are bad! Override this for your application - protected function checkPassword($user, $password) - { - return $user['password'] == $password; - } - - public function getUser($username) - { - $result = $this->getObjectByType('user_table',$username); - - return is_null($result) ? false : $result; - } - - public function setUser($username, $password, $firstName = null, $lastName = null) - { - if ($this->getUser($username)) { - $this->setObjectByType('user_table',$username, array( - 'username' => $username, - 'password' => $password, - 'first_name' => $firstName, - 'last_name' => $lastName - )); - - } else { - $this->setObjectByType('user_table',$username, array( - 'username' => $username, - 'password' => $password, - 'first_name' => $firstName, - 'last_name' => $lastName - )); - - } - - return true; - } - - public function getClientKey($client_id, $subject) - { - if (!$jwt = $this->getObjectByType('jwt_table',$client_id)) { - return false; - } - - if (isset($jwt['subject']) && $jwt['subject'] == $subject) { - return $jwt['key']; - } - - return false; - } - - public function getClientScope($client_id) - { - if (!$clientDetails = $this->getClientDetails($client_id)) { - return false; - } - - if (isset($clientDetails['scope'])) { - return $clientDetails['scope']; - } - - return null; - } - - public function getJti($client_id, $subject, $audience, $expiration, $jti) - { - //TODO: Needs couchbase implementation. - throw new \Exception('getJti() for the Couchbase driver is currently unimplemented.'); - } - - public function setJti($client_id, $subject, $audience, $expiration, $jti) - { - //TODO: Needs couchbase implementation. - throw new \Exception('setJti() for the Couchbase driver is currently unimplemented.'); - } -} diff --git a/library/oauth2/src/OAuth2/Storage/DynamoDB.php b/library/oauth2/src/OAuth2/Storage/DynamoDB.php deleted file mode 100644 index 8347ab258..000000000 --- a/library/oauth2/src/OAuth2/Storage/DynamoDB.php +++ /dev/null @@ -1,540 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -use Aws\DynamoDb\DynamoDbClient; - -use OAuth2\OpenID\Storage\UserClaimsInterface; -use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; -/** - * DynamoDB storage for all storage types - * - * To use, install "aws/aws-sdk-php" via composer - * <code> - * composer require aws/aws-sdk-php:dev-master - * </code> - * - * Once this is done, instantiate the DynamoDB client - * <code> - * $storage = new OAuth2\Storage\Dynamodb(array("key" => "YOURKEY", "secret" => "YOURSECRET", "region" => "YOURREGION")); - * </code> - * - * Table : - * - oauth_access_tokens (primary hash key : access_token) - * - oauth_authorization_codes (primary hash key : authorization_code) - * - oauth_clients (primary hash key : client_id) - * - oauth_jwt (primary hash key : client_id, primary range key : subject) - * - oauth_public_keys (primary hash key : client_id) - * - oauth_refresh_tokens (primary hash key : refresh_token) - * - oauth_scopes (primary hash key : scope, secondary index : is_default-index hash key is_default) - * - oauth_users (primary hash key : username) - * - * @author Frederic AUGUSTE <frederic.auguste at gmail dot com> - */ -class DynamoDB implements - AuthorizationCodeInterface, - AccessTokenInterface, - ClientCredentialsInterface, - UserCredentialsInterface, - RefreshTokenInterface, - JwtBearerInterface, - ScopeInterface, - PublicKeyInterface, - UserClaimsInterface, - OpenIDAuthorizationCodeInterface -{ - protected $client; - protected $config; - - public function __construct($connection, $config = array()) - { - if (!($connection instanceof DynamoDbClient)) { - if (!is_array($connection)) { - throw new \InvalidArgumentException('First argument to OAuth2\Storage\Dynamodb must be an instance a configuration array containt key, secret, region'); - } - if (!array_key_exists("key",$connection) || !array_key_exists("secret",$connection) || !array_key_exists("region",$connection) ) { - throw new \InvalidArgumentException('First argument to OAuth2\Storage\Dynamodb must be an instance a configuration array containt key, secret, region'); - } - $this->client = DynamoDbClient::factory(array( - 'key' => $connection["key"], - 'secret' => $connection["secret"], - 'region' =>$connection["region"] - )); - } else { - $this->client = $connection; - } - - $this->config = array_merge(array( - 'client_table' => 'oauth_clients', - 'access_token_table' => 'oauth_access_tokens', - 'refresh_token_table' => 'oauth_refresh_tokens', - 'code_table' => 'oauth_authorization_codes', - 'user_table' => 'oauth_users', - 'jwt_table' => 'oauth_jwt', - 'scope_table' => 'oauth_scopes', - 'public_key_table' => 'oauth_public_keys', - ), $config); - } - - /* OAuth2\Storage\ClientCredentialsInterface */ - public function checkClientCredentials($client_id, $client_secret = null) - { - $result = $this->client->getItem(array( - "TableName"=> $this->config['client_table'], - "Key" => array('client_id' => array('S' => $client_id)) - )); - - return $result->count()==1 && $result["Item"]["client_secret"]["S"] == $client_secret; - } - - public function isPublicClient($client_id) - { - $result = $this->client->getItem(array( - "TableName"=> $this->config['client_table'], - "Key" => array('client_id' => array('S' => $client_id)) - )); - - if ($result->count()==0) { - return false ; - } - - return empty($result["Item"]["client_secret"]); - } - - /* OAuth2\Storage\ClientInterface */ - public function getClientDetails($client_id) - { - $result = $this->client->getItem(array( - "TableName"=> $this->config['client_table'], - "Key" => array('client_id' => array('S' => $client_id)) - )); - if ($result->count()==0) { - return false ; - } - $result = $this->dynamo2array($result); - foreach (array('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id') as $key => $val) { - if (!array_key_exists ($val, $result)) { - $result[$val] = null; - } - } - - return $result; - } - - public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) - { - $clientData = compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id'); - $clientData = array_filter($clientData, 'self::isNotEmpty'); - - $result = $this->client->putItem(array( - 'TableName' => $this->config['client_table'], - 'Item' => $this->client->formatAttributes($clientData) - )); - - return true; - } - - public function checkRestrictedGrantType($client_id, $grant_type) - { - $details = $this->getClientDetails($client_id); - if (isset($details['grant_types'])) { - $grant_types = explode(' ', $details['grant_types']); - - return in_array($grant_type, (array) $grant_types); - } - - // if grant_types are not defined, then none are restricted - return true; - } - - /* OAuth2\Storage\AccessTokenInterface */ - public function getAccessToken($access_token) - { - $result = $this->client->getItem(array( - "TableName"=> $this->config['access_token_table'], - "Key" => array('access_token' => array('S' => $access_token)) - )); - if ($result->count()==0) { - return false ; - } - $token = $this->dynamo2array($result); - if (array_key_exists ('expires', $token)) { - $token['expires'] = strtotime($token['expires']); - } - - return $token; - } - - public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) - { - // convert expires to datestring - $expires = date('Y-m-d H:i:s', $expires); - - $clientData = compact('access_token', 'client_id', 'user_id', 'expires', 'scope'); - $clientData = array_filter($clientData, 'self::isNotEmpty'); - - $result = $this->client->putItem(array( - 'TableName' => $this->config['access_token_table'], - 'Item' => $this->client->formatAttributes($clientData) - )); - - return true; - - } - - public function unsetAccessToken($access_token) - { - $result = $this->client->deleteItem(array( - 'TableName' => $this->config['access_token_table'], - 'Key' => $this->client->formatAttributes(array("access_token" => $access_token)), - 'ReturnValues' => 'ALL_OLD', - )); - - return null !== $result->get('Attributes'); - } - - /* OAuth2\Storage\AuthorizationCodeInterface */ - public function getAuthorizationCode($code) - { - $result = $this->client->getItem(array( - "TableName"=> $this->config['code_table'], - "Key" => array('authorization_code' => array('S' => $code)) - )); - if ($result->count()==0) { - return false ; - } - $token = $this->dynamo2array($result); - if (!array_key_exists("id_token", $token )) { - $token['id_token'] = null; - } - $token['expires'] = strtotime($token['expires']); - - return $token; - - } - - public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) - { - // convert expires to datestring - $expires = date('Y-m-d H:i:s', $expires); - - $clientData = compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'id_token', 'scope'); - $clientData = array_filter($clientData, 'self::isNotEmpty'); - - $result = $this->client->putItem(array( - 'TableName' => $this->config['code_table'], - 'Item' => $this->client->formatAttributes($clientData) - )); - - return true; - } - - public function expireAuthorizationCode($code) - { - - $result = $this->client->deleteItem(array( - 'TableName' => $this->config['code_table'], - 'Key' => $this->client->formatAttributes(array("authorization_code" => $code)) - )); - - return true; - } - - /* OAuth2\Storage\UserCredentialsInterface */ - public function checkUserCredentials($username, $password) - { - if ($user = $this->getUser($username)) { - return $this->checkPassword($user, $password); - } - - return false; - } - - public function getUserDetails($username) - { - return $this->getUser($username); - } - - /* UserClaimsInterface */ - public function getUserClaims($user_id, $claims) - { - if (!$userDetails = $this->getUserDetails($user_id)) { - return false; - } - - $claims = explode(' ', trim($claims)); - $userClaims = array(); - - // for each requested claim, if the user has the claim, set it in the response - $validClaims = explode(' ', self::VALID_CLAIMS); - foreach ($validClaims as $validClaim) { - if (in_array($validClaim, $claims)) { - if ($validClaim == 'address') { - // address is an object with subfields - $userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails); - } else { - $userClaims = array_merge($userClaims, $this->getUserClaim($validClaim, $userDetails)); - } - } - } - - return $userClaims; - } - - protected function getUserClaim($claim, $userDetails) - { - $userClaims = array(); - $claimValuesString = constant(sprintf('self::%s_CLAIM_VALUES', strtoupper($claim))); - $claimValues = explode(' ', $claimValuesString); - - foreach ($claimValues as $value) { - if ($value == 'email_verified') { - $userClaims[$value] = $userDetails[$value]=='true' ? true : false; - } else { - $userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null; - } - } - - return $userClaims; - } - - /* OAuth2\Storage\RefreshTokenInterface */ - public function getRefreshToken($refresh_token) - { - $result = $this->client->getItem(array( - "TableName"=> $this->config['refresh_token_table'], - "Key" => array('refresh_token' => array('S' => $refresh_token)) - )); - if ($result->count()==0) { - return false ; - } - $token = $this->dynamo2array($result); - $token['expires'] = strtotime($token['expires']); - - return $token; - } - - public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) - { - // convert expires to datestring - $expires = date('Y-m-d H:i:s', $expires); - - $clientData = compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'); - $clientData = array_filter($clientData, 'self::isNotEmpty'); - - $result = $this->client->putItem(array( - 'TableName' => $this->config['refresh_token_table'], - 'Item' => $this->client->formatAttributes($clientData) - )); - - return true; - } - - public function unsetRefreshToken($refresh_token) - { - $result = $this->client->deleteItem(array( - 'TableName' => $this->config['refresh_token_table'], - 'Key' => $this->client->formatAttributes(array("refresh_token" => $refresh_token)) - )); - - return true; - } - - // plaintext passwords are bad! Override this for your application - protected function checkPassword($user, $password) - { - return $user['password'] == $this->hashPassword($password); - } - - // use a secure hashing algorithm when storing passwords. Override this for your application - protected function hashPassword($password) - { - return sha1($password); - } - - public function getUser($username) - { - $result = $this->client->getItem(array( - "TableName"=> $this->config['user_table'], - "Key" => array('username' => array('S' => $username)) - )); - if ($result->count()==0) { - return false ; - } - $token = $this->dynamo2array($result); - $token['user_id'] = $username; - - return $token; - } - - public function setUser($username, $password, $first_name = null, $last_name = null) - { - // do not store in plaintext - $password = $this->hashPassword($password); - - $clientData = compact('username', 'password', 'first_name', 'last_name'); - $clientData = array_filter($clientData, 'self::isNotEmpty'); - - $result = $this->client->putItem(array( - 'TableName' => $this->config['user_table'], - 'Item' => $this->client->formatAttributes($clientData) - )); - - return true; - - } - - /* ScopeInterface */ - public function scopeExists($scope) - { - $scope = explode(' ', $scope); - $scope_query = array(); - $count = 0; - foreach ($scope as $key => $val) { - $result = $this->client->query(array( - 'TableName' => $this->config['scope_table'], - 'Select' => 'COUNT', - 'KeyConditions' => array( - 'scope' => array( - 'AttributeValueList' => array(array('S' => $val)), - 'ComparisonOperator' => 'EQ' - ) - ) - )); - $count += $result['Count']; - } - - return $count == count($scope); - } - - public function getDefaultScope($client_id = null) - { - - $result = $this->client->query(array( - 'TableName' => $this->config['scope_table'], - 'IndexName' => 'is_default-index', - 'Select' => 'ALL_ATTRIBUTES', - 'KeyConditions' => array( - 'is_default' => array( - 'AttributeValueList' => array(array('S' => 'true')), - 'ComparisonOperator' => 'EQ', - ), - ) - )); - $defaultScope = array(); - if ($result->count() > 0) { - $array = $result->toArray(); - foreach ($array["Items"] as $item) { - $defaultScope[] = $item['scope']['S']; - } - - return empty($defaultScope) ? null : implode(' ', $defaultScope); - } - - return null; - } - - /* JWTBearerInterface */ - public function getClientKey($client_id, $subject) - { - $result = $this->client->getItem(array( - "TableName"=> $this->config['jwt_table'], - "Key" => array('client_id' => array('S' => $client_id), 'subject' => array('S' => $subject)) - )); - if ($result->count()==0) { - return false ; - } - $token = $this->dynamo2array($result); - - return $token['public_key']; - } - - public function getClientScope($client_id) - { - if (!$clientDetails = $this->getClientDetails($client_id)) { - return false; - } - - if (isset($clientDetails['scope'])) { - return $clientDetails['scope']; - } - - return null; - } - - public function getJti($client_id, $subject, $audience, $expires, $jti) - { - //TODO not use. - } - - public function setJti($client_id, $subject, $audience, $expires, $jti) - { - //TODO not use. - } - - /* PublicKeyInterface */ - public function getPublicKey($client_id = '0') - { - - $result = $this->client->getItem(array( - "TableName"=> $this->config['public_key_table'], - "Key" => array('client_id' => array('S' => $client_id)) - )); - if ($result->count()==0) { - return false ; - } - $token = $this->dynamo2array($result); - - return $token['public_key']; - - } - - public function getPrivateKey($client_id = '0') - { - $result = $this->client->getItem(array( - "TableName"=> $this->config['public_key_table'], - "Key" => array('client_id' => array('S' => $client_id)) - )); - if ($result->count()==0) { - return false ; - } - $token = $this->dynamo2array($result); - - return $token['private_key']; - } - - public function getEncryptionAlgorithm($client_id = null) - { - $result = $this->client->getItem(array( - "TableName"=> $this->config['public_key_table'], - "Key" => array('client_id' => array('S' => $client_id)) - )); - if ($result->count()==0) { - return 'RS256' ; - } - $token = $this->dynamo2array($result); - - return $token['encryption_algorithm']; - } - - /** - * Transform dynamodb resultset to an array. - * @param $dynamodbResult - * @return $array - */ - private function dynamo2array($dynamodbResult) - { - $result = array(); - foreach ($dynamodbResult["Item"] as $key => $val) { - $result[$key] = $val["S"]; - $result[] = $val["S"]; - } - - return $result; - } - - private static function isNotEmpty($value) - { - return null !== $value && '' !== $value; - } -} diff --git a/library/oauth2/src/OAuth2/Storage/JwtAccessToken.php b/library/oauth2/src/OAuth2/Storage/JwtAccessToken.php deleted file mode 100644 index 75b49d301..000000000 --- a/library/oauth2/src/OAuth2/Storage/JwtAccessToken.php +++ /dev/null @@ -1,88 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -use OAuth2\Encryption\EncryptionInterface; -use OAuth2\Encryption\Jwt; - -/** - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -class JwtAccessToken implements JwtAccessTokenInterface -{ - protected $publicKeyStorage; - protected $tokenStorage; - protected $encryptionUtil; - - /** - * @param OAuth2\Encryption\PublicKeyInterface $publicKeyStorage the public key encryption to use - * @param OAuth2\Storage\AccessTokenInterface $tokenStorage OPTIONAL persist the access token to another storage. This is useful if - * you want to retain access token grant information somewhere, but - * is not necessary when using this grant type. - * @param OAuth2\Encryption\EncryptionInterface $encryptionUtil OPTIONAL class to use for "encode" and "decode" functions. - */ - public function __construct(PublicKeyInterface $publicKeyStorage, AccessTokenInterface $tokenStorage = null, EncryptionInterface $encryptionUtil = null) - { - $this->publicKeyStorage = $publicKeyStorage; - $this->tokenStorage = $tokenStorage; - if (is_null($encryptionUtil)) { - $encryptionUtil = new Jwt; - } - $this->encryptionUtil = $encryptionUtil; - } - - public function getAccessToken($oauth_token) - { - // just decode the token, don't verify - if (!$tokenData = $this->encryptionUtil->decode($oauth_token, null, false)) { - return false; - } - - $client_id = isset($tokenData['aud']) ? $tokenData['aud'] : null; - $public_key = $this->publicKeyStorage->getPublicKey($client_id); - $algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id); - - // now that we have the client_id, verify the token - if (false === $this->encryptionUtil->decode($oauth_token, $public_key, array($algorithm))) { - return false; - } - - // normalize the JWT claims to the format expected by other components in this library - return $this->convertJwtToOAuth2($tokenData); - } - - public function setAccessToken($oauth_token, $client_id, $user_id, $expires, $scope = null) - { - if ($this->tokenStorage) { - return $this->tokenStorage->setAccessToken($oauth_token, $client_id, $user_id, $expires, $scope); - } - } - - public function unsetAccessToken($access_token) - { - if ($this->tokenStorage) { - return $this->tokenStorage->unsetAccessToken($access_token); - } - } - - - // converts a JWT access token into an OAuth2-friendly format - protected function convertJwtToOAuth2($tokenData) - { - $keyMapping = array( - 'aud' => 'client_id', - 'exp' => 'expires', - 'sub' => 'user_id' - ); - - foreach ($keyMapping as $jwtKey => $oauth2Key) { - if (isset($tokenData[$jwtKey])) { - $tokenData[$oauth2Key] = $tokenData[$jwtKey]; - unset($tokenData[$jwtKey]); - } - } - - return $tokenData; - } -} diff --git a/library/oauth2/src/OAuth2/Storage/JwtAccessTokenInterface.php b/library/oauth2/src/OAuth2/Storage/JwtAccessTokenInterface.php deleted file mode 100644 index 3abb2aa2d..000000000 --- a/library/oauth2/src/OAuth2/Storage/JwtAccessTokenInterface.php +++ /dev/null @@ -1,14 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -/** - * No specific methods, but allows the library to check "instanceof" - * against interface rather than class - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -interface JwtAccessTokenInterface extends AccessTokenInterface -{ - -} diff --git a/library/oauth2/src/OAuth2/Storage/JwtBearerInterface.php b/library/oauth2/src/OAuth2/Storage/JwtBearerInterface.php deleted file mode 100644 index c83aa72ea..000000000 --- a/library/oauth2/src/OAuth2/Storage/JwtBearerInterface.php +++ /dev/null @@ -1,74 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -/** - * Implement this interface to specify where the OAuth2 Server - * should get the JWT key for clients - * - * @TODO consider extending ClientInterface, as this will almost always - * be the same storage as retrieving clientData - * - * @author F21 - * @author Brent Shaffer <bshafs at gmail dot com> - */ -interface JwtBearerInterface -{ - /** - * Get the public key associated with a client_id - * - * @param $client_id - * Client identifier to be checked with. - * - * @return - * STRING Return the public key for the client_id if it exists, and MUST return FALSE if it doesn't. - */ - public function getClientKey($client_id, $subject); - - /** - * Get a jti (JSON token identifier) by matching against the client_id, subject, audience and expiration. - * - * @param $client_id - * Client identifier to match. - * - * @param $subject - * The subject to match. - * - * @param $audience - * The audience to match. - * - * @param $expiration - * The expiration of the jti. - * - * @param $jti - * The jti to match. - * - * @return - * An associative array as below, and return NULL if the jti does not exist. - * - issuer: Stored client identifier. - * - subject: Stored subject. - * - audience: Stored audience. - * - expires: Stored expiration in unix timestamp. - * - jti: The stored jti. - */ - public function getJti($client_id, $subject, $audience, $expiration, $jti); - - /** - * Store a used jti so that we can check against it to prevent replay attacks. - * @param $client_id - * Client identifier to insert. - * - * @param $subject - * The subject to insert. - * - * @param $audience - * The audience to insert. - * - * @param $expiration - * The expiration of the jti. - * - * @param $jti - * The jti to insert. - */ - public function setJti($client_id, $subject, $audience, $expiration, $jti); -} diff --git a/library/oauth2/src/OAuth2/Storage/Memory.php b/library/oauth2/src/OAuth2/Storage/Memory.php deleted file mode 100644 index 42d833ccb..000000000 --- a/library/oauth2/src/OAuth2/Storage/Memory.php +++ /dev/null @@ -1,381 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -use OAuth2\OpenID\Storage\UserClaimsInterface; -use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; - -/** - * Simple in-memory storage for all storage types - * - * NOTE: This class should never be used in production, and is - * a stub class for example use only - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -class Memory implements AuthorizationCodeInterface, - UserCredentialsInterface, - UserClaimsInterface, - AccessTokenInterface, - ClientCredentialsInterface, - RefreshTokenInterface, - JwtBearerInterface, - ScopeInterface, - PublicKeyInterface, - OpenIDAuthorizationCodeInterface -{ - public $authorizationCodes; - public $userCredentials; - public $clientCredentials; - public $refreshTokens; - public $accessTokens; - public $jwt; - public $jti; - public $supportedScopes; - public $defaultScope; - public $keys; - - public function __construct($params = array()) - { - $params = array_merge(array( - 'authorization_codes' => array(), - 'user_credentials' => array(), - 'client_credentials' => array(), - 'refresh_tokens' => array(), - 'access_tokens' => array(), - 'jwt' => array(), - 'jti' => array(), - 'default_scope' => null, - 'supported_scopes' => array(), - 'keys' => array(), - ), $params); - - $this->authorizationCodes = $params['authorization_codes']; - $this->userCredentials = $params['user_credentials']; - $this->clientCredentials = $params['client_credentials']; - $this->refreshTokens = $params['refresh_tokens']; - $this->accessTokens = $params['access_tokens']; - $this->jwt = $params['jwt']; - $this->jti = $params['jti']; - $this->supportedScopes = $params['supported_scopes']; - $this->defaultScope = $params['default_scope']; - $this->keys = $params['keys']; - } - - /* AuthorizationCodeInterface */ - public function getAuthorizationCode($code) - { - if (!isset($this->authorizationCodes[$code])) { - return false; - } - - return array_merge(array( - 'authorization_code' => $code, - ), $this->authorizationCodes[$code]); - } - - public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) - { - $this->authorizationCodes[$code] = compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'); - - return true; - } - - public function setAuthorizationCodes($authorization_codes) - { - $this->authorizationCodes = $authorization_codes; - } - - public function expireAuthorizationCode($code) - { - unset($this->authorizationCodes[$code]); - } - - /* UserCredentialsInterface */ - public function checkUserCredentials($username, $password) - { - $userDetails = $this->getUserDetails($username); - - return $userDetails && $userDetails['password'] && $userDetails['password'] === $password; - } - - public function setUser($username, $password, $firstName = null, $lastName = null) - { - $this->userCredentials[$username] = array( - 'password' => $password, - 'first_name' => $firstName, - 'last_name' => $lastName, - ); - - return true; - } - - public function getUserDetails($username) - { - if (!isset($this->userCredentials[$username])) { - return false; - } - - return array_merge(array( - 'user_id' => $username, - 'password' => null, - 'first_name' => null, - 'last_name' => null, - ), $this->userCredentials[$username]); - } - - /* UserClaimsInterface */ - public function getUserClaims($user_id, $claims) - { - if (!$userDetails = $this->getUserDetails($user_id)) { - return false; - } - - $claims = explode(' ', trim($claims)); - $userClaims = array(); - - // for each requested claim, if the user has the claim, set it in the response - $validClaims = explode(' ', self::VALID_CLAIMS); - foreach ($validClaims as $validClaim) { - if (in_array($validClaim, $claims)) { - if ($validClaim == 'address') { - // address is an object with subfields - $userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails); - } else { - $userClaims = array_merge($userClaims, $this->getUserClaim($validClaim, $userDetails)); - } - } - } - - return $userClaims; - } - - protected function getUserClaim($claim, $userDetails) - { - $userClaims = array(); - $claimValuesString = constant(sprintf('self::%s_CLAIM_VALUES', strtoupper($claim))); - $claimValues = explode(' ', $claimValuesString); - - foreach ($claimValues as $value) { - $userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null; - } - - return $userClaims; - } - - /* ClientCredentialsInterface */ - public function checkClientCredentials($client_id, $client_secret = null) - { - return isset($this->clientCredentials[$client_id]['client_secret']) && $this->clientCredentials[$client_id]['client_secret'] === $client_secret; - } - - public function isPublicClient($client_id) - { - if (!isset($this->clientCredentials[$client_id])) { - return false; - } - - return empty($this->clientCredentials[$client_id]['client_secret']); - } - - /* ClientInterface */ - public function getClientDetails($client_id) - { - if (!isset($this->clientCredentials[$client_id])) { - return false; - } - - $clientDetails = array_merge(array( - 'client_id' => $client_id, - 'client_secret' => null, - 'redirect_uri' => null, - 'scope' => null, - ), $this->clientCredentials[$client_id]); - - return $clientDetails; - } - - public function checkRestrictedGrantType($client_id, $grant_type) - { - if (isset($this->clientCredentials[$client_id]['grant_types'])) { - $grant_types = explode(' ', $this->clientCredentials[$client_id]['grant_types']); - - return in_array($grant_type, $grant_types); - } - - // if grant_types are not defined, then none are restricted - return true; - } - - public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) - { - $this->clientCredentials[$client_id] = array( - 'client_id' => $client_id, - 'client_secret' => $client_secret, - 'redirect_uri' => $redirect_uri, - 'grant_types' => $grant_types, - 'scope' => $scope, - 'user_id' => $user_id, - ); - - return true; - } - - /* RefreshTokenInterface */ - public function getRefreshToken($refresh_token) - { - return isset($this->refreshTokens[$refresh_token]) ? $this->refreshTokens[$refresh_token] : false; - } - - public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) - { - $this->refreshTokens[$refresh_token] = compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'); - - return true; - } - - public function unsetRefreshToken($refresh_token) - { - if (isset($this->refreshTokens[$refresh_token])) { - unset($this->refreshTokens[$refresh_token]); - - return true; - } - - return false; - } - - public function setRefreshTokens($refresh_tokens) - { - $this->refreshTokens = $refresh_tokens; - } - - /* AccessTokenInterface */ - public function getAccessToken($access_token) - { - return isset($this->accessTokens[$access_token]) ? $this->accessTokens[$access_token] : false; - } - - public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null, $id_token = null) - { - $this->accessTokens[$access_token] = compact('access_token', 'client_id', 'user_id', 'expires', 'scope', 'id_token'); - - return true; - } - - public function unsetAccessToken($access_token) - { - if (isset($this->accessTokens[$access_token])) { - unset($this->accessTokens[$access_token]); - - return true; - } - - return false; - } - - public function scopeExists($scope) - { - $scope = explode(' ', trim($scope)); - - return (count(array_diff($scope, $this->supportedScopes)) == 0); - } - - public function getDefaultScope($client_id = null) - { - return $this->defaultScope; - } - - /*JWTBearerInterface */ - public function getClientKey($client_id, $subject) - { - if (isset($this->jwt[$client_id])) { - $jwt = $this->jwt[$client_id]; - if ($jwt) { - if ($jwt["subject"] == $subject) { - return $jwt["key"]; - } - } - } - - return false; - } - - public function getClientScope($client_id) - { - if (!$clientDetails = $this->getClientDetails($client_id)) { - return false; - } - - if (isset($clientDetails['scope'])) { - return $clientDetails['scope']; - } - - return null; - } - - public function getJti($client_id, $subject, $audience, $expires, $jti) - { - foreach ($this->jti as $storedJti) { - if ($storedJti['issuer'] == $client_id && $storedJti['subject'] == $subject && $storedJti['audience'] == $audience && $storedJti['expires'] == $expires && $storedJti['jti'] == $jti) { - return array( - 'issuer' => $storedJti['issuer'], - 'subject' => $storedJti['subject'], - 'audience' => $storedJti['audience'], - 'expires' => $storedJti['expires'], - 'jti' => $storedJti['jti'] - ); - } - } - - return null; - } - - public function setJti($client_id, $subject, $audience, $expires, $jti) - { - $this->jti[] = array('issuer' => $client_id, 'subject' => $subject, 'audience' => $audience, 'expires' => $expires, 'jti' => $jti); - } - - /*PublicKeyInterface */ - public function getPublicKey($client_id = null) - { - if (isset($this->keys[$client_id])) { - return $this->keys[$client_id]['public_key']; - } - - // use a global encryption pair - if (isset($this->keys['public_key'])) { - return $this->keys['public_key']; - } - - return false; - } - - public function getPrivateKey($client_id = null) - { - if (isset($this->keys[$client_id])) { - return $this->keys[$client_id]['private_key']; - } - - // use a global encryption pair - if (isset($this->keys['private_key'])) { - return $this->keys['private_key']; - } - - return false; - } - - public function getEncryptionAlgorithm($client_id = null) - { - if (isset($this->keys[$client_id]['encryption_algorithm'])) { - return $this->keys[$client_id]['encryption_algorithm']; - } - - // use a global encryption algorithm - if (isset($this->keys['encryption_algorithm'])) { - return $this->keys['encryption_algorithm']; - } - - return 'RS256'; - } -} diff --git a/library/oauth2/src/OAuth2/Storage/Mongo.php b/library/oauth2/src/OAuth2/Storage/Mongo.php deleted file mode 100644 index cef35e5e9..000000000 --- a/library/oauth2/src/OAuth2/Storage/Mongo.php +++ /dev/null @@ -1,339 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; - -/** - * Simple MongoDB storage for all storage types - * - * NOTE: This class is meant to get users started - * quickly. If your application requires further - * customization, extend this class or create your own. - * - * NOTE: Passwords are stored in plaintext, which is never - * a good idea. Be sure to override this for your application - * - * @author Julien Chaumond <chaumond@gmail.com> - */ -class Mongo implements AuthorizationCodeInterface, - AccessTokenInterface, - ClientCredentialsInterface, - UserCredentialsInterface, - RefreshTokenInterface, - JwtBearerInterface, - OpenIDAuthorizationCodeInterface -{ - protected $db; - protected $config; - - public function __construct($connection, $config = array()) - { - if ($connection instanceof \MongoDB) { - $this->db = $connection; - } else { - if (!is_array($connection)) { - throw new \InvalidArgumentException('First argument to OAuth2\Storage\Mongo must be an instance of MongoDB or a configuration array'); - } - $server = sprintf('mongodb://%s:%d', $connection['host'], $connection['port']); - $m = new \MongoClient($server); - $this->db = $m->{$connection['database']}; - } - - $this->config = array_merge(array( - 'client_table' => 'oauth_clients', - 'access_token_table' => 'oauth_access_tokens', - 'refresh_token_table' => 'oauth_refresh_tokens', - 'code_table' => 'oauth_authorization_codes', - 'user_table' => 'oauth_users', - 'jwt_table' => 'oauth_jwt', - ), $config); - } - - // Helper function to access a MongoDB collection by `type`: - protected function collection($name) - { - return $this->db->{$this->config[$name]}; - } - - /* ClientCredentialsInterface */ - public function checkClientCredentials($client_id, $client_secret = null) - { - if ($result = $this->collection('client_table')->findOne(array('client_id' => $client_id))) { - return $result['client_secret'] == $client_secret; - } - - return false; - } - - public function isPublicClient($client_id) - { - if (!$result = $this->collection('client_table')->findOne(array('client_id' => $client_id))) { - return false; - } - - return empty($result['client_secret']); - } - - /* ClientInterface */ - public function getClientDetails($client_id) - { - $result = $this->collection('client_table')->findOne(array('client_id' => $client_id)); - - return is_null($result) ? false : $result; - } - - public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) - { - if ($this->getClientDetails($client_id)) { - $this->collection('client_table')->update( - array('client_id' => $client_id), - array('$set' => array( - 'client_secret' => $client_secret, - 'redirect_uri' => $redirect_uri, - 'grant_types' => $grant_types, - 'scope' => $scope, - 'user_id' => $user_id, - )) - ); - } else { - $client = array( - 'client_id' => $client_id, - 'client_secret' => $client_secret, - 'redirect_uri' => $redirect_uri, - 'grant_types' => $grant_types, - 'scope' => $scope, - 'user_id' => $user_id, - ); - $this->collection('client_table')->insert($client); - } - - return true; - } - - public function checkRestrictedGrantType($client_id, $grant_type) - { - $details = $this->getClientDetails($client_id); - if (isset($details['grant_types'])) { - $grant_types = explode(' ', $details['grant_types']); - - return in_array($grant_type, $grant_types); - } - - // if grant_types are not defined, then none are restricted - return true; - } - - /* AccessTokenInterface */ - public function getAccessToken($access_token) - { - $token = $this->collection('access_token_table')->findOne(array('access_token' => $access_token)); - - return is_null($token) ? false : $token; - } - - public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) - { - // if it exists, update it. - if ($this->getAccessToken($access_token)) { - $this->collection('access_token_table')->update( - array('access_token' => $access_token), - array('$set' => array( - 'client_id' => $client_id, - 'expires' => $expires, - 'user_id' => $user_id, - 'scope' => $scope - )) - ); - } else { - $token = array( - 'access_token' => $access_token, - 'client_id' => $client_id, - 'expires' => $expires, - 'user_id' => $user_id, - 'scope' => $scope - ); - $this->collection('access_token_table')->insert($token); - } - - return true; - } - - public function unsetAccessToken($access_token) - { - $result = $this->collection('access_token_table')->remove(array( - 'access_token' => $access_token - ), array('w' => 1)); - - return $result['n'] > 0; - } - - - /* AuthorizationCodeInterface */ - public function getAuthorizationCode($code) - { - $code = $this->collection('code_table')->findOne(array('authorization_code' => $code)); - - return is_null($code) ? false : $code; - } - - public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) - { - // if it exists, update it. - if ($this->getAuthorizationCode($code)) { - $this->collection('code_table')->update( - array('authorization_code' => $code), - array('$set' => array( - 'client_id' => $client_id, - 'user_id' => $user_id, - 'redirect_uri' => $redirect_uri, - 'expires' => $expires, - 'scope' => $scope, - 'id_token' => $id_token, - )) - ); - } else { - $token = array( - 'authorization_code' => $code, - 'client_id' => $client_id, - 'user_id' => $user_id, - 'redirect_uri' => $redirect_uri, - 'expires' => $expires, - 'scope' => $scope, - 'id_token' => $id_token, - ); - $this->collection('code_table')->insert($token); - } - - return true; - } - - public function expireAuthorizationCode($code) - { - $this->collection('code_table')->remove(array('authorization_code' => $code)); - - return true; - } - - /* UserCredentialsInterface */ - public function checkUserCredentials($username, $password) - { - if ($user = $this->getUser($username)) { - return $this->checkPassword($user, $password); - } - - return false; - } - - public function getUserDetails($username) - { - if ($user = $this->getUser($username)) { - $user['user_id'] = $user['username']; - } - - return $user; - } - - /* RefreshTokenInterface */ - public function getRefreshToken($refresh_token) - { - $token = $this->collection('refresh_token_table')->findOne(array('refresh_token' => $refresh_token)); - - return is_null($token) ? false : $token; - } - - public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) - { - $token = array( - 'refresh_token' => $refresh_token, - 'client_id' => $client_id, - 'user_id' => $user_id, - 'expires' => $expires, - 'scope' => $scope - ); - $this->collection('refresh_token_table')->insert($token); - - return true; - } - - public function unsetRefreshToken($refresh_token) - { - $result = $this->collection('refresh_token_table')->remove(array( - 'refresh_token' => $refresh_token - ), array('w' => 1)); - - return $result['n'] > 0; - } - - // plaintext passwords are bad! Override this for your application - protected function checkPassword($user, $password) - { - return $user['password'] == $password; - } - - public function getUser($username) - { - $result = $this->collection('user_table')->findOne(array('username' => $username)); - - return is_null($result) ? false : $result; - } - - public function setUser($username, $password, $firstName = null, $lastName = null) - { - if ($this->getUser($username)) { - $this->collection('user_table')->update( - array('username' => $username), - array('$set' => array( - 'password' => $password, - 'first_name' => $firstName, - 'last_name' => $lastName - )) - ); - } else { - $user = array( - 'username' => $username, - 'password' => $password, - 'first_name' => $firstName, - 'last_name' => $lastName - ); - $this->collection('user_table')->insert($user); - } - - return true; - } - - public function getClientKey($client_id, $subject) - { - $result = $this->collection('jwt_table')->findOne(array( - 'client_id' => $client_id, - 'subject' => $subject - )); - - return is_null($result) ? false : $result['key']; - } - - public function getClientScope($client_id) - { - if (!$clientDetails = $this->getClientDetails($client_id)) { - return false; - } - - if (isset($clientDetails['scope'])) { - return $clientDetails['scope']; - } - - return null; - } - - public function getJti($client_id, $subject, $audience, $expiration, $jti) - { - //TODO: Needs mongodb implementation. - throw new \Exception('getJti() for the MongoDB driver is currently unimplemented.'); - } - - public function setJti($client_id, $subject, $audience, $expiration, $jti) - { - //TODO: Needs mongodb implementation. - throw new \Exception('setJti() for the MongoDB driver is currently unimplemented.'); - } -} diff --git a/library/oauth2/src/OAuth2/Storage/Pdo.php b/library/oauth2/src/OAuth2/Storage/Pdo.php deleted file mode 100644 index ae5107e29..000000000 --- a/library/oauth2/src/OAuth2/Storage/Pdo.php +++ /dev/null @@ -1,553 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -use OAuth2\OpenID\Storage\UserClaimsInterface; -use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; - -/** - * Simple PDO storage for all storage types - * - * NOTE: This class is meant to get users started - * quickly. If your application requires further - * customization, extend this class or create your own. - * - * NOTE: Passwords are stored in plaintext, which is never - * a good idea. Be sure to override this for your application - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -class Pdo implements - AuthorizationCodeInterface, - AccessTokenInterface, - ClientCredentialsInterface, - UserCredentialsInterface, - RefreshTokenInterface, - JwtBearerInterface, - ScopeInterface, - PublicKeyInterface, - UserClaimsInterface, - OpenIDAuthorizationCodeInterface -{ - protected $db; - protected $config; - - public function __construct($connection, $config = array()) - { - if (!$connection instanceof \PDO) { - if (is_string($connection)) { - $connection = array('dsn' => $connection); - } - if (!is_array($connection)) { - throw new \InvalidArgumentException('First argument to OAuth2\Storage\Pdo must be an instance of PDO, a DSN string, or a configuration array'); - } - if (!isset($connection['dsn'])) { - throw new \InvalidArgumentException('configuration array must contain "dsn"'); - } - // merge optional parameters - $connection = array_merge(array( - 'username' => null, - 'password' => null, - 'options' => array(), - ), $connection); - $connection = new \PDO($connection['dsn'], $connection['username'], $connection['password'], $connection['options']); - } - $this->db = $connection; - - // debugging - $connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); - - $this->config = array_merge(array( - 'client_table' => 'oauth_clients', - 'access_token_table' => 'oauth_access_tokens', - 'refresh_token_table' => 'oauth_refresh_tokens', - 'code_table' => 'oauth_authorization_codes', - 'user_table' => 'oauth_users', - 'jwt_table' => 'oauth_jwt', - 'jti_table' => 'oauth_jti', - 'scope_table' => 'oauth_scopes', - 'public_key_table' => 'oauth_public_keys', - ), $config); - } - - /* OAuth2\Storage\ClientCredentialsInterface */ - public function checkClientCredentials($client_id, $client_secret = null) - { - $stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table'])); - $stmt->execute(compact('client_id')); - $result = $stmt->fetch(\PDO::FETCH_ASSOC); - - // make this extensible - return $result && $result['client_secret'] == $client_secret; - } - - public function isPublicClient($client_id) - { - $stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table'])); - $stmt->execute(compact('client_id')); - - if (!$result = $stmt->fetch(\PDO::FETCH_ASSOC)) { - return false; - } - - return empty($result['client_secret']); - } - - /* OAuth2\Storage\ClientInterface */ - public function getClientDetails($client_id) - { - $stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table'])); - $stmt->execute(compact('client_id')); - - return $stmt->fetch(\PDO::FETCH_ASSOC); - } - - public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) - { - // if it exists, update it. - if ($this->getClientDetails($client_id)) { - $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_secret=:client_secret, redirect_uri=:redirect_uri, grant_types=:grant_types, scope=:scope, user_id=:user_id where client_id=:client_id', $this->config['client_table'])); - } else { - $stmt = $this->db->prepare(sprintf('INSERT INTO %s (client_id, client_secret, redirect_uri, grant_types, scope, user_id) VALUES (:client_id, :client_secret, :redirect_uri, :grant_types, :scope, :user_id)', $this->config['client_table'])); - } - - return $stmt->execute(compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id')); - } - - public function checkRestrictedGrantType($client_id, $grant_type) - { - $details = $this->getClientDetails($client_id); - if (isset($details['grant_types'])) { - $grant_types = explode(' ', $details['grant_types']); - - return in_array($grant_type, (array) $grant_types); - } - - // if grant_types are not defined, then none are restricted - return true; - } - - /* OAuth2\Storage\AccessTokenInterface */ - public function getAccessToken($access_token) - { - $stmt = $this->db->prepare(sprintf('SELECT * from %s where access_token = :access_token', $this->config['access_token_table'])); - - $token = $stmt->execute(compact('access_token')); - if ($token = $stmt->fetch(\PDO::FETCH_ASSOC)) { - // convert date string back to timestamp - $token['expires'] = strtotime($token['expires']); - } - - return $token; - } - - public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) - { - // convert expires to datestring - $expires = date('Y-m-d H:i:s', $expires); - - // if it exists, update it. - if ($this->getAccessToken($access_token)) { - $stmt = $this->db->prepare(sprintf('UPDATE %s SET client_id=:client_id, expires=:expires, user_id=:user_id, scope=:scope where access_token=:access_token', $this->config['access_token_table'])); - } else { - $stmt = $this->db->prepare(sprintf('INSERT INTO %s (access_token, client_id, expires, user_id, scope) VALUES (:access_token, :client_id, :expires, :user_id, :scope)', $this->config['access_token_table'])); - } - - return $stmt->execute(compact('access_token', 'client_id', 'user_id', 'expires', 'scope')); - } - - public function unsetAccessToken($access_token) - { - $stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE access_token = :access_token', $this->config['access_token_table'])); - - $stmt->execute(compact('access_token')); - - return $stmt->rowCount() > 0; - } - - /* OAuth2\Storage\AuthorizationCodeInterface */ - public function getAuthorizationCode($code) - { - $stmt = $this->db->prepare(sprintf('SELECT * from %s where authorization_code = :code', $this->config['code_table'])); - $stmt->execute(compact('code')); - - if ($code = $stmt->fetch(\PDO::FETCH_ASSOC)) { - // convert date string back to timestamp - $code['expires'] = strtotime($code['expires']); - } - - return $code; - } - - public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) - { - if (func_num_args() > 6) { - // we are calling with an id token - return call_user_func_array(array($this, 'setAuthorizationCodeWithIdToken'), func_get_args()); - } - - // convert expires to datestring - $expires = date('Y-m-d H:i:s', $expires); - - // if it exists, update it. - if ($this->getAuthorizationCode($code)) { - $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_id=:client_id, user_id=:user_id, redirect_uri=:redirect_uri, expires=:expires, scope=:scope where authorization_code=:code', $this->config['code_table'])); - } else { - $stmt = $this->db->prepare(sprintf('INSERT INTO %s (authorization_code, client_id, user_id, redirect_uri, expires, scope) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope)', $this->config['code_table'])); - } - - return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope')); - } - - private function setAuthorizationCodeWithIdToken($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) - { - // convert expires to datestring - $expires = date('Y-m-d H:i:s', $expires); - - // if it exists, update it. - if ($this->getAuthorizationCode($code)) { - $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_id=:client_id, user_id=:user_id, redirect_uri=:redirect_uri, expires=:expires, scope=:scope, id_token =:id_token where authorization_code=:code', $this->config['code_table'])); - } else { - $stmt = $this->db->prepare(sprintf('INSERT INTO %s (authorization_code, client_id, user_id, redirect_uri, expires, scope, id_token) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope, :id_token)', $this->config['code_table'])); - } - - return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token')); - } - - public function expireAuthorizationCode($code) - { - $stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE authorization_code = :code', $this->config['code_table'])); - - return $stmt->execute(compact('code')); - } - - /* OAuth2\Storage\UserCredentialsInterface */ - public function checkUserCredentials($username, $password) - { - if ($user = $this->getUser($username)) { - return $this->checkPassword($user, $password); - } - - return false; - } - - public function getUserDetails($username) - { - return $this->getUser($username); - } - - /* UserClaimsInterface */ - public function getUserClaims($user_id, $claims) - { - if (!$userDetails = $this->getUserDetails($user_id)) { - return false; - } - - $claims = explode(' ', trim($claims)); - $userClaims = array(); - - // for each requested claim, if the user has the claim, set it in the response - $validClaims = explode(' ', self::VALID_CLAIMS); - foreach ($validClaims as $validClaim) { - if (in_array($validClaim, $claims)) { - if ($validClaim == 'address') { - // address is an object with subfields - $userClaims['address'] = $this->getUserClaim($validClaim, $userDetails['address'] ?: $userDetails); - } else { - $userClaims = array_merge($userClaims, $this->getUserClaim($validClaim, $userDetails)); - } - } - } - - return $userClaims; - } - - protected function getUserClaim($claim, $userDetails) - { - $userClaims = array(); - $claimValuesString = constant(sprintf('self::%s_CLAIM_VALUES', strtoupper($claim))); - $claimValues = explode(' ', $claimValuesString); - - foreach ($claimValues as $value) { - $userClaims[$value] = isset($userDetails[$value]) ? $userDetails[$value] : null; - } - - return $userClaims; - } - - /* OAuth2\Storage\RefreshTokenInterface */ - public function getRefreshToken($refresh_token) - { - $stmt = $this->db->prepare(sprintf('SELECT * FROM %s WHERE refresh_token = :refresh_token', $this->config['refresh_token_table'])); - - $token = $stmt->execute(compact('refresh_token')); - if ($token = $stmt->fetch(\PDO::FETCH_ASSOC)) { - // convert expires to epoch time - $token['expires'] = strtotime($token['expires']); - } - - return $token; - } - - public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) - { - // convert expires to datestring - $expires = date('Y-m-d H:i:s', $expires); - - $stmt = $this->db->prepare(sprintf('INSERT INTO %s (refresh_token, client_id, user_id, expires, scope) VALUES (:refresh_token, :client_id, :user_id, :expires, :scope)', $this->config['refresh_token_table'])); - - return $stmt->execute(compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope')); - } - - public function unsetRefreshToken($refresh_token) - { - $stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE refresh_token = :refresh_token', $this->config['refresh_token_table'])); - - $stmt->execute(compact('refresh_token')); - - return $stmt->rowCount() > 0; - } - - // plaintext passwords are bad! Override this for your application - protected function checkPassword($user, $password) - { - return $user['password'] == $this->hashPassword($password); - } - - // use a secure hashing algorithm when storing passwords. Override this for your application - protected function hashPassword($password) - { - return sha1($password); - } - - public function getUser($username) - { - $stmt = $this->db->prepare($sql = sprintf('SELECT * from %s where username=:username', $this->config['user_table'])); - $stmt->execute(array('username' => $username)); - - if (!$userInfo = $stmt->fetch(\PDO::FETCH_ASSOC)) { - return false; - } - - // the default behavior is to use "username" as the user_id - return array_merge(array( - 'user_id' => $username - ), $userInfo); - } - - public function setUser($username, $password, $firstName = null, $lastName = null) - { - // do not store in plaintext - $password = $this->hashPassword($password); - - // if it exists, update it. - if ($this->getUser($username)) { - $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET password=:password, first_name=:firstName, last_name=:lastName where username=:username', $this->config['user_table'])); - } else { - $stmt = $this->db->prepare(sprintf('INSERT INTO %s (username, password, first_name, last_name) VALUES (:username, :password, :firstName, :lastName)', $this->config['user_table'])); - } - - return $stmt->execute(compact('username', 'password', 'firstName', 'lastName')); - } - - /* ScopeInterface */ - public function scopeExists($scope) - { - $scope = explode(' ', $scope); - $whereIn = implode(',', array_fill(0, count($scope), '?')); - $stmt = $this->db->prepare(sprintf('SELECT count(scope) as count FROM %s WHERE scope IN (%s)', $this->config['scope_table'], $whereIn)); - $stmt->execute($scope); - - if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) { - return $result['count'] == count($scope); - } - - return false; - } - - public function getDefaultScope($client_id = null) - { - $stmt = $this->db->prepare(sprintf('SELECT scope FROM %s WHERE is_default=:is_default', $this->config['scope_table'])); - $stmt->execute(array('is_default' => true)); - - if ($result = $stmt->fetchAll(\PDO::FETCH_ASSOC)) { - $defaultScope = array_map(function ($row) { - return $row['scope']; - }, $result); - - return implode(' ', $defaultScope); - } - - return null; - } - - /* JWTBearerInterface */ - public function getClientKey($client_id, $subject) - { - $stmt = $this->db->prepare($sql = sprintf('SELECT public_key from %s where client_id=:client_id AND subject=:subject', $this->config['jwt_table'])); - - $stmt->execute(array('client_id' => $client_id, 'subject' => $subject)); - - return $stmt->fetchColumn(); - } - - public function getClientScope($client_id) - { - if (!$clientDetails = $this->getClientDetails($client_id)) { - return false; - } - - if (isset($clientDetails['scope'])) { - return $clientDetails['scope']; - } - - return null; - } - - public function getJti($client_id, $subject, $audience, $expires, $jti) - { - $stmt = $this->db->prepare($sql = sprintf('SELECT * FROM %s WHERE issuer=:client_id AND subject=:subject AND audience=:audience AND expires=:expires AND jti=:jti', $this->config['jti_table'])); - - $stmt->execute(compact('client_id', 'subject', 'audience', 'expires', 'jti')); - - if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) { - return array( - 'issuer' => $result['issuer'], - 'subject' => $result['subject'], - 'audience' => $result['audience'], - 'expires' => $result['expires'], - 'jti' => $result['jti'], - ); - } - - return null; - } - - public function setJti($client_id, $subject, $audience, $expires, $jti) - { - $stmt = $this->db->prepare(sprintf('INSERT INTO %s (issuer, subject, audience, expires, jti) VALUES (:client_id, :subject, :audience, :expires, :jti)', $this->config['jti_table'])); - - return $stmt->execute(compact('client_id', 'subject', 'audience', 'expires', 'jti')); - } - - /* PublicKeyInterface */ - public function getPublicKey($client_id = null) - { - $stmt = $this->db->prepare($sql = sprintf('SELECT public_key FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table'])); - - $stmt->execute(compact('client_id')); - if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) { - return $result['public_key']; - } - } - - public function getPrivateKey($client_id = null) - { - $stmt = $this->db->prepare($sql = sprintf('SELECT private_key FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table'])); - - $stmt->execute(compact('client_id')); - if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) { - return $result['private_key']; - } - } - - public function getEncryptionAlgorithm($client_id = null) - { - $stmt = $this->db->prepare($sql = sprintf('SELECT encryption_algorithm FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table'])); - - $stmt->execute(compact('client_id')); - if ($result = $stmt->fetch(\PDO::FETCH_ASSOC)) { - return $result['encryption_algorithm']; - } - - return 'RS256'; - } - - /** - * DDL to create OAuth2 database and tables for PDO storage - * - * @see https://github.com/dsquier/oauth2-server-php-mysql - */ - public function getBuildSql($dbName = 'oauth2_server_php') - { - $sql = " - CREATE TABLE {$this->config['client_table']} ( - client_id VARCHAR(80) NOT NULL, - client_secret VARCHAR(80), - redirect_uri VARCHAR(2000), - grant_types VARCHAR(80), - scope VARCHAR(4000), - user_id VARCHAR(80), - PRIMARY KEY (client_id) - ); - - CREATE TABLE {$this->config['access_token_table']} ( - access_token VARCHAR(40) NOT NULL, - client_id VARCHAR(80) NOT NULL, - user_id VARCHAR(80), - expires TIMESTAMP NOT NULL, - scope VARCHAR(4000), - PRIMARY KEY (access_token) - ); - - CREATE TABLE {$this->config['code_table']} ( - authorization_code VARCHAR(40) NOT NULL, - client_id VARCHAR(80) NOT NULL, - user_id VARCHAR(80), - redirect_uri VARCHAR(2000), - expires TIMESTAMP NOT NULL, - scope VARCHAR(4000), - id_token VARCHAR(1000), - PRIMARY KEY (authorization_code) - ); - - CREATE TABLE {$this->config['refresh_token_table']} ( - refresh_token VARCHAR(40) NOT NULL, - client_id VARCHAR(80) NOT NULL, - user_id VARCHAR(80), - expires TIMESTAMP NOT NULL, - scope VARCHAR(4000), - PRIMARY KEY (refresh_token) - ); - - CREATE TABLE {$this->config['user_table']} ( - username VARCHAR(80), - password VARCHAR(80), - first_name VARCHAR(80), - last_name VARCHAR(80), - email VARCHAR(80), - email_verified BOOLEAN, - scope VARCHAR(4000) - ); - - CREATE TABLE {$this->config['scope_table']} ( - scope VARCHAR(80) NOT NULL, - is_default BOOLEAN, - PRIMARY KEY (scope) - ); - - CREATE TABLE {$this->config['jwt_table']} ( - client_id VARCHAR(80) NOT NULL, - subject VARCHAR(80), - public_key VARCHAR(2000) NOT NULL - ); - - CREATE TABLE {$this->config['jti_table']} ( - issuer VARCHAR(80) NOT NULL, - subject VARCHAR(80), - audience VARCHAR(80), - expires TIMESTAMP NOT NULL, - jti VARCHAR(2000) NOT NULL - ); - - CREATE TABLE {$this->config['public_key_table']} ( - client_id VARCHAR(80), - public_key VARCHAR(2000), - private_key VARCHAR(2000), - encryption_algorithm VARCHAR(100) DEFAULT 'RS256' - ) -"; - - return $sql; - } -} diff --git a/library/oauth2/src/OAuth2/Storage/PublicKeyInterface.php b/library/oauth2/src/OAuth2/Storage/PublicKeyInterface.php deleted file mode 100644 index 108418d3a..000000000 --- a/library/oauth2/src/OAuth2/Storage/PublicKeyInterface.php +++ /dev/null @@ -1,16 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -/** - * Implement this interface to specify where the OAuth2 Server - * should get public/private key information - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -interface PublicKeyInterface -{ - public function getPublicKey($client_id = null); - public function getPrivateKey($client_id = null); - public function getEncryptionAlgorithm($client_id = null); -} diff --git a/library/oauth2/src/OAuth2/Storage/Redis.php b/library/oauth2/src/OAuth2/Storage/Redis.php deleted file mode 100644 index e6294e22d..000000000 --- a/library/oauth2/src/OAuth2/Storage/Redis.php +++ /dev/null @@ -1,321 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; - -/** - * redis storage for all storage types - * - * To use, install "predis/predis" via composer - * - * Register client: - * <code> - * $storage = new OAuth2\Storage\Redis($redis); - * $storage->setClientDetails($client_id, $client_secret, $redirect_uri); - * </code> - */ -class Redis implements AuthorizationCodeInterface, - AccessTokenInterface, - ClientCredentialsInterface, - UserCredentialsInterface, - RefreshTokenInterface, - JwtBearerInterface, - ScopeInterface, - OpenIDAuthorizationCodeInterface -{ - - private $cache; - - /* The redis client */ - protected $redis; - - /* Configuration array */ - protected $config; - - /** - * Redis Storage! - * - * @param \Predis\Client $redis - * @param array $config - */ - public function __construct($redis, $config=array()) - { - $this->redis = $redis; - $this->config = array_merge(array( - 'client_key' => 'oauth_clients:', - 'access_token_key' => 'oauth_access_tokens:', - 'refresh_token_key' => 'oauth_refresh_tokens:', - 'code_key' => 'oauth_authorization_codes:', - 'user_key' => 'oauth_users:', - 'jwt_key' => 'oauth_jwt:', - 'scope_key' => 'oauth_scopes:', - ), $config); - } - - protected function getValue($key) - { - if ( isset($this->cache[$key]) ) { - return $this->cache[$key]; - } - $value = $this->redis->get($key); - if ( isset($value) ) { - return json_decode($value, true); - } else { - return false; - } - } - - protected function setValue($key, $value, $expire=0) - { - $this->cache[$key] = $value; - $str = json_encode($value); - if ($expire > 0) { - $seconds = $expire - time(); - $ret = $this->redis->setex($key, $seconds, $str); - } else { - $ret = $this->redis->set($key, $str); - } - - // check that the key was set properly - // if this fails, an exception will usually thrown, so this step isn't strictly necessary - return is_bool($ret) ? $ret : $ret->getPayload() == 'OK'; - } - - protected function expireValue($key) - { - unset($this->cache[$key]); - - return $this->redis->del($key); - } - - /* AuthorizationCodeInterface */ - public function getAuthorizationCode($code) - { - return $this->getValue($this->config['code_key'] . $code); - } - - public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) - { - return $this->setValue( - $this->config['code_key'] . $authorization_code, - compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'), - $expires - ); - } - - public function expireAuthorizationCode($code) - { - $key = $this->config['code_key'] . $code; - unset($this->cache[$key]); - - return $this->expireValue($key); - } - - /* UserCredentialsInterface */ - public function checkUserCredentials($username, $password) - { - $user = $this->getUserDetails($username); - - return $user && $user['password'] === $password; - } - - public function getUserDetails($username) - { - return $this->getUser($username); - } - - public function getUser($username) - { - if (!$userInfo = $this->getValue($this->config['user_key'] . $username)) { - return false; - } - - // the default behavior is to use "username" as the user_id - return array_merge(array( - 'user_id' => $username, - ), $userInfo); - } - - public function setUser($username, $password, $first_name = null, $last_name = null) - { - return $this->setValue( - $this->config['user_key'] . $username, - compact('username', 'password', 'first_name', 'last_name') - ); - } - - /* ClientCredentialsInterface */ - public function checkClientCredentials($client_id, $client_secret = null) - { - if (!$client = $this->getClientDetails($client_id)) { - return false; - } - - return isset($client['client_secret']) - && $client['client_secret'] == $client_secret; - } - - public function isPublicClient($client_id) - { - if (!$client = $this->getClientDetails($client_id)) { - return false; - } - - return empty($client['client_secret']); - } - - /* ClientInterface */ - public function getClientDetails($client_id) - { - return $this->getValue($this->config['client_key'] . $client_id); - } - - public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) - { - return $this->setValue( - $this->config['client_key'] . $client_id, - compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id') - ); - } - - public function checkRestrictedGrantType($client_id, $grant_type) - { - $details = $this->getClientDetails($client_id); - if (isset($details['grant_types'])) { - $grant_types = explode(' ', $details['grant_types']); - - return in_array($grant_type, (array) $grant_types); - } - - // if grant_types are not defined, then none are restricted - return true; - } - - /* RefreshTokenInterface */ - public function getRefreshToken($refresh_token) - { - return $this->getValue($this->config['refresh_token_key'] . $refresh_token); - } - - public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) - { - return $this->setValue( - $this->config['refresh_token_key'] . $refresh_token, - compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'), - $expires - ); - } - - public function unsetRefreshToken($refresh_token) - { - $result = $this->expireValue($this->config['refresh_token_key'] . $refresh_token); - - return $result > 0; - } - - /* AccessTokenInterface */ - public function getAccessToken($access_token) - { - return $this->getValue($this->config['access_token_key'].$access_token); - } - - public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) - { - return $this->setValue( - $this->config['access_token_key'].$access_token, - compact('access_token', 'client_id', 'user_id', 'expires', 'scope'), - $expires - ); - } - - public function unsetAccessToken($access_token) - { - $result = $this->expireValue($this->config['access_token_key'] . $access_token); - - return $result > 0; - } - - /* ScopeInterface */ - public function scopeExists($scope) - { - $scope = explode(' ', $scope); - - $result = $this->getValue($this->config['scope_key'].'supported:global'); - - $supportedScope = explode(' ', (string) $result); - - return (count(array_diff($scope, $supportedScope)) == 0); - } - - public function getDefaultScope($client_id = null) - { - if (is_null($client_id) || !$result = $this->getValue($this->config['scope_key'].'default:'.$client_id)) { - $result = $this->getValue($this->config['scope_key'].'default:global'); - } - - return $result; - } - - public function setScope($scope, $client_id = null, $type = 'supported') - { - if (!in_array($type, array('default', 'supported'))) { - throw new \InvalidArgumentException('"$type" must be one of "default", "supported"'); - } - - if (is_null($client_id)) { - $key = $this->config['scope_key'].$type.':global'; - } else { - $key = $this->config['scope_key'].$type.':'.$client_id; - } - - return $this->setValue($key, $scope); - } - - /*JWTBearerInterface */ - public function getClientKey($client_id, $subject) - { - if (!$jwt = $this->getValue($this->config['jwt_key'] . $client_id)) { - return false; - } - - if (isset($jwt['subject']) && $jwt['subject'] == $subject) { - return $jwt['key']; - } - - return null; - } - - public function setClientKey($client_id, $key, $subject = null) - { - return $this->setValue($this->config['jwt_key'] . $client_id, array( - 'key' => $key, - 'subject' => $subject - )); - } - - public function getClientScope($client_id) - { - if (!$clientDetails = $this->getClientDetails($client_id)) { - return false; - } - - if (isset($clientDetails['scope'])) { - return $clientDetails['scope']; - } - - return null; - } - - public function getJti($client_id, $subject, $audience, $expiration, $jti) - { - //TODO: Needs redis implementation. - throw new \Exception('getJti() for the Redis driver is currently unimplemented.'); - } - - public function setJti($client_id, $subject, $audience, $expiration, $jti) - { - //TODO: Needs redis implementation. - throw new \Exception('setJti() for the Redis driver is currently unimplemented.'); - } -} diff --git a/library/oauth2/src/OAuth2/Storage/RefreshTokenInterface.php b/library/oauth2/src/OAuth2/Storage/RefreshTokenInterface.php deleted file mode 100644 index 0273f2125..000000000 --- a/library/oauth2/src/OAuth2/Storage/RefreshTokenInterface.php +++ /dev/null @@ -1,82 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -/** - * Implement this interface to specify where the OAuth2 Server - * should get/save refresh tokens for the "Refresh Token" - * grant type - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -interface RefreshTokenInterface -{ - /** - * Grant refresh access tokens. - * - * Retrieve the stored data for the given refresh token. - * - * Required for OAuth2::GRANT_TYPE_REFRESH_TOKEN. - * - * @param $refresh_token - * Refresh token to be check with. - * - * @return - * An associative array as below, and NULL if the refresh_token is - * invalid: - * - refresh_token: Refresh token identifier. - * - client_id: Client identifier. - * - user_id: User identifier. - * - expires: Expiration unix timestamp, or 0 if the token doesn't expire. - * - scope: (optional) Scope values in space-separated string. - * - * @see http://tools.ietf.org/html/rfc6749#section-6 - * - * @ingroup oauth2_section_6 - */ - public function getRefreshToken($refresh_token); - - /** - * Take the provided refresh token values and store them somewhere. - * - * This function should be the storage counterpart to getRefreshToken(). - * - * If storage fails for some reason, we're not currently checking for - * any sort of success/failure, so you should bail out of the script - * and provide a descriptive fail message. - * - * Required for OAuth2::GRANT_TYPE_REFRESH_TOKEN. - * - * @param $refresh_token - * Refresh token to be stored. - * @param $client_id - * Client identifier to be stored. - * @param $user_id - * User identifier to be stored. - * @param $expires - * Expiration timestamp to be stored. 0 if the token doesn't expire. - * @param $scope - * (optional) Scopes to be stored in space-separated string. - * - * @ingroup oauth2_section_6 - */ - public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null); - - /** - * Expire a used refresh token. - * - * This is not explicitly required in the spec, but is almost implied. - * After granting a new refresh token, the old one is no longer useful and - * so should be forcibly expired in the data store so it can't be used again. - * - * If storage fails for some reason, we're not currently checking for - * any sort of success/failure, so you should bail out of the script - * and provide a descriptive fail message. - * - * @param $refresh_token - * Refresh token to be expirse. - * - * @ingroup oauth2_section_6 - */ - public function unsetRefreshToken($refresh_token); -} diff --git a/library/oauth2/src/OAuth2/Storage/ScopeInterface.php b/library/oauth2/src/OAuth2/Storage/ScopeInterface.php deleted file mode 100644 index a8292269b..000000000 --- a/library/oauth2/src/OAuth2/Storage/ScopeInterface.php +++ /dev/null @@ -1,46 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -/** - * Implement this interface to specify where the OAuth2 Server - * should retrieve data involving the relevent scopes associated - * with this implementation. - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -interface ScopeInterface -{ - /** - * Check if the provided scope exists. - * - * @param $scope - * A space-separated string of scopes. - * - * @return - * TRUE if it exists, FALSE otherwise. - */ - public function scopeExists($scope); - - /** - * The default scope to use in the event the client - * does not request one. By returning "false", a - * request_error is returned by the server to force a - * scope request by the client. By returning "null", - * opt out of requiring scopes - * - * @param $client_id - * An optional client id that can be used to return customized default scopes. - * - * @return - * string representation of default scope, null if - * scopes are not defined, or false to force scope - * request by the client - * - * ex: - * 'default' - * ex: - * null - */ - public function getDefaultScope($client_id = null); -} diff --git a/library/oauth2/src/OAuth2/Storage/UserCredentialsInterface.php b/library/oauth2/src/OAuth2/Storage/UserCredentialsInterface.php deleted file mode 100644 index 6e0fd7bad..000000000 --- a/library/oauth2/src/OAuth2/Storage/UserCredentialsInterface.php +++ /dev/null @@ -1,52 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -/** - * Implement this interface to specify where the OAuth2 Server - * should retrieve user credentials for the - * "Resource Owner Password Credentials" grant type - * - * @author Brent Shaffer <bshafs at gmail dot com> - */ -interface UserCredentialsInterface -{ - /** - * Grant access tokens for basic user credentials. - * - * Check the supplied username and password for validity. - * - * You can also use the $client_id param to do any checks required based - * on a client, if you need that. - * - * Required for OAuth2::GRANT_TYPE_USER_CREDENTIALS. - * - * @param $username - * Username to be check with. - * @param $password - * Password to be check with. - * - * @return - * TRUE if the username and password are valid, and FALSE if it isn't. - * Moreover, if the username and password are valid, and you want to - * - * @see http://tools.ietf.org/html/rfc6749#section-4.3 - * - * @ingroup oauth2_section_4 - */ - public function checkUserCredentials($username, $password); - - /** - * @return - * ARRAY the associated "user_id" and optional "scope" values - * This function MUST return FALSE if the requested user does not exist or is - * invalid. "scope" is a space-separated list of restricted scopes. - * @code - * return array( - * "user_id" => USER_ID, // REQUIRED user_id to be stored with the authorization code or access token - * "scope" => SCOPE // OPTIONAL space-separated list of restricted scopes - * ); - * @endcode - */ - public function getUserDetails($username); -} diff --git a/library/oauth2/src/OAuth2/TokenType/Bearer.php b/library/oauth2/src/OAuth2/TokenType/Bearer.php deleted file mode 100644 index 8ac8596ac..000000000 --- a/library/oauth2/src/OAuth2/TokenType/Bearer.php +++ /dev/null @@ -1,130 +0,0 @@ -<?php - -namespace OAuth2\TokenType; - -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -/** -* -*/ -class Bearer implements TokenTypeInterface -{ - private $config; - - public function __construct(array $config = array()) - { - $this->config = array_merge(array( - 'token_param_name' => 'access_token', - 'token_bearer_header_name' => 'Bearer', - ), $config); - } - - public function getTokenType() - { - return 'Bearer'; - } - - /** - * Check if the request has supplied token - * - * @see https://github.com/bshaffer/oauth2-server-php/issues/349#issuecomment-37993588 - */ - public function requestHasToken(RequestInterface $request) - { - $headers = $request->headers('AUTHORIZATION'); - - // check the header, then the querystring, then the request body - return !empty($headers) || (bool) ($request->request($this->config['token_param_name'])) || (bool) ($request->query($this->config['token_param_name'])); - } - - /** - * This is a convenience function that can be used to get the token, which can then - * be passed to getAccessTokenData(). The constraints specified by the draft are - * attempted to be adheared to in this method. - * - * As per the Bearer spec (draft 8, section 2) - there are three ways for a client - * to specify the bearer token, in order of preference: Authorization Header, - * POST and GET. - * - * NB: Resource servers MUST accept tokens via the Authorization scheme - * (http://tools.ietf.org/html/rfc6750#section-2). - * - * @todo Should we enforce TLS/SSL in this function? - * - * @see http://tools.ietf.org/html/rfc6750#section-2.1 - * @see http://tools.ietf.org/html/rfc6750#section-2.2 - * @see http://tools.ietf.org/html/rfc6750#section-2.3 - * - * Old Android version bug (at least with version 2.2) - * @see http://code.google.com/p/android/issues/detail?id=6684 - * - */ - public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response) - { - $headers = $request->headers('AUTHORIZATION'); - - /** - * Ensure more than one method is not used for including an - * access token - * - * @see http://tools.ietf.org/html/rfc6750#section-3.1 - */ - $methodsUsed = !empty($headers) + (bool) ($request->query($this->config['token_param_name'])) + (bool) ($request->request($this->config['token_param_name'])); - if ($methodsUsed > 1) { - $response->setError(400, 'invalid_request', 'Only one method may be used to authenticate at a time (Auth header, GET or POST)'); - - return null; - } - - /** - * If no authentication is provided, set the status code - * to 401 and return no other error information - * - * @see http://tools.ietf.org/html/rfc6750#section-3.1 - */ - if ($methodsUsed == 0) { - $response->setStatusCode(401); - - return null; - } - - // HEADER: Get the access token from the header - if (!empty($headers)) { - if (!preg_match('/' . $this->config['token_bearer_header_name'] . '\s(\S+)/i', $headers, $matches)) { - $response->setError(400, 'invalid_request', 'Malformed auth header'); - - return null; - } - - return $matches[1]; - } - - if ($request->request($this->config['token_param_name'])) { - // // POST: Get the token from POST data - if (!in_array(strtolower($request->server('REQUEST_METHOD')), array('post', 'put'))) { - $response->setError(400, 'invalid_request', 'When putting the token in the body, the method must be POST or PUT', '#section-2.2'); - - return null; - } - - $contentType = $request->server('CONTENT_TYPE'); - if (false !== $pos = strpos($contentType, ';')) { - $contentType = substr($contentType, 0, $pos); - } - - if ($contentType !== null && $contentType != 'application/x-www-form-urlencoded') { - // IETF specifies content-type. NB: Not all webservers populate this _SERVER variable - // @see http://tools.ietf.org/html/rfc6750#section-2.2 - $response->setError(400, 'invalid_request', 'The content type for POST requests must be "application/x-www-form-urlencoded"'); - - return null; - } - - return $request->request($this->config['token_param_name']); - } - - // GET method - return $request->query($this->config['token_param_name']); - } -} diff --git a/library/oauth2/src/OAuth2/TokenType/Mac.php b/library/oauth2/src/OAuth2/TokenType/Mac.php deleted file mode 100644 index fe6a86aa6..000000000 --- a/library/oauth2/src/OAuth2/TokenType/Mac.php +++ /dev/null @@ -1,22 +0,0 @@ -<?php - -namespace OAuth2\TokenType; - -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -/** -* This is not yet supported! -*/ -class Mac implements TokenTypeInterface -{ - public function getTokenType() - { - return 'mac'; - } - - public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response) - { - throw new \LogicException("Not supported"); - } -} diff --git a/library/oauth2/src/OAuth2/TokenType/TokenTypeInterface.php b/library/oauth2/src/OAuth2/TokenType/TokenTypeInterface.php deleted file mode 100644 index ad77d4a25..000000000 --- a/library/oauth2/src/OAuth2/TokenType/TokenTypeInterface.php +++ /dev/null @@ -1,21 +0,0 @@ -<?php - -namespace OAuth2\TokenType; - -use OAuth2\RequestInterface; -use OAuth2\ResponseInterface; - -interface TokenTypeInterface -{ - /** - * Token type identification string - * - * ex: "bearer" or "mac" - */ - public function getTokenType(); - - /** - * Retrieves the token string from the request object - */ - public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response); -} diff --git a/library/oauth2/test/OAuth2/AutoloadTest.php b/library/oauth2/test/OAuth2/AutoloadTest.php deleted file mode 100644 index 5901bdc42..000000000 --- a/library/oauth2/test/OAuth2/AutoloadTest.php +++ /dev/null @@ -1,16 +0,0 @@ -<?php - -namespace OAuth2; - -class AutoloadTest extends \PHPUnit_Framework_TestCase -{ - public function testClassesExist() - { - // autoloader is called in test/bootstrap.php - $this->assertTrue(class_exists('OAuth2\Server')); - $this->assertTrue(class_exists('OAuth2\Request')); - $this->assertTrue(class_exists('OAuth2\Response')); - $this->assertTrue(class_exists('OAuth2\GrantType\UserCredentials')); - $this->assertTrue(interface_exists('OAuth2\Storage\AccessTokenInterface')); - } -} diff --git a/library/oauth2/test/OAuth2/Controller/AuthorizeControllerTest.php b/library/oauth2/test/OAuth2/Controller/AuthorizeControllerTest.php deleted file mode 100644 index 3bfc760e4..000000000 --- a/library/oauth2/test/OAuth2/Controller/AuthorizeControllerTest.php +++ /dev/null @@ -1,492 +0,0 @@ -<?php - -namespace OAuth2\Controller; - -use OAuth2\Storage\Memory; -use OAuth2\Scope; -use OAuth2\Storage\Bootstrap; -use OAuth2\Server; -use OAuth2\GrantType\AuthorizationCode; -use OAuth2\Request; -use OAuth2\Response; -use OAuth2\Request\TestRequest; - -class AuthorizeControllerTest extends \PHPUnit_Framework_TestCase -{ - public function testNoClientIdResponse() - { - $server = $this->getTestServer(); - $request = new Request(); - $server->handleAuthorizeRequest($request, $response = new Response(), false); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_client'); - $this->assertEquals($response->getParameter('error_description'), 'No client id supplied'); - } - - public function testInvalidClientIdResponse() - { - $server = $this->getTestServer(); - $request = new Request(array( - 'client_id' => 'Fake Client ID', // invalid client id - )); - $server->handleAuthorizeRequest($request, $response = new Response(), false); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_client'); - $this->assertEquals($response->getParameter('error_description'), 'The client id supplied is invalid'); - } - - public function testNoRedirectUriSuppliedOrStoredResponse() - { - $server = $this->getTestServer(); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - )); - $server->handleAuthorizeRequest($request, $response = new Response(), false); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_uri'); - $this->assertEquals($response->getParameter('error_description'), 'No redirect URI was supplied or stored'); - } - - public function testNoResponseTypeResponse() - { - $server = $this->getTestServer(); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com', // valid redirect URI - )); - $server->handleAuthorizeRequest($request, $response = new Response(), false); - - $this->assertEquals($response->getStatusCode(), 302); - $location = $response->getHttpHeader('Location'); - $parts = parse_url($location); - parse_str($parts['query'], $query); - - $this->assertEquals($query['error'], 'invalid_request'); - $this->assertEquals($query['error_description'], 'Invalid or missing response type'); - } - - public function testInvalidResponseTypeResponse() - { - $server = $this->getTestServer(); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com', // valid redirect URI - 'response_type' => 'invalid', // invalid response type - )); - $server->handleAuthorizeRequest($request, $response = new Response(), false); - - $this->assertEquals($response->getStatusCode(), 302); - $location = $response->getHttpHeader('Location'); - $parts = parse_url($location); - parse_str($parts['query'], $query); - - $this->assertEquals($query['error'], 'invalid_request'); - $this->assertEquals($query['error_description'], 'Invalid or missing response type'); - } - - public function testRedirectUriFragmentResponse() - { - $server = $this->getTestServer(); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com#fragment', // valid redirect URI - 'response_type' => 'code', // invalid response type - )); - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_uri'); - $this->assertEquals($response->getParameter('error_description'), 'The redirect URI must not contain a fragment'); - } - - public function testEnforceState() - { - $server = $this->getTestServer(array('enforce_state' => true)); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com', // valid redirect URI - 'response_type' => 'code', - )); - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 302); - $location = $response->getHttpHeader('Location'); - $parts = parse_url($location); - parse_str($parts['query'], $query); - - $this->assertEquals($query['error'], 'invalid_request'); - $this->assertEquals($query['error_description'], 'The state parameter is required'); - } - - public function testDoNotEnforceState() - { - $server = $this->getTestServer(array('enforce_state' => false)); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com', // valid redirect URI - 'response_type' => 'code', - )); - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 302); - $this->assertNotContains('error', $response->getHttpHeader('Location')); - } - - public function testEnforceScope() - { - $server = $this->getTestServer(); - $scopeStorage = new Memory(array('default_scope' => false, 'supported_scopes' => array('testscope'))); - $server->setScopeUtil(new Scope($scopeStorage)); - - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com', // valid redirect URI - 'response_type' => 'code', - 'state' => 'xyz', - )); - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 302); - $parts = parse_url($response->getHttpHeader('Location')); - parse_str($parts['query'], $query); - - $this->assertEquals($query['error'], 'invalid_client'); - $this->assertEquals($query['error_description'], 'This application requires you specify a scope parameter'); - - $request->query['scope'] = 'testscope'; - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 302); - $this->assertNotContains('error', $response->getHttpHeader('Location')); - } - - public function testInvalidRedirectUri() - { - $server = $this->getTestServer(); - $request = new Request(array( - 'client_id' => 'Test Client ID with Redirect Uri', // valid client id - 'redirect_uri' => 'http://adobe.com', // invalid redirect URI - 'response_type' => 'code', - )); - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'redirect_uri_mismatch'); - $this->assertEquals($response->getParameter('error_description'), 'The redirect URI provided is missing or does not match'); - } - - public function testInvalidRedirectUriApprovedByBuggyRegisteredUri() - { - $server = $this->getTestServer(); - $server->setConfig('require_exact_redirect_uri', false); - $request = new Request(array( - 'client_id' => 'Test Client ID with Buggy Redirect Uri', // valid client id - 'redirect_uri' => 'http://adobe.com', // invalid redirect URI - 'response_type' => 'code', - )); - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'redirect_uri_mismatch'); - $this->assertEquals($response->getParameter('error_description'), 'The redirect URI provided is missing or does not match'); - } - - public function testNoRedirectUriWithMultipleRedirectUris() - { - $server = $this->getTestServer(); - - // create a request with no "redirect_uri" in querystring - $request = new Request(array( - 'client_id' => 'Test Client ID with Multiple Redirect Uris', // valid client id - 'response_type' => 'code', - )); - - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_uri'); - $this->assertEquals($response->getParameter('error_description'), 'A redirect URI must be supplied when multiple redirect URIs are registered'); - } - - public function testRedirectUriWithValidRedirectUri() - { - $server = $this->getTestServer(); - - // create a request with no "redirect_uri" in querystring - $request = new Request(array( - 'client_id' => 'Test Client ID with Redirect Uri Parts', // valid client id - 'response_type' => 'code', - 'redirect_uri' => 'http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth&test=true', - 'state' => 'xyz', - )); - - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 302); - $this->assertContains('code', $response->getHttpHeader('Location')); - } - - public function testRedirectUriWithDifferentQueryAndExactMatchRequired() - { - $server = $this->getTestServer(array('require_exact_redirect_uri' => true)); - - // create a request with no "redirect_uri" in querystring - $request = new Request(array( - 'client_id' => 'Test Client ID with Redirect Uri Parts', // valid client id - 'response_type' => 'code', - 'redirect_uri' => 'http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth&test=true&hereisa=querystring', - )); - - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'redirect_uri_mismatch'); - $this->assertEquals($response->getParameter('error_description'), 'The redirect URI provided is missing or does not match'); - } - - public function testRedirectUriWithDifferentQueryAndExactMatchNotRequired() - { - $server = $this->getTestServer(array('require_exact_redirect_uri' => false)); - - // create a request with no "redirect_uri" in querystring - $request = new Request(array( - 'client_id' => 'Test Client ID with Redirect Uri Parts', // valid client id - 'response_type' => 'code', - 'redirect_uri' => 'http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth&test=true&hereisa=querystring', - 'state' => 'xyz', - )); - - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 302); - $this->assertContains('code', $response->getHttpHeader('Location')); - } - - public function testMultipleRedirectUris() - { - $server = $this->getTestServer(); - $request = new Request(array( - 'client_id' => 'Test Client ID with Multiple Redirect Uris', // valid client id - 'redirect_uri' => 'http://brentertainment.com', // valid redirect URI - 'response_type' => 'code', - 'state' => 'xyz' - )); - - $server->handleAuthorizeRequest($request, $response = new Response(), true); - $this->assertEquals($response->getStatusCode(), 302); - $this->assertContains('code', $response->getHttpHeader('Location')); - - // call again with different (but still valid) redirect URI - $request->query['redirect_uri'] = 'http://morehazards.com'; - - $server->handleAuthorizeRequest($request, $response = new Response(), true); - $this->assertEquals($response->getStatusCode(), 302); - $this->assertContains('code', $response->getHttpHeader('Location')); - } - - /** - * @see http://tools.ietf.org/html/rfc6749#section-4.1.3 - * @see https://github.com/bshaffer/oauth2-server-php/issues/163 - */ - public function testNoRedirectUriSuppliedDoesNotRequireTokenRedirectUri() - { - $server = $this->getTestServer(); - $request = new Request(array( - 'client_id' => 'Test Client ID with Redirect Uri', // valid client id - 'response_type' => 'code', - 'state' => 'xyz', - )); - - $server->handleAuthorizeRequest($request, $response = new Response(), true); - $this->assertEquals($response->getStatusCode(), 302); - $this->assertContains('state', $response->getHttpHeader('Location')); - $this->assertStringStartsWith('http://brentertainment.com?code=', $response->getHttpHeader('Location')); - - $parts = parse_url($response->getHttpHeader('Location')); - parse_str($parts['query'], $query); - - // call token endpoint with no redirect_uri supplied - $request = TestRequest::createPost(array( - 'client_id' => 'Test Client ID with Redirect Uri', // valid client id - 'client_secret' => 'TestSecret2', - 'grant_type' => 'authorization_code', - 'code' => $query['code'], - )); - - $server->handleTokenRequest($request, $response = new Response(), true); - $this->assertEquals($response->getStatusCode(), 200); - $this->assertNotNull($response->getParameter('access_token')); - } - - public function testUserDeniesAccessResponse() - { - $server = $this->getTestServer(); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com', // valid redirect URI - 'response_type' => 'code', - 'state' => 'xyz', - )); - $server->handleAuthorizeRequest($request, $response = new Response(), false); - - $this->assertEquals($response->getStatusCode(), 302); - $location = $response->getHttpHeader('Location'); - $parts = parse_url($location); - parse_str($parts['query'], $query); - - $this->assertEquals($query['error'], 'access_denied'); - $this->assertEquals($query['error_description'], 'The user denied access to your application'); - } - - public function testCodeQueryParamIsSet() - { - $server = $this->getTestServer(); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com', // valid redirect URI - 'response_type' => 'code', - 'state' => 'xyz', - )); - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 302); - $location = $response->getHttpHeader('Location'); - $parts = parse_url($location); - parse_str($parts['query'], $query); - - $location = $response->getHttpHeader('Location'); - $parts = parse_url($location); - - $this->assertEquals('http', $parts['scheme']); // same as passed in to redirect_uri - $this->assertEquals('adobe.com', $parts['host']); // same as passed in to redirect_uri - $this->assertArrayHasKey('query', $parts); - $this->assertFalse(isset($parts['fragment'])); - - // assert fragment is in "application/x-www-form-urlencoded" format - parse_str($parts['query'], $query); - $this->assertNotNull($query); - $this->assertArrayHasKey('code', $query); - - // ensure no id_token was saved, since the openid scope wasn't requested - $storage = $server->getStorage('authorization_code'); - $code = $storage->getAuthorizationCode($query['code']); - $this->assertTrue(empty($code['id_token'])); - - // ensure no error was returned - $this->assertFalse(isset($query['error'])); - $this->assertFalse(isset($query['error_description'])); - } - - public function testSuccessfulRequestReturnsStateParameter() - { - $server = $this->getTestServer(array('allow_implicit' => true)); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com', // valid redirect URI - 'response_type' => 'code', - 'state' => 'test', // valid state string (just needs to be passed back to us) - )); - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 302); - - $location = $response->getHttpHeader('Location'); - $parts = parse_url($location); - $this->assertArrayHasKey('query', $parts); - parse_str($parts['query'], $query); - - $this->assertArrayHasKey('state', $query); - $this->assertEquals($query['state'], 'test'); - - // ensure no error was returned - $this->assertFalse(isset($query['error'])); - $this->assertFalse(isset($query['error_description'])); - } - - public function testSuccessfulRequestStripsExtraParameters() - { - $server = $this->getTestServer(array('allow_implicit' => true)); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com', // valid redirect URI - 'response_type' => 'code', - 'state' => 'test', // valid state string (just needs to be passed back to us) - 'fake' => 'something', // extra query param - )); - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 302); - $location = $response->getHttpHeader('Location'); - $this->assertNotContains('error', $location); - - $parts = parse_url($location); - $this->assertFalse(isset($parts['fake'])); - $this->assertArrayHasKey('query', $parts); - parse_str($parts['query'], $query); - - $this->assertFalse(isset($parmas['fake'])); - $this->assertArrayHasKey('state', $query); - $this->assertEquals($query['state'], 'test'); - } - - public function testSuccessfulOpenidConnectRequest() - { - $server = $this->getTestServer(array( - 'use_openid_connect' => true, - 'issuer' => 'bojanz', - )); - - $request = new Request(array( - 'client_id' => 'Test Client ID', - 'redirect_uri' => 'http://adobe.com', - 'response_type' => 'code', - 'state' => 'xyz', - 'scope' => 'openid', - )); - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 302); - $location = $response->getHttpHeader('Location'); - $parts = parse_url($location); - parse_str($parts['query'], $query); - - $location = $response->getHttpHeader('Location'); - $parts = parse_url($location); - $this->assertArrayHasKey('query', $parts); - $this->assertFalse(isset($parts['fragment'])); - - // assert fragment is in "application/x-www-form-urlencoded" format - parse_str($parts['query'], $query); - $this->assertNotNull($query); - $this->assertArrayHasKey('code', $query); - - // ensure no error was returned - $this->assertFalse(isset($query['error'])); - $this->assertFalse(isset($query['error_description'])); - - // confirm that the id_token has been created. - $storage = $server->getStorage('authorization_code'); - $code = $storage->getAuthorizationCode($query['code']); - $this->assertTrue(!empty($code['id_token'])); - } - - public function testCreateController() - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $controller = new AuthorizeController($storage); - } - - private function getTestServer($config = array()) - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage, $config); - - // Add the two types supported for authorization grant - $server->addGrantType(new AuthorizationCode($storage)); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/Controller/ResourceControllerTest.php b/library/oauth2/test/OAuth2/Controller/ResourceControllerTest.php deleted file mode 100644 index ee6d96ff8..000000000 --- a/library/oauth2/test/OAuth2/Controller/ResourceControllerTest.php +++ /dev/null @@ -1,175 +0,0 @@ -<?php - -namespace OAuth2\Controller; - -use OAuth2\Storage\Bootstrap; -use OAuth2\Server; -use OAuth2\GrantType\AuthorizationCode; -use OAuth2\Request; -use OAuth2\Response; - -class ResourceControllerTest extends \PHPUnit_Framework_TestCase -{ - public function testNoAccessToken() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 401); - $this->assertNull($response->getParameter('error')); - $this->assertNull($response->getParameter('error_description')); - } - - public function testMalformedHeader() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->headers['AUTHORIZATION'] = 'tH1s i5 B0gU5'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'Malformed auth header'); - } - - public function testMultipleTokensSubmitted() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->request['access_token'] = 'TEST'; - $request->query['access_token'] = 'TEST'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'Only one method may be used to authenticate at a time (Auth header, GET or POST)'); - } - - public function testInvalidRequestMethod() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->server['REQUEST_METHOD'] = 'GET'; - $request->request['access_token'] = 'TEST'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'When putting the token in the body, the method must be POST or PUT'); - } - - public function testInvalidContentType() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->server['REQUEST_METHOD'] = 'POST'; - $request->server['CONTENT_TYPE'] = 'application/json'; - $request->request['access_token'] = 'TEST'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'The content type for POST requests must be "application/x-www-form-urlencoded"'); - } - - public function testInvalidToken() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->headers['AUTHORIZATION'] = 'Bearer TESTTOKEN'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 401); - $this->assertEquals($response->getParameter('error'), 'invalid_token'); - $this->assertEquals($response->getParameter('error_description'), 'The access token provided is invalid'); - } - - public function testExpiredToken() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-expired'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 401); - $this->assertEquals($response->getParameter('error'), 'expired_token'); - $this->assertEquals($response->getParameter('error_description'), 'The access token provided has expired'); - } - - public function testOutOfScopeToken() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-scope'; - $scope = 'outofscope'; - $allow = $server->verifyResourceRequest($request, $response = new Response(), $scope); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 403); - $this->assertEquals($response->getParameter('error'), 'insufficient_scope'); - $this->assertEquals($response->getParameter('error_description'), 'The request requires higher privileges than provided by the access token'); - - // verify the "scope" has been set in the "WWW-Authenticate" header - preg_match('/scope="(.*?)"/', $response->getHttpHeader('WWW-Authenticate'), $matches); - $this->assertEquals(2, count($matches)); - $this->assertEquals($matches[1], 'outofscope'); - } - - public function testMalformedToken() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-malformed'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertFalse($allow); - - $this->assertEquals($response->getStatusCode(), 401); - $this->assertEquals($response->getParameter('error'), 'malformed_token'); - $this->assertEquals($response->getParameter('error_description'), 'Malformed token (missing "expires")'); - } - - public function testValidToken() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-scope'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertTrue($allow); - } - - public function testValidTokenWithScopeParam() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-scope'; - $request->query['scope'] = 'testscope'; - $allow = $server->verifyResourceRequest($request, $response = new Response()); - $this->assertTrue($allow); - } - - public function testCreateController() - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $tokenType = new \OAuth2\TokenType\Bearer(); - $controller = new ResourceController($tokenType, $storage); - } - - private function getTestServer($config = array()) - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage, $config); - - // Add the two types supported for authorization grant - $server->addGrantType(new AuthorizationCode($storage)); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/Controller/TokenControllerTest.php b/library/oauth2/test/OAuth2/Controller/TokenControllerTest.php deleted file mode 100644 index 4a217bd55..000000000 --- a/library/oauth2/test/OAuth2/Controller/TokenControllerTest.php +++ /dev/null @@ -1,289 +0,0 @@ -<?php - -namespace OAuth2\Controller; - -use OAuth2\Storage\Bootstrap; -use OAuth2\Server; -use OAuth2\GrantType\AuthorizationCode; -use OAuth2\GrantType\ClientCredentials; -use OAuth2\GrantType\UserCredentials; -use OAuth2\Scope; -use OAuth2\Request\TestRequest; -use OAuth2\Response; - -class TokenControllerTest extends \PHPUnit_Framework_TestCase -{ - public function testNoGrantType() - { - // add the test parameters in memory - $server = $this->getTestServer(); - $server->handleTokenRequest(TestRequest::createPost(), $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'The grant type was not specified in the request'); - } - - public function testInvalidGrantType() - { - // add the test parameters in memory - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'invalid_grant_type', // invalid grant type - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'unsupported_grant_type'); - $this->assertEquals($response->getParameter('error_description'), 'Grant type "invalid_grant_type" not supported'); - } - - public function testNoClientId() - { - // add the test parameters in memory - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'code' => 'testcode', - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_client'); - $this->assertEquals($response->getParameter('error_description'), 'Client credentials were not found in the headers or body'); - } - - public function testNoClientSecretWithConfidentialClient() - { - // add the test parameters in memory - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'code' => 'testcode', - 'client_id' => 'Test Client ID', // valid client id - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_client'); - $this->assertEquals($response->getParameter('error_description'), 'This client is invalid or must authenticate using a client secret'); - } - - public function testNoClientSecretWithEmptySecret() - { - // add the test parameters in memory - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'code' => 'testcode-empty-secret', - 'client_id' => 'Test Client ID Empty Secret', // valid client id - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 200); - } - - public function testInvalidClientId() - { - // add the test parameters in memory - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'code' => 'testcode', - 'client_id' => 'Fake Client ID', // invalid client id - 'client_secret' => 'TestSecret', // valid client secret - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_client'); - $this->assertEquals($response->getParameter('error_description'), 'The client credentials are invalid'); - } - - public function testInvalidClientSecret() - { - // add the test parameters in memory - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'code' => 'testcode', - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'Fake Client Secret', // invalid client secret - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_client'); - $this->assertEquals($response->getParameter('error_description'), 'The client credentials are invalid'); - } - - public function testValidTokenResponse() - { - // add the test parameters in memory - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode', // valid authorization code - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertTrue($response instanceof Response); - $this->assertEquals($response->getStatusCode(), 200); - $this->assertNull($response->getParameter('error')); - $this->assertNull($response->getParameter('error_description')); - $this->assertNotNull($response->getParameter('access_token')); - $this->assertNotNull($response->getParameter('expires_in')); - $this->assertNotNull($response->getParameter('token_type')); - } - - public function testValidClientIdScope() - { - // add the test parameters in memory - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'code' => 'testcode', - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'scope' => 'clientscope1 clientscope2' - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 200); - $this->assertNull($response->getParameter('error')); - $this->assertNull($response->getParameter('error_description')); - $this->assertEquals('clientscope1 clientscope2', $response->getParameter('scope')); - } - - public function testInvalidClientIdScope() - { - // add the test parameters in memory - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'code' => 'testcode-with-scope', - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'scope' => 'clientscope3' - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_scope'); - $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request'); - } - - public function testEnforceScope() - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage); - $server->addGrantType(new ClientCredentials($storage)); - - $scope = new Scope(array( - 'default_scope' => false, - 'supported_scopes' => array('testscope') - )); - $server->setScopeUtil($scope); - - $request = TestRequest::createPost(array( - 'grant_type' => 'client_credentials', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - )); - $response = $server->handleTokenRequest($request); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_scope'); - $this->assertEquals($response->getParameter('error_description'), 'This application requires you specify a scope parameter'); - } - - public function testCanReceiveAccessTokenUsingPasswordGrantTypeWithoutClientSecret() - { - // add the test parameters in memory - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage); - $server->addGrantType(new UserCredentials($storage)); - - $request = TestRequest::createPost(array( - 'grant_type' => 'password', // valid grant type - 'client_id' => 'Test Client ID For Password Grant', // valid client id - 'username' => 'johndoe', // valid username - 'password' => 'password', // valid password for username - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertTrue($response instanceof Response); - $this->assertEquals(200, $response->getStatusCode(), var_export($response, 1)); - $this->assertNull($response->getParameter('error')); - $this->assertNull($response->getParameter('error_description')); - $this->assertNotNull($response->getParameter('access_token')); - $this->assertNotNull($response->getParameter('expires_in')); - $this->assertNotNull($response->getParameter('token_type')); - } - - public function testInvalidTokenTypeHintForRevoke() - { - $server = $this->getTestServer(); - - $request = TestRequest::createPost(array( - 'token_type_hint' => 'foo', - 'token' => 'sometoken' - )); - - $server->handleRevokeRequest($request, $response = new Response()); - - $this->assertTrue($response instanceof Response); - $this->assertEquals(400, $response->getStatusCode(), var_export($response, 1)); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'Token type hint must be either \'access_token\' or \'refresh_token\''); - } - - public function testMissingTokenForRevoke() - { - $server = $this->getTestServer(); - - $request = TestRequest::createPost(array( - 'token_type_hint' => 'access_token' - )); - - $server->handleRevokeRequest($request, $response = new Response()); - $this->assertTrue($response instanceof Response); - $this->assertEquals(400, $response->getStatusCode(), var_export($response, 1)); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'Missing token parameter to revoke'); - } - - public function testInvalidRequestMethodForRevoke() - { - $server = $this->getTestServer(); - - $request = new TestRequest(); - $request->setQuery(array( - 'token_type_hint' => 'access_token' - )); - - $server->handleRevokeRequest($request, $response = new Response()); - $this->assertTrue($response instanceof Response); - $this->assertEquals(405, $response->getStatusCode(), var_export($response, 1)); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'The request method must be POST when revoking an access token'); - } - - public function testCreateController() - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $accessToken = new \OAuth2\ResponseType\AccessToken($storage); - $controller = new TokenController($accessToken, $storage); - } - - private function getTestServer() - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage); - $server->addGrantType(new AuthorizationCode($storage)); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/Encryption/FirebaseJwtTest.php b/library/oauth2/test/OAuth2/Encryption/FirebaseJwtTest.php deleted file mode 100644 index d34136767..000000000 --- a/library/oauth2/test/OAuth2/Encryption/FirebaseJwtTest.php +++ /dev/null @@ -1,102 +0,0 @@ -<?php - -namespace OAuth2\Encryption; - -use OAuth2\Storage\Bootstrap; - -class FirebaseJwtTest extends \PHPUnit_Framework_TestCase -{ - private $privateKey; - - public function setUp() - { - $this->privateKey = <<<EOD ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQC5/SxVlE8gnpFqCxgl2wjhzY7ucEi00s0kUg3xp7lVEvgLgYcA -nHiWp+gtSjOFfH2zsvpiWm6Lz5f743j/FEzHIO1owR0p4d9pOaJK07d01+RzoQLO -IQAgXrr4T1CCWUesncwwPBVCyy2Mw3Nmhmr9MrF8UlvdRKBxriRnlP3qJQIDAQAB -AoGAVgJJVU4fhYMu1e5JfYAcTGfF+Gf+h3iQm4JCpoUcxMXf5VpB9ztk3K7LRN5y -kwFuFALpnUAarRcUPs0D8FoP4qBluKksbAtgHkO7bMSH9emN+mH4le4qpFlR7+P1 -3fLE2Y19IBwPwEfClC+TpJvuog6xqUYGPlg6XLq/MxQUB4ECQQDgovP1v+ONSeGS -R+NgJTR47noTkQT3M2izlce/OG7a+O0yw6BOZjNXqH2wx3DshqMcPUFrTjibIClP -l/tEQ3ShAkEA0/TdBYDtXpNNjqg0R9GVH2pw7Kh68ne6mZTuj0kCgFYpUF6L6iMm -zXamIJ51rTDsTyKTAZ1JuAhAsK/M2BbDBQJAKQ5fXEkIA+i+64dsDUR/hKLBeRYG -PFAPENONQGvGBwt7/s02XV3cgGbxIgAxqWkqIp0neb9AJUoJgtyaNe3GQQJANoL4 -QQ0af0NVJAZgg8QEHTNL3aGrFSbzx8IE5Lb7PLRsJa5bP5lQxnDoYuU+EI/Phr62 -niisp/b/ZDGidkTMXQJBALeRsH1I+LmICAvWXpLKa9Gv0zGCwkuIJLiUbV9c6CVh -suocCAteQwL5iW2gA4AnYr5OGeHFsEl7NCQcwfPZpJ0= ------END RSA PRIVATE KEY----- -EOD; - } - - /** @dataProvider provideClientCredentials */ - public function testJwtUtil($client_id, $client_key) - { - $jwtUtil = new FirebaseJwt(); - - $params = array( - 'iss' => $client_id, - 'exp' => time() + 1000, - 'iat' => time(), - 'sub' => 'testuser@ourdomain.com', - 'aud' => 'http://myapp.com/oauth/auth', - 'scope' => null, - ); - - $encoded = $jwtUtil->encode($params, $this->privateKey, 'RS256'); - - // test BC behaviour of trusting the algorithm in the header - $payload = $jwtUtil->decode($encoded, $client_key, array('RS256')); - $this->assertEquals($params, $payload); - - // test BC behaviour of not verifying by passing false - $payload = $jwtUtil->decode($encoded, $client_key, false); - $this->assertEquals($params, $payload); - - // test the new restricted algorithms header - $payload = $jwtUtil->decode($encoded, $client_key, array('RS256')); - $this->assertEquals($params, $payload); - } - - public function testInvalidJwt() - { - $jwtUtil = new FirebaseJwt(); - - $this->assertFalse($jwtUtil->decode('goob')); - $this->assertFalse($jwtUtil->decode('go.o.b')); - } - - /** @dataProvider provideClientCredentials */ - public function testInvalidJwtHeader($client_id, $client_key) - { - $jwtUtil = new FirebaseJwt(); - - $params = array( - 'iss' => $client_id, - 'exp' => time() + 1000, - 'iat' => time(), - 'sub' => 'testuser@ourdomain.com', - 'aud' => 'http://myapp.com/oauth/auth', - 'scope' => null, - ); - - // testing for algorithm tampering when only RSA256 signing is allowed - // @see https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/ - $tampered = $jwtUtil->encode($params, $client_key, 'HS256'); - - $payload = $jwtUtil->decode($tampered, $client_key, array('RS256')); - - $this->assertFalse($payload); - } - - public function provideClientCredentials() - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $client_id = 'Test Client ID'; - $client_key = $storage->getClientKey($client_id, "testuser@ourdomain.com"); - - return array( - array($client_id, $client_key), - ); - } -} diff --git a/library/oauth2/test/OAuth2/Encryption/JwtTest.php b/library/oauth2/test/OAuth2/Encryption/JwtTest.php deleted file mode 100644 index 214eebac8..000000000 --- a/library/oauth2/test/OAuth2/Encryption/JwtTest.php +++ /dev/null @@ -1,102 +0,0 @@ -<?php - -namespace OAuth2\Encryption; - -use OAuth2\Storage\Bootstrap; - -class JwtTest extends \PHPUnit_Framework_TestCase -{ - private $privateKey; - - public function setUp() - { - $this->privateKey = <<<EOD ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQC5/SxVlE8gnpFqCxgl2wjhzY7ucEi00s0kUg3xp7lVEvgLgYcA -nHiWp+gtSjOFfH2zsvpiWm6Lz5f743j/FEzHIO1owR0p4d9pOaJK07d01+RzoQLO -IQAgXrr4T1CCWUesncwwPBVCyy2Mw3Nmhmr9MrF8UlvdRKBxriRnlP3qJQIDAQAB -AoGAVgJJVU4fhYMu1e5JfYAcTGfF+Gf+h3iQm4JCpoUcxMXf5VpB9ztk3K7LRN5y -kwFuFALpnUAarRcUPs0D8FoP4qBluKksbAtgHkO7bMSH9emN+mH4le4qpFlR7+P1 -3fLE2Y19IBwPwEfClC+TpJvuog6xqUYGPlg6XLq/MxQUB4ECQQDgovP1v+ONSeGS -R+NgJTR47noTkQT3M2izlce/OG7a+O0yw6BOZjNXqH2wx3DshqMcPUFrTjibIClP -l/tEQ3ShAkEA0/TdBYDtXpNNjqg0R9GVH2pw7Kh68ne6mZTuj0kCgFYpUF6L6iMm -zXamIJ51rTDsTyKTAZ1JuAhAsK/M2BbDBQJAKQ5fXEkIA+i+64dsDUR/hKLBeRYG -PFAPENONQGvGBwt7/s02XV3cgGbxIgAxqWkqIp0neb9AJUoJgtyaNe3GQQJANoL4 -QQ0af0NVJAZgg8QEHTNL3aGrFSbzx8IE5Lb7PLRsJa5bP5lQxnDoYuU+EI/Phr62 -niisp/b/ZDGidkTMXQJBALeRsH1I+LmICAvWXpLKa9Gv0zGCwkuIJLiUbV9c6CVh -suocCAteQwL5iW2gA4AnYr5OGeHFsEl7NCQcwfPZpJ0= ------END RSA PRIVATE KEY----- -EOD; - } - - /** @dataProvider provideClientCredentials */ - public function testJwtUtil($client_id, $client_key) - { - $jwtUtil = new Jwt(); - - $params = array( - 'iss' => $client_id, - 'exp' => time() + 1000, - 'iat' => time(), - 'sub' => 'testuser@ourdomain.com', - 'aud' => 'http://myapp.com/oauth/auth', - 'scope' => null, - ); - - $encoded = $jwtUtil->encode($params, $this->privateKey, 'RS256'); - - // test BC behaviour of trusting the algorithm in the header - $payload = $jwtUtil->decode($encoded, $client_key); - $this->assertEquals($params, $payload); - - // test BC behaviour of not verifying by passing false - $payload = $jwtUtil->decode($encoded, $client_key, false); - $this->assertEquals($params, $payload); - - // test the new restricted algorithms header - $payload = $jwtUtil->decode($encoded, $client_key, array('RS256')); - $this->assertEquals($params, $payload); - } - - public function testInvalidJwt() - { - $jwtUtil = new Jwt(); - - $this->assertFalse($jwtUtil->decode('goob')); - $this->assertFalse($jwtUtil->decode('go.o.b')); - } - - /** @dataProvider provideClientCredentials */ - public function testInvalidJwtHeader($client_id, $client_key) - { - $jwtUtil = new Jwt(); - - $params = array( - 'iss' => $client_id, - 'exp' => time() + 1000, - 'iat' => time(), - 'sub' => 'testuser@ourdomain.com', - 'aud' => 'http://myapp.com/oauth/auth', - 'scope' => null, - ); - - // testing for algorithm tampering when only RSA256 signing is allowed - // @see https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/ - $tampered = $jwtUtil->encode($params, $client_key, 'HS256'); - - $payload = $jwtUtil->decode($tampered, $client_key, array('RS256')); - - $this->assertFalse($payload); - } - - public function provideClientCredentials() - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $client_id = 'Test Client ID'; - $client_key = $storage->getClientKey($client_id, "testuser@ourdomain.com"); - - return array( - array($client_id, $client_key), - ); - } -} diff --git a/library/oauth2/test/OAuth2/GrantType/AuthorizationCodeTest.php b/library/oauth2/test/OAuth2/GrantType/AuthorizationCodeTest.php deleted file mode 100644 index 740989635..000000000 --- a/library/oauth2/test/OAuth2/GrantType/AuthorizationCodeTest.php +++ /dev/null @@ -1,207 +0,0 @@ -<?php - -namespace OAuth2\GrantType; - -use OAuth2\Storage\Bootstrap; -use OAuth2\Server; -use OAuth2\Request\TestRequest; -use OAuth2\Response; - -class AuthorizationCodeTest extends \PHPUnit_Framework_TestCase -{ - public function testNoCode() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'Missing parameter: "code" is required'); - } - - public function testInvalidCode() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'InvalidCode', // invalid authorization code - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'Authorization code doesn\'t exist or is invalid for the client'); - } - - public function testCodeCannotBeUsedTwice() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode', // valid code - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 200); - $this->assertNotNull($response->getParameter('access_token')); - - // try to use the same code again - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'Authorization code doesn\'t exist or is invalid for the client'); - } - - public function testExpiredCode() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode-expired', // expired authorization code - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'The authorization code has expired'); - } - - public function testValidCode() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode', // valid code - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - } - - public function testValidCodeNoScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode-with-scope', // valid code - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertArrayHasKey('scope', $token); - $this->assertEquals($token['scope'], 'scope1 scope2'); - } - - public function testValidCodeSameScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode-with-scope', // valid code - 'scope' => 'scope2 scope1', - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertArrayHasKey('scope', $token); - $this->assertEquals($token['scope'], 'scope2 scope1'); - } - - public function testValidCodeLessScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode-with-scope', // valid code - 'scope' => 'scope1', - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertArrayHasKey('scope', $token); - $this->assertEquals($token['scope'], 'scope1'); - } - - public function testValidCodeDifferentScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode-with-scope', // valid code - 'scope' => 'scope3', - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_scope'); - $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request'); - } - - public function testValidCodeInvalidScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode-with-scope', // valid code - 'scope' => 'invalid-scope', - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_scope'); - $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request'); - } - - public function testValidClientDifferentCode() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Some Other Client', // valid client id - 'client_secret' => 'TestSecret3', // valid client secret - 'code' => 'testcode', // valid code - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'authorization_code doesn\'t exist or is invalid for the client'); - } - - private function getTestServer() - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage); - $server->addGrantType(new AuthorizationCode($storage)); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/GrantType/ClientCredentialsTest.php b/library/oauth2/test/OAuth2/GrantType/ClientCredentialsTest.php deleted file mode 100644 index f0d46ccb3..000000000 --- a/library/oauth2/test/OAuth2/GrantType/ClientCredentialsTest.php +++ /dev/null @@ -1,159 +0,0 @@ -<?php - -namespace OAuth2\GrantType; - -use OAuth2\Storage\Bootstrap; -use OAuth2\Server; -use OAuth2\Request\TestRequest; -use OAuth2\Request; -use OAuth2\Response; - -class ClientCredentialsTest extends \PHPUnit_Framework_TestCase -{ - public function testInvalidCredentials() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'client_credentials', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'FakeSecret', // valid client secret - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_client'); - $this->assertEquals($response->getParameter('error_description'), 'The client credentials are invalid'); - } - - public function testValidCredentials() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'client_credentials', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('scope', $token); - $this->assertNull($token['scope']); - } - - public function testValidCredentialsWithScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'client_credentials', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'scope' => 'scope1', - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertArrayHasKey('scope', $token); - $this->assertEquals($token['scope'], 'scope1'); - } - - public function testValidCredentialsInvalidScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'client_credentials', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'scope' => 'invalid-scope', - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_scope'); - $this->assertEquals($response->getParameter('error_description'), 'An unsupported scope was requested'); - } - - public function testValidCredentialsInHeader() - { - // create with HTTP_AUTHORIZATION in header - $server = $this->getTestServer(); - $headers = array('HTTP_AUTHORIZATION' => 'Basic '.base64_encode('Test Client ID:TestSecret'), 'REQUEST_METHOD' => 'POST'); - $params = array('grant_type' => 'client_credentials'); - $request = new Request(array(), $params, array(), array(), array(), $headers); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertNotNull($token['access_token']); - - // create using PHP Authorization Globals - $headers = array('PHP_AUTH_USER' => 'Test Client ID', 'PHP_AUTH_PW' => 'TestSecret', 'REQUEST_METHOD' => 'POST'); - $params = array('grant_type' => 'client_credentials'); - $request = new Request(array(), $params, array(), array(), array(), $headers); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertNotNull($token['access_token']); - } - - public function testValidCredentialsInRequest() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'client_credentials', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertNotNull($token['access_token']); - } - - public function testValidCredentialsInQuerystring() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'client_credentials', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertNotNull($token['access_token']); - } - - public function testClientUserIdIsSetInAccessToken() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'client_credentials', // valid grant type - 'client_id' => 'Client ID With User ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - - // verify the user_id was associated with the token - $storage = $server->getStorage('client'); - $token = $storage->getAccessToken($token['access_token']); - $this->assertNotNull($token); - $this->assertArrayHasKey('user_id', $token); - $this->assertEquals($token['user_id'], 'brent@brentertainment.com'); - } - - private function getTestServer() - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage); - $server->addGrantType(new ClientCredentials($storage)); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/GrantType/ImplicitTest.php b/library/oauth2/test/OAuth2/GrantType/ImplicitTest.php deleted file mode 100644 index a47aae3e8..000000000 --- a/library/oauth2/test/OAuth2/GrantType/ImplicitTest.php +++ /dev/null @@ -1,143 +0,0 @@ -<?php - -namespace OAuth2\GrantType; - -use OAuth2\Storage\Bootstrap; -use OAuth2\Server; -use OAuth2\Request; -use OAuth2\Response; - -class ImplicitTest extends \PHPUnit_Framework_TestCase -{ - public function testImplicitNotAllowedResponse() - { - $server = $this->getTestServer(); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com', // valid redirect URI - 'response_type' => 'token', // invalid response type - )); - $server->handleAuthorizeRequest($request, $response = new Response(), false); - - $this->assertEquals($response->getStatusCode(), 302); - $location = $response->getHttpHeader('Location'); - $parts = parse_url($location); - parse_str($parts['query'], $query); - - $this->assertEquals($query['error'], 'unsupported_response_type'); - $this->assertEquals($query['error_description'], 'implicit grant type not supported'); - } - - public function testUserDeniesAccessResponse() - { - $server = $this->getTestServer(array('allow_implicit' => true)); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com', // valid redirect URI - 'response_type' => 'token', // valid response type - 'state' => 'xyz', - )); - $server->handleAuthorizeRequest($request, $response = new Response(), false); - - $this->assertEquals($response->getStatusCode(), 302); - $location = $response->getHttpHeader('Location'); - $parts = parse_url($location); - parse_str($parts['query'], $query); - - $this->assertEquals($query['error'], 'access_denied'); - $this->assertEquals($query['error_description'], 'The user denied access to your application'); - } - - public function testSuccessfulRequestFragmentParameter() - { - $server = $this->getTestServer(array('allow_implicit' => true)); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com', // valid redirect URI - 'response_type' => 'token', // valid response type - 'state' => 'xyz', - )); - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 302); - $this->assertNull($response->getParameter('error')); - $this->assertNull($response->getParameter('error_description')); - - $location = $response->getHttpHeader('Location'); - $parts = parse_url($location); - - $this->assertEquals('http', $parts['scheme']); // same as passed in to redirect_uri - $this->assertEquals('adobe.com', $parts['host']); // same as passed in to redirect_uri - $this->assertArrayHasKey('fragment', $parts); - $this->assertFalse(isset($parts['query'])); - - // assert fragment is in "application/x-www-form-urlencoded" format - parse_str($parts['fragment'], $params); - $this->assertNotNull($params); - $this->assertArrayHasKey('access_token', $params); - $this->assertArrayHasKey('expires_in', $params); - $this->assertArrayHasKey('token_type', $params); - } - - public function testSuccessfulRequestReturnsStateParameter() - { - $server = $this->getTestServer(array('allow_implicit' => true)); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com', // valid redirect URI - 'response_type' => 'token', // valid response type - 'state' => 'test', // valid state string (just needs to be passed back to us) - )); - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 302); - $this->assertNull($response->getParameter('error')); - $this->assertNull($response->getParameter('error_description')); - - $location = $response->getHttpHeader('Location'); - $parts = parse_url($location); - $this->assertArrayHasKey('fragment', $parts); - parse_str($parts['fragment'], $params); - - $this->assertArrayHasKey('state', $params); - $this->assertEquals($params['state'], 'test'); - } - - public function testSuccessfulRequestStripsExtraParameters() - { - $server = $this->getTestServer(array('allow_implicit' => true)); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com?fake=something', // valid redirect URI - 'response_type' => 'token', // valid response type - 'state' => 'test', // valid state string (just needs to be passed back to us) - 'fake' => 'something', // add extra param to querystring - )); - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 302); - $this->assertNull($response->getParameter('error')); - $this->assertNull($response->getParameter('error_description')); - - $location = $response->getHttpHeader('Location'); - $parts = parse_url($location); - $this->assertFalse(isset($parts['fake'])); - $this->assertArrayHasKey('fragment', $parts); - parse_str($parts['fragment'], $params); - - $this->assertFalse(isset($params['fake'])); - $this->assertArrayHasKey('state', $params); - $this->assertEquals($params['state'], 'test'); - } - - private function getTestServer($config = array()) - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage, $config); - - // Add the two types supported for authorization grant - $server->addGrantType(new AuthorizationCode($storage)); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/GrantType/JwtBearerTest.php b/library/oauth2/test/OAuth2/GrantType/JwtBearerTest.php deleted file mode 100644 index 0a6c4b827..000000000 --- a/library/oauth2/test/OAuth2/GrantType/JwtBearerTest.php +++ /dev/null @@ -1,360 +0,0 @@ -<?php - -namespace OAuth2\GrantType; - -use OAuth2\Storage\Bootstrap; -use OAuth2\Server; -use OAuth2\Request\TestRequest; -use OAuth2\Response; -use OAuth2\Encryption\Jwt; - -class JwtBearerTest extends \PHPUnit_Framework_TestCase -{ - private $privateKey; - - public function setUp() - { - $this->privateKey = <<<EOD ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQC5/SxVlE8gnpFqCxgl2wjhzY7ucEi00s0kUg3xp7lVEvgLgYcA -nHiWp+gtSjOFfH2zsvpiWm6Lz5f743j/FEzHIO1owR0p4d9pOaJK07d01+RzoQLO -IQAgXrr4T1CCWUesncwwPBVCyy2Mw3Nmhmr9MrF8UlvdRKBxriRnlP3qJQIDAQAB -AoGAVgJJVU4fhYMu1e5JfYAcTGfF+Gf+h3iQm4JCpoUcxMXf5VpB9ztk3K7LRN5y -kwFuFALpnUAarRcUPs0D8FoP4qBluKksbAtgHkO7bMSH9emN+mH4le4qpFlR7+P1 -3fLE2Y19IBwPwEfClC+TpJvuog6xqUYGPlg6XLq/MxQUB4ECQQDgovP1v+ONSeGS -R+NgJTR47noTkQT3M2izlce/OG7a+O0yw6BOZjNXqH2wx3DshqMcPUFrTjibIClP -l/tEQ3ShAkEA0/TdBYDtXpNNjqg0R9GVH2pw7Kh68ne6mZTuj0kCgFYpUF6L6iMm -zXamIJ51rTDsTyKTAZ1JuAhAsK/M2BbDBQJAKQ5fXEkIA+i+64dsDUR/hKLBeRYG -PFAPENONQGvGBwt7/s02XV3cgGbxIgAxqWkqIp0neb9AJUoJgtyaNe3GQQJANoL4 -QQ0af0NVJAZgg8QEHTNL3aGrFSbzx8IE5Lb7PLRsJa5bP5lQxnDoYuU+EI/Phr62 -niisp/b/ZDGidkTMXQJBALeRsH1I+LmICAvWXpLKa9Gv0zGCwkuIJLiUbV9c6CVh -suocCAteQwL5iW2gA4AnYr5OGeHFsEl7NCQcwfPZpJ0= ------END RSA PRIVATE KEY----- -EOD; - } - - public function testMalformedJWT() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - )); - - //Get the jwt and break it - $jwt = $this->getJWT(); - $jwt = substr_replace($jwt, 'broken', 3, 6); - - $request->request['assertion'] = $jwt; - - $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'JWT is malformed'); - } - - public function testBrokenSignature() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - )); - - //Get the jwt and break signature - $jwt = $this->getJWT() . 'notSupposeToBeHere'; - $request->request['assertion'] = $jwt; - - $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'JWT failed signature verification'); - } - - public function testExpiredJWT() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - )); - - //Get an expired JWT - $jwt = $this->getJWT(1234); - $request->request['assertion'] = $jwt; - - $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'JWT has expired'); - } - - public function testBadExp() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - )); - - //Get an expired JWT - $jwt = $this->getJWT('badtimestamp'); - $request->request['assertion'] = $jwt; - - $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'Expiration (exp) time must be a unix time stamp'); - } - - public function testNoAssert() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - )); - - //Do not pass the assert (JWT) - - $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'Missing parameters: "assertion" required'); - } - - public function testNotBefore() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - )); - - //Get a future NBF - $jwt = $this->getJWT(null, time() + 10000); - $request->request['assertion'] = $jwt; - - $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'JWT cannot be used before the Not Before (nbf) time'); - } - - public function testBadNotBefore() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - )); - - //Get a non timestamp nbf - $jwt = $this->getJWT(null, 'notatimestamp'); - $request->request['assertion'] = $jwt; - - $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'Not Before (nbf) time must be a unix time stamp'); - } - - public function testNonMatchingAudience() - { - $server = $this->getTestServer('http://google.com/oauth/o/auth'); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - 'assertion' => $this->getJWT(), - )); - - $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'Invalid audience (aud)'); - } - - public function testBadClientID() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - 'assertion' => $this->getJWT(null, null, null, 'bad_client_id'), - )); - - $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'Invalid issuer (iss) or subject (sub) provided'); - } - - public function testBadSubject() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - 'assertion' => $this->getJWT(null, null, 'anotheruser@ourdomain,com'), - )); - - $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'Invalid issuer (iss) or subject (sub) provided'); - } - - public function testMissingKey() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - 'assertion' => $this->getJWT(null, null, null, 'Missing Key Cli,nt'), - )); - - $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'Invalid issuer (iss) or subject (sub) provided'); - } - - public function testValidJwt() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - 'assertion' => $this->getJWT(), // valid assertion - )); - - $token = $server->grantAccessToken($request, new Response()); - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - } - - public function testValidJwtWithScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - 'assertion' => $this->getJWT(null, null, null, 'Test Client ID'), // valid assertion - 'scope' => 'scope1', // valid scope - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertArrayHasKey('scope', $token); - $this->assertEquals($token['scope'], 'scope1'); - } - - public function testValidJwtInvalidScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - 'assertion' => $this->getJWT(null, null, null, 'Test Client ID'), // valid assertion - 'scope' => 'invalid-scope', // invalid scope - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_scope'); - $this->assertEquals($response->getParameter('error_description'), 'An unsupported scope was requested'); - } - - public function testValidJti() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - 'assertion' => $this->getJWT(null, null, 'testuser@ourdomain.com', 'Test Client ID', 'unused_jti'), // valid assertion with invalid scope - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - } - - public function testInvalidJti() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - 'assertion' => $this->getJWT(99999999900, null, 'testuser@ourdomain.com', 'Test Client ID', 'used_jti'), // valid assertion with invalid scope - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'JSON Token Identifier (jti) has already been used'); - } - - public function testJtiReplayAttack() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // valid grant type - 'assertion' => $this->getJWT(99999999900, null, 'testuser@ourdomain.com', 'Test Client ID', 'totally_new_jti'), // valid assertion with invalid scope - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - - //Replay the same request - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'JSON Token Identifier (jti) has already been used'); - } - - /** - * Generates a JWT - * @param $exp The expiration date. If the current time is greater than the exp, the JWT is invalid. - * @param $nbf The "not before" time. If the current time is less than the nbf, the JWT is invalid. - * @param $sub The subject we are acting on behalf of. This could be the email address of the user in the system. - * @param $iss The issuer, usually the client_id. - * @return string - */ - private function getJWT($exp = null, $nbf = null, $sub = null, $iss = 'Test Client ID', $jti = null) - { - if (!$exp) { - $exp = time() + 1000; - } - - if (!$sub) { - $sub = "testuser@ourdomain.com"; - } - - $params = array( - 'iss' => $iss, - 'exp' => $exp, - 'iat' => time(), - 'sub' => $sub, - 'aud' => 'http://myapp.com/oauth/auth', - ); - - if ($nbf) { - $params['nbf'] = $nbf; - } - - if ($jti) { - $params['jti'] = $jti; - } - - $jwtUtil = new Jwt(); - - return $jwtUtil->encode($params, $this->privateKey, 'RS256'); - } - - private function getTestServer($audience = 'http://myapp.com/oauth/auth') - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage); - $server->addGrantType(new JwtBearer($storage, $audience, new Jwt())); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/GrantType/RefreshTokenTest.php b/library/oauth2/test/OAuth2/GrantType/RefreshTokenTest.php deleted file mode 100644 index a458aad8a..000000000 --- a/library/oauth2/test/OAuth2/GrantType/RefreshTokenTest.php +++ /dev/null @@ -1,204 +0,0 @@ -<?php - -namespace OAuth2\GrantType; - -use OAuth2\Storage\Bootstrap; -use OAuth2\Server; -use OAuth2\Request\TestRequest; -use OAuth2\Response; - -class RefreshTokenTest extends \PHPUnit_Framework_TestCase -{ - private $storage; - - public function testNoRefreshToken() - { - $server = $this->getTestServer(); - $server->addGrantType(new RefreshToken($this->storage)); - - $request = TestRequest::createPost(array( - 'grant_type' => 'refresh_token', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - )); - $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'Missing parameter: "refresh_token" is required'); - } - - public function testInvalidRefreshToken() - { - $server = $this->getTestServer(); - $server->addGrantType(new RefreshToken($this->storage)); - - $request = TestRequest::createPost(array( - 'grant_type' => 'refresh_token', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'refresh_token' => 'fake-token', // invalid refresh token - )); - $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'Invalid refresh token'); - } - - public function testValidRefreshTokenWithNewRefreshTokenInResponse() - { - $server = $this->getTestServer(); - $server->addGrantType(new RefreshToken($this->storage, array('always_issue_new_refresh_token' => true))); - - $request = TestRequest::createPost(array( - 'grant_type' => 'refresh_token', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'refresh_token' => 'test-refreshtoken', // valid refresh token - )); - $token = $server->grantAccessToken($request, new Response()); - $this->assertTrue(isset($token['refresh_token']), 'refresh token should always refresh'); - - $refresh_token = $this->storage->getRefreshToken($token['refresh_token']); - $this->assertNotNull($refresh_token); - $this->assertEquals($refresh_token['refresh_token'], $token['refresh_token']); - $this->assertEquals($refresh_token['client_id'], $request->request('client_id')); - $this->assertTrue($token['refresh_token'] != 'test-refreshtoken', 'the refresh token returned is not the one used'); - $used_token = $this->storage->getRefreshToken('test-refreshtoken'); - $this->assertFalse($used_token, 'the refresh token used is no longer valid'); - } - - public function testValidRefreshTokenDoesNotUnsetToken() - { - $server = $this->getTestServer(); - $server->addGrantType(new RefreshToken($this->storage, array( - 'always_issue_new_refresh_token' => true, - 'unset_refresh_token_after_use' => false, - ))); - - $request = TestRequest::createPost(array( - 'grant_type' => 'refresh_token', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'refresh_token' => 'test-refreshtoken', // valid refresh token - )); - $token = $server->grantAccessToken($request, new Response()); - $this->assertTrue(isset($token['refresh_token']), 'refresh token should always refresh'); - - $used_token = $this->storage->getRefreshToken('test-refreshtoken'); - $this->assertNotNull($used_token, 'the refresh token used is still valid'); - } - - public function testValidRefreshTokenWithNoRefreshTokenInResponse() - { - $server = $this->getTestServer(); - $server->addGrantType(new RefreshToken($this->storage, array('always_issue_new_refresh_token' => false))); - - $request = TestRequest::createPost(array( - 'grant_type' => 'refresh_token', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'refresh_token' => 'test-refreshtoken', // valid refresh token - )); - $token = $server->grantAccessToken($request, new Response()); - $this->assertFalse(isset($token['refresh_token']), 'refresh token should not be returned'); - - $used_token = $this->storage->getRefreshToken('test-refreshtoken'); - $this->assertNotNull($used_token, 'the refresh token used is still valid'); - } - - public function testValidRefreshTokenSameScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'refresh_token', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'refresh_token' => 'test-refreshtoken-with-scope', // valid refresh token (with scope) - 'scope' => 'scope2 scope1', - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertArrayHasKey('scope', $token); - $this->assertEquals($token['scope'], 'scope2 scope1'); - } - - public function testValidRefreshTokenLessScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'refresh_token', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'refresh_token' => 'test-refreshtoken-with-scope', // valid refresh token (with scope) - 'scope' => 'scope1', - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertArrayHasKey('scope', $token); - $this->assertEquals($token['scope'], 'scope1'); - } - - public function testValidRefreshTokenDifferentScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'refresh_token', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'refresh_token' => 'test-refreshtoken-with-scope', // valid refresh token (with scope) - 'scope' => 'scope3', - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_scope'); - $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request'); - } - - public function testValidRefreshTokenInvalidScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'refresh_token', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'refresh_token' => 'test-refreshtoken-with-scope', // valid refresh token (with scope) - 'scope' => 'invalid-scope', - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_scope'); - $this->assertEquals($response->getParameter('error_description'), 'The scope requested is invalid for this request'); - } - - public function testValidClientDifferentRefreshToken() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'refresh_token', // valid grant type - 'client_id' => 'Test Some Other Client', // valid client id - 'client_secret' => 'TestSecret3', // valid client secret - 'refresh_token' => 'test-refreshtoken', // valid refresh token - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'refresh_token doesn\'t exist or is invalid for the client'); - } - - private function getTestServer() - { - $this->storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($this->storage); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/GrantType/UserCredentialsTest.php b/library/oauth2/test/OAuth2/GrantType/UserCredentialsTest.php deleted file mode 100644 index 18943d055..000000000 --- a/library/oauth2/test/OAuth2/GrantType/UserCredentialsTest.php +++ /dev/null @@ -1,172 +0,0 @@ -<?php - -namespace OAuth2\GrantType; - -use OAuth2\Storage\Bootstrap; -use OAuth2\Server; -use OAuth2\Request\TestRequest; -use OAuth2\Response; - -class UserCredentialsTest extends \PHPUnit_Framework_TestCase -{ - public function testNoUsername() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'password', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'password' => 'testpass', // valid password - )); - $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'Missing parameters: "username" and "password" required'); - } - - public function testNoPassword() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'password', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'username' => 'test-username', // valid username - )); - $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'Missing parameters: "username" and "password" required'); - } - - public function testInvalidUsername() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'password', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'username' => 'fake-username', // valid username - 'password' => 'testpass', // valid password - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 401); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'Invalid username and password combination'); - } - - public function testInvalidPassword() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'password', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'username' => 'test-username', // valid username - 'password' => 'fakepass', // invalid password - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 401); - $this->assertEquals($response->getParameter('error'), 'invalid_grant'); - $this->assertEquals($response->getParameter('error_description'), 'Invalid username and password combination'); - } - - public function testValidCredentials() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'password', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'username' => 'test-username', // valid username - 'password' => 'testpass', // valid password - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - } - - public function testValidCredentialsWithScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'password', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'username' => 'test-username', // valid username - 'password' => 'testpass', // valid password - 'scope' => 'scope1', // valid scope - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertArrayHasKey('scope', $token); - $this->assertEquals($token['scope'], 'scope1'); - } - - public function testValidCredentialsInvalidScope() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'password', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'username' => 'test-username', // valid username - 'password' => 'testpass', // valid password - 'scope' => 'invalid-scope', - )); - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_scope'); - $this->assertEquals($response->getParameter('error_description'), 'An unsupported scope was requested'); - } - - public function testNoSecretWithPublicClient() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'password', // valid grant type - 'client_id' => 'Test Client ID Empty Secret', // valid public client - 'username' => 'test-username', // valid username - 'password' => 'testpass', // valid password - )); - - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - } - - public function testNoSecretWithConfidentialClient() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'password', // valid grant type - 'client_id' => 'Test Client ID', // valid public client - 'username' => 'test-username', // valid username - 'password' => 'testpass', // valid password - )); - - $token = $server->grantAccessToken($request, $response = new Response()); - - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_client'); - $this->assertEquals($response->getParameter('error_description'), 'This client is invalid or must authenticate using a client secret'); - } - - private function getTestServer() - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage); - $server->addGrantType(new UserCredentials($storage)); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php b/library/oauth2/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php deleted file mode 100644 index 46de936d8..000000000 --- a/library/oauth2/test/OAuth2/OpenID/Controller/AuthorizeControllerTest.php +++ /dev/null @@ -1,182 +0,0 @@ -<?php - -namespace OAuth2\OpenID\Controller; - -use OAuth2\Storage\Bootstrap; -use OAuth2\Server; -use OAuth2\Request; -use OAuth2\Response; - -class AuthorizeControllerTest extends \PHPUnit_Framework_TestCase -{ - public function testValidateAuthorizeRequest() - { - $server = $this->getTestServer(); - - $response = new Response(); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com', // valid redirect URI - 'response_type' => 'id_token', - 'state' => 'af0ifjsldkj', - 'nonce' => 'n-0S6_WzA2Mj', - )); - - // Test valid id_token request - $server->handleAuthorizeRequest($request, $response, true); - - $parts = parse_url($response->getHttpHeader('Location')); - parse_str($parts['fragment'], $query); - - $this->assertEquals('n-0S6_WzA2Mj', $server->getAuthorizeController()->getNonce()); - $this->assertEquals($query['state'], 'af0ifjsldkj'); - - $this->assertArrayHasKey('id_token', $query); - $this->assertArrayHasKey('state', $query); - $this->assertArrayNotHasKey('access_token', $query); - $this->assertArrayNotHasKey('expires_in', $query); - $this->assertArrayNotHasKey('token_type', $query); - - // Test valid token id_token request - $request->query['response_type'] = 'id_token token'; - $server->handleAuthorizeRequest($request, $response, true); - - $parts = parse_url($response->getHttpHeader('Location')); - parse_str($parts['fragment'], $query); - - $this->assertEquals('n-0S6_WzA2Mj', $server->getAuthorizeController()->getNonce()); - $this->assertEquals($query['state'], 'af0ifjsldkj'); - - $this->assertArrayHasKey('access_token', $query); - $this->assertArrayHasKey('expires_in', $query); - $this->assertArrayHasKey('token_type', $query); - $this->assertArrayHasKey('state', $query); - $this->assertArrayHasKey('id_token', $query); - - // assert that with multiple-valued response types, order does not matter - $request->query['response_type'] = 'token id_token'; - $server->handleAuthorizeRequest($request, $response, true); - - $parts = parse_url($response->getHttpHeader('Location')); - parse_str($parts['fragment'], $query); - - $this->assertEquals('n-0S6_WzA2Mj', $server->getAuthorizeController()->getNonce()); - $this->assertEquals($query['state'], 'af0ifjsldkj'); - - $this->assertArrayHasKey('access_token', $query); - $this->assertArrayHasKey('expires_in', $query); - $this->assertArrayHasKey('token_type', $query); - $this->assertArrayHasKey('state', $query); - $this->assertArrayHasKey('id_token', $query); - - // assert that with multiple-valued response types with extra spaces do not matter - $request->query['response_type'] = ' token id_token '; - $server->handleAuthorizeRequest($request, $response, true); - - $parts = parse_url($response->getHttpHeader('Location')); - parse_str($parts['fragment'], $query); - - $this->assertEquals('n-0S6_WzA2Mj', $server->getAuthorizeController()->getNonce()); - $this->assertEquals($query['state'], 'af0ifjsldkj'); - - $this->assertArrayHasKey('access_token', $query); - $this->assertArrayHasKey('expires_in', $query); - $this->assertArrayHasKey('token_type', $query); - $this->assertArrayHasKey('state', $query); - $this->assertArrayHasKey('id_token', $query); - } - - public function testMissingNonce() - { - $server = $this->getTestServer(); - $authorize = $server->getAuthorizeController(); - - $response = new Response(); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com', // valid redirect URI - 'response_type' => 'id_token', - 'state' => 'xyz', - )); - - // Test missing nonce for 'id_token' response type - $server->handleAuthorizeRequest($request, $response, true); - $params = $response->getParameters(); - - $this->assertEquals($params['error'], 'invalid_nonce'); - $this->assertEquals($params['error_description'], 'This application requires you specify a nonce parameter'); - - // Test missing nonce for 'id_token token' response type - $request->query['response_type'] = 'id_token token'; - $server->handleAuthorizeRequest($request, $response, true); - $params = $response->getParameters(); - - $this->assertEquals($params['error'], 'invalid_nonce'); - $this->assertEquals($params['error_description'], 'This application requires you specify a nonce parameter'); - } - - public function testNotGrantedApplication() - { - $server = $this->getTestServer(); - - $response = new Response(); - $request = new Request(array( - 'client_id' => 'Test Client ID', // valid client id - 'redirect_uri' => 'http://adobe.com', // valid redirect URI - 'response_type' => 'id_token', - 'state' => 'af0ifjsldkj', - 'nonce' => 'n-0S6_WzA2Mj', - )); - - // Test not approved application - $server->handleAuthorizeRequest($request, $response, false); - - $params = $response->getParameters(); - - $this->assertEquals($params['error'], 'consent_required'); - $this->assertEquals($params['error_description'], 'The user denied access to your application'); - - // Test not approved application with prompt parameter - $request->query['prompt'] = 'none'; - $server->handleAuthorizeRequest($request, $response, false); - - $params = $response->getParameters(); - - $this->assertEquals($params['error'], 'login_required'); - $this->assertEquals($params['error_description'], 'The user must log in'); - - // Test not approved application with user_id set - $request->query['prompt'] = 'none'; - $server->handleAuthorizeRequest($request, $response, false, 'some-user-id'); - - $params = $response->getParameters(); - - $this->assertEquals($params['error'], 'interaction_required'); - $this->assertEquals($params['error_description'], 'The user must grant access to your application'); - } - - public function testNeedsIdToken() - { - $server = $this->getTestServer(); - $authorize = $server->getAuthorizeController(); - - $this->assertTrue($authorize->needsIdToken('openid')); - $this->assertTrue($authorize->needsIdToken('openid profile')); - $this->assertFalse($authorize->needsIdToken('')); - $this->assertFalse($authorize->needsIdToken('some-scope')); - } - - private function getTestServer($config = array()) - { - $config += array( - 'use_openid_connect' => true, - 'issuer' => 'phpunit', - 'allow_implicit' => true - ); - - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage, $config); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php b/library/oauth2/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php deleted file mode 100644 index b1b687077..000000000 --- a/library/oauth2/test/OAuth2/OpenID/Controller/UserInfoControllerTest.php +++ /dev/null @@ -1,44 +0,0 @@ -<?php - -namespace OAuth2\OpenID\Controller; - -use OAuth2\Storage\Bootstrap; -use OAuth2\Server; -use OAuth2\Request; -use OAuth2\Response; - -class UserInfoControllerTest extends \PHPUnit_Framework_TestCase -{ - public function testCreateController() - { - $tokenType = new \OAuth2\TokenType\Bearer(); - $storage = new \OAuth2\Storage\Memory(); - $controller = new UserInfoController($tokenType, $storage, $storage); - - $response = new Response(); - $controller->handleUserInfoRequest(new Request(), $response); - $this->assertEquals(401, $response->getStatusCode()); - } - - public function testValidToken() - { - $server = $this->getTestServer(); - $request = Request::createFromGlobals(); - $request->headers['AUTHORIZATION'] = 'Bearer accesstoken-openid-connect'; - $response = new Response(); - - $server->handleUserInfoRequest($request, $response); - $parameters = $response->getParameters(); - $this->assertEquals($parameters['sub'], 'testuser'); - $this->assertEquals($parameters['email'], 'testuser@test.com'); - $this->assertEquals($parameters['email_verified'], true); - } - - private function getTestServer($config = array()) - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage, $config); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/OpenID/GrantType/AuthorizationCodeTest.php b/library/oauth2/test/OAuth2/OpenID/GrantType/AuthorizationCodeTest.php deleted file mode 100644 index 776002d1e..000000000 --- a/library/oauth2/test/OAuth2/OpenID/GrantType/AuthorizationCodeTest.php +++ /dev/null @@ -1,57 +0,0 @@ -<?php - -namespace OAuth2\OpenID\GrantType; - -use OAuth2\Storage\Bootstrap; -use OAuth2\Server; -use OAuth2\Request\TestRequest; -use OAuth2\Response; - -class AuthorizationCodeTest extends \PHPUnit_Framework_TestCase -{ - public function testValidCode() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode-openid', // valid code - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('id_token', $token); - $this->assertEquals('test_id_token', $token['id_token']); - - // this is only true if "offline_access" was requested - $this->assertFalse(isset($token['refresh_token'])); - } - - public function testOfflineAccess() - { - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'code' => 'testcode-openid', // valid code - 'scope' => 'offline_access', // valid code - )); - $token = $server->grantAccessToken($request, new Response()); - - $this->assertNotNull($token); - $this->assertArrayHasKey('id_token', $token); - $this->assertEquals('test_id_token', $token['id_token']); - $this->assertTrue(isset($token['refresh_token'])); - } - - private function getTestServer() - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage, array('use_openid_connect' => true)); - $server->addGrantType(new AuthorizationCode($storage)); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/OpenID/ResponseType/CodeIdTokenTest.php b/library/oauth2/test/OAuth2/OpenID/ResponseType/CodeIdTokenTest.php deleted file mode 100644 index b0311434a..000000000 --- a/library/oauth2/test/OAuth2/OpenID/ResponseType/CodeIdTokenTest.php +++ /dev/null @@ -1,182 +0,0 @@ -<?php - -namespace OAuth2\OpenID\ResponseType; - -use OAuth2\Server; -use OAuth2\Request; -use OAuth2\Response; -use OAuth2\Storage\Bootstrap; -use OAuth2\GrantType\ClientCredentials; - -class CodeIdTokenTest extends \PHPUnit_Framework_TestCase -{ - public function testHandleAuthorizeRequest() - { - // add the test parameters in memory - $server = $this->getTestServer(); - - $request = new Request(array( - 'response_type' => 'code id_token', - 'redirect_uri' => 'http://adobe.com', - 'client_id' => 'Test Client ID', - 'scope' => 'openid', - 'state' => 'test', - 'nonce' => 'test', - )); - - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 302); - $location = $response->getHttpHeader('Location'); - $this->assertNotContains('error', $location); - - $parts = parse_url($location); - $this->assertArrayHasKey('query', $parts); - - // assert fragment is in "application/x-www-form-urlencoded" format - parse_str($parts['query'], $params); - $this->assertNotNull($params); - $this->assertArrayHasKey('id_token', $params); - $this->assertArrayHasKey('code', $params); - - // validate ID Token - $parts = explode('.', $params['id_token']); - foreach ($parts as &$part) { - // Each part is a base64url encoded json string. - $part = str_replace(array('-', '_'), array('+', '/'), $part); - $part = base64_decode($part); - $part = json_decode($part, true); - } - list($header, $claims, $signature) = $parts; - - $this->assertArrayHasKey('iss', $claims); - $this->assertArrayHasKey('sub', $claims); - $this->assertArrayHasKey('aud', $claims); - $this->assertArrayHasKey('iat', $claims); - $this->assertArrayHasKey('exp', $claims); - $this->assertArrayHasKey('auth_time', $claims); - $this->assertArrayHasKey('nonce', $claims); - - // only exists if an access token was granted along with the id_token - $this->assertArrayNotHasKey('at_hash', $claims); - - $this->assertEquals($claims['iss'], 'test'); - $this->assertEquals($claims['aud'], 'Test Client ID'); - $this->assertEquals($claims['nonce'], 'test'); - $duration = $claims['exp'] - $claims['iat']; - $this->assertEquals($duration, 3600); - } - - public function testUserClaimsWithUserId() - { - // add the test parameters in memory - $server = $this->getTestServer(); - - $request = new Request(array( - 'response_type' => 'code id_token', - 'redirect_uri' => 'http://adobe.com', - 'client_id' => 'Test Client ID', - 'scope' => 'openid email', - 'state' => 'test', - 'nonce' => 'test', - )); - - $userId = 'testuser'; - $server->handleAuthorizeRequest($request, $response = new Response(), true, $userId); - - $this->assertEquals($response->getStatusCode(), 302); - $location = $response->getHttpHeader('Location'); - $this->assertNotContains('error', $location); - - $parts = parse_url($location); - $this->assertArrayHasKey('query', $parts); - - // assert fragment is in "application/x-www-form-urlencoded" format - parse_str($parts['query'], $params); - $this->assertNotNull($params); - $this->assertArrayHasKey('id_token', $params); - $this->assertArrayHasKey('code', $params); - - // validate ID Token - $parts = explode('.', $params['id_token']); - foreach ($parts as &$part) { - // Each part is a base64url encoded json string. - $part = str_replace(array('-', '_'), array('+', '/'), $part); - $part = base64_decode($part); - $part = json_decode($part, true); - } - list($header, $claims, $signature) = $parts; - - $this->assertArrayHasKey('email', $claims); - $this->assertArrayHasKey('email_verified', $claims); - $this->assertNotNull($claims['email']); - $this->assertNotNull($claims['email_verified']); - } - - public function testUserClaimsWithoutUserId() - { - // add the test parameters in memory - $server = $this->getTestServer(); - - $request = new Request(array( - 'response_type' => 'code id_token', - 'redirect_uri' => 'http://adobe.com', - 'client_id' => 'Test Client ID', - 'scope' => 'openid email', - 'state' => 'test', - 'nonce' => 'test', - )); - - $userId = null; - $server->handleAuthorizeRequest($request, $response = new Response(), true, $userId); - - $this->assertEquals($response->getStatusCode(), 302); - $location = $response->getHttpHeader('Location'); - $this->assertNotContains('error', $location); - - $parts = parse_url($location); - $this->assertArrayHasKey('query', $parts); - - // assert fragment is in "application/x-www-form-urlencoded" format - parse_str($parts['query'], $params); - $this->assertNotNull($params); - $this->assertArrayHasKey('id_token', $params); - $this->assertArrayHasKey('code', $params); - - // validate ID Token - $parts = explode('.', $params['id_token']); - foreach ($parts as &$part) { - // Each part is a base64url encoded json string. - $part = str_replace(array('-', '_'), array('+', '/'), $part); - $part = base64_decode($part); - $part = json_decode($part, true); - } - list($header, $claims, $signature) = $parts; - - $this->assertArrayNotHasKey('email', $claims); - $this->assertArrayNotHasKey('email_verified', $claims); - } - - private function getTestServer($config = array()) - { - $config += array( - 'use_openid_connect' => true, - 'issuer' => 'test', - 'id_lifetime' => 3600, - 'allow_implicit' => true, - ); - - $memoryStorage = Bootstrap::getInstance()->getMemoryStorage(); - $memoryStorage->supportedScopes[] = 'email'; - $responseTypes = array( - 'code' => $code = new AuthorizationCode($memoryStorage), - 'id_token' => $idToken = new IdToken($memoryStorage, $memoryStorage, $config), - 'code id_token' => new CodeIdToken($code, $idToken), - ); - - $server = new Server($memoryStorage, $config, array(), $responseTypes); - $server->addGrantType(new ClientCredentials($memoryStorage)); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTest.php b/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTest.php deleted file mode 100644 index e772f6be4..000000000 --- a/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTest.php +++ /dev/null @@ -1,184 +0,0 @@ -<?php - -namespace OAuth2\OpenID\ResponseType; - -use OAuth2\Server; -use OAuth2\Request; -use OAuth2\Response; -use OAuth2\Storage\Bootstrap; -use OAuth2\GrantType\ClientCredentials; -use OAuth2\Encryption\Jwt; - -class IdTokenTest extends \PHPUnit_Framework_TestCase -{ - public function testValidateAuthorizeRequest() - { - $query = array( - 'response_type' => 'id_token', - 'redirect_uri' => 'http://adobe.com', - 'client_id' => 'Test Client ID', - 'scope' => 'openid', - 'state' => 'test', - ); - - // attempt to do the request without a nonce. - $server = $this->getTestServer(array('allow_implicit' => true)); - $request = new Request($query); - $valid = $server->validateAuthorizeRequest($request, $response = new Response()); - - // Add a nonce and retry. - $query['nonce'] = 'test'; - $request = new Request($query); - $valid = $server->validateAuthorizeRequest($request, $response = new Response()); - $this->assertTrue($valid); - } - - public function testHandleAuthorizeRequest() - { - // add the test parameters in memory - $server = $this->getTestServer(array('allow_implicit' => true)); - $request = new Request(array( - 'response_type' => 'id_token', - 'redirect_uri' => 'http://adobe.com', - 'client_id' => 'Test Client ID', - 'scope' => 'openid email', - 'state' => 'test', - 'nonce' => 'test', - )); - - $user_id = 'testuser'; - $server->handleAuthorizeRequest($request, $response = new Response(), true, $user_id); - - $this->assertEquals($response->getStatusCode(), 302); - $location = $response->getHttpHeader('Location'); - $this->assertNotContains('error', $location); - - $parts = parse_url($location); - $this->assertArrayHasKey('fragment', $parts); - $this->assertFalse(isset($parts['query'])); - - // assert fragment is in "application/x-www-form-urlencoded" format - parse_str($parts['fragment'], $params); - $this->assertNotNull($params); - $this->assertArrayHasKey('id_token', $params); - $this->assertArrayNotHasKey('access_token', $params); - $this->validateIdToken($params['id_token']); - } - - public function testPassInAuthTime() - { - $server = $this->getTestServer(array('allow_implicit' => true)); - $request = new Request(array( - 'response_type' => 'id_token', - 'redirect_uri' => 'http://adobe.com', - 'client_id' => 'Test Client ID', - 'scope' => 'openid email', - 'state' => 'test', - 'nonce' => 'test', - )); - - // test with a scalar user id - $user_id = 'testuser123'; - $server->handleAuthorizeRequest($request, $response = new Response(), true, $user_id); - - list($header, $payload, $signature) = $this->extractTokenDataFromResponse($response); - - $this->assertTrue(is_array($payload)); - $this->assertArrayHasKey('sub', $payload); - $this->assertEquals($user_id, $payload['sub']); - $this->assertArrayHasKey('auth_time', $payload); - - // test with an array of user info - $userInfo = array( - 'user_id' => 'testuser1234', - 'auth_time' => date('Y-m-d H:i:s', strtotime('20 minutes ago') - )); - - $server->handleAuthorizeRequest($request, $response = new Response(), true, $userInfo); - - list($header, $payload, $signature) = $this->extractTokenDataFromResponse($response); - - $this->assertTrue(is_array($payload)); - $this->assertArrayHasKey('sub', $payload); - $this->assertEquals($userInfo['user_id'], $payload['sub']); - $this->assertArrayHasKey('auth_time', $payload); - $this->assertEquals($userInfo['auth_time'], $payload['auth_time']); - } - - private function extractTokenDataFromResponse(Response $response) - { - $this->assertEquals($response->getStatusCode(), 302); - $location = $response->getHttpHeader('Location'); - $this->assertNotContains('error', $location); - - $parts = parse_url($location); - $this->assertArrayHasKey('fragment', $parts); - $this->assertFalse(isset($parts['query'])); - - parse_str($parts['fragment'], $params); - $this->assertNotNull($params); - $this->assertArrayHasKey('id_token', $params); - $this->assertArrayNotHasKey('access_token', $params); - - list($headb64, $payloadb64, $signature) = explode('.', $params['id_token']); - - $jwt = new Jwt(); - $header = json_decode($jwt->urlSafeB64Decode($headb64), true); - $payload = json_decode($jwt->urlSafeB64Decode($payloadb64), true); - - return array($header, $payload, $signature); - } - - private function validateIdToken($id_token) - { - $parts = explode('.', $id_token); - foreach ($parts as &$part) { - // Each part is a base64url encoded json string. - $part = str_replace(array('-', '_'), array('+', '/'), $part); - $part = base64_decode($part); - $part = json_decode($part, true); - } - list($header, $claims, $signature) = $parts; - - $this->assertArrayHasKey('iss', $claims); - $this->assertArrayHasKey('sub', $claims); - $this->assertArrayHasKey('aud', $claims); - $this->assertArrayHasKey('iat', $claims); - $this->assertArrayHasKey('exp', $claims); - $this->assertArrayHasKey('auth_time', $claims); - $this->assertArrayHasKey('nonce', $claims); - $this->assertArrayHasKey('email', $claims); - $this->assertArrayHasKey('email_verified', $claims); - - $this->assertEquals($claims['iss'], 'test'); - $this->assertEquals($claims['aud'], 'Test Client ID'); - $this->assertEquals($claims['nonce'], 'test'); - $this->assertEquals($claims['email'], 'testuser@test.com'); - $duration = $claims['exp'] - $claims['iat']; - $this->assertEquals($duration, 3600); - } - - private function getTestServer($config = array()) - { - $config += array( - 'use_openid_connect' => true, - 'issuer' => 'test', - 'id_lifetime' => 3600, - ); - - $memoryStorage = Bootstrap::getInstance()->getMemoryStorage(); - $memoryStorage->supportedScopes[] = 'email'; - $storage = array( - 'client' => $memoryStorage, - 'scope' => $memoryStorage, - ); - $responseTypes = array( - 'id_token' => new IdToken($memoryStorage, $memoryStorage, $config), - ); - - $server = new Server($storage, $config, array(), $responseTypes); - $server->addGrantType(new ClientCredentials($memoryStorage)); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTokenTest.php b/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTokenTest.php deleted file mode 100644 index bc564d37b..000000000 --- a/library/oauth2/test/OAuth2/OpenID/ResponseType/IdTokenTokenTest.php +++ /dev/null @@ -1,91 +0,0 @@ -<?php - -namespace OAuth2\OpenID\ResponseType; - -use OAuth2\Server; -use OAuth2\Request; -use OAuth2\Response; -use OAuth2\Storage\Bootstrap; -use OAuth2\GrantType\ClientCredentials; -use OAuth2\ResponseType\AccessToken; - -class IdTokenTokenTest extends \PHPUnit_Framework_TestCase -{ - - public function testHandleAuthorizeRequest() - { - // add the test parameters in memory - $server = $this->getTestServer(array('allow_implicit' => true)); - - $request = new Request(array( - 'response_type' => 'id_token token', - 'redirect_uri' => 'http://adobe.com', - 'client_id' => 'Test Client ID', - 'scope' => 'openid', - 'state' => 'test', - 'nonce' => 'test', - )); - - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - $this->assertEquals($response->getStatusCode(), 302); - $location = $response->getHttpHeader('Location'); - $this->assertNotContains('error', $location); - - $parts = parse_url($location); - $this->assertArrayHasKey('fragment', $parts); - $this->assertFalse(isset($parts['query'])); - - // assert fragment is in "application/x-www-form-urlencoded" format - parse_str($parts['fragment'], $params); - $this->assertNotNull($params); - $this->assertArrayHasKey('id_token', $params); - $this->assertArrayHasKey('access_token', $params); - - // validate ID Token - $parts = explode('.', $params['id_token']); - foreach ($parts as &$part) { - // Each part is a base64url encoded json string. - $part = str_replace(array('-', '_'), array('+', '/'), $part); - $part = base64_decode($part); - $part = json_decode($part, true); - } - list($header, $claims, $signature) = $parts; - - $this->assertArrayHasKey('iss', $claims); - $this->assertArrayHasKey('sub', $claims); - $this->assertArrayHasKey('aud', $claims); - $this->assertArrayHasKey('iat', $claims); - $this->assertArrayHasKey('exp', $claims); - $this->assertArrayHasKey('auth_time', $claims); - $this->assertArrayHasKey('nonce', $claims); - $this->assertArrayHasKey('at_hash', $claims); - - $this->assertEquals($claims['iss'], 'test'); - $this->assertEquals($claims['aud'], 'Test Client ID'); - $this->assertEquals($claims['nonce'], 'test'); - $duration = $claims['exp'] - $claims['iat']; - $this->assertEquals($duration, 3600); - } - - private function getTestServer($config = array()) - { - $config += array( - 'use_openid_connect' => true, - 'issuer' => 'test', - 'id_lifetime' => 3600, - ); - - $memoryStorage = Bootstrap::getInstance()->getMemoryStorage(); - $responseTypes = array( - 'token' => $token = new AccessToken($memoryStorage, $memoryStorage), - 'id_token' => $idToken = new IdToken($memoryStorage, $memoryStorage, $config), - 'id_token token' => new IdTokenToken($token, $idToken), - ); - - $server = new Server($memoryStorage, $config, array(), $responseTypes); - $server->addGrantType(new ClientCredentials($memoryStorage)); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/OpenID/Storage/AuthorizationCodeTest.php b/library/oauth2/test/OAuth2/OpenID/Storage/AuthorizationCodeTest.php deleted file mode 100644 index bdfb085e3..000000000 --- a/library/oauth2/test/OAuth2/OpenID/Storage/AuthorizationCodeTest.php +++ /dev/null @@ -1,95 +0,0 @@ -<?php - -namespace OAuth2\OpenID\Storage; - -use OAuth2\Storage\BaseTest; -use OAuth2\Storage\NullStorage; - -class AuthorizationCodeTest extends BaseTest -{ - /** @dataProvider provideStorage */ - public function testCreateAuthorizationCode($storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - if (!$storage instanceof AuthorizationCodeInterface) { - return; - } - - // assert code we are about to add does not exist - $code = $storage->getAuthorizationCode('new-openid-code'); - $this->assertFalse($code); - - // add new code - $expires = time() + 20; - $scope = null; - $id_token = 'fake_id_token'; - $success = $storage->setAuthorizationCode('new-openid-code', 'client ID', 'SOMEUSERID', 'http://example.com', $expires, $scope, $id_token); - $this->assertTrue($success); - - $code = $storage->getAuthorizationCode('new-openid-code'); - $this->assertNotNull($code); - $this->assertArrayHasKey('authorization_code', $code); - $this->assertArrayHasKey('client_id', $code); - $this->assertArrayHasKey('user_id', $code); - $this->assertArrayHasKey('redirect_uri', $code); - $this->assertArrayHasKey('expires', $code); - $this->assertEquals($code['authorization_code'], 'new-openid-code'); - $this->assertEquals($code['client_id'], 'client ID'); - $this->assertEquals($code['user_id'], 'SOMEUSERID'); - $this->assertEquals($code['redirect_uri'], 'http://example.com'); - $this->assertEquals($code['expires'], $expires); - $this->assertEquals($code['id_token'], $id_token); - - // change existing code - $expires = time() + 42; - $new_id_token = 'fake_id_token-2'; - $success = $storage->setAuthorizationCode('new-openid-code', 'client ID2', 'SOMEOTHERID', 'http://example.org', $expires, $scope, $new_id_token); - $this->assertTrue($success); - - $code = $storage->getAuthorizationCode('new-openid-code'); - $this->assertNotNull($code); - $this->assertArrayHasKey('authorization_code', $code); - $this->assertArrayHasKey('client_id', $code); - $this->assertArrayHasKey('user_id', $code); - $this->assertArrayHasKey('redirect_uri', $code); - $this->assertArrayHasKey('expires', $code); - $this->assertEquals($code['authorization_code'], 'new-openid-code'); - $this->assertEquals($code['client_id'], 'client ID2'); - $this->assertEquals($code['user_id'], 'SOMEOTHERID'); - $this->assertEquals($code['redirect_uri'], 'http://example.org'); - $this->assertEquals($code['expires'], $expires); - $this->assertEquals($code['id_token'], $new_id_token); - } - - /** @dataProvider provideStorage */ - public function testRemoveIdTokenFromAuthorizationCode($storage) - { - // add new code - $expires = time() + 20; - $scope = null; - $id_token = 'fake_id_token_to_remove'; - $authcode = 'new-openid-code-'.rand(); - $success = $storage->setAuthorizationCode($authcode, 'client ID', 'SOMEUSERID', 'http://example.com', $expires, $scope, $id_token); - $this->assertTrue($success); - - // verify params were set - $code = $storage->getAuthorizationCode($authcode); - $this->assertNotNull($code); - $this->assertArrayHasKey('id_token', $code); - $this->assertEquals($code['id_token'], $id_token); - - // remove the id_token - $success = $storage->setAuthorizationCode($authcode, 'client ID', 'SOMEUSERID', 'http://example.com', $expires, $scope, null); - - // verify the "id_token" is now null - $code = $storage->getAuthorizationCode($authcode); - $this->assertNotNull($code); - $this->assertArrayHasKey('id_token', $code); - $this->assertEquals($code['id_token'], null); - } -} diff --git a/library/oauth2/test/OAuth2/OpenID/Storage/UserClaimsTest.php b/library/oauth2/test/OAuth2/OpenID/Storage/UserClaimsTest.php deleted file mode 100644 index 840f6c566..000000000 --- a/library/oauth2/test/OAuth2/OpenID/Storage/UserClaimsTest.php +++ /dev/null @@ -1,41 +0,0 @@ -<?php - -namespace OAuth2\OpenID\Storage; - -use OAuth2\Storage\BaseTest; -use OAuth2\Storage\NullStorage; - -class UserClaimsTest extends BaseTest -{ - /** @dataProvider provideStorage */ - public function testGetUserClaims($storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - if (!$storage instanceof UserClaimsInterface) { - // incompatible storage - return; - } - - // invalid user - $claims = $storage->getUserClaims('fake-user', ''); - $this->assertFalse($claims); - - // valid user (no scope) - $claims = $storage->getUserClaims('testuser', ''); - - /* assert the decoded token is the same */ - $this->assertFalse(isset($claims['email'])); - - // valid user - $claims = $storage->getUserClaims('testuser', 'email'); - - /* assert the decoded token is the same */ - $this->assertEquals($claims['email'], "testuser@test.com"); - $this->assertEquals($claims['email_verified'], true); - } -} diff --git a/library/oauth2/test/OAuth2/RequestTest.php b/library/oauth2/test/OAuth2/RequestTest.php deleted file mode 100644 index 10db3215c..000000000 --- a/library/oauth2/test/OAuth2/RequestTest.php +++ /dev/null @@ -1,98 +0,0 @@ -<?php - -namespace OAuth2; - -use OAuth2\Request\TestRequest; -use OAuth2\Storage\Bootstrap; -use OAuth2\GrantType\AuthorizationCode; - -class RequestTest extends \PHPUnit_Framework_TestCase -{ - public function testRequestOverride() - { - $request = new TestRequest(); - $server = $this->getTestServer(); - - // Smoke test for override request class - // $server->handleTokenRequest($request, $response = new Response()); - // $this->assertInstanceOf('Response', $response); - // $server->handleAuthorizeRequest($request, $response = new Response(), true); - // $this->assertInstanceOf('Response', $response); - // $response = $server->verifyResourceRequest($request, $response = new Response()); - // $this->assertTrue(is_bool($response)); - - /*** make some valid requests ***/ - - // Valid Token Request - $request->setPost(array( - 'grant_type' => 'authorization_code', - 'client_id' => 'Test Client ID', - 'client_secret' => 'TestSecret', - 'code' => 'testcode', - )); - $server->handleTokenRequest($request, $response = new Response()); - $this->assertEquals($response->getStatusCode(), 200); - $this->assertNull($response->getParameter('error')); - $this->assertNotNUll($response->getParameter('access_token')); - } - - public function testHeadersReturnsValueByKey() - { - $request = new Request( - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array('AUTHORIZATION' => 'Basic secret') - ); - - $this->assertEquals('Basic secret', $request->headers('AUTHORIZATION')); - } - - public function testHeadersReturnsDefaultIfHeaderNotPresent() - { - $request = new Request(); - - $this->assertEquals('Bearer', $request->headers('AUTHORIZATION', 'Bearer')); - } - - public function testHeadersIsCaseInsensitive() - { - $request = new Request( - array(), - array(), - array(), - array(), - array(), - array(), - array(), - array('AUTHORIZATION' => 'Basic secret') - ); - - $this->assertEquals('Basic secret', $request->headers('Authorization')); - } - - public function testRequestReturnsPostParamIfNoQueryParamAvailable() - { - $request = new Request( - array(), - array('client_id' => 'correct') - ); - - $this->assertEquals('correct', $request->query('client_id', $request->request('client_id'))); - } - - private function getTestServer($config = array()) - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage, $config); - - // Add the two types supported for authorization grant - $server->addGrantType(new AuthorizationCode($storage)); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/ResponseTest.php b/library/oauth2/test/OAuth2/ResponseTest.php deleted file mode 100644 index b8149005d..000000000 --- a/library/oauth2/test/OAuth2/ResponseTest.php +++ /dev/null @@ -1,17 +0,0 @@ -<?php - -namespace OAuth2; - -class ResponseTest extends \PHPUnit_Framework_TestCase -{ - public function testRenderAsXml() - { - $response = new Response(array( - 'foo' => 'bar', - 'halland' => 'oates', - )); - - $string = $response->getResponseBody('xml'); - $this->assertContains('<response><foo>bar</foo><halland>oates</halland></response>', $string); - } -} diff --git a/library/oauth2/test/OAuth2/ResponseType/AccessTokenTest.php b/library/oauth2/test/OAuth2/ResponseType/AccessTokenTest.php deleted file mode 100644 index 0ed1c82fc..000000000 --- a/library/oauth2/test/OAuth2/ResponseType/AccessTokenTest.php +++ /dev/null @@ -1,107 +0,0 @@ -<?php - -namespace OAuth2\ResponseType; - -use OAuth2\Server; -use OAuth2\Storage\Memory; - -class AccessTokenTest extends \PHPUnit_Framework_TestCase -{ - public function testRevokeAccessTokenWithTypeHint() - { - $tokenStorage = new Memory(array( - 'access_tokens' => array( - 'revoke' => array('mytoken'), - ), - )); - - $this->assertEquals(array('mytoken'), $tokenStorage->getAccessToken('revoke')); - $accessToken = new AccessToken($tokenStorage); - $accessToken->revokeToken('revoke', 'access_token'); - $this->assertFalse($tokenStorage->getAccessToken('revoke')); - } - - public function testRevokeAccessTokenWithoutTypeHint() - { - $tokenStorage = new Memory(array( - 'access_tokens' => array( - 'revoke' => array('mytoken'), - ), - )); - - $this->assertEquals(array('mytoken'), $tokenStorage->getAccessToken('revoke')); - $accessToken = new AccessToken($tokenStorage); - $accessToken->revokeToken('revoke'); - $this->assertFalse($tokenStorage->getAccessToken('revoke')); - } - - public function testRevokeRefreshTokenWithTypeHint() - { - $tokenStorage = new Memory(array( - 'refresh_tokens' => array( - 'revoke' => array('mytoken'), - ), - )); - - $this->assertEquals(array('mytoken'), $tokenStorage->getRefreshToken('revoke')); - $accessToken = new AccessToken(new Memory, $tokenStorage); - $accessToken->revokeToken('revoke', 'refresh_token'); - $this->assertFalse($tokenStorage->getRefreshToken('revoke')); - } - - public function testRevokeRefreshTokenWithoutTypeHint() - { - $tokenStorage = new Memory(array( - 'refresh_tokens' => array( - 'revoke' => array('mytoken'), - ), - )); - - $this->assertEquals(array('mytoken'), $tokenStorage->getRefreshToken('revoke')); - $accessToken = new AccessToken(new Memory, $tokenStorage); - $accessToken->revokeToken('revoke'); - $this->assertFalse($tokenStorage->getRefreshToken('revoke')); - } - - public function testRevokeAccessTokenWithRefreshTokenTypeHint() - { - $tokenStorage = new Memory(array( - 'access_tokens' => array( - 'revoke' => array('mytoken'), - ), - )); - - $this->assertEquals(array('mytoken'), $tokenStorage->getAccessToken('revoke')); - $accessToken = new AccessToken($tokenStorage); - $accessToken->revokeToken('revoke', 'refresh_token'); - $this->assertFalse($tokenStorage->getAccessToken('revoke')); - } - - public function testRevokeAccessTokenWithBogusTypeHint() - { - $tokenStorage = new Memory(array( - 'access_tokens' => array( - 'revoke' => array('mytoken'), - ), - )); - - $this->assertEquals(array('mytoken'), $tokenStorage->getAccessToken('revoke')); - $accessToken = new AccessToken($tokenStorage); - $accessToken->revokeToken('revoke', 'foo'); - $this->assertFalse($tokenStorage->getAccessToken('revoke')); - } - - public function testRevokeRefreshTokenWithBogusTypeHint() - { - $tokenStorage = new Memory(array( - 'refresh_tokens' => array( - 'revoke' => array('mytoken'), - ), - )); - - $this->assertEquals(array('mytoken'), $tokenStorage->getRefreshToken('revoke')); - $accessToken = new AccessToken(new Memory, $tokenStorage); - $accessToken->revokeToken('revoke', 'foo'); - $this->assertFalse($tokenStorage->getRefreshToken('revoke')); - } -} diff --git a/library/oauth2/test/OAuth2/ResponseType/JwtAccessTokenTest.php b/library/oauth2/test/OAuth2/ResponseType/JwtAccessTokenTest.php deleted file mode 100644 index 51b01a927..000000000 --- a/library/oauth2/test/OAuth2/ResponseType/JwtAccessTokenTest.php +++ /dev/null @@ -1,160 +0,0 @@ -<?php - -namespace OAuth2\ResponseType; - -use OAuth2\Server; -use OAuth2\Response; -use OAuth2\Request\TestRequest; -use OAuth2\Storage\Bootstrap; -use OAuth2\Storage\JwtAccessToken as JwtAccessTokenStorage; -use OAuth2\GrantType\ClientCredentials; -use OAuth2\GrantType\UserCredentials; -use OAuth2\GrantType\RefreshToken; -use OAuth2\Encryption\Jwt; - -class JwtAccessTokenTest extends \PHPUnit_Framework_TestCase -{ - public function testCreateAccessToken() - { - $server = $this->getTestServer(); - $jwtResponseType = $server->getResponseType('token'); - - $accessToken = $jwtResponseType->createAccessToken('Test Client ID', 123, 'test', false); - $jwt = new Jwt; - $decodedAccessToken = $jwt->decode($accessToken['access_token'], null, false); - - $this->assertArrayHasKey('id', $decodedAccessToken); - $this->assertArrayHasKey('jti', $decodedAccessToken); - $this->assertArrayHasKey('iss', $decodedAccessToken); - $this->assertArrayHasKey('aud', $decodedAccessToken); - $this->assertArrayHasKey('exp', $decodedAccessToken); - $this->assertArrayHasKey('iat', $decodedAccessToken); - $this->assertArrayHasKey('token_type', $decodedAccessToken); - $this->assertArrayHasKey('scope', $decodedAccessToken); - - $this->assertEquals('https://api.example.com', $decodedAccessToken['iss']); - $this->assertEquals('Test Client ID', $decodedAccessToken['aud']); - $this->assertEquals(123, $decodedAccessToken['sub']); - $delta = $decodedAccessToken['exp'] - $decodedAccessToken['iat']; - $this->assertEquals(3600, $delta); - $this->assertEquals($decodedAccessToken['id'], $decodedAccessToken['jti']); - } - - public function testGrantJwtAccessToken() - { - // add the test parameters in memory - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'client_credentials', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - )); - $server->handleTokenRequest($request, $response = new Response()); - - $this->assertNotNull($response->getParameter('access_token')); - $this->assertEquals(2, substr_count($response->getParameter('access_token'), '.')); - } - - public function testAccessResourceWithJwtAccessToken() - { - // add the test parameters in memory - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'client_credentials', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - )); - $server->handleTokenRequest($request, $response = new Response()); - $this->assertNotNull($JwtAccessToken = $response->getParameter('access_token')); - - // make a call to the resource server using the crypto token - $request = TestRequest::createPost(array( - 'access_token' => $JwtAccessToken, - )); - - $this->assertTrue($server->verifyResourceRequest($request)); - } - - public function testAccessResourceWithJwtAccessTokenUsingSecondaryStorage() - { - // add the test parameters in memory - $server = $this->getTestServer(); - $request = TestRequest::createPost(array( - 'grant_type' => 'client_credentials', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - )); - $server->handleTokenRequest($request, $response = new Response()); - $this->assertNotNull($JwtAccessToken = $response->getParameter('access_token')); - - // make a call to the resource server using the crypto token - $request = TestRequest::createPost(array( - 'access_token' => $JwtAccessToken, - )); - - // create a resource server with the "memory" storage from the grant server - $resourceServer = new Server($server->getStorage('client_credentials')); - - $this->assertTrue($resourceServer->verifyResourceRequest($request)); - } - - public function testJwtAccessTokenWithRefreshToken() - { - $server = $this->getTestServer(); - - // add "UserCredentials" grant type and "JwtAccessToken" response type - // and ensure "JwtAccessToken" response type has "RefreshToken" storage - $memoryStorage = Bootstrap::getInstance()->getMemoryStorage(); - $server->addGrantType(new UserCredentials($memoryStorage)); - $server->addGrantType(new RefreshToken($memoryStorage)); - $server->addResponseType(new JwtAccessToken($memoryStorage, $memoryStorage, $memoryStorage), 'token'); - - $request = TestRequest::createPost(array( - 'grant_type' => 'password', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'username' => 'test-username', // valid username - 'password' => 'testpass', // valid password - )); - - // make the call to grant a crypto token - $server->handleTokenRequest($request, $response = new Response()); - $this->assertNotNull($JwtAccessToken = $response->getParameter('access_token')); - $this->assertNotNull($refreshToken = $response->getParameter('refresh_token')); - - // decode token and make sure refresh_token isn't set - list($header, $payload, $signature) = explode('.', $JwtAccessToken); - $decodedToken = json_decode(base64_decode($payload), true); - $this->assertFalse(array_key_exists('refresh_token', $decodedToken)); - - // use the refresh token to get another access token - $request = TestRequest::createPost(array( - 'grant_type' => 'refresh_token', - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'refresh_token' => $refreshToken, - )); - - $server->handleTokenRequest($request, $response = new Response()); - $this->assertNotNull($response->getParameter('access_token')); - } - - private function getTestServer() - { - $memoryStorage = Bootstrap::getInstance()->getMemoryStorage(); - - $storage = array( - 'access_token' => new JwtAccessTokenStorage($memoryStorage), - 'client' => $memoryStorage, - 'client_credentials' => $memoryStorage, - ); - $server = new Server($storage); - $server->addGrantType(new ClientCredentials($memoryStorage)); - - // make the "token" response type a JwtAccessToken - $config = array('issuer' => 'https://api.example.com'); - $server->addResponseType(new JwtAccessToken($memoryStorage, $memoryStorage, null, $config)); - - return $server; - } -} diff --git a/library/oauth2/test/OAuth2/ScopeTest.php b/library/oauth2/test/OAuth2/ScopeTest.php deleted file mode 100644 index 99f9cf6eb..000000000 --- a/library/oauth2/test/OAuth2/ScopeTest.php +++ /dev/null @@ -1,42 +0,0 @@ -<?php - -namespace OAuth2; - -use OAuth2\Storage\Memory; - -class ScopeTest extends \PHPUnit_Framework_TestCase -{ - public function testCheckScope() - { - $scopeUtil = new Scope(); - - $this->assertFalse($scopeUtil->checkScope('invalid', 'list of scopes')); - $this->assertTrue($scopeUtil->checkScope('valid', 'valid and-some other-scopes')); - $this->assertTrue($scopeUtil->checkScope('valid another-valid', 'valid another-valid and-some other-scopes')); - // all scopes must match - $this->assertFalse($scopeUtil->checkScope('valid invalid', 'valid and-some other-scopes')); - $this->assertFalse($scopeUtil->checkScope('valid valid2 invalid', 'valid valid2 and-some other-scopes')); - } - - public function testScopeStorage() - { - $scopeUtil = new Scope(); - $this->assertEquals($scopeUtil->getDefaultScope(), null); - - $scopeUtil = new Scope(array( - 'default_scope' => 'default', - 'supported_scopes' => array('this', 'that', 'another'), - )); - $this->assertEquals($scopeUtil->getDefaultScope(), 'default'); - $this->assertTrue($scopeUtil->scopeExists('this that another', 'client_id')); - - $memoryStorage = new Memory(array( - 'default_scope' => 'base', - 'supported_scopes' => array('only-this-one'), - )); - $scopeUtil = new Scope($memoryStorage); - - $this->assertEquals($scopeUtil->getDefaultScope(), 'base'); - $this->assertTrue($scopeUtil->scopeExists('only-this-one', 'client_id')); - } -} diff --git a/library/oauth2/test/OAuth2/ServerTest.php b/library/oauth2/test/OAuth2/ServerTest.php deleted file mode 100644 index 747e120f5..000000000 --- a/library/oauth2/test/OAuth2/ServerTest.php +++ /dev/null @@ -1,684 +0,0 @@ -<?php - -namespace OAuth2; - -use OAuth2\Request\TestRequest; -use OAuth2\ResponseType\AuthorizationCode; -use OAuth2\Storage\Bootstrap; - -class ServerTest extends \PHPUnit_Framework_TestCase -{ - /** - * @expectedException LogicException OAuth2\Storage\ClientInterface - **/ - public function testGetAuthorizeControllerWithNoClientStorageThrowsException() - { - // must set Client Storage - $server = new Server(); - $server->getAuthorizeController(); - } - - /** - * @expectedException LogicException OAuth2\Storage\AccessTokenInterface - **/ - public function testGetAuthorizeControllerWithNoAccessTokenStorageThrowsException() - { - // must set AccessToken or AuthorizationCode - $server = new Server(); - $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface')); - $server->getAuthorizeController(); - } - - public function testGetAuthorizeControllerWithClientStorageAndAccessTokenResponseType() - { - // must set AccessToken or AuthorizationCode - $server = new Server(); - $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface')); - $server->addResponseType($this->getMock('OAuth2\ResponseType\AccessTokenInterface')); - - $this->assertNotNull($server->getAuthorizeController()); - } - - public function testGetAuthorizeControllerWithClientStorageAndAuthorizationCodeResponseType() - { - // must set AccessToken or AuthorizationCode - $server = new Server(); - $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface')); - $server->addResponseType($this->getMock('OAuth2\ResponseType\AuthorizationCodeInterface')); - - $this->assertNotNull($server->getAuthorizeController()); - } - - /** - * @expectedException LogicException allow_implicit - **/ - public function testGetAuthorizeControllerWithClientStorageAndAccessTokenStorageThrowsException() - { - // must set AuthorizationCode or AccessToken / implicit - $server = new Server(); - $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface')); - $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface')); - - $this->assertNotNull($server->getAuthorizeController()); - } - - public function testGetAuthorizeControllerWithClientStorageAndAccessTokenStorage() - { - // must set AuthorizationCode or AccessToken / implicit - $server = new Server(array(), array('allow_implicit' => true)); - $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface')); - $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface')); - - $this->assertNotNull($server->getAuthorizeController()); - } - - public function testGetAuthorizeControllerWithClientStorageAndAuthorizationCodeStorage() - { - // must set AccessToken or AuthorizationCode - $server = new Server(); - $server->addStorage($this->getMock('OAuth2\Storage\ClientInterface')); - $server->addStorage($this->getMock('OAuth2\Storage\AuthorizationCodeInterface')); - - $this->assertNotNull($server->getAuthorizeController()); - } - - /** - * @expectedException LogicException grant_types - **/ - public function testGetTokenControllerWithGrantTypeStorageThrowsException() - { - $server = new Server(); - $server->getTokenController(); - } - - /** - * @expectedException LogicException OAuth2\Storage\ClientCredentialsInterface - **/ - public function testGetTokenControllerWithNoClientCredentialsStorageThrowsException() - { - $server = new Server(); - $server->addStorage($this->getMock('OAuth2\Storage\UserCredentialsInterface')); - $server->getTokenController(); - } - - /** - * @expectedException LogicException OAuth2\Storage\AccessTokenInterface - **/ - public function testGetTokenControllerWithNoAccessTokenStorageThrowsException() - { - $server = new Server(); - $server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface')); - $server->getTokenController(); - } - - public function testGetTokenControllerWithAccessTokenAndClientCredentialsStorage() - { - $server = new Server(); - $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface')); - $server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface')); - $server->getTokenController(); - } - - public function testGetTokenControllerAccessTokenStorageAndClientCredentialsStorageAndGrantTypes() - { - $server = new Server(); - $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface')); - $server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface')); - $server->addGrantType($this->getMockBuilder('OAuth2\GrantType\AuthorizationCode')->disableOriginalConstructor()->getMock()); - $server->getTokenController(); - } - - /** - * @expectedException LogicException OAuth2\Storage\AccessTokenInterface - **/ - public function testGetResourceControllerWithNoAccessTokenStorageThrowsException() - { - $server = new Server(); - $server->getResourceController(); - } - - public function testGetResourceControllerWithAccessTokenStorage() - { - $server = new Server(); - $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface')); - $server->getResourceController(); - } - - /** - * @expectedException InvalidArgumentException OAuth2\Storage\AccessTokenInterface - **/ - public function testAddingStorageWithInvalidClass() - { - $server = new Server(); - $server->addStorage(new \StdClass()); - } - - /** - * @expectedException InvalidArgumentException access_token - **/ - public function testAddingStorageWithInvalidKey() - { - $server = new Server(); - $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'), 'nonexistant_storage'); - } - - /** - * @expectedException InvalidArgumentException OAuth2\Storage\AuthorizationCodeInterface - **/ - public function testAddingStorageWithInvalidKeyStorageCombination() - { - $server = new Server(); - $server->addStorage($this->getMock('OAuth2\Storage\AccessTokenInterface'), 'authorization_code'); - } - - public function testAddingStorageWithValidKeyOnlySetsThatKey() - { - $server = new Server(); - $server->addStorage($this->getMock('OAuth2\Storage\Memory'), 'access_token'); - - $reflection = new \ReflectionClass($server); - $prop = $reflection->getProperty('storages'); - $prop->setAccessible(true); - - $storages = $prop->getValue($server); // get the private "storages" property - - $this->assertEquals(1, count($storages)); - $this->assertTrue(isset($storages['access_token'])); - $this->assertFalse(isset($storages['authorization_code'])); - } - - public function testAddingClientStorageSetsClientCredentialsStorageByDefault() - { - $server = new Server(); - $memory = $this->getMock('OAuth2\Storage\Memory'); - $server->addStorage($memory, 'client'); - - $client_credentials = $server->getStorage('client_credentials'); - - $this->assertNotNull($client_credentials); - $this->assertEquals($client_credentials, $memory); - } - - public function testAddStorageWithNullValue() - { - $memory = $this->getMock('OAuth2\Storage\Memory'); - $server = new Server($memory); - $server->addStorage(null, 'refresh_token'); - - $client_credentials = $server->getStorage('client_credentials'); - - $this->assertNotNull($client_credentials); - $this->assertEquals($client_credentials, $memory); - - $refresh_token = $server->getStorage('refresh_token'); - - $this->assertNull($refresh_token); - } - - public function testNewServerWithNullStorageValue() - { - $memory = $this->getMock('OAuth2\Storage\Memory'); - $server = new Server(array( - 'client_credentials' => $memory, - 'refresh_token' => null, - )); - - $client_credentials = $server->getStorage('client_credentials'); - - $this->assertNotNull($client_credentials); - $this->assertEquals($client_credentials, $memory); - - $refresh_token = $server->getStorage('refresh_token'); - - $this->assertNull($refresh_token); - } - - public function testAddingClientCredentialsStorageSetsClientStorageByDefault() - { - $server = new Server(); - $memory = $this->getMock('OAuth2\Storage\Memory'); - $server->addStorage($memory, 'client_credentials'); - - $client = $server->getStorage('client'); - - $this->assertNotNull($client); - $this->assertEquals($client, $memory); - } - - public function testSettingClientStorageByDefaultDoesNotOverrideSetStorage() - { - $server = new Server(); - $pdo = $this->getMockBuilder('OAuth2\Storage\Pdo') - ->disableOriginalConstructor()->getMock(); - - $memory = $this->getMock('OAuth2\Storage\Memory'); - - $server->addStorage($pdo, 'client'); - $server->addStorage($memory, 'client_credentials'); - - $client = $server->getStorage('client'); - $client_credentials = $server->getStorage('client_credentials'); - - $this->assertEquals($client, $pdo); - $this->assertEquals($client_credentials, $memory); - } - - public function testAddingResponseType() - { - $storage = $this->getMock('OAuth2\Storage\Memory'); - $storage - ->expects($this->any()) - ->method('getClientDetails') - ->will($this->returnValue(array('client_id' => 'some_client'))); - $storage - ->expects($this->any()) - ->method('checkRestrictedGrantType') - ->will($this->returnValue(true)); - - // add with the "code" key explicitly set - $codeType = new AuthorizationCode($storage); - $server = new Server(); - $server->addStorage($storage); - $server->addResponseType($codeType); - $request = new Request(array( - 'response_type' => 'code', - 'client_id' => 'some_client', - 'redirect_uri' => 'http://example.com', - 'state' => 'xyx', - )); - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - // the response is successful - $this->assertEquals($response->getStatusCode(), 302); - $parts = parse_url($response->getHttpHeader('Location')); - parse_str($parts['query'], $query); - $this->assertTrue(isset($query['code'])); - $this->assertFalse(isset($query['error'])); - - // add with the "code" key not set - $codeType = new AuthorizationCode($storage); - $server = new Server(array($storage), array(), array(), array($codeType)); - $request = new Request(array( - 'response_type' => 'code', - 'client_id' => 'some_client', - 'redirect_uri' => 'http://example.com', - 'state' => 'xyx', - )); - $server->handleAuthorizeRequest($request, $response = new Response(), true); - - // the response is successful - $this->assertEquals($response->getStatusCode(), 302); - $parts = parse_url($response->getHttpHeader('Location')); - parse_str($parts['query'], $query); - $this->assertTrue(isset($query['code'])); - $this->assertFalse(isset($query['error'])); - } - - public function testCustomClientAssertionType() - { - $request = TestRequest::createPost(array( - 'grant_type' => 'authorization_code', - 'client_id' =>'Test Client ID', - 'code' => 'testcode', - )); - // verify the mock clientAssertionType was called as expected - $clientAssertionType = $this->getMock('OAuth2\ClientAssertionType\ClientAssertionTypeInterface', array('validateRequest', 'getClientId')); - $clientAssertionType - ->expects($this->once()) - ->method('validateRequest') - ->will($this->returnValue(true)); - $clientAssertionType - ->expects($this->once()) - ->method('getClientId') - ->will($this->returnValue('Test Client ID')); - - // create mock storage - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server(array($storage), array(), array(), array(), null, null, $clientAssertionType); - $server->handleTokenRequest($request, $response = new Response()); - } - - public function testHttpBasicConfig() - { - // create mock storage - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server(array($storage), array( - 'allow_credentials_in_request_body' => false, - 'allow_public_clients' => false - )); - $server->getTokenController(); - $httpBasic = $server->getClientAssertionType(); - - $reflection = new \ReflectionClass($httpBasic); - $prop = $reflection->getProperty('config'); - $prop->setAccessible(true); - - $config = $prop->getValue($httpBasic); // get the private "config" property - - $this->assertEquals($config['allow_credentials_in_request_body'], false); - $this->assertEquals($config['allow_public_clients'], false); - } - - public function testRefreshTokenConfig() - { - // create mock storage - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server1 = new Server(array($storage)); - $server2 = new Server(array($storage), array('always_issue_new_refresh_token' => true, 'unset_refresh_token_after_use' => false)); - - $server1->getTokenController(); - $refreshToken1 = $server1->getGrantType('refresh_token'); - - $server2->getTokenController(); - $refreshToken2 = $server2->getGrantType('refresh_token'); - - $reflection1 = new \ReflectionClass($refreshToken1); - $prop1 = $reflection1->getProperty('config'); - $prop1->setAccessible(true); - - $reflection2 = new \ReflectionClass($refreshToken2); - $prop2 = $reflection2->getProperty('config'); - $prop2->setAccessible(true); - - // get the private "config" property - $config1 = $prop1->getValue($refreshToken1); - $config2 = $prop2->getValue($refreshToken2); - - $this->assertEquals($config1['always_issue_new_refresh_token'], false); - $this->assertEquals($config2['always_issue_new_refresh_token'], true); - - $this->assertEquals($config1['unset_refresh_token_after_use'], true); - $this->assertEquals($config2['unset_refresh_token_after_use'], false); - } - - /** - * Test setting "always_issue_new_refresh_token" on a server level - * - * @see test/OAuth2/GrantType/RefreshTokenTest::testValidRefreshTokenWithNewRefreshTokenInResponse - **/ - public function testValidRefreshTokenWithNewRefreshTokenInResponse() - { - $storage = Bootstrap::getInstance()->getMemoryStorage(); - $server = new Server($storage, array('always_issue_new_refresh_token' => true)); - - $request = TestRequest::createPost(array( - 'grant_type' => 'refresh_token', // valid grant type - 'client_id' => 'Test Client ID', // valid client id - 'client_secret' => 'TestSecret', // valid client secret - 'refresh_token' => 'test-refreshtoken', // valid refresh token - )); - $token = $server->grantAccessToken($request, new Response()); - $this->assertTrue(isset($token['refresh_token']), 'refresh token should always refresh'); - - $refresh_token = $storage->getRefreshToken($token['refresh_token']); - $this->assertNotNull($refresh_token); - $this->assertEquals($refresh_token['refresh_token'], $token['refresh_token']); - $this->assertEquals($refresh_token['client_id'], $request->request('client_id')); - $this->assertTrue($token['refresh_token'] != 'test-refreshtoken', 'the refresh token returned is not the one used'); - $used_token = $storage->getRefreshToken('test-refreshtoken'); - $this->assertFalse($used_token, 'the refresh token used is no longer valid'); - } - - /** - * @expectedException InvalidArgumentException OAuth2\ResponseType\AuthorizationCodeInterface - **/ - public function testAddingUnknownResponseTypeThrowsException() - { - $server = new Server(); - $server->addResponseType($this->getMock('OAuth2\ResponseType\ResponseTypeInterface')); - } - - /** - * @expectedException LogicException OAuth2\Storage\PublicKeyInterface - **/ - public function testUsingJwtAccessTokensWithoutPublicKeyStorageThrowsException() - { - $server = new Server(array(), array('use_jwt_access_tokens' => true)); - $server->addGrantType($this->getMock('OAuth2\GrantType\GrantTypeInterface')); - $server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface')); - $server->addStorage($this->getMock('OAuth2\Storage\ClientCredentialsInterface')); - - $server->getTokenController(); - } - - public function testUsingJustJwtAccessTokenStorageWithResourceControllerIsOkay() - { - $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); - $server = new Server(array($pubkey), array('use_jwt_access_tokens' => true)); - - $this->assertNotNull($server->getResourceController()); - $this->assertInstanceOf('OAuth2\Storage\PublicKeyInterface', $server->getStorage('public_key')); - } - - /** - * @expectedException LogicException OAuth2\Storage\ClientInterface - **/ - public function testUsingJustJwtAccessTokenStorageWithAuthorizeControllerThrowsException() - { - $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); - $server = new Server(array($pubkey), array('use_jwt_access_tokens' => true)); - $this->assertNotNull($server->getAuthorizeController()); - } - - /** - * @expectedException LogicException grant_types - **/ - public function testUsingJustJwtAccessTokenStorageWithTokenControllerThrowsException() - { - $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); - $server = new Server(array($pubkey), array('use_jwt_access_tokens' => true)); - $server->getTokenController(); - } - - public function testUsingJwtAccessTokenAndClientStorageWithAuthorizeControllerIsOkay() - { - $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); - $client = $this->getMock('OAuth2\Storage\ClientInterface'); - $server = new Server(array($pubkey, $client), array('use_jwt_access_tokens' => true, 'allow_implicit' => true)); - $this->assertNotNull($server->getAuthorizeController()); - - $this->assertInstanceOf('OAuth2\ResponseType\JwtAccessToken', $server->getResponseType('token')); - } - - /** - * @expectedException LogicException UserClaims - **/ - public function testUsingOpenIDConnectWithoutUserClaimsThrowsException() - { - $client = $this->getMock('OAuth2\Storage\ClientInterface'); - $server = new Server($client, array('use_openid_connect' => true)); - - $server->getAuthorizeController(); - } - - /** - * @expectedException LogicException PublicKeyInterface - **/ - public function testUsingOpenIDConnectWithoutPublicKeyThrowsException() - { - $client = $this->getMock('OAuth2\Storage\ClientInterface'); - $userclaims = $this->getMock('OAuth2\OPenID\Storage\UserClaimsInterface'); - $server = new Server(array($client, $userclaims), array('use_openid_connect' => true)); - - $server->getAuthorizeController(); - } - - /** - * @expectedException LogicException issuer - **/ - public function testUsingOpenIDConnectWithoutIssuerThrowsException() - { - $client = $this->getMock('OAuth2\Storage\ClientInterface'); - $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface'); - $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); - $server = new Server(array($client, $userclaims, $pubkey), array('use_openid_connect' => true)); - - $server->getAuthorizeController(); - } - - public function testUsingOpenIDConnectWithIssuerPublicKeyAndUserClaimsIsOkay() - { - $client = $this->getMock('OAuth2\Storage\ClientInterface'); - $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface'); - $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); - $server = new Server(array($client, $userclaims, $pubkey), array( - 'use_openid_connect' => true, - 'issuer' => 'someguy', - )); - - $server->getAuthorizeController(); - - $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenInterface', $server->getResponseType('id_token')); - $this->assertNull($server->getResponseType('id_token token')); - } - - /** - * @expectedException LogicException OAuth2\ResponseType\AccessTokenInterface - **/ - public function testUsingOpenIDConnectWithAllowImplicitWithoutTokenStorageThrowsException() - { - $client = $this->getMock('OAuth2\Storage\ClientInterface'); - $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface'); - $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); - $server = new Server(array($client, $userclaims, $pubkey), array( - 'use_openid_connect' => true, - 'issuer' => 'someguy', - 'allow_implicit' => true, - )); - - $server->getAuthorizeController(); - } - - public function testUsingOpenIDConnectWithAllowImplicitAndUseJwtAccessTokensIsOkay() - { - $client = $this->getMock('OAuth2\Storage\ClientInterface'); - $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface'); - $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); - $server = new Server(array($client, $userclaims, $pubkey), array( - 'use_openid_connect' => true, - 'issuer' => 'someguy', - 'allow_implicit' => true, - 'use_jwt_access_tokens' => true, - )); - - $server->getAuthorizeController(); - - $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenInterface', $server->getResponseType('id_token')); - $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenTokenInterface', $server->getResponseType('id_token token')); - } - - public function testUsingOpenIDConnectWithAllowImplicitAndAccessTokenStorageIsOkay() - { - $client = $this->getMock('OAuth2\Storage\ClientInterface'); - $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface'); - $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); - $token = $this->getMock('OAuth2\Storage\AccessTokenInterface'); - $server = new Server(array($client, $userclaims, $pubkey, $token), array( - 'use_openid_connect' => true, - 'issuer' => 'someguy', - 'allow_implicit' => true, - )); - - $server->getAuthorizeController(); - - $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenInterface', $server->getResponseType('id_token')); - $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenTokenInterface', $server->getResponseType('id_token token')); - } - - public function testUsingOpenIDConnectWithAllowImplicitAndAccessTokenResponseTypeIsOkay() - { - $client = $this->getMock('OAuth2\Storage\ClientInterface'); - $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface'); - $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); - // $token = $this->getMock('OAuth2\Storage\AccessTokenInterface'); - $server = new Server(array($client, $userclaims, $pubkey), array( - 'use_openid_connect' => true, - 'issuer' => 'someguy', - 'allow_implicit' => true, - )); - - $token = $this->getMock('OAuth2\ResponseType\AccessTokenInterface'); - $server->addResponseType($token, 'token'); - - $server->getAuthorizeController(); - - $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenInterface', $server->getResponseType('id_token')); - $this->assertInstanceOf('OAuth2\OpenID\ResponseType\IdTokenTokenInterface', $server->getResponseType('id_token token')); - } - - /** - * @expectedException LogicException OAuth2\OpenID\Storage\AuthorizationCodeInterface - **/ - public function testUsingOpenIDConnectWithAuthorizationCodeStorageThrowsException() - { - $client = $this->getMock('OAuth2\Storage\ClientCredentialsInterface'); - $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface'); - $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); - $token = $this->getMock('OAuth2\Storage\AccessTokenInterface'); - $authcode = $this->getMock('OAuth2\Storage\AuthorizationCodeInterface'); - - $server = new Server(array($client, $userclaims, $pubkey, $token, $authcode), array( - 'use_openid_connect' => true, - 'issuer' => 'someguy' - )); - - $server->getTokenController(); - - $this->assertInstanceOf('OAuth2\OpenID\GrantType\AuthorizationCode', $server->getGrantType('authorization_code')); - } - - public function testUsingOpenIDConnectWithOpenIDAuthorizationCodeStorageCreatesOpenIDAuthorizationCodeGrantType() - { - $client = $this->getMock('OAuth2\Storage\ClientCredentialsInterface'); - $userclaims = $this->getMock('OAuth2\OpenID\Storage\UserClaimsInterface'); - $pubkey = $this->getMock('OAuth2\Storage\PublicKeyInterface'); - $token = $this->getMock('OAuth2\Storage\AccessTokenInterface'); - $authcode = $this->getMock('OAuth2\OpenID\Storage\AuthorizationCodeInterface'); - - $server = new Server(array($client, $userclaims, $pubkey, $token, $authcode), array( - 'use_openid_connect' => true, - 'issuer' => 'someguy' - )); - - $server->getTokenController(); - - $this->assertInstanceOf('OAuth2\OpenID\GrantType\AuthorizationCode', $server->getGrantType('authorization_code')); - } - - public function testMultipleValuedResponseTypeOrderDoesntMatter() - { - $responseType = $this->getMock('OAuth2\OpenID\ResponseType\IdTokenTokenInterface'); - $server = new Server(array(), array(), array(), array( - 'token id_token' => $responseType, - )); - - $this->assertEquals($responseType, $server->getResponseType('id_token token')); - } - - public function testAddGrantTypeWithoutKey() - { - $server = new Server(); - $server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->getMock('OAuth2\Storage\AuthorizationCodeInterface'))); - - $grantTypes = $server->getGrantTypes(); - $this->assertEquals('authorization_code', key($grantTypes)); - } - - public function testAddGrantTypeWithKey() - { - $server = new Server(); - $server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->getMock('OAuth2\Storage\AuthorizationCodeInterface')), 'ac'); - - $grantTypes = $server->getGrantTypes(); - $this->assertEquals('ac', key($grantTypes)); - } - - public function testAddGrantTypeWithKeyNotString() - { - $server = new Server(); - $server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($this->getMock('OAuth2\Storage\AuthorizationCodeInterface')), 42); - - $grantTypes = $server->getGrantTypes(); - $this->assertEquals('authorization_code', key($grantTypes)); - } -} diff --git a/library/oauth2/test/OAuth2/Storage/AccessTokenTest.php b/library/oauth2/test/OAuth2/Storage/AccessTokenTest.php deleted file mode 100644 index b34e0bfc0..000000000 --- a/library/oauth2/test/OAuth2/Storage/AccessTokenTest.php +++ /dev/null @@ -1,102 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -class AccessTokenTest extends BaseTest -{ - /** @dataProvider provideStorage */ - public function testSetAccessToken(AccessTokenInterface $storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - // assert token we are about to add does not exist - $token = $storage->getAccessToken('newtoken'); - $this->assertFalse($token); - - // add new token - $expires = time() + 20; - $success = $storage->setAccessToken('newtoken', 'client ID', 'SOMEUSERID', $expires); - $this->assertTrue($success); - - $token = $storage->getAccessToken('newtoken'); - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertArrayHasKey('client_id', $token); - $this->assertArrayHasKey('user_id', $token); - $this->assertArrayHasKey('expires', $token); - $this->assertEquals($token['access_token'], 'newtoken'); - $this->assertEquals($token['client_id'], 'client ID'); - $this->assertEquals($token['user_id'], 'SOMEUSERID'); - $this->assertEquals($token['expires'], $expires); - - // change existing token - $expires = time() + 42; - $success = $storage->setAccessToken('newtoken', 'client ID2', 'SOMEOTHERID', $expires); - $this->assertTrue($success); - - $token = $storage->getAccessToken('newtoken'); - $this->assertNotNull($token); - $this->assertArrayHasKey('access_token', $token); - $this->assertArrayHasKey('client_id', $token); - $this->assertArrayHasKey('user_id', $token); - $this->assertArrayHasKey('expires', $token); - $this->assertEquals($token['access_token'], 'newtoken'); - $this->assertEquals($token['client_id'], 'client ID2'); - $this->assertEquals($token['user_id'], 'SOMEOTHERID'); - $this->assertEquals($token['expires'], $expires); - - // add token with scope having an empty string value - $expires = time() + 42; - $success = $storage->setAccessToken('newtoken', 'client ID', 'SOMEOTHERID', $expires, ''); - $this->assertTrue($success); - } - - /** @dataProvider provideStorage */ - public function testUnsetAccessToken(AccessTokenInterface $storage) - { - if ($storage instanceof NullStorage || !method_exists($storage, 'unsetAccessToken')) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - // assert token we are about to unset does not exist - $token = $storage->getAccessToken('revokabletoken'); - $this->assertFalse($token); - - // add new token - $expires = time() + 20; - $success = $storage->setAccessToken('revokabletoken', 'client ID', 'SOMEUSERID', $expires); - $this->assertTrue($success); - - // assert unsetAccessToken returns true - $result = $storage->unsetAccessToken('revokabletoken'); - $this->assertTrue($result); - - // assert token we unset does not exist - $token = $storage->getAccessToken('revokabletoken'); - $this->assertFalse($token); - } - - /** @dataProvider provideStorage */ - public function testUnsetAccessTokenReturnsFalse(AccessTokenInterface $storage) - { - if ($storage instanceof NullStorage || !method_exists($storage, 'unsetAccessToken')) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - // assert token we are about to unset does not exist - $token = $storage->getAccessToken('nonexistanttoken'); - $this->assertFalse($token); - - // assert unsetAccessToken returns false - $result = $storage->unsetAccessToken('nonexistanttoken'); - $this->assertFalse($result); - } -} diff --git a/library/oauth2/test/OAuth2/Storage/AuthorizationCodeTest.php b/library/oauth2/test/OAuth2/Storage/AuthorizationCodeTest.php deleted file mode 100644 index 2d901b501..000000000 --- a/library/oauth2/test/OAuth2/Storage/AuthorizationCodeTest.php +++ /dev/null @@ -1,106 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -class AuthorizationCodeTest extends BaseTest -{ - /** @dataProvider provideStorage */ - public function testGetAuthorizationCode(AuthorizationCodeInterface $storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - // nonexistant client_id - $details = $storage->getAuthorizationCode('faketoken'); - $this->assertFalse($details); - - // valid client_id - $details = $storage->getAuthorizationCode('testtoken'); - $this->assertNotNull($details); - } - - /** @dataProvider provideStorage */ - public function testSetAuthorizationCode(AuthorizationCodeInterface $storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - // assert code we are about to add does not exist - $code = $storage->getAuthorizationCode('newcode'); - $this->assertFalse($code); - - // add new code - $expires = time() + 20; - $success = $storage->setAuthorizationCode('newcode', 'client ID', 'SOMEUSERID', 'http://example.com', $expires); - $this->assertTrue($success); - - $code = $storage->getAuthorizationCode('newcode'); - $this->assertNotNull($code); - $this->assertArrayHasKey('authorization_code', $code); - $this->assertArrayHasKey('client_id', $code); - $this->assertArrayHasKey('user_id', $code); - $this->assertArrayHasKey('redirect_uri', $code); - $this->assertArrayHasKey('expires', $code); - $this->assertEquals($code['authorization_code'], 'newcode'); - $this->assertEquals($code['client_id'], 'client ID'); - $this->assertEquals($code['user_id'], 'SOMEUSERID'); - $this->assertEquals($code['redirect_uri'], 'http://example.com'); - $this->assertEquals($code['expires'], $expires); - - // change existing code - $expires = time() + 42; - $success = $storage->setAuthorizationCode('newcode', 'client ID2', 'SOMEOTHERID', 'http://example.org', $expires); - $this->assertTrue($success); - - $code = $storage->getAuthorizationCode('newcode'); - $this->assertNotNull($code); - $this->assertArrayHasKey('authorization_code', $code); - $this->assertArrayHasKey('client_id', $code); - $this->assertArrayHasKey('user_id', $code); - $this->assertArrayHasKey('redirect_uri', $code); - $this->assertArrayHasKey('expires', $code); - $this->assertEquals($code['authorization_code'], 'newcode'); - $this->assertEquals($code['client_id'], 'client ID2'); - $this->assertEquals($code['user_id'], 'SOMEOTHERID'); - $this->assertEquals($code['redirect_uri'], 'http://example.org'); - $this->assertEquals($code['expires'], $expires); - - // add new code with scope having an empty string value - $expires = time() + 20; - $success = $storage->setAuthorizationCode('newcode', 'client ID', 'SOMEUSERID', 'http://example.com', $expires, ''); - $this->assertTrue($success); - } - - /** @dataProvider provideStorage */ - public function testExpireAccessToken(AccessTokenInterface $storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - // create a valid code - $expires = time() + 20; - $success = $storage->setAuthorizationCode('code-to-expire', 'client ID', 'SOMEUSERID', 'http://example.com', time() + 20); - $this->assertTrue($success); - - // verify the new code exists - $code = $storage->getAuthorizationCode('code-to-expire'); - $this->assertNotNull($code); - - $this->assertArrayHasKey('authorization_code', $code); - $this->assertEquals($code['authorization_code'], 'code-to-expire'); - - // now expire the code and ensure it's no longer available - $storage->expireAuthorizationCode('code-to-expire'); - $code = $storage->getAuthorizationCode('code-to-expire'); - $this->assertFalse($code); - } -} diff --git a/library/oauth2/test/OAuth2/Storage/ClientCredentialsTest.php b/library/oauth2/test/OAuth2/Storage/ClientCredentialsTest.php deleted file mode 100644 index 15289af30..000000000 --- a/library/oauth2/test/OAuth2/Storage/ClientCredentialsTest.php +++ /dev/null @@ -1,28 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -class ClientCredentialsTest extends BaseTest -{ - /** @dataProvider provideStorage */ - public function testCheckClientCredentials(ClientCredentialsInterface $storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - // nonexistant client_id - $pass = $storage->checkClientCredentials('fakeclient', 'testpass'); - $this->assertFalse($pass); - - // invalid password - $pass = $storage->checkClientCredentials('oauth_test_client', 'invalidcredentials'); - $this->assertFalse($pass); - - // valid credentials - $pass = $storage->checkClientCredentials('oauth_test_client', 'testpass'); - $this->assertTrue($pass); - } -} diff --git a/library/oauth2/test/OAuth2/Storage/ClientTest.php b/library/oauth2/test/OAuth2/Storage/ClientTest.php deleted file mode 100644 index 6a5cc0b49..000000000 --- a/library/oauth2/test/OAuth2/Storage/ClientTest.php +++ /dev/null @@ -1,110 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -class ClientTest extends BaseTest -{ - /** @dataProvider provideStorage */ - public function testGetClientDetails(ClientInterface $storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - // nonexistant client_id - $details = $storage->getClientDetails('fakeclient'); - $this->assertFalse($details); - - // valid client_id - $details = $storage->getClientDetails('oauth_test_client'); - $this->assertNotNull($details); - $this->assertArrayHasKey('client_id', $details); - $this->assertArrayHasKey('client_secret', $details); - $this->assertArrayHasKey('redirect_uri', $details); - } - - /** @dataProvider provideStorage */ - public function testCheckRestrictedGrantType(ClientInterface $storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - // Check invalid - $pass = $storage->checkRestrictedGrantType('oauth_test_client', 'authorization_code'); - $this->assertFalse($pass); - - // Check valid - $pass = $storage->checkRestrictedGrantType('oauth_test_client', 'implicit'); - $this->assertTrue($pass); - } - - /** @dataProvider provideStorage */ - public function testGetAccessToken(ClientInterface $storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - // nonexistant client_id - $details = $storage->getAccessToken('faketoken'); - $this->assertFalse($details); - - // valid client_id - $details = $storage->getAccessToken('testtoken'); - $this->assertNotNull($details); - } - - /** @dataProvider provideStorage */ - public function testIsPublicClient(ClientInterface $storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - $publicClientId = 'public-client-'.rand(); - $confidentialClientId = 'confidential-client-'.rand(); - - // create a new client - $success1 = $storage->setClientDetails($publicClientId, ''); - $success2 = $storage->setClientDetails($confidentialClientId, 'some-secret'); - $this->assertTrue($success1); - $this->assertTrue($success2); - - // assert isPublicClient for both - $this->assertTrue($storage->isPublicClient($publicClientId)); - $this->assertFalse($storage->isPublicClient($confidentialClientId)); - } - - /** @dataProvider provideStorage */ - public function testSaveClient(ClientInterface $storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - $clientId = 'some-client-'.rand(); - - // create a new client - $success = $storage->setClientDetails($clientId, 'somesecret', 'http://test.com', 'client_credentials', 'clientscope1', 'brent@brentertainment.com'); - $this->assertTrue($success); - - // valid client_id - $details = $storage->getClientDetails($clientId); - $this->assertEquals($details['client_secret'], 'somesecret'); - $this->assertEquals($details['redirect_uri'], 'http://test.com'); - $this->assertEquals($details['grant_types'], 'client_credentials'); - $this->assertEquals($details['scope'], 'clientscope1'); - $this->assertEquals($details['user_id'], 'brent@brentertainment.com'); - } -} diff --git a/library/oauth2/test/OAuth2/Storage/DynamoDBTest.php b/library/oauth2/test/OAuth2/Storage/DynamoDBTest.php deleted file mode 100644 index 2147f0914..000000000 --- a/library/oauth2/test/OAuth2/Storage/DynamoDBTest.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -class DynamoDBTest extends BaseTest -{ - public function testGetDefaultScope() - { - $client = $this->getMockBuilder('\Aws\DynamoDb\DynamoDbClient') - ->disableOriginalConstructor() - ->setMethods(array('query')) - ->getMock(); - - $return = $this->getMockBuilder('\Guzzle\Service\Resource\Model') - ->setMethods(array('count', 'toArray')) - ->getMock(); - - $data = array( - 'Items' => array(), - 'Count' => 0, - 'ScannedCount'=> 0 - ); - - $return->expects($this->once()) - ->method('count') - ->will($this->returnValue(count($data))); - - $return->expects($this->once()) - ->method('toArray') - ->will($this->returnValue($data)); - - // should return null default scope if none is set in database - $client->expects($this->once()) - ->method('query') - ->will($this->returnValue($return)); - - $storage = new DynamoDB($client); - $this->assertNull($storage->getDefaultScope()); - } -} diff --git a/library/oauth2/test/OAuth2/Storage/JwtAccessTokenTest.php b/library/oauth2/test/OAuth2/Storage/JwtAccessTokenTest.php deleted file mode 100644 index a6acbea1f..000000000 --- a/library/oauth2/test/OAuth2/Storage/JwtAccessTokenTest.php +++ /dev/null @@ -1,41 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -use OAuth2\Encryption\Jwt; - -class JwtAccessTokenTest extends BaseTest -{ - /** @dataProvider provideStorage */ - public function testSetAccessToken($storage) - { - if (!$storage instanceof PublicKey) { - // incompatible storage - return; - } - - $crypto = new jwtAccessToken($storage); - - $publicKeyStorage = Bootstrap::getInstance()->getMemoryStorage(); - $encryptionUtil = new Jwt(); - - $jwtAccessToken = array( - 'access_token' => rand(), - 'expires' => time() + 100, - 'scope' => 'foo', - ); - - $token = $encryptionUtil->encode($jwtAccessToken, $storage->getPrivateKey(), $storage->getEncryptionAlgorithm()); - - $this->assertNotNull($token); - - $tokenData = $crypto->getAccessToken($token); - - $this->assertTrue(is_array($tokenData)); - - /* assert the decoded token is the same */ - $this->assertEquals($tokenData['access_token'], $jwtAccessToken['access_token']); - $this->assertEquals($tokenData['expires'], $jwtAccessToken['expires']); - $this->assertEquals($tokenData['scope'], $jwtAccessToken['scope']); - } -} diff --git a/library/oauth2/test/OAuth2/Storage/JwtBearerTest.php b/library/oauth2/test/OAuth2/Storage/JwtBearerTest.php deleted file mode 100644 index d0ab9b899..000000000 --- a/library/oauth2/test/OAuth2/Storage/JwtBearerTest.php +++ /dev/null @@ -1,25 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -class JwtBearerTest extends BaseTest -{ - /** @dataProvider provideStorage */ - public function testGetClientKey(JwtBearerInterface $storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - // nonexistant client_id - $key = $storage->getClientKey('this-is-not-real', 'nor-is-this'); - $this->assertFalse($key); - - // valid client_id and subject - $key = $storage->getClientKey('oauth_test_client', 'test_subject'); - $this->assertNotNull($key); - $this->assertEquals($key, Bootstrap::getInstance()->getTestPublicKey()); - } -} diff --git a/library/oauth2/test/OAuth2/Storage/PdoTest.php b/library/oauth2/test/OAuth2/Storage/PdoTest.php deleted file mode 100644 index 57eb39072..000000000 --- a/library/oauth2/test/OAuth2/Storage/PdoTest.php +++ /dev/null @@ -1,39 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -class PdoTest extends BaseTest -{ - public function testCreatePdoStorageUsingPdoClass() - { - $pdo = new \PDO(sprintf('sqlite://%s', Bootstrap::getInstance()->getSqliteDir())); - $storage = new Pdo($pdo); - - $this->assertNotNull($storage->getClientDetails('oauth_test_client')); - } - - public function testCreatePdoStorageUsingDSN() - { - $dsn = sprintf('sqlite://%s', Bootstrap::getInstance()->getSqliteDir()); - $storage = new Pdo($dsn); - - $this->assertNotNull($storage->getClientDetails('oauth_test_client')); - } - - public function testCreatePdoStorageUsingConfig() - { - $config = array('dsn' => sprintf('sqlite://%s', Bootstrap::getInstance()->getSqliteDir())); - $storage = new Pdo($config); - - $this->assertNotNull($storage->getClientDetails('oauth_test_client')); - } - - /** - * @expectedException InvalidArgumentException dsn - */ - public function testCreatePdoStorageWithoutDSNThrowsException() - { - $config = array('username' => 'brent', 'password' => 'brentisaballer'); - $storage = new Pdo($config); - } -} diff --git a/library/oauth2/test/OAuth2/Storage/PublicKeyTest.php b/library/oauth2/test/OAuth2/Storage/PublicKeyTest.php deleted file mode 100644 index f85195870..000000000 --- a/library/oauth2/test/OAuth2/Storage/PublicKeyTest.php +++ /dev/null @@ -1,29 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -class PublicKeyTest extends BaseTest -{ - /** @dataProvider provideStorage */ - public function testSetAccessToken($storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - if (!$storage instanceof PublicKeyInterface) { - // incompatible storage - return; - } - - $configDir = Bootstrap::getInstance()->getConfigDir(); - $globalPublicKey = file_get_contents($configDir.'/keys/id_rsa.pub'); - $globalPrivateKey = file_get_contents($configDir.'/keys/id_rsa'); - - /* assert values from storage */ - $this->assertEquals($storage->getPublicKey(), $globalPublicKey); - $this->assertEquals($storage->getPrivateKey(), $globalPrivateKey); - } -} diff --git a/library/oauth2/test/OAuth2/Storage/RefreshTokenTest.php b/library/oauth2/test/OAuth2/Storage/RefreshTokenTest.php deleted file mode 100644 index 314c93195..000000000 --- a/library/oauth2/test/OAuth2/Storage/RefreshTokenTest.php +++ /dev/null @@ -1,41 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -class RefreshTokenTest extends BaseTest -{ - /** @dataProvider provideStorage */ - public function testSetRefreshToken(RefreshTokenInterface $storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - // assert token we are about to add does not exist - $token = $storage->getRefreshToken('refreshtoken'); - $this->assertFalse($token); - - // add new token - $expires = time() + 20; - $success = $storage->setRefreshToken('refreshtoken', 'client ID', 'SOMEUSERID', $expires); - $this->assertTrue($success); - - $token = $storage->getRefreshToken('refreshtoken'); - $this->assertNotNull($token); - $this->assertArrayHasKey('refresh_token', $token); - $this->assertArrayHasKey('client_id', $token); - $this->assertArrayHasKey('user_id', $token); - $this->assertArrayHasKey('expires', $token); - $this->assertEquals($token['refresh_token'], 'refreshtoken'); - $this->assertEquals($token['client_id'], 'client ID'); - $this->assertEquals($token['user_id'], 'SOMEUSERID'); - $this->assertEquals($token['expires'], $expires); - - // add token with scope having an empty string value - $expires = time() + 20; - $success = $storage->setRefreshToken('refreshtoken2', 'client ID', 'SOMEUSERID', $expires, ''); - $this->assertTrue($success); - } -} diff --git a/library/oauth2/test/OAuth2/Storage/ScopeTest.php b/library/oauth2/test/OAuth2/Storage/ScopeTest.php deleted file mode 100644 index fd1edeb93..000000000 --- a/library/oauth2/test/OAuth2/Storage/ScopeTest.php +++ /dev/null @@ -1,53 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -use OAuth2\Scope; - -class ScopeTest extends BaseTest -{ - /** @dataProvider provideStorage */ - public function testScopeExists($storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - if (!$storage instanceof ScopeInterface) { - // incompatible storage - return; - } - - //Test getting scopes - $scopeUtil = new Scope($storage); - $this->assertTrue($scopeUtil->scopeExists('supportedscope1')); - $this->assertTrue($scopeUtil->scopeExists('supportedscope1 supportedscope2 supportedscope3')); - $this->assertFalse($scopeUtil->scopeExists('fakescope')); - $this->assertFalse($scopeUtil->scopeExists('supportedscope1 supportedscope2 supportedscope3 fakescope')); - } - - /** @dataProvider provideStorage */ - public function testGetDefaultScope($storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - if (!$storage instanceof ScopeInterface) { - // incompatible storage - return; - } - - // test getting default scope - $scopeUtil = new Scope($storage); - $expected = explode(' ', $scopeUtil->getDefaultScope()); - $actual = explode(' ', 'defaultscope1 defaultscope2'); - sort($expected); - sort($actual); - $this->assertEquals($expected, $actual); - } -} diff --git a/library/oauth2/test/OAuth2/Storage/UserCredentialsTest.php b/library/oauth2/test/OAuth2/Storage/UserCredentialsTest.php deleted file mode 100644 index 65655a6b2..000000000 --- a/library/oauth2/test/OAuth2/Storage/UserCredentialsTest.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -class UserCredentialsTest extends BaseTest -{ - /** @dataProvider provideStorage */ - public function testCheckUserCredentials(UserCredentialsInterface $storage) - { - if ($storage instanceof NullStorage) { - $this->markTestSkipped('Skipped Storage: ' . $storage->getMessage()); - - return; - } - - // create a new user for testing - $success = $storage->setUser('testusername', 'testpass', 'Test', 'User'); - $this->assertTrue($success); - - // correct credentials - $this->assertTrue($storage->checkUserCredentials('testusername', 'testpass')); - // invalid password - $this->assertFalse($storage->checkUserCredentials('testusername', 'fakepass')); - // invalid username - $this->assertFalse($storage->checkUserCredentials('fakeusername', 'testpass')); - - // invalid username - $this->assertFalse($storage->getUserDetails('fakeusername')); - - // ensure all properties are set - $user = $storage->getUserDetails('testusername'); - $this->assertTrue($user !== false); - $this->assertArrayHasKey('user_id', $user); - $this->assertArrayHasKey('first_name', $user); - $this->assertArrayHasKey('last_name', $user); - $this->assertEquals($user['user_id'], 'testusername'); - $this->assertEquals($user['first_name'], 'Test'); - $this->assertEquals($user['last_name'], 'User'); - } -} diff --git a/library/oauth2/test/OAuth2/TokenType/BearerTest.php b/library/oauth2/test/OAuth2/TokenType/BearerTest.php deleted file mode 100644 index a2e000e22..000000000 --- a/library/oauth2/test/OAuth2/TokenType/BearerTest.php +++ /dev/null @@ -1,58 +0,0 @@ -<?php - -namespace OAuth2\TokenType; - -use OAuth2\Request\TestRequest; -use OAuth2\Response; - -class BearerTest extends \PHPUnit_Framework_TestCase -{ - public function testValidContentTypeWithCharset() - { - $bearer = new Bearer(); - $request = TestRequest::createPost(array( - 'access_token' => 'ThisIsMyAccessToken' - )); - $request->server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=UTF-8'; - - $param = $bearer->getAccessTokenParameter($request, $response = new Response()); - $this->assertEquals($param, 'ThisIsMyAccessToken'); - } - - public function testInvalidContentType() - { - $bearer = new Bearer(); - $request = TestRequest::createPost(array( - 'access_token' => 'ThisIsMyAccessToken' - )); - $request->server['CONTENT_TYPE'] = 'application/json; charset=UTF-8'; - - $param = $bearer->getAccessTokenParameter($request, $response = new Response()); - $this->assertNull($param); - $this->assertEquals($response->getStatusCode(), 400); - $this->assertEquals($response->getParameter('error'), 'invalid_request'); - $this->assertEquals($response->getParameter('error_description'), 'The content type for POST requests must be "application/x-www-form-urlencoded"'); - } - - public function testValidRequestUsingAuthorizationHeader() - { - $bearer = new Bearer(); - $request = new TestRequest(); - $request->headers['AUTHORIZATION'] = 'Bearer MyToken'; - $request->server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=UTF-8'; - - $param = $bearer->getAccessTokenParameter($request, $response = new Response()); - $this->assertEquals('MyToken', $param); - } - - public function testValidRequestUsingAuthorizationHeaderCaseInsensitive() - { - $bearer = new Bearer(); - $request = new TestRequest(); - $request->server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=UTF-8'; - $request->headers['Authorization'] = 'Bearer MyToken'; - - $param = $bearer->getAccessTokenParameter($request, $response = new Response()); - $this->assertEquals('MyToken', $param); - } -} diff --git a/library/oauth2/test/bootstrap.php b/library/oauth2/test/bootstrap.php deleted file mode 100644 index 0a4af0716..000000000 --- a/library/oauth2/test/bootstrap.php +++ /dev/null @@ -1,12 +0,0 @@ -<?php - -require_once(dirname(__FILE__).'/../src/OAuth2/Autoloader.php'); -OAuth2\Autoloader::register(); - -// register test classes -OAuth2\Autoloader::register(dirname(__FILE__).'/lib'); - -// register vendors if possible -if (file_exists(__DIR__.'/../vendor/autoload.php')) { - require_once(__DIR__.'/../vendor/autoload.php'); -} diff --git a/library/oauth2/test/cleanup.php b/library/oauth2/test/cleanup.php deleted file mode 100644 index 8663a901b..000000000 --- a/library/oauth2/test/cleanup.php +++ /dev/null @@ -1,15 +0,0 @@ -<?php - -require_once(dirname(__FILE__).'/../src/OAuth2/Autoloader.php'); -OAuth2\Autoloader::register(); - -// register test classes -OAuth2\Autoloader::register(dirname(__FILE__).'/lib'); - -// register vendors if possible -if (file_exists(__DIR__.'/../vendor/autoload.php')) { - require_once(__DIR__.'/../vendor/autoload.php'); -} - -// remove the dynamoDB database that was created for this build -OAuth2\Storage\Bootstrap::getInstance()->cleanupTravisDynamoDb(); diff --git a/library/oauth2/test/config/keys/id_rsa b/library/oauth2/test/config/keys/id_rsa deleted file mode 100644 index e8b9eff2d..000000000 --- a/library/oauth2/test/config/keys/id_rsa +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQC8fpi06NfVYHAOAnxNMVnTXr/ptsLsNjP+uAt2eO0cc5J9H5XV -8lFVujOrRu/JWi1TDmAvOaf/6A3BphIA1Pwp0AAqlZdwizIum8j0KzpsGYH5qReN -QDwF3oUSKMsQCCGCDHrDYifG/pRi9bN1ZVjEXPr35HJuBe+FQpZTs8DewwIDAQAB -AoGARfNxNknmtx/n1bskZ/01iZRzAge6BLEE0LV6Q4gS7mkRZu/Oyiv39Sl5vUlA -+WdGxLjkBwKNjxGN8Vxw9/ASd8rSsqeAUYIwAeifXrHhj5DBPQT/pDPkeFnp9B1w -C6jo+3AbBQ4/b0ONSIEnCL2xGGglSIAxO17T1ViXp7lzXPECQQDe63nkRdWM0OCb -oaHQPT3E26224maIstrGFUdt9yw3yJf4bOF7TtiPLlLuHsTTge3z+fG6ntC0xG56 -1cl37C3ZAkEA2HdVcRGugNp/qmVz4LJTpD+WZKi73PLAO47wDOrYh9Pn2I6fcEH0 -CPnggt1ko4ujvGzFTvRH64HXa6aPCv1j+wJBAMQMah3VQPNf/DlDVFEUmw9XeBZg -VHaifX851aEjgXLp6qVj9IYCmLiLsAmVa9rr6P7p8asD418nZlaHUHE0eDkCQQCr -uxis6GMx1Ka971jcJX2X696LoxXPd0KsvXySMupv79yagKPa8mgBiwPjrnK+EPVo -cj6iochA/bSCshP/mwFrAkBHEKPi6V6gb94JinCT7x3weahbdp6bJ6/nzBH/p9VA -HoT1JtwNFhGv9BCjmDydshQHfSWpY9NxlccBKL7ITm8R ------END RSA PRIVATE KEY-----
\ No newline at end of file diff --git a/library/oauth2/test/config/keys/id_rsa.pub b/library/oauth2/test/config/keys/id_rsa.pub deleted file mode 100644 index 1ac15f5eb..000000000 --- a/library/oauth2/test/config/keys/id_rsa.pub +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICiDCCAfGgAwIBAgIBADANBgkqhkiG9w0BAQQFADA9MQswCQYDVQQGEwJVUzEL -MAkGA1UECBMCVVQxITAfBgNVBAoTGFZpZ25ldHRlIENvcnBvcmF0aW9uIFNCWDAe -Fw0xMTEwMTUwMzE4MjdaFw0zMTEwMTAwMzE4MjdaMD0xCzAJBgNVBAYTAlVTMQsw -CQYDVQQIEwJVVDEhMB8GA1UEChMYVmlnbmV0dGUgQ29ycG9yYXRpb24gU0JYMIGf -MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8fpi06NfVYHAOAnxNMVnTXr/ptsLs -NjP+uAt2eO0cc5J9H5XV8lFVujOrRu/JWi1TDmAvOaf/6A3BphIA1Pwp0AAqlZdw -izIum8j0KzpsGYH5qReNQDwF3oUSKMsQCCGCDHrDYifG/pRi9bN1ZVjEXPr35HJu -Be+FQpZTs8DewwIDAQABo4GXMIGUMB0GA1UdDgQWBBRe8hrEXm+Yim4YlD5Nx+1K -vCYs9DBlBgNVHSMEXjBcgBRe8hrEXm+Yim4YlD5Nx+1KvCYs9KFBpD8wPTELMAkG -A1UEBhMCVVMxCzAJBgNVBAgTAlVUMSEwHwYDVQQKExhWaWduZXR0ZSBDb3Jwb3Jh -dGlvbiBTQliCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBjhyRD -lM7vnLn6drgQVftW5V9nDFAyPAuiGvMIKFSbiAf1PxXCRn5sfJquwWKsJUi4ZGNl -aViXdFmN6/F13PSM+yg63tpKy0fYqMbTM+Oe5WuSHkSW1VuYNHV+24adgNk/FRDL -FRrlM1f6s9VTLWvwGItjfrof0Ba8Uq7ZDSb9Xg== ------END CERTIFICATE-----
\ No newline at end of file diff --git a/library/oauth2/test/config/storage.json b/library/oauth2/test/config/storage.json deleted file mode 100644 index a31d3bca2..000000000 --- a/library/oauth2/test/config/storage.json +++ /dev/null @@ -1,181 +0,0 @@ -{ - "authorization_codes": { - "testcode": { - "client_id": "Test Client ID", - "user_id": "", - "redirect_uri": "", - "expires": "9999999999", - "id_token": "IDTOKEN" - }, - "testcode-with-scope": { - "client_id": "Test Client ID", - "user_id": "", - "redirect_uri": "", - "expires": "9999999999", - "scope": "scope1 scope2" - }, - "testcode-expired": { - "client_id": "Test Client ID", - "user_id": "", - "redirect_uri": "", - "expires": "1356998400" - }, - "testcode-empty-secret": { - "client_id": "Test Client ID Empty Secret", - "user_id": "", - "redirect_uri": "", - "expires": "9999999999" - }, - "testcode-openid": { - "client_id": "Test Client ID", - "user_id": "", - "redirect_uri": "", - "expires": "9999999999", - "id_token": "test_id_token" - } - }, - "client_credentials" : { - "Test Client ID": { - "client_secret": "TestSecret" - }, - "Test Client ID with Redirect Uri": { - "client_secret": "TestSecret2", - "redirect_uri": "http://brentertainment.com" - }, - "Test Client ID with Buggy Redirect Uri": { - "client_secret": "TestSecret2", - "redirect_uri": " http://brentertainment.com" - }, - "Test Client ID with Multiple Redirect Uris": { - "client_secret": "TestSecret3", - "redirect_uri": "http://brentertainment.com http://morehazards.com" - }, - "Test Client ID with Redirect Uri Parts": { - "client_secret": "TestSecret4", - "redirect_uri": "http://user:pass@brentertainment.com:2222/authorize/cb?auth_type=oauth&test=true" - }, - "Test Some Other Client": { - "client_secret": "TestSecret3" - }, - "Test Client ID Empty Secret": { - "client_secret": "" - }, - "Test Client ID For Password Grant": { - "grant_types": "password", - "client_secret": "" - }, - "Client ID With User ID": { - "client_secret": "TestSecret", - "user_id": "brent@brentertainment.com" - }, - "oauth_test_client": { - "client_secret": "testpass", - "grant_types": "implicit password" - } - }, - "user_credentials" : { - "test-username": { - "password": "testpass" - }, - "testusername": { - "password": "testpass" - }, - "testuser": { - "password": "password", - "email": "testuser@test.com", - "email_verified": true - }, - "johndoe": { - "password": "password" - } - }, - "refresh_tokens" : { - "test-refreshtoken": { - "refresh_token": "test-refreshtoken", - "client_id": "Test Client ID", - "user_id": "test-username", - "expires": 0, - "scope": null - }, - "test-refreshtoken-with-scope": { - "refresh_token": "test-refreshtoken", - "client_id": "Test Client ID", - "user_id": "test-username", - "expires": 0, - "scope": "scope1 scope2" - } - }, - "access_tokens" : { - "accesstoken-expired": { - "access_token": "accesstoken-expired", - "client_id": "Test Client ID", - "expires": 1234567, - "scope": null - }, - "accesstoken-scope": { - "access_token": "accesstoken-scope", - "client_id": "Test Client ID", - "expires": 99999999900, - "scope": "testscope" - }, - "accesstoken-openid-connect": { - "access_token": "accesstoken-openid-connect", - "client_id": "Test Client ID", - "user_id": "testuser", - "expires": 99999999900, - "scope": "openid email" - }, - "accesstoken-malformed": { - "access_token": "accesstoken-mallformed", - "expires": 99999999900, - "scope": "testscope" - } - }, - "jwt": { - "Test Client ID": { - "key": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5/SxVlE8gnpFqCxgl2wjhzY7u\ncEi00s0kUg3xp7lVEvgLgYcAnHiWp+gtSjOFfH2zsvpiWm6Lz5f743j/FEzHIO1o\nwR0p4d9pOaJK07d01+RzoQLOIQAgXrr4T1CCWUesncwwPBVCyy2Mw3Nmhmr9MrF8\nUlvdRKBxriRnlP3qJQIDAQAB\n-----END PUBLIC KEY-----", - "subject": "testuser@ourdomain.com" - }, - "Test Client ID PHP-5.2": { - "key": "mysecretkey", - "subject": "testuser@ourdomain.com" - }, - "Missing Key Client": { - "key": null, - "subject": "testuser@ourdomain.com" - }, - "Missing Key Client PHP-5.2": { - "key": null, - "subject": "testuser@ourdomain.com" - }, - "oauth_test_client": { - "key": "-----BEGIN CERTIFICATE-----\nMIICiDCCAfGgAwIBAgIBADANBgkqhkiG9w0BAQQFADA9MQswCQYDVQQGEwJVUzEL\nMAkGA1UECBMCVVQxITAfBgNVBAoTGFZpZ25ldHRlIENvcnBvcmF0aW9uIFNCWDAe\nFw0xMTEwMTUwMzE4MjdaFw0zMTEwMTAwMzE4MjdaMD0xCzAJBgNVBAYTAlVTMQsw\nCQYDVQQIEwJVVDEhMB8GA1UEChMYVmlnbmV0dGUgQ29ycG9yYXRpb24gU0JYMIGf\nMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8fpi06NfVYHAOAnxNMVnTXr/ptsLs\nNjP+uAt2eO0cc5J9H5XV8lFVujOrRu/JWi1TDmAvOaf/6A3BphIA1Pwp0AAqlZdw\nizIum8j0KzpsGYH5qReNQDwF3oUSKMsQCCGCDHrDYifG/pRi9bN1ZVjEXPr35HJu\nBe+FQpZTs8DewwIDAQABo4GXMIGUMB0GA1UdDgQWBBRe8hrEXm+Yim4YlD5Nx+1K\nvCYs9DBlBgNVHSMEXjBcgBRe8hrEXm+Yim4YlD5Nx+1KvCYs9KFBpD8wPTELMAkG\nA1UEBhMCVVMxCzAJBgNVBAgTAlVUMSEwHwYDVQQKExhWaWduZXR0ZSBDb3Jwb3Jh\ndGlvbiBTQliCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBjhyRD\nlM7vnLn6drgQVftW5V9nDFAyPAuiGvMIKFSbiAf1PxXCRn5sfJquwWKsJUi4ZGNl\naViXdFmN6/F13PSM+yg63tpKy0fYqMbTM+Oe5WuSHkSW1VuYNHV+24adgNk/FRDL\nFRrlM1f6s9VTLWvwGItjfrof0Ba8Uq7ZDSb9Xg==\n-----END CERTIFICATE-----", - "subject": "test_subject" - } - }, - "jti": [ - { - "issuer": "Test Client ID", - "subject": "testuser@ourdomain.com", - "audience": "http://myapp.com/oauth/auth", - "expires": 99999999900, - "jti": "used_jti" - } - ], - "supported_scopes" : [ - "scope1", - "scope2", - "scope3", - "clientscope1", - "clientscope2", - "clientscope3", - "supportedscope1", - "supportedscope2", - "supportedscope3", - "supportedscope4" - ], - "keys": { - "public_key": "-----BEGIN CERTIFICATE-----\nMIICiDCCAfGgAwIBAgIBADANBgkqhkiG9w0BAQQFADA9MQswCQYDVQQGEwJVUzEL\nMAkGA1UECBMCVVQxITAfBgNVBAoTGFZpZ25ldHRlIENvcnBvcmF0aW9uIFNCWDAe\nFw0xMTEwMTUwMzE4MjdaFw0zMTEwMTAwMzE4MjdaMD0xCzAJBgNVBAYTAlVTMQsw\nCQYDVQQIEwJVVDEhMB8GA1UEChMYVmlnbmV0dGUgQ29ycG9yYXRpb24gU0JYMIGf\nMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8fpi06NfVYHAOAnxNMVnTXr/ptsLs\nNjP+uAt2eO0cc5J9H5XV8lFVujOrRu/JWi1TDmAvOaf/6A3BphIA1Pwp0AAqlZdw\nizIum8j0KzpsGYH5qReNQDwF3oUSKMsQCCGCDHrDYifG/pRi9bN1ZVjEXPr35HJu\nBe+FQpZTs8DewwIDAQABo4GXMIGUMB0GA1UdDgQWBBRe8hrEXm+Yim4YlD5Nx+1K\nvCYs9DBlBgNVHSMEXjBcgBRe8hrEXm+Yim4YlD5Nx+1KvCYs9KFBpD8wPTELMAkG\nA1UEBhMCVVMxCzAJBgNVBAgTAlVUMSEwHwYDVQQKExhWaWduZXR0ZSBDb3Jwb3Jh\ndGlvbiBTQliCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBjhyRD\nlM7vnLn6drgQVftW5V9nDFAyPAuiGvMIKFSbiAf1PxXCRn5sfJquwWKsJUi4ZGNl\naViXdFmN6/F13PSM+yg63tpKy0fYqMbTM+Oe5WuSHkSW1VuYNHV+24adgNk/FRDL\nFRrlM1f6s9VTLWvwGItjfrof0Ba8Uq7ZDSb9Xg==\n-----END CERTIFICATE-----", - "private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIICXQIBAAKBgQC8fpi06NfVYHAOAnxNMVnTXr/ptsLsNjP+uAt2eO0cc5J9H5XV\n8lFVujOrRu/JWi1TDmAvOaf/6A3BphIA1Pwp0AAqlZdwizIum8j0KzpsGYH5qReN\nQDwF3oUSKMsQCCGCDHrDYifG/pRi9bN1ZVjEXPr35HJuBe+FQpZTs8DewwIDAQAB\nAoGARfNxNknmtx/n1bskZ/01iZRzAge6BLEE0LV6Q4gS7mkRZu/Oyiv39Sl5vUlA\n+WdGxLjkBwKNjxGN8Vxw9/ASd8rSsqeAUYIwAeifXrHhj5DBPQT/pDPkeFnp9B1w\nC6jo+3AbBQ4/b0ONSIEnCL2xGGglSIAxO17T1ViXp7lzXPECQQDe63nkRdWM0OCb\noaHQPT3E26224maIstrGFUdt9yw3yJf4bOF7TtiPLlLuHsTTge3z+fG6ntC0xG56\n1cl37C3ZAkEA2HdVcRGugNp/qmVz4LJTpD+WZKi73PLAO47wDOrYh9Pn2I6fcEH0\nCPnggt1ko4ujvGzFTvRH64HXa6aPCv1j+wJBAMQMah3VQPNf/DlDVFEUmw9XeBZg\nVHaifX851aEjgXLp6qVj9IYCmLiLsAmVa9rr6P7p8asD418nZlaHUHE0eDkCQQCr\nuxis6GMx1Ka971jcJX2X696LoxXPd0KsvXySMupv79yagKPa8mgBiwPjrnK+EPVo\ncj6iochA/bSCshP/mwFrAkBHEKPi6V6gb94JinCT7x3weahbdp6bJ6/nzBH/p9VA\nHoT1JtwNFhGv9BCjmDydshQHfSWpY9NxlccBKL7ITm8R\n-----END RSA PRIVATE KEY-----" - } -} diff --git a/library/oauth2/test/lib/OAuth2/Request/TestRequest.php b/library/oauth2/test/lib/OAuth2/Request/TestRequest.php deleted file mode 100644 index 7bbce28a4..000000000 --- a/library/oauth2/test/lib/OAuth2/Request/TestRequest.php +++ /dev/null @@ -1,61 +0,0 @@ -<?php - -namespace OAuth2\Request; - -use OAuth2\Request; -use OAuth2\RequestInterface; - -/** -* -*/ -class TestRequest extends Request implements RequestInterface -{ - public $query, $request, $server, $headers; - - public function __construct() - { - $this->query = $_GET; - $this->request = $_POST; - $this->server = $_SERVER; - $this->headers = array(); - } - - public function query($name, $default = null) - { - return isset($this->query[$name]) ? $this->query[$name] : $default; - } - - public function request($name, $default = null) - { - return isset($this->request[$name]) ? $this->request[$name] : $default; - } - - public function server($name, $default = null) - { - return isset($this->server[$name]) ? $this->server[$name] : $default; - } - - public function getAllQueryParameters() - { - return $this->query; - } - - public function setQuery(array $query) - { - $this->query = $query; - } - - public function setPost(array $params) - { - $this->server['REQUEST_METHOD'] = 'POST'; - $this->request = $params; - } - - public static function createPost(array $params = array()) - { - $request = new self(); - $request->setPost($params); - - return $request; - } -} diff --git a/library/oauth2/test/lib/OAuth2/Storage/BaseTest.php b/library/oauth2/test/lib/OAuth2/Storage/BaseTest.php deleted file mode 100755 index 921d52500..000000000 --- a/library/oauth2/test/lib/OAuth2/Storage/BaseTest.php +++ /dev/null @@ -1,34 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -abstract class BaseTest extends \PHPUnit_Framework_TestCase -{ - public function provideStorage() - { - $memory = Bootstrap::getInstance()->getMemoryStorage(); - $sqlite = Bootstrap::getInstance()->getSqlitePdo(); - $mysql = Bootstrap::getInstance()->getMysqlPdo(); - $postgres = Bootstrap::getInstance()->getPostgresPdo(); - $mongo = Bootstrap::getInstance()->getMongo(); - $redis = Bootstrap::getInstance()->getRedisStorage(); - $cassandra = Bootstrap::getInstance()->getCassandraStorage(); - $dynamodb = Bootstrap::getInstance()->getDynamoDbStorage(); - $couchbase = Bootstrap::getInstance()->getCouchbase(); - - /* hack until we can fix "default_scope" dependencies in other tests */ - $memory->defaultScope = 'defaultscope1 defaultscope2'; - - return array( - array($memory), - array($sqlite), - array($mysql), - array($postgres), - array($mongo), - array($redis), - array($cassandra), - array($dynamodb), - array($couchbase), - ); - } -} diff --git a/library/oauth2/test/lib/OAuth2/Storage/Bootstrap.php b/library/oauth2/test/lib/OAuth2/Storage/Bootstrap.php deleted file mode 100755 index 4ac9022b1..000000000 --- a/library/oauth2/test/lib/OAuth2/Storage/Bootstrap.php +++ /dev/null @@ -1,888 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -class Bootstrap -{ - const DYNAMODB_PHP_VERSION = 'none'; - - protected static $instance; - private $mysql; - private $sqlite; - private $postgres; - private $mongo; - private $redis; - private $cassandra; - private $configDir; - private $dynamodb; - private $couchbase; - - public function __construct() - { - $this->configDir = __DIR__.'/../../../config'; - } - - public static function getInstance() - { - if (!self::$instance) { - self::$instance = new self(); - } - - return self::$instance; - } - - public function getSqlitePdo() - { - if (!$this->sqlite) { - $this->removeSqliteDb(); - $pdo = new \PDO(sprintf('sqlite://%s', $this->getSqliteDir())); - $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); - $this->createSqliteDb($pdo); - - $this->sqlite = new Pdo($pdo); - } - - return $this->sqlite; - } - - public function getPostgresPdo() - { - if (!$this->postgres) { - if (in_array('pgsql', \PDO::getAvailableDrivers())) { - $this->removePostgresDb(); - $this->createPostgresDb(); - if ($pdo = $this->getPostgresDriver()) { - $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); - $this->populatePostgresDb($pdo); - $this->postgres = new Pdo($pdo); - } - } else { - $this->postgres = new NullStorage('Postgres', 'Missing postgres PDO extension.'); - } - } - - return $this->postgres; - } - - public function getPostgresDriver() - { - try { - $pdo = new \PDO('pgsql:host=localhost;dbname=oauth2_server_php', 'postgres'); - - return $pdo; - } catch (\PDOException $e) { - $this->postgres = new NullStorage('Postgres', $e->getMessage()); - } - } - - public function getMemoryStorage() - { - return new Memory(json_decode(file_get_contents($this->configDir. '/storage.json'), true)); - } - - public function getRedisStorage() - { - if (!$this->redis) { - if (class_exists('Predis\Client')) { - $redis = new \Predis\Client(); - if ($this->testRedisConnection($redis)) { - $redis->flushdb(); - $this->redis = new Redis($redis); - $this->createRedisDb($this->redis); - } else { - $this->redis = new NullStorage('Redis', 'Unable to connect to redis server on port 6379'); - } - } else { - $this->redis = new NullStorage('Redis', 'Missing redis library. Please run "composer.phar require predis/predis:dev-master"'); - } - } - - return $this->redis; - } - - private function testRedisConnection(\Predis\Client $redis) - { - try { - $redis->connect(); - } catch (\Predis\CommunicationException $exception) { - // we were unable to connect to the redis server - return false; - } - - return true; - } - - public function getMysqlPdo() - { - if (!$this->mysql) { - $pdo = null; - try { - $pdo = new \PDO('mysql:host=localhost;', 'root'); - } catch (\PDOException $e) { - $this->mysql = new NullStorage('MySQL', 'Unable to connect to MySQL on root@localhost'); - } - - if ($pdo) { - $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); - $this->removeMysqlDb($pdo); - $this->createMysqlDb($pdo); - - $this->mysql = new Pdo($pdo); - } - } - - return $this->mysql; - } - - public function getMongo() - { - if (!$this->mongo) { - $skipMongo = $this->getEnvVar('SKIP_MONGO_TESTS'); - if (!$skipMongo && class_exists('MongoClient')) { - $mongo = new \MongoClient('mongodb://localhost:27017', array('connect' => false)); - if ($this->testMongoConnection($mongo)) { - $db = $mongo->oauth2_server_php; - $this->removeMongoDb($db); - $this->createMongoDb($db); - - $this->mongo = new Mongo($db); - } else { - $this->mongo = new NullStorage('Mongo', 'Unable to connect to mongo server on "localhost:27017"'); - } - } else { - $this->mongo = new NullStorage('Mongo', 'Missing mongo php extension. Please install mongo.so'); - } - } - - return $this->mongo; - } - - private function testMongoConnection(\MongoClient $mongo) - { - try { - $mongo->connect(); - } catch (\MongoConnectionException $e) { - return false; - } - - return true; - } - - public function getCouchbase() - { - if (!$this->couchbase) { - if ($this->getEnvVar('SKIP_COUCHBASE_TESTS')) { - $this->couchbase = new NullStorage('Couchbase', 'Skipping Couchbase tests'); - } elseif (!class_exists('Couchbase')) { - $this->couchbase = new NullStorage('Couchbase', 'Missing Couchbase php extension. Please install couchbase.so'); - } else { - // round-about way to make sure couchbase is working - // this is required because it throws a "floating point exception" otherwise - $code = "new \Couchbase(array('localhost:8091'), '', '', 'auth', false);"; - $exec = sprintf('php -r "%s"', $code); - $ret = exec($exec, $test, $var); - if ($ret != 0) { - $couchbase = new \Couchbase(array('localhost:8091'), '', '', 'auth', false); - if ($this->testCouchbaseConnection($couchbase)) { - $this->clearCouchbase($couchbase); - $this->createCouchbaseDB($couchbase); - - $this->couchbase = new CouchbaseDB($couchbase); - } else { - $this->couchbase = new NullStorage('Couchbase', 'Unable to connect to Couchbase server on "localhost:8091"'); - } - } else { - $this->couchbase = new NullStorage('Couchbase', 'Error while trying to connect to Couchbase'); - } - } - } - - return $this->couchbase; - } - - private function testCouchbaseConnection(\Couchbase $couchbase) - { - try { - if (count($couchbase->getServers()) > 0) { - return true; - } - } catch (\CouchbaseException $e) { - return false; - } - - return true; - } - - public function getCassandraStorage() - { - if (!$this->cassandra) { - if (class_exists('phpcassa\ColumnFamily')) { - $cassandra = new \phpcassa\Connection\ConnectionPool('oauth2_test', array('127.0.0.1:9160')); - if ($this->testCassandraConnection($cassandra)) { - $this->removeCassandraDb(); - $this->cassandra = new Cassandra($cassandra); - $this->createCassandraDb($this->cassandra); - } else { - $this->cassandra = new NullStorage('Cassandra', 'Unable to connect to cassandra server on "127.0.0.1:9160"'); - } - } else { - $this->cassandra = new NullStorage('Cassandra', 'Missing cassandra library. Please run "composer.phar require thobbs/phpcassa:dev-master"'); - } - } - - return $this->cassandra; - } - - private function testCassandraConnection(\phpcassa\Connection\ConnectionPool $cassandra) - { - try { - new \phpcassa\SystemManager('localhost:9160'); - } catch (\Exception $e) { - return false; - } - - return true; - } - - private function removeCassandraDb() - { - $sys = new \phpcassa\SystemManager('localhost:9160'); - - try { - $sys->drop_keyspace('oauth2_test'); - } catch (\cassandra\InvalidRequestException $e) { - - } - } - - private function createCassandraDb(Cassandra $storage) - { - // create the cassandra keyspace and column family - $sys = new \phpcassa\SystemManager('localhost:9160'); - - $sys->create_keyspace('oauth2_test', array( - "strategy_class" => \phpcassa\Schema\StrategyClass::SIMPLE_STRATEGY, - "strategy_options" => array('replication_factor' => '1') - )); - - $sys->create_column_family('oauth2_test', 'auth'); - $cassandra = new \phpcassa\Connection\ConnectionPool('oauth2_test', array('127.0.0.1:9160')); - $cf = new \phpcassa\ColumnFamily($cassandra, 'auth'); - - // populate the data - $storage->setClientDetails("oauth_test_client", "testpass", "http://example.com", 'implicit password'); - $storage->setAccessToken("testtoken", "Some Client", '', time() + 1000); - $storage->setAuthorizationCode("testcode", "Some Client", '', '', time() + 1000); - - $storage->setScope('supportedscope1 supportedscope2 supportedscope3 supportedscope4'); - $storage->setScope('defaultscope1 defaultscope2', null, 'default'); - - $storage->setScope('clientscope1 clientscope2', 'Test Client ID'); - $storage->setScope('clientscope1 clientscope2', 'Test Client ID', 'default'); - - $storage->setScope('clientscope1 clientscope2 clientscope3', 'Test Client ID 2'); - $storage->setScope('clientscope1 clientscope2', 'Test Client ID 2', 'default'); - - $storage->setScope('clientscope1 clientscope2', 'Test Default Scope Client ID'); - $storage->setScope('clientscope1 clientscope2', 'Test Default Scope Client ID', 'default'); - - $storage->setScope('clientscope1 clientscope2 clientscope3', 'Test Default Scope Client ID 2'); - $storage->setScope('clientscope3', 'Test Default Scope Client ID 2', 'default'); - - $storage->setClientKey('oauth_test_client', $this->getTestPublicKey(), 'test_subject'); - - $cf->insert("oauth_public_keys:ClientID_One", array('__data' => json_encode(array("public_key" => "client_1_public", "private_key" => "client_1_private", "encryption_algorithm" => "RS256")))); - $cf->insert("oauth_public_keys:ClientID_Two", array('__data' => json_encode(array("public_key" => "client_2_public", "private_key" => "client_2_private", "encryption_algorithm" => "RS256")))); - $cf->insert("oauth_public_keys:", array('__data' => json_encode(array("public_key" => $this->getTestPublicKey(), "private_key" => $this->getTestPrivateKey(), "encryption_algorithm" => "RS256")))); - - $cf->insert("oauth_users:testuser", array('__data' =>json_encode(array("password" => "password", "email" => "testuser@test.com", "email_verified" => true)))); - - } - - private function createSqliteDb(\PDO $pdo) - { - $this->runPdoSql($pdo); - } - - private function removeSqliteDb() - { - if (file_exists($this->getSqliteDir())) { - unlink($this->getSqliteDir()); - } - } - - private function createMysqlDb(\PDO $pdo) - { - $pdo->exec('CREATE DATABASE oauth2_server_php'); - $pdo->exec('USE oauth2_server_php'); - $this->runPdoSql($pdo); - } - - private function removeMysqlDb(\PDO $pdo) - { - $pdo->exec('DROP DATABASE IF EXISTS oauth2_server_php'); - } - - private function createPostgresDb() - { - if (!`psql postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='postgres'"`) { - `createuser -s -r postgres`; - } - - `createdb -O postgres oauth2_server_php`; - } - - private function populatePostgresDb(\PDO $pdo) - { - $this->runPdoSql($pdo); - } - - private function removePostgresDb() - { - if (trim(`psql -l | grep oauth2_server_php | wc -l`)) { - `dropdb oauth2_server_php`; - } - } - - public function runPdoSql(\PDO $pdo) - { - $storage = new Pdo($pdo); - foreach (explode(';', $storage->getBuildSql()) as $statement) { - $result = $pdo->exec($statement); - } - - // set up scopes - $sql = 'INSERT INTO oauth_scopes (scope) VALUES (?)'; - foreach (explode(' ', 'supportedscope1 supportedscope2 supportedscope3 supportedscope4 clientscope1 clientscope2 clientscope3') as $supportedScope) { - $pdo->prepare($sql)->execute(array($supportedScope)); - } - - $sql = 'INSERT INTO oauth_scopes (scope, is_default) VALUES (?, ?)'; - foreach (array('defaultscope1', 'defaultscope2') as $defaultScope) { - $pdo->prepare($sql)->execute(array($defaultScope, true)); - } - - // set up clients - $sql = 'INSERT INTO oauth_clients (client_id, client_secret, scope, grant_types) VALUES (?, ?, ?, ?)'; - $pdo->prepare($sql)->execute(array('Test Client ID', 'TestSecret', 'clientscope1 clientscope2', null)); - $pdo->prepare($sql)->execute(array('Test Client ID 2', 'TestSecret', 'clientscope1 clientscope2 clientscope3', null)); - $pdo->prepare($sql)->execute(array('Test Default Scope Client ID', 'TestSecret', 'clientscope1 clientscope2', null)); - $pdo->prepare($sql)->execute(array('oauth_test_client', 'testpass', null, 'implicit password')); - - // set up misc - $sql = 'INSERT INTO oauth_access_tokens (access_token, client_id, expires, user_id) VALUES (?, ?, ?, ?)'; - $pdo->prepare($sql)->execute(array('testtoken', 'Some Client', date('Y-m-d H:i:s', strtotime('+1 hour')), null)); - $pdo->prepare($sql)->execute(array('accesstoken-openid-connect', 'Some Client', date('Y-m-d H:i:s', strtotime('+1 hour')), 'testuser')); - - $sql = 'INSERT INTO oauth_authorization_codes (authorization_code, client_id, expires) VALUES (?, ?, ?)'; - $pdo->prepare($sql)->execute(array('testcode', 'Some Client', date('Y-m-d H:i:s', strtotime('+1 hour')))); - - $sql = 'INSERT INTO oauth_users (username, password, email, email_verified) VALUES (?, ?, ?, ?)'; - $pdo->prepare($sql)->execute(array('testuser', 'password', 'testuser@test.com', true)); - - $sql = 'INSERT INTO oauth_public_keys (client_id, public_key, private_key, encryption_algorithm) VALUES (?, ?, ?, ?)'; - $pdo->prepare($sql)->execute(array('ClientID_One', 'client_1_public', 'client_1_private', 'RS256')); - $pdo->prepare($sql)->execute(array('ClientID_Two', 'client_2_public', 'client_2_private', 'RS256')); - - $sql = 'INSERT INTO oauth_public_keys (client_id, public_key, private_key, encryption_algorithm) VALUES (?, ?, ?, ?)'; - $pdo->prepare($sql)->execute(array(null, $this->getTestPublicKey(), $this->getTestPrivateKey(), 'RS256')); - - $sql = 'INSERT INTO oauth_jwt (client_id, subject, public_key) VALUES (?, ?, ?)'; - $pdo->prepare($sql)->execute(array('oauth_test_client', 'test_subject', $this->getTestPublicKey())); - } - - public function getSqliteDir() - { - return $this->configDir. '/test.sqlite'; - } - - public function getConfigDir() - { - return $this->configDir; - } - - private function createCouchbaseDB(\Couchbase $db) - { - $db->set('oauth_clients-oauth_test_client',json_encode(array( - 'client_id' => "oauth_test_client", - 'client_secret' => "testpass", - 'redirect_uri' => "http://example.com", - 'grant_types' => 'implicit password' - ))); - - $db->set('oauth_access_tokens-testtoken',json_encode(array( - 'access_token' => "testtoken", - 'client_id' => "Some Client" - ))); - - $db->set('oauth_authorization_codes-testcode',json_encode(array( - 'access_token' => "testcode", - 'client_id' => "Some Client" - ))); - - $db->set('oauth_users-testuser',json_encode(array( - 'username' => 'testuser', - 'password' => 'password', - 'email' => 'testuser@test.com', - 'email_verified' => true, - ))); - - $db->set('oauth_jwt-oauth_test_client',json_encode(array( - 'client_id' => 'oauth_test_client', - 'key' => $this->getTestPublicKey(), - 'subject' => 'test_subject', - ))); - } - - private function clearCouchbase(\Couchbase $cb) - { - $cb->delete('oauth_authorization_codes-new-openid-code'); - $cb->delete('oauth_access_tokens-newtoken'); - $cb->delete('oauth_authorization_codes-newcode'); - $cb->delete('oauth_refresh_tokens-refreshtoken'); - } - - private function createMongoDb(\MongoDB $db) - { - $db->oauth_clients->insert(array( - 'client_id' => "oauth_test_client", - 'client_secret' => "testpass", - 'redirect_uri' => "http://example.com", - 'grant_types' => 'implicit password' - )); - - $db->oauth_access_tokens->insert(array( - 'access_token' => "testtoken", - 'client_id' => "Some Client" - )); - - $db->oauth_authorization_codes->insert(array( - 'authorization_code' => "testcode", - 'client_id' => "Some Client" - )); - - $db->oauth_users->insert(array( - 'username' => 'testuser', - 'password' => 'password', - 'email' => 'testuser@test.com', - 'email_verified' => true, - )); - - $db->oauth_jwt->insert(array( - 'client_id' => 'oauth_test_client', - 'key' => $this->getTestPublicKey(), - 'subject' => 'test_subject', - )); - } - - private function createRedisDb(Redis $storage) - { - $storage->setClientDetails("oauth_test_client", "testpass", "http://example.com", 'implicit password'); - $storage->setAccessToken("testtoken", "Some Client", '', time() + 1000); - $storage->setAuthorizationCode("testcode", "Some Client", '', '', time() + 1000); - $storage->setUser("testuser", "password"); - - $storage->setScope('supportedscope1 supportedscope2 supportedscope3 supportedscope4'); - $storage->setScope('defaultscope1 defaultscope2', null, 'default'); - - $storage->setScope('clientscope1 clientscope2', 'Test Client ID'); - $storage->setScope('clientscope1 clientscope2', 'Test Client ID', 'default'); - - $storage->setScope('clientscope1 clientscope2 clientscope3', 'Test Client ID 2'); - $storage->setScope('clientscope1 clientscope2', 'Test Client ID 2', 'default'); - - $storage->setScope('clientscope1 clientscope2', 'Test Default Scope Client ID'); - $storage->setScope('clientscope1 clientscope2', 'Test Default Scope Client ID', 'default'); - - $storage->setScope('clientscope1 clientscope2 clientscope3', 'Test Default Scope Client ID 2'); - $storage->setScope('clientscope3', 'Test Default Scope Client ID 2', 'default'); - - $storage->setClientKey('oauth_test_client', $this->getTestPublicKey(), 'test_subject'); - } - - public function removeMongoDb(\MongoDB $db) - { - $db->drop(); - } - - public function getTestPublicKey() - { - return file_get_contents(__DIR__.'/../../../config/keys/id_rsa.pub'); - } - - private function getTestPrivateKey() - { - return file_get_contents(__DIR__.'/../../../config/keys/id_rsa'); - } - - public function getDynamoDbStorage() - { - if (!$this->dynamodb) { - // only run once per travis build - if (true == $this->getEnvVar('TRAVIS')) { - if (self::DYNAMODB_PHP_VERSION != $this->getEnvVar('TRAVIS_PHP_VERSION')) { - $this->dynamodb = new NullStorage('DynamoDb', 'Skipping for travis.ci - only run once per build'); - - return; - } - } - if (class_exists('\Aws\DynamoDb\DynamoDbClient')) { - if ($client = $this->getDynamoDbClient()) { - // travis runs a unique set of tables per build, to avoid conflict - $prefix = ''; - if ($build_id = $this->getEnvVar('TRAVIS_JOB_NUMBER')) { - $prefix = sprintf('build_%s_', $build_id); - } else { - if (!$this->deleteDynamoDb($client, $prefix, true)) { - return $this->dynamodb = new NullStorage('DynamoDb', 'Timed out while waiting for DynamoDB deletion (30 seconds)'); - } - } - $this->createDynamoDb($client, $prefix); - $this->populateDynamoDb($client, $prefix); - $config = array( - 'client_table' => $prefix.'oauth_clients', - 'access_token_table' => $prefix.'oauth_access_tokens', - 'refresh_token_table' => $prefix.'oauth_refresh_tokens', - 'code_table' => $prefix.'oauth_authorization_codes', - 'user_table' => $prefix.'oauth_users', - 'jwt_table' => $prefix.'oauth_jwt', - 'scope_table' => $prefix.'oauth_scopes', - 'public_key_table' => $prefix.'oauth_public_keys', - ); - $this->dynamodb = new DynamoDB($client, $config); - } elseif (!$this->dynamodb) { - $this->dynamodb = new NullStorage('DynamoDb', 'unable to connect to DynamoDB'); - } - } else { - $this->dynamodb = new NullStorage('DynamoDb', 'Missing DynamoDB library. Please run "composer.phar require aws/aws-sdk-php:dev-master'); - } - } - - return $this->dynamodb; - } - - private function getDynamoDbClient() - { - $config = array(); - // check for environment variables - if (($key = $this->getEnvVar('AWS_ACCESS_KEY_ID')) && ($secret = $this->getEnvVar('AWS_SECRET_KEY'))) { - $config['key'] = $key; - $config['secret'] = $secret; - } else { - // fall back on ~/.aws/credentials file - // @see http://docs.aws.amazon.com/aws-sdk-php/guide/latest/credentials.html#credential-profiles - if (!file_exists($this->getEnvVar('HOME') . '/.aws/credentials')) { - $this->dynamodb = new NullStorage('DynamoDb', 'No aws credentials file found, and no AWS_ACCESS_KEY_ID or AWS_SECRET_KEY environment variable set'); - - return; - } - - // set profile in AWS_PROFILE environment variable, defaults to "default" - $config['profile'] = $this->getEnvVar('AWS_PROFILE', 'default'); - } - - // set region in AWS_REGION environment variable, defaults to "us-east-1" - $config['region'] = $this->getEnvVar('AWS_REGION', \Aws\Common\Enum\Region::US_EAST_1); - - return \Aws\DynamoDb\DynamoDbClient::factory($config); - } - - private function deleteDynamoDb(\Aws\DynamoDb\DynamoDbClient $client, $prefix = null, $waitForDeletion = false) - { - $tablesList = explode(' ', 'oauth_access_tokens oauth_authorization_codes oauth_clients oauth_jwt oauth_public_keys oauth_refresh_tokens oauth_scopes oauth_users'); - $nbTables = count($tablesList); - - // Delete all table. - foreach ($tablesList as $key => $table) { - try { - $client->deleteTable(array('TableName' => $prefix.$table)); - } catch (\Aws\DynamoDb\Exception\DynamoDbException $e) { - // Table does not exist : nothing to do - } - } - - // Wait for deleting - if ($waitForDeletion) { - $retries = 5; - $nbTableDeleted = 0; - while ($nbTableDeleted != $nbTables) { - $nbTableDeleted = 0; - foreach ($tablesList as $key => $table) { - try { - $result = $client->describeTable(array('TableName' => $prefix.$table)); - } catch (\Aws\DynamoDb\Exception\DynamoDbException $e) { - // Table does not exist : nothing to do - $nbTableDeleted++; - } - } - if ($nbTableDeleted != $nbTables) { - if ($retries < 0) { - // we are tired of waiting - return false; - } - sleep(5); - echo "Sleeping 5 seconds for DynamoDB ($retries more retries)...\n"; - $retries--; - } - } - } - - return true; - } - - private function createDynamoDb(\Aws\DynamoDb\DynamoDbClient $client, $prefix = null) - { - $tablesList = explode(' ', 'oauth_access_tokens oauth_authorization_codes oauth_clients oauth_jwt oauth_public_keys oauth_refresh_tokens oauth_scopes oauth_users'); - $nbTables = count($tablesList); - $client->createTable(array( - 'TableName' => $prefix.'oauth_access_tokens', - 'AttributeDefinitions' => array( - array('AttributeName' => 'access_token','AttributeType' => 'S') - ), - 'KeySchema' => array(array('AttributeName' => 'access_token','KeyType' => 'HASH')), - 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) - )); - - $client->createTable(array( - 'TableName' => $prefix.'oauth_authorization_codes', - 'AttributeDefinitions' => array( - array('AttributeName' => 'authorization_code','AttributeType' => 'S') - ), - 'KeySchema' => array(array('AttributeName' => 'authorization_code','KeyType' => 'HASH')), - 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) - )); - - $client->createTable(array( - 'TableName' => $prefix.'oauth_clients', - 'AttributeDefinitions' => array( - array('AttributeName' => 'client_id','AttributeType' => 'S') - ), - 'KeySchema' => array(array('AttributeName' => 'client_id','KeyType' => 'HASH')), - 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) - )); - - $client->createTable(array( - 'TableName' => $prefix.'oauth_jwt', - 'AttributeDefinitions' => array( - array('AttributeName' => 'client_id','AttributeType' => 'S'), - array('AttributeName' => 'subject','AttributeType' => 'S') - ), - 'KeySchema' => array( - array('AttributeName' => 'client_id','KeyType' => 'HASH'), - array('AttributeName' => 'subject','KeyType' => 'RANGE') - ), - 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) - )); - - $client->createTable(array( - 'TableName' => $prefix.'oauth_public_keys', - 'AttributeDefinitions' => array( - array('AttributeName' => 'client_id','AttributeType' => 'S') - ), - 'KeySchema' => array(array('AttributeName' => 'client_id','KeyType' => 'HASH')), - 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) - )); - - $client->createTable(array( - 'TableName' => $prefix.'oauth_refresh_tokens', - 'AttributeDefinitions' => array( - array('AttributeName' => 'refresh_token','AttributeType' => 'S') - ), - 'KeySchema' => array(array('AttributeName' => 'refresh_token','KeyType' => 'HASH')), - 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) - )); - - $client->createTable(array( - 'TableName' => $prefix.'oauth_scopes', - 'AttributeDefinitions' => array( - array('AttributeName' => 'scope','AttributeType' => 'S'), - array('AttributeName' => 'is_default','AttributeType' => 'S') - ), - 'KeySchema' => array(array('AttributeName' => 'scope','KeyType' => 'HASH')), - 'GlobalSecondaryIndexes' => array( - array( - 'IndexName' => 'is_default-index', - 'KeySchema' => array(array('AttributeName' => 'is_default', 'KeyType' => 'HASH')), - 'Projection' => array('ProjectionType' => 'ALL'), - 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) - ), - ), - 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) - )); - - $client->createTable(array( - 'TableName' => $prefix.'oauth_users', - 'AttributeDefinitions' => array(array('AttributeName' => 'username','AttributeType' => 'S')), - 'KeySchema' => array(array('AttributeName' => 'username','KeyType' => 'HASH')), - 'ProvisionedThroughput' => array('ReadCapacityUnits' => 1,'WriteCapacityUnits' => 1) - )); - - // Wait for creation - $nbTableCreated = 0; - while ($nbTableCreated != $nbTables) { - $nbTableCreated = 0; - foreach ($tablesList as $key => $table) { - try { - $result = $client->describeTable(array('TableName' => $prefix.$table)); - if ($result['Table']['TableStatus'] == 'ACTIVE') { - $nbTableCreated++; - } - } catch (\Aws\DynamoDb\Exception\DynamoDbException $e) { - // Table does not exist : nothing to do - $nbTableCreated++; - } - } - if ($nbTableCreated != $nbTables) { - sleep(1); - } - } - } - - private function populateDynamoDb($client, $prefix = null) - { - // set up scopes - foreach (explode(' ', 'supportedscope1 supportedscope2 supportedscope3 supportedscope4 clientscope1 clientscope2 clientscope3') as $supportedScope) { - $client->putItem(array( - 'TableName' => $prefix.'oauth_scopes', - 'Item' => array('scope' => array('S' => $supportedScope)) - )); - } - - foreach (array('defaultscope1', 'defaultscope2') as $defaultScope) { - $client->putItem(array( - 'TableName' => $prefix.'oauth_scopes', - 'Item' => array('scope' => array('S' => $defaultScope), 'is_default' => array('S' => "true")) - )); - } - - $client->putItem(array( - 'TableName' => $prefix.'oauth_clients', - 'Item' => array( - 'client_id' => array('S' => 'Test Client ID'), - 'client_secret' => array('S' => 'TestSecret'), - 'scope' => array('S' => 'clientscope1 clientscope2') - ) - )); - - $client->putItem(array( - 'TableName' => $prefix.'oauth_clients', - 'Item' => array( - 'client_id' => array('S' => 'Test Client ID 2'), - 'client_secret' => array('S' => 'TestSecret'), - 'scope' => array('S' => 'clientscope1 clientscope2 clientscope3') - ) - )); - - $client->putItem(array( - 'TableName' => $prefix.'oauth_clients', - 'Item' => array( - 'client_id' => array('S' => 'Test Default Scope Client ID'), - 'client_secret' => array('S' => 'TestSecret'), - 'scope' => array('S' => 'clientscope1 clientscope2') - ) - )); - - $client->putItem(array( - 'TableName' => $prefix.'oauth_clients', - 'Item' => array( - 'client_id' => array('S' => 'oauth_test_client'), - 'client_secret' => array('S' => 'testpass'), - 'grant_types' => array('S' => 'implicit password') - ) - )); - - $client->putItem(array( - 'TableName' => $prefix.'oauth_access_tokens', - 'Item' => array( - 'access_token' => array('S' => 'testtoken'), - 'client_id' => array('S' => 'Some Client'), - ) - )); - - $client->putItem(array( - 'TableName' => $prefix.'oauth_access_tokens', - 'Item' => array( - 'access_token' => array('S' => 'accesstoken-openid-connect'), - 'client_id' => array('S' => 'Some Client'), - 'user_id' => array('S' => 'testuser'), - ) - )); - - $client->putItem(array( - 'TableName' => $prefix.'oauth_authorization_codes', - 'Item' => array( - 'authorization_code' => array('S' => 'testcode'), - 'client_id' => array('S' => 'Some Client'), - ) - )); - - $client->putItem(array( - 'TableName' => $prefix.'oauth_users', - 'Item' => array( - 'username' => array('S' => 'testuser'), - 'password' => array('S' => 'password'), - 'email' => array('S' => 'testuser@test.com'), - 'email_verified' => array('S' => 'true'), - ) - )); - - $client->putItem(array( - 'TableName' => $prefix.'oauth_public_keys', - 'Item' => array( - 'client_id' => array('S' => 'ClientID_One'), - 'public_key' => array('S' => 'client_1_public'), - 'private_key' => array('S' => 'client_1_private'), - 'encryption_algorithm' => array('S' => 'RS256'), - ) - )); - - $client->putItem(array( - 'TableName' => $prefix.'oauth_public_keys', - 'Item' => array( - 'client_id' => array('S' => 'ClientID_Two'), - 'public_key' => array('S' => 'client_2_public'), - 'private_key' => array('S' => 'client_2_private'), - 'encryption_algorithm' => array('S' => 'RS256'), - ) - )); - - $client->putItem(array( - 'TableName' => $prefix.'oauth_public_keys', - 'Item' => array( - 'client_id' => array('S' => '0'), - 'public_key' => array('S' => $this->getTestPublicKey()), - 'private_key' => array('S' => $this->getTestPrivateKey()), - 'encryption_algorithm' => array('S' => 'RS256'), - ) - )); - - $client->putItem(array( - 'TableName' => $prefix.'oauth_jwt', - 'Item' => array( - 'client_id' => array('S' => 'oauth_test_client'), - 'subject' => array('S' => 'test_subject'), - 'public_key' => array('S' => $this->getTestPublicKey()), - ) - )); - } - - public function cleanupTravisDynamoDb($prefix = null) - { - if (is_null($prefix)) { - // skip this when not applicable - if (!$this->getEnvVar('TRAVIS') || self::DYNAMODB_PHP_VERSION != $this->getEnvVar('TRAVIS_PHP_VERSION')) { - return; - } - - $prefix = sprintf('build_%s_', $this->getEnvVar('TRAVIS_JOB_NUMBER')); - } - - $client = $this->getDynamoDbClient(); - $this->deleteDynamoDb($client, $prefix); - } - - private function getEnvVar($var, $default = null) - { - return isset($_SERVER[$var]) ? $_SERVER[$var] : (getenv($var) ?: $default); - } -} diff --git a/library/oauth2/test/lib/OAuth2/Storage/NullStorage.php b/library/oauth2/test/lib/OAuth2/Storage/NullStorage.php deleted file mode 100644 index 6caa62068..000000000 --- a/library/oauth2/test/lib/OAuth2/Storage/NullStorage.php +++ /dev/null @@ -1,32 +0,0 @@ -<?php - -namespace OAuth2\Storage; - -/** -* -*/ -class NullStorage extends Memory -{ - private $name; - private $description; - - public function __construct($name, $description = null) - { - $this->name = $name; - $this->description = $description; - } - - public function __toString() - { - return $this->name; - } - - public function getMessage() - { - if ($this->description) { - return $this->description; - } - - return $this->name; - } -} diff --git a/tests/unit/includes/TextTest.php b/tests/unit/includes/TextTest.php index 4afa2b49b..acc490001 100644 --- a/tests/unit/includes/TextTest.php +++ b/tests/unit/includes/TextTest.php @@ -11,27 +11,7 @@ use Zotlabs\Tests\Unit\UnitTestCase; */ class TextTest extends UnitTestCase { - /** - * @covers ::valid_email_regex - */ - public function testGoodEmail() { - $this->assertTrue(valid_email_regex('ken@spaz.org')); - $this->assertTrue(valid_email_regex('ken@restivo.org')); - $this->assertTrue(valid_email_regex('nobody@hubzilla.org')); - $this->assertTrue(valid_email_regex('foo+nobody@hubzilla.org')); - } - - /** - * @covers ::valid_email_regex - */ - public function testBadEmail() { - $this->assertFalse(valid_email_regex('nobody!uses!these!any.more')); - $this->assertFalse(valid_email_regex('foo@bar@hubzilla.org')); - } - /** - * @covers ::purify_html - */ public function testPurifyHTML() { // linebreaks $htmlbr = 'first line<br /> diff --git a/util/hmessages.po b/util/hmessages.po index 3dd3a22cc..43ce90835 100644 --- a/util/hmessages.po +++ b/util/hmessages.po @@ -1,14 +1,20 @@ -# hubzilla -# Copyright (C) 2012-2016 hubzilla -# This file is distributed under the same license as the hubzilla package. +# red +# Copyright (C) 2012-2016 red +# This file is distributed under the same license as the red package. # Mike Macgirvin, 2012 # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: 2.5.3\n" +<<<<<<< HEAD +"Project-Id-Version: 5.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-06-20 12:03+0200\n" +"POT-Creation-Date: 2017-04-07 00:05-0700\n" +======= +"Project-Id-Version: 2.3.5\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-05-01 15:36+0200\n" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,162 +23,154 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../../Zotlabs/Access/Permissions.php:53 -msgid "Can view my channel stream and posts" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:54 ../../include/permissions.php:42 -msgid "Can send me their channel stream and posts" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:55 ../../include/permissions.php:36 -msgid "Can view my default channel profile" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:56 ../../include/permissions.php:37 -msgid "Can view my connections" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:57 ../../include/permissions.php:38 -msgid "Can view my file storage and photos" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:58 -msgid "Can upload/modify my file storage and photos" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:59 -msgid "Can view my channel webpages" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:60 -msgid "Can view my wiki pages" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:61 -msgid "Can create/edit my channel webpages" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:62 -msgid "Can write to my wiki pages" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:63 -msgid "Can post on my channel (wall) page" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:64 ../../include/permissions.php:44 -msgid "Can comment on or like my posts" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:65 ../../include/permissions.php:45 -msgid "Can send me private mail messages" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:66 -msgid "Can like/dislike profiles and profile things" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:67 -msgid "Can forward to all my channel connections via @+ mentions in posts" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:68 -msgid "Can chat with me" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:69 ../../include/permissions.php:53 -msgid "Can source my public posts in derived channels" -msgstr "" - -#: ../../Zotlabs/Access/Permissions.php:70 -msgid "Can administer my channel" -msgstr "" - #: ../../Zotlabs/Access/PermissionRoles.php:248 +<<<<<<< HEAD +======= #: ../../include/permissions.php:946 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "Social Networking" msgstr "" #: ../../Zotlabs/Access/PermissionRoles.php:249 +<<<<<<< HEAD +======= #: ../../include/permissions.php:946 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "Social - Mostly Public" msgstr "" #: ../../Zotlabs/Access/PermissionRoles.php:250 +<<<<<<< HEAD +======= #: ../../include/permissions.php:946 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "Social - Restricted" msgstr "" #: ../../Zotlabs/Access/PermissionRoles.php:251 +<<<<<<< HEAD +======= #: ../../include/permissions.php:946 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "Social - Private" msgstr "" #: ../../Zotlabs/Access/PermissionRoles.php:254 +<<<<<<< HEAD +======= #: ../../include/permissions.php:947 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "Community Forum" msgstr "" #: ../../Zotlabs/Access/PermissionRoles.php:255 +<<<<<<< HEAD +======= #: ../../include/permissions.php:947 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "Forum - Mostly Public" msgstr "" #: ../../Zotlabs/Access/PermissionRoles.php:256 +<<<<<<< HEAD +======= #: ../../include/permissions.php:947 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "Forum - Restricted" msgstr "" #: ../../Zotlabs/Access/PermissionRoles.php:257 +<<<<<<< HEAD +======= #: ../../include/permissions.php:947 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "Forum - Private" msgstr "" #: ../../Zotlabs/Access/PermissionRoles.php:260 +<<<<<<< HEAD +======= #: ../../include/permissions.php:948 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "Feed Republish" msgstr "" #: ../../Zotlabs/Access/PermissionRoles.php:261 +<<<<<<< HEAD +======= #: ../../include/permissions.php:948 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "Feed - Mostly Public" msgstr "" #: ../../Zotlabs/Access/PermissionRoles.php:262 +<<<<<<< HEAD +======= #: ../../include/permissions.php:948 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "Feed - Restricted" msgstr "" #: ../../Zotlabs/Access/PermissionRoles.php:265 +<<<<<<< HEAD +======= #: ../../include/permissions.php:949 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "Special Purpose" msgstr "" #: ../../Zotlabs/Access/PermissionRoles.php:266 +<<<<<<< HEAD +======= #: ../../include/permissions.php:949 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "Special - Celebrity/Soapbox" msgstr "" #: ../../Zotlabs/Access/PermissionRoles.php:267 +<<<<<<< HEAD +======= #: ../../include/permissions.php:949 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "Special - Group Repository" msgstr "" #: ../../Zotlabs/Access/PermissionRoles.php:270 +#: ../../Zotlabs/Module/Register.php:213 ../../Zotlabs/Module/Profiles.php:798 #: ../../Zotlabs/Module/New_channel.php:132 +#: ../../Zotlabs/Module/Connedit.php:914 #: ../../Zotlabs/Module/Settings/Channel.php:463 +<<<<<<< HEAD +#: ../../extend/addon/addon/cdav/cdav.php:277 +#: ../../extend/addon/addon/cdav/cdav.php:284 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1148 +#: ../../include/connections.php:675 ../../include/connections.php:682 +#: ../../include/selectors.php:49 ../../include/selectors.php:66 +#: ../../include/selectors.php:104 ../../include/selectors.php:140 +======= #: ../../Zotlabs/Module/Connedit.php:914 ../../Zotlabs/Module/Profiles.php:798 #: ../../Zotlabs/Module/Register.php:213 ../../addon/cdav/Mod_Cdav.php:1148 #: ../../addon/cdav/cdav.php:277 ../../addon/cdav/cdav.php:284 #: ../../include/selectors.php:49 ../../include/selectors.php:66 #: ../../include/selectors.php:104 ../../include/selectors.php:140 -#: ../../include/permissions.php:950 ../../include/connections.php:681 -#: ../../include/connections.php:688 +#: ../../include/permissions.php:950 ../../include/connections.php:675 +#: ../../include/connections.php:682 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "Other" msgstr "" #: ../../Zotlabs/Access/PermissionRoles.php:271 +<<<<<<< HEAD +msgid "Custom/Expert Mode" +msgstr "" + +#: ../../Zotlabs/Access/Permissions.php:46 +msgid "Can view my channel stream and posts" +msgstr "" + +#: ../../Zotlabs/Access/Permissions.php:47 +msgid "Can send me their channel stream and posts" +======= #: ../../include/permissions.php:950 msgid "Custom/Expert Mode" msgstr "" @@ -182,7 +180,7 @@ msgstr "" #: ../../Zotlabs/Module/Hcard.php:12 ../../Zotlabs/Module/Editblock.php:31 #: ../../Zotlabs/Module/Profile.php:20 ../../Zotlabs/Module/Layouts.php:31 #: ../../Zotlabs/Module/Editwebpage.php:32 ../../Zotlabs/Module/Webpages.php:33 -#: ../../Zotlabs/Module/Filestorage.php:59 ../../include/channel.php:959 +#: ../../Zotlabs/Module/Filestorage.php:59 ../../include/channel.php:945 msgid "Requested profile is not available." msgstr "" @@ -197,7 +195,6 @@ msgstr "" #: ../../Zotlabs/Module/New_channel.php:77 #: ../../Zotlabs/Module/New_channel.php:104 #: ../../Zotlabs/Module/Sharedwithme.php:11 ../../Zotlabs/Module/Setup.php:212 -#: ../../Zotlabs/Module/Moderate.php:13 #: ../../Zotlabs/Module/Achievements.php:34 ../../Zotlabs/Module/Thing.php:274 #: ../../Zotlabs/Module/Thing.php:294 ../../Zotlabs/Module/Thing.php:335 #: ../../Zotlabs/Module/Api.php:24 ../../Zotlabs/Module/Editblock.php:67 @@ -205,19 +202,18 @@ msgstr "" #: ../../Zotlabs/Module/Mood.php:116 ../../Zotlabs/Module/Connections.php:29 #: ../../Zotlabs/Module/Viewsrc.php:19 ../../Zotlabs/Module/Bookmarks.php:61 #: ../../Zotlabs/Module/Photos.php:69 ../../Zotlabs/Module/Wiki.php:50 -#: ../../Zotlabs/Module/Wiki.php:233 ../../Zotlabs/Module/Wiki.php:339 +#: ../../Zotlabs/Module/Wiki.php:216 ../../Zotlabs/Module/Wiki.php:315 #: ../../Zotlabs/Module/Pdledit.php:29 ../../Zotlabs/Module/Poke.php:137 #: ../../Zotlabs/Module/Profile_photo.php:280 #: ../../Zotlabs/Module/Profile_photo.php:293 -#: ../../Zotlabs/Module/Authtest.php:16 ../../Zotlabs/Module/Item.php:223 -#: ../../Zotlabs/Module/Item.php:240 ../../Zotlabs/Module/Item.php:250 -#: ../../Zotlabs/Module/Item.php:1071 ../../Zotlabs/Module/Page.php:35 -#: ../../Zotlabs/Module/Page.php:126 ../../Zotlabs/Module/Connedit.php:385 -#: ../../Zotlabs/Module/Chat.php:98 ../../Zotlabs/Module/Chat.php:103 -#: ../../Zotlabs/Module/Menu.php:78 ../../Zotlabs/Module/Layouts.php:71 -#: ../../Zotlabs/Module/Layouts.php:78 ../../Zotlabs/Module/Layouts.php:89 -#: ../../Zotlabs/Module/Group.php:13 ../../Zotlabs/Module/Profiles.php:198 -#: ../../Zotlabs/Module/Profiles.php:635 +#: ../../Zotlabs/Module/Authtest.php:16 ../../Zotlabs/Module/Item.php:221 +#: ../../Zotlabs/Module/Item.php:231 ../../Zotlabs/Module/Item.php:1038 +#: ../../Zotlabs/Module/Page.php:35 ../../Zotlabs/Module/Page.php:91 +#: ../../Zotlabs/Module/Connedit.php:385 ../../Zotlabs/Module/Chat.php:98 +#: ../../Zotlabs/Module/Chat.php:103 ../../Zotlabs/Module/Menu.php:78 +#: ../../Zotlabs/Module/Layouts.php:71 ../../Zotlabs/Module/Layouts.php:78 +#: ../../Zotlabs/Module/Layouts.php:89 ../../Zotlabs/Module/Group.php:13 +#: ../../Zotlabs/Module/Profiles.php:198 ../../Zotlabs/Module/Profiles.php:635 #: ../../Zotlabs/Module/Editwebpage.php:68 #: ../../Zotlabs/Module/Editwebpage.php:89 #: ../../Zotlabs/Module/Editwebpage.php:107 @@ -226,7 +222,7 @@ msgstr "" #: ../../Zotlabs/Module/Block.php:76 ../../Zotlabs/Module/Editpost.php:17 #: ../../Zotlabs/Module/Sources.php:74 ../../Zotlabs/Module/Like.php:181 #: ../../Zotlabs/Module/Suggest.php:28 ../../Zotlabs/Module/Message.php:18 -#: ../../Zotlabs/Module/Mail.php:146 ../../Zotlabs/Module/Register.php:77 +#: ../../Zotlabs/Module/Mail.php:164 ../../Zotlabs/Module/Register.php:77 #: ../../Zotlabs/Module/Cover_photo.php:281 #: ../../Zotlabs/Module/Cover_photo.php:294 ../../Zotlabs/Module/Network.php:15 #: ../../Zotlabs/Module/Filestorage.php:23 @@ -247,40 +243,49 @@ msgstr "" #: ../../include/attach.php:344 ../../include/attach.php:358 #: ../../include/attach.php:365 ../../include/attach.php:442 #: ../../include/attach.php:909 ../../include/attach.php:983 -#: ../../include/attach.php:1148 ../../include/items.php:3495 +#: ../../include/attach.php:1148 ../../include/items.php:3470 #: ../../include/photos.php:27 msgid "Permission denied." +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Blocks.php:97 ../../Zotlabs/Module/Blocks.php:155 -#: ../../Zotlabs/Module/Editblock.php:113 -msgid "Block Name" +#: ../../Zotlabs/Access/Permissions.php:48 +msgid "Can view my default channel profile" msgstr "" -#: ../../Zotlabs/Module/Blocks.php:154 ../../include/text.php:2280 +<<<<<<< HEAD +#: ../../Zotlabs/Access/Permissions.php:49 +msgid "Can view my connections" +======= +#: ../../Zotlabs/Module/Blocks.php:154 ../../include/text.php:2267 msgid "Blocks" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Blocks.php:156 -msgid "Block Title" +#: ../../Zotlabs/Access/Permissions.php:50 +msgid "Can view my file storage and photos" msgstr "" -#: ../../Zotlabs/Module/Blocks.php:157 ../../Zotlabs/Module/Menu.php:114 -#: ../../Zotlabs/Module/Layouts.php:191 ../../Zotlabs/Module/Webpages.php:258 -#: ../../include/page_widgets.php:47 -msgid "Created" +#: ../../Zotlabs/Access/Permissions.php:51 +msgid "Can upload/modify my file storage and photos" msgstr "" -#: ../../Zotlabs/Module/Blocks.php:158 ../../Zotlabs/Module/Menu.php:115 -#: ../../Zotlabs/Module/Layouts.php:192 ../../Zotlabs/Module/Webpages.php:259 -#: ../../include/page_widgets.php:48 -msgid "Edited" +#: ../../Zotlabs/Access/Permissions.php:52 +msgid "Can view my channel webpages" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Access/Permissions.php:53 +msgid "Can view my wiki pages" msgstr "" +#: ../../Zotlabs/Access/Permissions.php:54 +msgid "Can create/edit my channel webpages" +======= #: ../../Zotlabs/Module/Blocks.php:159 ../../Zotlabs/Module/New_channel.php:147 #: ../../Zotlabs/Module/Connedit.php:917 ../../Zotlabs/Module/Menu.php:118 #: ../../Zotlabs/Module/Layouts.php:185 ../../Zotlabs/Module/Profiles.php:801 -#: ../../Zotlabs/Module/Webpages.php:246 ../../Zotlabs/Storage/Browser.php:228 +#: ../../Zotlabs/Module/Webpages.php:244 ../../Zotlabs/Storage/Browser.php:228 #: ../../Zotlabs/Storage/Browser.php:332 ../../addon/cdav/Mod_Cdav.php:1151 #: ../../addon/cdav/include/widgets.php:127 #: ../../addon/cdav/include/widgets.php:164 @@ -293,27 +298,30 @@ msgstr "" #: ../../Zotlabs/Module/Thing.php:260 ../../Zotlabs/Module/Editblock.php:114 #: ../../Zotlabs/Module/Connections.php:296 #: ../../Zotlabs/Module/Connections.php:316 ../../Zotlabs/Module/Wiki.php:165 -#: ../../Zotlabs/Module/Wiki.php:298 ../../Zotlabs/Module/Menu.php:112 +#: ../../Zotlabs/Module/Wiki.php:275 ../../Zotlabs/Module/Menu.php:112 #: ../../Zotlabs/Module/Layouts.php:193 #: ../../Zotlabs/Module/Editwebpage.php:142 -#: ../../Zotlabs/Module/Webpages.php:247 ../../Zotlabs/Module/Editpost.php:80 +#: ../../Zotlabs/Module/Webpages.php:245 ../../Zotlabs/Module/Editpost.php:80 #: ../../Zotlabs/Lib/Apps.php:367 ../../Zotlabs/Lib/ThreadItem.php:107 #: ../../Zotlabs/Storage/Browser.php:238 #: ../../addon/cdav/include/widgets.php:125 #: ../../addon/cdav/include/widgets.php:161 #: ../../addon/gitwiki/Mod_Gitwiki.php:151 -#: ../../addon/gitwiki/Mod_Gitwiki.php:252 ../../include/channel.php:1058 -#: ../../include/channel.php:1062 ../../include/menu.php:113 +#: ../../addon/gitwiki/Mod_Gitwiki.php:252 ../../include/channel.php:1044 +#: ../../include/channel.php:1048 ../../include/menu.php:113 #: ../../include/page_widgets.php:9 ../../include/page_widgets.php:39 msgid "Edit" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Blocks.php:161 ../../Zotlabs/Module/Photos.php:1042 -#: ../../Zotlabs/Module/Layouts.php:194 ../../Zotlabs/Module/Webpages.php:248 -#: ../../addon/cdav/include/widgets.php:123 ../../include/conversation.php:1309 -msgid "Share" +#: ../../Zotlabs/Access/Permissions.php:55 +msgid "Can write to my wiki pages" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Access/Permissions.php:56 +msgid "Can post on my channel (wall) page" +======= #: ../../Zotlabs/Module/Blocks.php:162 ../../Zotlabs/Module/Editlayout.php:138 #: ../../Zotlabs/Module/Admin/Accounts.php:173 #: ../../Zotlabs/Module/Admin/Channels.php:149 @@ -325,92 +333,98 @@ msgstr "" #: ../../Zotlabs/Module/Connedit.php:919 ../../Zotlabs/Module/Group.php:177 #: ../../Zotlabs/Module/Profiles.php:803 #: ../../Zotlabs/Module/Editwebpage.php:167 -#: ../../Zotlabs/Module/Webpages.php:249 ../../Zotlabs/Lib/Apps.php:368 +#: ../../Zotlabs/Module/Webpages.php:247 ../../Zotlabs/Lib/Apps.php:368 #: ../../Zotlabs/Lib/ThreadItem.php:127 ../../Zotlabs/Storage/Browser.php:239 #: ../../addon/cdav/Mod_Cdav.php:864 ../../addon/cdav/Mod_Cdav.php:1153 -#: ../../include/conversation.php:650 ../../include/conversation.php:687 +#: ../../include/conversation.php:654 msgid "Delete" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Blocks.php:166 ../../Zotlabs/Module/Events.php:694 -#: ../../Zotlabs/Module/Wiki.php:167 ../../Zotlabs/Module/Layouts.php:198 -#: ../../Zotlabs/Module/Webpages.php:253 ../../Zotlabs/Module/Pubsites.php:59 -#: ../../addon/gitwiki/Mod_Gitwiki.php:153 ../../include/page_widgets.php:42 -msgid "View" +#: ../../Zotlabs/Access/Permissions.php:57 +msgid "Can comment on or like my posts" msgstr "" -#: ../../Zotlabs/Module/Invite.php:29 -msgid "Total invitation limit exceeded." +#: ../../Zotlabs/Access/Permissions.php:58 +msgid "Can send me private mail messages" msgstr "" -#: ../../Zotlabs/Module/Invite.php:53 -#, php-format -msgid "%s : Not a valid email address." +#: ../../Zotlabs/Access/Permissions.php:59 +msgid "Can like/dislike profiles and profile things" msgstr "" -#: ../../Zotlabs/Module/Invite.php:67 -msgid "Please join us on $Projectname" +#: ../../Zotlabs/Access/Permissions.php:60 +msgid "Can forward to all my channel connections via @+ mentions in posts" msgstr "" -#: ../../Zotlabs/Module/Invite.php:77 -msgid "Invitation limit exceeded. Please contact your site administrator." +#: ../../Zotlabs/Access/Permissions.php:61 +msgid "Can chat with me" msgstr "" -#: ../../Zotlabs/Module/Invite.php:82 -#, php-format -msgid "%s : Message delivery failed." +#: ../../Zotlabs/Access/Permissions.php:62 +msgid "Can source my public posts in derived channels" msgstr "" -#: ../../Zotlabs/Module/Invite.php:86 -#, php-format -msgid "%d message sent." -msgid_plural "%d messages sent." -msgstr[0] "" -msgstr[1] "" - -#: ../../Zotlabs/Module/Invite.php:105 -msgid "You have no more invitations available" +#: ../../Zotlabs/Access/Permissions.php:63 +msgid "Can administer my channel" msgstr "" -#: ../../Zotlabs/Module/Invite.php:136 -msgid "Send invitations" +#: ../../Zotlabs/Storage/Browser.php:106 ../../Zotlabs/Storage/Browser.php:237 +msgid "parent" msgstr "" -#: ../../Zotlabs/Module/Invite.php:137 -msgid "Enter email addresses, one per line:" +#: ../../Zotlabs/Storage/Browser.php:130 ../../include/text.php:2706 +msgid "Collection" msgstr "" -#: ../../Zotlabs/Module/Invite.php:138 ../../Zotlabs/Module/Mail.php:285 +<<<<<<< HEAD +#: ../../Zotlabs/Storage/Browser.php:133 +msgid "Principal" +======= +#: ../../Zotlabs/Module/Invite.php:138 ../../Zotlabs/Module/Mail.php:303 msgid "Your message:" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Invite.php:139 -msgid "Please join my community on $Projectname." +#: ../../Zotlabs/Storage/Browser.php:136 +msgid "Addressbook" msgstr "" -#: ../../Zotlabs/Module/Invite.php:141 -msgid "You will need to supply this invitation code:" +#: ../../Zotlabs/Storage/Browser.php:139 +msgid "Calendar" msgstr "" -#: ../../Zotlabs/Module/Invite.php:142 -msgid "1. Register at any $Projectname location (they are all inter-connected)" +#: ../../Zotlabs/Storage/Browser.php:142 +msgid "Schedule Inbox" msgstr "" -#: ../../Zotlabs/Module/Invite.php:144 -msgid "2. Enter my $Projectname network address into the site searchbar." +#: ../../Zotlabs/Storage/Browser.php:145 +msgid "Schedule Outbox" msgstr "" -#: ../../Zotlabs/Module/Invite.php:145 -msgid "or visit" +#: ../../Zotlabs/Storage/Browser.php:163 ../../Zotlabs/Module/Photos.php:757 +#: ../../Zotlabs/Module/Photos.php:1213 +#: ../../Zotlabs/Module/Embedphotos.php:145 ../../Zotlabs/Lib/Apps.php:571 +#: ../../Zotlabs/Lib/Apps.php:649 ../../Zotlabs/Widget/Album.php:84 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:745 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:746 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:753 +#: ../../include/conversation.php:1110 +msgid "Unknown" msgstr "" -#: ../../Zotlabs/Module/Invite.php:147 -msgid "3. Click [Connect]" +#: ../../Zotlabs/Storage/Browser.php:224 ../../Zotlabs/Module/Fbrowser.php:85 +#: ../../Zotlabs/Lib/Apps.php:224 ../../include/conversation.php:1782 +msgid "Files" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Storage/Browser.php:225 +msgid "Total" +======= #: ../../Zotlabs/Module/Invite.php:149 ../../Zotlabs/Module/Locs.php:121 #: ../../Zotlabs/Module/Mitem.php:243 ../../Zotlabs/Module/Events.php:493 -#: ../../Zotlabs/Module/Appman.php:148 +#: ../../Zotlabs/Module/Appman.php:134 #: ../../Zotlabs/Module/Import_items.php:129 ../../Zotlabs/Module/Setup.php:309 #: ../../Zotlabs/Module/Setup.php:357 ../../Zotlabs/Module/Connect.php:98 #: ../../Zotlabs/Module/Admin/Features.php:66 @@ -432,7 +446,7 @@ msgstr "" #: ../../Zotlabs/Module/Settings/Display.php:203 #: ../../Zotlabs/Module/Settings/Oauth.php:87 #: ../../Zotlabs/Module/Thing.php:320 ../../Zotlabs/Module/Thing.php:370 -#: ../../Zotlabs/Module/Import.php:515 ../../Zotlabs/Module/Cal.php:343 +#: ../../Zotlabs/Module/Import.php:514 ../../Zotlabs/Module/Cal.php:343 #: ../../Zotlabs/Module/Mood.php:139 ../../Zotlabs/Module/Photos.php:657 #: ../../Zotlabs/Module/Photos.php:1022 ../../Zotlabs/Module/Photos.php:1062 #: ../../Zotlabs/Module/Photos.php:1180 ../../Zotlabs/Module/Wiki.php:169 @@ -441,11 +455,11 @@ msgstr "" #: ../../Zotlabs/Module/Chat.php:240 ../../Zotlabs/Module/Pconfig.php:107 #: ../../Zotlabs/Module/Group.php:85 ../../Zotlabs/Module/Profiles.php:726 #: ../../Zotlabs/Module/Sources.php:114 ../../Zotlabs/Module/Sources.php:149 -#: ../../Zotlabs/Module/Xchan.php:15 ../../Zotlabs/Module/Mail.php:431 +#: ../../Zotlabs/Module/Xchan.php:15 ../../Zotlabs/Module/Mail.php:449 #: ../../Zotlabs/Module/Filestorage.php:165 ../../Zotlabs/Module/Rate.php:166 #: ../../Zotlabs/Lib/ThreadItem.php:732 ../../Zotlabs/Widget/Eventstools.php:16 -#: ../../view/theme/redbasic/php/config.php:95 -#: ../../addon/skeleton/skeleton.php:65 ../../addon/gnusoc/gnusoc.php:185 +#: ../../view/theme/redbasic/php/config.php:84 +#: ../../addon/skeleton/skeleton.php:65 ../../addon/gnusoc/gnusoc.php:134 #: ../../addon/cdav/cdav.php:246 ../../addon/planets/planets.php:157 #: ../../addon/openclipatar/openclipatar.php:53 #: ../../addon/wppost/wppost.php:113 ../../addon/nsfw/nsfw.php:92 @@ -470,287 +484,438 @@ msgstr "" #: ../../addon/statusnet/statusnet.php:432 #: ../../addon/statusnet/statusnet.php:899 ../../addon/twitter/twitter.php:217 #: ../../addon/twitter/twitter.php:259 -#: ../../addon/smileybutton/smileybutton.php:219 ../../addon/piwik/piwik.php:95 +#: ../../addon/smileybutton/smileybutton.php:281 ../../addon/piwik/piwik.php:95 #: ../../addon/pageheader/pageheader.php:48 ../../addon/xmpp/xmpp.php:69 #: ../../addon/pumpio/pumpio.php:237 ../../addon/redfiles/redfiles.php:124 #: ../../addon/hubwall/hubwall.php:95 ../../include/js_strings.php:22 msgid "Submit" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Editlayout.php:79 ../../Zotlabs/Module/Editblock.php:79 -#: ../../Zotlabs/Module/Editblock.php:95 -#: ../../Zotlabs/Module/Editwebpage.php:80 ../../Zotlabs/Module/Editpost.php:24 -msgid "Item not found" +#: ../../Zotlabs/Storage/Browser.php:227 +msgid "Shared" msgstr "" -#: ../../Zotlabs/Module/Editlayout.php:128 ../../Zotlabs/Module/Layouts.php:129 -#: ../../Zotlabs/Module/Layouts.php:189 -msgid "Layout Name" +#: ../../Zotlabs/Storage/Browser.php:228 ../../Zotlabs/Storage/Browser.php:332 +#: ../../Zotlabs/Module/Profiles.php:801 ../../Zotlabs/Module/Layouts.php:185 +#: ../../Zotlabs/Module/Webpages.php:244 ../../Zotlabs/Module/Menu.php:118 +#: ../../Zotlabs/Module/New_channel.php:147 +#: ../../Zotlabs/Module/Connedit.php:917 ../../Zotlabs/Module/Blocks.php:159 +#: ../../extend/addon/addon/cdav/include/widgets.php:127 +#: ../../extend/addon/addon/cdav/include/widgets.php:164 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1151 +msgid "Create" msgstr "" -#: ../../Zotlabs/Module/Editlayout.php:129 ../../Zotlabs/Module/Layouts.php:132 -msgid "Layout Description (Optional)" +#: ../../Zotlabs/Storage/Browser.php:229 ../../Zotlabs/Storage/Browser.php:334 +#: ../../Zotlabs/Module/Cover_photo.php:361 +#: ../../Zotlabs/Module/Profile_photo.php:423 +#: ../../Zotlabs/Module/Photos.php:784 ../../Zotlabs/Module/Photos.php:1321 +#: ../../Zotlabs/Module/Embedphotos.php:157 ../../Zotlabs/Widget/Album.php:97 +#: ../../extend/addon/addon/cdav/include/widgets.php:132 +#: ../../extend/addon/addon/cdav/include/widgets.php:168 +msgid "Upload" msgstr "" -#: ../../Zotlabs/Module/Editlayout.php:137 -msgid "Edit Layout" +#: ../../Zotlabs/Storage/Browser.php:233 +#: ../../Zotlabs/Module/Admin/Channels.php:159 +#: ../../Zotlabs/Module/Wiki.php:172 ../../Zotlabs/Module/Connedit.php:902 +#: ../../Zotlabs/Module/Sharedwithme.php:100 +#: ../../Zotlabs/Module/Settings/Oauth.php:89 +#: ../../Zotlabs/Module/Settings/Oauth.php:115 +#: ../../Zotlabs/Module/Chat.php:249 ../../Zotlabs/Lib/NativeWikiPage.php:528 +#: ../../Zotlabs/Widget/Wiki_page_history.php:22 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1136 +#: ../../extend/addon/addon/rendezvous/rendezvous.php:172 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:158 +msgid "Name" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Storage/Browser.php:234 ../../Zotlabs/Module/Wiki.php:173 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:159 +msgid "Type" +======= #: ../../Zotlabs/Module/Profperm.php:28 ../../Zotlabs/Module/Subthread.php:62 #: ../../Zotlabs/Module/Import_items.php:120 ../../Zotlabs/Module/Group.php:72 #: ../../Zotlabs/Module/Dreport.php:10 ../../Zotlabs/Module/Dreport.php:68 #: ../../Zotlabs/Module/Like.php:283 ../../Zotlabs/Web/WebServer.php:130 #: ../../addon/redphotos/redphotos.php:119 ../../addon/frphotos/frphotos.php:81 -#: ../../addon/redfiles/redfiles.php:109 ../../include/items.php:341 +#: ../../addon/redfiles/redfiles.php:109 ../../include/items.php:327 msgid "Permission denied" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Profperm.php:34 ../../Zotlabs/Module/Profperm.php:63 -msgid "Invalid profile identifier." +#: ../../Zotlabs/Storage/Browser.php:235 +#: ../../Zotlabs/Module/Sharedwithme.php:102 ../../include/text.php:1415 +msgid "Size" msgstr "" -#: ../../Zotlabs/Module/Profperm.php:111 -msgid "Profile Visibility Editor" +#: ../../Zotlabs/Storage/Browser.php:236 +#: ../../Zotlabs/Module/Sharedwithme.php:103 +msgid "Last Modified" msgstr "" -#: ../../Zotlabs/Module/Profperm.php:113 ../../include/channel.php:1376 +<<<<<<< HEAD +#: ../../Zotlabs/Storage/Browser.php:238 ../../Zotlabs/Module/Layouts.php:193 +#: ../../Zotlabs/Module/Webpages.php:245 +#: ../../Zotlabs/Module/Connections.php:296 +#: ../../Zotlabs/Module/Connections.php:316 +#: ../../Zotlabs/Module/Admin/Profs.php:154 +#: ../../Zotlabs/Module/Editlayout.php:114 +#: ../../Zotlabs/Module/Editwebpage.php:147 ../../Zotlabs/Module/Menu.php:112 +#: ../../Zotlabs/Module/Editpost.php:85 ../../Zotlabs/Module/Editblock.php:114 +#: ../../Zotlabs/Module/Wiki.php:165 ../../Zotlabs/Module/Wiki.php:275 +#: ../../Zotlabs/Module/Blocks.php:160 +#: ../../Zotlabs/Module/Settings/Oauth.php:149 +#: ../../Zotlabs/Module/Thing.php:260 ../../Zotlabs/Lib/ThreadItem.php:107 +#: ../../Zotlabs/Lib/Apps.php:367 +#: ../../extend/addon/addon/cdav/include/widgets.php:125 +#: ../../extend/addon/addon/cdav/include/widgets.php:161 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:151 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:252 +#: ../../include/page_widgets.php:9 ../../include/page_widgets.php:39 +#: ../../include/channel.php:1043 ../../include/channel.php:1047 +#: ../../include/menu.php:113 +msgid "Edit" +======= +#: ../../Zotlabs/Module/Profperm.php:113 ../../include/channel.php:1362 msgid "Profile" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Profperm.php:115 -msgid "Click on a contact to add or remove." +#: ../../Zotlabs/Storage/Browser.php:239 ../../Zotlabs/Module/Profiles.php:803 +#: ../../Zotlabs/Module/Webpages.php:247 +#: ../../Zotlabs/Module/Connections.php:267 +#: ../../Zotlabs/Module/Admin/Profs.php:155 +#: ../../Zotlabs/Module/Admin/Accounts.php:173 +#: ../../Zotlabs/Module/Admin/Channels.php:149 +#: ../../Zotlabs/Module/Editlayout.php:138 +#: ../../Zotlabs/Module/Editwebpage.php:172 ../../Zotlabs/Module/Group.php:177 +#: ../../Zotlabs/Module/Editblock.php:139 +#: ../../Zotlabs/Module/Connedit.php:650 ../../Zotlabs/Module/Connedit.php:919 +#: ../../Zotlabs/Module/Blocks.php:162 +#: ../../Zotlabs/Module/Settings/Oauth.php:150 +#: ../../Zotlabs/Module/Thing.php:261 ../../Zotlabs/Module/Photos.php:1143 +#: ../../Zotlabs/Lib/ThreadItem.php:127 ../../Zotlabs/Lib/Apps.php:368 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:864 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1153 +#: ../../include/conversation.php:654 +msgid "Delete" msgstr "" -#: ../../Zotlabs/Module/Profperm.php:124 -msgid "Visible To" +#: ../../Zotlabs/Storage/Browser.php:301 +#, php-format +msgid "You are using %1$s of your available file storage." msgstr "" -#: ../../Zotlabs/Module/Profperm.php:140 -#: ../../Zotlabs/Module/Connections.php:141 -msgid "All Connections" +#: ../../Zotlabs/Storage/Browser.php:306 +#, php-format +msgid "You are using %1$s of %2$s available file storage. (%3$s%)" msgstr "" -#: ../../Zotlabs/Module/Regdir.php:49 ../../Zotlabs/Module/Dirsearch.php:25 -msgid "This site is not a directory server" +#: ../../Zotlabs/Storage/Browser.php:317 +msgid "WARNING:" msgstr "" -#: ../../Zotlabs/Module/Channel.php:32 ../../Zotlabs/Module/Chat.php:25 -#: ../../addon/gitwiki/Mod_Gitwiki.php:28 ../../addon/chess/chess.php:403 -msgid "You must be logged in to see this page." +#: ../../Zotlabs/Storage/Browser.php:327 +msgid "" +"Please use DAV to upload large (video, audio) files.<br>See <a class=\"zrl\" " +"href=\"help/member/member_guide#Cloud_Desktop_Clients\">Cloud Desktop " +"Clients</a>" msgstr "" -#: ../../Zotlabs/Module/Channel.php:47 ../../Zotlabs/Module/Hcard.php:35 -#: ../../Zotlabs/Module/Profile.php:43 -msgid "Posts and comments" +#: ../../Zotlabs/Storage/Browser.php:331 +msgid "Create new folder" msgstr "" -#: ../../Zotlabs/Module/Channel.php:54 ../../Zotlabs/Module/Hcard.php:42 -#: ../../Zotlabs/Module/Profile.php:50 -msgid "Only posts" +#: ../../Zotlabs/Storage/Browser.php:333 +msgid "Upload file" msgstr "" -#: ../../Zotlabs/Module/Channel.php:112 -msgid "Insufficient permissions. Request redirected to profile page." +#: ../../Zotlabs/Storage/Browser.php:347 +msgid "Drop files here to immediately upload" msgstr "" -#: ../../Zotlabs/Module/Uexport.php:57 ../../Zotlabs/Module/Uexport.php:58 -msgid "Export Channel" +#: ../../Zotlabs/Web/Router.php:146 ../../Zotlabs/Module/Page.php:94 +#: ../../Zotlabs/Module/Block.php:79 ../../Zotlabs/Module/Display.php:122 +#: ../../Zotlabs/Lib/NativeWikiPage.php:489 ../../include/help.php:68 +msgid "Page not found." msgstr "" -#: ../../Zotlabs/Module/Uexport.php:59 -msgid "" -"Export your basic channel information to a file. This acts as a backup of " -"your connections, permissions, profile and basic data, which can be used to " -"import your data to a new server hub, but does not contain your content." +#: ../../Zotlabs/Web/WebServer.php:130 ../../Zotlabs/Module/Group.php:72 +#: ../../Zotlabs/Module/Dreport.php:10 ../../Zotlabs/Module/Dreport.php:68 +#: ../../Zotlabs/Module/Import_items.php:120 ../../Zotlabs/Module/Like.php:283 +#: ../../Zotlabs/Module/Subthread.php:62 ../../Zotlabs/Module/Profperm.php:28 +#: ../../extend/addon/addon/frphotos/frphotos.php:81 +#: ../../extend/addon/addon/redfiles/redfiles.php:109 +#: ../../extend/addon/addon/redphotos/redphotos.php:119 +#: ../../include/items.php:325 +msgid "Permission denied" msgstr "" -#: ../../Zotlabs/Module/Uexport.php:60 -msgid "Export Content" +#: ../../Zotlabs/Web/WebServer.php:131 +#: ../../Zotlabs/Module/Achievements.php:34 +#: ../../Zotlabs/Module/Register.php:77 ../../Zotlabs/Module/Message.php:18 +#: ../../Zotlabs/Module/Profiles.php:198 ../../Zotlabs/Module/Profiles.php:635 +#: ../../Zotlabs/Module/Authtest.php:16 ../../Zotlabs/Module/Layouts.php:71 +#: ../../Zotlabs/Module/Layouts.php:78 ../../Zotlabs/Module/Layouts.php:89 +#: ../../Zotlabs/Module/Page.php:35 ../../Zotlabs/Module/Page.php:91 +#: ../../Zotlabs/Module/Webpages.php:116 +#: ../../Zotlabs/Module/Connections.php:29 +#: ../../Zotlabs/Module/Cover_photo.php:281 +#: ../../Zotlabs/Module/Cover_photo.php:294 +#: ../../Zotlabs/Module/Editlayout.php:67 +#: ../../Zotlabs/Module/Editlayout.php:90 +#: ../../Zotlabs/Module/Editwebpage.php:68 +#: ../../Zotlabs/Module/Editwebpage.php:89 +#: ../../Zotlabs/Module/Editwebpage.php:104 +#: ../../Zotlabs/Module/Editwebpage.php:126 +#: ../../Zotlabs/Module/Network.php:15 ../../Zotlabs/Module/Menu.php:78 +#: ../../Zotlabs/Module/Editpost.php:17 ../../Zotlabs/Module/Locs.php:87 +#: ../../Zotlabs/Module/Channel.php:115 ../../Zotlabs/Module/Channel.php:245 +#: ../../Zotlabs/Module/Channel.php:285 +#: ../../Zotlabs/Module/Filestorage.php:23 +#: ../../Zotlabs/Module/Filestorage.php:78 +#: ../../Zotlabs/Module/Filestorage.php:93 +#: ../../Zotlabs/Module/Filestorage.php:120 +#: ../../Zotlabs/Module/Settings.php:59 ../../Zotlabs/Module/Group.php:13 +#: ../../Zotlabs/Module/Block.php:26 ../../Zotlabs/Module/Block.php:76 +#: ../../Zotlabs/Module/Setup.php:212 ../../Zotlabs/Module/Manage.php:10 +#: ../../Zotlabs/Module/Editblock.php:67 ../../Zotlabs/Module/Mitem.php:115 +#: ../../Zotlabs/Module/Wiki.php:50 ../../Zotlabs/Module/Wiki.php:216 +#: ../../Zotlabs/Module/Wiki.php:315 ../../Zotlabs/Module/Api.php:24 +#: ../../Zotlabs/Module/Invite.php:17 ../../Zotlabs/Module/Invite.php:94 +#: ../../Zotlabs/Module/New_channel.php:77 +#: ../../Zotlabs/Module/New_channel.php:104 +#: ../../Zotlabs/Module/Profile.php:83 ../../Zotlabs/Module/Profile.php:100 +#: ../../Zotlabs/Module/Notifications.php:11 ../../Zotlabs/Module/Poke.php:137 +#: ../../Zotlabs/Module/Like.php:181 ../../Zotlabs/Module/Mood.php:116 +#: ../../Zotlabs/Module/Connedit.php:385 ../../Zotlabs/Module/Blocks.php:73 +#: ../../Zotlabs/Module/Blocks.php:80 ../../Zotlabs/Module/Rate.php:113 +#: ../../Zotlabs/Module/Profile_photo.php:280 +#: ../../Zotlabs/Module/Profile_photo.php:293 +#: ../../Zotlabs/Module/Appman.php:82 ../../Zotlabs/Module/Common.php:39 +#: ../../Zotlabs/Module/Item.php:220 ../../Zotlabs/Module/Item.php:230 +#: ../../Zotlabs/Module/Item.php:1037 ../../Zotlabs/Module/Regmod.php:21 +#: ../../Zotlabs/Module/Pdledit.php:29 ../../Zotlabs/Module/Events.php:271 +#: ../../Zotlabs/Module/Service_limits.php:11 +#: ../../Zotlabs/Module/Bookmarks.php:61 +#: ../../Zotlabs/Module/Sharedwithme.php:11 +#: ../../Zotlabs/Module/Viewsrc.php:18 ../../Zotlabs/Module/Sources.php:74 +#: ../../Zotlabs/Module/Mail.php:164 ../../Zotlabs/Module/Suggest.php:28 +#: ../../Zotlabs/Module/Thing.php:274 ../../Zotlabs/Module/Thing.php:294 +#: ../../Zotlabs/Module/Thing.php:335 +#: ../../Zotlabs/Module/Viewconnections.php:28 +#: ../../Zotlabs/Module/Viewconnections.php:33 +#: ../../Zotlabs/Module/Photos.php:69 ../../Zotlabs/Module/Chat.php:98 +#: ../../Zotlabs/Module/Chat.php:103 ../../Zotlabs/Lib/Chatroom.php:137 +#: ../../extend/addon/addon/keepout/keepout.php:36 +#: ../../extend/addon/addon/pumpio/pumpio.php:40 +#: ../../extend/addon/addon/openid/Mod_Id.php:53 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:196 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:292 +#: ../../include/photos.php:28 ../../include/attach.php:144 +#: ../../include/attach.php:191 ../../include/attach.php:255 +#: ../../include/attach.php:269 ../../include/attach.php:276 +#: ../../include/attach.php:344 ../../include/attach.php:358 +#: ../../include/attach.php:365 ../../include/attach.php:442 +#: ../../include/attach.php:909 ../../include/attach.php:983 +#: ../../include/attach.php:1148 ../../include/items.php:3395 +msgid "Permission denied." msgstr "" -#: ../../Zotlabs/Module/Uexport.php:61 +#: ../../Zotlabs/Zot/Auth.php:138 msgid "" -"Export your channel information and recent content to a JSON backup that can " -"be restored or imported to another server hub. This backs up all of your " -"connections, permissions, profile data and several months of posts. This " -"file may be VERY large. Please be patient - it may take several minutes for " -"this download to begin." +"Remote authentication blocked. You are logged into this site locally. Please " +"logout and retry." msgstr "" -#: ../../Zotlabs/Module/Uexport.php:63 -msgid "Export your posts from a given year." +#: ../../Zotlabs/Zot/Auth.php:250 +#: ../../extend/addon/addon/openid/Mod_Openid.php:76 +#: ../../extend/addon/addon/openid/Mod_Openid.php:178 +#, php-format +msgid "Welcome %s. Remote authentication successful." msgstr "" -#: ../../Zotlabs/Module/Uexport.php:65 -msgid "" -"You may also export your posts and conversations for a particular year or " -"month. Adjust the date in your browser location bar to select other dates. " -"If the export fails (possibly due to memory exhaustion on your server hub), " -"please try again selecting a more limited date range." +#: ../../Zotlabs/Module/Achievements.php:15 +#: ../../Zotlabs/Module/Layouts.php:31 ../../Zotlabs/Module/Connect.php:17 +#: ../../Zotlabs/Module/Webpages.php:33 ../../Zotlabs/Module/Editlayout.php:31 +#: ../../Zotlabs/Module/Editwebpage.php:32 +#: ../../Zotlabs/Module/Filestorage.php:59 +#: ../../Zotlabs/Module/Editblock.php:31 ../../Zotlabs/Module/Profile.php:20 +#: ../../Zotlabs/Module/Hcard.php:12 ../../Zotlabs/Module/Blocks.php:33 +#: ../../include/channel.php:944 +msgid "Requested profile is not available." msgstr "" -#: ../../Zotlabs/Module/Uexport.php:66 -#, php-format -msgid "" -"To select all posts for a given year, such as this year, visit <a href=\"%1$s" -"\">%2$s</a>" +#: ../../Zotlabs/Module/Achievements.php:38 +msgid "Some blurb about what to do when you're new here" msgstr "" -#: ../../Zotlabs/Module/Uexport.php:67 -#, php-format -msgid "" -"To select all posts for a given month, such as January of this year, visit " -"<a href=\"%1$s\">%2$s</a>" +#: ../../Zotlabs/Module/Register.php:49 +msgid "Maximum daily site registrations exceeded. Please try again tomorrow." msgstr "" -#: ../../Zotlabs/Module/Uexport.php:68 -#, php-format +#: ../../Zotlabs/Module/Register.php:55 msgid "" -"These content files may be imported or restored by visiting <a href=\"%1$s\">" -"%2$s</a> on any site containing your channel. For best results please import " -"or restore these in date order (oldest first)." +"Please indicate acceptance of the Terms of Service. Registration failed." msgstr "" -#: ../../Zotlabs/Module/Search.php:17 ../../Zotlabs/Module/Photos.php:490 -#: ../../Zotlabs/Module/Ratings.php:83 ../../Zotlabs/Module/Directory.php:63 -#: ../../Zotlabs/Module/Display.php:22 -#: ../../Zotlabs/Module/Viewconnections.php:23 -msgid "Public access denied." +#: ../../Zotlabs/Module/Register.php:89 +msgid "Passwords do not match." msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Register.php:131 +msgid "" +"Registration successful. Please check your email for validation instructions." +======= #: ../../Zotlabs/Module/Search.php:44 ../../Zotlabs/Module/Connections.php:312 #: ../../Zotlabs/Lib/Apps.php:237 ../../Zotlabs/Widget/Sitesearch.php:31 #: ../../include/text.php:1027 ../../include/text.php:1039 #: ../../include/acl_selectors.php:213 ../../include/nav.php:164 msgid "Search" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Search.php:224 -#, php-format -msgid "Items tagged with: %s" +#: ../../Zotlabs/Module/Register.php:137 +msgid "Your registration is pending approval by the site owner." msgstr "" -#: ../../Zotlabs/Module/Search.php:226 -#, php-format -msgid "Search results for: %s" +#: ../../Zotlabs/Module/Register.php:140 +msgid "Your registration can not be processed." msgstr "" -#: ../../Zotlabs/Module/Locs.php:25 ../../Zotlabs/Module/Locs.php:54 -msgid "Location not found." +#: ../../Zotlabs/Module/Register.php:184 +msgid "Registration on this hub is disabled." msgstr "" -#: ../../Zotlabs/Module/Locs.php:62 -msgid "Location lookup failed." +#: ../../Zotlabs/Module/Register.php:193 +msgid "Registration on this hub is by approval only." msgstr "" -#: ../../Zotlabs/Module/Locs.php:66 -msgid "" -"Please select another location to become primary before removing the primary " -"location." +#: ../../Zotlabs/Module/Register.php:194 +msgid "<a href=\"pubsites\">Register at another affiliated hub.</a>" msgstr "" -#: ../../Zotlabs/Module/Locs.php:95 -msgid "Syncing locations" +#: ../../Zotlabs/Module/Register.php:204 +msgid "" +"This site has exceeded the number of allowed daily account registrations. " +"Please try again tomorrow." msgstr "" -#: ../../Zotlabs/Module/Locs.php:105 -msgid "No locations found." +#: ../../Zotlabs/Module/Register.php:221 ../../Zotlabs/Module/Siteinfo.php:27 +msgid "Terms of Service" msgstr "" -#: ../../Zotlabs/Module/Locs.php:116 -msgid "Manage Channel Locations" +#: ../../Zotlabs/Module/Register.php:227 +#, php-format +msgid "I accept the %s for this website" msgstr "" -#: ../../Zotlabs/Module/Locs.php:117 ../../Zotlabs/Module/Events.php:475 -#: ../../Zotlabs/Module/Profiles.php:509 ../../Zotlabs/Module/Profiles.php:737 -#: ../../Zotlabs/Module/Pubsites.php:51 ../../addon/cdav/Mod_Cdav.php:839 -#: ../../include/js_strings.php:25 -msgid "Location" +#: ../../Zotlabs/Module/Register.php:229 +#, php-format +msgid "I am over 13 years of age and accept the %s for this website" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Register.php:233 +msgid "Your email address" +======= #: ../../Zotlabs/Module/Locs.php:118 #: ../../Zotlabs/Module/Admin/Channels.php:160 #: ../../Zotlabs/Module/Connedit.php:909 ../../Zotlabs/Module/Profiles.php:502 #: ../../Zotlabs/Module/Profiles.php:793 ../../addon/cdav/Mod_Cdav.php:1143 msgid "Address" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Locs.php:119 -msgid "Primary" +#: ../../Zotlabs/Module/Register.php:234 +msgid "Choose a password" msgstr "" -#: ../../Zotlabs/Module/Locs.php:120 ../../Zotlabs/Module/Menu.php:113 -msgid "Drop" +#: ../../Zotlabs/Module/Register.php:235 +msgid "Please re-enter your password" msgstr "" -#: ../../Zotlabs/Module/Locs.php:122 -msgid "Sync Now" +#: ../../Zotlabs/Module/Register.php:236 +msgid "Please enter your invitation code" msgstr "" -#: ../../Zotlabs/Module/Locs.php:123 -msgid "Please wait several minutes between consecutive operations." +#: ../../Zotlabs/Module/Register.php:237 +#: ../../Zotlabs/Module/New_channel.php:134 +msgid "Name or caption" msgstr "" -#: ../../Zotlabs/Module/Locs.php:124 +#: ../../Zotlabs/Module/Register.php:237 +#: ../../Zotlabs/Module/New_channel.php:134 msgid "" -"When possible, drop a location by logging into that website/hub and removing " -"your channel." -msgstr "" - -#: ../../Zotlabs/Module/Locs.php:125 -msgid "Use this form to drop the location if the hub is no longer operating." -msgstr "" - -#: ../../Zotlabs/Module/Apporder.php:34 -msgid "Change Order of Navigation Apps" +"Examples: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation " +"Group\"" msgstr "" -#: ../../Zotlabs/Module/Apporder.php:35 -msgid "Use arrows to move the corresponding app up or down in the display list" +#: ../../Zotlabs/Module/Register.php:239 +#: ../../Zotlabs/Module/New_channel.php:136 +msgid "Choose a short nickname" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:28 ../../Zotlabs/Module/Menu.php:144 -msgid "Menu not found." +#: ../../Zotlabs/Module/Register.php:239 +#: ../../Zotlabs/Module/New_channel.php:136 +#, php-format +msgid "" +"Your nickname will be used to create an easy to remember channel address e." +"g. nickname%s" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:52 -msgid "Unable to create element." +#: ../../Zotlabs/Module/Register.php:240 +#: ../../Zotlabs/Module/New_channel.php:137 +msgid "Channel role and privacy" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:76 -msgid "Unable to update menu element." +#: ../../Zotlabs/Module/Register.php:240 +#: ../../Zotlabs/Module/New_channel.php:137 +msgid "Select a channel role with your privacy requirements." msgstr "" -#: ../../Zotlabs/Module/Mitem.php:92 -msgid "Unable to add menu element." +#: ../../Zotlabs/Module/Register.php:240 +#: ../../Zotlabs/Module/New_channel.php:137 +msgid "Read more about roles" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:120 ../../Zotlabs/Module/Menu.php:166 -#: ../../Zotlabs/Module/Xchan.php:41 -msgid "Not found." +#: ../../Zotlabs/Module/Register.php:241 +msgid "no" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:153 ../../Zotlabs/Module/Mitem.php:230 -msgid "Menu Item Permissions" +#: ../../Zotlabs/Module/Register.php:241 +msgid "yes" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:154 ../../Zotlabs/Module/Mitem.php:231 -#: ../../Zotlabs/Module/Settings/Channel.php:510 -msgid "(click to open/close)" +#: ../../Zotlabs/Module/Register.php:253 +#: ../../Zotlabs/Module/Admin/Site.php:280 +msgid "Registration" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:160 ../../Zotlabs/Module/Mitem.php:176 -msgid "Link Name" +#: ../../Zotlabs/Module/Register.php:258 +msgid "Membership on this site is by invitation only." msgstr "" -#: ../../Zotlabs/Module/Mitem.php:161 ../../Zotlabs/Module/Mitem.php:239 -msgid "Link or Submenu Target" +#: ../../Zotlabs/Module/Register.php:270 ../../include/nav.php:145 +#: ../../boot.php:1572 +msgid "Register" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:161 -msgid "Enter URL of the link or select a menu name to create a submenu" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Register.php:271 +msgid "" +"This site may require email verification after submitting this form. If you " +"are returned to a login page, please check your email for instructions." msgstr "" +#: ../../Zotlabs/Module/Probe.php:28 ../../Zotlabs/Module/Probe.php:32 +#, php-format +msgid "Fetching URL returns error: %1$s" +======= #: ../../Zotlabs/Module/Mitem.php:162 ../../Zotlabs/Module/Mitem.php:240 msgid "Use magic-auth if available" msgstr "" @@ -766,9 +931,9 @@ msgstr "" #: ../../Zotlabs/Module/Connedit.php:775 ../../Zotlabs/Module/Menu.php:100 #: ../../Zotlabs/Module/Menu.php:157 ../../Zotlabs/Module/Profiles.php:681 #: ../../Zotlabs/Module/Filestorage.php:160 -#: ../../Zotlabs/Module/Filestorage.php:168 ../../boot.php:1635 -#: ../../view/theme/redbasic/php/config.php:100 -#: ../../view/theme/redbasic/php/config.php:115 ../../addon/cdav/cdav.php:234 +#: ../../Zotlabs/Module/Filestorage.php:168 ../../boot.php:1633 +#: ../../view/theme/redbasic/php/config.php:89 +#: ../../view/theme/redbasic/php/config.php:104 ../../addon/cdav/cdav.php:234 #: ../../addon/planets/planets.php:153 ../../addon/wppost/wppost.php:82 #: ../../addon/wppost/wppost.php:105 ../../addon/wppost/wppost.php:109 #: ../../addon/nsfw/nsfw.php:84 ../../addon/ijpost/ijpost.php:73 @@ -792,8 +957,8 @@ msgstr "" #: ../../addon/statusnet/statusnet.php:415 #: ../../addon/statusnet/statusnet.php:424 ../../addon/twitter/twitter.php:242 #: ../../addon/twitter/twitter.php:246 ../../addon/twitter/twitter.php:255 -#: ../../addon/smileybutton/smileybutton.php:211 -#: ../../addon/smileybutton/smileybutton.php:215 ../../addon/xmpp/xmpp.php:53 +#: ../../addon/smileybutton/smileybutton.php:273 +#: ../../addon/smileybutton/smileybutton.php:277 ../../addon/xmpp/xmpp.php:53 #: ../../addon/pumpio/pumpio.php:219 ../../addon/pumpio/pumpio.php:223 #: ../../addon/pumpio/pumpio.php:227 ../../addon/pumpio/pumpio.php:231 #: ../../include/dir_fns.php:143 ../../include/dir_fns.php:144 @@ -812,9 +977,9 @@ msgstr "" #: ../../Zotlabs/Module/Menu.php:100 ../../Zotlabs/Module/Menu.php:157 #: ../../Zotlabs/Module/Profiles.php:681 #: ../../Zotlabs/Module/Filestorage.php:160 -#: ../../Zotlabs/Module/Filestorage.php:168 ../../boot.php:1635 -#: ../../view/theme/redbasic/php/config.php:100 -#: ../../view/theme/redbasic/php/config.php:115 ../../addon/cdav/cdav.php:234 +#: ../../Zotlabs/Module/Filestorage.php:168 ../../boot.php:1633 +#: ../../view/theme/redbasic/php/config.php:89 +#: ../../view/theme/redbasic/php/config.php:104 ../../addon/cdav/cdav.php:234 #: ../../addon/planets/planets.php:153 ../../addon/wppost/wppost.php:82 #: ../../addon/wppost/wppost.php:105 ../../addon/wppost/wppost.php:109 #: ../../addon/nsfw/nsfw.php:84 ../../addon/ijpost/ijpost.php:73 @@ -838,371 +1003,637 @@ msgstr "" #: ../../addon/statusnet/statusnet.php:415 #: ../../addon/statusnet/statusnet.php:424 ../../addon/twitter/twitter.php:242 #: ../../addon/twitter/twitter.php:246 ../../addon/twitter/twitter.php:255 -#: ../../addon/smileybutton/smileybutton.php:211 -#: ../../addon/smileybutton/smileybutton.php:215 ../../addon/xmpp/xmpp.php:53 +#: ../../addon/smileybutton/smileybutton.php:273 +#: ../../addon/smileybutton/smileybutton.php:277 ../../addon/xmpp/xmpp.php:53 #: ../../addon/pumpio/pumpio.php:219 ../../addon/pumpio/pumpio.php:223 #: ../../addon/pumpio/pumpio.php:227 ../../addon/pumpio/pumpio.php:231 #: ../../include/dir_fns.php:143 ../../include/dir_fns.php:144 #: ../../include/dir_fns.php:145 msgid "Yes" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Mitem.php:163 ../../Zotlabs/Module/Mitem.php:241 -msgid "Open link in new window" +#: ../../Zotlabs/Module/Directory.php:63 ../../Zotlabs/Module/Ratings.php:83 +#: ../../Zotlabs/Module/Search.php:17 ../../Zotlabs/Module/Display.php:22 +#: ../../Zotlabs/Module/Viewconnections.php:23 +#: ../../Zotlabs/Module/Photos.php:490 +msgid "Public access denied." msgstr "" -#: ../../Zotlabs/Module/Mitem.php:164 ../../Zotlabs/Module/Mitem.php:242 -msgid "Order in list" -msgstr "" +#: ../../Zotlabs/Module/Directory.php:245 +#, php-format +msgid "%d rating" +msgid_plural "%d ratings" +msgstr[0] "" +msgstr[1] "" -#: ../../Zotlabs/Module/Mitem.php:164 ../../Zotlabs/Module/Mitem.php:242 -msgid "Higher numbers will sink to bottom of listing" +#: ../../Zotlabs/Module/Directory.php:256 +msgid "Gender: " msgstr "" -#: ../../Zotlabs/Module/Mitem.php:165 -msgid "Submit and finish" +#: ../../Zotlabs/Module/Directory.php:258 +msgid "Status: " msgstr "" -#: ../../Zotlabs/Module/Mitem.php:166 -msgid "Submit and continue" +#: ../../Zotlabs/Module/Directory.php:260 +msgid "Homepage: " msgstr "" -#: ../../Zotlabs/Module/Mitem.php:174 -msgid "Menu:" +#: ../../Zotlabs/Module/Directory.php:309 ../../include/channel.php:1272 +msgid "Age:" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:177 -msgid "Link Target" +#: ../../Zotlabs/Module/Directory.php:314 ../../include/channel.php:1133 +#: ../../include/event.php:52 ../../include/event.php:84 +msgid "Location:" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:180 -msgid "Edit menu" +#: ../../Zotlabs/Module/Directory.php:320 +msgid "Description:" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:183 -msgid "Edit element" +#: ../../Zotlabs/Module/Directory.php:325 ../../include/channel.php:1288 +msgid "Hometown:" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:184 -msgid "Drop element" +#: ../../Zotlabs/Module/Directory.php:327 ../../include/channel.php:1296 +msgid "About:" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:185 -msgid "New element" +#: ../../Zotlabs/Module/Directory.php:328 ../../Zotlabs/Module/Suggest.php:54 +#: ../../Zotlabs/Widget/Follow.php:32 ../../Zotlabs/Widget/Suggestions.php:44 +#: ../../include/connections.php:110 ../../include/channel.php:1118 +#: ../../include/conversation.php:1002 +msgid "Connect" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:186 -msgid "Edit this menu container" +#: ../../Zotlabs/Module/Directory.php:329 +msgid "Public Forum:" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:187 -msgid "Add menu element" +#: ../../Zotlabs/Module/Directory.php:332 +msgid "Keywords: " msgstr "" -#: ../../Zotlabs/Module/Mitem.php:188 -msgid "Delete this menu item" +#: ../../Zotlabs/Module/Directory.php:335 +msgid "Don't suggest" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:189 -msgid "Edit this menu item" +#: ../../Zotlabs/Module/Directory.php:337 +msgid "Common connections:" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:206 -msgid "Menu item not found." +#: ../../Zotlabs/Module/Directory.php:386 +msgid "Global Directory" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:219 -msgid "Menu item deleted." +#: ../../Zotlabs/Module/Directory.php:386 +msgid "Local Directory" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:221 -msgid "Menu item could not be deleted." +#: ../../Zotlabs/Module/Directory.php:391 +#: ../../Zotlabs/Module/Directory.php:396 +#: ../../Zotlabs/Module/Connections.php:315 +#: ../../include/contact_widgets.php:23 +msgid "Find" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:228 -msgid "Edit Menu Element" +#: ../../Zotlabs/Module/Directory.php:392 +msgid "Finding:" msgstr "" -#: ../../Zotlabs/Module/Mitem.php:238 -msgid "Link text" +#: ../../Zotlabs/Module/Directory.php:395 ../../Zotlabs/Module/Suggest.php:62 +#: ../../include/contact_widgets.php:24 +msgid "Channel Suggestions" msgstr "" -#: ../../Zotlabs/Module/Events.php:25 -msgid "Calendar entries imported." +#: ../../Zotlabs/Module/Directory.php:397 +msgid "next page" msgstr "" -#: ../../Zotlabs/Module/Events.php:27 -msgid "No calendar entries found." +#: ../../Zotlabs/Module/Directory.php:397 +msgid "previous page" msgstr "" -#: ../../Zotlabs/Module/Events.php:110 -msgid "Event can not end before it has started." +#: ../../Zotlabs/Module/Directory.php:398 +msgid "Sort options" msgstr "" -#: ../../Zotlabs/Module/Events.php:112 ../../Zotlabs/Module/Events.php:121 -#: ../../Zotlabs/Module/Events.php:143 -msgid "Unable to generate preview." +#: ../../Zotlabs/Module/Directory.php:399 +msgid "Alphabetic" msgstr "" -#: ../../Zotlabs/Module/Events.php:119 -msgid "Event title and start time are required." +#: ../../Zotlabs/Module/Directory.php:400 +msgid "Reverse Alphabetic" msgstr "" -#: ../../Zotlabs/Module/Events.php:141 ../../Zotlabs/Module/Events.php:265 -msgid "Event not found." +#: ../../Zotlabs/Module/Directory.php:401 +msgid "Newest to Oldest" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Directory.php:402 +msgid "Oldest to Newest" +======= #: ../../Zotlabs/Module/Events.php:260 ../../Zotlabs/Module/Tagger.php:51 #: ../../Zotlabs/Module/Like.php:372 ../../include/conversation.php:119 -#: ../../include/text.php:1954 ../../include/event.php:1141 +#: ../../include/text.php:1940 ../../include/event.php:1141 msgid "event" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Events.php:460 -msgid "Edit event title" +#: ../../Zotlabs/Module/Directory.php:419 +msgid "No entries (some entries may be hidden)." msgstr "" -#: ../../Zotlabs/Module/Events.php:460 ../../addon/cdav/Mod_Cdav.php:835 -msgid "Event title" +#: ../../Zotlabs/Module/Profiles.php:24 ../../Zotlabs/Module/Profiles.php:184 +#: ../../Zotlabs/Module/Profiles.php:241 ../../Zotlabs/Module/Profiles.php:659 +msgid "Profile not found." msgstr "" -#: ../../Zotlabs/Module/Events.php:460 ../../Zotlabs/Module/Events.php:465 -#: ../../Zotlabs/Module/Appman.php:136 ../../Zotlabs/Module/Appman.php:137 -#: ../../Zotlabs/Module/Profiles.php:748 ../../Zotlabs/Module/Profiles.php:752 -#: ../../include/datetime.php:259 -msgid "Required" +#: ../../Zotlabs/Module/Profiles.php:44 +msgid "Profile deleted." msgstr "" -#: ../../Zotlabs/Module/Events.php:462 -msgid "Categories (comma-separated list)" +#: ../../Zotlabs/Module/Profiles.php:68 ../../Zotlabs/Module/Profiles.php:105 +msgid "Profile-" msgstr "" -#: ../../Zotlabs/Module/Events.php:463 -msgid "Edit Category" +#: ../../Zotlabs/Module/Profiles.php:90 ../../Zotlabs/Module/Profiles.php:127 +msgid "New profile created." msgstr "" -#: ../../Zotlabs/Module/Events.php:463 -msgid "Category" +#: ../../Zotlabs/Module/Profiles.php:111 +msgid "Profile unavailable to clone." msgstr "" -#: ../../Zotlabs/Module/Events.php:466 -msgid "Edit start date and time" +#: ../../Zotlabs/Module/Profiles.php:146 +msgid "Profile unavailable to export." msgstr "" -#: ../../Zotlabs/Module/Events.php:466 ../../addon/cdav/Mod_Cdav.php:836 -msgid "Start date and time" +#: ../../Zotlabs/Module/Profiles.php:252 +msgid "Profile Name is required." msgstr "" -#: ../../Zotlabs/Module/Events.php:467 ../../Zotlabs/Module/Events.php:470 -msgid "Finish date and time are not known or not relevant" +#: ../../Zotlabs/Module/Profiles.php:459 +msgid "Marital Status" msgstr "" -#: ../../Zotlabs/Module/Events.php:469 -msgid "Edit finish date and time" +#: ../../Zotlabs/Module/Profiles.php:463 +msgid "Romantic Partner" msgstr "" -#: ../../Zotlabs/Module/Events.php:469 -msgid "Finish date and time" +#: ../../Zotlabs/Module/Profiles.php:467 ../../Zotlabs/Module/Profiles.php:775 +msgid "Likes" msgstr "" -#: ../../Zotlabs/Module/Events.php:471 ../../Zotlabs/Module/Events.php:472 -msgid "Adjust for viewer timezone" +#: ../../Zotlabs/Module/Profiles.php:471 ../../Zotlabs/Module/Profiles.php:776 +msgid "Dislikes" msgstr "" -#: ../../Zotlabs/Module/Events.php:471 -msgid "" -"Important for events that happen in a particular place. Not practical for " -"global holidays." +#: ../../Zotlabs/Module/Profiles.php:475 ../../Zotlabs/Module/Profiles.php:783 +msgid "Work/Employment" msgstr "" -#: ../../Zotlabs/Module/Events.php:473 -msgid "Edit Description" +#: ../../Zotlabs/Module/Profiles.php:478 +msgid "Religion" msgstr "" -#: ../../Zotlabs/Module/Events.php:473 ../../Zotlabs/Module/Appman.php:138 -#: ../../Zotlabs/Module/Rbmark.php:101 -#: ../../addon/rendezvous/rendezvous.php:173 ../../addon/cdav/Mod_Cdav.php:838 -msgid "Description" +#: ../../Zotlabs/Module/Profiles.php:482 +msgid "Political Views" msgstr "" -#: ../../Zotlabs/Module/Events.php:475 -msgid "Edit Location" +#: ../../Zotlabs/Module/Profiles.php:486 +#: ../../extend/addon/addon/openid/MysqlProvider.php:74 +msgid "Gender" msgstr "" -#: ../../Zotlabs/Module/Events.php:478 ../../Zotlabs/Module/Photos.php:1063 -#: ../../Zotlabs/Module/Webpages.php:254 ../../Zotlabs/Lib/ThreadItem.php:741 -#: ../../include/conversation.php:1278 ../../include/page_widgets.php:43 -msgid "Preview" +#: ../../Zotlabs/Module/Profiles.php:490 +msgid "Sexual Preference" msgstr "" -#: ../../Zotlabs/Module/Events.php:479 ../../include/conversation.php:1341 -msgid "Permission settings" +#: ../../Zotlabs/Module/Profiles.php:494 +msgid "Homepage" msgstr "" -#: ../../Zotlabs/Module/Events.php:489 -msgid "Timezone:" +#: ../../Zotlabs/Module/Profiles.php:498 +msgid "Interests" msgstr "" -#: ../../Zotlabs/Module/Events.php:494 -msgid "Advanced Options" +#: ../../Zotlabs/Module/Profiles.php:502 ../../Zotlabs/Module/Profiles.php:793 +#: ../../Zotlabs/Module/Admin/Channels.php:160 +#: ../../Zotlabs/Module/Locs.php:118 ../../Zotlabs/Module/Connedit.php:909 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1143 +msgid "Address" msgstr "" -#: ../../Zotlabs/Module/Events.php:605 ../../Zotlabs/Module/Cal.php:264 -msgid "l, F j" +#: ../../Zotlabs/Module/Profiles.php:509 ../../Zotlabs/Module/Profiles.php:737 +#: ../../Zotlabs/Module/Locs.php:117 ../../Zotlabs/Module/Pubsites.php:51 +#: ../../Zotlabs/Module/Events.php:475 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:839 +#: ../../include/js_strings.php:25 +msgid "Location" msgstr "" -#: ../../Zotlabs/Module/Events.php:633 -msgid "Edit event" +#: ../../Zotlabs/Module/Profiles.php:594 +msgid "Profile updated." msgstr "" -#: ../../Zotlabs/Module/Events.php:635 -msgid "Delete event" +#: ../../Zotlabs/Module/Profiles.php:678 +msgid "Hide your connections list from viewers of this profile" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Profiles.php:681 +#: ../../Zotlabs/Module/Admin/Site.php:237 ../../Zotlabs/Module/Menu.php:100 +#: ../../Zotlabs/Module/Menu.php:157 ../../Zotlabs/Module/Filestorage.php:160 +#: ../../Zotlabs/Module/Filestorage.php:168 ../../Zotlabs/Module/Mitem.php:162 +#: ../../Zotlabs/Module/Mitem.php:163 ../../Zotlabs/Module/Mitem.php:240 +#: ../../Zotlabs/Module/Mitem.php:241 ../../Zotlabs/Module/Wiki.php:180 +#: ../../Zotlabs/Module/Api.php:97 ../../Zotlabs/Module/Connedit.php:392 +#: ../../Zotlabs/Module/Connedit.php:775 ../../Zotlabs/Module/Events.php:470 +#: ../../Zotlabs/Module/Events.php:471 ../../Zotlabs/Module/Removeme.php:63 +#: ../../Zotlabs/Module/Settings/Display.php:103 +#: ../../Zotlabs/Module/Settings/Channel.php:294 +#: ../../Zotlabs/Module/Photos.php:642 +#: ../../extend/addon/addon/dwpost/dwpost.php:73 +#: ../../extend/addon/addon/dwpost/dwpost.php:85 +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:120 +#: ../../extend/addon/addon/ijpost/ijpost.php:73 +#: ../../extend/addon/addon/ijpost/ijpost.php:85 +#: ../../extend/addon/addon/jappixmini/jappixmini.php:309 +#: ../../extend/addon/addon/jappixmini/jappixmini.php:313 +#: ../../extend/addon/addon/jappixmini/jappixmini.php:343 +#: ../../extend/addon/addon/jappixmini/jappixmini.php:351 +#: ../../extend/addon/addon/jappixmini/jappixmini.php:355 +#: ../../extend/addon/addon/jappixmini/jappixmini.php:359 +#: ../../extend/addon/addon/libertree/libertree.php:69 +#: ../../extend/addon/addon/libertree/libertree.php:81 +#: ../../extend/addon/addon/ljpost/ljpost.php:70 +#: ../../extend/addon/addon/ljpost/ljpost.php:82 +#: ../../extend/addon/addon/nofed/nofed.php:72 +#: ../../extend/addon/addon/nofed/nofed.php:76 +#: ../../extend/addon/addon/nsabait/nsabait.php:157 +#: ../../extend/addon/addon/nsfw/nsfw.php:84 +#: ../../extend/addon/addon/planets/planets.php:153 +#: ../../extend/addon/addon/pumpio/pumpio.php:219 +#: ../../extend/addon/addon/pumpio/pumpio.php:223 +#: ../../extend/addon/addon/pumpio/pumpio.php:227 +#: ../../extend/addon/addon/pumpio/pumpio.php:231 +#: ../../extend/addon/addon/rainbowtag/rainbowtag.php:81 +#: ../../extend/addon/addon/redred/redred.php:95 +#: ../../extend/addon/addon/redred/redred.php:99 +#: ../../extend/addon/addon/rtof/rtof.php:81 +#: ../../extend/addon/addon/rtof/rtof.php:85 +#: ../../extend/addon/addon/smileybutton/smileybutton.php:273 +#: ../../extend/addon/addon/smileybutton/smileybutton.php:277 +#: ../../extend/addon/addon/statusnet/statusnet.php:389 +#: ../../extend/addon/addon/statusnet/statusnet.php:411 +#: ../../extend/addon/addon/statusnet/statusnet.php:415 +#: ../../extend/addon/addon/statusnet/statusnet.php:424 +#: ../../extend/addon/addon/twitter/twitter.php:242 +#: ../../extend/addon/addon/twitter/twitter.php:246 +#: ../../extend/addon/addon/twitter/twitter.php:255 +#: ../../extend/addon/addon/visage/visage.php:166 +#: ../../extend/addon/addon/wppost/wppost.php:82 +#: ../../extend/addon/addon/wppost/wppost.php:105 +#: ../../extend/addon/addon/wppost/wppost.php:109 +#: ../../extend/addon/addon/xmpp/xmpp.php:53 +#: ../../extend/addon/addon/cdav/cdav.php:234 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:166 +#: ../../include/dir_fns.php:143 ../../include/dir_fns.php:144 +#: ../../include/dir_fns.php:145 ../../view/theme/redbasic/php/config.php:89 +#: ../../view/theme/redbasic/php/config.php:104 ../../boot.php:1595 +msgid "No" +======= #: ../../Zotlabs/Module/Events.php:660 ../../Zotlabs/Module/Cal.php:313 -#: ../../include/text.php:1773 +#: ../../include/text.php:1759 msgid "Link to Source" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Events.php:669 -msgid "calendar" +#: ../../Zotlabs/Module/Profiles.php:681 +#: ../../Zotlabs/Module/Admin/Site.php:239 ../../Zotlabs/Module/Menu.php:100 +#: ../../Zotlabs/Module/Menu.php:157 ../../Zotlabs/Module/Filestorage.php:160 +#: ../../Zotlabs/Module/Filestorage.php:168 ../../Zotlabs/Module/Mitem.php:162 +#: ../../Zotlabs/Module/Mitem.php:163 ../../Zotlabs/Module/Mitem.php:240 +#: ../../Zotlabs/Module/Mitem.php:241 ../../Zotlabs/Module/Wiki.php:180 +#: ../../Zotlabs/Module/Api.php:96 ../../Zotlabs/Module/Connedit.php:392 +#: ../../Zotlabs/Module/Events.php:470 ../../Zotlabs/Module/Events.php:471 +#: ../../Zotlabs/Module/Removeme.php:63 +#: ../../Zotlabs/Module/Settings/Display.php:103 +#: ../../Zotlabs/Module/Settings/Channel.php:294 +#: ../../Zotlabs/Module/Photos.php:642 +#: ../../extend/addon/addon/dwpost/dwpost.php:73 +#: ../../extend/addon/addon/dwpost/dwpost.php:85 +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:120 +#: ../../extend/addon/addon/ijpost/ijpost.php:73 +#: ../../extend/addon/addon/ijpost/ijpost.php:85 +#: ../../extend/addon/addon/jappixmini/jappixmini.php:309 +#: ../../extend/addon/addon/jappixmini/jappixmini.php:313 +#: ../../extend/addon/addon/jappixmini/jappixmini.php:343 +#: ../../extend/addon/addon/jappixmini/jappixmini.php:351 +#: ../../extend/addon/addon/jappixmini/jappixmini.php:355 +#: ../../extend/addon/addon/jappixmini/jappixmini.php:359 +#: ../../extend/addon/addon/libertree/libertree.php:69 +#: ../../extend/addon/addon/libertree/libertree.php:81 +#: ../../extend/addon/addon/ljpost/ljpost.php:70 +#: ../../extend/addon/addon/ljpost/ljpost.php:82 +#: ../../extend/addon/addon/nofed/nofed.php:72 +#: ../../extend/addon/addon/nofed/nofed.php:76 +#: ../../extend/addon/addon/nsabait/nsabait.php:157 +#: ../../extend/addon/addon/nsfw/nsfw.php:84 +#: ../../extend/addon/addon/planets/planets.php:153 +#: ../../extend/addon/addon/pumpio/pumpio.php:219 +#: ../../extend/addon/addon/pumpio/pumpio.php:223 +#: ../../extend/addon/addon/pumpio/pumpio.php:227 +#: ../../extend/addon/addon/pumpio/pumpio.php:231 +#: ../../extend/addon/addon/rainbowtag/rainbowtag.php:81 +#: ../../extend/addon/addon/redred/redred.php:95 +#: ../../extend/addon/addon/redred/redred.php:99 +#: ../../extend/addon/addon/rtof/rtof.php:81 +#: ../../extend/addon/addon/rtof/rtof.php:85 +#: ../../extend/addon/addon/smileybutton/smileybutton.php:273 +#: ../../extend/addon/addon/smileybutton/smileybutton.php:277 +#: ../../extend/addon/addon/statusnet/statusnet.php:389 +#: ../../extend/addon/addon/statusnet/statusnet.php:411 +#: ../../extend/addon/addon/statusnet/statusnet.php:415 +#: ../../extend/addon/addon/statusnet/statusnet.php:424 +#: ../../extend/addon/addon/twitter/twitter.php:242 +#: ../../extend/addon/addon/twitter/twitter.php:246 +#: ../../extend/addon/addon/twitter/twitter.php:255 +#: ../../extend/addon/addon/visage/visage.php:166 +#: ../../extend/addon/addon/wppost/wppost.php:82 +#: ../../extend/addon/addon/wppost/wppost.php:105 +#: ../../extend/addon/addon/wppost/wppost.php:109 +#: ../../extend/addon/addon/xmpp/xmpp.php:53 +#: ../../extend/addon/addon/cdav/cdav.php:234 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:166 +#: ../../include/dir_fns.php:143 ../../include/dir_fns.php:144 +#: ../../include/dir_fns.php:145 ../../view/theme/redbasic/php/config.php:89 +#: ../../view/theme/redbasic/php/config.php:104 ../../boot.php:1595 +msgid "Yes" msgstr "" -#: ../../Zotlabs/Module/Events.php:688 ../../Zotlabs/Module/Cal.php:336 -msgid "Edit Event" +#: ../../Zotlabs/Module/Profiles.php:725 +msgid "Edit Profile Details" msgstr "" -#: ../../Zotlabs/Module/Events.php:688 ../../Zotlabs/Module/Cal.php:336 -msgid "Create Event" +#: ../../Zotlabs/Module/Profiles.php:726 ../../Zotlabs/Module/Connect.php:98 +#: ../../Zotlabs/Module/Import.php:514 +#: ../../Zotlabs/Module/Admin/Features.php:66 +#: ../../Zotlabs/Module/Admin/Logs.php:84 +#: ../../Zotlabs/Module/Admin/Profs.php:157 +#: ../../Zotlabs/Module/Admin/Security.php:104 +#: ../../Zotlabs/Module/Admin/Account_edit.php:74 +#: ../../Zotlabs/Module/Admin/Accounts.php:166 +#: ../../Zotlabs/Module/Admin/Channels.php:147 +#: ../../Zotlabs/Module/Admin/Plugins.php:438 +#: ../../Zotlabs/Module/Admin/Themes.php:158 +#: ../../Zotlabs/Module/Admin/Site.php:279 ../../Zotlabs/Module/Locs.php:121 +#: ../../Zotlabs/Module/Filestorage.php:165 ../../Zotlabs/Module/Group.php:85 +#: ../../Zotlabs/Module/Setup.php:309 ../../Zotlabs/Module/Setup.php:350 +#: ../../Zotlabs/Module/Import_items.php:129 +#: ../../Zotlabs/Module/Mitem.php:243 ../../Zotlabs/Module/Wiki.php:169 +#: ../../Zotlabs/Module/Invite.php:149 ../../Zotlabs/Module/Poke.php:186 +#: ../../Zotlabs/Module/Pconfig.php:107 ../../Zotlabs/Module/Mood.php:139 +#: ../../Zotlabs/Module/Connedit.php:882 ../../Zotlabs/Module/Cal.php:343 +#: ../../Zotlabs/Module/Rate.php:166 ../../Zotlabs/Module/Appman.php:134 +#: ../../Zotlabs/Module/Pdledit.php:74 ../../Zotlabs/Module/Events.php:493 +#: ../../Zotlabs/Module/Sources.php:114 ../../Zotlabs/Module/Sources.php:149 +#: ../../Zotlabs/Module/Mail.php:425 +#: ../../Zotlabs/Module/Settings/Features.php:47 +#: ../../Zotlabs/Module/Settings/Oauth.php:87 +#: ../../Zotlabs/Module/Settings/Account.php:118 +#: ../../Zotlabs/Module/Settings/Display.php:203 +#: ../../Zotlabs/Module/Settings/Featured.php:50 +#: ../../Zotlabs/Module/Settings/Tokens.php:168 +#: ../../Zotlabs/Module/Settings/Channel.php:476 +#: ../../Zotlabs/Module/Settings/Permcats.php:110 +#: ../../Zotlabs/Module/Thing.php:320 ../../Zotlabs/Module/Thing.php:370 +#: ../../Zotlabs/Module/Photos.php:657 ../../Zotlabs/Module/Photos.php:1022 +#: ../../Zotlabs/Module/Photos.php:1062 ../../Zotlabs/Module/Photos.php:1180 +#: ../../Zotlabs/Module/Chat.php:194 ../../Zotlabs/Module/Chat.php:240 +#: ../../Zotlabs/Module/Xchan.php:15 ../../Zotlabs/Lib/ThreadItem.php:732 +#: ../../Zotlabs/Widget/Eventstools.php:16 +#: ../../extend/addon/addon/chords/Mod_Chords.php:60 +#: ../../extend/addon/addon/dwpost/dwpost.php:89 +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:124 +#: ../../extend/addon/addon/frphotos/frphotos.php:96 +#: ../../extend/addon/addon/hubwall/hubwall.php:95 +#: ../../extend/addon/addon/ijpost/ijpost.php:89 +#: ../../extend/addon/addon/irc/irc.php:53 +#: ../../extend/addon/addon/jappixmini/jappixmini.php:371 +#: ../../extend/addon/addon/libertree/libertree.php:85 +#: ../../extend/addon/addon/ljpost/ljpost.php:86 +#: ../../extend/addon/addon/logrot/logrot.php:35 +#: ../../extend/addon/addon/mailhost/mailhost.php:40 +#: ../../extend/addon/addon/nofed/nofed.php:80 +#: ../../extend/addon/addon/nsabait/nsabait.php:161 +#: ../../extend/addon/addon/nsfw/nsfw.php:92 +#: ../../extend/addon/addon/openclipatar/openclipatar.php:53 +#: ../../extend/addon/addon/openstreetmap/openstreetmap.php:168 +#: ../../extend/addon/addon/pageheader/pageheader.php:48 +#: ../../extend/addon/addon/piwik/piwik.php:95 +#: ../../extend/addon/addon/planets/planets.php:157 +#: ../../extend/addon/addon/pumpio/pumpio.php:237 +#: ../../extend/addon/addon/rainbowtag/rainbowtag.php:85 +#: ../../extend/addon/addon/redfiles/redfiles.php:124 +#: ../../extend/addon/addon/redphotos/redphotos.php:136 +#: ../../extend/addon/addon/redred/redred.php:119 +#: ../../extend/addon/addon/rtof/rtof.php:101 +#: ../../extend/addon/addon/skeleton/skeleton.php:65 +#: ../../extend/addon/addon/smileybutton/smileybutton.php:281 +#: ../../extend/addon/addon/startpage/startpage.php:113 +#: ../../extend/addon/addon/statusnet/statusnet.php:322 +#: ../../extend/addon/addon/statusnet/statusnet.php:380 +#: ../../extend/addon/addon/statusnet/statusnet.php:432 +#: ../../extend/addon/addon/statusnet/statusnet.php:899 +#: ../../extend/addon/addon/superblock/superblock.php:120 +#: ../../extend/addon/addon/twitter/twitter.php:217 +#: ../../extend/addon/addon/twitter/twitter.php:259 +#: ../../extend/addon/addon/visage/visage.php:170 +#: ../../extend/addon/addon/wppost/wppost.php:113 +#: ../../extend/addon/addon/xmpp/xmpp.php:69 +#: ../../extend/addon/addon/cdav/cdav.php:246 +#: ../../extend/addon/addon/likebanner/likebanner.php:57 +#: ../../extend/addon/addon/mailtest/mailtest.php:100 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:155 +#: ../../include/js_strings.php:22 ../../view/theme/redbasic/php/config.php:84 +msgid "Submit" msgstr "" -#: ../../Zotlabs/Module/Events.php:689 ../../Zotlabs/Module/Events.php:698 -#: ../../Zotlabs/Module/Cal.php:337 ../../Zotlabs/Module/Cal.php:344 -#: ../../Zotlabs/Module/Photos.php:911 ../../addon/cdav/Mod_Cdav.php:846 -msgid "Previous" +#: ../../Zotlabs/Module/Profiles.php:727 +msgid "View this profile" msgstr "" -#: ../../Zotlabs/Module/Events.php:690 ../../Zotlabs/Module/Events.php:699 -#: ../../Zotlabs/Module/Setup.php:264 ../../Zotlabs/Module/Cal.php:338 -#: ../../Zotlabs/Module/Cal.php:345 ../../Zotlabs/Module/Photos.php:920 -#: ../../addon/cdav/Mod_Cdav.php:847 -msgid "Next" +#: ../../Zotlabs/Module/Profiles.php:728 ../../Zotlabs/Module/Profiles.php:827 +#: ../../include/channel.php:1065 +msgid "Edit visibility" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Profiles.php:729 +msgid "Profile Tools" +======= #: ../../Zotlabs/Module/Events.php:691 ../../Zotlabs/Module/Cal.php:339 -#: ../../include/channel.php:1379 +#: ../../include/channel.php:1365 msgid "Export" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Events.php:695 ../../addon/cdav/Mod_Cdav.php:849 -msgid "Month" +#: ../../Zotlabs/Module/Profiles.php:730 +msgid "Change cover photo" msgstr "" -#: ../../Zotlabs/Module/Events.php:696 ../../addon/cdav/Mod_Cdav.php:850 -msgid "Week" +#: ../../Zotlabs/Module/Profiles.php:731 ../../include/channel.php:1036 +msgid "Change profile photo" msgstr "" -#: ../../Zotlabs/Module/Events.php:697 ../../addon/cdav/Mod_Cdav.php:851 -msgid "Day" +#: ../../Zotlabs/Module/Profiles.php:732 +msgid "Create a new profile using these settings" msgstr "" -#: ../../Zotlabs/Module/Events.php:700 ../../Zotlabs/Module/Cal.php:346 -#: ../../addon/cdav/Mod_Cdav.php:848 -msgid "Today" +#: ../../Zotlabs/Module/Profiles.php:733 +msgid "Clone this profile" msgstr "" -#: ../../Zotlabs/Module/Events.php:731 -msgid "Event removed" +#: ../../Zotlabs/Module/Profiles.php:734 +msgid "Delete this profile" msgstr "" -#: ../../Zotlabs/Module/Events.php:734 -msgid "Failed to remove event" +#: ../../Zotlabs/Module/Profiles.php:735 +msgid "Add profile things" msgstr "" -#: ../../Zotlabs/Module/Appman.php:38 ../../Zotlabs/Module/Appman.php:55 -msgid "App installed." +#: ../../Zotlabs/Module/Profiles.php:736 ../../include/conversation.php:1648 +msgid "Personal" msgstr "" -#: ../../Zotlabs/Module/Appman.php:48 -msgid "Malformed app." +#: ../../Zotlabs/Module/Profiles.php:738 +msgid "Relation" msgstr "" -#: ../../Zotlabs/Module/Appman.php:125 -msgid "Embed code" +#: ../../Zotlabs/Module/Profiles.php:739 ../../include/datetime.php:55 +msgid "Miscellaneous" msgstr "" -#: ../../Zotlabs/Module/Appman.php:131 -msgid "Edit App" +#: ../../Zotlabs/Module/Profiles.php:741 +msgid "Import profile from file" msgstr "" -#: ../../Zotlabs/Module/Appman.php:131 -msgid "Create App" +#: ../../Zotlabs/Module/Profiles.php:742 +msgid "Export profile to file" msgstr "" -#: ../../Zotlabs/Module/Appman.php:136 -msgid "Name of app" +#: ../../Zotlabs/Module/Profiles.php:743 +msgid "Your gender" msgstr "" -#: ../../Zotlabs/Module/Appman.php:137 -msgid "Location (URL) of app" +#: ../../Zotlabs/Module/Profiles.php:744 +msgid "Marital status" msgstr "" -#: ../../Zotlabs/Module/Appman.php:139 -msgid "Photo icon URL" +#: ../../Zotlabs/Module/Profiles.php:745 +msgid "Sexual preference" msgstr "" -#: ../../Zotlabs/Module/Appman.php:139 -msgid "80 x 80 pixels - optional" +#: ../../Zotlabs/Module/Profiles.php:748 +msgid "Profile name" msgstr "" -#: ../../Zotlabs/Module/Appman.php:140 -msgid "Categories (optional, comma separated list)" +#: ../../Zotlabs/Module/Profiles.php:748 ../../Zotlabs/Module/Profiles.php:752 +#: ../../Zotlabs/Module/Appman.php:122 ../../Zotlabs/Module/Appman.php:123 +#: ../../Zotlabs/Module/Events.php:460 ../../Zotlabs/Module/Events.php:465 +#: ../../include/datetime.php:259 +msgid "Required" msgstr "" -#: ../../Zotlabs/Module/Appman.php:141 -msgid "Version ID" +#: ../../Zotlabs/Module/Profiles.php:750 +msgid "This is your default profile." msgstr "" -#: ../../Zotlabs/Module/Appman.php:142 -msgid "Price of app" +#: ../../Zotlabs/Module/Profiles.php:752 +msgid "Your full name" msgstr "" -#: ../../Zotlabs/Module/Appman.php:143 -msgid "Location (URL) to purchase app" +#: ../../Zotlabs/Module/Profiles.php:753 +msgid "Title/Description" msgstr "" -#: ../../Zotlabs/Module/Regmod.php:15 -msgid "Please login." +#: ../../Zotlabs/Module/Profiles.php:756 +msgid "Street address" msgstr "" -#: ../../Zotlabs/Module/Magic.php:71 -msgid "Hub not found." +#: ../../Zotlabs/Module/Profiles.php:757 +msgid "Locality/City" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Profiles.php:758 +msgid "Region/State" msgstr "" +#: ../../Zotlabs/Module/Profiles.php:759 +msgid "Postal/Zip code" +======= #: ../../Zotlabs/Module/Subthread.php:87 ../../Zotlabs/Module/Tagger.php:47 #: ../../Zotlabs/Module/Like.php:370 #: ../../addon/redphotos/redphotohelper.php:71 -#: ../../addon/diaspora/inbound.php:1782 ../../include/conversation.php:116 -#: ../../include/text.php:1951 +#: ../../addon/diaspora/inbound.php:1783 ../../include/conversation.php:116 +#: ../../include/text.php:1937 msgid "photo" msgstr "" #: ../../Zotlabs/Module/Subthread.php:87 ../../Zotlabs/Module/Like.php:370 -#: ../../addon/diaspora/inbound.php:1782 ../../include/conversation.php:144 -#: ../../include/text.php:1957 +#: ../../addon/diaspora/inbound.php:1783 ../../include/conversation.php:144 +#: ../../include/text.php:1943 msgid "status" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Subthread.php:118 -#, php-format -msgid "%1$s is following %2$s's %3$s" +#: ../../Zotlabs/Module/Profiles.php:760 ../../Zotlabs/Module/Connedit.php:927 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1161 +msgid "Country" msgstr "" -#: ../../Zotlabs/Module/Subthread.php:120 -#, php-format -msgid "%1$s stopped following %2$s's %3$s" +#: ../../Zotlabs/Module/Profiles.php:765 +msgid "Who (if applicable)" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Profiles.php:765 +msgid "Examples: cathy123, Cathy Williams, cathy@example.com" +msgstr "" + +#: ../../Zotlabs/Module/Profiles.php:766 +msgid "Since (date)" +msgstr "" + +#: ../../Zotlabs/Module/Profiles.php:769 +msgid "Tell us about yourself" +msgstr "" + +#: ../../Zotlabs/Module/Profiles.php:770 +#: ../../extend/addon/addon/openid/MysqlProvider.php:68 +msgid "Homepage URL" +msgstr "" + +#: ../../Zotlabs/Module/Profiles.php:771 +msgid "Hometown" +msgstr "" + +#: ../../Zotlabs/Module/Profiles.php:772 +msgid "Political views" +msgstr "" + +#: ../../Zotlabs/Module/Profiles.php:773 +msgid "Religious views" msgstr "" +#: ../../Zotlabs/Module/Profiles.php:774 +msgid "Keywords used in directory listings" +======= #: ../../Zotlabs/Module/Import_items.php:48 ../../Zotlabs/Module/Import.php:64 msgid "Nothing to import." msgstr "" @@ -1234,119 +1665,129 @@ msgid "Use this form to import existing posts and content from an export file." msgstr "" #: ../../Zotlabs/Module/Import_items.php:127 -#: ../../Zotlabs/Module/Import.php:502 +#: ../../Zotlabs/Module/Import.php:501 msgid "File to Upload" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/New_channel.php:121 ../../Zotlabs/Module/Manage.php:136 -#, php-format -msgid "You have created %1$.0f of %2$.0f allowed channels." +#: ../../Zotlabs/Module/Profiles.php:774 +msgid "Example: fishing photography software" msgstr "" -#: ../../Zotlabs/Module/New_channel.php:134 -#: ../../Zotlabs/Module/Register.php:237 -msgid "Name or caption" +#: ../../Zotlabs/Module/Profiles.php:777 +msgid "Musical interests" msgstr "" -#: ../../Zotlabs/Module/New_channel.php:134 -#: ../../Zotlabs/Module/Register.php:237 -msgid "" -"Examples: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation " -"Group\"" +#: ../../Zotlabs/Module/Profiles.php:778 +msgid "Books, literature" msgstr "" -#: ../../Zotlabs/Module/New_channel.php:136 -#: ../../Zotlabs/Module/Register.php:239 -msgid "Choose a short nickname" +#: ../../Zotlabs/Module/Profiles.php:779 +msgid "Television" msgstr "" -#: ../../Zotlabs/Module/New_channel.php:136 -#: ../../Zotlabs/Module/Register.php:239 -#, php-format -msgid "" -"Your nickname will be used to create an easy to remember channel address e." -"g. nickname%s" +#: ../../Zotlabs/Module/Profiles.php:780 +msgid "Film/Dance/Culture/Entertainment" msgstr "" -#: ../../Zotlabs/Module/New_channel.php:137 -#: ../../Zotlabs/Module/Register.php:240 -msgid "Channel role and privacy" +#: ../../Zotlabs/Module/Profiles.php:781 +msgid "Hobbies/Interests" msgstr "" -#: ../../Zotlabs/Module/New_channel.php:137 -#: ../../Zotlabs/Module/Register.php:240 -msgid "Select a channel role with your privacy requirements." +#: ../../Zotlabs/Module/Profiles.php:782 +msgid "Love/Romance" msgstr "" -#: ../../Zotlabs/Module/New_channel.php:137 -#: ../../Zotlabs/Module/Register.php:240 -msgid "Read more about roles" +#: ../../Zotlabs/Module/Profiles.php:784 +msgid "School/Education" msgstr "" -#: ../../Zotlabs/Module/New_channel.php:140 -msgid "Create Channel" +#: ../../Zotlabs/Module/Profiles.php:785 +msgid "Contact information and social networks" msgstr "" -#: ../../Zotlabs/Module/New_channel.php:141 -msgid "" -"A channel is your identity on this network. It can represent a person, a " -"blog, or a forum to name a few. Channels can make connections with other " -"channels to share information with highly detailed permissions." +#: ../../Zotlabs/Module/Profiles.php:786 +msgid "My other channels" msgstr "" -#: ../../Zotlabs/Module/New_channel.php:142 -msgid "" -"or <a href=\"import\">import an existing channel</a> from another location." +#: ../../Zotlabs/Module/Profiles.php:788 +msgid "Communications" msgstr "" -#: ../../Zotlabs/Module/Removeme.php:35 -msgid "" -"Channel removals are not allowed within 48 hours of changing the account " -"password." +#: ../../Zotlabs/Module/Profiles.php:789 ../../Zotlabs/Module/Connedit.php:905 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1139 +msgid "Phone" msgstr "" -#: ../../Zotlabs/Module/Removeme.php:60 -msgid "Remove This Channel" +#: ../../Zotlabs/Module/Profiles.php:790 +#: ../../Zotlabs/Module/Admin/Accounts.php:169 +#: ../../Zotlabs/Module/Admin/Accounts.php:181 +#: ../../Zotlabs/Module/Connedit.php:906 +#: ../../extend/addon/addon/redred/redred.php:107 +#: ../../extend/addon/addon/rtof/rtof.php:93 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1140 +#: ../../extend/addon/addon/openid/MysqlProvider.php:56 +#: ../../extend/addon/addon/openid/MysqlProvider.php:57 +#: ../../include/network.php:1749 +msgid "Email" msgstr "" -#: ../../Zotlabs/Module/Removeme.php:61 -#: ../../Zotlabs/Module/Removeaccount.php:58 -msgid "WARNING: " +#: ../../Zotlabs/Module/Profiles.php:791 ../../Zotlabs/Module/Connedit.php:907 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1141 +msgid "Instant messenger" msgstr "" -#: ../../Zotlabs/Module/Removeme.php:61 -msgid "This channel will be completely removed from the network. " +#: ../../Zotlabs/Module/Profiles.php:792 ../../Zotlabs/Module/Connedit.php:908 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1142 +msgid "Website" msgstr "" -#: ../../Zotlabs/Module/Removeme.php:61 -#: ../../Zotlabs/Module/Removeaccount.php:58 -msgid "This action is permanent and can not be undone!" +#: ../../Zotlabs/Module/Profiles.php:794 ../../Zotlabs/Module/Connedit.php:910 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1144 +msgid "Note" msgstr "" -#: ../../Zotlabs/Module/Removeme.php:62 -#: ../../Zotlabs/Module/Removeaccount.php:59 -msgid "Please enter your password for verification:" +#: ../../Zotlabs/Module/Profiles.php:795 ../../Zotlabs/Module/Connedit.php:911 +#: ../../extend/addon/addon/cdav/cdav.php:270 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1145 +#: ../../include/connections.php:668 +msgid "Mobile" msgstr "" -#: ../../Zotlabs/Module/Removeme.php:63 -msgid "Remove this channel and all its clones from the network" +#: ../../Zotlabs/Module/Profiles.php:796 ../../Zotlabs/Module/Connedit.php:912 +#: ../../extend/addon/addon/cdav/cdav.php:271 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1146 +#: ../../include/connections.php:669 +msgid "Home" msgstr "" -#: ../../Zotlabs/Module/Removeme.php:63 -msgid "" -"By default only the instance of the channel located on this hub will be " -"removed from the network" +#: ../../Zotlabs/Module/Profiles.php:797 ../../Zotlabs/Module/Connedit.php:913 +#: ../../extend/addon/addon/cdav/cdav.php:274 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1147 +#: ../../include/connections.php:672 +msgid "Work" msgstr "" -#: ../../Zotlabs/Module/Removeme.php:64 -#: ../../Zotlabs/Module/Settings/Channel.php:575 -msgid "Remove Channel" +#: ../../Zotlabs/Module/Profiles.php:799 ../../Zotlabs/Module/Connedit.php:915 +#: ../../extend/addon/addon/jappixmini/jappixmini.php:368 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1149 +msgid "Add Contact" msgstr "" -#: ../../Zotlabs/Module/Sharedwithme.php:99 -msgid "Files: shared with me" +#: ../../Zotlabs/Module/Profiles.php:800 ../../Zotlabs/Module/Connedit.php:916 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1150 +msgid "Add Field" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Profiles.php:802 +#: ../../Zotlabs/Module/Admin/Plugins.php:453 +#: ../../Zotlabs/Module/Connedit.php:918 +#: ../../Zotlabs/Module/Settings/Oauth.php:42 +#: ../../Zotlabs/Module/Settings/Oauth.php:113 ../../Zotlabs/Lib/Apps.php:358 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1152 +msgid "Update" +======= #: ../../Zotlabs/Module/Sharedwithme.php:100 #: ../../Zotlabs/Module/Admin/Channels.php:159 #: ../../Zotlabs/Module/Settings/Oauth.php:89 @@ -1358,734 +1799,754 @@ msgstr "" #: ../../addon/rendezvous/rendezvous.php:172 ../../addon/cdav/Mod_Cdav.php:1136 #: ../../addon/gitwiki/Mod_Gitwiki.php:158 msgid "Name" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Sharedwithme.php:101 -msgid "NEW" +#: ../../Zotlabs/Module/Profiles.php:804 +#: ../../Zotlabs/Module/Admin/Plugins.php:423 +#: ../../Zotlabs/Module/Filer.php:55 ../../Zotlabs/Module/Fbrowser.php:66 +#: ../../Zotlabs/Module/Fbrowser.php:88 ../../Zotlabs/Module/Wiki.php:265 +#: ../../Zotlabs/Module/Wiki.php:290 ../../Zotlabs/Module/Connedit.php:920 +#: ../../Zotlabs/Module/Settings/Oauth.php:88 +#: ../../Zotlabs/Module/Settings/Oauth.php:114 +#: ../../Zotlabs/Module/Tagrm.php:15 ../../Zotlabs/Module/Tagrm.php:138 +#: ../../extend/addon/addon/js_upload/js_upload.php:46 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:866 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1154 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:244 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:267 +#: ../../include/conversation.php:1327 ../../include/conversation.php:1376 +msgid "Cancel" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Profiles.php:823 ../../include/channel.php:1061 +msgid "Profile Image" +======= #: ../../Zotlabs/Module/Sharedwithme.php:102 -#: ../../Zotlabs/Storage/Browser.php:235 ../../include/text.php:1407 +#: ../../Zotlabs/Storage/Browser.php:235 ../../include/text.php:1409 msgid "Size" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Sharedwithme.php:103 -#: ../../Zotlabs/Storage/Browser.php:236 -msgid "Last Modified" -msgstr "" - -#: ../../Zotlabs/Module/Sharedwithme.php:104 -msgid "Remove all files" +#: ../../Zotlabs/Module/Profiles.php:833 ../../include/nav.php:105 +#: ../../include/channel.php:1043 +msgid "Edit Profiles" msgstr "" -#: ../../Zotlabs/Module/Sharedwithme.php:105 -msgid "Remove this file" +#: ../../Zotlabs/Module/Profiles.php:834 ../../Zotlabs/Module/Manage.php:143 +#: ../../Zotlabs/Module/Wiki.php:168 ../../Zotlabs/Module/Chat.php:254 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:154 +msgid "Create New" msgstr "" -#: ../../Zotlabs/Module/Setup.php:176 -msgid "$Projectname Server - Setup" +#: ../../Zotlabs/Module/Help.php:23 +msgid "Documentation Search" msgstr "" -#: ../../Zotlabs/Module/Setup.php:180 -msgid "Could not connect to database." +#: ../../Zotlabs/Module/Help.php:80 ../../include/conversation.php:1764 +msgid "About" msgstr "" -#: ../../Zotlabs/Module/Setup.php:184 -msgid "" -"Could not connect to specified site URL. Possible SSL certificate or DNS " -"issue." +#: ../../Zotlabs/Module/Help.php:81 ../../Zotlabs/Module/Group.php:197 +msgid "Members" msgstr "" -#: ../../Zotlabs/Module/Setup.php:191 -msgid "Could not create table." +#: ../../Zotlabs/Module/Help.php:82 +msgid "Administrators" msgstr "" -#: ../../Zotlabs/Module/Setup.php:196 -msgid "Your site database has been installed." +#: ../../Zotlabs/Module/Help.php:83 +msgid "Developers" msgstr "" -#: ../../Zotlabs/Module/Setup.php:200 -msgid "" -"You may need to import the file \"install/schema_xxx.sql\" manually using a " -"database client." +#: ../../Zotlabs/Module/Help.php:84 +msgid "Tutorials" msgstr "" -#: ../../Zotlabs/Module/Setup.php:201 ../../Zotlabs/Module/Setup.php:263 -#: ../../Zotlabs/Module/Setup.php:753 -msgid "Please see the file \"install/INSTALL.txt\"." +#: ../../Zotlabs/Module/Help.php:93 +msgid "$Projectname Documentation" msgstr "" -#: ../../Zotlabs/Module/Setup.php:260 -msgid "System check" +#: ../../Zotlabs/Module/Help.php:94 +msgid "Contents" msgstr "" -#: ../../Zotlabs/Module/Setup.php:265 -msgid "Check again" +#: ../../Zotlabs/Module/Layouts.php:129 ../../Zotlabs/Module/Layouts.php:189 +#: ../../Zotlabs/Module/Editlayout.php:128 +msgid "Layout Name" msgstr "" -#: ../../Zotlabs/Module/Setup.php:287 -msgid "Database connection" +#: ../../Zotlabs/Module/Layouts.php:132 +#: ../../Zotlabs/Module/Editlayout.php:129 +msgid "Layout Description (Optional)" msgstr "" -#: ../../Zotlabs/Module/Setup.php:288 -msgid "" -"In order to install $Projectname we need to know how to connect to your " -"database." +#: ../../Zotlabs/Module/Layouts.php:184 ../../include/text.php:2296 +msgid "Layouts" msgstr "" -#: ../../Zotlabs/Module/Setup.php:289 -msgid "" -"Please contact your hosting provider or site administrator if you have " -"questions about these settings." +#: ../../Zotlabs/Module/Layouts.php:186 ../../Zotlabs/Lib/Apps.php:232 +#: ../../include/nav.php:157 ../../include/nav.php:264 +#: ../../include/help.php:55 ../../include/help.php:61 +msgid "Help" msgstr "" -#: ../../Zotlabs/Module/Setup.php:290 -msgid "" -"The database you specify below should already exist. If it does not, please " -"create it before continuing." +#: ../../Zotlabs/Module/Layouts.php:186 +msgid "Comanche page description language help" msgstr "" -#: ../../Zotlabs/Module/Setup.php:294 -msgid "Database Server Name" +#: ../../Zotlabs/Module/Layouts.php:190 +msgid "Layout Description" msgstr "" -#: ../../Zotlabs/Module/Setup.php:294 -msgid "Default is 127.0.0.1" +#: ../../Zotlabs/Module/Layouts.php:191 ../../Zotlabs/Module/Webpages.php:256 +#: ../../Zotlabs/Module/Menu.php:114 ../../Zotlabs/Module/Blocks.php:157 +#: ../../include/page_widgets.php:47 +msgid "Created" msgstr "" -#: ../../Zotlabs/Module/Setup.php:295 -msgid "Database Port" +#: ../../Zotlabs/Module/Layouts.php:192 ../../Zotlabs/Module/Webpages.php:257 +#: ../../Zotlabs/Module/Menu.php:115 ../../Zotlabs/Module/Blocks.php:158 +#: ../../include/page_widgets.php:48 +msgid "Edited" msgstr "" -#: ../../Zotlabs/Module/Setup.php:295 -msgid "Communication port number - use 0 for default" +#: ../../Zotlabs/Module/Layouts.php:194 ../../Zotlabs/Module/Webpages.php:246 +#: ../../Zotlabs/Module/Blocks.php:161 ../../Zotlabs/Module/Photos.php:1042 +#: ../../extend/addon/addon/cdav/include/widgets.php:123 +#: ../../include/conversation.php:1311 +msgid "Share" msgstr "" -#: ../../Zotlabs/Module/Setup.php:296 -msgid "Database Login Name" +#: ../../Zotlabs/Module/Layouts.php:195 +msgid "Download PDL file" msgstr "" -#: ../../Zotlabs/Module/Setup.php:297 -msgid "Database Login Password" +#: ../../Zotlabs/Module/Layouts.php:198 ../../Zotlabs/Module/Webpages.php:251 +#: ../../Zotlabs/Module/Pubsites.php:59 ../../Zotlabs/Module/Wiki.php:167 +#: ../../Zotlabs/Module/Blocks.php:166 ../../Zotlabs/Module/Events.php:694 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:153 +#: ../../include/page_widgets.php:42 +msgid "View" msgstr "" -#: ../../Zotlabs/Module/Setup.php:298 -msgid "Database Name" +#: ../../Zotlabs/Module/Connect.php:61 ../../Zotlabs/Module/Connect.php:109 +msgid "Continue" msgstr "" -#: ../../Zotlabs/Module/Setup.php:299 -msgid "Database Type" +#: ../../Zotlabs/Module/Connect.php:90 +msgid "Premium Channel Setup" msgstr "" -#: ../../Zotlabs/Module/Setup.php:301 ../../Zotlabs/Module/Setup.php:347 -msgid "Site administrator email address" +#: ../../Zotlabs/Module/Connect.php:92 +msgid "Enable premium channel connection restrictions" msgstr "" -#: ../../Zotlabs/Module/Setup.php:301 ../../Zotlabs/Module/Setup.php:347 +#: ../../Zotlabs/Module/Connect.php:93 msgid "" -"Your account email address must match this in order to use the web admin " -"panel." +"Please enter your restrictions or conditions, such as paypal receipt, usage " +"guidelines, etc." msgstr "" -#: ../../Zotlabs/Module/Setup.php:302 ../../Zotlabs/Module/Setup.php:349 -msgid "Website URL" +#: ../../Zotlabs/Module/Connect.php:95 ../../Zotlabs/Module/Connect.php:115 +msgid "" +"This channel may require additional steps or acknowledgement of the " +"following conditions prior to connecting:" msgstr "" -#: ../../Zotlabs/Module/Setup.php:302 ../../Zotlabs/Module/Setup.php:349 -msgid "Please use SSL (https) URL if available." +#: ../../Zotlabs/Module/Connect.php:96 +msgid "" +"Potential connections will then see the following text before proceeding:" msgstr "" -#: ../../Zotlabs/Module/Setup.php:303 ../../Zotlabs/Module/Setup.php:353 -msgid "Please select a default timezone for your website" +#: ../../Zotlabs/Module/Connect.php:97 ../../Zotlabs/Module/Connect.php:118 +msgid "" +"By continuing, I certify that I have complied with any instructions provided " +"on this page." msgstr "" -#: ../../Zotlabs/Module/Setup.php:328 ../../Zotlabs/Module/Admin/Site.php:258 -msgid "Basic/Minimal Social Networking" +#: ../../Zotlabs/Module/Connect.php:106 +msgid "(No specific instructions have been provided by the channel owner.)" msgstr "" -#: ../../Zotlabs/Module/Setup.php:329 ../../Zotlabs/Module/Admin/Site.php:259 -msgid "Standard Configuration (default)" +#: ../../Zotlabs/Module/Connect.php:114 +msgid "Restricted or Premium Channel" msgstr "" -#: ../../Zotlabs/Module/Setup.php:330 ../../Zotlabs/Module/Admin/Site.php:260 -msgid "Professional" +#: ../../Zotlabs/Module/Admin.php:60 +#: ../../Zotlabs/Module/Admin/Plugins.php:259 +#: ../../Zotlabs/Module/Admin/Themes.php:72 +#: ../../Zotlabs/Module/Filestorage.php:32 ../../Zotlabs/Module/Display.php:35 +#: ../../Zotlabs/Module/Viewsrc.php:24 ../../Zotlabs/Module/Thing.php:89 +#: ../../include/items.php:3316 +msgid "Item not found." msgstr "" -#: ../../Zotlabs/Module/Setup.php:336 -msgid "Site settings" +#: ../../Zotlabs/Module/Admin.php:94 +msgid "# Accounts" msgstr "" -#: ../../Zotlabs/Module/Setup.php:351 ../../Zotlabs/Module/Admin/Site.php:289 -msgid "Server Configuration/Role" +#: ../../Zotlabs/Module/Admin.php:95 +msgid "# blocked accounts" msgstr "" -#: ../../Zotlabs/Module/Setup.php:392 -msgid "PHP version 5.5 or greater is required." +#: ../../Zotlabs/Module/Admin.php:96 +msgid "# expired accounts" msgstr "" -#: ../../Zotlabs/Module/Setup.php:393 -msgid "PHP version" +#: ../../Zotlabs/Module/Admin.php:97 +msgid "# expiring accounts" msgstr "" -#: ../../Zotlabs/Module/Setup.php:409 -msgid "Could not find a command line version of PHP in the web server PATH." +#: ../../Zotlabs/Module/Admin.php:108 +msgid "# Channels" msgstr "" -#: ../../Zotlabs/Module/Setup.php:410 -msgid "" -"If you don't have a command line version of PHP installed on server, you " -"will not be able to run background polling via cron." +#: ../../Zotlabs/Module/Admin.php:109 +msgid "# primary" msgstr "" -#: ../../Zotlabs/Module/Setup.php:414 -msgid "PHP executable path" +#: ../../Zotlabs/Module/Admin.php:110 +msgid "# clones" msgstr "" -#: ../../Zotlabs/Module/Setup.php:414 -msgid "" -"Enter full path to php executable. You can leave this blank to continue the " -"installation." +#: ../../Zotlabs/Module/Admin.php:116 +msgid "Message queues" msgstr "" -#: ../../Zotlabs/Module/Setup.php:419 -msgid "Command line PHP" +#: ../../Zotlabs/Module/Admin.php:133 +msgid "Your software should be updated" msgstr "" -#: ../../Zotlabs/Module/Setup.php:429 -msgid "" -"Unable to check command line PHP, as shell_exec() is disabled. This is " -"required." +#: ../../Zotlabs/Module/Admin.php:137 ../../Zotlabs/Module/Admin/Logs.php:82 +#: ../../Zotlabs/Module/Admin/Security.php:86 +#: ../../Zotlabs/Module/Admin/Accounts.php:164 +#: ../../Zotlabs/Module/Admin/Channels.php:145 +#: ../../Zotlabs/Module/Admin/Plugins.php:341 +#: ../../Zotlabs/Module/Admin/Plugins.php:436 +#: ../../Zotlabs/Module/Admin/Themes.php:122 +#: ../../Zotlabs/Module/Admin/Themes.php:156 +#: ../../Zotlabs/Module/Admin/Site.php:277 +msgid "Administration" msgstr "" -#: ../../Zotlabs/Module/Setup.php:432 -msgid "" -"The command line version of PHP on your system does not have " -"\"register_argc_argv\" enabled." +#: ../../Zotlabs/Module/Admin.php:138 +msgid "Summary" msgstr "" -#: ../../Zotlabs/Module/Setup.php:433 -msgid "This is required for message delivery to work." +#: ../../Zotlabs/Module/Admin.php:141 +msgid "Registered accounts" msgstr "" -#: ../../Zotlabs/Module/Setup.php:436 -msgid "PHP register_argc_argv" +#: ../../Zotlabs/Module/Admin.php:142 +msgid "Pending registrations" msgstr "" -#: ../../Zotlabs/Module/Setup.php:454 -#, php-format -msgid "" -"Your max allowed total upload size is set to %s. Maximum size of one file to " -"upload is set to %s. You are allowed to upload up to %d files at once." +#: ../../Zotlabs/Module/Admin.php:143 +msgid "Registered channels" msgstr "" -#: ../../Zotlabs/Module/Setup.php:459 -msgid "You can adjust these settings in the server php.ini file." +#: ../../Zotlabs/Module/Admin.php:144 +msgid "Active plugins" msgstr "" -#: ../../Zotlabs/Module/Setup.php:461 -msgid "PHP upload limits" +#: ../../Zotlabs/Module/Admin.php:145 +msgid "Version" msgstr "" -#: ../../Zotlabs/Module/Setup.php:484 -msgid "" -"Error: the \"openssl_pkey_new\" function on this system is not able to " -"generate encryption keys" +#: ../../Zotlabs/Module/Admin.php:146 +msgid "Repository version (master)" msgstr "" -#: ../../Zotlabs/Module/Setup.php:485 -msgid "" -"If running under Windows, please see \"http://www.php.net/manual/en/openssl." -"installation.php\"." +#: ../../Zotlabs/Module/Admin.php:147 +msgid "Repository version (dev)" msgstr "" -#: ../../Zotlabs/Module/Setup.php:488 -msgid "Generate encryption keys" +#: ../../Zotlabs/Module/Import.php:64 ../../Zotlabs/Module/Import_items.php:48 +msgid "Nothing to import." msgstr "" -#: ../../Zotlabs/Module/Setup.php:505 -msgid "libCurl PHP module" +#: ../../Zotlabs/Module/Import.php:79 ../../Zotlabs/Module/Import.php:95 +#: ../../Zotlabs/Module/Import_items.php:72 +msgid "Unable to download data from old server" msgstr "" -#: ../../Zotlabs/Module/Setup.php:506 -msgid "GD graphics PHP module" +#: ../../Zotlabs/Module/Import.php:102 +#: ../../Zotlabs/Module/Import_items.php:77 +msgid "Imported file is empty." msgstr "" -#: ../../Zotlabs/Module/Setup.php:507 -msgid "OpenSSL PHP module" +#: ../../Zotlabs/Module/Import.php:121 +#: ../../Zotlabs/Module/Import_items.php:93 +#, php-format +msgid "Warning: Database versions differ by %1$d updates." msgstr "" -#: ../../Zotlabs/Module/Setup.php:508 -msgid "PDO database PHP module" +#: ../../Zotlabs/Module/Import.php:144 +#, php-format +msgid "Your service plan only allows %d channels." msgstr "" -#: ../../Zotlabs/Module/Setup.php:509 -msgid "mb_string PHP module" +#: ../../Zotlabs/Module/Import.php:158 +msgid "No channel. Import failed." msgstr "" -#: ../../Zotlabs/Module/Setup.php:510 -msgid "xml PHP module" +#: ../../Zotlabs/Module/Import.php:466 +msgid "Import completed." msgstr "" -#: ../../Zotlabs/Module/Setup.php:511 -msgid "zip PHP module" +#: ../../Zotlabs/Module/Import.php:494 +msgid "You must be logged in to use this feature." msgstr "" -#: ../../Zotlabs/Module/Setup.php:515 ../../Zotlabs/Module/Setup.php:517 -msgid "Apache mod_rewrite module" +#: ../../Zotlabs/Module/Import.php:499 +msgid "Import Channel" msgstr "" -#: ../../Zotlabs/Module/Setup.php:515 +#: ../../Zotlabs/Module/Import.php:500 msgid "" -"Error: Apache webserver mod-rewrite module is required but not installed." +"Use this form to import an existing channel from a different server/hub. You " +"may retrieve the channel identity from the old server/hub via the network or " +"provide an export file." msgstr "" -#: ../../Zotlabs/Module/Setup.php:521 ../../Zotlabs/Module/Setup.php:524 -msgid "exec" +#: ../../Zotlabs/Module/Import.php:501 +#: ../../Zotlabs/Module/Import_items.php:127 +msgid "File to Upload" msgstr "" -#: ../../Zotlabs/Module/Setup.php:521 -msgid "" -"Error: exec is required but is either not installed or has been disabled in " -"php.ini" +#: ../../Zotlabs/Module/Import.php:502 +msgid "Or provide the old server/hub details" msgstr "" -#: ../../Zotlabs/Module/Setup.php:527 ../../Zotlabs/Module/Setup.php:530 -msgid "shell_exec" +#: ../../Zotlabs/Module/Import.php:503 +msgid "Your old identity address (xyz@example.com)" msgstr "" -#: ../../Zotlabs/Module/Setup.php:527 -msgid "" -"Error: shell_exec is required but is either not installed or has been " -"disabled in php.ini" +#: ../../Zotlabs/Module/Import.php:504 +msgid "Your old login email address" msgstr "" -#: ../../Zotlabs/Module/Setup.php:535 -msgid "Error: libCURL PHP module required but not installed." +#: ../../Zotlabs/Module/Import.php:505 +msgid "Your old login password" msgstr "" -#: ../../Zotlabs/Module/Setup.php:539 +#: ../../Zotlabs/Module/Import.php:506 msgid "" -"Error: GD graphics PHP module with JPEG support required but not installed." -msgstr "" - -#: ../../Zotlabs/Module/Setup.php:543 -msgid "Error: openssl PHP module required but not installed." -msgstr "" - -#: ../../Zotlabs/Module/Setup.php:547 -msgid "Error: PDO database PHP module required but not installed." +"For either option, please choose whether to make this hub your new primary " +"address, or whether your old location should continue this role. You will be " +"able to post from either location, but only one can be marked as the primary " +"location for files, photos, and media." msgstr "" -#: ../../Zotlabs/Module/Setup.php:551 -msgid "Error: mb_string PHP module required but not installed." +#: ../../Zotlabs/Module/Import.php:507 +msgid "Make this hub my primary location" msgstr "" -#: ../../Zotlabs/Module/Setup.php:555 -msgid "Error: xml PHP module required for DAV but not installed." +#: ../../Zotlabs/Module/Import.php:508 +msgid "Move this channel (disable all previous locations)" msgstr "" -#: ../../Zotlabs/Module/Setup.php:559 -msgid "Error: zip PHP module required but not installed." +#: ../../Zotlabs/Module/Import.php:509 +msgid "Import a few months of posts if possible (limited by available memory" msgstr "" -#: ../../Zotlabs/Module/Setup.php:577 +#: ../../Zotlabs/Module/Import.php:510 msgid "" -"The web installer needs to be able to create a file called \".htconfig.php\" " -"in the top folder of your web server and it is unable to do so." +"This process may take several minutes to complete. Please submit the form " +"only once and leave this page open until finished." msgstr "" -#: ../../Zotlabs/Module/Setup.php:578 -msgid "" -"This is most often a permission setting, as the web server may not be able " -"to write files in your folder - even if you can." +#: ../../Zotlabs/Module/Page.php:40 ../../Zotlabs/Module/Block.php:31 +msgid "Invalid item." msgstr "" -#: ../../Zotlabs/Module/Setup.php:579 -msgid "" -"At the end of this procedure, we will give you a text to save in a file " -"named .htconfig.php in your Red top folder." +#: ../../Zotlabs/Module/Page.php:56 ../../Zotlabs/Module/Block.php:43 +#: ../../Zotlabs/Module/Cal.php:62 ../../Zotlabs/Module/Chanview.php:96 +#: ../../Zotlabs/Module/Wall_upload.php:31 +msgid "Channel not found." msgstr "" -#: ../../Zotlabs/Module/Setup.php:580 +#: ../../Zotlabs/Module/Page.php:131 msgid "" -"You can alternatively skip this procedure and perform a manual installation. " -"Please see the file \"install/INSTALL.txt\" for instructions." +"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod " +"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, " +"quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo " +"consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse " +"cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat " +"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." msgstr "" -#: ../../Zotlabs/Module/Setup.php:583 -msgid ".htconfig.php is writable" +#: ../../Zotlabs/Module/Webpages.php:52 +msgid "Import Webpage Elements" msgstr "" -#: ../../Zotlabs/Module/Setup.php:597 -msgid "" -"This software uses the Smarty3 template engine to render its web views. " -"Smarty3 compiles templates to PHP to speed up rendering." +#: ../../Zotlabs/Module/Webpages.php:53 +msgid "Import selected" msgstr "" -#: ../../Zotlabs/Module/Setup.php:598 -#, php-format -msgid "" -"In order to store these compiled templates, the web server needs to have " -"write access to the directory %s under the top level web folder." +#: ../../Zotlabs/Module/Webpages.php:76 +msgid "Export Webpage Elements" msgstr "" -#: ../../Zotlabs/Module/Setup.php:599 ../../Zotlabs/Module/Setup.php:620 -msgid "" -"Please ensure that the user that your web server runs as (e.g. www-data) has " -"write access to this folder." +#: ../../Zotlabs/Module/Webpages.php:77 +msgid "Export selected" msgstr "" -#: ../../Zotlabs/Module/Setup.php:600 -#, php-format -msgid "" -"Note: as a security measure, you should give the web server write access to " -"%s only--not the template files (.tpl) that it contains." +#: ../../Zotlabs/Module/Webpages.php:242 ../../Zotlabs/Lib/Apps.php:225 +#: ../../include/conversation.php:1832 +msgid "Webpages" msgstr "" -#: ../../Zotlabs/Module/Setup.php:603 -#, php-format -msgid "%s is writable" +#: ../../Zotlabs/Module/Webpages.php:252 ../../Zotlabs/Module/Events.php:478 +#: ../../Zotlabs/Module/Photos.php:1063 ../../Zotlabs/Lib/ThreadItem.php:741 +#: ../../include/page_widgets.php:43 ../../include/conversation.php:1280 +msgid "Preview" msgstr "" -#: ../../Zotlabs/Module/Setup.php:619 -msgid "" -"This software uses the store directory to save uploaded files. The web " -"server needs to have write access to the store directory under the top level " -"web folder" +#: ../../Zotlabs/Module/Webpages.php:253 ../../include/page_widgets.php:44 +msgid "Actions" msgstr "" -#: ../../Zotlabs/Module/Setup.php:623 -msgid "store is writable" +#: ../../Zotlabs/Module/Webpages.php:254 ../../include/page_widgets.php:45 +msgid "Page Link" msgstr "" -#: ../../Zotlabs/Module/Setup.php:655 -msgid "" -"SSL certificate cannot be validated. Fix certificate or disable https access " -"to this site." +#: ../../Zotlabs/Module/Webpages.php:255 +msgid "Page Title" msgstr "" -#: ../../Zotlabs/Module/Setup.php:656 -msgid "" -"If you have https access to your website or allow connections to TCP port " -"443 (the https: port), you MUST use a browser-valid certificate. You MUST " -"NOT use self-signed certificates!" +#: ../../Zotlabs/Module/Webpages.php:285 +msgid "Invalid file type." msgstr "" -#: ../../Zotlabs/Module/Setup.php:657 -msgid "" -"This restriction is incorporated because public posts from you may for " -"example contain references to images on your own hub." +#: ../../Zotlabs/Module/Webpages.php:297 +msgid "Error opening zip file" msgstr "" -#: ../../Zotlabs/Module/Setup.php:658 -msgid "" -"If your certificate is not recognized, members of other sites (who may " -"themselves have valid certificates) will get a warning message on their own " -"site complaining about security issues." +#: ../../Zotlabs/Module/Webpages.php:308 +msgid "Invalid folder path." msgstr "" -#: ../../Zotlabs/Module/Setup.php:659 -msgid "" -"This can cause usability issues elsewhere (not just on your own site) so we " -"must insist on this requirement." +#: ../../Zotlabs/Module/Webpages.php:335 +msgid "No webpage elements detected." msgstr "" -#: ../../Zotlabs/Module/Setup.php:660 -msgid "" -"Providers are available that issue free certificates which are browser-valid." +#: ../../Zotlabs/Module/Webpages.php:410 +msgid "Import complete." msgstr "" -#: ../../Zotlabs/Module/Setup.php:662 -msgid "" -"If you are confident that the certificate is valid and signed by a trusted " -"authority, check to see if you have failed to install an intermediate cert. " -"These are not normally required by browsers, but are required for server-to-" -"server communications." +#: ../../Zotlabs/Module/Ping.php:254 +msgid "sent you a private message" msgstr "" -#: ../../Zotlabs/Module/Setup.php:664 -msgid "SSL certificate validation" +#: ../../Zotlabs/Module/Ping.php:302 +msgid "added your channel" msgstr "" -#: ../../Zotlabs/Module/Setup.php:670 -msgid "" -"Url rewrite in .htaccess is not working. Check your server configuration." -"Test: " +#: ../../Zotlabs/Module/Ping.php:312 +msgid "g A l F d" msgstr "" -#: ../../Zotlabs/Module/Setup.php:673 -msgid "Url rewrite is working" +#: ../../Zotlabs/Module/Ping.php:330 +msgid "[today]" msgstr "" -#: ../../Zotlabs/Module/Setup.php:687 -msgid "" -"The database configuration file \".htconfig.php\" could not be written. " -"Please use the enclosed text to create a configuration file in your web " -"server root." +#: ../../Zotlabs/Module/Ping.php:339 +msgid "posted an event" msgstr "" -#: ../../Zotlabs/Module/Setup.php:711 ../../addon/rendezvous/rendezvous.php:401 -#: ../../addon/cdav/cdav.php:41 -msgid "Errors encountered creating database tables." +#: ../../Zotlabs/Module/Connections.php:52 +#: ../../Zotlabs/Module/Connections.php:157 +#: ../../Zotlabs/Module/Connections.php:246 +msgid "Blocked" msgstr "" -#: ../../Zotlabs/Module/Setup.php:751 -msgid "<h1>What next</h1>" +#: ../../Zotlabs/Module/Connections.php:57 +#: ../../Zotlabs/Module/Connections.php:164 +#: ../../Zotlabs/Module/Connections.php:245 +msgid "Ignored" msgstr "" -#: ../../Zotlabs/Module/Setup.php:752 -msgid "" -"IMPORTANT: You will need to [manually] setup a scheduled task for the poller." +#: ../../Zotlabs/Module/Connections.php:62 +#: ../../Zotlabs/Module/Connections.php:178 +#: ../../Zotlabs/Module/Connections.php:244 +msgid "Hidden" msgstr "" -#: ../../Zotlabs/Module/Connect.php:61 ../../Zotlabs/Module/Connect.php:109 -msgid "Continue" +#: ../../Zotlabs/Module/Connections.php:67 +#: ../../Zotlabs/Module/Connections.php:171 +#: ../../Zotlabs/Module/Connections.php:243 +msgid "Archived" msgstr "" -#: ../../Zotlabs/Module/Connect.php:90 -msgid "Premium Channel Setup" +#: ../../Zotlabs/Module/Connections.php:72 +#: ../../Zotlabs/Module/Connections.php:82 ../../Zotlabs/Module/Menu.php:116 +#: ../../include/conversation.php:1657 +msgid "New" msgstr "" -#: ../../Zotlabs/Module/Connect.php:92 -msgid "Enable premium channel connection restrictions" +#: ../../Zotlabs/Module/Connections.php:88 +#: ../../Zotlabs/Module/Connections.php:103 +#: ../../Zotlabs/Module/Connedit.php:709 ../../Zotlabs/Widget/Affinity.php:30 +msgid "All" msgstr "" -#: ../../Zotlabs/Module/Connect.php:93 -msgid "" -"Please enter your restrictions or conditions, such as paypal receipt, usage " -"guidelines, etc." +#: ../../Zotlabs/Module/Connections.php:134 +msgid "New Connections" msgstr "" -#: ../../Zotlabs/Module/Connect.php:95 ../../Zotlabs/Module/Connect.php:115 -msgid "" -"This channel may require additional steps or acknowledgement of the " -"following conditions prior to connecting:" +#: ../../Zotlabs/Module/Connections.php:137 +msgid "Show pending (new) connections" msgstr "" -#: ../../Zotlabs/Module/Connect.php:96 -msgid "" -"Potential connections will then see the following text before proceeding:" +#: ../../Zotlabs/Module/Connections.php:141 +#: ../../Zotlabs/Module/Profperm.php:140 +msgid "All Connections" msgstr "" -#: ../../Zotlabs/Module/Connect.php:97 ../../Zotlabs/Module/Connect.php:118 -msgid "" -"By continuing, I certify that I have complied with any instructions provided " -"on this page." +#: ../../Zotlabs/Module/Connections.php:144 +msgid "Show all connections" msgstr "" -#: ../../Zotlabs/Module/Connect.php:106 -msgid "(No specific instructions have been provided by the channel owner.)" +#: ../../Zotlabs/Module/Connections.php:160 +msgid "Only show blocked connections" msgstr "" -#: ../../Zotlabs/Module/Connect.php:114 -msgid "Restricted or Premium Channel" +#: ../../Zotlabs/Module/Connections.php:167 +msgid "Only show ignored connections" msgstr "" -#: ../../Zotlabs/Module/Admin/Queue.php:35 -msgid "Queue Statistics" +#: ../../Zotlabs/Module/Connections.php:174 +msgid "Only show archived connections" msgstr "" -#: ../../Zotlabs/Module/Admin/Queue.php:36 -msgid "Total Entries" +#: ../../Zotlabs/Module/Connections.php:181 +msgid "Only show hidden connections" msgstr "" -#: ../../Zotlabs/Module/Admin/Queue.php:37 -msgid "Priority" +#: ../../Zotlabs/Module/Connections.php:242 +msgid "Pending approval" msgstr "" -#: ../../Zotlabs/Module/Admin/Queue.php:38 -msgid "Destination URL" +#: ../../Zotlabs/Module/Connections.php:258 +#, php-format +msgid "%1$s [%2$s]" msgstr "" -#: ../../Zotlabs/Module/Admin/Queue.php:39 -msgid "Mark hub permanently offline" +#: ../../Zotlabs/Module/Connections.php:259 +msgid "Edit connection" msgstr "" -#: ../../Zotlabs/Module/Admin/Queue.php:40 -msgid "Empty queue for this hub" +#: ../../Zotlabs/Module/Connections.php:260 +msgid "Delete connection" msgstr "" -#: ../../Zotlabs/Module/Admin/Queue.php:41 -msgid "Last known contact" +#: ../../Zotlabs/Module/Connections.php:269 +msgid "Channel address" msgstr "" -#: ../../Zotlabs/Module/Admin/Features.php:55 -#: ../../Zotlabs/Module/Admin/Features.php:56 -#: ../../Zotlabs/Module/Settings/Features.php:38 -msgid "Off" +#: ../../Zotlabs/Module/Connections.php:271 +msgid "Network" msgstr "" -#: ../../Zotlabs/Module/Admin/Features.php:55 -#: ../../Zotlabs/Module/Admin/Features.php:56 -#: ../../Zotlabs/Module/Settings/Features.php:38 -msgid "On" +#: ../../Zotlabs/Module/Connections.php:274 +msgid "Call" msgstr "" -#: ../../Zotlabs/Module/Admin/Features.php:56 -#, php-format -msgid "Lock feature %s" +#: ../../Zotlabs/Module/Connections.php:276 +msgid "Status" msgstr "" -#: ../../Zotlabs/Module/Admin/Features.php:64 -msgid "Manage Additional Features" +#: ../../Zotlabs/Module/Connections.php:278 +msgid "Connected" msgstr "" -#: ../../Zotlabs/Module/Admin/Dbsync.php:19 -msgid "Update has been marked successful" +#: ../../Zotlabs/Module/Connections.php:280 +msgid "Approve connection" msgstr "" -#: ../../Zotlabs/Module/Admin/Dbsync.php:29 -#, php-format -msgid "Executing %s failed. Check system logs." +#: ../../Zotlabs/Module/Connections.php:281 +#: ../../Zotlabs/Module/Admin/Accounts.php:171 +msgid "Approve" msgstr "" -#: ../../Zotlabs/Module/Admin/Dbsync.php:32 -#, php-format -msgid "Update %s was successfully applied." +#: ../../Zotlabs/Module/Connections.php:282 +msgid "Ignore connection" msgstr "" -#: ../../Zotlabs/Module/Admin/Dbsync.php:36 -#, php-format -msgid "Update %s did not return a status. Unknown if it succeeded." +#: ../../Zotlabs/Module/Connections.php:283 +#: ../../Zotlabs/Module/Connedit.php:626 +msgid "Ignore" msgstr "" -#: ../../Zotlabs/Module/Admin/Dbsync.php:39 -#, php-format -msgid "Update function %s could not be found." +#: ../../Zotlabs/Module/Connections.php:284 +msgid "Recent activity" msgstr "" -#: ../../Zotlabs/Module/Admin/Dbsync.php:55 -msgid "No failed updates." +#: ../../Zotlabs/Module/Connections.php:308 ../../Zotlabs/Lib/Apps.php:216 +#: ../../include/text.php:957 ../../include/nav.php:181 +msgid "Connections" msgstr "" -#: ../../Zotlabs/Module/Admin/Dbsync.php:59 -msgid "Failed Updates" +#: ../../Zotlabs/Module/Connections.php:312 ../../Zotlabs/Module/Search.php:44 +#: ../../Zotlabs/Lib/Apps.php:237 ../../Zotlabs/Widget/Sitesearch.php:31 +#: ../../include/text.php:1027 ../../include/text.php:1039 +#: ../../include/nav.php:160 ../../include/acl_selectors.php:213 +msgid "Search" msgstr "" -#: ../../Zotlabs/Module/Admin/Dbsync.php:61 -msgid "Mark success (if update was manually applied)" +#: ../../Zotlabs/Module/Connections.php:313 +msgid "Search your connections" msgstr "" -#: ../../Zotlabs/Module/Admin/Dbsync.php:62 -msgid "Attempt to execute this update step automatically" +#: ../../Zotlabs/Module/Connections.php:314 +msgid "Connections search" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Cover_photo.php:56 +#: ../../Zotlabs/Module/Profile_photo.php:61 +msgid "Image uploaded but image cropping failed." +======= #: ../../Zotlabs/Module/Admin/Plugins.php:259 #: ../../Zotlabs/Module/Admin/Themes.php:72 ../../Zotlabs/Module/Thing.php:89 #: ../../Zotlabs/Module/Viewsrc.php:25 ../../Zotlabs/Module/Display.php:35 #: ../../Zotlabs/Module/Filestorage.php:32 ../../Zotlabs/Module/Admin.php:60 -#: ../../include/items.php:3416 +#: ../../include/items.php:3391 msgid "Item not found." +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:289 -#, php-format -msgid "Plugin %s disabled." +#: ../../Zotlabs/Module/Cover_photo.php:136 +#: ../../Zotlabs/Module/Cover_photo.php:186 +msgid "Cover Photos" msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:294 -#, php-format -msgid "Plugin %s enabled." +#: ../../Zotlabs/Module/Cover_photo.php:159 +#: ../../Zotlabs/Module/Profile_photo.php:137 +msgid "Image resize failed." msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:310 -#: ../../Zotlabs/Module/Admin/Themes.php:95 -msgid "Disable" +#: ../../Zotlabs/Module/Cover_photo.php:173 +#: ../../Zotlabs/Module/Profile_photo.php:203 ../../include/photos.php:145 +msgid "Unable to process image" msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:313 -#: ../../Zotlabs/Module/Admin/Themes.php:97 -msgid "Enable" +#: ../../Zotlabs/Module/Cover_photo.php:197 +#: ../../Zotlabs/Module/Profile_photo.php:238 +msgid "Image upload failed." msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:341 -#: ../../Zotlabs/Module/Admin/Plugins.php:436 -#: ../../Zotlabs/Module/Admin/Accounts.php:164 -#: ../../Zotlabs/Module/Admin/Logs.php:82 -#: ../../Zotlabs/Module/Admin/Channels.php:145 -#: ../../Zotlabs/Module/Admin/Themes.php:122 -#: ../../Zotlabs/Module/Admin/Themes.php:156 -#: ../../Zotlabs/Module/Admin/Site.php:277 -#: ../../Zotlabs/Module/Admin/Security.php:86 -#: ../../Zotlabs/Module/Admin.php:137 -msgid "Administration" +#: ../../Zotlabs/Module/Cover_photo.php:214 +#: ../../Zotlabs/Module/Profile_photo.php:257 +msgid "Unable to process image." msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:342 -#: ../../Zotlabs/Module/Admin/Plugins.php:437 ../../Zotlabs/Widget/Admin.php:27 -msgid "Plugins" +#: ../../Zotlabs/Module/Cover_photo.php:237 ../../include/items.php:4224 +msgid "female" msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:343 -#: ../../Zotlabs/Module/Admin/Themes.php:124 -msgid "Toggle" +#: ../../Zotlabs/Module/Cover_photo.php:238 ../../include/items.php:4225 +#, php-format +msgid "%1$s updated her %2$s" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Cover_photo.php:239 ../../include/items.php:4226 +msgid "male" +======= #: ../../Zotlabs/Module/Admin/Plugins.php:344 #: ../../Zotlabs/Module/Admin/Themes.php:125 ../../Zotlabs/Lib/Apps.php:223 #: ../../Zotlabs/Widget/Settings_menu.php:131 ../../include/nav.php:207 msgid "Settings" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:351 -#: ../../Zotlabs/Module/Admin/Themes.php:134 -msgid "Author: " +#: ../../Zotlabs/Module/Cover_photo.php:240 ../../include/items.php:4227 +#, php-format +msgid "%1$s updated his %2$s" msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:352 -#: ../../Zotlabs/Module/Admin/Themes.php:135 -msgid "Maintainer: " +#: ../../Zotlabs/Module/Cover_photo.php:242 ../../include/items.php:4229 +#, php-format +msgid "%1$s updated their %2$s" msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:353 -msgid "Minimum project version: " +#: ../../Zotlabs/Module/Cover_photo.php:244 ../../include/channel.php:1738 +msgid "cover photo" msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:354 -msgid "Maximum project version: " +#: ../../Zotlabs/Module/Cover_photo.php:307 +#: ../../Zotlabs/Module/Cover_photo.php:322 +#: ../../Zotlabs/Module/Profile_photo.php:318 +#: ../../Zotlabs/Module/Profile_photo.php:365 +msgid "Photo not available." msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:355 -msgid "Minimum PHP version: " +#: ../../Zotlabs/Module/Cover_photo.php:358 +#: ../../Zotlabs/Module/Profile_photo.php:420 +msgid "Upload File:" msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:356 -msgid "Compatible Server Roles: " +#: ../../Zotlabs/Module/Cover_photo.php:359 +#: ../../Zotlabs/Module/Profile_photo.php:421 +msgid "Select a profile:" msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:357 -msgid "Requires: " +#: ../../Zotlabs/Module/Cover_photo.php:360 +msgid "Upload Cover Photo" msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:358 -#: ../../Zotlabs/Module/Admin/Plugins.php:442 -msgid "Disabled - version incompatibility" +#: ../../Zotlabs/Module/Cover_photo.php:365 +#: ../../Zotlabs/Module/Profile_photo.php:429 +#: ../../Zotlabs/Module/Settings/Channel.php:404 +msgid "or" msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:411 -msgid "Enter the public git repository URL of the plugin repo." +#: ../../Zotlabs/Module/Cover_photo.php:365 +#: ../../Zotlabs/Module/Profile_photo.php:429 +msgid "skip this step" msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:412 -msgid "Plugin repo git URL" +#: ../../Zotlabs/Module/Cover_photo.php:365 +#: ../../Zotlabs/Module/Profile_photo.php:429 +msgid "select a photo from your photo albums" msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:413 -msgid "Custom repo name" +#: ../../Zotlabs/Module/Cover_photo.php:381 +#: ../../Zotlabs/Module/Profile_photo.php:448 +msgid "Crop Image" msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:413 -msgid "(optional)" +#: ../../Zotlabs/Module/Cover_photo.php:382 +#: ../../Zotlabs/Module/Profile_photo.php:449 +msgid "Please adjust the image cropping for optimum viewing." msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:414 -msgid "Download Plugin Repo" +#: ../../Zotlabs/Module/Cover_photo.php:384 +#: ../../Zotlabs/Module/Profile_photo.php:451 +msgid "Done Editing" msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:421 -msgid "Install new repo" +#: ../../Zotlabs/Module/Admin/Features.php:55 +#: ../../Zotlabs/Module/Admin/Features.php:56 +#: ../../Zotlabs/Module/Settings/Features.php:38 +msgid "Off" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Admin/Features.php:55 +#: ../../Zotlabs/Module/Admin/Features.php:56 +#: ../../Zotlabs/Module/Settings/Features.php:38 +msgid "On" msgstr "" +#: ../../Zotlabs/Module/Admin/Features.php:56 +#, php-format +msgid "Lock feature %s" +======= #: ../../Zotlabs/Module/Admin/Plugins.php:422 ../../Zotlabs/Lib/Apps.php:358 msgid "Install" msgstr "" @@ -2093,46 +2554,325 @@ msgstr "" #: ../../Zotlabs/Module/Admin/Plugins.php:423 #: ../../Zotlabs/Module/Settings/Oauth.php:88 #: ../../Zotlabs/Module/Settings/Oauth.php:114 -#: ../../Zotlabs/Module/Wiki.php:288 ../../Zotlabs/Module/Wiki.php:314 +#: ../../Zotlabs/Module/Wiki.php:265 ../../Zotlabs/Module/Wiki.php:290 #: ../../Zotlabs/Module/Connedit.php:920 ../../Zotlabs/Module/Fbrowser.php:66 #: ../../Zotlabs/Module/Fbrowser.php:88 ../../Zotlabs/Module/Profiles.php:804 #: ../../Zotlabs/Module/Filer.php:55 ../../Zotlabs/Module/Tagrm.php:15 #: ../../Zotlabs/Module/Tagrm.php:138 ../../addon/cdav/Mod_Cdav.php:866 #: ../../addon/cdav/Mod_Cdav.php:1154 ../../addon/js_upload/js_upload.php:46 #: ../../addon/gitwiki/Mod_Gitwiki.php:244 -#: ../../addon/gitwiki/Mod_Gitwiki.php:267 ../../include/conversation.php:1325 -#: ../../include/conversation.php:1374 +#: ../../addon/gitwiki/Mod_Gitwiki.php:267 ../../include/conversation.php:1327 +#: ../../include/conversation.php:1376 msgid "Cancel" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:445 -msgid "Manage Repos" +#: ../../Zotlabs/Module/Admin/Features.php:64 +msgid "Manage Additional Features" msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:446 -msgid "Installed Plugin Repositories" +#: ../../Zotlabs/Module/Admin/Logs.php:28 +msgid "Log settings updated." msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:447 -msgid "Install a New Plugin Repository" +#: ../../Zotlabs/Module/Admin/Logs.php:83 ../../Zotlabs/Widget/Admin.php:48 +#: ../../Zotlabs/Widget/Admin.php:58 +msgid "Logs" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Admin/Logs.php:85 +msgid "Clear" +======= #: ../../Zotlabs/Module/Admin/Plugins.php:453 #: ../../Zotlabs/Module/Settings/Oauth.php:42 #: ../../Zotlabs/Module/Settings/Oauth.php:113 #: ../../Zotlabs/Module/Connedit.php:918 ../../Zotlabs/Module/Profiles.php:802 #: ../../Zotlabs/Lib/Apps.php:358 ../../addon/cdav/Mod_Cdav.php:1152 msgid "Update" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:454 -msgid "Switch branch" +#: ../../Zotlabs/Module/Admin/Logs.php:91 +msgid "Debugging" msgstr "" -#: ../../Zotlabs/Module/Admin/Plugins.php:455 -#: ../../Zotlabs/Module/Photos.php:960 ../../Zotlabs/Module/Tagrm.php:137 -#: ../../addon/superblock/superblock.php:116 -msgid "Remove" +#: ../../Zotlabs/Module/Admin/Logs.php:92 +msgid "Log file" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Logs.php:92 +msgid "" +"Must be writable by web server. Relative to your top-level webserver " +"directory." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Logs.php:93 +msgid "Log level" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Profs.php:69 +msgid "New Profile Field" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Profs.php:70 +#: ../../Zotlabs/Module/Admin/Profs.php:90 +msgid "Field nickname" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Profs.php:70 +#: ../../Zotlabs/Module/Admin/Profs.php:90 +msgid "System name of field" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Profs.php:71 +#: ../../Zotlabs/Module/Admin/Profs.php:91 +msgid "Input type" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Profs.php:72 +#: ../../Zotlabs/Module/Admin/Profs.php:92 +msgid "Field Name" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Profs.php:72 +#: ../../Zotlabs/Module/Admin/Profs.php:92 +msgid "Label on profile pages" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Admin/Profs.php:73 +#: ../../Zotlabs/Module/Admin/Profs.php:93 +msgid "Help text" +======= +#: ../../Zotlabs/Module/Admin/Accounts.php:169 +#: ../../Zotlabs/Module/Admin/Accounts.php:181 +#: ../../Zotlabs/Module/Connedit.php:906 ../../Zotlabs/Module/Profiles.php:790 +#: ../../addon/cdav/Mod_Cdav.php:1140 ../../addon/openid/MysqlProvider.php:56 +#: ../../addon/openid/MysqlProvider.php:57 ../../addon/rtof/rtof.php:93 +#: ../../addon/redred/redred.php:107 ../../include/network.php:2315 +msgid "Email" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 +msgstr "" + +#: ../../Zotlabs/Module/Admin/Profs.php:73 +#: ../../Zotlabs/Module/Admin/Profs.php:93 +msgid "Additional info (optional)" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Profs.php:74 +#: ../../Zotlabs/Module/Admin/Profs.php:94 ../../Zotlabs/Module/Filer.php:53 +#: ../../Zotlabs/Module/Rbmark.php:32 ../../Zotlabs/Module/Rbmark.php:104 +#: ../../Zotlabs/Widget/Notes.php:18 ../../include/text.php:1028 +#: ../../include/text.php:1040 +msgid "Save" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Profs.php:83 +msgid "Field definition not found" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Admin/Profs.php:89 +msgid "Edit Profile Field" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Profs.php:147 ../../Zotlabs/Widget/Admin.php:30 +msgid "Profile Fields" +======= +#: ../../Zotlabs/Module/Admin/Accounts.php:174 +#: ../../Zotlabs/Module/Connedit.php:618 +msgid "Block" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Accounts.php:175 +#: ../../Zotlabs/Module/Connedit.php:618 +msgid "Unblock" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 +msgstr "" + +#: ../../Zotlabs/Module/Admin/Profs.php:148 +msgid "Basic Profile Fields" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Profs.php:149 +msgid "Advanced Profile Fields" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Profs.php:149 +msgid "(In addition to basic fields)" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Profs.php:151 +msgid "All available fields" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Profs.php:152 +msgid "Custom Fields" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Profs.php:156 +msgid "Create Custom Field" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:77 +msgid "" +"By default, unfiltered HTML is allowed in embedded media. This is inherently " +"insecure." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:80 +msgid "" +"The recommended setting is to only allow unfiltered HTML from the following " +"sites:" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:81 +msgid "" +"https://youtube.com/<br />https://www.youtube.com/<br />https://youtu.be/" +"<br />https://vimeo.com/<br />https://soundcloud.com/<br />" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:82 +msgid "" +"All other embedded content will be filtered, <strong>unless</strong> " +"embedded content from that site is explicitly blocked." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:87 +#: ../../Zotlabs/Widget/Admin.php:25 +msgid "Security" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:89 +msgid "Block public" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:89 +msgid "" +"Check to block public access to all otherwise public personal pages on this " +"site unless you are currently authenticated." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:90 +msgid "Set \"Transport Security\" HTTP header" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:91 +msgid "Set \"Content Security Policy\" HTTP header" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:92 +msgid "Allowed email domains" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:92 +msgid "" +"Comma separated list of domains which are allowed in email addresses for " +"registrations to this site. Wildcards are accepted. Empty to allow any " +"domains" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:93 +msgid "Not allowed email domains" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:93 +msgid "" +"Comma separated list of domains which are not allowed in email addresses for " +"registrations to this site. Wildcards are accepted. Empty to allow any " +"domains, unless allowed domains have been defined." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:94 +msgid "Allow communications only from these sites" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:94 +msgid "" +"One site per line. Leave empty to allow communication from anywhere by " +"default" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:95 +msgid "Block communications from these sites" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:96 +msgid "Allow communications only from these channels" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:96 +msgid "" +"One channel (hash) per line. Leave empty to allow from any channel by default" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:97 +msgid "Block communications from these channels" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:98 +msgid "Only allow embeds from secure (SSL) websites and links." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:99 +msgid "Allow unfiltered embedded HTML content only from these domains" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Security.php:99 +msgid "One site per line. By default embedded content is filtered." +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Admin/Security.php:100 +msgid "Block embedded HTML from these domains" +======= +#: ../../Zotlabs/Module/Admin/Channels.php:154 +#: ../../include/conversation.php:1760 ../../include/nav.php:369 +msgid "Channel" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 +msgstr "" + +#: ../../Zotlabs/Module/Admin/Account_edit.php:29 +#, php-format +msgid "Password changed for account %d." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Account_edit.php:46 +msgid "Account settings updated." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Account_edit.php:61 +msgid "Account not found." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Account_edit.php:68 +msgid "Account Edit" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Account_edit.php:69 +msgid "New Password" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Account_edit.php:70 +msgid "New Password again" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Account_edit.php:71 +msgid "Technical skill level" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Account_edit.php:72 +msgid "Account language (for emails)" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Admin/Account_edit.php:73 +msgid "Service class" +======= +#: ../../Zotlabs/Module/Admin/Site.php:170 ../../include/text.php:2915 +msgid "Default" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" #: ../../Zotlabs/Module/Admin/Accounts.php:36 @@ -2187,24 +2927,10 @@ msgstr "" msgid "Request date" msgstr "" -#: ../../Zotlabs/Module/Admin/Accounts.php:169 -#: ../../Zotlabs/Module/Admin/Accounts.php:181 -#: ../../Zotlabs/Module/Connedit.php:906 ../../Zotlabs/Module/Profiles.php:790 -#: ../../addon/cdav/Mod_Cdav.php:1140 ../../addon/openid/MysqlProvider.php:56 -#: ../../addon/openid/MysqlProvider.php:57 ../../addon/rtof/rtof.php:93 -#: ../../addon/redred/redred.php:107 ../../include/network.php:2315 -msgid "Email" -msgstr "" - #: ../../Zotlabs/Module/Admin/Accounts.php:170 msgid "No registrations." msgstr "" -#: ../../Zotlabs/Module/Admin/Accounts.php:171 -#: ../../Zotlabs/Module/Connections.php:281 ../../include/conversation.php:686 -msgid "Approve" -msgstr "" - #: ../../Zotlabs/Module/Admin/Accounts.php:172 msgid "Deny" msgstr "" @@ -2255,37 +2981,6 @@ msgid "" "this site will be permanently deleted!\\n\\nAre you sure?" msgstr "" -#: ../../Zotlabs/Module/Admin/Logs.php:28 -msgid "Log settings updated." -msgstr "" - -#: ../../Zotlabs/Module/Admin/Logs.php:83 ../../Zotlabs/Widget/Admin.php:48 -#: ../../Zotlabs/Widget/Admin.php:58 -msgid "Logs" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Logs.php:85 -msgid "Clear" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Logs.php:91 -msgid "Debugging" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Logs.php:92 -msgid "Log file" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Logs.php:92 -msgid "" -"Must be writable by web server. Relative to your top-level webserver " -"directory." -msgstr "" - -#: ../../Zotlabs/Module/Admin/Logs.php:93 -msgid "Log level" -msgstr "" - #: ../../Zotlabs/Module/Admin/Channels.php:31 #, php-format msgid "%s channel censored/uncensored" @@ -2358,7 +3053,7 @@ msgid "Disallow Code" msgstr "" #: ../../Zotlabs/Module/Admin/Channels.php:154 -#: ../../include/conversation.php:1758 ../../include/nav.php:362 +#: ../../include/conversation.php:1751 msgid "Channel" msgstr "" @@ -2378,6 +3073,196 @@ msgid "" "channel on this site will be permanently deleted!\\n\\nAre you sure?" msgstr "" +#: ../../Zotlabs/Module/Admin/Dbsync.php:19 +msgid "Update has been marked successful" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Dbsync.php:29 +#, php-format +msgid "Executing %s failed. Check system logs." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Dbsync.php:32 +#, php-format +msgid "Update %s was successfully applied." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Dbsync.php:36 +#, php-format +msgid "Update %s did not return a status. Unknown if it succeeded." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Dbsync.php:39 +#, php-format +msgid "Update function %s could not be found." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Dbsync.php:55 +msgid "No failed updates." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Dbsync.php:59 +msgid "Failed Updates" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Dbsync.php:61 +msgid "Mark success (if update was manually applied)" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Dbsync.php:62 +msgid "Attempt to execute this update step automatically" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Queue.php:35 +msgid "Queue Statistics" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Queue.php:36 +msgid "Total Entries" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Queue.php:37 +msgid "Priority" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Queue.php:38 +msgid "Destination URL" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Queue.php:39 +msgid "Mark hub permanently offline" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Queue.php:40 +msgid "Empty queue for this hub" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Queue.php:41 +msgid "Last known contact" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:289 +#, php-format +msgid "Plugin %s disabled." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:294 +#, php-format +msgid "Plugin %s enabled." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:310 +#: ../../Zotlabs/Module/Admin/Themes.php:95 +msgid "Disable" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:313 +#: ../../Zotlabs/Module/Admin/Themes.php:97 +msgid "Enable" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:342 +#: ../../Zotlabs/Module/Admin/Plugins.php:437 +#: ../../Zotlabs/Widget/Admin.php:27 +msgid "Plugins" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:343 +#: ../../Zotlabs/Module/Admin/Themes.php:124 +msgid "Toggle" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:344 +#: ../../Zotlabs/Module/Admin/Themes.php:125 ../../Zotlabs/Lib/Apps.php:223 +#: ../../Zotlabs/Widget/Settings_menu.php:131 ../../include/nav.php:203 +msgid "Settings" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:351 +#: ../../Zotlabs/Module/Admin/Themes.php:134 +msgid "Author: " +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:352 +#: ../../Zotlabs/Module/Admin/Themes.php:135 +msgid "Maintainer: " +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:353 +msgid "Minimum project version: " +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:354 +msgid "Maximum project version: " +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:355 +msgid "Minimum PHP version: " +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:356 +msgid "Compatible Server Roles: " +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:357 +msgid "Requires: " +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:358 +#: ../../Zotlabs/Module/Admin/Plugins.php:442 +msgid "Disabled - version incompatibility" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:411 +msgid "Enter the public git repository URL of the plugin repo." +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:412 +msgid "Plugin repo git URL" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:413 +msgid "Custom repo name" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:413 +msgid "(optional)" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:414 +msgid "Download Plugin Repo" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:421 +msgid "Install new repo" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:422 ../../Zotlabs/Lib/Apps.php:358 +msgid "Install" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:445 +msgid "Manage Repos" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:446 +msgid "Installed Plugin Repositories" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:447 +msgid "Install a New Plugin Repository" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:454 +msgid "Switch branch" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Plugins.php:455 +#: ../../Zotlabs/Module/Tagrm.php:137 ../../Zotlabs/Module/Photos.php:960 +#: ../../extend/addon/addon/superblock/superblock.php:116 +msgid "Remove" +msgstr "" + #: ../../Zotlabs/Module/Admin/Themes.php:26 msgid "Theme settings updated." msgstr "" @@ -2407,8 +3292,7 @@ msgstr "" msgid "Site settings updated." msgstr "" -#: ../../Zotlabs/Module/Admin/Site.php:170 -#: ../../view/theme/redbasic/php/config.php:15 ../../include/text.php:2928 +#: ../../Zotlabs/Module/Admin/Site.php:170 ../../include/text.php:2942 msgid "Default" msgstr "" @@ -2451,27 +3335,39 @@ msgstr "" msgid "My site offers free accounts with optional paid upgrades" msgstr "" -#: ../../Zotlabs/Module/Admin/Site.php:264 +#: ../../Zotlabs/Module/Admin/Site.php:258 +msgid "Basic/Minimal Social Networking" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Site.php:259 +msgid "Standard Configuration (default)" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Site.php:260 +msgid "Professional" +msgstr "" + +#: ../../Zotlabs/Module/Admin/Site.php:264 ../../Zotlabs/Lib/Techlevels.php:10 msgid "Beginner/Basic" msgstr "" -#: ../../Zotlabs/Module/Admin/Site.php:265 +#: ../../Zotlabs/Module/Admin/Site.php:265 ../../Zotlabs/Lib/Techlevels.php:11 msgid "Novice - not skilled but willing to learn" msgstr "" -#: ../../Zotlabs/Module/Admin/Site.php:266 +#: ../../Zotlabs/Module/Admin/Site.php:266 ../../Zotlabs/Lib/Techlevels.php:12 msgid "Intermediate - somewhat comfortable" msgstr "" -#: ../../Zotlabs/Module/Admin/Site.php:267 +#: ../../Zotlabs/Module/Admin/Site.php:267 ../../Zotlabs/Lib/Techlevels.php:13 msgid "Advanced - very comfortable" msgstr "" -#: ../../Zotlabs/Module/Admin/Site.php:268 +#: ../../Zotlabs/Module/Admin/Site.php:268 ../../Zotlabs/Lib/Techlevels.php:14 msgid "Expert - I can write computer code" msgstr "" -#: ../../Zotlabs/Module/Admin/Site.php:269 +#: ../../Zotlabs/Module/Admin/Site.php:269 ../../Zotlabs/Lib/Techlevels.php:15 msgid "Wizard - I probably know more than you do" msgstr "" @@ -2479,11 +3375,6 @@ msgstr "" msgid "Site" msgstr "" -#: ../../Zotlabs/Module/Admin/Site.php:280 -#: ../../Zotlabs/Module/Register.php:253 -msgid "Registration" -msgstr "" - #: ../../Zotlabs/Module/Admin/Site.php:281 msgid "File upload" msgstr "" @@ -2492,21 +3383,65 @@ msgstr "" msgid "Policies" msgstr "" -#: ../../Zotlabs/Module/Admin/Site.php:283 ../../include/contact_widgets.php:16 +<<<<<<< HEAD +#: ../../Zotlabs/Module/Admin/Site.php:283 +#: ../../include/contact_widgets.php:16 msgid "Advanced" msgstr "" #: ../../Zotlabs/Module/Admin/Site.php:287 -#: ../../addon/statusnet/statusnet.php:890 +#: ../../extend/addon/addon/statusnet/statusnet.php:890 msgid "Site name" msgstr "" +#: ../../Zotlabs/Module/Admin/Site.php:289 +msgid "Server Configuration/Role" +msgstr "" + #: ../../Zotlabs/Module/Admin/Site.php:291 msgid "Site default technical skill level" msgstr "" #: ../../Zotlabs/Module/Admin/Site.php:291 msgid "Used to provide a member experience matched to technical comfort level" +======= +#: ../../Zotlabs/Module/Settings/Permcats.php:103 +#: ../../Zotlabs/Module/Settings/Tokens.php:161 +#: ../../Zotlabs/Module/Connedit.php:886 +msgid "My Settings" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Permcats.php:105 +#: ../../Zotlabs/Module/Settings/Tokens.php:163 +#: ../../Zotlabs/Module/Connedit.php:881 +msgid "inherited" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Permcats.php:108 +#: ../../Zotlabs/Module/Settings/Tokens.php:166 +#: ../../Zotlabs/Module/Connedit.php:888 +msgid "Individual Permissions" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Permcats.php:109 +#: ../../Zotlabs/Module/Settings/Tokens.php:167 +#: ../../Zotlabs/Module/Connedit.php:889 +msgid "" +"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." +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:62 +#: ../../Zotlabs/Module/Settings/Channel.php:66 +#: ../../Zotlabs/Module/Settings/Channel.php:67 +#: ../../Zotlabs/Module/Settings/Channel.php:70 +#: ../../Zotlabs/Module/Settings/Channel.php:81 +#: ../../Zotlabs/Module/Connedit.php:707 ../../Zotlabs/Widget/Affinity.php:28 +#: ../../include/selectors.php:123 ../../include/channel.php:406 +#: ../../include/channel.php:407 ../../include/channel.php:414 +msgid "Friends" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" #: ../../Zotlabs/Module/Admin/Site.php:293 @@ -2531,7 +3466,8 @@ msgid "" "BBCode can be used here" msgstr "" -#: ../../Zotlabs/Module/Admin/Site.php:297 ../../Zotlabs/Module/Siteinfo.php:23 +#: ../../Zotlabs/Module/Admin/Site.php:297 +#: ../../Zotlabs/Module/Siteinfo.php:23 msgid "Site Information" msgstr "" @@ -2581,8 +3517,13 @@ msgid "" "limits." msgstr "" +<<<<<<< HEAD #: ../../Zotlabs/Module/Admin/Site.php:304 msgid "Does this site allow new member registration?" +======= +#: ../../Zotlabs/Module/Settings/Channel.php:482 ../../include/channel.php:1250 +msgid "Full Name:" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" #: ../../Zotlabs/Module/Admin/Site.php:305 @@ -2779,1195 +3720,730 @@ msgstr "" msgid "0 for no expiration of imported content" msgstr "" -#: ../../Zotlabs/Module/Admin/Profs.php:69 -msgid "New Profile Field" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Profs.php:70 -#: ../../Zotlabs/Module/Admin/Profs.php:90 -msgid "Field nickname" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Profs.php:70 -#: ../../Zotlabs/Module/Admin/Profs.php:90 -msgid "System name of field" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Profs.php:71 -#: ../../Zotlabs/Module/Admin/Profs.php:91 -msgid "Input type" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Profs.php:72 -#: ../../Zotlabs/Module/Admin/Profs.php:92 -msgid "Field Name" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Profs.php:72 -#: ../../Zotlabs/Module/Admin/Profs.php:92 -msgid "Label on profile pages" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Profs.php:73 -#: ../../Zotlabs/Module/Admin/Profs.php:93 -msgid "Help text" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Profs.php:73 -#: ../../Zotlabs/Module/Admin/Profs.php:93 -msgid "Additional info (optional)" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Profs.php:74 -#: ../../Zotlabs/Module/Admin/Profs.php:94 ../../Zotlabs/Module/Rbmark.php:32 -#: ../../Zotlabs/Module/Rbmark.php:104 ../../Zotlabs/Module/Filer.php:53 -#: ../../Zotlabs/Widget/Notes.php:18 ../../include/text.php:1028 -#: ../../include/text.php:1040 -msgid "Save" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Profs.php:83 -msgid "Field definition not found" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Profs.php:89 -msgid "Edit Profile Field" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Profs.php:147 ../../Zotlabs/Widget/Admin.php:30 -msgid "Profile Fields" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Profs.php:148 -msgid "Basic Profile Fields" -msgstr "" - -#: ../../Zotlabs/Module/Admin/Profs.php:149 -msgid "Advanced Profile Fields" +#: ../../Zotlabs/Module/Filer.php:52 +msgid "Enter a folder name" msgstr "" -#: ../../Zotlabs/Module/Admin/Profs.php:149 -msgid "(In addition to basic fields)" +#: ../../Zotlabs/Module/Filer.php:52 +msgid "or select an existing folder (doubleclick)" msgstr "" -#: ../../Zotlabs/Module/Admin/Profs.php:151 -msgid "All available fields" +#: ../../Zotlabs/Module/Filer.php:54 ../../Zotlabs/Lib/ThreadItem.php:137 +msgid "Save to Folder" msgstr "" -#: ../../Zotlabs/Module/Admin/Profs.php:152 -msgid "Custom Fields" +#: ../../Zotlabs/Module/Editlayout.php:79 +#: ../../Zotlabs/Module/Editwebpage.php:80 +#: ../../Zotlabs/Module/Editpost.php:24 ../../Zotlabs/Module/Editblock.php:79 +#: ../../Zotlabs/Module/Editblock.php:95 +msgid "Item not found" msgstr "" -#: ../../Zotlabs/Module/Admin/Profs.php:156 -msgid "Create Custom Field" +#: ../../Zotlabs/Module/Editlayout.php:137 +msgid "Edit Layout" msgstr "" -#: ../../Zotlabs/Module/Admin/Account_edit.php:29 -#, php-format -msgid "Password changed for account %d." +#: ../../Zotlabs/Module/Editwebpage.php:144 +msgid "Page link" msgstr "" -#: ../../Zotlabs/Module/Admin/Account_edit.php:46 -msgid "Account settings updated." +#: ../../Zotlabs/Module/Editwebpage.php:148 +#: ../../Zotlabs/Module/Editblock.php:116 ../../Zotlabs/Module/Mail.php:287 +#: ../../Zotlabs/Module/Mail.php:424 ../../Zotlabs/Module/Chat.php:205 +#: ../../include/conversation.php:1228 +msgid "Insert web link" msgstr "" -#: ../../Zotlabs/Module/Admin/Account_edit.php:61 -msgid "Account not found." +#: ../../Zotlabs/Module/Editwebpage.php:171 +msgid "Edit Webpage" msgstr "" -#: ../../Zotlabs/Module/Admin/Account_edit.php:68 -msgid "Account Edit" +#: ../../Zotlabs/Module/Chatsvc.php:131 +msgid "Away" msgstr "" -#: ../../Zotlabs/Module/Admin/Account_edit.php:69 -msgid "New Password" +#: ../../Zotlabs/Module/Chatsvc.php:136 +msgid "Online" msgstr "" -#: ../../Zotlabs/Module/Admin/Account_edit.php:70 -msgid "New Password again" +#: ../../Zotlabs/Module/Dirsearch.php:25 ../../Zotlabs/Module/Regdir.php:49 +msgid "This site is not a directory server" msgstr "" -#: ../../Zotlabs/Module/Admin/Account_edit.php:71 -msgid "Technical skill level" +#: ../../Zotlabs/Module/Dirsearch.php:33 +msgid "This directory server requires an access token" msgstr "" -#: ../../Zotlabs/Module/Admin/Account_edit.php:72 -msgid "Account language (for emails)" +#: ../../Zotlabs/Module/Network.php:96 +msgid "No such group" msgstr "" -#: ../../Zotlabs/Module/Admin/Account_edit.php:73 -msgid "Service class" +#: ../../Zotlabs/Module/Network.php:136 +msgid "No such channel" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:77 -msgid "" -"By default, unfiltered HTML is allowed in embedded media. This is inherently " -"insecure." +#: ../../Zotlabs/Module/Network.php:141 +msgid "forum" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:80 -msgid "" -"The recommended setting is to only allow unfiltered HTML from the following " -"sites:" +#: ../../Zotlabs/Module/Network.php:153 +msgid "Search Results For:" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:81 -msgid "" -"https://youtube.com/<br />https://www.youtube.com/<br />https://youtu.be/" -"<br />https://vimeo.com/<br />https://soundcloud.com/<br />" +#: ../../Zotlabs/Module/Network.php:221 +msgid "Privacy group is empty" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:82 -msgid "" -"All other embedded content will be filtered, <strong>unless</strong> " -"embedded content from that site is explicitly blocked." +#: ../../Zotlabs/Module/Network.php:230 +msgid "Privacy group: " msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:87 ../../Zotlabs/Widget/Admin.php:25 -msgid "Security" +#: ../../Zotlabs/Module/Network.php:256 +msgid "Invalid connection." msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:89 -msgid "Block public" +#: ../../Zotlabs/Module/Network.php:275 +#: ../../extend/addon/addon/redred/redred.php:65 +msgid "Invalid channel." msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:89 -msgid "" -"Check to block public access to all otherwise public personal pages on this " -"site unless you are currently authenticated." +#: ../../Zotlabs/Module/Menu.php:49 +msgid "Unable to update menu." msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:90 -msgid "Set \"Transport Security\" HTTP header" +#: ../../Zotlabs/Module/Menu.php:60 +msgid "Unable to create menu." msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:91 -msgid "Set \"Content Security Policy\" HTTP header" +#: ../../Zotlabs/Module/Menu.php:98 ../../Zotlabs/Module/Menu.php:110 +msgid "Menu Name" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:92 -msgid "Allowed email domains" +#: ../../Zotlabs/Module/Menu.php:98 +msgid "Unique name (not visible on webpage) - required" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:92 -msgid "" -"Comma separated list of domains which are allowed in email addresses for " -"registrations to this site. Wildcards are accepted. Empty to allow any " -"domains" +#: ../../Zotlabs/Module/Menu.php:99 ../../Zotlabs/Module/Menu.php:111 +msgid "Menu Title" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:93 -msgid "Not allowed email domains" +#: ../../Zotlabs/Module/Menu.php:99 +msgid "Visible on webpage - leave empty for no title" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:93 -msgid "" -"Comma separated list of domains which are not allowed in email addresses for " -"registrations to this site. Wildcards are accepted. Empty to allow any " -"domains, unless allowed domains have been defined." +#: ../../Zotlabs/Module/Menu.php:100 +msgid "Allow Bookmarks" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:94 -msgid "Allow communications only from these sites" +#: ../../Zotlabs/Module/Menu.php:100 ../../Zotlabs/Module/Menu.php:157 +msgid "Menu may be used to store saved bookmarks" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:94 -msgid "" -"One site per line. Leave empty to allow communication from anywhere by " -"default" +#: ../../Zotlabs/Module/Menu.php:101 ../../Zotlabs/Module/Menu.php:159 +msgid "Submit and proceed" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:95 -msgid "Block communications from these sites" +#: ../../Zotlabs/Module/Menu.php:107 ../../include/text.php:2295 +msgid "Menus" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:96 -msgid "Allow communications only from these channels" +#: ../../Zotlabs/Module/Menu.php:113 ../../Zotlabs/Module/Locs.php:120 +msgid "Drop" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:96 -msgid "" -"One channel (hash) per line. Leave empty to allow from any channel by default" +#: ../../Zotlabs/Module/Menu.php:117 +msgid "Bookmarks allowed" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:97 -msgid "Block communications from these channels" +#: ../../Zotlabs/Module/Menu.php:119 +msgid "Delete this menu" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:98 -msgid "Only allow embeds from secure (SSL) websites and links." +#: ../../Zotlabs/Module/Menu.php:120 ../../Zotlabs/Module/Menu.php:154 +msgid "Edit menu contents" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:99 -msgid "Allow unfiltered embedded HTML content only from these domains" +#: ../../Zotlabs/Module/Menu.php:121 +msgid "Edit this menu" msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:99 -msgid "One site per line. By default embedded content is filtered." +#: ../../Zotlabs/Module/Menu.php:136 +msgid "Menu could not be deleted." msgstr "" -#: ../../Zotlabs/Module/Admin/Security.php:100 -msgid "Block embedded HTML from these domains" +#: ../../Zotlabs/Module/Menu.php:144 ../../Zotlabs/Module/Mitem.php:28 +msgid "Menu not found." msgstr "" -#: ../../Zotlabs/Module/Lockview.php:75 -msgid "Remote privacy information not available." +#: ../../Zotlabs/Module/Menu.php:149 +msgid "Edit Menu" msgstr "" -#: ../../Zotlabs/Module/Lockview.php:96 -msgid "Visible to:" +#: ../../Zotlabs/Module/Menu.php:153 +msgid "Add or remove entries to this menu" msgstr "" -#: ../../Zotlabs/Module/Lockview.php:117 ../../Zotlabs/Module/Lockview.php:153 -#: ../../Zotlabs/Module/Acl.php:117 ../../include/acl_selectors.php:183 -msgctxt "acl" -msgid "Profile" +#: ../../Zotlabs/Module/Menu.php:155 +msgid "Menu name" msgstr "" -#: ../../Zotlabs/Module/Moderate.php:39 -msgid "Comment approved" +#: ../../Zotlabs/Module/Menu.php:155 +msgid "Must be unique, only seen by you" msgstr "" -#: ../../Zotlabs/Module/Moderate.php:43 -msgid "Comment deleted" +#: ../../Zotlabs/Module/Menu.php:156 +msgid "Menu title" msgstr "" -#: ../../Zotlabs/Module/Settings/Permcats.php:37 -msgid "Permission category saved." +#: ../../Zotlabs/Module/Menu.php:156 +msgid "Menu title as seen by others" msgstr "" -#: ../../Zotlabs/Module/Settings/Permcats.php:61 -msgid "" -"Use this form to create permission rules for various classes of people or " -"connections." +#: ../../Zotlabs/Module/Menu.php:157 +msgid "Allow bookmarks" msgstr "" -#: ../../Zotlabs/Module/Settings/Permcats.php:94 -msgid "Permission Categories" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Menu.php:166 ../../Zotlabs/Module/Mitem.php:120 +#: ../../Zotlabs/Module/Xchan.php:41 +msgid "Not found." +======= +#: ../../Zotlabs/Module/Settings/Tokens.php:160 +#: ../../Zotlabs/Module/Connedit.php:885 +msgid "Their Settings" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Settings/Permcats.php:102 -msgid "Permission Name" +#: ../../Zotlabs/Module/Editpost.php:35 +msgid "Item is not editable" msgstr "" -#: ../../Zotlabs/Module/Settings/Permcats.php:103 -#: ../../Zotlabs/Module/Settings/Tokens.php:161 -#: ../../Zotlabs/Module/Connedit.php:886 -msgid "My Settings" +#: ../../Zotlabs/Module/Editpost.php:108 ../../Zotlabs/Module/Rpost.php:138 +msgid "Edit post" msgstr "" -#: ../../Zotlabs/Module/Settings/Permcats.php:105 -#: ../../Zotlabs/Module/Settings/Tokens.php:163 -#: ../../Zotlabs/Module/Connedit.php:881 -msgid "inherited" +#: ../../Zotlabs/Module/Locs.php:25 ../../Zotlabs/Module/Locs.php:54 +msgid "Location not found." msgstr "" -#: ../../Zotlabs/Module/Settings/Permcats.php:108 -#: ../../Zotlabs/Module/Settings/Tokens.php:166 -#: ../../Zotlabs/Module/Connedit.php:888 -msgid "Individual Permissions" +#: ../../Zotlabs/Module/Locs.php:62 +msgid "Location lookup failed." msgstr "" -#: ../../Zotlabs/Module/Settings/Permcats.php:109 -#: ../../Zotlabs/Module/Settings/Tokens.php:167 -#: ../../Zotlabs/Module/Connedit.php:889 +#: ../../Zotlabs/Module/Locs.php:66 msgid "" -"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." -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:62 -#: ../../Zotlabs/Module/Settings/Channel.php:66 -#: ../../Zotlabs/Module/Settings/Channel.php:67 -#: ../../Zotlabs/Module/Settings/Channel.php:70 -#: ../../Zotlabs/Module/Settings/Channel.php:81 -#: ../../Zotlabs/Module/Connedit.php:707 ../../Zotlabs/Widget/Affinity.php:28 -#: ../../include/selectors.php:123 ../../include/channel.php:407 -#: ../../include/channel.php:408 ../../include/channel.php:415 -msgid "Friends" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:251 -#: ../../addon/rendezvous/rendezvous.php:82 -#: ../../addon/openstreetmap/openstreetmap.php:184 -#: ../../addon/msgfooter/msgfooter.php:54 ../../addon/logrot/logrot.php:54 -#: ../../addon/twitter/twitter.php:766 ../../addon/piwik/piwik.php:116 -#: ../../addon/xmpp/xmpp.php:102 -msgid "Settings updated." -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:312 -msgid "Nobody except yourself" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:313 -msgid "Only those you specifically allow" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:314 -msgid "Approved connections" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:315 -msgid "Any connections" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:316 -msgid "Anybody on this website" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:317 -msgid "Anybody in this network" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:318 -msgid "Anybody authenticated" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:319 -msgid "Anybody on the internet" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:395 -msgid "Publish your default profile in the network directory" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:400 -msgid "Allow us to suggest you as a potential friend to new members?" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:404 -#: ../../Zotlabs/Module/Profile_photo.php:429 -#: ../../Zotlabs/Module/Cover_photo.php:365 -msgid "or" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:409 -msgid "Your channel address is" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:412 -msgid "Your files/photos are accessible via WebDAV at" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:474 -msgid "Channel Settings" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:481 -msgid "Basic Settings" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:482 ../../include/channel.php:1264 -msgid "Full Name:" +"Please select another location to become primary before removing the primary " +"location." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:483 -#: ../../Zotlabs/Module/Settings/Account.php:119 -msgid "Email Address:" +#: ../../Zotlabs/Module/Locs.php:95 +msgid "Syncing locations" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:484 -msgid "Your Timezone:" +#: ../../Zotlabs/Module/Locs.php:105 +msgid "No locations found." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:485 -msgid "Default Post Location:" +#: ../../Zotlabs/Module/Locs.php:116 +msgid "Manage Channel Locations" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:485 -msgid "Geographical location to display on your posts" +#: ../../Zotlabs/Module/Locs.php:119 +msgid "Primary" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:486 -msgid "Use Browser Location:" +#: ../../Zotlabs/Module/Locs.php:122 +msgid "Sync Now" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:488 -msgid "Adult Content" +#: ../../Zotlabs/Module/Locs.php:123 +msgid "Please wait several minutes between consecutive operations." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:488 +#: ../../Zotlabs/Module/Locs.php:124 msgid "" -"This channel frequently or regularly publishes adult content. (Please tag " -"any adult material and/or nudity with #NSFW)" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:490 -msgid "Security and Privacy Settings" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:493 -msgid "Your permissions are already configured. Click to view/adjust" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:495 -msgid "Hide my online presence" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:495 -msgid "Prevents displaying in your profile that you are online" +"When possible, drop a location by logging into that website/hub and removing " +"your channel." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:497 -msgid "Simple Privacy Settings:" +#: ../../Zotlabs/Module/Locs.php:125 +msgid "Use this form to drop the location if the hub is no longer operating." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:498 -msgid "" -"Very Public - <em>extremely permissive (should be used with caution)</em>" +#: ../../Zotlabs/Module/Pubsites.php:24 ../../Zotlabs/Widget/Pubsites.php:12 +msgid "Public Hubs" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:499 +#: ../../Zotlabs/Module/Pubsites.php:27 msgid "" -"Typical - <em>default public, privacy when desired (similar to social " -"network permissions but with improved privacy)</em>" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Channel.php:500 -msgid "Private - <em>default private, never open or public</em>" +"The listed hubs allow public registration for the $Projectname network. All " +"hubs in the network are interlinked so membership on any of them conveys " +"membership in the network as a whole. Some hubs may require subscription or " +"provide tiered service plans. The hub itself <strong>may</strong> provide " +"additional details." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:501 -msgid "Blocked - <em>default blocked to/from everybody</em>" +#: ../../Zotlabs/Module/Pubsites.php:33 +msgid "Hub URL" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:503 -msgid "Allow others to tag your posts" +#: ../../Zotlabs/Module/Pubsites.php:33 +msgid "Access Type" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:503 -msgid "" -"Often used by the community to retro-actively flag inappropriate content" +#: ../../Zotlabs/Module/Pubsites.php:33 +msgid "Registration Policy" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:505 -msgid "Channel Permission Limits" +#: ../../Zotlabs/Module/Pubsites.php:33 +msgid "Stats" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:507 -msgid "Expire other channel content after this many days" +#: ../../Zotlabs/Module/Pubsites.php:33 +msgid "Software" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:507 -msgid "0 or blank to use the website limit." +#: ../../Zotlabs/Module/Pubsites.php:35 ../../Zotlabs/Module/Ratings.php:97 +#: ../../include/conversation.php:1032 +msgid "Ratings" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:507 -#, php-format -msgid "This website expires after %d days." +#: ../../Zotlabs/Module/Pubsites.php:48 +msgid "Rate" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:507 -msgid "This website does not expire imported content." +#: ../../Zotlabs/Module/Channel.php:32 ../../Zotlabs/Module/Chat.php:25 +#: ../../extend/addon/addon/chess/chess.php:403 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:28 +msgid "You must be logged in to see this page." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:507 -msgid "The website limit takes precedence if lower than your limit." +#: ../../Zotlabs/Module/Channel.php:47 ../../Zotlabs/Module/Profile.php:43 +#: ../../Zotlabs/Module/Hcard.php:35 +msgid "Posts and comments" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:508 -msgid "Maximum Friend Requests/Day:" +#: ../../Zotlabs/Module/Channel.php:54 ../../Zotlabs/Module/Profile.php:50 +#: ../../Zotlabs/Module/Hcard.php:42 +msgid "Only posts" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:508 -msgid "May reduce spam activity" +#: ../../Zotlabs/Module/Channel.php:112 +msgid "Insufficient permissions. Request redirected to profile page." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:509 -msgid "Default Access Control List (ACL)" +#: ../../Zotlabs/Module/Apps.php:45 +msgid "Apps" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:511 -msgid "Use my default audience setting for the type of object published" +#: ../../Zotlabs/Module/Apps.php:48 +msgid "Manage apps" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:518 -msgid "Channel permissions category:" +#: ../../Zotlabs/Module/Apps.php:49 +msgid "Create new app" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:519 -msgid "Default Permissions Group" +#: ../../Zotlabs/Module/Home.php:74 ../../Zotlabs/Module/Home.php:82 +#: ../../extend/addon/addon/opensearch/opensearch.php:42 +msgid "$Projectname" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:525 -msgid "Maximum private messages per day from unknown people:" +#: ../../Zotlabs/Module/Home.php:92 +#, php-format +msgid "Welcome to %s" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:525 -msgid "Useful to reduce spamming" +#: ../../Zotlabs/Module/Filestorage.php:87 +msgid "Permission Denied." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:528 -msgid "Notification Settings" +#: ../../Zotlabs/Module/Filestorage.php:103 +msgid "File not found." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:529 -msgid "By default post a status message when:" +#: ../../Zotlabs/Module/Filestorage.php:146 +msgid "Edit file permissions" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:530 -msgid "accepting a friend request" +#: ../../Zotlabs/Module/Filestorage.php:152 +#: ../../Zotlabs/Module/Connedit.php:672 ../../Zotlabs/Module/Thing.php:313 +#: ../../Zotlabs/Module/Thing.php:363 ../../Zotlabs/Module/Photos.php:647 +#: ../../Zotlabs/Module/Photos.php:1011 ../../Zotlabs/Module/Chat.php:233 +#: ../../include/acl_selectors.php:218 +msgid "Permissions" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:531 -msgid "joining a forum/community" +#: ../../Zotlabs/Module/Filestorage.php:159 +msgid "Set/edit permissions" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:532 -msgid "making an <em>interesting</em> profile change" +#: ../../Zotlabs/Module/Filestorage.php:160 +msgid "Include all files and sub folders" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:533 -msgid "Send a notification email when:" +#: ../../Zotlabs/Module/Filestorage.php:161 +msgid "Return to file list" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:534 -msgid "You receive a connection request" +#: ../../Zotlabs/Module/Filestorage.php:163 +msgid "Copy/paste this code to attach file to a post" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:535 -msgid "Your connections are confirmed" +#: ../../Zotlabs/Module/Filestorage.php:164 +msgid "Copy/paste this URL to link file from a web page" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:536 -msgid "Someone writes on your profile wall" +#: ../../Zotlabs/Module/Filestorage.php:166 +msgid "Share this file" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:537 -msgid "Someone writes a followup comment" +#: ../../Zotlabs/Module/Filestorage.php:167 +msgid "Show URL to this file" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:538 -msgid "You receive a private message" +#: ../../Zotlabs/Module/Filestorage.php:168 +msgid "Notify your contacts about this file" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:539 -msgid "You receive a friend suggestion" +#: ../../Zotlabs/Module/Fbrowser.php:29 ../../Zotlabs/Lib/Apps.php:229 +#: ../../include/conversation.php:1774 +msgid "Photos" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:540 -msgid "You are tagged in a post" +#: ../../Zotlabs/Module/Acl.php:117 ../../Zotlabs/Module/Lockview.php:117 +#: ../../Zotlabs/Module/Lockview.php:153 ../../include/acl_selectors.php:183 +msgctxt "acl" +msgid "Profile" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:541 -msgid "You are poked/prodded/etc. in a post" +#: ../../Zotlabs/Module/Acl.php:344 +msgid "network" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:543 -msgid "Someone likes your post/comment" +#: ../../Zotlabs/Module/Acl.php:354 +msgid "RSS" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:546 -msgid "Show visual notifications including:" +#: ../../Zotlabs/Module/Group.php:24 +msgid "Privacy group created." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:548 -msgid "Unseen grid activity" +#: ../../Zotlabs/Module/Group.php:30 +msgid "Could not create privacy group." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:549 -msgid "Unseen channel activity" +#: ../../Zotlabs/Module/Group.php:42 ../../Zotlabs/Module/Group.php:141 +#: ../../include/items.php:3847 +msgid "Privacy group not found." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:550 -msgid "Unseen private messages" +#: ../../Zotlabs/Module/Group.php:58 +msgid "Privacy group updated." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:550 -#: ../../Zotlabs/Module/Settings/Channel.php:555 -#: ../../Zotlabs/Module/Settings/Channel.php:556 -#: ../../Zotlabs/Module/Settings/Channel.php:557 -#: ../../addon/jappixmini/jappixmini.php:343 -msgid "Recommended" +#: ../../Zotlabs/Module/Group.php:90 +msgid "Create a group of channels." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:551 -msgid "Upcoming events" +#: ../../Zotlabs/Module/Group.php:91 ../../Zotlabs/Module/Group.php:184 +msgid "Privacy group name: " msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:552 -msgid "Events today" +#: ../../Zotlabs/Module/Group.php:93 ../../Zotlabs/Module/Group.php:187 +msgid "Members are visible to other channels" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:553 -msgid "Upcoming birthdays" +#: ../../Zotlabs/Module/Group.php:111 +msgid "Privacy group removed." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:553 -msgid "Not available in all themes" +#: ../../Zotlabs/Module/Group.php:113 +msgid "Unable to remove privacy group." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:554 -msgid "System (personal) notifications" +#: ../../Zotlabs/Module/Group.php:183 +msgid "Privacy group editor" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:555 -msgid "System info messages" +#: ../../Zotlabs/Module/Group.php:199 +msgid "All Connected Channels" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:556 -msgid "System critical alerts" +#: ../../Zotlabs/Module/Group.php:231 +msgid "Click on a channel to add or remove." msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:557 -msgid "New connections" +#: ../../Zotlabs/Module/Dreport.php:45 +msgid "Invalid message" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:558 -msgid "System Registrations" +#: ../../Zotlabs/Module/Dreport.php:78 +msgid "no results" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:559 -msgid "" -"Also show new wall posts, private messages and connections under Notices" +#: ../../Zotlabs/Module/Dreport.php:93 +msgid "channel sync processed" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:561 -msgid "Notify me of events this many days in advance" +#: ../../Zotlabs/Module/Dreport.php:97 +msgid "queued" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:561 -msgid "Must be greater than 0" +#: ../../Zotlabs/Module/Dreport.php:101 +msgid "posted" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:567 -msgid "Advanced Account/Page Type Settings" +#: ../../Zotlabs/Module/Dreport.php:105 +msgid "accepted for delivery" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:568 -msgid "Change the behaviour of this account for special situations" +#: ../../Zotlabs/Module/Dreport.php:109 +msgid "updated" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:570 -msgid "Miscellaneous Settings" +#: ../../Zotlabs/Module/Dreport.php:112 +msgid "update ignored" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:571 -msgid "Default photo upload folder" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Dreport.php:115 +msgid "permission denied" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:571 -#: ../../Zotlabs/Module/Settings/Channel.php:572 -msgid "%Y - current year, %m - current month" +#: ../../Zotlabs/Module/Dreport.php:119 +msgid "recipient not found" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:572 -msgid "Default file upload folder" +#: ../../Zotlabs/Module/Dreport.php:122 +msgid "mail recalled" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:574 -msgid "Personal menu to display in your channel pages" +#: ../../Zotlabs/Module/Dreport.php:125 +msgid "duplicate mail received" +======= +#: ../../Zotlabs/Module/Embedphotos.php:140 ../../Zotlabs/Module/Photos.php:751 +#: ../../Zotlabs/Module/Photos.php:1290 ../../Zotlabs/Widget/Album.php:78 +msgid "View Photo" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:576 -msgid "Remove this channel." +#: ../../Zotlabs/Module/Embedphotos.php:146 ../../Zotlabs/Module/Photos.php:757 +#: ../../Zotlabs/Module/Photos.php:1213 ../../Zotlabs/Lib/Apps.php:571 +#: ../../Zotlabs/Lib/Apps.php:649 ../../Zotlabs/Storage/Browser.php:163 +#: ../../Zotlabs/Widget/Album.php:84 ../../addon/cdav/Mod_Cdav.php:745 +#: ../../addon/cdav/Mod_Cdav.php:746 ../../addon/cdav/Mod_Cdav.php:753 +#: ../../include/conversation.php:1110 +msgid "Unknown" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:577 -msgid "Firefox Share $Projectname provider" +#: ../../Zotlabs/Module/Embedphotos.php:156 ../../Zotlabs/Module/Photos.php:782 +#: ../../Zotlabs/Widget/Album.php:95 +msgid "Edit Album" msgstr "" -#: ../../Zotlabs/Module/Settings/Channel.php:578 -msgid "Start calendar week on Monday" +#: ../../Zotlabs/Module/Embedphotos.php:158 ../../Zotlabs/Module/Photos.php:784 +#: ../../Zotlabs/Module/Photos.php:1321 +#: ../../Zotlabs/Module/Profile_photo.php:423 +#: ../../Zotlabs/Module/Cover_photo.php:361 +#: ../../Zotlabs/Storage/Browser.php:229 ../../Zotlabs/Storage/Browser.php:334 +#: ../../Zotlabs/Widget/Album.php:97 ../../addon/cdav/include/widgets.php:132 +#: ../../addon/cdav/include/widgets.php:168 +msgid "Upload" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Settings/Features.php:45 -msgid "Additional Features" +#: ../../Zotlabs/Module/Dreport.php:128 +msgid "mail delivered" msgstr "" -#: ../../Zotlabs/Module/Settings/Tokens.php:31 +#: ../../Zotlabs/Module/Dreport.php:148 #, php-format -msgid "This channel is limited to %d tokens" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Tokens.php:37 -msgid "Name and Password are required." -msgstr "" - -#: ../../Zotlabs/Module/Settings/Tokens.php:77 -msgid "Token saved." -msgstr "" - -#: ../../Zotlabs/Module/Settings/Tokens.php:113 -msgid "" -"Use this form to create temporary access identifiers to share things with " -"non-members. These identities may be used in Access Control Lists and " -"visitors may login using these credentials to access private content." -msgstr "" - -#: ../../Zotlabs/Module/Settings/Tokens.php:115 -msgid "" -"You may also provide <em>dropbox</em> style access links to friends and " -"associates by adding the Login Password to any specific site URL as shown. " -"Examples:" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Tokens.php:150 -#: ../../Zotlabs/Widget/Settings_menu.php:90 -msgid "Guest Access Tokens" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Tokens.php:157 -msgid "Login Name" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Tokens.php:158 -msgid "Login Password" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Tokens.php:159 -msgid "Expires (yyyy-mm-dd)" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Tokens.php:160 -#: ../../Zotlabs/Module/Connedit.php:885 -msgid "Their Settings" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:20 -msgid "Not valid email." -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:23 -msgid "Protected email address. Cannot change to that email." -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:32 -msgid "System failure storing new email. Please try again." -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:40 -msgid "Technical skill level updated" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:56 -msgid "Password verification failed." -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:63 -msgid "Passwords do not match. Password unchanged." -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:67 -msgid "Empty passwords are not allowed. Password unchanged." -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:81 -msgid "Password changed." -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:83 -msgid "Password update failed. Please try again." -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:112 -msgid "Account Settings" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:113 -msgid "Current Password" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:114 -msgid "Enter New Password" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:115 -msgid "Confirm New Password" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:115 -msgid "Leave password fields blank unless changing" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:116 -msgid "Your technical skill level" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:116 -msgid "Used to provide a member experience matched to your comfort level" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:120 -#: ../../Zotlabs/Module/Removeaccount.php:61 -msgid "Remove Account" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Account.php:121 -msgid "Remove this account including all its channels" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Featured.php:20 -msgid "Affinity Slider settings updated." +msgid "Delivery report for %1$s" msgstr "" -#: ../../Zotlabs/Module/Settings/Featured.php:34 -msgid "No feature settings configured" +#: ../../Zotlabs/Module/Dreport.php:151 +msgid "Options" msgstr "" -#: ../../Zotlabs/Module/Settings/Featured.php:41 -msgid "Default maximum affinity level" +#: ../../Zotlabs/Module/Dreport.php:152 +msgid "Redeliver" msgstr "" -#: ../../Zotlabs/Module/Settings/Featured.php:46 -msgid "Default minimum affinity level" +#: ../../Zotlabs/Module/Impel.php:41 ../../include/bbcode.php:203 +msgid "webpage" msgstr "" -#: ../../Zotlabs/Module/Settings/Featured.php:50 -msgid "Affinity Slider Settings" +#: ../../Zotlabs/Module/Impel.php:46 ../../include/bbcode.php:209 +msgid "block" msgstr "" -#: ../../Zotlabs/Module/Settings/Featured.php:60 -msgid "Feature/Addon Settings" +#: ../../Zotlabs/Module/Impel.php:51 ../../include/bbcode.php:206 +msgid "layout" msgstr "" -#: ../../Zotlabs/Module/Settings/Display.php:145 -msgid "No special theme for mobile devices" +#: ../../Zotlabs/Module/Impel.php:58 ../../include/bbcode.php:212 +msgid "menu" msgstr "" -#: ../../Zotlabs/Module/Settings/Display.php:148 +#: ../../Zotlabs/Module/Impel.php:181 #, php-format -msgid "%s - (Experimental)" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:198 -msgid "Display Settings" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:199 -msgid "Theme Settings" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:200 -msgid "Custom Theme Settings" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:201 -msgid "Content Settings" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:207 -msgid "Display Theme:" +msgid "%s element installed" msgstr "" -#: ../../Zotlabs/Module/Settings/Display.php:208 -msgid "Select scheme" +#: ../../Zotlabs/Module/Impel.php:184 +#, php-format +msgid "%s element installation failed" msgstr "" -#: ../../Zotlabs/Module/Settings/Display.php:210 -msgid "Mobile Theme:" +#: ../../Zotlabs/Module/Setup.php:176 +msgid "$Projectname Server - Setup" msgstr "" -#: ../../Zotlabs/Module/Settings/Display.php:211 -msgid "Preload images before rendering the page" +#: ../../Zotlabs/Module/Setup.php:180 +msgid "Could not connect to database." msgstr "" -#: ../../Zotlabs/Module/Settings/Display.php:211 +#: ../../Zotlabs/Module/Setup.php:184 msgid "" -"The subjective page load time will be longer but the page will be ready when " -"displayed" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:212 -msgid "Enable user zoom on mobile devices" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:213 -msgid "Update browser every xx seconds" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:213 -msgid "Minimum of 10 seconds, no maximum" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:214 -msgid "Maximum number of conversations to load at any time:" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:214 -msgid "Maximum of 100 items" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:215 -msgid "Show emoticons (smilies) as images" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:216 -msgid "Manual conversation updates" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:216 -msgid "Default is on, turning this off may increase screen jumping" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:217 -msgid "Link post titles to source" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:218 -msgid "System Page Layout Editor - (advanced)" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:221 -msgid "Use blog/list mode on channel page" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:221 -#: ../../Zotlabs/Module/Settings/Display.php:222 -msgid "(comments displayed separately)" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:222 -msgid "Use blog/list mode on grid page" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:223 -msgid "Channel page max height of content (in pixels)" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:223 -#: ../../Zotlabs/Module/Settings/Display.php:224 -msgid "click to expand content exceeding this height" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Display.php:224 -msgid "Grid page max height of content (in pixels)" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Oauth.php:34 -msgid "Name is required" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Oauth.php:38 -msgid "Key and Secret are required" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Oauth.php:86 -#: ../../Zotlabs/Module/Settings/Oauth.php:112 -#: ../../Zotlabs/Module/Settings/Oauth.php:148 -msgid "Add application" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Oauth.php:89 -msgid "Name of application" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Oauth.php:90 -#: ../../Zotlabs/Module/Settings/Oauth.php:116 -#: ../../addon/statusnet/statusnet.php:893 ../../addon/twitter/twitter.php:775 -msgid "Consumer Key" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Oauth.php:90 -#: ../../Zotlabs/Module/Settings/Oauth.php:91 -msgid "Automatically generated - change if desired. Max length 20" +"Could not connect to specified site URL. Possible SSL certificate or DNS " +"issue." msgstr "" -#: ../../Zotlabs/Module/Settings/Oauth.php:91 -#: ../../Zotlabs/Module/Settings/Oauth.php:117 -#: ../../addon/statusnet/statusnet.php:892 ../../addon/twitter/twitter.php:776 -msgid "Consumer Secret" +#: ../../Zotlabs/Module/Setup.php:191 +msgid "Could not create table." msgstr "" -#: ../../Zotlabs/Module/Settings/Oauth.php:92 -#: ../../Zotlabs/Module/Settings/Oauth.php:118 -msgid "Redirect" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Setup.php:196 +msgid "Your site database has been installed." +======= +#: ../../Zotlabs/Module/Thing.php:313 ../../Zotlabs/Module/Thing.php:363 +#: ../../Zotlabs/Module/Photos.php:647 ../../Zotlabs/Module/Photos.php:1011 +#: ../../Zotlabs/Module/Connedit.php:672 ../../Zotlabs/Module/Chat.php:233 +#: ../../Zotlabs/Module/Filestorage.php:152 ../../include/acl_selectors.php:218 +msgid "Permissions" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Settings/Oauth.php:92 +#: ../../Zotlabs/Module/Setup.php:200 msgid "" -"Redirect URI - leave blank unless your application specifically requires this" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Oauth.php:93 -#: ../../Zotlabs/Module/Settings/Oauth.php:119 -msgid "Icon url" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Oauth.php:93 -#: ../../Zotlabs/Module/Sources.php:112 ../../Zotlabs/Module/Sources.php:147 -msgid "Optional" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Oauth.php:104 -msgid "Application not found." -msgstr "" - -#: ../../Zotlabs/Module/Settings/Oauth.php:147 -msgid "Connected Apps" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Oauth.php:151 -msgid "Client key starts with" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Oauth.php:152 -msgid "No name" -msgstr "" - -#: ../../Zotlabs/Module/Settings/Oauth.php:153 -msgid "Remove authorization" -msgstr "" - -#: ../../Zotlabs/Module/Embedphotos.php:140 ../../Zotlabs/Module/Photos.php:751 -#: ../../Zotlabs/Module/Photos.php:1290 ../../Zotlabs/Widget/Portfolio.php:78 -#: ../../Zotlabs/Widget/Album.php:78 -msgid "View Photo" -msgstr "" - -#: ../../Zotlabs/Module/Embedphotos.php:146 ../../Zotlabs/Module/Photos.php:757 -#: ../../Zotlabs/Module/Photos.php:1213 ../../Zotlabs/Lib/Apps.php:700 -#: ../../Zotlabs/Lib/Apps.php:778 ../../Zotlabs/Storage/Browser.php:163 -#: ../../Zotlabs/Widget/Portfolio.php:86 ../../Zotlabs/Widget/Album.php:84 -#: ../../addon/cdav/Mod_Cdav.php:745 ../../addon/cdav/Mod_Cdav.php:746 -#: ../../addon/cdav/Mod_Cdav.php:753 ../../include/conversation.php:1108 -msgid "Unknown" -msgstr "" - -#: ../../Zotlabs/Module/Embedphotos.php:156 ../../Zotlabs/Module/Photos.php:782 -#: ../../Zotlabs/Widget/Portfolio.php:97 ../../Zotlabs/Widget/Album.php:95 -msgid "Edit Album" -msgstr "" - -#: ../../Zotlabs/Module/Embedphotos.php:158 ../../Zotlabs/Module/Photos.php:784 -#: ../../Zotlabs/Module/Photos.php:1321 -#: ../../Zotlabs/Module/Profile_photo.php:423 -#: ../../Zotlabs/Module/Cover_photo.php:361 -#: ../../Zotlabs/Storage/Browser.php:229 ../../Zotlabs/Storage/Browser.php:334 -#: ../../Zotlabs/Widget/Portfolio.php:99 ../../Zotlabs/Widget/Album.php:97 -#: ../../addon/cdav/include/widgets.php:132 -#: ../../addon/cdav/include/widgets.php:168 -msgid "Upload" -msgstr "" - -#: ../../Zotlabs/Module/Achievements.php:38 -msgid "Some blurb about what to do when you're new here" -msgstr "" - -#: ../../Zotlabs/Module/Thing.php:114 -msgid "Thing updated" -msgstr "" - -#: ../../Zotlabs/Module/Thing.php:166 -msgid "Object store: failed" -msgstr "" - -#: ../../Zotlabs/Module/Thing.php:170 -msgid "Thing added" -msgstr "" - -#: ../../Zotlabs/Module/Thing.php:196 -#, php-format -msgid "OBJ: %1$s %2$s %3$s" +"You may need to import the file \"install/schema_xxx.sql\" manually using a " +"database client." msgstr "" -#: ../../Zotlabs/Module/Thing.php:259 -msgid "Show Thing" +#: ../../Zotlabs/Module/Setup.php:201 ../../Zotlabs/Module/Setup.php:263 +#: ../../Zotlabs/Module/Setup.php:741 +msgid "Please see the file \"install/INSTALL.txt\"." msgstr "" -#: ../../Zotlabs/Module/Thing.php:266 -msgid "item not found." +#: ../../Zotlabs/Module/Setup.php:260 +msgid "System check" msgstr "" -#: ../../Zotlabs/Module/Thing.php:299 -msgid "Edit Thing" +#: ../../Zotlabs/Module/Setup.php:264 ../../Zotlabs/Module/Cal.php:338 +#: ../../Zotlabs/Module/Cal.php:345 ../../Zotlabs/Module/Events.php:690 +#: ../../Zotlabs/Module/Events.php:699 ../../Zotlabs/Module/Photos.php:920 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:847 +msgid "Next" msgstr "" -#: ../../Zotlabs/Module/Thing.php:301 ../../Zotlabs/Module/Thing.php:355 -msgid "Select a profile" +#: ../../Zotlabs/Module/Setup.php:265 +msgid "Check again" msgstr "" -#: ../../Zotlabs/Module/Thing.php:305 ../../Zotlabs/Module/Thing.php:358 -msgid "Post an activity" +#: ../../Zotlabs/Module/Setup.php:287 +msgid "Database connection" msgstr "" -#: ../../Zotlabs/Module/Thing.php:305 ../../Zotlabs/Module/Thing.php:358 -msgid "Only sends to viewers of the applicable profile" +#: ../../Zotlabs/Module/Setup.php:288 +msgid "" +"In order to install $Projectname we need to know how to connect to your " +"database." msgstr "" -#: ../../Zotlabs/Module/Thing.php:307 ../../Zotlabs/Module/Thing.php:360 -msgid "Name of thing e.g. something" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Setup.php:289 +msgid "" +"Please contact your hosting provider or site administrator if you have " +"questions about these settings." msgstr "" -#: ../../Zotlabs/Module/Thing.php:309 ../../Zotlabs/Module/Thing.php:361 -msgid "URL of thing (optional)" +#: ../../Zotlabs/Module/Setup.php:290 +msgid "" +"The database you specify below should already exist. If it does not, please " +"create it before continuing." msgstr "" -#: ../../Zotlabs/Module/Thing.php:311 ../../Zotlabs/Module/Thing.php:362 -msgid "URL for photo of thing (optional)" +#: ../../Zotlabs/Module/Setup.php:294 +msgid "Database Server Name" msgstr "" -#: ../../Zotlabs/Module/Thing.php:313 ../../Zotlabs/Module/Thing.php:363 -#: ../../Zotlabs/Module/Photos.php:647 ../../Zotlabs/Module/Photos.php:1011 -#: ../../Zotlabs/Module/Connedit.php:672 ../../Zotlabs/Module/Chat.php:233 -#: ../../Zotlabs/Module/Filestorage.php:152 ../../include/acl_selectors.php:218 -msgid "Permissions" +#: ../../Zotlabs/Module/Setup.php:294 +msgid "Default is 127.0.0.1" msgstr "" -#: ../../Zotlabs/Module/Thing.php:353 -msgid "Add Thing to your Profile" +#: ../../Zotlabs/Module/Setup.php:295 +msgid "Database Port" msgstr "" -#: ../../Zotlabs/Module/Notify.php:57 ../../Zotlabs/Module/Notifications.php:38 -msgid "No more system notifications." +#: ../../Zotlabs/Module/Setup.php:295 +msgid "Communication port number - use 0 for default" msgstr "" -#: ../../Zotlabs/Module/Notify.php:61 ../../Zotlabs/Module/Notifications.php:42 -msgid "System Notifications" +#: ../../Zotlabs/Module/Setup.php:296 +msgid "Database Login Name" msgstr "" -#: ../../Zotlabs/Module/Follow.php:31 -msgid "Channel added." +#: ../../Zotlabs/Module/Setup.php:297 +msgid "Database Login Password" msgstr "" -#: ../../Zotlabs/Module/Import.php:144 -#, php-format -msgid "Your service plan only allows %d channels." +#: ../../Zotlabs/Module/Setup.php:298 +msgid "Database Name" msgstr "" -#: ../../Zotlabs/Module/Import.php:158 -msgid "No channel. Import failed." +#: ../../Zotlabs/Module/Setup.php:299 +msgid "Database Type" msgstr "" -#: ../../Zotlabs/Module/Import.php:467 -#: ../../addon/diaspora/import_diaspora.php:142 -msgid "Import completed." +#: ../../Zotlabs/Module/Setup.php:301 ../../Zotlabs/Module/Setup.php:342 +msgid "Site administrator email address" msgstr "" -#: ../../Zotlabs/Module/Import.php:495 +#: ../../Zotlabs/Module/Setup.php:301 ../../Zotlabs/Module/Setup.php:342 +======= +#: ../../Zotlabs/Module/Import.php:494 msgid "You must be logged in to use this feature." msgstr "" -#: ../../Zotlabs/Module/Import.php:500 +#: ../../Zotlabs/Module/Import.php:499 msgid "Import Channel" msgstr "" -#: ../../Zotlabs/Module/Import.php:501 +#: ../../Zotlabs/Module/Import.php:500 msgid "" "Use this form to import an existing channel from a different server/hub. You " "may retrieve the channel identity from the old server/hub via the network or " "provide an export file." msgstr "" -#: ../../Zotlabs/Module/Import.php:503 +#: ../../Zotlabs/Module/Import.php:502 msgid "Or provide the old server/hub details" msgstr "" -#: ../../Zotlabs/Module/Import.php:504 +#: ../../Zotlabs/Module/Import.php:503 msgid "Your old identity address (xyz@example.com)" msgstr "" -#: ../../Zotlabs/Module/Import.php:505 +#: ../../Zotlabs/Module/Import.php:504 msgid "Your old login email address" msgstr "" -#: ../../Zotlabs/Module/Import.php:506 +#: ../../Zotlabs/Module/Import.php:505 msgid "Your old login password" msgstr "" -#: ../../Zotlabs/Module/Import.php:507 +#: ../../Zotlabs/Module/Import.php:506 msgid "" "For either option, please choose whether to make this hub your new primary " "address, or whether your old location should continue this role. You will be " @@ -3975,147 +4451,180 @@ msgid "" "location for files, photos, and media." msgstr "" -#: ../../Zotlabs/Module/Import.php:508 +#: ../../Zotlabs/Module/Import.php:507 msgid "Make this hub my primary location" msgstr "" -#: ../../Zotlabs/Module/Import.php:509 +#: ../../Zotlabs/Module/Import.php:508 msgid "Move this channel (disable all previous locations)" msgstr "" -#: ../../Zotlabs/Module/Import.php:510 +#: ../../Zotlabs/Module/Import.php:509 msgid "Import a few months of posts if possible (limited by available memory" msgstr "" -#: ../../Zotlabs/Module/Import.php:511 +#: ../../Zotlabs/Module/Import.php:510 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "" -"This process may take several minutes to complete. Please submit the form " -"only once and leave this page open until finished." +"Your account email address must match this in order to use the web admin " +"panel." msgstr "" -#: ../../Zotlabs/Module/Rmagic.php:35 -msgid "Authentication failed." +#: ../../Zotlabs/Module/Setup.php:302 ../../Zotlabs/Module/Setup.php:344 +msgid "Website URL" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Setup.php:302 ../../Zotlabs/Module/Setup.php:344 +msgid "Please use SSL (https) URL if available." msgstr "" -#: ../../Zotlabs/Module/Rmagic.php:75 ../../include/channel.php:1993 +#: ../../Zotlabs/Module/Setup.php:303 ../../Zotlabs/Module/Setup.php:346 +msgid "Please select a default timezone for your website" +msgstr "" + +#: ../../Zotlabs/Module/Setup.php:331 +msgid "Site settings" +======= +#: ../../Zotlabs/Module/Rmagic.php:75 ../../include/channel.php:1984 msgid "Remote Authentication" msgstr "" -#: ../../Zotlabs/Module/Rmagic.php:76 ../../include/channel.php:1994 +#: ../../Zotlabs/Module/Rmagic.php:76 ../../include/channel.php:1985 msgid "Enter your channel address (e.g. channel@example.com)" msgstr "" -#: ../../Zotlabs/Module/Rmagic.php:77 ../../include/channel.php:1995 +#: ../../Zotlabs/Module/Rmagic.php:77 ../../include/channel.php:1986 msgid "Authenticate" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Cal.php:62 ../../Zotlabs/Module/Chanview.php:96 -#: ../../Zotlabs/Module/Page.php:76 ../../Zotlabs/Module/Wall_upload.php:31 -#: ../../Zotlabs/Module/Block.php:43 -msgid "Channel not found." +#: ../../Zotlabs/Module/Setup.php:385 +msgid "PHP version 5.5 or greater is required." msgstr "" -#: ../../Zotlabs/Module/Cal.php:69 -msgid "Permissions denied." +#: ../../Zotlabs/Module/Setup.php:386 +msgid "PHP version" msgstr "" -#: ../../Zotlabs/Module/Cal.php:342 ../../include/text.php:2304 +<<<<<<< HEAD +#: ../../Zotlabs/Module/Setup.php:402 +msgid "Could not find a command line version of PHP in the web server PATH." +======= +#: ../../Zotlabs/Module/Cal.php:342 ../../include/text.php:2291 msgid "Import" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Api.php:72 ../../Zotlabs/Module/Api.php:93 -msgid "Authorize application connection" +#: ../../Zotlabs/Module/Setup.php:403 +msgid "" +"If you don't have a command line version of PHP installed on server, you " +"will not be able to run background polling via cron." msgstr "" -#: ../../Zotlabs/Module/Api.php:73 -msgid "Return to your app and insert this Security Code:" +#: ../../Zotlabs/Module/Setup.php:407 +msgid "PHP executable path" msgstr "" -#: ../../Zotlabs/Module/Api.php:83 -msgid "Please login to continue." +#: ../../Zotlabs/Module/Setup.php:407 +msgid "" +"Enter full path to php executable. You can leave this blank to continue the " +"installation." msgstr "" -#: ../../Zotlabs/Module/Api.php:95 -msgid "" -"Do you want to authorize this application to access your posts and contacts, " -"and/or create new posts for you?" +#: ../../Zotlabs/Module/Setup.php:412 +msgid "Command line PHP" msgstr "" -#: ../../Zotlabs/Module/Attach.php:13 -msgid "Item not available." +#: ../../Zotlabs/Module/Setup.php:422 +msgid "" +"Unable to check command line PHP, as shell_exec() is disabled. This is " +"required." msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Setup.php:425 +msgid "" +"The command line version of PHP on your system does not have " +"\"register_argc_argv\" enabled." +======= #: ../../Zotlabs/Module/Editblock.php:116 ../../Zotlabs/Module/Chat.php:205 -#: ../../Zotlabs/Module/Editwebpage.php:143 ../../Zotlabs/Module/Mail.php:288 -#: ../../Zotlabs/Module/Mail.php:430 ../../include/conversation.php:1226 +#: ../../Zotlabs/Module/Editwebpage.php:143 ../../Zotlabs/Module/Mail.php:306 +#: ../../Zotlabs/Module/Mail.php:448 ../../include/conversation.php:1228 msgid "Insert web link" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Editblock.php:129 ../../include/conversation.php:1337 -msgid "Title (optional)" +#: ../../Zotlabs/Module/Setup.php:426 +msgid "This is required for message delivery to work." msgstr "" -#: ../../Zotlabs/Module/Editblock.php:138 -msgid "Edit Block" +#: ../../Zotlabs/Module/Setup.php:429 +msgid "PHP register_argc_argv" msgstr "" -#: ../../Zotlabs/Module/Profile.php:91 -msgid "vcard" +#: ../../Zotlabs/Module/Setup.php:447 +#, php-format +msgid "" +"Your max allowed total upload size is set to %s. Maximum size of one file to " +"upload is set to %s. You are allowed to upload up to %d files at once." msgstr "" -#: ../../Zotlabs/Module/Apps.php:45 -msgid "Apps" +#: ../../Zotlabs/Module/Setup.php:452 +msgid "You can adjust these settings in the server php.ini file." msgstr "" -#: ../../Zotlabs/Module/Apps.php:48 -msgid "Manage apps" +#: ../../Zotlabs/Module/Setup.php:454 +msgid "PHP upload limits" msgstr "" -#: ../../Zotlabs/Module/Apps.php:49 -msgid "Create new app" +#: ../../Zotlabs/Module/Setup.php:477 +msgid "" +"Error: the \"openssl_pkey_new\" function on this system is not able to " +"generate encryption keys" msgstr "" -#: ../../Zotlabs/Module/Mood.php:67 ../../include/conversation.php:256 -#, php-format -msgctxt "mood" -msgid "%1$s is %2$s" +#: ../../Zotlabs/Module/Setup.php:478 +msgid "" +"If running under Windows, please see \"http://www.php.net/manual/en/openssl." +"installation.php\"." msgstr "" -#: ../../Zotlabs/Module/Mood.php:135 ../../Zotlabs/Lib/Apps.php:234 -msgid "Mood" +#: ../../Zotlabs/Module/Setup.php:481 +msgid "Generate encryption keys" msgstr "" -#: ../../Zotlabs/Module/Mood.php:136 -msgid "Set your current mood and tell your friends" +#: ../../Zotlabs/Module/Setup.php:498 +msgid "libCurl PHP module" msgstr "" -#: ../../Zotlabs/Module/Connections.php:52 -#: ../../Zotlabs/Module/Connections.php:157 -#: ../../Zotlabs/Module/Connections.php:246 -msgid "Blocked" +#: ../../Zotlabs/Module/Setup.php:499 +msgid "GD graphics PHP module" msgstr "" -#: ../../Zotlabs/Module/Connections.php:57 -#: ../../Zotlabs/Module/Connections.php:164 -#: ../../Zotlabs/Module/Connections.php:245 -msgid "Ignored" +#: ../../Zotlabs/Module/Setup.php:500 +msgid "OpenSSL PHP module" msgstr "" -#: ../../Zotlabs/Module/Connections.php:62 -#: ../../Zotlabs/Module/Connections.php:178 -#: ../../Zotlabs/Module/Connections.php:244 -msgid "Hidden" +#: ../../Zotlabs/Module/Setup.php:501 +msgid "PDO database PHP module" msgstr "" -#: ../../Zotlabs/Module/Connections.php:67 -#: ../../Zotlabs/Module/Connections.php:171 -#: ../../Zotlabs/Module/Connections.php:243 -msgid "Archived" +#: ../../Zotlabs/Module/Setup.php:502 +msgid "mb_string PHP module" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Setup.php:503 +msgid "xml PHP module" msgstr "" +#: ../../Zotlabs/Module/Setup.php:507 ../../Zotlabs/Module/Setup.php:509 +msgid "Apache mod_rewrite module" +======= #: ../../Zotlabs/Module/Connections.php:72 #: ../../Zotlabs/Module/Connections.php:82 ../../Zotlabs/Module/Menu.php:116 -#: ../../include/conversation.php:1664 +#: ../../include/conversation.php:1666 msgid "New" msgstr "" @@ -4123,358 +4632,426 @@ msgstr "" #: ../../Zotlabs/Module/Connections.php:103 #: ../../Zotlabs/Module/Connedit.php:709 ../../Zotlabs/Widget/Affinity.php:30 msgid "All" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Connections.php:134 -msgid "New Connections" +#: ../../Zotlabs/Module/Setup.php:507 +msgid "" +"Error: Apache webserver mod-rewrite module is required but not installed." msgstr "" -#: ../../Zotlabs/Module/Connections.php:137 -msgid "Show pending (new) connections" +#: ../../Zotlabs/Module/Setup.php:513 ../../Zotlabs/Module/Setup.php:516 +msgid "exec" msgstr "" -#: ../../Zotlabs/Module/Connections.php:144 -msgid "Show all connections" +#: ../../Zotlabs/Module/Setup.php:513 +msgid "" +"Error: exec is required but is either not installed or has been disabled in " +"php.ini" msgstr "" -#: ../../Zotlabs/Module/Connections.php:160 -msgid "Only show blocked connections" +#: ../../Zotlabs/Module/Setup.php:519 ../../Zotlabs/Module/Setup.php:522 +msgid "shell_exec" msgstr "" -#: ../../Zotlabs/Module/Connections.php:167 -msgid "Only show ignored connections" +#: ../../Zotlabs/Module/Setup.php:519 +msgid "" +"Error: shell_exec is required but is either not installed or has been " +"disabled in php.ini" msgstr "" -#: ../../Zotlabs/Module/Connections.php:174 -msgid "Only show archived connections" +#: ../../Zotlabs/Module/Setup.php:527 +msgid "Error: libCURL PHP module required but not installed." msgstr "" -#: ../../Zotlabs/Module/Connections.php:181 -msgid "Only show hidden connections" +#: ../../Zotlabs/Module/Setup.php:531 +msgid "" +"Error: GD graphics PHP module with JPEG support required but not installed." msgstr "" -#: ../../Zotlabs/Module/Connections.php:242 -msgid "Pending approval" +#: ../../Zotlabs/Module/Setup.php:535 +msgid "Error: openssl PHP module required but not installed." msgstr "" -#: ../../Zotlabs/Module/Connections.php:258 -#, php-format -msgid "%1$s [%2$s]" +#: ../../Zotlabs/Module/Setup.php:539 +msgid "Error: PDO database PHP module required but not installed." msgstr "" -#: ../../Zotlabs/Module/Connections.php:259 -msgid "Edit connection" +#: ../../Zotlabs/Module/Setup.php:543 +msgid "Error: mb_string PHP module required but not installed." msgstr "" -#: ../../Zotlabs/Module/Connections.php:260 -msgid "Delete connection" +#: ../../Zotlabs/Module/Setup.php:547 +msgid "Error: xml PHP module required for DAV but not installed." msgstr "" -#: ../../Zotlabs/Module/Connections.php:269 -msgid "Channel address" +#: ../../Zotlabs/Module/Setup.php:565 +msgid "" +"The web installer needs to be able to create a file called \".htconfig.php\" " +"in the top folder of your web server and it is unable to do so." msgstr "" -#: ../../Zotlabs/Module/Connections.php:271 -msgid "Network" +#: ../../Zotlabs/Module/Setup.php:566 +msgid "" +"This is most often a permission setting, as the web server may not be able " +"to write files in your folder - even if you can." msgstr "" -#: ../../Zotlabs/Module/Connections.php:274 -msgid "Call" +#: ../../Zotlabs/Module/Setup.php:567 +msgid "" +"At the end of this procedure, we will give you a text to save in a file " +"named .htconfig.php in your Red top folder." msgstr "" -#: ../../Zotlabs/Module/Connections.php:276 -msgid "Status" +#: ../../Zotlabs/Module/Setup.php:568 +msgid "" +"You can alternatively skip this procedure and perform a manual installation. " +"Please see the file \"install/INSTALL.txt\" for instructions." msgstr "" -#: ../../Zotlabs/Module/Connections.php:278 -msgid "Connected" +#: ../../Zotlabs/Module/Setup.php:571 +msgid ".htconfig.php is writable" msgstr "" -#: ../../Zotlabs/Module/Connections.php:280 -msgid "Approve connection" +#: ../../Zotlabs/Module/Setup.php:585 +msgid "" +"This software uses the Smarty3 template engine to render its web views. " +"Smarty3 compiles templates to PHP to speed up rendering." msgstr "" -#: ../../Zotlabs/Module/Connections.php:282 -msgid "Ignore connection" +#: ../../Zotlabs/Module/Setup.php:586 +#, php-format +msgid "" +"In order to store these compiled templates, the web server needs to have " +"write access to the directory %s under the top level web folder." msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Setup.php:587 ../../Zotlabs/Module/Setup.php:608 +msgid "" +"Please ensure that the user that your web server runs as (e.g. www-data) has " +"write access to this folder." +======= #: ../../Zotlabs/Module/Connections.php:283 #: ../../Zotlabs/Module/Connedit.php:626 msgid "Ignore" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Connections.php:284 -msgid "Recent activity" +#: ../../Zotlabs/Module/Setup.php:588 +#, php-format +msgid "" +"Note: as a security measure, you should give the web server write access to " +"%s only--not the template files (.tpl) that it contains." msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Setup.php:591 +#, php-format +msgid "%s is writable" +======= #: ../../Zotlabs/Module/Connections.php:308 ../../Zotlabs/Lib/Apps.php:216 #: ../../include/text.php:957 ../../include/nav.php:185 msgid "Connections" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Connections.php:313 -msgid "Search your connections" +#: ../../Zotlabs/Module/Setup.php:607 +msgid "" +"This software uses the store directory to save uploaded files. The web " +"server needs to have write access to the store directory under the top level " +"web folder" msgstr "" -#: ../../Zotlabs/Module/Connections.php:314 -msgid "Connections search" +#: ../../Zotlabs/Module/Setup.php:611 +msgid "store is writable" msgstr "" -#: ../../Zotlabs/Module/Connections.php:315 -#: ../../Zotlabs/Module/Directory.php:391 -#: ../../Zotlabs/Module/Directory.php:396 ../../include/contact_widgets.php:23 -msgid "Find" +#: ../../Zotlabs/Module/Setup.php:643 +msgid "" +"SSL certificate cannot be validated. Fix certificate or disable https access " +"to this site." msgstr "" +#: ../../Zotlabs/Module/Setup.php:644 +msgid "" +"If you have https access to your website or allow connections to TCP port " +"443 (the https: port), you MUST use a browser-valid certificate. You MUST " +"NOT use self-signed certificates!" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Setup.php:645 +msgid "" +"This restriction is incorporated because public posts from you may for " +"example contain references to images on your own hub." +======= #: ../../Zotlabs/Module/Viewsrc.php:43 msgid "item" msgstr "" #: ../../Zotlabs/Module/Viewsrc.php:55 msgid "Source of Item" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Bookmarks.php:53 -msgid "Bookmark added" +#: ../../Zotlabs/Module/Setup.php:646 +msgid "" +"If your certificate is not recognized, members of other sites (who may " +"themselves have valid certificates) will get a warning message on their own " +"site complaining about security issues." msgstr "" -#: ../../Zotlabs/Module/Bookmarks.php:76 -msgid "My Bookmarks" +#: ../../Zotlabs/Module/Setup.php:647 +msgid "" +"This can cause usability issues elsewhere (not just on your own site) so we " +"must insist on this requirement." msgstr "" -#: ../../Zotlabs/Module/Bookmarks.php:87 -msgid "My Connections Bookmarks" +#: ../../Zotlabs/Module/Setup.php:648 +msgid "" +"Providers are available that issue free certificates which are browser-valid." msgstr "" -#: ../../Zotlabs/Module/Removeaccount.php:35 +#: ../../Zotlabs/Module/Setup.php:650 msgid "" -"Account removals are not allowed within 48 hours of changing the account " -"password." +"If you are confident that the certificate is valid and signed by a trusted " +"authority, check to see if you have failed to install an intermediate cert. " +"These are not normally required by browsers, but are required for server-to-" +"server communications." msgstr "" -#: ../../Zotlabs/Module/Removeaccount.php:57 -msgid "Remove This Account" +#: ../../Zotlabs/Module/Setup.php:652 +msgid "SSL certificate validation" msgstr "" -#: ../../Zotlabs/Module/Removeaccount.php:58 +#: ../../Zotlabs/Module/Setup.php:658 msgid "" -"This account and all its channels will be completely removed from the " -"network. " +"Url rewrite in .htaccess is not working. Check your server configuration." +"Test: " msgstr "" -#: ../../Zotlabs/Module/Removeaccount.php:60 -msgid "" -"Remove this account, all its channels and all its channel clones from the " -"network" +#: ../../Zotlabs/Module/Setup.php:661 +msgid "Url rewrite is working" msgstr "" -#: ../../Zotlabs/Module/Removeaccount.php:60 +#: ../../Zotlabs/Module/Setup.php:675 msgid "" -"By default only the instances of the channels located on this hub will be " -"removed from the network" +"The database configuration file \".htconfig.php\" could not be written. " +"Please use the enclosed text to create a configuration file in your web " +"server root." msgstr "" -#: ../../Zotlabs/Module/Photos.php:78 -msgid "Page owner information could not be retrieved." +#: ../../Zotlabs/Module/Setup.php:699 +#: ../../extend/addon/addon/cdav/cdav.php:41 +#: ../../extend/addon/addon/rendezvous/rendezvous.php:401 +msgid "Errors encountered creating database tables." msgstr "" -#: ../../Zotlabs/Module/Photos.php:94 ../../Zotlabs/Module/Photos.php:120 -msgid "Album not found." +#: ../../Zotlabs/Module/Setup.php:739 +msgid "<h1>What next</h1>" msgstr "" -#: ../../Zotlabs/Module/Photos.php:103 -msgid "Delete Album" +#: ../../Zotlabs/Module/Setup.php:740 +msgid "" +"IMPORTANT: You will need to [manually] setup a scheduled task for the poller." msgstr "" -#: ../../Zotlabs/Module/Photos.php:174 ../../Zotlabs/Module/Photos.php:1023 -msgid "Delete Photo" +#: ../../Zotlabs/Module/Import_items.php:108 +msgid "Import completed" msgstr "" -#: ../../Zotlabs/Module/Photos.php:501 -msgid "No photos selected" +#: ../../Zotlabs/Module/Import_items.php:125 +msgid "Import Items" msgstr "" -#: ../../Zotlabs/Module/Photos.php:550 -msgid "Access to this item is restricted." +#: ../../Zotlabs/Module/Import_items.php:126 +msgid "Use this form to import existing posts and content from an export file." msgstr "" -#: ../../Zotlabs/Module/Photos.php:591 +#: ../../Zotlabs/Module/Manage.php:136 +#: ../../Zotlabs/Module/New_channel.php:121 #, php-format -msgid "%1$.2f MB of %2$.2f MB photo storage used." +msgid "You have created %1$.0f of %2$.0f allowed channels." msgstr "" -#: ../../Zotlabs/Module/Photos.php:594 -#, php-format -msgid "%1$.2f MB photo storage used." +#: ../../Zotlabs/Module/Manage.php:143 +msgid "Create a new channel" msgstr "" -#: ../../Zotlabs/Module/Photos.php:636 -msgid "Upload Photos" +#: ../../Zotlabs/Module/Manage.php:164 ../../Zotlabs/Lib/Apps.php:221 +#: ../../include/nav.php:201 +msgid "Channel Manager" msgstr "" -#: ../../Zotlabs/Module/Photos.php:640 -msgid "Enter an album name" +#: ../../Zotlabs/Module/Manage.php:165 +msgid "Current Channel" msgstr "" -#: ../../Zotlabs/Module/Photos.php:641 -msgid "or select an existing album (doubleclick)" +#: ../../Zotlabs/Module/Manage.php:167 +msgid "Switch to one of your channels by selecting it." msgstr "" -#: ../../Zotlabs/Module/Photos.php:642 -msgid "Create a status post for this upload" +#: ../../Zotlabs/Module/Manage.php:168 +msgid "Default Channel" msgstr "" -#: ../../Zotlabs/Module/Photos.php:643 -msgid "Caption (optional):" +#: ../../Zotlabs/Module/Manage.php:169 +msgid "Make Default" msgstr "" -#: ../../Zotlabs/Module/Photos.php:644 -msgid "Description (optional):" +#: ../../Zotlabs/Module/Manage.php:172 +#, php-format +msgid "%d new messages" msgstr "" -#: ../../Zotlabs/Module/Photos.php:725 -msgid "Show Newest First" +#: ../../Zotlabs/Module/Manage.php:173 +#, php-format +msgid "%d new introductions" msgstr "" -#: ../../Zotlabs/Module/Photos.php:727 -msgid "Show Oldest First" +#: ../../Zotlabs/Module/Manage.php:175 +msgid "Delegated Channel" msgstr "" -#: ../../Zotlabs/Module/Photos.php:832 -msgid "Permission denied. Access to this item may be restricted." +#: ../../Zotlabs/Module/Oexchange.php:27 +msgid "Unable to find your hub." msgstr "" -#: ../../Zotlabs/Module/Photos.php:834 -msgid "Photo not available" +#: ../../Zotlabs/Module/Oexchange.php:41 +msgid "Post successful." msgstr "" -#: ../../Zotlabs/Module/Photos.php:892 -msgid "Use as profile photo" +#: ../../Zotlabs/Module/Editblock.php:113 ../../Zotlabs/Module/Blocks.php:97 +#: ../../Zotlabs/Module/Blocks.php:155 +msgid "Block Name" msgstr "" -#: ../../Zotlabs/Module/Photos.php:893 -msgid "Use as cover photo" +#: ../../Zotlabs/Module/Editblock.php:129 ../../include/conversation.php:1339 +msgid "Title (optional)" msgstr "" -#: ../../Zotlabs/Module/Photos.php:900 -msgid "Private Photo" +#: ../../Zotlabs/Module/Editblock.php:138 +msgid "Edit Block" msgstr "" -#: ../../Zotlabs/Module/Photos.php:915 -msgid "View Full Size" +#: ../../Zotlabs/Module/Magic.php:71 +msgid "Hub not found." msgstr "" -#: ../../Zotlabs/Module/Photos.php:997 -msgid "Edit photo" +#: ../../Zotlabs/Module/Mitem.php:52 +msgid "Unable to create element." msgstr "" -#: ../../Zotlabs/Module/Photos.php:999 -msgid "Rotate CW (right)" +#: ../../Zotlabs/Module/Mitem.php:76 +msgid "Unable to update menu element." msgstr "" -#: ../../Zotlabs/Module/Photos.php:1000 -msgid "Rotate CCW (left)" +#: ../../Zotlabs/Module/Mitem.php:92 +msgid "Unable to add menu element." msgstr "" -#: ../../Zotlabs/Module/Photos.php:1003 -msgid "Move photo to album" +#: ../../Zotlabs/Module/Mitem.php:153 ../../Zotlabs/Module/Mitem.php:230 +msgid "Menu Item Permissions" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1004 -msgid "Enter a new album name" +#: ../../Zotlabs/Module/Mitem.php:154 ../../Zotlabs/Module/Mitem.php:231 +#: ../../Zotlabs/Module/Settings/Channel.php:510 +msgid "(click to open/close)" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1005 -msgid "or select an existing one (doubleclick)" +#: ../../Zotlabs/Module/Mitem.php:160 ../../Zotlabs/Module/Mitem.php:176 +msgid "Link Name" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1008 -msgid "Caption" +#: ../../Zotlabs/Module/Mitem.php:161 ../../Zotlabs/Module/Mitem.php:239 +msgid "Link or Submenu Target" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1010 -msgid "Add a Tag" +#: ../../Zotlabs/Module/Mitem.php:161 +msgid "Enter URL of the link or select a menu name to create a submenu" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1018 -msgid "Example: @bob, @Barbara_Jensen, @jim@example.com" +#: ../../Zotlabs/Module/Mitem.php:162 ../../Zotlabs/Module/Mitem.php:240 +msgid "Use magic-auth if available" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1021 -msgid "Flag as adult in album view" +#: ../../Zotlabs/Module/Mitem.php:163 ../../Zotlabs/Module/Mitem.php:241 +msgid "Open link in new window" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1040 ../../Zotlabs/Lib/ThreadItem.php:269 -msgid "I like this (toggle)" +#: ../../Zotlabs/Module/Mitem.php:164 ../../Zotlabs/Module/Mitem.php:242 +msgid "Order in list" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1041 ../../Zotlabs/Lib/ThreadItem.php:270 -msgid "I don't like this (toggle)" +#: ../../Zotlabs/Module/Mitem.php:164 ../../Zotlabs/Module/Mitem.php:242 +msgid "Higher numbers will sink to bottom of listing" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1043 ../../Zotlabs/Lib/ThreadItem.php:412 -#: ../../include/conversation.php:737 -msgid "Please wait" +#: ../../Zotlabs/Module/Mitem.php:165 +msgid "Submit and finish" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1059 ../../Zotlabs/Module/Photos.php:1177 -#: ../../Zotlabs/Lib/ThreadItem.php:729 -msgid "This is you" +#: ../../Zotlabs/Module/Mitem.php:166 +msgid "Submit and continue" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1061 ../../Zotlabs/Module/Photos.php:1179 -#: ../../Zotlabs/Lib/ThreadItem.php:731 ../../include/js_strings.php:6 -msgid "Comment" +#: ../../Zotlabs/Module/Mitem.php:174 +msgid "Menu:" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1077 ../../include/conversation.php:570 -msgctxt "title" -msgid "Likes" +#: ../../Zotlabs/Module/Mitem.php:177 +msgid "Link Target" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1077 ../../include/conversation.php:570 -msgctxt "title" -msgid "Dislikes" +#: ../../Zotlabs/Module/Mitem.php:180 +msgid "Edit menu" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1078 ../../include/conversation.php:571 -msgctxt "title" -msgid "Agree" +#: ../../Zotlabs/Module/Mitem.php:183 +msgid "Edit element" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1078 ../../include/conversation.php:571 -msgctxt "title" -msgid "Disagree" +#: ../../Zotlabs/Module/Mitem.php:184 +msgid "Drop element" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1078 ../../include/conversation.php:571 -msgctxt "title" -msgid "Abstain" +#: ../../Zotlabs/Module/Mitem.php:185 +msgid "New element" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1079 ../../include/conversation.php:572 -msgctxt "title" -msgid "Attending" +#: ../../Zotlabs/Module/Mitem.php:186 +msgid "Edit this menu container" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1079 ../../include/conversation.php:572 -msgctxt "title" -msgid "Not attending" +#: ../../Zotlabs/Module/Mitem.php:187 +msgid "Add menu element" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1079 ../../include/conversation.php:572 -msgctxt "title" -msgid "Might attend" +#: ../../Zotlabs/Module/Mitem.php:188 +msgid "Delete this menu item" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1096 ../../Zotlabs/Module/Photos.php:1108 -#: ../../Zotlabs/Lib/ThreadItem.php:187 ../../Zotlabs/Lib/ThreadItem.php:199 -msgid "View all" +#: ../../Zotlabs/Module/Mitem.php:189 +msgid "Edit this menu item" +msgstr "" + +#: ../../Zotlabs/Module/Mitem.php:206 +msgid "Menu item not found." msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Mitem.php:219 +msgid "Menu item deleted." +msgstr "" + +#: ../../Zotlabs/Module/Mitem.php:221 +msgid "Menu item could not be deleted." +msgstr "" +======= #: ../../Zotlabs/Module/Photos.php:1100 ../../Zotlabs/Lib/ThreadItem.php:191 -#: ../../include/conversation.php:1905 ../../include/channel.php:1282 -#: ../../include/taxonomy.php:433 +#: ../../include/conversation.php:1907 ../../include/channel.php:1268 +#: ../../include/taxonomy.php:403 msgctxt "noun" msgid "Like" msgid_plural "Likes" @@ -4482,243 +5059,398 @@ msgstr[0] "" msgstr[1] "" #: ../../Zotlabs/Module/Photos.php:1105 ../../Zotlabs/Lib/ThreadItem.php:196 -#: ../../include/conversation.php:1908 +#: ../../include/conversation.php:1910 msgctxt "noun" msgid "Dislike" msgid_plural "Dislikes" msgstr[0] "" msgstr[1] "" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 -#: ../../Zotlabs/Module/Photos.php:1205 -msgid "Photo Tools" +#: ../../Zotlabs/Module/Mitem.php:228 +msgid "Edit Menu Element" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1214 -msgid "In This Photo:" +#: ../../Zotlabs/Module/Mitem.php:238 +msgid "Link text" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1219 -msgid "Map" +#: ../../Zotlabs/Module/Ratings.php:70 +msgid "No ratings" msgstr "" -#: ../../Zotlabs/Module/Photos.php:1227 ../../Zotlabs/Lib/ThreadItem.php:401 -msgctxt "noun" -msgid "Likes" +#: ../../Zotlabs/Module/Ratings.php:98 +msgid "Rating: " msgstr "" -#: ../../Zotlabs/Module/Photos.php:1228 ../../Zotlabs/Lib/ThreadItem.php:402 -msgctxt "noun" -msgid "Dislikes" +#: ../../Zotlabs/Module/Ratings.php:99 +msgid "Website: " msgstr "" -#: ../../Zotlabs/Module/Photos.php:1233 ../../Zotlabs/Lib/ThreadItem.php:407 -#: ../../include/acl_selectors.php:220 -msgid "Close" +#: ../../Zotlabs/Module/Ratings.php:101 +msgid "Description: " msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Attach.php:13 +msgid "Item not available." +======= #: ../../Zotlabs/Module/Photos.php:1305 ../../Zotlabs/Module/Photos.php:1318 #: ../../Zotlabs/Module/Photos.php:1319 ../../include/photos.php:529 msgid "Recent Photos" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" #: ../../Zotlabs/Module/Wiki.php:30 msgid "Profile Unavailable." msgstr "" -#: ../../Zotlabs/Module/Wiki.php:44 ../../addon/gitwiki/Mod_Gitwiki.php:42 +#: ../../Zotlabs/Module/Wiki.php:44 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:42 msgid "Not found" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:68 ../../addon/gitwiki/Mod_Gitwiki.php:62 +#: ../../Zotlabs/Module/Wiki.php:68 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:62 msgid "Invalid channel" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Wiki.php:160 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:146 +#: ../../include/conversation.php:1845 +======= #: ../../Zotlabs/Module/Wiki.php:160 ../../addon/gitwiki/Mod_Gitwiki.php:146 -#: ../../include/conversation.php:1852 ../../include/nav.php:455 +#: ../../include/conversation.php:1854 ../../include/nav.php:462 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "Wikis" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:166 ../../addon/gitwiki/Mod_Gitwiki.php:152 +#: ../../Zotlabs/Module/Wiki.php:166 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:152 msgid "Download" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:168 ../../Zotlabs/Module/Chat.php:254 -#: ../../Zotlabs/Module/Profiles.php:834 ../../Zotlabs/Module/Manage.php:143 -#: ../../addon/gitwiki/Mod_Gitwiki.php:154 -msgid "Create New" -msgstr "" - -#: ../../Zotlabs/Module/Wiki.php:170 ../../addon/gitwiki/Mod_Gitwiki.php:156 +#: ../../Zotlabs/Module/Wiki.php:170 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:156 msgid "Wiki name" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:171 ../../addon/gitwiki/Mod_Gitwiki.php:157 +#: ../../Zotlabs/Module/Wiki.php:171 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:157 msgid "Content type" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:173 ../../Zotlabs/Storage/Browser.php:234 -#: ../../addon/gitwiki/Mod_Gitwiki.php:159 -msgid "Type" -msgstr "" - -#: ../../Zotlabs/Module/Wiki.php:180 ../../addon/gitwiki/Mod_Gitwiki.php:166 +#: ../../Zotlabs/Module/Wiki.php:180 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:166 msgid "Create a status post for this wiki" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:222 ../../addon/gitwiki/Mod_Gitwiki.php:185 +#: ../../Zotlabs/Module/Wiki.php:205 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:185 msgid "Wiki not found" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:246 ../../addon/gitwiki/Mod_Gitwiki.php:210 +#: ../../Zotlabs/Module/Wiki.php:229 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:210 msgid "Rename page" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:256 ../../addon/gitwiki/Mod_Gitwiki.php:214 +#: ../../Zotlabs/Module/Wiki.php:233 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:214 msgid "Error retrieving page content" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:262 +#: ../../Zotlabs/Module/Wiki.php:239 msgid "New page" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:286 ../../addon/gitwiki/Mod_Gitwiki.php:242 +#: ../../Zotlabs/Module/Wiki.php:263 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:242 msgid "Revision Comparison" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:287 ../../addon/gitwiki/Mod_Gitwiki.php:243 +#: ../../Zotlabs/Module/Wiki.php:264 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:243 msgid "Revert" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:291 +#: ../../Zotlabs/Module/Wiki.php:268 msgid "Short description of your changes (optional)" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:298 ../../addon/gitwiki/Mod_Gitwiki.php:252 +#: ../../Zotlabs/Module/Wiki.php:275 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:252 msgid "Source" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:307 ../../addon/gitwiki/Mod_Gitwiki.php:260 +#: ../../Zotlabs/Module/Wiki.php:283 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:260 msgid "New page name" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:312 ../../addon/gitwiki/Mod_Gitwiki.php:265 -#: ../../include/conversation.php:1230 +#: ../../Zotlabs/Module/Wiki.php:288 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:265 +#: ../../include/conversation.php:1232 msgid "Embed image from photo albums" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:313 ../../addon/gitwiki/Mod_Gitwiki.php:266 -#: ../../include/conversation.php:1324 +#: ../../Zotlabs/Module/Wiki.php:289 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:266 +#: ../../include/conversation.php:1326 msgid "Embed an image from your albums" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:315 ../../addon/gitwiki/Mod_Gitwiki.php:268 -#: ../../include/conversation.php:1326 ../../include/conversation.php:1373 +#: ../../Zotlabs/Module/Wiki.php:291 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:268 +#: ../../include/conversation.php:1328 ../../include/conversation.php:1375 msgid "OK" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:316 ../../addon/gitwiki/Mod_Gitwiki.php:269 -#: ../../include/conversation.php:1266 +#: ../../Zotlabs/Module/Wiki.php:292 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:269 +#: ../../include/conversation.php:1268 msgid "Choose images to embed" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:317 ../../addon/gitwiki/Mod_Gitwiki.php:270 -#: ../../include/conversation.php:1267 +#: ../../Zotlabs/Module/Wiki.php:293 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:270 +#: ../../include/conversation.php:1269 msgid "Choose an album" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:318 ../../addon/gitwiki/Mod_Gitwiki.php:271 +#: ../../Zotlabs/Module/Wiki.php:294 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:271 msgid "Choose a different album" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:319 ../../addon/gitwiki/Mod_Gitwiki.php:272 -#: ../../include/conversation.php:1269 +#: ../../Zotlabs/Module/Wiki.php:295 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:272 +#: ../../include/conversation.php:1271 msgid "Error getting album list" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:320 ../../addon/gitwiki/Mod_Gitwiki.php:273 -#: ../../include/conversation.php:1270 +#: ../../Zotlabs/Module/Wiki.php:296 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:273 +#: ../../include/conversation.php:1272 msgid "Error getting photo link" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:321 ../../addon/gitwiki/Mod_Gitwiki.php:274 -#: ../../include/conversation.php:1271 +#: ../../Zotlabs/Module/Wiki.php:297 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:274 +#: ../../include/conversation.php:1273 msgid "Error getting album" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:388 ../../addon/gitwiki/Mod_Gitwiki.php:337 +#: ../../Zotlabs/Module/Wiki.php:365 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:337 msgid "Error creating wiki. Invalid name." msgstr "" -#: ../../Zotlabs/Module/Wiki.php:395 +#: ../../Zotlabs/Module/Wiki.php:372 msgid "A wiki with this name already exists." msgstr "" -#: ../../Zotlabs/Module/Wiki.php:408 ../../addon/gitwiki/Mod_Gitwiki.php:348 +#: ../../Zotlabs/Module/Wiki.php:385 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:348 msgid "Wiki created, but error creating Home page." msgstr "" -#: ../../Zotlabs/Module/Wiki.php:415 ../../addon/gitwiki/Mod_Gitwiki.php:353 +#: ../../Zotlabs/Module/Wiki.php:392 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:353 msgid "Error creating wiki" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:427 +#: ../../Zotlabs/Module/Wiki.php:404 msgid "Wiki delete permission denied." msgstr "" -#: ../../Zotlabs/Module/Wiki.php:437 +#: ../../Zotlabs/Module/Wiki.php:414 msgid "Error deleting wiki" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:463 ../../addon/gitwiki/Mod_Gitwiki.php:400 +#: ../../Zotlabs/Module/Wiki.php:440 +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:400 msgid "New page created" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:584 +#: ../../Zotlabs/Module/Wiki.php:559 msgid "Cannot delete Home" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:648 +#: ../../Zotlabs/Module/Wiki.php:623 msgid "Current Revision" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:648 +#: ../../Zotlabs/Module/Wiki.php:623 msgid "Selected Revision" msgstr "" -#: ../../Zotlabs/Module/Wiki.php:698 +#: ../../Zotlabs/Module/Wiki.php:673 msgid "You must be authenticated." msgstr "" -#: ../../Zotlabs/Module/Chanview.php:134 -msgid "toggle full screen mode" +#: ../../Zotlabs/Module/Notify.php:57 +#: ../../Zotlabs/Module/Notifications.php:38 +msgid "No more system notifications." msgstr "" -#: ../../Zotlabs/Module/Pdledit.php:21 -msgid "Layout updated." +#: ../../Zotlabs/Module/Notify.php:61 +#: ../../Zotlabs/Module/Notifications.php:42 +msgid "System Notifications" msgstr "" -#: ../../Zotlabs/Module/Pdledit.php:34 ../../Zotlabs/Module/Chat.php:217 -msgid "Feature disabled." +#: ../../Zotlabs/Module/Api.php:72 ../../Zotlabs/Module/Api.php:93 +msgid "Authorize application connection" msgstr "" -#: ../../Zotlabs/Module/Pdledit.php:42 ../../Zotlabs/Module/Pdledit.php:69 -msgid "Edit System Page Description" +#: ../../Zotlabs/Module/Api.php:73 +msgid "Return to your app and insert this Security Code:" msgstr "" -#: ../../Zotlabs/Module/Pdledit.php:64 -msgid "Layout not found." +#: ../../Zotlabs/Module/Api.php:83 +msgid "Please login to continue." msgstr "" -#: ../../Zotlabs/Module/Pdledit.php:70 -msgid "Module Name:" +#: ../../Zotlabs/Module/Api.php:95 +msgid "" +"Do you want to authorize this application to access your posts and contacts, " +"and/or create new posts for you?" msgstr "" -#: ../../Zotlabs/Module/Pdledit.php:71 -msgid "Layout Help" +#: ../../Zotlabs/Module/Invite.php:29 +msgid "Total invitation limit exceeded." +msgstr "" + +#: ../../Zotlabs/Module/Invite.php:53 +#, php-format +msgid "%s : Not a valid email address." +msgstr "" + +#: ../../Zotlabs/Module/Invite.php:67 +msgid "Please join us on $Projectname" +msgstr "" + +#: ../../Zotlabs/Module/Invite.php:77 +msgid "Invitation limit exceeded. Please contact your site administrator." +msgstr "" + +#: ../../Zotlabs/Module/Invite.php:82 +#, php-format +msgid "%s : Message delivery failed." +msgstr "" + +#: ../../Zotlabs/Module/Invite.php:86 +#, php-format +msgid "%d message sent." +msgid_plural "%d messages sent." +msgstr[0] "" +msgstr[1] "" + +#: ../../Zotlabs/Module/Invite.php:105 +msgid "You have no more invitations available" +msgstr "" + +#: ../../Zotlabs/Module/Invite.php:136 +msgid "Send invitations" +msgstr "" + +#: ../../Zotlabs/Module/Invite.php:137 +msgid "Enter email addresses, one per line:" +msgstr "" + +#: ../../Zotlabs/Module/Invite.php:138 ../../Zotlabs/Module/Mail.php:284 +msgid "Your message:" +msgstr "" + +#: ../../Zotlabs/Module/Invite.php:139 +msgid "Please join my community on $Projectname." +msgstr "" + +#: ../../Zotlabs/Module/Invite.php:141 +msgid "You will need to supply this invitation code:" +msgstr "" + +#: ../../Zotlabs/Module/Invite.php:142 +msgid "1. Register at any $Projectname location (they are all inter-connected)" +msgstr "" + +#: ../../Zotlabs/Module/Invite.php:144 +msgid "2. Enter my $Projectname network address into the site searchbar." +msgstr "" + +#: ../../Zotlabs/Module/Invite.php:145 +msgid "or visit" +msgstr "" + +#: ../../Zotlabs/Module/Invite.php:147 +msgid "3. Click [Connect]" +msgstr "" + +#: ../../Zotlabs/Module/Siteinfo.php:20 +msgid "About this site" +msgstr "" + +#: ../../Zotlabs/Module/Siteinfo.php:21 +msgid "Site Name" +msgstr "" + +#: ../../Zotlabs/Module/Siteinfo.php:25 ../../include/network.php:1474 +msgid "Administrator" +msgstr "" + +#: ../../Zotlabs/Module/Siteinfo.php:28 +msgid "Software and Project information" +msgstr "" + +#: ../../Zotlabs/Module/Siteinfo.php:29 +msgid "This site is powered by $Projectname" +msgstr "" + +#: ../../Zotlabs/Module/Siteinfo.php:30 +msgid "" +"Federated and decentralised networking and identity services provided by Zot" +msgstr "" + +#: ../../Zotlabs/Module/Siteinfo.php:32 +#, php-format +msgid "Version %s" +msgstr "" + +#: ../../Zotlabs/Module/Siteinfo.php:33 +msgid "Project homepage" +msgstr "" + +#: ../../Zotlabs/Module/Siteinfo.php:34 +msgid "Developer homepage" +msgstr "" + +#: ../../Zotlabs/Module/New_channel.php:140 +msgid "Create Channel" +msgstr "" + +#: ../../Zotlabs/Module/New_channel.php:141 +msgid "" +"A channel is your identity on this network. It can represent a person, a " +"blog, or a forum to name a few. Channels can make connections with other " +"channels to share information with highly detailed permissions." +msgstr "" + +#: ../../Zotlabs/Module/New_channel.php:142 +msgid "" +"or <a href=\"import\">import an existing channel</a> from another location." +msgstr "" + +#: ../../Zotlabs/Module/Profile.php:91 +msgid "vcard" +msgstr "" + +#: ../../Zotlabs/Module/Notifications.php:43 ../../include/nav.php:186 +msgid "Mark all system notifications seen" msgstr "" #: ../../Zotlabs/Module/Poke.php:168 ../../Zotlabs/Lib/Apps.php:235 -#: ../../include/conversation.php:1040 +#: ../../include/conversation.php:1042 msgid "Poke" msgstr "" @@ -4746,6 +5478,11 @@ msgstr "" msgid "Make this post private" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Search.php:224 +#, php-format +msgid "Items tagged with: %s" +======= #: ../../Zotlabs/Module/Profile_photo.php:61 #: ../../Zotlabs/Module/Cover_photo.php:56 msgid "Image uploaded but image cropping failed." @@ -4753,174 +5490,206 @@ msgstr "" #: ../../Zotlabs/Module/Profile_photo.php:115 #: ../../Zotlabs/Module/Profile_photo.php:226 -#: ../../include/photo/photo_driver.php:648 +#: ../../include/photo/photo_driver.php:647 msgid "Profile Photos" msgstr "" #: ../../Zotlabs/Module/Profile_photo.php:137 #: ../../Zotlabs/Module/Cover_photo.php:159 msgid "Image resize failed." +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Profile_photo.php:196 -#: ../../addon/openclipatar/openclipatar.php:298 +#: ../../Zotlabs/Module/Search.php:226 +#, php-format +msgid "Search results for: %s" +msgstr "" + +#: ../../Zotlabs/Module/Like.php:19 +msgid "Like/Dislike" +msgstr "" + +#: ../../Zotlabs/Module/Like.php:24 +msgid "This action is restricted to members." +msgstr "" + +#: ../../Zotlabs/Module/Like.php:25 msgid "" -"Shift-reload the page or clear browser cache if the new photo does not " -"display immediately." +"Please <a href=\"rmagic\">login with your $Projectname ID</a> or <a href=" +"\"register\">register as a new $Projectname member</a> to continue." msgstr "" -#: ../../Zotlabs/Module/Profile_photo.php:203 -#: ../../Zotlabs/Module/Cover_photo.php:173 ../../include/photos.php:149 -msgid "Unable to process image" +#: ../../Zotlabs/Module/Like.php:105 ../../Zotlabs/Module/Like.php:131 +#: ../../Zotlabs/Module/Like.php:169 +msgid "Invalid request." msgstr "" -#: ../../Zotlabs/Module/Profile_photo.php:238 -#: ../../Zotlabs/Module/Cover_photo.php:197 -msgid "Image upload failed." +#: ../../Zotlabs/Module/Like.php:117 ../../include/conversation.php:122 +msgid "channel" msgstr "" -#: ../../Zotlabs/Module/Profile_photo.php:257 -#: ../../Zotlabs/Module/Cover_photo.php:214 -msgid "Unable to process image." +#: ../../Zotlabs/Module/Like.php:146 +msgid "thing" msgstr "" -#: ../../Zotlabs/Module/Profile_photo.php:318 -#: ../../Zotlabs/Module/Profile_photo.php:365 -#: ../../Zotlabs/Module/Cover_photo.php:307 -#: ../../Zotlabs/Module/Cover_photo.php:322 -msgid "Photo not available." +#: ../../Zotlabs/Module/Like.php:192 +msgid "Channel unavailable." msgstr "" -#: ../../Zotlabs/Module/Profile_photo.php:420 -#: ../../Zotlabs/Module/Cover_photo.php:358 -msgid "Upload File:" +#: ../../Zotlabs/Module/Like.php:240 +msgid "Previous action reversed." msgstr "" -#: ../../Zotlabs/Module/Profile_photo.php:421 -#: ../../Zotlabs/Module/Cover_photo.php:359 -msgid "Select a profile:" +#: ../../Zotlabs/Module/Like.php:370 ../../Zotlabs/Module/Subthread.php:87 +#: ../../Zotlabs/Module/Tagger.php:47 +#: ../../extend/addon/addon/redphotos/redphotohelper.php:71 +#: ../../include/text.php:1943 ../../include/conversation.php:116 +msgid "photo" msgstr "" -#: ../../Zotlabs/Module/Profile_photo.php:422 -msgid "Use Photo for Profile" +#: ../../Zotlabs/Module/Like.php:370 ../../Zotlabs/Module/Subthread.php:87 +#: ../../include/text.php:1949 ../../include/conversation.php:144 +msgid "status" msgstr "" -#: ../../Zotlabs/Module/Profile_photo.php:422 -msgid "Upload Profile Photo" +#: ../../Zotlabs/Module/Like.php:372 ../../Zotlabs/Module/Events.php:260 +#: ../../Zotlabs/Module/Tagger.php:51 ../../include/text.php:1946 +#: ../../include/event.php:1145 ../../include/conversation.php:119 +msgid "event" msgstr "" -#: ../../Zotlabs/Module/Profile_photo.php:423 -#: ../../addon/openclipatar/openclipatar.php:182 -#: ../../addon/openclipatar/openclipatar.php:194 -msgid "Use" +#: ../../Zotlabs/Module/Like.php:419 ../../include/conversation.php:160 +#, php-format +msgid "%1$s likes %2$s's %3$s" msgstr "" -#: ../../Zotlabs/Module/Profile_photo.php:429 -#: ../../Zotlabs/Module/Cover_photo.php:365 -msgid "skip this step" +#: ../../Zotlabs/Module/Like.php:421 ../../include/conversation.php:163 +#, php-format +msgid "%1$s doesn't like %2$s's %3$s" msgstr "" -#: ../../Zotlabs/Module/Profile_photo.php:429 -#: ../../Zotlabs/Module/Cover_photo.php:365 -msgid "select a photo from your photo albums" +#: ../../Zotlabs/Module/Like.php:423 +#, php-format +msgid "%1$s agrees with %2$s's %3$s" msgstr "" -#: ../../Zotlabs/Module/Profile_photo.php:448 -#: ../../Zotlabs/Module/Cover_photo.php:381 -msgid "Crop Image" +#: ../../Zotlabs/Module/Like.php:425 +#, php-format +msgid "%1$s doesn't agree with %2$s's %3$s" msgstr "" -#: ../../Zotlabs/Module/Profile_photo.php:449 -#: ../../Zotlabs/Module/Cover_photo.php:382 -msgid "Please adjust the image cropping for optimum viewing." +#: ../../Zotlabs/Module/Like.php:427 +#, php-format +msgid "%1$s abstains from a decision on %2$s's %3$s" msgstr "" -#: ../../Zotlabs/Module/Profile_photo.php:451 -#: ../../Zotlabs/Module/Cover_photo.php:384 -msgid "Done Editing" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Like.php:429 +#, php-format +msgid "%1$s is attending %2$s's %3$s" msgstr "" -#: ../../Zotlabs/Module/Chatsvc.php:131 -msgid "Away" +#: ../../Zotlabs/Module/Like.php:431 +#, php-format +msgid "%1$s is not attending %2$s's %3$s" msgstr "" -#: ../../Zotlabs/Module/Chatsvc.php:136 -msgid "Online" +#: ../../Zotlabs/Module/Like.php:433 +#, php-format +msgid "%1$s may attend %2$s's %3$s" +msgstr "" + +#: ../../Zotlabs/Module/Like.php:538 +msgid "Action completed." msgstr "" +#: ../../Zotlabs/Module/Like.php:539 +msgid "Thank you." +msgstr "" + +#: ../../Zotlabs/Module/Lockview.php:75 +msgid "Remote privacy information not available." +msgstr "" + +#: ../../Zotlabs/Module/Lockview.php:96 +msgid "Visible to:" +======= #: ../../Zotlabs/Module/Item.php:185 msgid "Unable to locate original post." msgstr "" -#: ../../Zotlabs/Module/Item.php:470 +#: ../../Zotlabs/Module/Item.php:451 msgid "Empty post discarded." msgstr "" -#: ../../Zotlabs/Module/Item.php:844 +#: ../../Zotlabs/Module/Item.php:825 msgid "Duplicate post suppressed." msgstr "" -#: ../../Zotlabs/Module/Item.php:984 +#: ../../Zotlabs/Module/Item.php:955 msgid "System error. Post not saved." msgstr "" -#: ../../Zotlabs/Module/Item.php:1020 -msgid "Your comment is awaiting approval." -msgstr "" - -#: ../../Zotlabs/Module/Item.php:1118 +#: ../../Zotlabs/Module/Item.php:1085 msgid "Unable to obtain post information from database." msgstr "" -#: ../../Zotlabs/Module/Item.php:1125 +#: ../../Zotlabs/Module/Item.php:1092 #, php-format msgid "You have reached your limit of %1$.0f top level posts." msgstr "" -#: ../../Zotlabs/Module/Item.php:1132 +#: ../../Zotlabs/Module/Item.php:1099 #, php-format msgid "You have reached your limit of %1$.0f webpages." +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Ping.php:254 -msgid "sent you a private message" +#: ../../Zotlabs/Module/Pconfig.php:26 ../../Zotlabs/Module/Pconfig.php:59 +msgid "This setting requires special processing and editing has been blocked." msgstr "" -#: ../../Zotlabs/Module/Ping.php:302 -msgid "added your channel" +#: ../../Zotlabs/Module/Pconfig.php:48 +msgid "Configuration Editor" msgstr "" -#: ../../Zotlabs/Module/Ping.php:312 -msgid "g A l F d" +#: ../../Zotlabs/Module/Pconfig.php:49 +msgid "" +"Warning: Changing some settings could render your channel inoperable. Please " +"leave this page unless you are comfortable with and knowledgeable about how " +"to correctly use this feature." msgstr "" -#: ../../Zotlabs/Module/Ping.php:330 -msgid "[today]" +#: ../../Zotlabs/Module/Subthread.php:118 +#, php-format +msgid "%1$s is following %2$s's %3$s" msgstr "" -#: ../../Zotlabs/Module/Ping.php:339 -msgid "posted an event" +#: ../../Zotlabs/Module/Subthread.php:120 +#, php-format +msgid "%1$s stopped following %2$s's %3$s" msgstr "" -#: ../../Zotlabs/Module/Page.php:40 ../../Zotlabs/Module/Block.php:31 -msgid "Invalid item." +#: ../../Zotlabs/Module/Mood.php:67 ../../include/conversation.php:256 +#, php-format +msgctxt "mood" +msgid "%1$s is %2$s" msgstr "" -#: ../../Zotlabs/Module/Page.php:129 ../../Zotlabs/Module/Block.php:79 +<<<<<<< HEAD +#: ../../Zotlabs/Module/Mood.php:135 ../../Zotlabs/Lib/Apps.php:234 +msgid "Mood" +======= +#: ../../Zotlabs/Module/Page.php:94 ../../Zotlabs/Module/Block.php:79 #: ../../Zotlabs/Module/Display.php:122 #: ../../Zotlabs/Lib/NativeWikiPage.php:500 ../../Zotlabs/Web/Router.php:146 #: ../../include/help.php:68 msgid "Page not found." +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Page.php:166 -msgid "" -"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod " -"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, " -"quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo " -"consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse " -"cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat " -"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." +#: ../../Zotlabs/Module/Mood.php:136 +msgid "Set your current mood and tell your friends" msgstr "" #: ../../Zotlabs/Module/Connedit.php:79 @@ -4962,8 +5731,13 @@ msgid "Connection has been removed." msgstr "" #: ../../Zotlabs/Module/Connedit.php:590 ../../Zotlabs/Lib/Apps.php:228 +<<<<<<< HEAD +#: ../../extend/addon/addon/openclipatar/openclipatar.php:57 +#: ../../include/nav.php:102 ../../include/conversation.php:982 +======= #: ../../addon/openclipatar/openclipatar.php:57 -#: ../../include/conversation.php:980 ../../include/nav.php:106 +#: ../../include/conversation.php:982 ../../include/nav.php:106 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "View Profile" msgstr "" @@ -5081,6 +5855,21 @@ msgstr "" msgid "Family" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Connedit.php:707 +#: ../../Zotlabs/Module/Settings/Channel.php:62 +#: ../../Zotlabs/Module/Settings/Channel.php:66 +#: ../../Zotlabs/Module/Settings/Channel.php:67 +#: ../../Zotlabs/Module/Settings/Channel.php:70 +#: ../../Zotlabs/Module/Settings/Channel.php:81 +#: ../../Zotlabs/Widget/Affinity.php:28 ../../include/selectors.php:123 +#: ../../include/channel.php:407 ../../include/channel.php:408 +#: ../../include/channel.php:415 +msgid "Friends" +msgstr "" + +======= +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 #: ../../Zotlabs/Module/Connedit.php:708 ../../Zotlabs/Widget/Affinity.php:29 msgid "Acquaintances" msgstr "" @@ -5122,7 +5911,11 @@ msgstr "" msgid "Connection Default Permissions" msgstr "" -#: ../../Zotlabs/Module/Connedit.php:847 ../../include/items.php:3980 +<<<<<<< HEAD +#: ../../Zotlabs/Module/Connedit.php:847 ../../include/items.php:3880 +======= +#: ../../Zotlabs/Module/Connedit.php:847 ../../include/items.php:3955 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 #, php-format msgid "Connection: %s" msgstr "" @@ -5204,6 +5997,15 @@ msgstr "" msgid "Connection Pending Approval" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Connedit.php:881 +#: ../../Zotlabs/Module/Settings/Tokens.php:163 +#: ../../Zotlabs/Module/Settings/Permcats.php:105 +msgid "inherited" +msgstr "" + +======= +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 #: ../../Zotlabs/Module/Connedit.php:883 #, php-format msgid "" @@ -5211,6 +6013,35 @@ msgid "" "profile securely." msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Connedit.php:885 +#: ../../Zotlabs/Module/Settings/Tokens.php:160 +msgid "Their Settings" +msgstr "" + +#: ../../Zotlabs/Module/Connedit.php:886 +#: ../../Zotlabs/Module/Settings/Tokens.php:161 +#: ../../Zotlabs/Module/Settings/Permcats.php:103 +msgid "My Settings" +msgstr "" + +#: ../../Zotlabs/Module/Connedit.php:888 +#: ../../Zotlabs/Module/Settings/Tokens.php:166 +#: ../../Zotlabs/Module/Settings/Permcats.php:108 +msgid "Individual Permissions" +msgstr "" + +#: ../../Zotlabs/Module/Connedit.php:889 +#: ../../Zotlabs/Module/Settings/Tokens.php:167 +#: ../../Zotlabs/Module/Settings/Permcats.php:109 +msgid "" +"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." +msgstr "" + +======= +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 #: ../../Zotlabs/Module/Connedit.php:890 msgid "" "Some permissions may be inherited from your channel's <a href=\"settings" @@ -5227,6 +6058,51 @@ msgstr "" msgid "Details" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Connedit.php:903 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1137 +msgid "Organisation" +msgstr "" + +#: ../../Zotlabs/Module/Connedit.php:904 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1138 +#: ../../include/page_widgets.php:46 +msgid "Title" +msgstr "" + +#: ../../Zotlabs/Module/Connedit.php:921 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1155 +msgid "P.O. Box" +msgstr "" + +#: ../../Zotlabs/Module/Connedit.php:922 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1156 +msgid "Additional" +msgstr "" + +#: ../../Zotlabs/Module/Connedit.php:923 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1157 +msgid "Street" +msgstr "" + +#: ../../Zotlabs/Module/Connedit.php:924 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1158 +msgid "Locality" +msgstr "" + +#: ../../Zotlabs/Module/Connedit.php:925 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1159 +msgid "Region" +msgstr "" + +#: ../../Zotlabs/Module/Connedit.php:926 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:1160 +msgid "ZIP Code" +msgstr "" + +#: ../../Zotlabs/Module/Blocks.php:154 ../../include/text.php:2294 +msgid "Blocks" +======= #: ../../Zotlabs/Module/Connedit.php:903 ../../addon/cdav/Mod_Cdav.php:1137 msgid "Organisation" msgstr "" @@ -5258,19 +6134,19 @@ msgstr "" #: ../../Zotlabs/Module/Connedit.php:911 ../../Zotlabs/Module/Profiles.php:795 #: ../../addon/cdav/Mod_Cdav.php:1145 ../../addon/cdav/cdav.php:270 -#: ../../include/connections.php:674 +#: ../../include/connections.php:668 msgid "Mobile" msgstr "" #: ../../Zotlabs/Module/Connedit.php:912 ../../Zotlabs/Module/Profiles.php:796 #: ../../addon/cdav/Mod_Cdav.php:1146 ../../addon/cdav/cdav.php:271 -#: ../../include/connections.php:675 +#: ../../include/connections.php:669 msgid "Home" msgstr "" #: ../../Zotlabs/Module/Connedit.php:913 ../../Zotlabs/Module/Profiles.php:797 #: ../../addon/cdav/Mod_Cdav.php:1147 ../../addon/cdav/cdav.php:274 -#: ../../include/connections.php:678 +#: ../../include/connections.php:672 msgid "Work" msgstr "" @@ -5311,548 +6187,701 @@ msgstr "" #: ../../Zotlabs/Module/Connedit.php:927 ../../Zotlabs/Module/Profiles.php:760 #: ../../addon/cdav/Mod_Cdav.php:1161 msgid "Country" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Chat.php:179 -msgid "Room not found" +#: ../../Zotlabs/Module/Blocks.php:156 +msgid "Block Title" msgstr "" -#: ../../Zotlabs/Module/Chat.php:195 -msgid "Leave Room" +#: ../../Zotlabs/Module/Cal.php:69 +msgid "Permissions denied." msgstr "" -#: ../../Zotlabs/Module/Chat.php:196 -msgid "Delete Room" +#: ../../Zotlabs/Module/Cal.php:264 ../../Zotlabs/Module/Events.php:605 +msgid "l, F j" msgstr "" -#: ../../Zotlabs/Module/Chat.php:197 -msgid "I am away right now" +#: ../../Zotlabs/Module/Cal.php:313 ../../Zotlabs/Module/Events.php:660 +#: ../../include/text.php:1765 +msgid "Link to Source" msgstr "" -#: ../../Zotlabs/Module/Chat.php:198 -msgid "I am online" +#: ../../Zotlabs/Module/Cal.php:336 ../../Zotlabs/Module/Events.php:688 +msgid "Edit Event" msgstr "" -#: ../../Zotlabs/Module/Chat.php:200 -msgid "Bookmark this room" +#: ../../Zotlabs/Module/Cal.php:336 ../../Zotlabs/Module/Events.php:688 +msgid "Create Event" msgstr "" -#: ../../Zotlabs/Module/Chat.php:203 ../../Zotlabs/Module/Mail.php:241 -#: ../../Zotlabs/Module/Mail.php:362 ../../include/conversation.php:1261 +<<<<<<< HEAD +#: ../../Zotlabs/Module/Cal.php:337 ../../Zotlabs/Module/Cal.php:344 +#: ../../Zotlabs/Module/Events.php:689 ../../Zotlabs/Module/Events.php:698 +#: ../../Zotlabs/Module/Photos.php:911 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:846 +msgid "Previous" +msgstr "" + +#: ../../Zotlabs/Module/Cal.php:339 ../../Zotlabs/Module/Events.php:691 +#: ../../include/channel.php:1344 +msgid "Export" +======= +#: ../../Zotlabs/Module/Chat.php:203 ../../Zotlabs/Module/Mail.php:259 +#: ../../Zotlabs/Module/Mail.php:380 ../../include/conversation.php:1263 msgid "Please enter a link URL:" msgstr "" -#: ../../Zotlabs/Module/Chat.php:204 ../../Zotlabs/Module/Mail.php:294 -#: ../../Zotlabs/Module/Mail.php:436 ../../Zotlabs/Lib/ThreadItem.php:744 -#: ../../include/conversation.php:1371 +#: ../../Zotlabs/Module/Chat.php:204 ../../Zotlabs/Module/Mail.php:312 +#: ../../Zotlabs/Module/Mail.php:454 ../../Zotlabs/Lib/ThreadItem.php:744 +#: ../../include/conversation.php:1373 msgid "Encrypt text" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Chat.php:230 -msgid "New Chatroom" +#: ../../Zotlabs/Module/Cal.php:342 ../../include/text.php:2318 +msgid "Import" msgstr "" -#: ../../Zotlabs/Module/Chat.php:231 -msgid "Chatroom name" +#: ../../Zotlabs/Module/Cal.php:346 ../../Zotlabs/Module/Events.php:700 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:848 +msgid "Today" msgstr "" -#: ../../Zotlabs/Module/Chat.php:232 -msgid "Expiration of chats (minutes)" +#: ../../Zotlabs/Module/Rate.php:156 +msgid "Website:" msgstr "" -#: ../../Zotlabs/Module/Chat.php:248 +#: ../../Zotlabs/Module/Rate.php:159 #, php-format -msgid "%1$s's Chatrooms" +msgid "Remote Channel [%s] (not yet known on this site)" msgstr "" -#: ../../Zotlabs/Module/Chat.php:253 -msgid "No chatrooms available" +#: ../../Zotlabs/Module/Rate.php:160 +msgid "Rating (this information is public)" msgstr "" -#: ../../Zotlabs/Module/Chat.php:257 -msgid "Expiration" +#: ../../Zotlabs/Module/Rate.php:161 +msgid "Optionally explain your rating (this information is public)" msgstr "" -#: ../../Zotlabs/Module/Chat.php:258 -msgid "min" +#: ../../Zotlabs/Module/Profile_photo.php:115 +#: ../../Zotlabs/Module/Profile_photo.php:226 +#: ../../include/photo/photo_driver.php:646 +msgid "Profile Photos" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Profile_photo.php:196 +#: ../../extend/addon/addon/openclipatar/openclipatar.php:298 +msgid "" +"Shift-reload the page or clear browser cache if the new photo does not " +"display immediately." msgstr "" +#: ../../Zotlabs/Module/Profile_photo.php:422 +msgid "Use Photo for Profile" +======= #: ../../Zotlabs/Module/Fbrowser.php:29 ../../Zotlabs/Lib/Apps.php:229 -#: ../../include/conversation.php:1781 ../../include/nav.php:385 +#: ../../include/conversation.php:1783 ../../include/nav.php:392 msgid "Photos" msgstr "" #: ../../Zotlabs/Module/Fbrowser.php:85 ../../Zotlabs/Lib/Apps.php:224 -#: ../../Zotlabs/Storage/Browser.php:224 ../../include/conversation.php:1789 -#: ../../include/nav.php:393 +#: ../../Zotlabs/Storage/Browser.php:224 ../../include/conversation.php:1791 +#: ../../include/nav.php:400 msgid "Files" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Menu.php:49 -msgid "Unable to update menu." +#: ../../Zotlabs/Module/Profile_photo.php:422 +msgid "Upload Profile Photo" msgstr "" -#: ../../Zotlabs/Module/Menu.php:60 -msgid "Unable to create menu." +#: ../../Zotlabs/Module/Profile_photo.php:423 +#: ../../extend/addon/addon/openclipatar/openclipatar.php:182 +#: ../../extend/addon/addon/openclipatar/openclipatar.php:194 +msgid "Use" msgstr "" -#: ../../Zotlabs/Module/Menu.php:98 ../../Zotlabs/Module/Menu.php:110 -msgid "Menu Name" +#: ../../Zotlabs/Module/Appman.php:38 ../../Zotlabs/Module/Appman.php:55 +msgid "App installed." msgstr "" -#: ../../Zotlabs/Module/Menu.php:98 -msgid "Unique name (not visible on webpage) - required" +#: ../../Zotlabs/Module/Appman.php:48 +msgid "Malformed app." msgstr "" -#: ../../Zotlabs/Module/Menu.php:99 ../../Zotlabs/Module/Menu.php:111 -msgid "Menu Title" +#: ../../Zotlabs/Module/Appman.php:111 +msgid "Embed code" msgstr "" -#: ../../Zotlabs/Module/Menu.php:99 -msgid "Visible on webpage - leave empty for no title" +#: ../../Zotlabs/Module/Appman.php:117 +msgid "Edit App" msgstr "" -#: ../../Zotlabs/Module/Menu.php:100 -msgid "Allow Bookmarks" +#: ../../Zotlabs/Module/Appman.php:117 +msgid "Create App" msgstr "" -#: ../../Zotlabs/Module/Menu.php:100 ../../Zotlabs/Module/Menu.php:157 -msgid "Menu may be used to store saved bookmarks" +#: ../../Zotlabs/Module/Appman.php:122 +msgid "Name of app" msgstr "" -#: ../../Zotlabs/Module/Menu.php:101 ../../Zotlabs/Module/Menu.php:159 -msgid "Submit and proceed" +#: ../../Zotlabs/Module/Appman.php:123 +msgid "Location (URL) of app" msgstr "" -#: ../../Zotlabs/Module/Menu.php:107 ../../include/text.php:2281 +<<<<<<< HEAD +#: ../../Zotlabs/Module/Appman.php:124 ../../Zotlabs/Module/Rbmark.php:101 +#: ../../Zotlabs/Module/Events.php:473 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:838 +#: ../../extend/addon/addon/rendezvous/rendezvous.php:173 +msgid "Description" +======= +#: ../../Zotlabs/Module/Menu.php:107 ../../include/text.php:2268 msgid "Menus" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Menu.php:117 -msgid "Bookmarks allowed" +#: ../../Zotlabs/Module/Appman.php:125 +msgid "Photo icon URL" msgstr "" -#: ../../Zotlabs/Module/Menu.php:119 -msgid "Delete this menu" +#: ../../Zotlabs/Module/Appman.php:125 +msgid "80 x 80 pixels - optional" msgstr "" -#: ../../Zotlabs/Module/Menu.php:120 ../../Zotlabs/Module/Menu.php:154 -msgid "Edit menu contents" +#: ../../Zotlabs/Module/Appman.php:126 +msgid "Categories (optional, comma separated list)" msgstr "" -#: ../../Zotlabs/Module/Menu.php:121 -msgid "Edit this menu" +#: ../../Zotlabs/Module/Appman.php:127 +msgid "Version ID" msgstr "" -#: ../../Zotlabs/Module/Menu.php:136 -msgid "Menu could not be deleted." +#: ../../Zotlabs/Module/Appman.php:128 +msgid "Price of app" msgstr "" -#: ../../Zotlabs/Module/Menu.php:149 -msgid "Edit Menu" +#: ../../Zotlabs/Module/Appman.php:129 +msgid "Location (URL) to purchase app" msgstr "" -#: ../../Zotlabs/Module/Menu.php:153 -msgid "Add or remove entries to this menu" +#: ../../Zotlabs/Module/Common.php:14 +msgid "No channel." msgstr "" -#: ../../Zotlabs/Module/Menu.php:155 -msgid "Menu name" +#: ../../Zotlabs/Module/Common.php:43 +msgid "Common connections" msgstr "" -#: ../../Zotlabs/Module/Menu.php:155 -msgid "Must be unique, only seen by you" +#: ../../Zotlabs/Module/Common.php:48 +msgid "No connections in common." msgstr "" -#: ../../Zotlabs/Module/Menu.php:156 -msgid "Menu title" +#: ../../Zotlabs/Module/Chanview.php:134 +msgid "toggle full screen mode" msgstr "" -#: ../../Zotlabs/Module/Menu.php:156 -msgid "Menu title as seen by others" +#: ../../Zotlabs/Module/Uexport.php:57 ../../Zotlabs/Module/Uexport.php:58 +msgid "Export Channel" msgstr "" -#: ../../Zotlabs/Module/Menu.php:157 -msgid "Allow bookmarks" +#: ../../Zotlabs/Module/Uexport.php:59 +msgid "" +"Export your basic channel information to a file. This acts as a backup of " +"your connections, permissions, profile and basic data, which can be used to " +"import your data to a new server hub, but does not contain your content." msgstr "" -#: ../../Zotlabs/Module/Layouts.php:184 ../../include/text.php:2282 +<<<<<<< HEAD +#: ../../Zotlabs/Module/Uexport.php:60 +msgid "Export Content" +msgstr "" + +#: ../../Zotlabs/Module/Uexport.php:61 +msgid "" +"Export your channel information and recent content to a JSON backup that can " +"be restored or imported to another server hub. This backs up all of your " +"connections, permissions, profile data and several months of posts. This " +"file may be VERY large. Please be patient - it may take several minutes for " +"this download to begin." +======= +#: ../../Zotlabs/Module/Layouts.php:184 ../../include/text.php:2269 msgid "Layouts" msgstr "" #: ../../Zotlabs/Module/Layouts.php:186 ../../Zotlabs/Lib/Apps.php:232 -#: ../../include/nav.php:161 ../../include/nav.php:258 +#: ../../include/nav.php:161 ../../include/nav.php:268 #: ../../include/help.php:55 ../../include/help.php:61 msgid "Help" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Layouts.php:186 -msgid "Comanche page description language help" +#: ../../Zotlabs/Module/Uexport.php:63 +msgid "Export your posts from a given year." msgstr "" -#: ../../Zotlabs/Module/Layouts.php:190 -msgid "Layout Description" +#: ../../Zotlabs/Module/Uexport.php:65 +msgid "" +"You may also export your posts and conversations for a particular year or " +"month. Adjust the date in your browser location bar to select other dates. " +"If the export fails (possibly due to memory exhaustion on your server hub), " +"please try again selecting a more limited date range." msgstr "" -#: ../../Zotlabs/Module/Layouts.php:195 -msgid "Download PDL file" +#: ../../Zotlabs/Module/Uexport.php:66 +#, php-format +msgid "" +"To select all posts for a given year, such as this year, visit <a href=\"%1$s" +"\">%2$s</a>" msgstr "" -#: ../../Zotlabs/Module/Tagger.php:55 ../../include/bbcode.php:334 -msgid "post" +#: ../../Zotlabs/Module/Uexport.php:67 +#, php-format +msgid "" +"To select all posts for a given month, such as January of this year, visit " +"<a href=\"%1$s\">%2$s</a>" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Uexport.php:68 +#, php-format +msgid "" +"These content files may be imported or restored by visiting <a href=\"%1$s\">" +"%2$s</a> on any site containing your channel. For best results please import " +"or restore these in date order (oldest first)." +======= #: ../../Zotlabs/Module/Tagger.php:57 ../../include/conversation.php:146 -#: ../../include/text.php:1959 +#: ../../include/text.php:1945 msgid "comment" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Tagger.php:95 -#, php-format -msgid "%1$s tagged %2$s's %3$s with %4$s" +#: ../../Zotlabs/Module/Item.php:184 +msgid "Unable to locate original post." msgstr "" -#: ../../Zotlabs/Module/Pconfig.php:26 ../../Zotlabs/Module/Pconfig.php:59 -msgid "This setting requires special processing and editing has been blocked." +#: ../../Zotlabs/Module/Item.php:450 +msgid "Empty post discarded." msgstr "" -#: ../../Zotlabs/Module/Pconfig.php:48 -msgid "Configuration Editor" +#: ../../Zotlabs/Module/Item.php:824 +msgid "Duplicate post suppressed." msgstr "" -#: ../../Zotlabs/Module/Pconfig.php:49 -msgid "" -"Warning: Changing some settings could render your channel inoperable. Please " -"leave this page unless you are comfortable with and knowledgeable about how " -"to correctly use this feature." +#: ../../Zotlabs/Module/Item.php:954 +msgid "System error. Post not saved." msgstr "" -#: ../../Zotlabs/Module/Group.php:24 -msgid "Privacy group created." +#: ../../Zotlabs/Module/Item.php:1084 +msgid "Unable to obtain post information from database." msgstr "" -#: ../../Zotlabs/Module/Group.php:30 -msgid "Could not create privacy group." +#: ../../Zotlabs/Module/Item.php:1091 +#, php-format +msgid "You have reached your limit of %1$.0f top level posts." msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Item.php:1098 +#, php-format +msgid "You have reached your limit of %1$.0f webpages." +======= #: ../../Zotlabs/Module/Group.php:42 ../../Zotlabs/Module/Group.php:141 -#: ../../include/items.php:3947 +#: ../../include/items.php:3922 msgid "Privacy group not found." +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Group.php:58 -msgid "Privacy group updated." +#: ../../Zotlabs/Module/Lostpass.php:19 +msgid "No valid account found." msgstr "" -#: ../../Zotlabs/Module/Group.php:90 -msgid "Create a group of channels." +#: ../../Zotlabs/Module/Lostpass.php:33 +msgid "Password reset request issued. Check your email." msgstr "" -#: ../../Zotlabs/Module/Group.php:91 ../../Zotlabs/Module/Group.php:184 -msgid "Privacy group name: " +#: ../../Zotlabs/Module/Lostpass.php:39 ../../Zotlabs/Module/Lostpass.php:108 +#, php-format +msgid "Site Member (%s)" msgstr "" -#: ../../Zotlabs/Module/Group.php:93 ../../Zotlabs/Module/Group.php:187 -msgid "Members are visible to other channels" +#: ../../Zotlabs/Module/Lostpass.php:44 ../../Zotlabs/Module/Lostpass.php:49 +#, php-format +msgid "Password reset requested at %s" msgstr "" -#: ../../Zotlabs/Module/Group.php:111 -msgid "Privacy group removed." +#: ../../Zotlabs/Module/Lostpass.php:68 +msgid "" +"Request could not be verified. (You may have previously submitted it.) " +"Password reset failed." msgstr "" -#: ../../Zotlabs/Module/Group.php:113 -msgid "Unable to remove privacy group." +#: ../../Zotlabs/Module/Lostpass.php:91 ../../boot.php:1599 +msgid "Password Reset" msgstr "" -#: ../../Zotlabs/Module/Group.php:183 -msgid "Privacy group editor" +#: ../../Zotlabs/Module/Lostpass.php:92 +msgid "Your password has been reset as requested." msgstr "" -#: ../../Zotlabs/Module/Group.php:197 ../../Zotlabs/Module/Help.php:81 -msgid "Members" +#: ../../Zotlabs/Module/Lostpass.php:93 +msgid "Your new password is" msgstr "" -#: ../../Zotlabs/Module/Group.php:199 -msgid "All Connected Channels" +#: ../../Zotlabs/Module/Lostpass.php:94 +msgid "Save or copy your new password - and then" msgstr "" -#: ../../Zotlabs/Module/Group.php:231 -msgid "Click on a channel to add or remove." +#: ../../Zotlabs/Module/Lostpass.php:95 +msgid "click here to login" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:24 ../../Zotlabs/Module/Profiles.php:184 -#: ../../Zotlabs/Module/Profiles.php:241 ../../Zotlabs/Module/Profiles.php:659 -msgid "Profile not found." +#: ../../Zotlabs/Module/Lostpass.php:96 +msgid "" +"Your password may be changed from the <em>Settings</em> page after " +"successful login." msgstr "" -#: ../../Zotlabs/Module/Profiles.php:44 -msgid "Profile deleted." +#: ../../Zotlabs/Module/Lostpass.php:117 +#, php-format +msgid "Your password has changed at %s" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:68 ../../Zotlabs/Module/Profiles.php:105 -msgid "Profile-" +#: ../../Zotlabs/Module/Lostpass.php:130 +msgid "Forgot your Password?" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:90 ../../Zotlabs/Module/Profiles.php:127 -msgid "New profile created." +#: ../../Zotlabs/Module/Lostpass.php:131 +msgid "" +"Enter your email address and submit to have your password reset. Then check " +"your email for further instructions." msgstr "" -#: ../../Zotlabs/Module/Profiles.php:111 -msgid "Profile unavailable to clone." +#: ../../Zotlabs/Module/Lostpass.php:132 +msgid "Email Address" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:146 -msgid "Profile unavailable to export." +#: ../../Zotlabs/Module/Lostpass.php:133 +msgid "Reset" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:252 -msgid "Profile Name is required." +#: ../../Zotlabs/Module/Rbmark.php:94 +msgid "Select a bookmark folder" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:459 -msgid "Marital Status" +#: ../../Zotlabs/Module/Rbmark.php:99 +msgid "Save Bookmark" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:463 -msgid "Romantic Partner" +#: ../../Zotlabs/Module/Rbmark.php:100 +msgid "URL of bookmark" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:467 ../../Zotlabs/Module/Profiles.php:775 -msgid "Likes" +#: ../../Zotlabs/Module/Rbmark.php:105 +msgid "Or enter new bookmark folder name" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:471 ../../Zotlabs/Module/Profiles.php:776 -msgid "Dislikes" +#: ../../Zotlabs/Module/Follow.php:31 +msgid "Channel added." msgstr "" -#: ../../Zotlabs/Module/Profiles.php:475 ../../Zotlabs/Module/Profiles.php:783 -msgid "Work/Employment" +#: ../../Zotlabs/Module/Regmod.php:15 +msgid "Please login." msgstr "" -#: ../../Zotlabs/Module/Profiles.php:478 -msgid "Religion" +#: ../../Zotlabs/Module/Removeaccount.php:35 +msgid "" +"Account removals are not allowed within 48 hours of changing the account " +"password." msgstr "" -#: ../../Zotlabs/Module/Profiles.php:482 -msgid "Political Views" +#: ../../Zotlabs/Module/Removeaccount.php:57 +msgid "Remove This Account" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:486 -#: ../../addon/openid/MysqlProvider.php:74 -msgid "Gender" +#: ../../Zotlabs/Module/Removeaccount.php:58 +#: ../../Zotlabs/Module/Removeme.php:61 +msgid "WARNING: " msgstr "" -#: ../../Zotlabs/Module/Profiles.php:490 -msgid "Sexual Preference" +#: ../../Zotlabs/Module/Removeaccount.php:58 +msgid "" +"This account and all its channels will be completely removed from the " +"network. " msgstr "" -#: ../../Zotlabs/Module/Profiles.php:494 -msgid "Homepage" +#: ../../Zotlabs/Module/Removeaccount.php:58 +#: ../../Zotlabs/Module/Removeme.php:61 +msgid "This action is permanent and can not be undone!" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:498 -msgid "Interests" +#: ../../Zotlabs/Module/Removeaccount.php:59 +#: ../../Zotlabs/Module/Removeme.php:62 +msgid "Please enter your password for verification:" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:594 -msgid "Profile updated." +#: ../../Zotlabs/Module/Removeaccount.php:60 +msgid "" +"Remove this account, all its channels and all its channel clones from the " +"network" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:678 -msgid "Hide your connections list from viewers of this profile" +#: ../../Zotlabs/Module/Removeaccount.php:60 +msgid "" +"By default only the instances of the channels located on this hub will be " +"removed from the network" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:725 -msgid "Edit Profile Details" +#: ../../Zotlabs/Module/Removeaccount.php:61 +#: ../../Zotlabs/Module/Settings/Account.php:120 +msgid "Remove Account" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:727 -msgid "View this profile" +#: ../../Zotlabs/Module/Pdledit.php:21 +msgid "Layout updated." +msgstr "" + +#: ../../Zotlabs/Module/Pdledit.php:34 ../../Zotlabs/Module/Chat.php:217 +msgid "Feature disabled." msgstr "" +#: ../../Zotlabs/Module/Pdledit.php:42 ../../Zotlabs/Module/Pdledit.php:69 +msgid "Edit System Page Description" +msgstr "" + +#: ../../Zotlabs/Module/Pdledit.php:64 +msgid "Layout not found." +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Pdledit.php:70 +msgid "Module Name:" +======= #: ../../Zotlabs/Module/Profiles.php:728 ../../Zotlabs/Module/Profiles.php:827 -#: ../../include/channel.php:1080 +#: ../../include/channel.php:1066 msgid "Edit visibility" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Profiles.php:729 -msgid "Profile Tools" +#: ../../Zotlabs/Module/Pdledit.php:71 +msgid "Layout Help" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:730 -msgid "Change cover photo" +#: ../../Zotlabs/Module/Profperm.php:34 ../../Zotlabs/Module/Profperm.php:63 +msgid "Invalid profile identifier." msgstr "" -#: ../../Zotlabs/Module/Profiles.php:731 ../../include/channel.php:1051 +<<<<<<< HEAD +#: ../../Zotlabs/Module/Profperm.php:111 +msgid "Profile Visibility Editor" +======= +#: ../../Zotlabs/Module/Profiles.php:731 ../../include/channel.php:1037 msgid "Change profile photo" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Profiles.php:732 -msgid "Create a new profile using these settings" +#: ../../Zotlabs/Module/Profperm.php:113 ../../include/channel.php:1341 +msgid "Profile" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:733 -msgid "Clone this profile" +#: ../../Zotlabs/Module/Profperm.php:115 +msgid "Click on a contact to add or remove." msgstr "" -#: ../../Zotlabs/Module/Profiles.php:734 -msgid "Delete this profile" +#: ../../Zotlabs/Module/Profperm.php:124 +msgid "Visible To" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:735 -msgid "Add profile things" +#: ../../Zotlabs/Module/Events.php:25 +msgid "Calendar entries imported." msgstr "" -#: ../../Zotlabs/Module/Profiles.php:736 ../../include/conversation.php:1655 +<<<<<<< HEAD +#: ../../Zotlabs/Module/Events.php:27 +msgid "No calendar entries found." +======= +#: ../../Zotlabs/Module/Profiles.php:736 ../../include/conversation.php:1657 msgid "Personal" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Profiles.php:738 -msgid "Relation" +#: ../../Zotlabs/Module/Events.php:110 +msgid "Event can not end before it has started." msgstr "" -#: ../../Zotlabs/Module/Profiles.php:739 ../../include/datetime.php:55 -msgid "Miscellaneous" +#: ../../Zotlabs/Module/Events.php:112 ../../Zotlabs/Module/Events.php:121 +#: ../../Zotlabs/Module/Events.php:143 +msgid "Unable to generate preview." msgstr "" -#: ../../Zotlabs/Module/Profiles.php:741 -msgid "Import profile from file" +#: ../../Zotlabs/Module/Events.php:119 +msgid "Event title and start time are required." msgstr "" -#: ../../Zotlabs/Module/Profiles.php:742 -msgid "Export profile to file" +#: ../../Zotlabs/Module/Events.php:141 ../../Zotlabs/Module/Events.php:265 +msgid "Event not found." msgstr "" -#: ../../Zotlabs/Module/Profiles.php:743 -msgid "Your gender" +#: ../../Zotlabs/Module/Events.php:460 +msgid "Edit event title" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:744 -msgid "Marital status" +#: ../../Zotlabs/Module/Events.php:460 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:835 +msgid "Event title" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:745 -msgid "Sexual preference" +#: ../../Zotlabs/Module/Events.php:462 +msgid "Categories (comma-separated list)" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:748 -msgid "Profile name" +#: ../../Zotlabs/Module/Events.php:463 +msgid "Edit Category" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:750 -msgid "This is your default profile." +#: ../../Zotlabs/Module/Events.php:463 +msgid "Category" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:752 -msgid "Your full name" +#: ../../Zotlabs/Module/Events.php:466 +msgid "Edit start date and time" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:753 -msgid "Title/Description" +#: ../../Zotlabs/Module/Events.php:466 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:836 +msgid "Start date and time" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:756 -msgid "Street address" +#: ../../Zotlabs/Module/Events.php:467 ../../Zotlabs/Module/Events.php:470 +msgid "Finish date and time are not known or not relevant" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:757 -msgid "Locality/City" +#: ../../Zotlabs/Module/Events.php:469 +msgid "Edit finish date and time" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:758 -msgid "Region/State" +#: ../../Zotlabs/Module/Events.php:469 +msgid "Finish date and time" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:759 -msgid "Postal/Zip code" +#: ../../Zotlabs/Module/Events.php:471 ../../Zotlabs/Module/Events.php:472 +msgid "Adjust for viewer timezone" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:765 -msgid "Who (if applicable)" +#: ../../Zotlabs/Module/Events.php:471 +msgid "" +"Important for events that happen in a particular place. Not practical for " +"global holidays." msgstr "" -#: ../../Zotlabs/Module/Profiles.php:765 -msgid "Examples: cathy123, Cathy Williams, cathy@example.com" +#: ../../Zotlabs/Module/Events.php:473 +msgid "Edit Description" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:766 -msgid "Since (date)" +#: ../../Zotlabs/Module/Events.php:475 +msgid "Edit Location" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:769 -msgid "Tell us about yourself" +#: ../../Zotlabs/Module/Events.php:479 ../../include/conversation.php:1343 +msgid "Permission settings" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:770 -#: ../../addon/openid/MysqlProvider.php:68 -msgid "Homepage URL" +#: ../../Zotlabs/Module/Events.php:489 +msgid "Timezone:" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:771 -msgid "Hometown" +#: ../../Zotlabs/Module/Events.php:494 +msgid "Advanced Options" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:772 -msgid "Political views" +#: ../../Zotlabs/Module/Events.php:633 +msgid "Edit event" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:773 -msgid "Religious views" +#: ../../Zotlabs/Module/Events.php:635 +msgid "Delete event" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:774 -msgid "Keywords used in directory listings" +#: ../../Zotlabs/Module/Events.php:669 +msgid "calendar" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:774 -msgid "Example: fishing photography software" +#: ../../Zotlabs/Module/Events.php:695 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:849 +msgid "Month" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:777 -msgid "Musical interests" +#: ../../Zotlabs/Module/Events.php:696 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:850 +msgid "Week" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:778 -msgid "Books, literature" +#: ../../Zotlabs/Module/Events.php:697 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:851 +msgid "Day" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:779 -msgid "Television" +#: ../../Zotlabs/Module/Events.php:731 +msgid "Event removed" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:780 -msgid "Film/Dance/Culture/Entertainment" +#: ../../Zotlabs/Module/Events.php:734 +msgid "Failed to remove event" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:781 -msgid "Hobbies/Interests" +#: ../../Zotlabs/Module/Service_limits.php:23 +msgid "No service class restrictions found." msgstr "" -#: ../../Zotlabs/Module/Profiles.php:782 -msgid "Love/Romance" +#: ../../Zotlabs/Module/Bookmarks.php:53 +msgid "Bookmark added" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:784 -msgid "School/Education" +#: ../../Zotlabs/Module/Bookmarks.php:76 +msgid "My Bookmarks" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:785 -msgid "Contact information and social networks" +#: ../../Zotlabs/Module/Bookmarks.php:87 +msgid "My Connections Bookmarks" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:786 -msgid "My other channels" +#: ../../Zotlabs/Module/Removeme.php:35 +msgid "" +"Channel removals are not allowed within 48 hours of changing the account " +"password." msgstr "" -#: ../../Zotlabs/Module/Profiles.php:788 -msgid "Communications" +#: ../../Zotlabs/Module/Removeme.php:60 +msgid "Remove This Channel" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Removeme.php:61 +msgid "This channel will be completely removed from the network. " +msgstr "" + +#: ../../Zotlabs/Module/Removeme.php:63 +msgid "Remove this channel and all its clones from the network" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:823 ../../include/channel.php:1076 +#: ../../Zotlabs/Module/Removeme.php:63 +msgid "" +"By default only the instance of the channel located on this hub will be " +"removed from the network" +msgstr "" + +#: ../../Zotlabs/Module/Removeme.php:64 +#: ../../Zotlabs/Module/Settings/Channel.php:575 +msgid "Remove Channel" +======= +#: ../../Zotlabs/Module/Profiles.php:823 ../../include/channel.php:1062 msgid "Profile Image" msgstr "" -#: ../../Zotlabs/Module/Profiles.php:833 ../../include/channel.php:1058 +#: ../../Zotlabs/Module/Profiles.php:833 ../../include/channel.php:1044 #: ../../include/nav.php:109 msgid "Edit Profiles" msgstr "" @@ -5863,12 +6892,45 @@ msgstr "" #: ../../Zotlabs/Module/Editwebpage.php:166 msgid "Edit Webpage" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Manage.php:143 -msgid "Create a new channel" +#: ../../Zotlabs/Module/Sharedwithme.php:99 +msgid "Files: shared with me" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Sharedwithme.php:101 +msgid "NEW" +msgstr "" + +#: ../../Zotlabs/Module/Sharedwithme.php:104 +msgid "Remove all files" +msgstr "" + +#: ../../Zotlabs/Module/Sharedwithme.php:105 +msgid "Remove this file" msgstr "" +#: ../../Zotlabs/Module/Viewsrc.php:46 +msgid "Source of Item" +msgstr "" + +#: ../../Zotlabs/Module/Sources.php:37 +msgid "Failed to create source. No channel selected." +msgstr "" + +#: ../../Zotlabs/Module/Sources.php:51 +msgid "Source created." +msgstr "" + +#: ../../Zotlabs/Module/Sources.php:64 +msgid "Source updated." +msgstr "" + +#: ../../Zotlabs/Module/Sources.php:90 +msgid "*" +======= #: ../../Zotlabs/Module/Manage.php:168 ../../Zotlabs/Lib/Apps.php:221 #: ../../include/nav.php:205 msgid "Channel Manager" @@ -5902,1203 +6964,1391 @@ msgstr "" #: ../../Zotlabs/Module/Manage.php:179 msgid "Delegated Channel" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Dirsearch.php:33 -msgid "This directory server requires an access token" +#: ../../Zotlabs/Module/Sources.php:96 +#: ../../Zotlabs/Widget/Settings_menu.php:123 ../../include/features.php:213 +msgid "Channel Sources" msgstr "" -#: ../../Zotlabs/Module/Siteinfo.php:20 -msgid "About this site" +#: ../../Zotlabs/Module/Sources.php:97 +msgid "Manage remote sources of content for your channel." msgstr "" -#: ../../Zotlabs/Module/Siteinfo.php:21 -msgid "Site Name" +#: ../../Zotlabs/Module/Sources.php:98 ../../Zotlabs/Module/Sources.php:108 +msgid "New Source" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Sources.php:109 ../../Zotlabs/Module/Sources.php:143 +msgid "" +"Import all or selected content from the following channel into this channel " +"and distribute it according to your channel settings." +======= #: ../../Zotlabs/Module/Siteinfo.php:25 ../../include/network.php:2025 msgid "Administrator" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Siteinfo.php:27 ../../Zotlabs/Module/Register.php:221 -msgid "Terms of Service" +#: ../../Zotlabs/Module/Sources.php:110 ../../Zotlabs/Module/Sources.php:144 +msgid "Only import content with these words (one per line)" msgstr "" -#: ../../Zotlabs/Module/Siteinfo.php:28 -msgid "Software and Project information" +#: ../../Zotlabs/Module/Sources.php:110 ../../Zotlabs/Module/Sources.php:144 +msgid "Leave blank to import all public content" msgstr "" -#: ../../Zotlabs/Module/Siteinfo.php:29 -msgid "This site is powered by $Projectname" +#: ../../Zotlabs/Module/Sources.php:111 ../../Zotlabs/Module/Sources.php:148 +msgid "Channel Name" msgstr "" -#: ../../Zotlabs/Module/Siteinfo.php:30 +#: ../../Zotlabs/Module/Sources.php:112 ../../Zotlabs/Module/Sources.php:147 msgid "" -"Federated and decentralised networking and identity services provided by Zot" +"Add the following categories to posts imported from this source (comma " +"separated)" msgstr "" -#: ../../Zotlabs/Module/Siteinfo.php:32 -#, php-format -msgid "Version %s" +#: ../../Zotlabs/Module/Sources.php:112 ../../Zotlabs/Module/Sources.php:147 +#: ../../Zotlabs/Module/Settings/Oauth.php:93 +msgid "Optional" msgstr "" -#: ../../Zotlabs/Module/Siteinfo.php:33 -msgid "Project homepage" +#: ../../Zotlabs/Module/Sources.php:133 ../../Zotlabs/Module/Sources.php:161 +msgid "Source not found." msgstr "" -#: ../../Zotlabs/Module/Siteinfo.php:34 -msgid "Developer homepage" +#: ../../Zotlabs/Module/Sources.php:140 +msgid "Edit Source" msgstr "" -#: ../../Zotlabs/Module/Ratings.php:70 -msgid "No ratings" +#: ../../Zotlabs/Module/Sources.php:141 +msgid "Delete Source" msgstr "" -#: ../../Zotlabs/Module/Ratings.php:97 ../../Zotlabs/Module/Pubsites.php:35 -#: ../../include/conversation.php:1030 -msgid "Ratings" +#: ../../Zotlabs/Module/Sources.php:169 +msgid "Source removed" msgstr "" -#: ../../Zotlabs/Module/Ratings.php:98 -msgid "Rating: " +#: ../../Zotlabs/Module/Sources.php:171 +msgid "Unable to remove source." msgstr "" -#: ../../Zotlabs/Module/Ratings.php:99 -msgid "Website: " +#: ../../Zotlabs/Module/Mail.php:65 +msgid "Unable to lookup recipient." msgstr "" -#: ../../Zotlabs/Module/Ratings.php:101 -msgid "Description: " +#: ../../Zotlabs/Module/Mail.php:72 +msgid "Unable to communicate with requested channel." msgstr "" -#: ../../Zotlabs/Module/Webpages.php:52 -msgid "Import Webpage Elements" +#: ../../Zotlabs/Module/Mail.php:79 +msgid "Cannot verify requested channel." msgstr "" -#: ../../Zotlabs/Module/Webpages.php:53 -msgid "Import selected" +#: ../../Zotlabs/Module/Mail.php:97 +msgid "Selected channel has private message restrictions. Send failed." msgstr "" -#: ../../Zotlabs/Module/Webpages.php:76 -msgid "Export Webpage Elements" +#: ../../Zotlabs/Module/Mail.php:178 +msgid "Messages" msgstr "" -#: ../../Zotlabs/Module/Webpages.php:77 -msgid "Export selected" +#: ../../Zotlabs/Module/Mail.php:213 +msgid "Message recalled." msgstr "" -#: ../../Zotlabs/Module/Webpages.php:244 ../../Zotlabs/Lib/Apps.php:225 -#: ../../include/conversation.php:1839 ../../include/nav.php:442 +<<<<<<< HEAD +#: ../../Zotlabs/Module/Mail.php:226 +msgid "Conversation removed." +======= +#: ../../Zotlabs/Module/Webpages.php:242 ../../Zotlabs/Lib/Apps.php:225 +#: ../../include/conversation.php:1841 ../../include/nav.php:449 msgid "Webpages" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Webpages.php:255 ../../include/page_widgets.php:44 -msgid "Actions" +#: ../../Zotlabs/Module/Mail.php:240 ../../Zotlabs/Module/Mail.php:361 +#: ../../Zotlabs/Module/Chat.php:203 ../../include/conversation.php:1263 +msgid "Please enter a link URL:" msgstr "" -#: ../../Zotlabs/Module/Webpages.php:256 ../../include/page_widgets.php:45 -msgid "Page Link" +#: ../../Zotlabs/Module/Mail.php:241 ../../Zotlabs/Module/Mail.php:362 +msgid "Expires YYYY-MM-DD HH:MM" msgstr "" -#: ../../Zotlabs/Module/Webpages.php:257 -msgid "Page Title" +#: ../../Zotlabs/Module/Mail.php:269 +msgid "Requested channel is not in this network" msgstr "" -#: ../../Zotlabs/Module/Webpages.php:287 -msgid "Invalid file type." +#: ../../Zotlabs/Module/Mail.php:277 +msgid "Send Private Message" msgstr "" -#: ../../Zotlabs/Module/Webpages.php:299 -msgid "Error opening zip file" +#: ../../Zotlabs/Module/Mail.php:278 ../../Zotlabs/Module/Mail.php:415 +msgid "To:" msgstr "" -#: ../../Zotlabs/Module/Webpages.php:310 -msgid "Invalid folder path." +#: ../../Zotlabs/Module/Mail.php:281 ../../Zotlabs/Module/Mail.php:417 +msgid "Subject:" msgstr "" -#: ../../Zotlabs/Module/Webpages.php:337 -msgid "No webpage elements detected." +#: ../../Zotlabs/Module/Mail.php:286 ../../Zotlabs/Module/Mail.php:423 +#: ../../include/conversation.php:1323 +msgid "Attach file" msgstr "" -#: ../../Zotlabs/Module/Webpages.php:412 -msgid "Import complete." +#: ../../Zotlabs/Module/Mail.php:288 +msgid "Send" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Mail.php:291 ../../Zotlabs/Module/Mail.php:428 +#: ../../include/conversation.php:1368 +msgid "Set expiration date" msgstr "" +#: ../../Zotlabs/Module/Mail.php:293 ../../Zotlabs/Module/Mail.php:430 +#: ../../Zotlabs/Module/Chat.php:204 ../../Zotlabs/Lib/ThreadItem.php:744 +#: ../../include/conversation.php:1373 +msgid "Encrypt text" +======= #: ../../Zotlabs/Module/Editpost.php:38 msgid "Item is not editable" msgstr "" #: ../../Zotlabs/Module/Editpost.php:103 ../../Zotlabs/Module/Rpost.php:138 msgid "Edit post" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Dreport.php:45 -msgid "Invalid message" +#: ../../Zotlabs/Module/Mail.php:387 +msgid "Delete message" msgstr "" -#: ../../Zotlabs/Module/Dreport.php:78 -msgid "no results" +#: ../../Zotlabs/Module/Mail.php:388 +msgid "Delivery report" msgstr "" -#: ../../Zotlabs/Module/Dreport.php:93 -msgid "channel sync processed" +#: ../../Zotlabs/Module/Mail.php:389 +msgid "Recall message" msgstr "" -#: ../../Zotlabs/Module/Dreport.php:97 -msgid "queued" +#: ../../Zotlabs/Module/Mail.php:391 +msgid "Message has been recalled." msgstr "" -#: ../../Zotlabs/Module/Dreport.php:101 -msgid "posted" +#: ../../Zotlabs/Module/Mail.php:408 +msgid "Delete Conversation" msgstr "" -#: ../../Zotlabs/Module/Dreport.php:105 -msgid "accepted for delivery" +#: ../../Zotlabs/Module/Mail.php:410 +msgid "" +"No secure communications available. You <strong>may</strong> be able to " +"respond from the sender's profile page." msgstr "" -#: ../../Zotlabs/Module/Dreport.php:109 -msgid "updated" +#: ../../Zotlabs/Module/Mail.php:414 +msgid "Send Reply" msgstr "" -#: ../../Zotlabs/Module/Dreport.php:112 -msgid "update ignored" +#: ../../Zotlabs/Module/Mail.php:419 +#, php-format +msgid "Your message for %s (%s):" msgstr "" -#: ../../Zotlabs/Module/Dreport.php:115 -msgid "permission denied" +#: ../../Zotlabs/Module/Suggest.php:37 +msgid "" +"No suggestions available. If this is a new site, please try again in 24 " +"hours." msgstr "" -#: ../../Zotlabs/Module/Dreport.php:119 -msgid "recipient not found" +#: ../../Zotlabs/Module/Suggest.php:56 ../../Zotlabs/Widget/Suggestions.php:46 +msgid "Ignore/Hide" msgstr "" -#: ../../Zotlabs/Module/Dreport.php:122 -msgid "mail recalled" +#: ../../Zotlabs/Module/Rmagic.php:35 +msgid "Authentication failed." msgstr "" -#: ../../Zotlabs/Module/Dreport.php:125 -msgid "duplicate mail received" +#: ../../Zotlabs/Module/Rmagic.php:75 ../../include/channel.php:1963 +msgid "Remote Authentication" msgstr "" -#: ../../Zotlabs/Module/Dreport.php:128 -msgid "mail delivered" +#: ../../Zotlabs/Module/Rmagic.php:76 ../../include/channel.php:1964 +msgid "Enter your channel address (e.g. channel@example.com)" msgstr "" -#: ../../Zotlabs/Module/Dreport.php:148 -#, php-format -msgid "Delivery report for %1$s" +#: ../../Zotlabs/Module/Rmagic.php:77 ../../include/channel.php:1965 +msgid "Authenticate" msgstr "" -#: ../../Zotlabs/Module/Dreport.php:151 -msgid "Options" +#: ../../Zotlabs/Module/Settings/Features.php:45 +msgid "Additional Features" msgstr "" -#: ../../Zotlabs/Module/Dreport.php:152 -msgid "Redeliver" +#: ../../Zotlabs/Module/Settings/Oauth.php:34 +msgid "Name is required" msgstr "" -#: ../../Zotlabs/Module/Sources.php:37 -msgid "Failed to create source. No channel selected." +#: ../../Zotlabs/Module/Settings/Oauth.php:38 +msgid "Key and Secret are required" msgstr "" -#: ../../Zotlabs/Module/Sources.php:51 -msgid "Source created." +#: ../../Zotlabs/Module/Settings/Oauth.php:86 +#: ../../Zotlabs/Module/Settings/Oauth.php:112 +#: ../../Zotlabs/Module/Settings/Oauth.php:148 +msgid "Add application" msgstr "" -#: ../../Zotlabs/Module/Sources.php:64 -msgid "Source updated." +#: ../../Zotlabs/Module/Settings/Oauth.php:89 +msgid "Name of application" msgstr "" -#: ../../Zotlabs/Module/Sources.php:90 -msgid "*" +#: ../../Zotlabs/Module/Settings/Oauth.php:90 +#: ../../Zotlabs/Module/Settings/Oauth.php:116 +#: ../../extend/addon/addon/statusnet/statusnet.php:893 +#: ../../extend/addon/addon/twitter/twitter.php:775 +msgid "Consumer Key" msgstr "" -#: ../../Zotlabs/Module/Sources.php:96 -#: ../../Zotlabs/Widget/Settings_menu.php:123 ../../include/features.php:213 -msgid "Channel Sources" +#: ../../Zotlabs/Module/Settings/Oauth.php:90 +#: ../../Zotlabs/Module/Settings/Oauth.php:91 +msgid "Automatically generated - change if desired. Max length 20" msgstr "" -#: ../../Zotlabs/Module/Sources.php:97 -msgid "Manage remote sources of content for your channel." +#: ../../Zotlabs/Module/Settings/Oauth.php:91 +#: ../../Zotlabs/Module/Settings/Oauth.php:117 +#: ../../extend/addon/addon/statusnet/statusnet.php:892 +#: ../../extend/addon/addon/twitter/twitter.php:776 +msgid "Consumer Secret" msgstr "" -#: ../../Zotlabs/Module/Sources.php:98 ../../Zotlabs/Module/Sources.php:108 -msgid "New Source" +#: ../../Zotlabs/Module/Settings/Oauth.php:92 +#: ../../Zotlabs/Module/Settings/Oauth.php:118 +msgid "Redirect" msgstr "" -#: ../../Zotlabs/Module/Sources.php:109 ../../Zotlabs/Module/Sources.php:143 +#: ../../Zotlabs/Module/Settings/Oauth.php:92 msgid "" -"Import all or selected content from the following channel into this channel " -"and distribute it according to your channel settings." +"Redirect URI - leave blank unless your application specifically requires this" msgstr "" -#: ../../Zotlabs/Module/Sources.php:110 ../../Zotlabs/Module/Sources.php:144 -msgid "Only import content with these words (one per line)" +#: ../../Zotlabs/Module/Settings/Oauth.php:93 +#: ../../Zotlabs/Module/Settings/Oauth.php:119 +msgid "Icon url" msgstr "" -#: ../../Zotlabs/Module/Sources.php:110 ../../Zotlabs/Module/Sources.php:144 -msgid "Leave blank to import all public content" +#: ../../Zotlabs/Module/Settings/Oauth.php:104 +msgid "Application not found." msgstr "" -#: ../../Zotlabs/Module/Sources.php:111 ../../Zotlabs/Module/Sources.php:148 -msgid "Channel Name" +#: ../../Zotlabs/Module/Settings/Oauth.php:147 +msgid "Connected Apps" msgstr "" -#: ../../Zotlabs/Module/Sources.php:112 ../../Zotlabs/Module/Sources.php:147 -msgid "" -"Add the following categories to posts imported from this source (comma " -"separated)" +#: ../../Zotlabs/Module/Settings/Oauth.php:151 +msgid "Client key starts with" msgstr "" -#: ../../Zotlabs/Module/Sources.php:133 ../../Zotlabs/Module/Sources.php:161 -msgid "Source not found." +#: ../../Zotlabs/Module/Settings/Oauth.php:152 +msgid "No name" msgstr "" -#: ../../Zotlabs/Module/Sources.php:140 -msgid "Edit Source" +#: ../../Zotlabs/Module/Settings/Oauth.php:153 +msgid "Remove authorization" msgstr "" -#: ../../Zotlabs/Module/Sources.php:141 -msgid "Delete Source" +#: ../../Zotlabs/Module/Settings/Account.php:20 +msgid "Not valid email." msgstr "" -#: ../../Zotlabs/Module/Sources.php:169 -msgid "Source removed" +#: ../../Zotlabs/Module/Settings/Account.php:23 +msgid "Protected email address. Cannot change to that email." msgstr "" -#: ../../Zotlabs/Module/Sources.php:171 -msgid "Unable to remove source." +#: ../../Zotlabs/Module/Settings/Account.php:32 +msgid "System failure storing new email. Please try again." msgstr "" -#: ../../Zotlabs/Module/Like.php:19 -msgid "Like/Dislike" +#: ../../Zotlabs/Module/Settings/Account.php:40 +msgid "Technical skill level updated" msgstr "" -#: ../../Zotlabs/Module/Like.php:24 -msgid "This action is restricted to members." +#: ../../Zotlabs/Module/Settings/Account.php:56 +msgid "Password verification failed." msgstr "" -#: ../../Zotlabs/Module/Like.php:25 -msgid "" -"Please <a href=\"rmagic\">login with your $Projectname ID</a> or <a href=" -"\"register\">register as a new $Projectname member</a> to continue." +#: ../../Zotlabs/Module/Settings/Account.php:63 +msgid "Passwords do not match. Password unchanged." msgstr "" -#: ../../Zotlabs/Module/Like.php:105 ../../Zotlabs/Module/Like.php:131 -#: ../../Zotlabs/Module/Like.php:169 -msgid "Invalid request." +#: ../../Zotlabs/Module/Settings/Account.php:67 +msgid "Empty passwords are not allowed. Password unchanged." msgstr "" -#: ../../Zotlabs/Module/Like.php:117 ../../include/conversation.php:122 -msgid "channel" +#: ../../Zotlabs/Module/Settings/Account.php:81 +msgid "Password changed." msgstr "" -#: ../../Zotlabs/Module/Like.php:146 -msgid "thing" +#: ../../Zotlabs/Module/Settings/Account.php:83 +msgid "Password update failed. Please try again." msgstr "" -#: ../../Zotlabs/Module/Like.php:192 -msgid "Channel unavailable." +#: ../../Zotlabs/Module/Settings/Account.php:112 +msgid "Account Settings" msgstr "" -#: ../../Zotlabs/Module/Like.php:240 -msgid "Previous action reversed." +#: ../../Zotlabs/Module/Settings/Account.php:113 +msgid "Current Password" msgstr "" -#: ../../Zotlabs/Module/Like.php:423 ../../addon/diaspora/inbound.php:1811 +<<<<<<< HEAD +#: ../../Zotlabs/Module/Settings/Account.php:114 +msgid "Enter New Password" +======= +#: ../../Zotlabs/Module/Like.php:419 ../../addon/diaspora/inbound.php:1812 #: ../../include/conversation.php:160 #, php-format msgid "%1$s likes %2$s's %3$s" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Like.php:425 ../../include/conversation.php:163 -#, php-format -msgid "%1$s doesn't like %2$s's %3$s" +#: ../../Zotlabs/Module/Settings/Account.php:115 +msgid "Confirm New Password" msgstr "" -#: ../../Zotlabs/Module/Like.php:427 -#, php-format -msgid "%1$s agrees with %2$s's %3$s" +#: ../../Zotlabs/Module/Settings/Account.php:115 +msgid "Leave password fields blank unless changing" msgstr "" -#: ../../Zotlabs/Module/Like.php:429 -#, php-format -msgid "%1$s doesn't agree with %2$s's %3$s" +#: ../../Zotlabs/Module/Settings/Account.php:116 +msgid "Your technical skill level" msgstr "" -#: ../../Zotlabs/Module/Like.php:431 -#, php-format -msgid "%1$s abstains from a decision on %2$s's %3$s" +#: ../../Zotlabs/Module/Settings/Account.php:116 +msgid "Used to provide a member experience matched to your comfort level" msgstr "" -#: ../../Zotlabs/Module/Like.php:433 -#, php-format -msgid "%1$s is attending %2$s's %3$s" +#: ../../Zotlabs/Module/Settings/Account.php:119 +#: ../../Zotlabs/Module/Settings/Channel.php:483 +msgid "Email Address:" msgstr "" -#: ../../Zotlabs/Module/Like.php:435 -#, php-format -msgid "%1$s is not attending %2$s's %3$s" +#: ../../Zotlabs/Module/Settings/Account.php:121 +msgid "Remove this account including all its channels" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Display.php:145 +msgid "No special theme for mobile devices" msgstr "" -#: ../../Zotlabs/Module/Like.php:437 +#: ../../Zotlabs/Module/Settings/Display.php:148 #, php-format -msgid "%1$s may attend %2$s's %3$s" +msgid "%s - (Experimental)" msgstr "" -#: ../../Zotlabs/Module/Like.php:542 -msgid "Action completed." +#: ../../Zotlabs/Module/Settings/Display.php:198 +msgid "Display Settings" msgstr "" -#: ../../Zotlabs/Module/Like.php:543 -msgid "Thank you." +#: ../../Zotlabs/Module/Settings/Display.php:199 +msgid "Theme Settings" msgstr "" -#: ../../Zotlabs/Module/Directory.php:245 -#, php-format -msgid "%d rating" -msgid_plural "%d ratings" -msgstr[0] "" -msgstr[1] "" +#: ../../Zotlabs/Module/Settings/Display.php:200 +msgid "Custom Theme Settings" +msgstr "" -#: ../../Zotlabs/Module/Directory.php:256 -msgid "Gender: " +#: ../../Zotlabs/Module/Settings/Display.php:201 +msgid "Content Settings" msgstr "" -#: ../../Zotlabs/Module/Directory.php:258 -msgid "Status: " +#: ../../Zotlabs/Module/Settings/Display.php:207 +msgid "Display Theme:" msgstr "" -#: ../../Zotlabs/Module/Directory.php:260 -msgid "Homepage: " +#: ../../Zotlabs/Module/Settings/Display.php:208 +msgid "Select scheme" msgstr "" -#: ../../Zotlabs/Module/Directory.php:309 ../../include/channel.php:1307 +<<<<<<< HEAD +#: ../../Zotlabs/Module/Settings/Display.php:210 +msgid "Mobile Theme:" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Display.php:211 +msgid "Preload images before rendering the page" +======= +#: ../../Zotlabs/Module/Directory.php:309 ../../include/channel.php:1293 msgid "Age:" msgstr "" -#: ../../Zotlabs/Module/Directory.php:314 ../../include/markdown.php:496 -#: ../../include/channel.php:1148 ../../include/event.php:52 +#: ../../Zotlabs/Module/Directory.php:314 ../../include/markdown.php:560 +#: ../../include/channel.php:1134 ../../include/event.php:52 #: ../../include/event.php:84 msgid "Location:" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Directory.php:320 -msgid "Description:" +#: ../../Zotlabs/Module/Settings/Display.php:211 +msgid "" +"The subjective page load time will be longer but the page will be ready when " +"displayed" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Settings/Display.php:212 +msgid "Enable user zoom on mobile devices" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Display.php:213 +msgid "Update browser every xx seconds" msgstr "" -#: ../../Zotlabs/Module/Directory.php:325 ../../include/channel.php:1323 +#: ../../Zotlabs/Module/Settings/Display.php:213 +msgid "Minimum of 10 seconds, no maximum" +======= +#: ../../Zotlabs/Module/Directory.php:325 ../../include/channel.php:1309 msgid "Hometown:" msgstr "" -#: ../../Zotlabs/Module/Directory.php:327 ../../include/channel.php:1331 +#: ../../Zotlabs/Module/Directory.php:327 ../../include/channel.php:1317 msgid "About:" msgstr "" #: ../../Zotlabs/Module/Directory.php:328 ../../Zotlabs/Module/Suggest.php:54 #: ../../Zotlabs/Widget/Follow.php:32 ../../Zotlabs/Widget/Suggestions.php:44 -#: ../../include/conversation.php:1000 ../../include/channel.php:1133 -#: ../../include/connections.php:111 +#: ../../include/conversation.php:1002 ../../include/channel.php:1119 +#: ../../include/connections.php:110 msgid "Connect" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Directory.php:329 -msgid "Public Forum:" +#: ../../Zotlabs/Module/Settings/Display.php:214 +msgid "Maximum number of conversations to load at any time:" msgstr "" -#: ../../Zotlabs/Module/Directory.php:332 -msgid "Keywords: " +#: ../../Zotlabs/Module/Settings/Display.php:214 +msgid "Maximum of 100 items" msgstr "" -#: ../../Zotlabs/Module/Directory.php:335 -msgid "Don't suggest" +#: ../../Zotlabs/Module/Settings/Display.php:215 +msgid "Show emoticons (smilies) as images" msgstr "" -#: ../../Zotlabs/Module/Directory.php:337 -msgid "Common connections:" +#: ../../Zotlabs/Module/Settings/Display.php:216 +msgid "Manual conversation updates" msgstr "" -#: ../../Zotlabs/Module/Directory.php:386 -msgid "Global Directory" +#: ../../Zotlabs/Module/Settings/Display.php:216 +msgid "Default is on, turning this off may increase screen jumping" msgstr "" -#: ../../Zotlabs/Module/Directory.php:386 -msgid "Local Directory" +#: ../../Zotlabs/Module/Settings/Display.php:217 +msgid "Link post titles to source" msgstr "" -#: ../../Zotlabs/Module/Directory.php:392 -msgid "Finding:" +#: ../../Zotlabs/Module/Settings/Display.php:218 +msgid "System Page Layout Editor - (advanced)" msgstr "" -#: ../../Zotlabs/Module/Directory.php:395 ../../Zotlabs/Module/Suggest.php:62 -#: ../../include/contact_widgets.php:24 -msgid "Channel Suggestions" +#: ../../Zotlabs/Module/Settings/Display.php:221 +msgid "Use blog/list mode on channel page" msgstr "" -#: ../../Zotlabs/Module/Directory.php:397 -msgid "next page" +#: ../../Zotlabs/Module/Settings/Display.php:221 +#: ../../Zotlabs/Module/Settings/Display.php:222 +msgid "(comments displayed separately)" msgstr "" -#: ../../Zotlabs/Module/Directory.php:397 -msgid "previous page" +#: ../../Zotlabs/Module/Settings/Display.php:222 +msgid "Use blog/list mode on grid page" msgstr "" -#: ../../Zotlabs/Module/Directory.php:398 -msgid "Sort options" +#: ../../Zotlabs/Module/Settings/Display.php:223 +msgid "Channel page max height of content (in pixels)" msgstr "" -#: ../../Zotlabs/Module/Directory.php:399 -msgid "Alphabetic" +#: ../../Zotlabs/Module/Settings/Display.php:223 +#: ../../Zotlabs/Module/Settings/Display.php:224 +msgid "click to expand content exceeding this height" msgstr "" -#: ../../Zotlabs/Module/Directory.php:400 -msgid "Reverse Alphabetic" +#: ../../Zotlabs/Module/Settings/Display.php:224 +msgid "Grid page max height of content (in pixels)" msgstr "" -#: ../../Zotlabs/Module/Directory.php:401 -msgid "Newest to Oldest" +#: ../../Zotlabs/Module/Settings/Featured.php:20 +msgid "Affinity Slider settings updated." msgstr "" -#: ../../Zotlabs/Module/Directory.php:402 -msgid "Oldest to Newest" +#: ../../Zotlabs/Module/Settings/Featured.php:34 +msgid "No feature settings configured" msgstr "" -#: ../../Zotlabs/Module/Directory.php:419 -msgid "No entries (some entries may be hidden)." +#: ../../Zotlabs/Module/Settings/Featured.php:41 +msgid "Default maximum affinity level" msgstr "" -#: ../../Zotlabs/Module/Xchan.php:10 -msgid "Xchan Lookup" +#: ../../Zotlabs/Module/Settings/Featured.php:46 +msgid "Default minimum affinity level" msgstr "" -#: ../../Zotlabs/Module/Xchan.php:13 -msgid "Lookup xchan beginning with (or webbie): " +#: ../../Zotlabs/Module/Settings/Featured.php:50 +msgid "Affinity Slider Settings" msgstr "" -#: ../../Zotlabs/Module/Suggest.php:37 +#: ../../Zotlabs/Module/Settings/Featured.php:60 +msgid "Feature/Addon Settings" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Tokens.php:31 +#, php-format +msgid "This channel is limited to %d tokens" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Tokens.php:37 +msgid "Name and Password are required." +msgstr "" + +#: ../../Zotlabs/Module/Settings/Tokens.php:77 +msgid "Token saved." +msgstr "" + +#: ../../Zotlabs/Module/Settings/Tokens.php:113 msgid "" -"No suggestions available. If this is a new site, please try again in 24 " -"hours." +"Use this form to create temporary access identifiers to share things with " +"non-members. These identities may be used in Access Control Lists and " +"visitors may login using these credentials to access private content." msgstr "" -#: ../../Zotlabs/Module/Suggest.php:56 ../../Zotlabs/Widget/Suggestions.php:46 -msgid "Ignore/Hide" +#: ../../Zotlabs/Module/Settings/Tokens.php:115 +msgid "" +"You may also provide <em>dropbox</em> style access links to friends and " +"associates by adding the Login Password to any specific site URL as shown. " +"Examples:" msgstr "" -#: ../../Zotlabs/Module/Oexchange.php:27 -msgid "Unable to find your hub." +#: ../../Zotlabs/Module/Settings/Tokens.php:150 +#: ../../Zotlabs/Widget/Settings_menu.php:90 +msgid "Guest Access Tokens" msgstr "" -#: ../../Zotlabs/Module/Oexchange.php:41 -msgid "Post successful." +#: ../../Zotlabs/Module/Settings/Tokens.php:157 +msgid "Login Name" msgstr "" -#: ../../Zotlabs/Module/Mail.php:73 -msgid "Unable to lookup recipient." +#: ../../Zotlabs/Module/Settings/Tokens.php:158 +msgid "Login Password" msgstr "" -#: ../../Zotlabs/Module/Mail.php:80 -msgid "Unable to communicate with requested channel." +<<<<<<< HEAD +#: ../../Zotlabs/Module/Settings/Tokens.php:159 +msgid "Expires (yyyy-mm-dd)" msgstr "" -#: ../../Zotlabs/Module/Mail.php:87 -msgid "Cannot verify requested channel." +#: ../../Zotlabs/Module/Settings/Channel.php:251 +#: ../../extend/addon/addon/logrot/logrot.php:54 +#: ../../extend/addon/addon/msgfooter/msgfooter.php:54 +#: ../../extend/addon/addon/openstreetmap/openstreetmap.php:184 +#: ../../extend/addon/addon/piwik/piwik.php:116 +#: ../../extend/addon/addon/twitter/twitter.php:766 +#: ../../extend/addon/addon/xmpp/xmpp.php:102 +#: ../../extend/addon/addon/rendezvous/rendezvous.php:82 +msgid "Settings updated." msgstr "" -#: ../../Zotlabs/Module/Mail.php:105 -msgid "Selected channel has private message restrictions. Send failed." +#: ../../Zotlabs/Module/Settings/Channel.php:312 +msgid "Nobody except yourself" msgstr "" -#: ../../Zotlabs/Module/Mail.php:160 -msgid "Messages" +#: ../../Zotlabs/Module/Settings/Channel.php:313 +msgid "Only those you specifically allow" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:314 +msgid "Approved connections" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:315 +msgid "Any connections" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:316 +msgid "Anybody on this website" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:317 +msgid "Anybody in this network" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:318 +msgid "Anybody authenticated" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:319 +msgid "Anybody on the internet" msgstr "" -#: ../../Zotlabs/Module/Mail.php:173 +#: ../../Zotlabs/Module/Settings/Channel.php:395 +msgid "Publish your default profile in the network directory" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:400 +msgid "Allow us to suggest you as a potential friend to new members?" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:409 +msgid "Your channel address is" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:412 +msgid "Your files/photos are accessible via WebDAV at" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:474 +msgid "Channel Settings" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:481 +msgid "Basic Settings" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:482 +#: ../../include/channel.php:1229 +msgid "Full Name:" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:484 +msgid "Your Timezone:" +======= +#: ../../Zotlabs/Module/Mail.php:191 msgid "message" msgstr "" -#: ../../Zotlabs/Module/Mail.php:214 +#: ../../Zotlabs/Module/Mail.php:232 msgid "Message recalled." msgstr "" -#: ../../Zotlabs/Module/Mail.php:227 +#: ../../Zotlabs/Module/Mail.php:245 msgid "Conversation removed." msgstr "" -#: ../../Zotlabs/Module/Mail.php:242 ../../Zotlabs/Module/Mail.php:363 +#: ../../Zotlabs/Module/Mail.php:260 ../../Zotlabs/Module/Mail.php:381 msgid "Expires YYYY-MM-DD HH:MM" msgstr "" -#: ../../Zotlabs/Module/Mail.php:270 +#: ../../Zotlabs/Module/Mail.php:288 msgid "Requested channel is not in this network" msgstr "" -#: ../../Zotlabs/Module/Mail.php:278 +#: ../../Zotlabs/Module/Mail.php:296 msgid "Send Private Message" msgstr "" -#: ../../Zotlabs/Module/Mail.php:279 ../../Zotlabs/Module/Mail.php:421 +#: ../../Zotlabs/Module/Mail.php:297 ../../Zotlabs/Module/Mail.php:439 msgid "To:" msgstr "" -#: ../../Zotlabs/Module/Mail.php:282 ../../Zotlabs/Module/Mail.php:423 +#: ../../Zotlabs/Module/Mail.php:300 ../../Zotlabs/Module/Mail.php:441 msgid "Subject:" msgstr "" -#: ../../Zotlabs/Module/Mail.php:287 ../../Zotlabs/Module/Mail.php:429 -#: ../../include/conversation.php:1321 +#: ../../Zotlabs/Module/Mail.php:305 ../../Zotlabs/Module/Mail.php:447 +#: ../../include/conversation.php:1323 msgid "Attach file" msgstr "" -#: ../../Zotlabs/Module/Mail.php:289 +#: ../../Zotlabs/Module/Mail.php:307 msgid "Send" msgstr "" -#: ../../Zotlabs/Module/Mail.php:292 ../../Zotlabs/Module/Mail.php:434 -#: ../../include/conversation.php:1366 +#: ../../Zotlabs/Module/Mail.php:310 ../../Zotlabs/Module/Mail.php:452 +#: ../../include/conversation.php:1368 msgid "Set expiration date" msgstr "" -#: ../../Zotlabs/Module/Mail.php:393 +#: ../../Zotlabs/Module/Mail.php:411 msgid "Delete message" msgstr "" -#: ../../Zotlabs/Module/Mail.php:394 +#: ../../Zotlabs/Module/Mail.php:412 msgid "Delivery report" msgstr "" -#: ../../Zotlabs/Module/Mail.php:395 +#: ../../Zotlabs/Module/Mail.php:413 msgid "Recall message" msgstr "" -#: ../../Zotlabs/Module/Mail.php:397 +#: ../../Zotlabs/Module/Mail.php:415 msgid "Message has been recalled." msgstr "" -#: ../../Zotlabs/Module/Mail.php:414 +#: ../../Zotlabs/Module/Mail.php:432 msgid "Delete Conversation" msgstr "" -#: ../../Zotlabs/Module/Mail.php:416 +#: ../../Zotlabs/Module/Mail.php:434 msgid "" "No secure communications available. You <strong>may</strong> be able to " "respond from the sender's profile page." msgstr "" -#: ../../Zotlabs/Module/Mail.php:420 +#: ../../Zotlabs/Module/Mail.php:438 msgid "Send Reply" msgstr "" -#: ../../Zotlabs/Module/Mail.php:425 +#: ../../Zotlabs/Module/Mail.php:443 #, php-format msgid "Your message for %s (%s):" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Pubsites.php:24 ../../Zotlabs/Widget/Pubsites.php:12 -msgid "Public Hubs" +#: ../../Zotlabs/Module/Settings/Channel.php:485 +msgid "Default Post Location:" msgstr "" -#: ../../Zotlabs/Module/Pubsites.php:27 -msgid "" -"The listed hubs allow public registration for the $Projectname network. All " -"hubs in the network are interlinked so membership on any of them conveys " -"membership in the network as a whole. Some hubs may require subscription or " -"provide tiered service plans. The hub itself <strong>may</strong> provide " -"additional details." +#: ../../Zotlabs/Module/Settings/Channel.php:485 +msgid "Geographical location to display on your posts" msgstr "" -#: ../../Zotlabs/Module/Pubsites.php:33 -msgid "Hub URL" +#: ../../Zotlabs/Module/Settings/Channel.php:486 +msgid "Use Browser Location:" msgstr "" -#: ../../Zotlabs/Module/Pubsites.php:33 -msgid "Access Type" +#: ../../Zotlabs/Module/Settings/Channel.php:488 +msgid "Adult Content" msgstr "" -#: ../../Zotlabs/Module/Pubsites.php:33 -msgid "Registration Policy" +#: ../../Zotlabs/Module/Settings/Channel.php:488 +msgid "" +"This channel frequently or regularly publishes adult content. (Please tag " +"any adult material and/or nudity with #NSFW)" msgstr "" -#: ../../Zotlabs/Module/Pubsites.php:33 -msgid "Stats" +#: ../../Zotlabs/Module/Settings/Channel.php:490 +msgid "Security and Privacy Settings" msgstr "" -#: ../../Zotlabs/Module/Pubsites.php:33 -msgid "Software" +#: ../../Zotlabs/Module/Settings/Channel.php:493 +msgid "Your permissions are already configured. Click to view/adjust" msgstr "" -#: ../../Zotlabs/Module/Pubsites.php:48 -msgid "Rate" +#: ../../Zotlabs/Module/Settings/Channel.php:495 +msgid "Hide my online presence" msgstr "" -#: ../../Zotlabs/Module/Impel.php:41 ../../include/bbcode.php:263 -msgid "webpage" +#: ../../Zotlabs/Module/Settings/Channel.php:495 +msgid "Prevents displaying in your profile that you are online" msgstr "" -#: ../../Zotlabs/Module/Impel.php:46 ../../include/bbcode.php:269 -msgid "block" +#: ../../Zotlabs/Module/Settings/Channel.php:497 +msgid "Simple Privacy Settings:" msgstr "" -#: ../../Zotlabs/Module/Impel.php:51 ../../include/bbcode.php:266 -msgid "layout" +#: ../../Zotlabs/Module/Settings/Channel.php:498 +msgid "" +"Very Public - <em>extremely permissive (should be used with caution)</em>" msgstr "" -#: ../../Zotlabs/Module/Impel.php:58 ../../include/bbcode.php:272 -msgid "menu" +#: ../../Zotlabs/Module/Settings/Channel.php:499 +msgid "" +"Typical - <em>default public, privacy when desired (similar to social " +"network permissions but with improved privacy)</em>" msgstr "" -#: ../../Zotlabs/Module/Impel.php:181 -#, php-format -msgid "%s element installed" +#: ../../Zotlabs/Module/Settings/Channel.php:500 +msgid "Private - <em>default private, never open or public</em>" msgstr "" -#: ../../Zotlabs/Module/Impel.php:184 -#, php-format -msgid "%s element installation failed" +#: ../../Zotlabs/Module/Settings/Channel.php:501 +msgid "Blocked - <em>default blocked to/from everybody</em>" msgstr "" -#: ../../Zotlabs/Module/Rbmark.php:94 -msgid "Select a bookmark folder" +#: ../../Zotlabs/Module/Settings/Channel.php:503 +msgid "Allow others to tag your posts" msgstr "" -#: ../../Zotlabs/Module/Rbmark.php:99 -msgid "Save Bookmark" +#: ../../Zotlabs/Module/Settings/Channel.php:503 +msgid "" +"Often used by the community to retro-actively flag inappropriate content" msgstr "" -#: ../../Zotlabs/Module/Rbmark.php:100 -msgid "URL of bookmark" +#: ../../Zotlabs/Module/Settings/Channel.php:505 +msgid "Channel Permission Limits" msgstr "" -#: ../../Zotlabs/Module/Rbmark.php:105 -msgid "Or enter new bookmark folder name" +#: ../../Zotlabs/Module/Settings/Channel.php:507 +msgid "Expire other channel content after this many days" msgstr "" -#: ../../Zotlabs/Module/Filer.php:52 -msgid "Enter a folder name" +#: ../../Zotlabs/Module/Settings/Channel.php:507 +msgid "0 or blank to use the website limit." msgstr "" -#: ../../Zotlabs/Module/Filer.php:52 -msgid "or select an existing folder (doubleclick)" +#: ../../Zotlabs/Module/Settings/Channel.php:507 +#, php-format +msgid "This website expires after %d days." msgstr "" -#: ../../Zotlabs/Module/Filer.php:54 ../../Zotlabs/Lib/ThreadItem.php:137 -msgid "Save to Folder" +#: ../../Zotlabs/Module/Settings/Channel.php:507 +msgid "This website does not expire imported content." msgstr "" -#: ../../Zotlabs/Module/Probe.php:28 ../../Zotlabs/Module/Probe.php:32 -#, php-format -msgid "Fetching URL returns error: %1$s" +#: ../../Zotlabs/Module/Settings/Channel.php:507 +msgid "The website limit takes precedence if lower than your limit." msgstr "" -#: ../../Zotlabs/Module/Register.php:49 -msgid "Maximum daily site registrations exceeded. Please try again tomorrow." +#: ../../Zotlabs/Module/Settings/Channel.php:508 +msgid "Maximum Friend Requests/Day:" msgstr "" -#: ../../Zotlabs/Module/Register.php:55 -msgid "" -"Please indicate acceptance of the Terms of Service. Registration failed." +#: ../../Zotlabs/Module/Settings/Channel.php:508 +msgid "May reduce spam activity" msgstr "" -#: ../../Zotlabs/Module/Register.php:89 -msgid "Passwords do not match." +#: ../../Zotlabs/Module/Settings/Channel.php:509 +msgid "Default Access Control List (ACL)" msgstr "" -#: ../../Zotlabs/Module/Register.php:131 -msgid "" -"Registration successful. Please check your email for validation instructions." +#: ../../Zotlabs/Module/Settings/Channel.php:511 +msgid "Use my default audience setting for the type of object published" msgstr "" -#: ../../Zotlabs/Module/Register.php:137 -msgid "Your registration is pending approval by the site owner." +#: ../../Zotlabs/Module/Settings/Channel.php:518 +msgid "Channel permissions category:" msgstr "" -#: ../../Zotlabs/Module/Register.php:140 -msgid "Your registration can not be processed." +#: ../../Zotlabs/Module/Settings/Channel.php:519 +msgid "Default Permissions Group" msgstr "" -#: ../../Zotlabs/Module/Register.php:184 -msgid "Registration on this hub is disabled." +#: ../../Zotlabs/Module/Settings/Channel.php:525 +msgid "Maximum private messages per day from unknown people:" msgstr "" -#: ../../Zotlabs/Module/Register.php:193 -msgid "Registration on this hub is by approval only." +#: ../../Zotlabs/Module/Settings/Channel.php:525 +msgid "Useful to reduce spamming" msgstr "" -#: ../../Zotlabs/Module/Register.php:194 -msgid "<a href=\"pubsites\">Register at another affiliated hub.</a>" +#: ../../Zotlabs/Module/Settings/Channel.php:528 +msgid "Notification Settings" msgstr "" -#: ../../Zotlabs/Module/Register.php:204 -msgid "" -"This site has exceeded the number of allowed daily account registrations. " -"Please try again tomorrow." +#: ../../Zotlabs/Module/Settings/Channel.php:529 +msgid "By default post a status message when:" msgstr "" -#: ../../Zotlabs/Module/Register.php:227 -#, php-format -msgid "I accept the %s for this website" +#: ../../Zotlabs/Module/Settings/Channel.php:530 +msgid "accepting a friend request" msgstr "" -#: ../../Zotlabs/Module/Register.php:229 -#, php-format -msgid "I am over 13 years of age and accept the %s for this website" +#: ../../Zotlabs/Module/Settings/Channel.php:531 +msgid "joining a forum/community" msgstr "" -#: ../../Zotlabs/Module/Register.php:233 -msgid "Your email address" +#: ../../Zotlabs/Module/Settings/Channel.php:532 +msgid "making an <em>interesting</em> profile change" msgstr "" -#: ../../Zotlabs/Module/Register.php:234 -msgid "Choose a password" +#: ../../Zotlabs/Module/Settings/Channel.php:533 +msgid "Send a notification email when:" msgstr "" -#: ../../Zotlabs/Module/Register.php:235 -msgid "Please re-enter your password" +#: ../../Zotlabs/Module/Settings/Channel.php:534 +msgid "You receive a connection request" msgstr "" -#: ../../Zotlabs/Module/Register.php:236 -msgid "Please enter your invitation code" +#: ../../Zotlabs/Module/Settings/Channel.php:535 +msgid "Your connections are confirmed" msgstr "" -#: ../../Zotlabs/Module/Register.php:241 -msgid "no" +#: ../../Zotlabs/Module/Settings/Channel.php:536 +msgid "Someone writes on your profile wall" msgstr "" -#: ../../Zotlabs/Module/Register.php:241 -msgid "yes" +#: ../../Zotlabs/Module/Settings/Channel.php:537 +msgid "Someone writes a followup comment" msgstr "" -#: ../../Zotlabs/Module/Register.php:258 -msgid "Membership on this site is by invitation only." +#: ../../Zotlabs/Module/Settings/Channel.php:538 +msgid "You receive a private message" msgstr "" -#: ../../Zotlabs/Module/Register.php:270 ../../boot.php:1612 +<<<<<<< HEAD +#: ../../Zotlabs/Module/Settings/Channel.php:539 +msgid "You receive a friend suggestion" +======= +#: ../../Zotlabs/Module/Register.php:270 ../../boot.php:1610 #: ../../include/nav.php:149 msgid "Register" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Register.php:271 -msgid "" -"This site may require email verification after submitting this form. If you " -"are returned to a login page, please check your email for instructions." +#: ../../Zotlabs/Module/Settings/Channel.php:540 +msgid "You are tagged in a post" msgstr "" -#: ../../Zotlabs/Module/Cover_photo.php:136 -#: ../../Zotlabs/Module/Cover_photo.php:186 -msgid "Cover Photos" +#: ../../Zotlabs/Module/Settings/Channel.php:541 +msgid "You are poked/prodded/etc. in a post" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Settings/Channel.php:543 +msgid "Someone likes your post/comment" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:546 +msgid "Show visual notifications including:" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:548 +msgid "Unseen grid activity" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:549 +msgid "Unseen channel activity" +msgstr "" + +#: ../../Zotlabs/Module/Settings/Channel.php:550 +msgid "Unseen private messages" msgstr "" -#: ../../Zotlabs/Module/Cover_photo.php:237 ../../include/items.php:4328 +#: ../../Zotlabs/Module/Settings/Channel.php:550 +#: ../../Zotlabs/Module/Settings/Channel.php:555 +#: ../../Zotlabs/Module/Settings/Channel.php:556 +#: ../../Zotlabs/Module/Settings/Channel.php:557 +#: ../../extend/addon/addon/jappixmini/jappixmini.php:343 +msgid "Recommended" +======= +#: ../../Zotlabs/Module/Cover_photo.php:237 ../../include/items.php:4303 msgid "female" msgstr "" -#: ../../Zotlabs/Module/Cover_photo.php:238 ../../include/items.php:4329 +#: ../../Zotlabs/Module/Cover_photo.php:238 ../../include/items.php:4304 #, php-format msgid "%1$s updated her %2$s" msgstr "" -#: ../../Zotlabs/Module/Cover_photo.php:239 ../../include/items.php:4330 +#: ../../Zotlabs/Module/Cover_photo.php:239 ../../include/items.php:4305 msgid "male" msgstr "" -#: ../../Zotlabs/Module/Cover_photo.php:240 ../../include/items.php:4331 +#: ../../Zotlabs/Module/Cover_photo.php:240 ../../include/items.php:4306 #, php-format msgid "%1$s updated his %2$s" msgstr "" -#: ../../Zotlabs/Module/Cover_photo.php:242 ../../include/items.php:4333 +#: ../../Zotlabs/Module/Cover_photo.php:242 ../../include/items.php:4308 #, php-format msgid "%1$s updated their %2$s" msgstr "" -#: ../../Zotlabs/Module/Cover_photo.php:244 ../../include/channel.php:1769 +#: ../../Zotlabs/Module/Cover_photo.php:244 ../../include/channel.php:1759 msgid "cover photo" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Cover_photo.php:360 -msgid "Upload Cover Photo" +#: ../../Zotlabs/Module/Settings/Channel.php:551 +msgid "Upcoming events" msgstr "" -#: ../../Zotlabs/Module/Help.php:23 -msgid "Documentation Search" +#: ../../Zotlabs/Module/Settings/Channel.php:552 +msgid "Events today" msgstr "" -#: ../../Zotlabs/Module/Help.php:80 ../../include/conversation.php:1771 -#: ../../include/nav.php:375 +<<<<<<< HEAD +#: ../../Zotlabs/Module/Settings/Channel.php:553 +msgid "Upcoming birthdays" +======= +#: ../../Zotlabs/Module/Help.php:80 ../../include/conversation.php:1773 +#: ../../include/nav.php:382 msgid "About" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Help.php:82 -msgid "Administrators" +#: ../../Zotlabs/Module/Settings/Channel.php:553 +msgid "Not available in all themes" msgstr "" -#: ../../Zotlabs/Module/Help.php:83 -msgid "Developers" +#: ../../Zotlabs/Module/Settings/Channel.php:554 +msgid "System (personal) notifications" msgstr "" -#: ../../Zotlabs/Module/Help.php:84 -msgid "Tutorials" +#: ../../Zotlabs/Module/Settings/Channel.php:555 +msgid "System info messages" msgstr "" -#: ../../Zotlabs/Module/Help.php:93 -msgid "$Projectname Documentation" +#: ../../Zotlabs/Module/Settings/Channel.php:556 +msgid "System critical alerts" msgstr "" -#: ../../Zotlabs/Module/Help.php:94 -msgid "Contents" +#: ../../Zotlabs/Module/Settings/Channel.php:557 +msgid "New connections" msgstr "" -#: ../../Zotlabs/Module/Tagrm.php:48 ../../Zotlabs/Module/Tagrm.php:98 -msgid "Tag removed" +#: ../../Zotlabs/Module/Settings/Channel.php:558 +msgid "System Registrations" msgstr "" -#: ../../Zotlabs/Module/Tagrm.php:123 -msgid "Remove Item Tag" +#: ../../Zotlabs/Module/Settings/Channel.php:559 +msgid "" +"Also show new wall posts, private messages and connections under Notices" msgstr "" -#: ../../Zotlabs/Module/Tagrm.php:125 -msgid "Select a tag to remove: " +#: ../../Zotlabs/Module/Settings/Channel.php:561 +msgid "Notify me of events this many days in advance" msgstr "" -#: ../../Zotlabs/Module/Network.php:96 -msgid "No such group" +#: ../../Zotlabs/Module/Settings/Channel.php:561 +msgid "Must be greater than 0" msgstr "" -#: ../../Zotlabs/Module/Network.php:136 -msgid "No such channel" +#: ../../Zotlabs/Module/Settings/Channel.php:567 +msgid "Advanced Account/Page Type Settings" msgstr "" -#: ../../Zotlabs/Module/Network.php:141 -msgid "forum" +#: ../../Zotlabs/Module/Settings/Channel.php:568 +msgid "Change the behaviour of this account for special situations" msgstr "" -#: ../../Zotlabs/Module/Network.php:153 -msgid "Search Results For:" +#: ../../Zotlabs/Module/Settings/Channel.php:570 +msgid "Miscellaneous Settings" msgstr "" -#: ../../Zotlabs/Module/Network.php:221 -msgid "Privacy group is empty" +#: ../../Zotlabs/Module/Settings/Channel.php:571 +msgid "Default photo upload folder" msgstr "" -#: ../../Zotlabs/Module/Network.php:230 -msgid "Privacy group: " +#: ../../Zotlabs/Module/Settings/Channel.php:571 +#: ../../Zotlabs/Module/Settings/Channel.php:572 +msgid "%Y - current year, %m - current month" msgstr "" -#: ../../Zotlabs/Module/Network.php:256 -msgid "Invalid connection." +#: ../../Zotlabs/Module/Settings/Channel.php:572 +msgid "Default file upload folder" msgstr "" -#: ../../Zotlabs/Module/Network.php:275 ../../addon/redred/redred.php:65 -msgid "Invalid channel." +#: ../../Zotlabs/Module/Settings/Channel.php:574 +msgid "Personal menu to display in your channel pages" msgstr "" -#: ../../Zotlabs/Module/Acl.php:344 -msgid "network" +#: ../../Zotlabs/Module/Settings/Channel.php:576 +msgid "Remove this channel." msgstr "" -#: ../../Zotlabs/Module/Acl.php:354 -msgid "RSS" +#: ../../Zotlabs/Module/Settings/Channel.php:577 +msgid "Firefox Share $Projectname provider" msgstr "" -#: ../../Zotlabs/Module/Home.php:74 ../../Zotlabs/Module/Home.php:82 -#: ../../addon/opensearch/opensearch.php:42 -msgid "$Projectname" +#: ../../Zotlabs/Module/Settings/Channel.php:578 +msgid "Start calendar week on Monday" msgstr "" -#: ../../Zotlabs/Module/Home.php:92 -#, php-format -msgid "Welcome to %s" +#: ../../Zotlabs/Module/Settings/Permcats.php:37 +msgid "Permission category saved." msgstr "" -#: ../../Zotlabs/Module/Filestorage.php:87 -msgid "Permission Denied." +#: ../../Zotlabs/Module/Settings/Permcats.php:61 +msgid "" +"Use this form to create permission rules for various classes of people or " +"connections." msgstr "" -#: ../../Zotlabs/Module/Filestorage.php:103 -msgid "File not found." +#: ../../Zotlabs/Module/Settings/Permcats.php:94 +msgid "Permission Categories" msgstr "" -#: ../../Zotlabs/Module/Filestorage.php:146 -msgid "Edit file permissions" +#: ../../Zotlabs/Module/Settings/Permcats.php:102 +msgid "Permission Name" msgstr "" -#: ../../Zotlabs/Module/Filestorage.php:159 -msgid "Set/edit permissions" +#: ../../Zotlabs/Module/Tagrm.php:48 ../../Zotlabs/Module/Tagrm.php:98 +msgid "Tag removed" msgstr "" -#: ../../Zotlabs/Module/Filestorage.php:160 -msgid "Include all files and sub folders" +#: ../../Zotlabs/Module/Tagrm.php:123 +msgid "Remove Item Tag" msgstr "" -#: ../../Zotlabs/Module/Filestorage.php:161 -msgid "Return to file list" +#: ../../Zotlabs/Module/Tagrm.php:125 +msgid "Select a tag to remove: " msgstr "" -#: ../../Zotlabs/Module/Filestorage.php:163 -msgid "Copy/paste this code to attach file to a post" +#: ../../Zotlabs/Module/Thing.php:114 +msgid "Thing updated" msgstr "" -#: ../../Zotlabs/Module/Filestorage.php:164 -msgid "Copy/paste this URL to link file from a web page" +#: ../../Zotlabs/Module/Thing.php:166 +msgid "Object store: failed" msgstr "" -#: ../../Zotlabs/Module/Filestorage.php:166 -msgid "Share this file" +#: ../../Zotlabs/Module/Thing.php:170 +msgid "Thing added" msgstr "" -#: ../../Zotlabs/Module/Filestorage.php:167 -msgid "Show URL to this file" +#: ../../Zotlabs/Module/Thing.php:196 +#, php-format +msgid "OBJ: %1$s %2$s %3$s" msgstr "" -#: ../../Zotlabs/Module/Filestorage.php:168 -msgid "Notify your contacts about this file" +#: ../../Zotlabs/Module/Thing.php:259 +msgid "Show Thing" msgstr "" -#: ../../Zotlabs/Module/Common.php:14 -msgid "No channel." +#: ../../Zotlabs/Module/Thing.php:266 +msgid "item not found." msgstr "" -#: ../../Zotlabs/Module/Common.php:43 -msgid "Common connections" +#: ../../Zotlabs/Module/Thing.php:299 +msgid "Edit Thing" msgstr "" -#: ../../Zotlabs/Module/Common.php:48 -msgid "No connections in common." +#: ../../Zotlabs/Module/Thing.php:301 ../../Zotlabs/Module/Thing.php:355 +msgid "Select a profile" msgstr "" -#: ../../Zotlabs/Module/Viewconnections.php:65 -msgid "No connections." +#: ../../Zotlabs/Module/Thing.php:305 ../../Zotlabs/Module/Thing.php:358 +msgid "Post an activity" msgstr "" -#: ../../Zotlabs/Module/Viewconnections.php:78 -#, php-format -msgid "Visit %s's profile [%s]" +#: ../../Zotlabs/Module/Thing.php:305 ../../Zotlabs/Module/Thing.php:358 +msgid "Only sends to viewers of the applicable profile" msgstr "" -#: ../../Zotlabs/Module/Viewconnections.php:107 -msgid "View Connections" +#: ../../Zotlabs/Module/Thing.php:307 ../../Zotlabs/Module/Thing.php:360 +msgid "Name of thing e.g. something" msgstr "" -#: ../../Zotlabs/Module/Admin.php:94 -msgid "# Accounts" +#: ../../Zotlabs/Module/Thing.php:309 ../../Zotlabs/Module/Thing.php:361 +msgid "URL of thing (optional)" msgstr "" -#: ../../Zotlabs/Module/Admin.php:95 -msgid "# blocked accounts" +#: ../../Zotlabs/Module/Thing.php:311 ../../Zotlabs/Module/Thing.php:362 +msgid "URL for photo of thing (optional)" msgstr "" -#: ../../Zotlabs/Module/Admin.php:96 -msgid "# expired accounts" +#: ../../Zotlabs/Module/Thing.php:353 +msgid "Add Thing to your Profile" msgstr "" -#: ../../Zotlabs/Module/Admin.php:97 -msgid "# expiring accounts" +#: ../../Zotlabs/Module/Tagger.php:55 ../../include/bbcode.php:274 +msgid "post" msgstr "" -#: ../../Zotlabs/Module/Admin.php:108 -msgid "# Channels" +#: ../../Zotlabs/Module/Tagger.php:57 ../../include/text.php:1951 +#: ../../include/conversation.php:146 +msgid "comment" msgstr "" -#: ../../Zotlabs/Module/Admin.php:109 -msgid "# primary" +#: ../../Zotlabs/Module/Tagger.php:95 +#, php-format +msgid "%1$s tagged %2$s's %3$s with %4$s" msgstr "" -#: ../../Zotlabs/Module/Admin.php:110 -msgid "# clones" +#: ../../Zotlabs/Module/Viewconnections.php:65 +msgid "No connections." msgstr "" -#: ../../Zotlabs/Module/Admin.php:116 -msgid "Message queues" +#: ../../Zotlabs/Module/Viewconnections.php:78 +#, php-format +msgid "Visit %s's profile [%s]" msgstr "" -#: ../../Zotlabs/Module/Admin.php:133 -msgid "Your software should be updated" +#: ../../Zotlabs/Module/Viewconnections.php:107 +msgid "View Connections" msgstr "" -#: ../../Zotlabs/Module/Admin.php:138 -msgid "Summary" +#: ../../Zotlabs/Module/Photos.php:78 +msgid "Page owner information could not be retrieved." msgstr "" -#: ../../Zotlabs/Module/Admin.php:141 -msgid "Registered accounts" +#: ../../Zotlabs/Module/Photos.php:94 ../../Zotlabs/Module/Photos.php:120 +msgid "Album not found." msgstr "" -#: ../../Zotlabs/Module/Admin.php:142 -msgid "Pending registrations" +#: ../../Zotlabs/Module/Photos.php:103 +msgid "Delete Album" msgstr "" -#: ../../Zotlabs/Module/Admin.php:143 -msgid "Registered channels" +#: ../../Zotlabs/Module/Photos.php:174 ../../Zotlabs/Module/Photos.php:1023 +msgid "Delete Photo" msgstr "" -#: ../../Zotlabs/Module/Admin.php:144 -msgid "Active plugins" +#: ../../Zotlabs/Module/Photos.php:501 +msgid "No photos selected" msgstr "" -#: ../../Zotlabs/Module/Admin.php:145 -msgid "Version" +#: ../../Zotlabs/Module/Photos.php:550 +msgid "Access to this item is restricted." msgstr "" -#: ../../Zotlabs/Module/Admin.php:146 -msgid "Repository version (master)" +#: ../../Zotlabs/Module/Photos.php:591 +#, php-format +msgid "%1$.2f MB of %2$.2f MB photo storage used." msgstr "" -#: ../../Zotlabs/Module/Admin.php:147 -msgid "Repository version (dev)" +#: ../../Zotlabs/Module/Photos.php:594 +#, php-format +msgid "%1$.2f MB photo storage used." msgstr "" -#: ../../Zotlabs/Module/Service_limits.php:23 -msgid "No service class restrictions found." +#: ../../Zotlabs/Module/Photos.php:636 +msgid "Upload Photos" msgstr "" -#: ../../Zotlabs/Module/Rate.php:156 -msgid "Website:" +#: ../../Zotlabs/Module/Photos.php:640 +msgid "Enter an album name" msgstr "" -#: ../../Zotlabs/Module/Rate.php:159 -#, php-format -msgid "Remote Channel [%s] (not yet known on this site)" +#: ../../Zotlabs/Module/Photos.php:641 +msgid "or select an existing album (doubleclick)" msgstr "" -#: ../../Zotlabs/Module/Rate.php:160 -msgid "Rating (this information is public)" +#: ../../Zotlabs/Module/Photos.php:642 +msgid "Create a status post for this upload" msgstr "" -#: ../../Zotlabs/Module/Rate.php:161 -msgid "Optionally explain your rating (this information is public)" +#: ../../Zotlabs/Module/Photos.php:643 +msgid "Caption (optional):" msgstr "" -#: ../../Zotlabs/Module/Lostpass.php:19 -msgid "No valid account found." +#: ../../Zotlabs/Module/Photos.php:644 +msgid "Description (optional):" msgstr "" -#: ../../Zotlabs/Module/Lostpass.php:33 -msgid "Password reset request issued. Check your email." +#: ../../Zotlabs/Module/Photos.php:725 +msgid "Show Newest First" msgstr "" -#: ../../Zotlabs/Module/Lostpass.php:39 ../../Zotlabs/Module/Lostpass.php:108 -#, php-format -msgid "Site Member (%s)" +#: ../../Zotlabs/Module/Photos.php:727 +msgid "Show Oldest First" msgstr "" -#: ../../Zotlabs/Module/Lostpass.php:44 ../../Zotlabs/Module/Lostpass.php:49 -#, php-format -msgid "Password reset requested at %s" +#: ../../Zotlabs/Module/Photos.php:751 ../../Zotlabs/Module/Photos.php:1290 +#: ../../Zotlabs/Module/Embedphotos.php:139 ../../Zotlabs/Widget/Album.php:78 +msgid "View Photo" msgstr "" -#: ../../Zotlabs/Module/Lostpass.php:68 -msgid "" -"Request could not be verified. (You may have previously submitted it.) " -"Password reset failed." +#: ../../Zotlabs/Module/Photos.php:782 +#: ../../Zotlabs/Module/Embedphotos.php:155 ../../Zotlabs/Widget/Album.php:95 +msgid "Edit Album" msgstr "" -#: ../../Zotlabs/Module/Lostpass.php:91 ../../boot.php:1639 +<<<<<<< HEAD +#: ../../Zotlabs/Module/Photos.php:832 +msgid "Permission denied. Access to this item may be restricted." +======= +#: ../../Zotlabs/Module/Lostpass.php:91 ../../boot.php:1637 msgid "Password Reset" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Module/Lostpass.php:92 -msgid "Your password has been reset as requested." -msgstr "" - -#: ../../Zotlabs/Module/Lostpass.php:93 -msgid "Your new password is" -msgstr "" - -#: ../../Zotlabs/Module/Lostpass.php:94 -msgid "Save or copy your new password - and then" +#: ../../Zotlabs/Module/Photos.php:834 +msgid "Photo not available" msgstr "" -#: ../../Zotlabs/Module/Lostpass.php:95 -msgid "click here to login" +#: ../../Zotlabs/Module/Photos.php:892 +msgid "Use as profile photo" msgstr "" -#: ../../Zotlabs/Module/Lostpass.php:96 -msgid "" -"Your password may be changed from the <em>Settings</em> page after " -"successful login." +#: ../../Zotlabs/Module/Photos.php:893 +msgid "Use as cover photo" msgstr "" -#: ../../Zotlabs/Module/Lostpass.php:117 -#, php-format -msgid "Your password has changed at %s" +#: ../../Zotlabs/Module/Photos.php:900 +msgid "Private Photo" msgstr "" -#: ../../Zotlabs/Module/Lostpass.php:130 -msgid "Forgot your Password?" +#: ../../Zotlabs/Module/Photos.php:915 +msgid "View Full Size" msgstr "" -#: ../../Zotlabs/Module/Lostpass.php:131 -msgid "" -"Enter your email address and submit to have your password reset. Then check " -"your email for further instructions." +#: ../../Zotlabs/Module/Photos.php:997 +msgid "Edit photo" msgstr "" -#: ../../Zotlabs/Module/Lostpass.php:132 -msgid "Email Address" +#: ../../Zotlabs/Module/Photos.php:999 +msgid "Rotate CW (right)" msgstr "" -#: ../../Zotlabs/Module/Lostpass.php:133 -msgid "Reset" +#: ../../Zotlabs/Module/Photos.php:1000 +msgid "Rotate CCW (left)" msgstr "" -#: ../../Zotlabs/Module/Notifications.php:43 -#: ../../Zotlabs/Lib/ThreadItem.php:394 -msgid "Mark all seen" +#: ../../Zotlabs/Module/Photos.php:1003 +msgid "Move photo to album" msgstr "" -#: ../../Zotlabs/Lib/Techlevels.php:10 -msgid "0. Beginner/Basic" +#: ../../Zotlabs/Module/Photos.php:1004 +msgid "Enter a new album name" msgstr "" -#: ../../Zotlabs/Lib/Techlevels.php:11 -msgid "1. Novice - not skilled but willing to learn" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Photos.php:1005 +msgid "or select an existing one (doubleclick)" +======= +#: ../../Zotlabs/Module/Notifications.php:43 ../../include/nav.php:190 +msgid "Mark all system notifications seen" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Lib/Techlevels.php:12 -msgid "2. Intermediate - somewhat comfortable" +#: ../../Zotlabs/Module/Photos.php:1008 +msgid "Caption" msgstr "" -#: ../../Zotlabs/Lib/Techlevels.php:13 -msgid "3. Advanced - very comfortable" +#: ../../Zotlabs/Module/Photos.php:1010 +msgid "Add a Tag" msgstr "" -#: ../../Zotlabs/Lib/Techlevels.php:14 -msgid "4. Expert - I can write computer code" +#: ../../Zotlabs/Module/Photos.php:1018 +msgid "Example: @bob, @Barbara_Jensen, @jim@example.com" msgstr "" -#: ../../Zotlabs/Lib/Techlevels.php:15 -msgid "5. Wizard - I probably know more than you do" +#: ../../Zotlabs/Module/Photos.php:1021 +msgid "Flag as adult in album view" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:212 -msgid "Site Admin" +#: ../../Zotlabs/Module/Photos.php:1040 ../../Zotlabs/Lib/ThreadItem.php:269 +msgid "I like this (toggle)" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:213 ../../addon/buglink/buglink.php:16 -msgid "Report Bug" +#: ../../Zotlabs/Module/Photos.php:1041 ../../Zotlabs/Lib/ThreadItem.php:270 +msgid "I don't like this (toggle)" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:214 -msgid "View Bookmarks" +#: ../../Zotlabs/Module/Photos.php:1043 ../../Zotlabs/Lib/ThreadItem.php:412 +#: ../../include/conversation.php:739 +msgid "Please wait" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:215 -msgid "My Chatrooms" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Photos.php:1059 ../../Zotlabs/Module/Photos.php:1177 +#: ../../Zotlabs/Lib/ThreadItem.php:729 +msgid "This is you" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:217 -msgid "Firefox Share" +#: ../../Zotlabs/Module/Photos.php:1061 ../../Zotlabs/Module/Photos.php:1179 +#: ../../Zotlabs/Lib/ThreadItem.php:731 ../../include/js_strings.php:6 +msgid "Comment" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:218 -msgid "Remote Diagnostics" +#: ../../Zotlabs/Module/Photos.php:1077 ../../include/conversation.php:574 +msgctxt "title" +msgid "Likes" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:219 ../../include/features.php:337 -msgid "Suggest Channels" +#: ../../Zotlabs/Module/Photos.php:1077 ../../include/conversation.php:574 +msgctxt "title" +msgid "Dislikes" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:220 ../../boot.php:1631 ../../include/nav.php:117 +#: ../../Zotlabs/Module/Photos.php:1078 ../../include/conversation.php:575 +msgctxt "title" +msgid "Agree" +======= +#: ../../Zotlabs/Lib/Apps.php:220 ../../boot.php:1629 ../../include/nav.php:117 msgid "Login" msgstr "" @@ -7106,8 +8356,8 @@ msgstr "" msgid "Activity" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:226 ../../include/conversation.php:1855 -#: ../../include/features.php:99 ../../include/nav.php:458 +#: ../../Zotlabs/Lib/Apps.php:226 ../../include/conversation.php:1857 +#: ../../include/features.php:99 ../../include/nav.php:465 msgid "Wiki" msgstr "" @@ -7115,58 +8365,101 @@ msgstr "" msgid "Channel Home" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:230 ../../include/conversation.php:1800 -#: ../../include/conversation.php:1803 ../../include/nav.php:200 -#: ../../include/nav.php:404 ../../include/nav.php:407 +#: ../../Zotlabs/Lib/Apps.php:230 ../../include/conversation.php:1802 +#: ../../include/conversation.php:1805 ../../include/nav.php:200 +#: ../../include/nav.php:411 ../../include/nav.php:414 msgid "Events" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Lib/Apps.php:231 -msgid "Directory" +#: ../../Zotlabs/Module/Photos.php:1078 ../../include/conversation.php:575 +msgctxt "title" +msgid "Disagree" msgstr "" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Photos.php:1078 ../../include/conversation.php:575 +msgctxt "title" +msgid "Abstain" +======= #: ../../Zotlabs/Lib/Apps.php:233 ../../include/nav.php:192 msgid "Mail" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Lib/Apps.php:236 -msgid "Chat" +#: ../../Zotlabs/Module/Photos.php:1079 ../../include/conversation.php:576 +msgctxt "title" +msgid "Attending" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:238 -msgid "Probe" +#: ../../Zotlabs/Module/Photos.php:1079 ../../include/conversation.php:576 +msgctxt "title" +msgid "Not attending" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:239 -msgid "Suggest" +#: ../../Zotlabs/Module/Photos.php:1079 ../../include/conversation.php:576 +msgctxt "title" +msgid "Might attend" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:240 -msgid "Random Channel" +#: ../../Zotlabs/Module/Photos.php:1096 ../../Zotlabs/Module/Photos.php:1108 +#: ../../Zotlabs/Lib/ThreadItem.php:187 ../../Zotlabs/Lib/ThreadItem.php:199 +msgid "View all" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:241 -msgid "Invite" +#: ../../Zotlabs/Module/Photos.php:1100 ../../Zotlabs/Lib/ThreadItem.php:191 +#: ../../include/taxonomy.php:403 ../../include/channel.php:1247 +#: ../../include/conversation.php:1898 +msgctxt "noun" +msgid "Like" +msgid_plural "Likes" +msgstr[0] "" +msgstr[1] "" + +#: ../../Zotlabs/Module/Photos.php:1105 ../../Zotlabs/Lib/ThreadItem.php:196 +#: ../../include/conversation.php:1901 +msgctxt "noun" +msgid "Dislike" +msgid_plural "Dislikes" +msgstr[0] "" +msgstr[1] "" + +#: ../../Zotlabs/Module/Photos.php:1205 +msgid "Photo Tools" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:242 ../../Zotlabs/Widget/Admin.php:26 -msgid "Features" +#: ../../Zotlabs/Module/Photos.php:1214 +msgid "In This Photo:" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:243 ../../addon/openid/MysqlProvider.php:69 -msgid "Language" +#: ../../Zotlabs/Module/Photos.php:1219 +msgid "Map" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:244 -msgid "Post" +#: ../../Zotlabs/Module/Photos.php:1227 ../../Zotlabs/Lib/ThreadItem.php:401 +msgctxt "noun" +msgid "Likes" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:245 ../../addon/openid/MysqlProvider.php:58 -#: ../../addon/openid/MysqlProvider.php:59 -#: ../../addon/openid/MysqlProvider.php:60 -msgid "Profile Photo" +<<<<<<< HEAD +#: ../../Zotlabs/Module/Photos.php:1228 ../../Zotlabs/Lib/ThreadItem.php:402 +msgctxt "noun" +msgid "Dislikes" msgstr "" +#: ../../Zotlabs/Module/Photos.php:1233 ../../Zotlabs/Lib/ThreadItem.php:407 +#: ../../include/acl_selectors.php:220 +msgid "Close" +msgstr "" + +#: ../../Zotlabs/Module/Photos.php:1305 ../../Zotlabs/Module/Photos.php:1318 +#: ../../Zotlabs/Module/Photos.php:1319 ../../include/photos.php:525 +msgid "Recent Photos" +msgstr "" + +#: ../../Zotlabs/Module/Chat.php:179 +msgid "Room not found" +======= #: ../../Zotlabs/Lib/Apps.php:365 msgid "Purchase" msgstr "" @@ -7175,34 +8468,92 @@ msgstr "" msgid "Undelete" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:375 +#: ../../Zotlabs/Lib/Apps.php:374 msgid "Add to app-tray" msgstr "" -#: ../../Zotlabs/Lib/Apps.php:376 +#: ../../Zotlabs/Lib/Apps.php:375 msgid "Remove from app-tray" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Lib/Permcat.php:58 -msgctxt "permcat" -msgid "default" +#: ../../Zotlabs/Module/Chat.php:195 +msgid "Leave Room" msgstr "" -#: ../../Zotlabs/Lib/Permcat.php:96 -msgctxt "permcat" -msgid "follower" +#: ../../Zotlabs/Module/Chat.php:196 +msgid "Delete Room" msgstr "" -#: ../../Zotlabs/Lib/Permcat.php:100 -msgctxt "permcat" -msgid "contributor" +#: ../../Zotlabs/Module/Chat.php:197 +msgid "I am away right now" msgstr "" -#: ../../Zotlabs/Lib/Permcat.php:104 -msgctxt "permcat" -msgid "publisher" +#: ../../Zotlabs/Module/Chat.php:198 +msgid "I am online" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Module/Chat.php:200 +msgid "Bookmark this room" +msgstr "" + +#: ../../Zotlabs/Module/Chat.php:230 +msgid "New Chatroom" +msgstr "" + +#: ../../Zotlabs/Module/Chat.php:231 +msgid "Chatroom name" +msgstr "" + +#: ../../Zotlabs/Module/Chat.php:232 +msgid "Expiration of chats (minutes)" +msgstr "" + +#: ../../Zotlabs/Module/Chat.php:248 +#, php-format +msgid "%1$s's Chatrooms" +msgstr "" + +#: ../../Zotlabs/Module/Chat.php:253 +msgid "No chatrooms available" +msgstr "" + +#: ../../Zotlabs/Module/Chat.php:257 +msgid "Expiration" msgstr "" +#: ../../Zotlabs/Module/Chat.php:258 +msgid "min" +msgstr "" + +#: ../../Zotlabs/Module/Xchan.php:10 +msgid "Xchan Lookup" +msgstr "" + +#: ../../Zotlabs/Module/Xchan.php:13 +msgid "Lookup xchan beginning with (or webbie): " +msgstr "" + +#: ../../Zotlabs/Lib/Chatroom.php:27 +msgid "Missing room name" +msgstr "" + +#: ../../Zotlabs/Lib/Chatroom.php:36 +msgid "Duplicate room name" +msgstr "" + +#: ../../Zotlabs/Lib/Chatroom.php:86 ../../Zotlabs/Lib/Chatroom.php:94 +msgid "Invalid room specifier." +msgstr "" + +#: ../../Zotlabs/Lib/Chatroom.php:126 +msgid "Room not found." +msgstr "" + +#: ../../Zotlabs/Lib/Chatroom.php:147 +msgid "Room is full" +======= #: ../../Zotlabs/Lib/NativeWikiPage.php:42 #: ../../Zotlabs/Lib/NativeWikiPage.php:83 msgid "(No Title)" @@ -7267,9 +8618,10 @@ msgid "Message" msgstr "" #: ../../Zotlabs/Lib/NativeWikiPage.php:578 -#: ../../addon/gitwiki/gitwiki_backend.php:579 ../../include/bbcode.php:667 -#: ../../include/bbcode.php:813 +#: ../../addon/gitwiki/gitwiki_backend.php:579 ../../include/bbcode.php:610 +#: ../../include/bbcode.php:756 msgid "Different viewers will see this text differently" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" #: ../../Zotlabs/Lib/PermissionDescription.php:34 @@ -7335,26 +8687,76 @@ msgstr "" msgid "This is your default setting for the audience of your webpages" msgstr "" -#: ../../Zotlabs/Lib/Chatroom.php:27 -msgid "Missing room name" +#: ../../Zotlabs/Lib/DB_Upgrade.php:93 +#, php-format +msgid "Update Error at %s" msgstr "" -#: ../../Zotlabs/Lib/Chatroom.php:36 -msgid "Duplicate room name" +#: ../../Zotlabs/Lib/DB_Upgrade.php:99 +#, php-format +msgid "Update %s failed. See error logs." msgstr "" -#: ../../Zotlabs/Lib/Chatroom.php:86 ../../Zotlabs/Lib/Chatroom.php:94 -msgid "Invalid room specifier." +#: ../../Zotlabs/Lib/ThreadItem.php:96 ../../include/conversation.php:661 +msgid "Private Message" msgstr "" -#: ../../Zotlabs/Lib/Chatroom.php:126 -msgid "Room not found." +#: ../../Zotlabs/Lib/ThreadItem.php:133 ../../include/conversation.php:653 +msgid "Select" msgstr "" -#: ../../Zotlabs/Lib/Chatroom.php:147 -msgid "Room is full" +#: ../../Zotlabs/Lib/ThreadItem.php:158 +msgid "I will attend" +msgstr "" + +#: ../../Zotlabs/Lib/ThreadItem.php:158 +msgid "I will not attend" +msgstr "" + +#: ../../Zotlabs/Lib/ThreadItem.php:158 +msgid "I might attend" +msgstr "" + +#: ../../Zotlabs/Lib/ThreadItem.php:168 +msgid "I agree" +msgstr "" + +#: ../../Zotlabs/Lib/ThreadItem.php:168 +msgid "I disagree" +msgstr "" + +#: ../../Zotlabs/Lib/ThreadItem.php:168 +msgid "I abstain" +msgstr "" + +#: ../../Zotlabs/Lib/ThreadItem.php:224 +msgid "Add Star" +msgstr "" + +#: ../../Zotlabs/Lib/ThreadItem.php:225 +msgid "Remove Star" msgstr "" +#: ../../Zotlabs/Lib/ThreadItem.php:226 +msgid "Toggle Star Status" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Lib/ThreadItem.php:230 +msgid "starred" +msgstr "" + +#: ../../Zotlabs/Lib/ThreadItem.php:240 ../../include/conversation.php:668 +msgid "Message signature validated" +msgstr "" + +#: ../../Zotlabs/Lib/ThreadItem.php:241 ../../include/conversation.php:669 +msgid "Message signature incorrect" +msgstr "" + +#: ../../Zotlabs/Lib/ThreadItem.php:249 +msgid "Add Tag" +======= #: ../../Zotlabs/Lib/Enotify.php:60 ../../include/network.php:1977 msgid "$Projectname Notification" msgstr "" @@ -7372,551 +8774,565 @@ msgstr "" #: ../../Zotlabs/Lib/Enotify.php:65 ../../include/network.php:1982 #, php-format msgid "%s Administrator" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:116 -#, php-format -msgid "%s <!item_type!>" +#: ../../Zotlabs/Lib/ThreadItem.php:269 ../../include/taxonomy.php:316 +msgid "like" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:120 -#, php-format -msgid "[$Projectname:Notify] New mail received at %s" +#: ../../Zotlabs/Lib/ThreadItem.php:270 ../../include/taxonomy.php:317 +msgid "dislike" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:122 -#, php-format -msgid "%1$s, %2$s sent you a new private message at %3$s." +#: ../../Zotlabs/Lib/ThreadItem.php:274 +msgid "Share This" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:123 -#, php-format -msgid "%1$s sent you %2$s." +#: ../../Zotlabs/Lib/ThreadItem.php:274 +msgid "share" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:123 -msgid "a private message" +#: ../../Zotlabs/Lib/ThreadItem.php:283 +msgid "Delivery Report" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:124 +#: ../../Zotlabs/Lib/ThreadItem.php:301 #, php-format -msgid "Please visit %s to view and/or reply to your private messages." -msgstr "" +msgid "%d comment" +msgid_plural "%d comments" +msgstr[0] "" +msgstr[1] "" -#: ../../Zotlabs/Lib/Enotify.php:184 +#: ../../Zotlabs/Lib/ThreadItem.php:330 ../../Zotlabs/Lib/ThreadItem.php:331 #, php-format -msgid "%1$s, %2$s commented on [zrl=%3$s]a %4$s[/zrl]" +msgid "View %s's profile - %s" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:192 -#, php-format -msgid "%1$s, %2$s commented on [zrl=%3$s]%4$s's %5$s[/zrl]" +#: ../../Zotlabs/Lib/ThreadItem.php:334 +msgid "to" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:201 -#, php-format -msgid "%1$s, %2$s commented on [zrl=%3$s]your %4$s[/zrl]" +#: ../../Zotlabs/Lib/ThreadItem.php:335 +msgid "via" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:213 -#, php-format -msgid "[$Projectname:Notify] Moderated Comment to conversation #%1$d by %2$s" +#: ../../Zotlabs/Lib/ThreadItem.php:336 +msgid "Wall-to-Wall" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:215 -#, php-format -msgid "[$Projectname:Notify] Comment to conversation #%1$d by %2$s" +#: ../../Zotlabs/Lib/ThreadItem.php:337 +msgid "via Wall-To-Wall:" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:216 +#: ../../Zotlabs/Lib/ThreadItem.php:350 ../../include/conversation.php:718 #, php-format -msgid "%1$s, %2$s commented on an item/conversation you have been following." +msgid "from %s" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:219 ../../Zotlabs/Lib/Enotify.php:301 -#: ../../Zotlabs/Lib/Enotify.php:318 ../../Zotlabs/Lib/Enotify.php:344 -#: ../../Zotlabs/Lib/Enotify.php:362 ../../Zotlabs/Lib/Enotify.php:376 +#: ../../Zotlabs/Lib/ThreadItem.php:353 ../../include/conversation.php:721 #, php-format -msgid "Please visit %s to view and/or reply to the conversation." +msgid "last edited: %s" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:223 ../../Zotlabs/Lib/Enotify.php:224 +#: ../../Zotlabs/Lib/ThreadItem.php:354 ../../include/conversation.php:722 #, php-format -msgid "Please visit %s to approve or reject this comment." +msgid "Expires: %s" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:282 -#, php-format -msgid "%1$s, %2$s liked [zrl=%3$s]your %4$s[/zrl]" +#: ../../Zotlabs/Lib/ThreadItem.php:360 +msgid "Attend" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:297 -#, php-format -msgid "[$Projectname:Notify] Like received to conversation #%1$d by %2$s" +#: ../../Zotlabs/Lib/ThreadItem.php:361 +msgid "Attendance Options" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:298 -#, php-format -msgid "%1$s, %2$s liked an item/conversation you created." +#: ../../Zotlabs/Lib/ThreadItem.php:362 +msgid "Vote" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:309 -#, php-format -msgid "[$Projectname:Notify] %s posted to your profile wall" +#: ../../Zotlabs/Lib/ThreadItem.php:363 +msgid "Voting Options" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:311 -#, php-format -msgid "%1$s, %2$s posted to your profile wall at %3$s" +#: ../../Zotlabs/Lib/ThreadItem.php:384 +#: ../../extend/addon/addon/bookmarker/bookmarker.php:38 +msgid "Save Bookmarks" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:313 -#, php-format -msgid "%1$s, %2$s posted to [zrl=%3$s]your wall[/zrl]" +#: ../../Zotlabs/Lib/ThreadItem.php:385 +msgid "Add to Calendar" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:337 -#, php-format -msgid "[$Projectname:Notify] %s tagged you" +#: ../../Zotlabs/Lib/ThreadItem.php:394 +msgid "Mark all seen" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:338 +#: ../../Zotlabs/Lib/ThreadItem.php:443 ../../include/js_strings.php:7 #, php-format -msgid "%1$s, %2$s tagged you at %3$s" +msgid "%s show all" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:339 -#, php-format -msgid "%1$s, %2$s [zrl=%3$s]tagged you[/zrl]." +#: ../../Zotlabs/Lib/ThreadItem.php:733 ../../include/conversation.php:1318 +msgid "Bold" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:351 -#, php-format -msgid "[$Projectname:Notify] %1$s poked you" +#: ../../Zotlabs/Lib/ThreadItem.php:734 ../../include/conversation.php:1319 +msgid "Italic" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:352 -#, php-format -msgid "%1$s, %2$s poked you at %3$s" +#: ../../Zotlabs/Lib/ThreadItem.php:735 ../../include/conversation.php:1320 +msgid "Underline" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:353 -#, php-format -msgid "%1$s, %2$s [zrl=%2$s]poked you[/zrl]." +#: ../../Zotlabs/Lib/ThreadItem.php:736 ../../include/conversation.php:1321 +msgid "Quote" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:369 -#, php-format -msgid "[$Projectname:Notify] %s tagged your post" +#: ../../Zotlabs/Lib/ThreadItem.php:737 ../../include/conversation.php:1322 +msgid "Code" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:370 -#, php-format -msgid "%1$s, %2$s tagged your post at %3$s" +#: ../../Zotlabs/Lib/ThreadItem.php:738 +msgid "Image" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:371 -#, php-format -msgid "%1$s, %2$s tagged [zrl=%3$s]your post[/zrl]" +#: ../../Zotlabs/Lib/ThreadItem.php:739 +msgid "Insert Link" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:383 -msgid "[$Projectname:Notify] Introduction received" +#: ../../Zotlabs/Lib/ThreadItem.php:740 +msgid "Video" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:384 -#, php-format -msgid "%1$s, you've received an new connection request from '%2$s' at %3$s" +#: ../../Zotlabs/Lib/Permcat.php:58 +msgctxt "permcat" +msgid "default" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:385 -#, php-format -msgid "" -"%1$s, you've received [zrl=%2$s]a new connection request[/zrl] from %3$s." +#: ../../Zotlabs/Lib/Permcat.php:96 +msgctxt "permcat" +msgid "follower" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:389 ../../Zotlabs/Lib/Enotify.php:408 -#, php-format -msgid "You may visit their profile at %s" +#: ../../Zotlabs/Lib/Permcat.php:100 +msgctxt "permcat" +msgid "contributor" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:391 -#, php-format -msgid "Please visit %s to approve or reject the connection request." +#: ../../Zotlabs/Lib/Permcat.php:104 +msgctxt "permcat" +msgid "publisher" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:398 -msgid "[$Projectname:Notify] Friend suggestion received" +#: ../../Zotlabs/Lib/Apps.php:212 +msgid "Site Admin" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:399 -#, php-format -msgid "%1$s, you've received a friend suggestion from '%2$s' at %3$s" +#: ../../Zotlabs/Lib/Apps.php:213 +#: ../../extend/addon/addon/buglink/buglink.php:16 +msgid "Report Bug" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:400 -#, php-format -msgid "" -"%1$s, you've received [zrl=%2$s]a friend suggestion[/zrl] for %3$s from %4$s." +#: ../../Zotlabs/Lib/Apps.php:214 +msgid "View Bookmarks" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:406 -msgid "Name:" +#: ../../Zotlabs/Lib/Apps.php:215 +msgid "My Chatrooms" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:407 -msgid "Photo:" +<<<<<<< HEAD +#: ../../Zotlabs/Lib/Apps.php:217 +msgid "Firefox Share" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:410 -#, php-format -msgid "Please visit %s to approve or reject the suggestion." +#: ../../Zotlabs/Lib/Apps.php:218 +msgid "Remote Diagnostics" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:629 +#: ../../Zotlabs/Lib/Apps.php:219 ../../include/features.php:337 +msgid "Suggest Channels" +======= +#: ../../Zotlabs/Lib/Enotify.php:620 msgid "[$Projectname:Notify]" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:789 +#: ../../Zotlabs/Lib/Enotify.php:780 msgid "created a new post" msgstr "" -#: ../../Zotlabs/Lib/Enotify.php:790 +#: ../../Zotlabs/Lib/Enotify.php:781 #, php-format msgid "commented on %s's post" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Lib/NativeWiki.php:128 -msgid "Wiki files deleted successfully" +#: ../../Zotlabs/Lib/Apps.php:220 ../../include/nav.php:113 +#: ../../boot.php:1591 +msgid "Login" msgstr "" -#: ../../Zotlabs/Lib/DB_Upgrade.php:93 -#, php-format -msgid "Update Error at %s" +#: ../../Zotlabs/Lib/Apps.php:222 +msgid "Activity" msgstr "" -#: ../../Zotlabs/Lib/DB_Upgrade.php:99 -#, php-format -msgid "Update %s failed. See error logs." +#: ../../Zotlabs/Lib/Apps.php:226 ../../include/conversation.php:1848 +#: ../../include/features.php:99 +msgid "Wiki" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:96 ../../include/conversation.php:657 -msgid "Private Message" +#: ../../Zotlabs/Lib/Apps.php:227 ../../include/nav.php:176 +msgid "Channel Home" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:133 ../../include/conversation.php:649 -msgid "Select" +#: ../../Zotlabs/Lib/Apps.php:230 ../../include/nav.php:196 +#: ../../include/conversation.php:1793 ../../include/conversation.php:1796 +msgid "Events" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:158 -msgid "I will attend" +#: ../../Zotlabs/Lib/Apps.php:231 +msgid "Directory" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:158 -msgid "I will not attend" +#: ../../Zotlabs/Lib/Apps.php:233 ../../include/nav.php:188 +msgid "Mail" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:158 -msgid "I might attend" +#: ../../Zotlabs/Lib/Apps.php:236 +msgid "Chat" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:168 -msgid "I agree" +#: ../../Zotlabs/Lib/Apps.php:238 +msgid "Probe" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:168 -msgid "I disagree" +#: ../../Zotlabs/Lib/Apps.php:239 +msgid "Suggest" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:168 -msgid "I abstain" +#: ../../Zotlabs/Lib/Apps.php:240 +msgid "Random Channel" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:224 -msgid "Add Star" +#: ../../Zotlabs/Lib/Apps.php:241 +msgid "Invite" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:225 -msgid "Remove Star" +#: ../../Zotlabs/Lib/Apps.php:242 ../../Zotlabs/Widget/Admin.php:26 +msgid "Features" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:226 -msgid "Toggle Star Status" +#: ../../Zotlabs/Lib/Apps.php:243 +#: ../../extend/addon/addon/openid/MysqlProvider.php:69 +msgid "Language" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:230 -msgid "starred" +#: ../../Zotlabs/Lib/Apps.php:244 +msgid "Post" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:240 ../../include/conversation.php:664 -msgid "Message signature validated" +#: ../../Zotlabs/Lib/Apps.php:245 +#: ../../extend/addon/addon/openid/MysqlProvider.php:58 +#: ../../extend/addon/addon/openid/MysqlProvider.php:59 +#: ../../extend/addon/addon/openid/MysqlProvider.php:60 +msgid "Profile Photo" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:241 ../../include/conversation.php:665 -msgid "Message signature incorrect" +#: ../../Zotlabs/Lib/Apps.php:365 +msgid "Purchase" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:249 -msgid "Add Tag" +#: ../../Zotlabs/Lib/Apps.php:369 +msgid "Undelete" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:269 ../../include/taxonomy.php:346 -msgid "like" +#: ../../Zotlabs/Lib/Apps.php:374 +msgid "Add to app-tray" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:270 ../../include/taxonomy.php:347 -msgid "dislike" +#: ../../Zotlabs/Lib/Apps.php:375 +msgid "Remove from app-tray" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:274 -msgid "Share This" +#: ../../Zotlabs/Lib/Enotify.php:60 ../../include/network.php:1426 +msgid "$Projectname Notification" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:274 -msgid "share" +#: ../../Zotlabs/Lib/Enotify.php:61 ../../include/network.php:1427 +msgid "$projectname" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:283 -msgid "Delivery Report" +#: ../../Zotlabs/Lib/Enotify.php:63 ../../include/network.php:1429 +msgid "Thank You," msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:301 +#: ../../Zotlabs/Lib/Enotify.php:65 ../../include/network.php:1431 #, php-format -msgid "%d comment" -msgid_plural "%d comments" -msgstr[0] "" -msgstr[1] "" +msgid "%s Administrator" +msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:330 ../../Zotlabs/Lib/ThreadItem.php:331 +#: ../../Zotlabs/Lib/Enotify.php:116 #, php-format -msgid "View %s's profile - %s" +msgid "%s <!item_type!>" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:334 -msgid "to" +#: ../../Zotlabs/Lib/Enotify.php:120 +#, php-format +msgid "[$Projectname:Notify] New mail received at %s" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:335 -msgid "via" +#: ../../Zotlabs/Lib/Enotify.php:122 +#, php-format +msgid "%1$s, %2$s sent you a new private message at %3$s." msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:336 -msgid "Wall-to-Wall" +#: ../../Zotlabs/Lib/Enotify.php:123 +#, php-format +msgid "%1$s sent you %2$s." msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:337 -msgid "via Wall-To-Wall:" +#: ../../Zotlabs/Lib/Enotify.php:123 +msgid "a private message" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:350 ../../include/conversation.php:716 +#: ../../Zotlabs/Lib/Enotify.php:124 #, php-format -msgid "from %s" +msgid "Please visit %s to view and/or reply to your private messages." msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:353 ../../include/conversation.php:719 +#: ../../Zotlabs/Lib/Enotify.php:183 #, php-format -msgid "last edited: %s" +msgid "%1$s, %2$s commented on [zrl=%3$s]a %4$s[/zrl]" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:354 ../../include/conversation.php:720 +#: ../../Zotlabs/Lib/Enotify.php:191 #, php-format -msgid "Expires: %s" -msgstr "" - -#: ../../Zotlabs/Lib/ThreadItem.php:360 -msgid "Attend" +msgid "%1$s, %2$s commented on [zrl=%3$s]%4$s's %5$s[/zrl]" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:361 -msgid "Attendance Options" +#: ../../Zotlabs/Lib/Enotify.php:200 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]your %4$s[/zrl]" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:362 -msgid "Vote" +#: ../../Zotlabs/Lib/Enotify.php:211 +#, php-format +msgid "[$Projectname:Notify] Comment to conversation #%1$d by %2$s" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:363 -msgid "Voting Options" +#: ../../Zotlabs/Lib/Enotify.php:212 +#, php-format +msgid "%1$s, %2$s commented on an item/conversation you have been following." msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:384 -#: ../../addon/bookmarker/bookmarker.php:38 -msgid "Save Bookmarks" +#: ../../Zotlabs/Lib/Enotify.php:215 ../../Zotlabs/Lib/Enotify.php:292 +#: ../../Zotlabs/Lib/Enotify.php:309 ../../Zotlabs/Lib/Enotify.php:335 +#: ../../Zotlabs/Lib/Enotify.php:353 ../../Zotlabs/Lib/Enotify.php:367 +#, php-format +msgid "Please visit %s to view and/or reply to the conversation." msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:385 -msgid "Add to Calendar" +#: ../../Zotlabs/Lib/Enotify.php:273 +#, php-format +msgid "%1$s, %2$s liked [zrl=%3$s]your %4$s[/zrl]" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:443 ../../include/js_strings.php:7 +#: ../../Zotlabs/Lib/Enotify.php:288 #, php-format -msgid "%s show all" +msgid "[$Projectname:Notify] Like received to conversation #%1$d by %2$s" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:733 ../../include/conversation.php:1316 -msgid "Bold" +#: ../../Zotlabs/Lib/Enotify.php:289 +#, php-format +msgid "%1$s, %2$s liked an item/conversation you created." msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:734 ../../include/conversation.php:1317 -msgid "Italic" +#: ../../Zotlabs/Lib/Enotify.php:300 +#, php-format +msgid "[$Projectname:Notify] %s posted to your profile wall" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:735 ../../include/conversation.php:1318 -msgid "Underline" +#: ../../Zotlabs/Lib/Enotify.php:302 +#, php-format +msgid "%1$s, %2$s posted to your profile wall at %3$s" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:736 ../../include/conversation.php:1319 -msgid "Quote" +#: ../../Zotlabs/Lib/Enotify.php:304 +#, php-format +msgid "%1$s, %2$s posted to [zrl=%3$s]your wall[/zrl]" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:737 ../../include/conversation.php:1320 -msgid "Code" +#: ../../Zotlabs/Lib/Enotify.php:328 +#, php-format +msgid "[$Projectname:Notify] %s tagged you" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:738 -msgid "Image" +#: ../../Zotlabs/Lib/Enotify.php:329 +#, php-format +msgid "%1$s, %2$s tagged you at %3$s" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:739 -msgid "Insert Link" +#: ../../Zotlabs/Lib/Enotify.php:330 +#, php-format +msgid "%1$s, %2$s [zrl=%3$s]tagged you[/zrl]." msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:740 -msgid "Video" +#: ../../Zotlabs/Lib/Enotify.php:342 +#, php-format +msgid "[$Projectname:Notify] %1$s poked you" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:749 -msgid "Your full name (required)" +#: ../../Zotlabs/Lib/Enotify.php:343 +#, php-format +msgid "%1$s, %2$s poked you at %3$s" msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:750 -msgid "Your email address (required)" +#: ../../Zotlabs/Lib/Enotify.php:344 +#, php-format +msgid "%1$s, %2$s [zrl=%2$s]poked you[/zrl]." msgstr "" -#: ../../Zotlabs/Lib/ThreadItem.php:751 -msgid "Your website URL (optional)" +#: ../../Zotlabs/Lib/Enotify.php:360 +#, php-format +msgid "[$Projectname:Notify] %s tagged your post" msgstr "" -#: ../../Zotlabs/Zot/Auth.php:138 -msgid "" -"Remote authentication blocked. You are logged into this site locally. Please " -"logout and retry." +<<<<<<< HEAD +#: ../../Zotlabs/Lib/Enotify.php:361 +#, php-format +msgid "%1$s, %2$s tagged your post at %3$s" +======= +#: ../../Zotlabs/Storage/Browser.php:130 ../../include/text.php:2679 +msgid "Collection" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Zot/Auth.php:250 ../../addon/openid/Mod_Openid.php:76 -#: ../../addon/openid/Mod_Openid.php:178 +#: ../../Zotlabs/Lib/Enotify.php:362 #, php-format -msgid "Welcome %s. Remote authentication successful." +msgid "%1$s, %2$s tagged [zrl=%3$s]your post[/zrl]" msgstr "" -#: ../../Zotlabs/Storage/Browser.php:106 ../../Zotlabs/Storage/Browser.php:237 -msgid "parent" +#: ../../Zotlabs/Lib/Enotify.php:374 +msgid "[$Projectname:Notify] Introduction received" msgstr "" -#: ../../Zotlabs/Storage/Browser.php:130 ../../include/text.php:2692 -msgid "Collection" +#: ../../Zotlabs/Lib/Enotify.php:375 +#, php-format +msgid "%1$s, you've received an new connection request from '%2$s' at %3$s" msgstr "" -#: ../../Zotlabs/Storage/Browser.php:133 -msgid "Principal" +#: ../../Zotlabs/Lib/Enotify.php:376 +#, php-format +msgid "" +"%1$s, you've received [zrl=%2$s]a new connection request[/zrl] from %3$s." msgstr "" -#: ../../Zotlabs/Storage/Browser.php:136 -msgid "Addressbook" +#: ../../Zotlabs/Lib/Enotify.php:380 ../../Zotlabs/Lib/Enotify.php:399 +#, php-format +msgid "You may visit their profile at %s" msgstr "" -#: ../../Zotlabs/Storage/Browser.php:139 -msgid "Calendar" +#: ../../Zotlabs/Lib/Enotify.php:382 +#, php-format +msgid "Please visit %s to approve or reject the connection request." msgstr "" -#: ../../Zotlabs/Storage/Browser.php:142 -msgid "Schedule Inbox" +#: ../../Zotlabs/Lib/Enotify.php:389 +msgid "[$Projectname:Notify] Friend suggestion received" msgstr "" -#: ../../Zotlabs/Storage/Browser.php:145 -msgid "Schedule Outbox" +#: ../../Zotlabs/Lib/Enotify.php:390 +#, php-format +msgid "%1$s, you've received a friend suggestion from '%2$s' at %3$s" msgstr "" -#: ../../Zotlabs/Storage/Browser.php:225 -msgid "Total" +#: ../../Zotlabs/Lib/Enotify.php:391 +#, php-format +msgid "" +"%1$s, you've received [zrl=%2$s]a friend suggestion[/zrl] for %3$s from %4$s." msgstr "" -#: ../../Zotlabs/Storage/Browser.php:227 -msgid "Shared" +#: ../../Zotlabs/Lib/Enotify.php:397 +msgid "Name:" msgstr "" -#: ../../Zotlabs/Storage/Browser.php:301 -#, php-format -msgid "You are using %1$s of your available file storage." +#: ../../Zotlabs/Lib/Enotify.php:398 +msgid "Photo:" msgstr "" -#: ../../Zotlabs/Storage/Browser.php:306 +#: ../../Zotlabs/Lib/Enotify.php:401 #, php-format -msgid "You are using %1$s of %2$s available file storage. (%3$s%)" +msgid "Please visit %s to approve or reject the suggestion." msgstr "" -#: ../../Zotlabs/Storage/Browser.php:317 -msgid "WARNING:" +#: ../../Zotlabs/Lib/Enotify.php:619 +msgid "[$Projectname:Notify]" msgstr "" -#: ../../Zotlabs/Storage/Browser.php:327 -msgid "" -"Please use DAV to upload large (video, audio) files.<br>See <a class=\"zrl\" " -"href=\"help/member/member_guide#Cloud_Desktop_Clients\">Cloud Desktop " -"Clients</a>" +#: ../../Zotlabs/Lib/Enotify.php:779 +msgid "created a new post" msgstr "" -#: ../../Zotlabs/Storage/Browser.php:331 -msgid "Create new folder" +#: ../../Zotlabs/Lib/Enotify.php:780 +#, php-format +msgid "commented on %s's post" msgstr "" -#: ../../Zotlabs/Storage/Browser.php:333 -msgid "Upload file" +#: ../../Zotlabs/Lib/NativeWiki.php:128 +msgid "Wiki files deleted successfully" msgstr "" -#: ../../Zotlabs/Storage/Browser.php:347 -msgid "Drop files here to immediately upload" +#: ../../Zotlabs/Lib/NativeWikiPage.php:31 +#: ../../Zotlabs/Lib/NativeWikiPage.php:72 +msgid "(No Title)" msgstr "" -#: ../../Zotlabs/Widget/Forums.php:85 -msgid "Forums" +#: ../../Zotlabs/Lib/NativeWikiPage.php:86 +msgid "Wiki page create failed." msgstr "" -#: ../../Zotlabs/Widget/Appcategories.php:39 -#: ../../Zotlabs/Widget/Tagcloud.php:25 ../../include/contact_widgets.php:91 -#: ../../include/taxonomy.php:218 ../../include/taxonomy.php:300 -msgid "Categories" +#: ../../Zotlabs/Lib/NativeWikiPage.php:99 +msgid "Wiki not found." msgstr "" -#: ../../Zotlabs/Widget/Appcategories.php:42 ../../Zotlabs/Widget/Filer.php:31 -#: ../../include/contact_widgets.php:56 ../../include/contact_widgets.php:94 -msgid "Everything" +#: ../../Zotlabs/Lib/NativeWikiPage.php:110 +msgid "Destination name already exists" msgstr "" -#: ../../Zotlabs/Widget/Eventstools.php:13 -msgid "Events Tools" +#: ../../Zotlabs/Lib/NativeWikiPage.php:136 +#: ../../Zotlabs/Lib/NativeWikiPage.php:331 +msgid "Page not found" msgstr "" -#: ../../Zotlabs/Widget/Eventstools.php:14 -msgid "Export Calendar" +#: ../../Zotlabs/Lib/NativeWikiPage.php:166 +msgid "Error reading page content" msgstr "" -#: ../../Zotlabs/Widget/Eventstools.php:15 -msgid "Import Calendar" +#: ../../Zotlabs/Lib/NativeWikiPage.php:322 +#: ../../Zotlabs/Lib/NativeWikiPage.php:370 +#: ../../Zotlabs/Lib/NativeWikiPage.php:437 +#: ../../Zotlabs/Lib/NativeWikiPage.php:478 +msgid "Error reading wiki" msgstr "" -#: ../../Zotlabs/Widget/Suggestedchats.php:32 -msgid "Suggested Chatrooms" +<<<<<<< HEAD +#: ../../Zotlabs/Lib/NativeWikiPage.php:358 +msgid "Page update failed." msgstr "" -#: ../../Zotlabs/Widget/Mailmenu.php:13 -msgid "Private Mail Menu" +#: ../../Zotlabs/Lib/NativeWikiPage.php:392 +msgid "Nothing deleted" msgstr "" -#: ../../Zotlabs/Widget/Mailmenu.php:15 -msgid "Combined View" +#: ../../Zotlabs/Lib/NativeWikiPage.php:458 +msgid "Compare: object not found." msgstr "" +#: ../../Zotlabs/Lib/NativeWikiPage.php:464 +msgid "Page updated" +======= #: ../../Zotlabs/Widget/Mailmenu.php:20 ../../include/nav.php:195 msgid "Inbox" msgstr "" @@ -7930,25 +9346,30 @@ msgid "New Message" msgstr "" #: ../../Zotlabs/Widget/Chatroom_list.php:16 -#: ../../include/conversation.php:1814 ../../include/conversation.php:1817 -#: ../../include/nav.php:418 ../../include/nav.php:421 +#: ../../include/conversation.php:1816 ../../include/conversation.php:1819 +#: ../../include/nav.php:425 ../../include/nav.php:428 msgid "Chatrooms" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Widget/Chatroom_list.php:20 -msgid "Overview" +#: ../../Zotlabs/Lib/NativeWikiPage.php:467 +msgid "Untitled" msgstr "" -#: ../../Zotlabs/Widget/Rating.php:51 -msgid "Rating Tools" +#: ../../Zotlabs/Lib/NativeWikiPage.php:473 +msgid "Wiki resource_id required for git commit" msgstr "" -#: ../../Zotlabs/Widget/Rating.php:55 ../../Zotlabs/Widget/Rating.php:57 -msgid "Rate Me" +#: ../../Zotlabs/Lib/NativeWikiPage.php:529 +#: ../../Zotlabs/Widget/Wiki_page_history.php:23 +msgctxt "wiki_history" +msgid "Message" msgstr "" -#: ../../Zotlabs/Widget/Rating.php:60 -msgid "View Ratings" +#: ../../Zotlabs/Lib/NativeWikiPage.php:567 +#: ../../extend/addon/addon/gitwiki/gitwiki_backend.php:579 +#: ../../include/bbcode.php:610 ../../include/bbcode.php:756 +msgid "Different viewers will see this text differently" msgstr "" #: ../../Zotlabs/Widget/Activity.php:50 @@ -7956,131 +9377,159 @@ msgctxt "widget" msgid "Activity" msgstr "" -#: ../../Zotlabs/Widget/Follow.php:22 -#, php-format -msgid "You have %1$.0f of %2$.0f allowed connections." +#: ../../Zotlabs/Widget/Admin.php:23 ../../Zotlabs/Widget/Admin.php:60 +msgid "Member registrations waiting for confirmation" msgstr "" -#: ../../Zotlabs/Widget/Follow.php:29 -msgid "Add New Connection" +#: ../../Zotlabs/Widget/Admin.php:29 +msgid "Inspect queue" msgstr "" -#: ../../Zotlabs/Widget/Follow.php:30 -msgid "Enter channel address" +#: ../../Zotlabs/Widget/Admin.php:31 +msgid "DB updates" msgstr "" -#: ../../Zotlabs/Widget/Follow.php:31 -msgid "Examples: bob@example.com, https://example.com/barbara" +#: ../../Zotlabs/Widget/Admin.php:55 ../../include/nav.php:211 +msgid "Admin" msgstr "" -#: ../../Zotlabs/Widget/Wiki_list.php:15 ../../addon/gitwiki/gitwiki.php:95 -msgid "Wiki List" +#: ../../Zotlabs/Widget/Admin.php:56 +msgid "Plugin Features" msgstr "" -#: ../../Zotlabs/Widget/Archive.php:43 -msgid "Archives" +#: ../../Zotlabs/Widget/Affinity.php:49 +msgid "Refresh" msgstr "" -#: ../../Zotlabs/Widget/Conversations.php:17 -#: ../../Zotlabs/Widget/Conversations.php:29 -msgid "Conversations" +#: ../../Zotlabs/Widget/Appcategories.php:39 +#: ../../Zotlabs/Widget/Tagcloud.php:25 ../../include/taxonomy.php:188 +#: ../../include/taxonomy.php:270 ../../include/contact_widgets.php:91 +msgid "Categories" msgstr "" -#: ../../Zotlabs/Widget/Conversations.php:21 -msgid "Received Messages" +#: ../../Zotlabs/Widget/Appcategories.php:42 ../../Zotlabs/Widget/Filer.php:31 +#: ../../include/contact_widgets.php:56 ../../include/contact_widgets.php:94 +msgid "Everything" msgstr "" -#: ../../Zotlabs/Widget/Conversations.php:25 -msgid "Sent Messages" +#: ../../Zotlabs/Widget/Archive.php:43 +msgid "Archives" msgstr "" -#: ../../Zotlabs/Widget/Conversations.php:39 -msgid "No messages." +#: ../../Zotlabs/Widget/Bookmarkedchats.php:24 +msgid "Bookmarked Chatrooms" msgstr "" -#: ../../Zotlabs/Widget/Conversations.php:57 -msgid "Delete conversation" +#: ../../Zotlabs/Widget/Chatroom_list.php:16 +#: ../../include/conversation.php:1807 ../../include/conversation.php:1810 +msgid "Chatrooms" +msgstr "" + +#: ../../Zotlabs/Widget/Chatroom_list.php:20 +msgid "Overview" msgstr "" #: ../../Zotlabs/Widget/Chatroom_members.php:11 msgid "Chat Members" msgstr "" -#: ../../Zotlabs/Widget/Photo.php:48 ../../Zotlabs/Widget/Photo_rand.php:58 -msgid "photo/image" +#: ../../Zotlabs/Widget/Cover_photo.php:54 +msgid "Click to show more" msgstr "" -#: ../../Zotlabs/Widget/Savedsearch.php:75 -msgid "Remove term" +#: ../../Zotlabs/Widget/Eventstools.php:13 +msgid "Events Tools" msgstr "" -#: ../../Zotlabs/Widget/Savedsearch.php:83 ../../include/features.php:301 -msgid "Saved Searches" +#: ../../Zotlabs/Widget/Eventstools.php:14 +msgid "Export Calendar" msgstr "" -#: ../../Zotlabs/Widget/Savedsearch.php:84 ../../include/group.php:336 -msgid "add" +#: ../../Zotlabs/Widget/Eventstools.php:15 +msgid "Import Calendar" msgstr "" -#: ../../Zotlabs/Widget/Notes.php:16 -msgid "Notes" +#: ../../Zotlabs/Widget/Filer.php:28 ../../include/contact_widgets.php:53 +#: ../../include/features.php:390 +msgid "Saved Folders" msgstr "" -#: ../../Zotlabs/Widget/Wiki_pages.php:52 ../../addon/gitwiki/gitwiki.php:76 -msgid "Wiki Pages" +#: ../../Zotlabs/Widget/Follow.php:22 +#, php-format +msgid "You have %1$.0f of %2$.0f allowed connections." msgstr "" -#: ../../Zotlabs/Widget/Wiki_pages.php:58 ../../addon/gitwiki/gitwiki.php:81 -msgid "Add new page" +#: ../../Zotlabs/Widget/Follow.php:29 +msgid "Add New Connection" msgstr "" -#: ../../Zotlabs/Widget/Wiki_pages.php:59 ../../addon/gitwiki/gitwiki.php:82 -msgid "Page name" +#: ../../Zotlabs/Widget/Follow.php:30 +msgid "Enter channel address" msgstr "" -#: ../../Zotlabs/Widget/Affinity.php:49 -msgid "Refresh" +#: ../../Zotlabs/Widget/Follow.php:31 +msgid "Examples: bob@example.com, https://example.com/barbara" msgstr "" -#: ../../Zotlabs/Widget/Tasklist.php:23 -msgid "Tasks" +#: ../../Zotlabs/Widget/Forums.php:85 +msgid "Forums" msgstr "" -#: ../../Zotlabs/Widget/Suggestions.php:51 -msgid "Suggestions" +#: ../../Zotlabs/Widget/Mailmenu.php:13 +msgid "Private Mail Menu" msgstr "" -#: ../../Zotlabs/Widget/Suggestions.php:52 -msgid "See more..." +#: ../../Zotlabs/Widget/Mailmenu.php:15 +msgid "Combined View" msgstr "" -#: ../../Zotlabs/Widget/Filer.php:28 ../../include/contact_widgets.php:53 -#: ../../include/features.php:390 -msgid "Saved Folders" +#: ../../Zotlabs/Widget/Mailmenu.php:20 ../../include/nav.php:191 +msgid "Inbox" msgstr "" -#: ../../Zotlabs/Widget/Cover_photo.php:54 -msgid "Click to show more" +#: ../../Zotlabs/Widget/Mailmenu.php:25 ../../include/nav.php:192 +msgid "Outbox" msgstr "" -#: ../../Zotlabs/Widget/Admin.php:23 ../../Zotlabs/Widget/Admin.php:60 -msgid "Member registrations waiting for confirmation" +#: ../../Zotlabs/Widget/Mailmenu.php:30 ../../include/nav.php:193 +msgid "New Message" msgstr "" -#: ../../Zotlabs/Widget/Admin.php:29 -msgid "Inspect queue" +#: ../../Zotlabs/Widget/Notes.php:16 +msgid "Notes" msgstr "" -#: ../../Zotlabs/Widget/Admin.php:31 -msgid "DB updates" +#: ../../Zotlabs/Widget/Photo.php:48 ../../Zotlabs/Widget/Photo_rand.php:58 +msgid "photo/image" +msgstr "" + +#: ../../Zotlabs/Widget/Rating.php:51 +msgid "Rating Tools" +msgstr "" + +#: ../../Zotlabs/Widget/Rating.php:55 ../../Zotlabs/Widget/Rating.php:57 +msgid "Rate Me" msgstr "" +#: ../../Zotlabs/Widget/Rating.php:60 +msgid "View Ratings" +msgstr "" + +#: ../../Zotlabs/Widget/Savedsearch.php:75 +msgid "Remove term" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Widget/Savedsearch.php:83 ../../include/features.php:301 +msgid "Saved Searches" +======= #: ../../Zotlabs/Widget/Admin.php:55 ../../include/nav.php:215 msgid "Admin" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../Zotlabs/Widget/Admin.php:56 -msgid "Plugin Features" +#: ../../Zotlabs/Widget/Savedsearch.php:84 ../../include/group.php:336 +msgid "add" msgstr "" #: ../../Zotlabs/Widget/Settings_menu.php:35 @@ -8123,1295 +9572,1474 @@ msgstr "" msgid "Premium Channel Settings" msgstr "" -#: ../../Zotlabs/Widget/Bookmarkedchats.php:24 -msgid "Bookmarked Chatrooms" +#: ../../Zotlabs/Widget/Suggestedchats.php:32 +msgid "Suggested Chatrooms" msgstr "" -#: ../../util/nconfig.php:34 -msgid "Source channel not found." +#: ../../Zotlabs/Widget/Suggestions.php:51 +msgid "Suggestions" +msgstr "" + +<<<<<<< HEAD +#: ../../Zotlabs/Widget/Suggestions.php:52 +msgid "See more..." +msgstr "" + +#: ../../Zotlabs/Widget/Wiki_list.php:15 +#: ../../extend/addon/addon/gitwiki/gitwiki.php:95 +msgid "Wiki List" +msgstr "" + +#: ../../Zotlabs/Widget/Wiki_pages.php:54 +#: ../../extend/addon/addon/gitwiki/gitwiki.php:76 +msgid "Wiki Pages" +msgstr "" + +#: ../../Zotlabs/Widget/Wiki_pages.php:60 +#: ../../extend/addon/addon/gitwiki/gitwiki.php:81 +msgid "Add new page" +msgstr "" + +#: ../../Zotlabs/Widget/Wiki_pages.php:61 +#: ../../extend/addon/addon/gitwiki/gitwiki.php:82 +msgid "Page name" +msgstr "" + +#: ../../Zotlabs/Widget/Tasklist.php:23 +msgid "Tasks" +msgstr "" + +#: ../../Zotlabs/Widget/Conversations.php:17 +#: ../../Zotlabs/Widget/Conversations.php:29 +msgid "Conversations" +msgstr "" + +#: ../../Zotlabs/Widget/Conversations.php:21 +msgid "Received Messages" +msgstr "" + +#: ../../Zotlabs/Widget/Conversations.php:25 +msgid "Sent Messages" +msgstr "" + +#: ../../Zotlabs/Widget/Conversations.php:39 +msgid "No messages." msgstr "" -#: ../../boot.php:1164 ../../addon/opensearch/opensearch.php:26 +#: ../../Zotlabs/Widget/Conversations.php:57 +msgid "Delete conversation" +msgstr "" + +#: ../../extend/addon/addon/adultphotoflag/adultphotoflag.php:24 +msgid "Flag Adult Photos" +msgstr "" + +#: ../../extend/addon/addon/adultphotoflag/adultphotoflag.php:25 +msgid "" +"Provide photo edit option to hide inappropriate photos from default album " +"view" +msgstr "" + +#: ../../extend/addon/addon/chords/Mod_Chords.php:44 +msgid "" +"This is a fairly comprehensive and complete guitar chord dictionary which " +"will list most of the available ways to play a certain chord, starting from " +"the base of the fingerboard up to a few frets beyond the twelfth fret " +"(beyond which everything repeats). A couple of non-standard tunings are " +"provided for the benefit of slide players, etc." +======= +#: ../../boot.php:1162 ../../addon/opensearch/opensearch.php:26 #, php-format msgctxt "opensearch" msgid "Search %1$s (%2$s)" msgstr "" -#: ../../boot.php:1164 ../../addon/opensearch/opensearch.php:28 +#: ../../boot.php:1162 ../../addon/opensearch/opensearch.php:28 msgctxt "opensearch" msgid "$Projectname" msgstr "" -#: ../../boot.php:1611 +#: ../../boot.php:1609 msgid "Create an account to access services and applications" msgstr "" -#: ../../boot.php:1630 ../../include/nav.php:103 ../../include/nav.php:127 +#: ../../boot.php:1628 ../../include/nav.php:103 ../../include/nav.php:127 msgid "Logout" msgstr "" -#: ../../boot.php:1633 +#: ../../boot.php:1631 msgid "Login/Email" msgstr "" -#: ../../boot.php:1634 +#: ../../boot.php:1632 msgid "Password" msgstr "" -#: ../../boot.php:1635 +#: ../../boot.php:1633 msgid "Remember me" msgstr "" -#: ../../boot.php:1638 +#: ../../boot.php:1636 msgid "Forgot your password?" msgstr "" -#: ../../boot.php:2176 +#: ../../boot.php:2174 msgid "toggle mobile" msgstr "" -#: ../../boot.php:2329 +#: ../../boot.php:2327 #, php-format msgid "[$Projectname] Website SSL error for %s" msgstr "" -#: ../../boot.php:2334 +#: ../../boot.php:2332 msgid "Website SSL certificate is not valid. Please correct." msgstr "" -#: ../../boot.php:2452 +#: ../../boot.php:2450 #, php-format msgid "[$Projectname] Cron tasks not running on %s" msgstr "" -#: ../../boot.php:2457 +#: ../../boot.php:2455 msgid "Cron/Scheduled tasks not running." msgstr "" -#: ../../boot.php:2458 ../../include/datetime.php:286 +#: ../../boot.php:2456 ../../include/datetime.php:286 msgid "never" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../view/theme/redbasic/php/config.php:16 -#: ../../view/theme/redbasic/php/config.php:19 -msgid "Focus (Hubzilla default)" +#: ../../extend/addon/addon/chords/Mod_Chords.php:46 +msgid "" +"Chord names start with a root note (A-G) and may include sharps (#) and " +"flats (b). This software will parse most of the standard naming conventions " +"such as maj, min, dim, sus(2 or 4), aug, with optional repeating elements." msgstr "" -#: ../../view/theme/redbasic/php/config.php:99 -msgid "Theme settings" +#: ../../extend/addon/addon/chords/Mod_Chords.php:48 +msgid "" +"Valid examples include A, A7, Am7, Amaj7, Amaj9, Ammaj7, Aadd4, Asus2Add4, " +"E7b13b11 ..." msgstr "" -#: ../../view/theme/redbasic/php/config.php:100 -msgid "Narrow navbar" +#: ../../extend/addon/addon/chords/Mod_Chords.php:51 +msgid "Guitar Chords" msgstr "" -#: ../../view/theme/redbasic/php/config.php:101 -msgid "Navigation bar background color" +#: ../../extend/addon/addon/chords/Mod_Chords.php:52 +msgid "The complete online chord dictionary" msgstr "" -#: ../../view/theme/redbasic/php/config.php:102 -msgid "Navigation bar icon color " +#: ../../extend/addon/addon/chords/Mod_Chords.php:57 +msgid "Tuning" msgstr "" -#: ../../view/theme/redbasic/php/config.php:103 -msgid "Navigation bar active icon color " +#: ../../extend/addon/addon/chords/Mod_Chords.php:58 +msgid "Chord name: example: Em7" msgstr "" -#: ../../view/theme/redbasic/php/config.php:104 -msgid "Link color" +#: ../../extend/addon/addon/chords/Mod_Chords.php:59 +msgid "Show for left handed stringing" msgstr "" -#: ../../view/theme/redbasic/php/config.php:105 -msgid "Set font-color for banner" +#: ../../extend/addon/addon/chords/chords.php:33 +msgid "Quick Reference" msgstr "" -#: ../../view/theme/redbasic/php/config.php:106 -msgid "Set the background color" +#: ../../extend/addon/addon/dirstats/dirstats.php:94 +msgid "Hubzilla Directory Stats" msgstr "" -#: ../../view/theme/redbasic/php/config.php:107 -msgid "Set the background image" +#: ../../extend/addon/addon/dirstats/dirstats.php:95 +msgid "Total Hubs" msgstr "" -#: ../../view/theme/redbasic/php/config.php:108 -msgid "Set the background color of items" +#: ../../extend/addon/addon/dirstats/dirstats.php:97 +msgid "Hubzilla Hubs" msgstr "" -#: ../../view/theme/redbasic/php/config.php:109 -msgid "Set the background color of comments" +#: ../../extend/addon/addon/dirstats/dirstats.php:99 +msgid "Friendica Hubs" msgstr "" -#: ../../view/theme/redbasic/php/config.php:110 -msgid "Set font-size for the entire application" +#: ../../extend/addon/addon/dirstats/dirstats.php:101 +msgid "Diaspora Pods" msgstr "" -#: ../../view/theme/redbasic/php/config.php:110 +<<<<<<< HEAD +#: ../../extend/addon/addon/dirstats/dirstats.php:103 +msgid "Hubzilla Channels" +======= +#: ../../view/theme/redbasic/php/config.php:99 msgid "Examples: 1rem, 100%, 16px" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../view/theme/redbasic/php/config.php:111 -msgid "Set font-color for posts and comments" +#: ../../extend/addon/addon/dirstats/dirstats.php:105 +msgid "Friendica Channels" msgstr "" -#: ../../view/theme/redbasic/php/config.php:112 -msgid "Set radius of corners" +#: ../../extend/addon/addon/dirstats/dirstats.php:107 +msgid "Diaspora Channels" msgstr "" -#: ../../view/theme/redbasic/php/config.php:112 -msgid "Example: 4px" +#: ../../extend/addon/addon/dirstats/dirstats.php:109 +msgid "Aged 35 and above" msgstr "" -#: ../../view/theme/redbasic/php/config.php:113 -msgid "Set shadow depth of photos" +#: ../../extend/addon/addon/dirstats/dirstats.php:111 +msgid "Aged 34 and under" msgstr "" -#: ../../view/theme/redbasic/php/config.php:114 -msgid "Set maximum width of content region in pixel" +#: ../../extend/addon/addon/dirstats/dirstats.php:113 +msgid "Average Age" msgstr "" -#: ../../view/theme/redbasic/php/config.php:114 -msgid "Leave empty for default width" +#: ../../extend/addon/addon/dirstats/dirstats.php:115 +msgid "Known Chatrooms" msgstr "" -#: ../../view/theme/redbasic/php/config.php:115 -msgid "Left align page content" +#: ../../extend/addon/addon/dirstats/dirstats.php:117 +msgid "Known Tags" msgstr "" -#: ../../view/theme/redbasic/php/config.php:116 -msgid "Set size of conversation author photo" +#: ../../extend/addon/addon/dirstats/dirstats.php:119 +msgid "" +"Please note Diaspora and Friendica statistics are merely those **this " +"directory** is aware of, and not all those known in the network. This also " +"applies to chatrooms," msgstr "" -#: ../../view/theme/redbasic/php/config.php:117 -msgid "Set size of followup author photos" +#: ../../extend/addon/addon/donate/donate.php:21 +msgid "Project Servers and Resources" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:57 -msgid "Errors encountered deleting database table " +#: ../../extend/addon/addon/donate/donate.php:22 +msgid "Project Creator and Tech Lead" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:95 ../../addon/twitter/twitter.php:773 -msgid "Submit Settings" +#: ../../extend/addon/addon/donate/donate.php:23 +msgid "Admin, developer, directorymin, support bloke" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:96 -msgid "Drop tables when uninstalling?" +#: ../../extend/addon/addon/donate/donate.php:50 +msgid "" +"And the hundreds of other people and organisations who helped make the " +"Hubzilla possible." msgstr "" -#: ../../addon/rendezvous/rendezvous.php:96 +#: ../../extend/addon/addon/donate/donate.php:53 msgid "" -"If checked, the Rendezvous database tables will be deleted when the plugin " -"is uninstalled." +"The Redmatrix/Hubzilla projects are provided primarily by volunteers giving " +"their time and expertise - and often paying out of pocket for services they " +"share with others." msgstr "" -#: ../../addon/rendezvous/rendezvous.php:97 -msgid "Mapbox Access Token" +#: ../../extend/addon/addon/donate/donate.php:54 +msgid "" +"There is no corporate funding and no ads, and we do not collect and sell " +"your personal information. (We don't control your personal information - " +"<strong>you do</strong>.)" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:97 +#: ../../extend/addon/addon/donate/donate.php:55 msgid "" -"If you enter a Mapbox access token, it will be used to retrieve map tiles " -"from Mapbox instead of the default OpenStreetMap tile server." +"Help support our ground-breaking work in decentralisation, web identity, and " +"privacy." msgstr "" -#: ../../addon/rendezvous/rendezvous.php:162 -msgid "Rendezvous" +#: ../../extend/addon/addon/donate/donate.php:57 +msgid "" +"Your donations keep servers and services running and also helps us to " +"provide innovative new features and continued development." msgstr "" -#: ../../addon/rendezvous/rendezvous.php:167 +#: ../../extend/addon/addon/donate/donate.php:60 +msgid "Donate" +msgstr "" + +#: ../../extend/addon/addon/donate/donate.php:62 msgid "" -"This identity has been deleted by another member due to inactivity. Please " -"press the \"New identity\" button or refresh the page to register a new " -"identity. You may use the same name." +"Choose a project, developer, or public hub to support with a one-time " +"donation" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:168 -msgid "Welcome to Rendezvous!" +#: ../../extend/addon/addon/donate/donate.php:63 +msgid "Donate Now" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:169 +#: ../../extend/addon/addon/donate/donate.php:64 msgid "" -"Enter your name to join this rendezvous. To begin sharing your location with " -"the other members, tap the GPS control. When your location is discovered, a " -"red dot will appear and others will be able to see you on the map." +"<strong><em>Or</em></strong> become a project sponsor (Hubzilla Project only)" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:171 -msgid "Let's meet here" +#: ../../extend/addon/addon/donate/donate.php:65 +msgid "" +"Please indicate if you would like your first name or full name (or nothing) " +"to appear in our sponsor listing" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:174 -msgid "New marker" +#: ../../extend/addon/addon/donate/donate.php:66 +msgid "Sponsor" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:175 -msgid "Edit marker" +#: ../../extend/addon/addon/donate/donate.php:69 +msgid "Special thanks to: " msgstr "" -#: ../../addon/rendezvous/rendezvous.php:176 -msgid "New identity" +#: ../../extend/addon/addon/dwpost/dwpost.php:42 +msgid "Post to Dreamwidth" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:177 -msgid "Delete marker" +#: ../../extend/addon/addon/dwpost/dwpost.php:73 +msgid "Enable Dreamwidth Post Plugin" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:178 -msgid "Delete member" +#: ../../extend/addon/addon/dwpost/dwpost.php:77 +msgid "Dreamwidth username" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:179 -msgid "Edit proximity alert" +#: ../../extend/addon/addon/dwpost/dwpost.php:81 +msgid "Dreamwidth password" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:180 -msgid "" -"A proximity alert will be issued when this member is within a certain radius " -"of you.<br><br>Enter a radius in meters (0 to disable):" +#: ../../extend/addon/addon/dwpost/dwpost.php:85 +msgid "Post to Dreamwidth by default" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:180 -#: ../../addon/rendezvous/rendezvous.php:185 -msgid "distance" +#: ../../extend/addon/addon/dwpost/dwpost.php:89 +msgid "Dreamwidth Post Settings" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:181 -msgid "Proximity alert distance (meters)" +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:45 +msgid "Flattr this!" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:182 -#: ../../addon/rendezvous/rendezvous.php:184 -msgid "" -"A proximity alert will be issued when you are within a certain radius of the " -"marker location.<br><br>Enter a radius in meters (0 to disable):" +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:83 +msgid "Flattr widget settings updated." msgstr "" -#: ../../addon/rendezvous/rendezvous.php:183 -msgid "Marker proximity alert" +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:100 +msgid "Flattr user" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:186 -msgid "Reminder note" +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:104 +msgid "URL of the Thing to flattr" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:187 -msgid "" -"Enter a note to be displayed when you are within the specified proximity..." +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:104 +msgid "If empty channel URL is used" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:199 -msgid "Add new rendezvous" +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:108 +msgid "Title of the Thing to flattr" msgstr "" -#: ../../addon/rendezvous/rendezvous.php:200 -msgid "" -"Create a new rendezvous and share the access link with those you wish to " -"invite to the group. Those who open the link become members of the " -"rendezvous. They can view other member locations, add markers to the map, or " -"share their own locations with the group." +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:108 +msgid "If empty \"channel name on The Hubzilla\" will be used" msgstr "" -#: ../../addon/skeleton/skeleton.php:59 -msgid "Some setting" +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:112 +msgid "Static or dynamic flattr button" msgstr "" -#: ../../addon/skeleton/skeleton.php:61 -msgid "A setting" +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:112 +msgid "static" msgstr "" -#: ../../addon/skeleton/skeleton.php:64 -msgid "Skeleton Settings" +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:112 +msgid "dynamic" +msgstr "" + +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:116 +msgid "Alignment of the widget" +msgstr "" + +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:116 +msgid "left" +msgstr "" + +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:116 +msgid "right" +msgstr "" + +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:120 +msgid "Enable Flattr widget" +msgstr "" + +#: ../../extend/addon/addon/flattrwidget/flattrwidget.php:124 +msgid "Flattr Widget Settings" +msgstr "" + +#: ../../extend/addon/addon/frphotos/frphotos.php:91 +msgid "Friendica Photo Album Import" +msgstr "" + +#: ../../extend/addon/addon/frphotos/frphotos.php:92 +msgid "This will import all your Friendica photo albums to this Red channel." +msgstr "" + +#: ../../extend/addon/addon/frphotos/frphotos.php:93 +msgid "Friendica Server base URL" msgstr "" -#: ../../addon/gnusoc/gnusoc.php:170 +#: ../../extend/addon/addon/frphotos/frphotos.php:94 +msgid "Friendica Login Username" +msgstr "" + +<<<<<<< HEAD +#: ../../extend/addon/addon/frphotos/frphotos.php:95 +msgid "Friendica Login Password" +msgstr "" + +#: ../../extend/addon/addon/hubwall/hubwall.php:19 +msgid "Send email to all members" +msgstr "" + +#: ../../extend/addon/addon/hubwall/hubwall.php:33 +#, php-format +msgid "$1%s Administrator" +msgstr "" + +#: ../../extend/addon/addon/hubwall/hubwall.php:50 +#: ../../extend/addon/addon/mailtest/mailtest.php:50 +msgid "No recipients found." +msgstr "" + +#: ../../extend/addon/addon/hubwall/hubwall.php:73 +======= +#: ../../addon/gnusoc/gnusoc.php:119 msgid "GNU-Social Protocol Settings updated." msgstr "" -#: ../../addon/gnusoc/gnusoc.php:181 +#: ../../addon/gnusoc/gnusoc.php:130 msgid "Enable the GNU-Social protocol for this channel" msgstr "" -#: ../../addon/gnusoc/gnusoc.php:185 +#: ../../addon/gnusoc/gnusoc.php:134 msgid "GNU-Social Protocol Settings" msgstr "" -#: ../../addon/gnusoc/gnusoc.php:376 +#: ../../addon/gnusoc/gnusoc.php:324 msgid "Follow" msgstr "" -#: ../../addon/gnusoc/gnusoc.php:379 +#: ../../addon/gnusoc/gnusoc.php:327 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 #, php-format -msgid "%1$s is now following %2$s" +msgid "%1$d of %2$d messages sent." msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:744 -msgid "INVALID EVENT DISMISSED!" +#: ../../extend/addon/addon/hubwall/hubwall.php:81 +msgid "Send email to all hub members." msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:745 -msgid "Summary: " +#: ../../extend/addon/addon/hubwall/hubwall.php:92 +#: ../../extend/addon/addon/mailtest/mailtest.php:96 +msgid "Message subject" msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:746 -msgid "Date: " +#: ../../extend/addon/addon/hubwall/hubwall.php:93 +msgid "Sender Email address" msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:747 ../../addon/cdav/Mod_Cdav.php:754 -msgid "Reason: " +#: ../../extend/addon/addon/hubwall/hubwall.php:94 +msgid "Test mode (only send to hub administrator)" msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:752 -msgid "INVALID CARD DISMISSED!" +#: ../../extend/addon/addon/ijpost/ijpost.php:42 +msgid "Post to Insanejournal" msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:753 -msgid "Name: " +#: ../../extend/addon/addon/ijpost/ijpost.php:73 +msgid "Enable InsaneJournal Post Plugin" msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:770 -msgid "" -"You have to enable this plugin in Feature/Addon Settings > CalDAV/CardDAV " -"Settings before you can use it." +#: ../../extend/addon/addon/ijpost/ijpost.php:77 +msgid "InsaneJournal username" msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:836 ../../addon/cdav/Mod_Cdav.php:837 -msgid "Example: YYYY-MM-DD HH:mm" +#: ../../extend/addon/addon/ijpost/ijpost.php:81 +msgid "InsaneJournal password" msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:837 -msgid "End date and time" +#: ../../extend/addon/addon/ijpost/ijpost.php:85 +msgid "Post to InsaneJournal by default" msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:852 -msgid "List month" +#: ../../extend/addon/addon/ijpost/ijpost.php:89 +msgid "InsaneJournal Post Settings" msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:853 -msgid "List week" +#: ../../extend/addon/addon/ijpost/ijpost.php:104 +msgid "Insane Journal Settings saved." msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:854 -msgid "List day" +#: ../../extend/addon/addon/irc/irc.php:45 +msgid "Channels to auto connect" msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:861 -msgid "More" +#: ../../extend/addon/addon/irc/irc.php:45 +#: ../../extend/addon/addon/irc/irc.php:49 +msgid "Comma separated list" msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:862 -msgid "Less" +#: ../../extend/addon/addon/irc/irc.php:49 +#: ../../extend/addon/addon/irc/irc.php:96 +msgid "Popular Channels" msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:863 -msgid "Select calendar" +#: ../../extend/addon/addon/irc/irc.php:53 +msgid "IRC Settings" msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:865 -msgid "Delete all" +#: ../../extend/addon/addon/irc/irc.php:69 +msgid "IRC settings saved." msgstr "" -#: ../../addon/cdav/Mod_Cdav.php:867 -msgid "Sorry! Editing of recurrent events is not yet implemented." +#: ../../extend/addon/addon/irc/irc.php:74 +msgid "IRC Chatroom" msgstr "" -#: ../../addon/cdav/cdav.php:36 -msgid "Errors encountered creating database table: " +#: ../../extend/addon/addon/jappixmini/jappixmini.php:305 +#: ../../include/channel.php:1138 ../../include/channel.php:1275 +msgid "Status:" msgstr "" -#: ../../addon/cdav/cdav.php:197 -msgid "Default Calendar" +#: ../../extend/addon/addon/jappixmini/jappixmini.php:309 +msgid "Activate addon" msgstr "" -#: ../../addon/cdav/cdav.php:206 -msgid "Default Addressbook" +#: ../../extend/addon/addon/jappixmini/jappixmini.php:313 +msgid "Hide Jappixmini Chat-Widget from the webinterface" msgstr "" -#: ../../addon/cdav/cdav.php:215 -msgid "CalDAV/CardDAV Settings saved." +#: ../../extend/addon/addon/jappixmini/jappixmini.php:318 +msgid "Jabber username" msgstr "" -#: ../../addon/cdav/cdav.php:234 -msgid "Enable CalDAV/CardDAV Server for this channel" +#: ../../extend/addon/addon/jappixmini/jappixmini.php:324 +msgid "Jabber server" msgstr "" -#: ../../addon/cdav/cdav.php:237 -#, php-format -msgid "Your CalDAV resources are located at %s " +#: ../../extend/addon/addon/jappixmini/jappixmini.php:330 +msgid "Jabber BOSH host URL" msgstr "" -#: ../../addon/cdav/cdav.php:240 -#, php-format -msgid "Your CardDAV resources are located at %s " +#: ../../extend/addon/addon/jappixmini/jappixmini.php:337 +msgid "Jabber password" msgstr "" -#: ../../addon/cdav/cdav.php:246 -msgid "CalDAV/CardDAV Settings" +#: ../../extend/addon/addon/jappixmini/jappixmini.php:343 +msgid "Encrypt Jabber password with Hubzilla password" msgstr "" -#: ../../addon/cdav/cdav.php:272 ../../include/connections.php:676 -msgid "Home, Voice" +#: ../../extend/addon/addon/jappixmini/jappixmini.php:347 +#: ../../extend/addon/addon/redred/redred.php:115 +msgid "Hubzilla password" msgstr "" -#: ../../addon/cdav/cdav.php:273 ../../include/connections.php:677 -msgid "Home, Fax" +#: ../../extend/addon/addon/jappixmini/jappixmini.php:351 +#: ../../extend/addon/addon/jappixmini/jappixmini.php:355 +msgid "Approve subscription requests from Hubzilla contacts automatically" msgstr "" -#: ../../addon/cdav/cdav.php:275 ../../include/connections.php:679 -msgid "Work, Voice" +#: ../../extend/addon/addon/jappixmini/jappixmini.php:359 +msgid "Purge internal list of jabber addresses of contacts" msgstr "" -#: ../../addon/cdav/cdav.php:276 ../../include/connections.php:680 -msgid "Work, Fax" +#: ../../extend/addon/addon/jappixmini/jappixmini.php:364 +msgid "Configuration Help" msgstr "" -#: ../../addon/cdav/include/widgets.php:37 -msgid "Select Channel" +#: ../../extend/addon/addon/jappixmini/jappixmini.php:371 +msgid "Jappix Mini Settings" msgstr "" -#: ../../addon/cdav/include/widgets.php:42 -msgid "Read-write" +#: ../../extend/addon/addon/js_upload/js_upload.php:44 +msgid "Upload a file" msgstr "" -#: ../../addon/cdav/include/widgets.php:43 -msgid "Read-only" +#: ../../extend/addon/addon/js_upload/js_upload.php:45 +msgid "Drop files here to upload" msgstr "" -#: ../../addon/cdav/include/widgets.php:116 -msgid "My Calendars" +#: ../../extend/addon/addon/js_upload/js_upload.php:47 +msgid "Failed" msgstr "" -#: ../../addon/cdav/include/widgets.php:118 -msgid "Shared Calendars" +#: ../../extend/addon/addon/js_upload/js_upload.php:315 +msgid "No files were uploaded." msgstr "" -#: ../../addon/cdav/include/widgets.php:122 -msgid "Share this calendar" +#: ../../extend/addon/addon/js_upload/js_upload.php:322 +msgid "Uploaded file is empty" msgstr "" -#: ../../addon/cdav/include/widgets.php:124 -msgid "Calendar name and color" +#: ../../extend/addon/addon/js_upload/js_upload.php:335 +msgid "Image exceeds size limit of " msgstr "" -#: ../../addon/cdav/include/widgets.php:126 -msgid "Create new calendar" +#: ../../extend/addon/addon/js_upload/js_upload.php:347 +msgid "File has an invalid extension, it should be one of " msgstr "" -#: ../../addon/cdav/include/widgets.php:128 -msgid "Calendar Name" +#: ../../extend/addon/addon/js_upload/js_upload.php:359 +msgid "Upload was cancelled, or server error encountered" msgstr "" -#: ../../addon/cdav/include/widgets.php:129 -msgid "Calendar Tools" +#: ../../extend/addon/addon/ldapauth/ldapauth.php:61 +msgid "An account has been created for you." msgstr "" -#: ../../addon/cdav/include/widgets.php:130 -msgid "Import calendar" +#: ../../extend/addon/addon/ldapauth/ldapauth.php:68 +msgid "Authentication successful but rejected: account creation is disabled." msgstr "" -#: ../../addon/cdav/include/widgets.php:131 -msgid "Select a calendar to import to" +#: ../../extend/addon/addon/libertree/libertree.php:38 +msgid "Post to Libertree" msgstr "" -#: ../../addon/cdav/include/widgets.php:158 -msgid "Addressbooks" +#: ../../extend/addon/addon/libertree/libertree.php:69 +msgid "Enable Libertree Post Plugin" msgstr "" -#: ../../addon/cdav/include/widgets.php:160 -msgid "Addressbook name" +#: ../../extend/addon/addon/libertree/libertree.php:73 +msgid "Libertree API token" msgstr "" -#: ../../addon/cdav/include/widgets.php:162 -msgid "Create new addressbook" +#: ../../extend/addon/addon/libertree/libertree.php:77 +msgid "Libertree site URL" msgstr "" -#: ../../addon/cdav/include/widgets.php:163 -msgid "Addressbook Name" +#: ../../extend/addon/addon/libertree/libertree.php:81 +msgid "Post to Libertree by default" msgstr "" -#: ../../addon/cdav/include/widgets.php:165 -msgid "Addressbook Tools" +#: ../../extend/addon/addon/libertree/libertree.php:85 +msgid "Libertree Post Settings" msgstr "" -#: ../../addon/cdav/include/widgets.php:166 -msgid "Import addressbook" +#: ../../extend/addon/addon/libertree/libertree.php:99 +msgid "Libertree Settings saved." msgstr "" -#: ../../addon/cdav/include/widgets.php:167 -msgid "Select an addressbook to import to" +#: ../../extend/addon/addon/ljpost/ljpost.php:42 +msgid "Post to LiveJournal" msgstr "" -#: ../../addon/planets/planets.php:121 -msgid "Planets Settings updated." +#: ../../extend/addon/addon/ljpost/ljpost.php:70 +msgid "Enable LiveJournal Post Plugin" msgstr "" -#: ../../addon/planets/planets.php:153 -msgid "Enable Planets Plugin" +#: ../../extend/addon/addon/ljpost/ljpost.php:74 +msgid "LiveJournal username" msgstr "" -#: ../../addon/planets/planets.php:157 -msgid "Planets Settings" +#: ../../extend/addon/addon/ljpost/ljpost.php:78 +msgid "LiveJournal password" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:50 -#: ../../addon/openclipatar/openclipatar.php:128 -msgid "System defaults:" +#: ../../extend/addon/addon/ljpost/ljpost.php:82 +msgid "Post to LiveJournal by default" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:54 -msgid "Preferred Clipart IDs" +#: ../../extend/addon/addon/ljpost/ljpost.php:86 +msgid "LiveJournal Post Settings" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:54 -msgid "List of preferred clipart ids. These will be shown first." +#: ../../extend/addon/addon/ljpost/ljpost.php:101 +msgid "LiveJournal Settings saved." msgstr "" -#: ../../addon/openclipatar/openclipatar.php:55 -msgid "Default Search Term" +#: ../../extend/addon/addon/logrot/logrot.php:36 +msgid "Logfile archive directory" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:55 -msgid "The default search term. These will be shown second." +#: ../../extend/addon/addon/logrot/logrot.php:36 +msgid "Directory to store rotated logs" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:56 -msgid "Return After" +#: ../../extend/addon/addon/logrot/logrot.php:37 +msgid "Logfile size in bytes before rotating" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:56 -msgid "Page to load after image selection." +#: ../../extend/addon/addon/logrot/logrot.php:38 +msgid "Number of logfiles to retain" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:58 ../../include/channel.php:1062 +<<<<<<< HEAD +#: ../../extend/addon/addon/mailhost/mailhost.php:36 +msgid "Email notification hub" +======= +#: ../../addon/openclipatar/openclipatar.php:58 ../../include/channel.php:1048 #: ../../include/nav.php:111 msgid "Edit Profile" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../addon/openclipatar/openclipatar.php:59 -msgid "Profile List" +#: ../../extend/addon/addon/mailhost/mailhost.php:36 +msgid "Hostname" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:61 -msgid "Order of Preferred" +#: ../../extend/addon/addon/mailhost/mailhost.php:40 +msgid "Mailhost Settings" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:61 -msgid "Sort order of preferred clipart ids." +#: ../../extend/addon/addon/mailhost/mailhost.php:54 +msgid "MAILHOST Settings saved." msgstr "" -#: ../../addon/openclipatar/openclipatar.php:62 -#: ../../addon/openclipatar/openclipatar.php:68 -msgid "Newest first" +#: ../../extend/addon/addon/moremoods/moremoods.php:19 +msgid "lonely" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:65 -msgid "As entered" +#: ../../extend/addon/addon/moremoods/moremoods.php:20 +msgid "drunk" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:67 -msgid "Order of other" +#: ../../extend/addon/addon/moremoods/moremoods.php:21 +msgid "horny" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:67 -msgid "Sort order of other clipart ids." +#: ../../extend/addon/addon/moremoods/moremoods.php:22 +msgid "stoned" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:69 -msgid "Most downloaded first" +#: ../../extend/addon/addon/moremoods/moremoods.php:23 +msgid "fucked up" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:70 -msgid "Most liked first" +#: ../../extend/addon/addon/moremoods/moremoods.php:24 +msgid "clusterfucked" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:72 -msgid "Preferred IDs Message" +#: ../../extend/addon/addon/moremoods/moremoods.php:25 +msgid "crazy" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:72 -msgid "Message to display above preferred results." +#: ../../extend/addon/addon/moremoods/moremoods.php:26 +msgid "hurt" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:78 -msgid "Uploaded by: " +#: ../../extend/addon/addon/moremoods/moremoods.php:27 +msgid "sleepy" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:78 -msgid "Drawn by: " +#: ../../extend/addon/addon/moremoods/moremoods.php:28 +msgid "grumpy" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:192 -msgid "Or select from a free OpenClipart.org image:" +#: ../../extend/addon/addon/moremoods/moremoods.php:29 +msgid "high" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:195 -msgid "Search Term" +#: ../../extend/addon/addon/moremoods/moremoods.php:30 +msgid "semi-conscious" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:232 -msgid "Unknown error. Please try again later." +#: ../../extend/addon/addon/moremoods/moremoods.php:31 +msgid "in love" msgstr "" -#: ../../addon/openclipatar/openclipatar.php:308 -msgid "Profile photo updated successfully." +#: ../../extend/addon/addon/moremoods/moremoods.php:32 +msgid "in lust" msgstr "" -#: ../../addon/adultphotoflag/adultphotoflag.php:24 -msgid "Flag Adult Photos" +#: ../../extend/addon/addon/moremoods/moremoods.php:33 +msgid "naked" msgstr "" -#: ../../addon/adultphotoflag/adultphotoflag.php:25 -msgid "" -"Provide photo edit option to hide inappropriate photos from default album " -"view" +#: ../../extend/addon/addon/moremoods/moremoods.php:34 +msgid "stinky" msgstr "" -#: ../../addon/wppost/wppost.php:45 -msgid "Post to WordPress" +#: ../../extend/addon/addon/moremoods/moremoods.php:35 +msgid "sweaty" msgstr "" -#: ../../addon/wppost/wppost.php:82 -msgid "Enable WordPress Post Plugin" +#: ../../extend/addon/addon/moremoods/moremoods.php:36 +msgid "bleeding out" msgstr "" -#: ../../addon/wppost/wppost.php:86 -msgid "WordPress username" +#: ../../extend/addon/addon/moremoods/moremoods.php:37 +msgid "victorious" msgstr "" -#: ../../addon/wppost/wppost.php:90 -msgid "WordPress password" +#: ../../extend/addon/addon/moremoods/moremoods.php:38 +msgid "defeated" msgstr "" -#: ../../addon/wppost/wppost.php:94 -msgid "WordPress API URL" +#: ../../extend/addon/addon/moremoods/moremoods.php:39 +msgid "envious" msgstr "" -#: ../../addon/wppost/wppost.php:95 -msgid "Typically https://your-blog.tld/xmlrpc.php" +#: ../../extend/addon/addon/moremoods/moremoods.php:40 +msgid "jealous" msgstr "" -#: ../../addon/wppost/wppost.php:98 -msgid "WordPress blogid" +#: ../../extend/addon/addon/morepokes/morepokes.php:19 +msgid "bitchslap" msgstr "" -#: ../../addon/wppost/wppost.php:99 -msgid "For multi-user sites such as wordpress.com, otherwise leave blank" +#: ../../extend/addon/addon/morepokes/morepokes.php:19 +msgid "bitchslapped" msgstr "" -#: ../../addon/wppost/wppost.php:105 -msgid "Post to WordPress by default" +#: ../../extend/addon/addon/morepokes/morepokes.php:20 +msgid "shag" msgstr "" -#: ../../addon/wppost/wppost.php:109 -msgid "Forward comments (requires hubzilla_wp plugin)" +#: ../../extend/addon/addon/morepokes/morepokes.php:20 +msgid "shagged" msgstr "" -#: ../../addon/wppost/wppost.php:113 -msgid "WordPress Post Settings" +#: ../../extend/addon/addon/morepokes/morepokes.php:21 +msgid "patent" msgstr "" -#: ../../addon/wppost/wppost.php:129 -msgid "Wordpress Settings saved." +#: ../../extend/addon/addon/morepokes/morepokes.php:21 +msgid "patented" msgstr "" -#: ../../addon/nsfw/nsfw.php:80 -msgid "" -"This plugin looks in posts for the words/text you specify below, and " -"collapses any content containing those keywords so it is not displayed at " -"inappropriate times, such as sexual innuendo that may be improper in a work " -"setting. It is polite and recommended to tag any content containing nudity " -"with #NSFW. This filter can also match any other word/text you specify, and " -"can thereby be used as a general purpose content filter." +#: ../../extend/addon/addon/morepokes/morepokes.php:22 +msgid "hug" msgstr "" -#: ../../addon/nsfw/nsfw.php:84 -msgid "Enable Content filter" +#: ../../extend/addon/addon/morepokes/morepokes.php:22 +msgid "hugged" msgstr "" -#: ../../addon/nsfw/nsfw.php:88 -msgid "Comma separated list of keywords to hide" +#: ../../extend/addon/addon/morepokes/morepokes.php:23 +msgid "murder" msgstr "" -#: ../../addon/nsfw/nsfw.php:88 -msgid "Word, /regular-expression/, lang=xx, lang!=xx" +#: ../../extend/addon/addon/morepokes/morepokes.php:23 +msgid "murdered" msgstr "" -#: ../../addon/nsfw/nsfw.php:92 -msgid "Not Safe For Work Settings" +#: ../../extend/addon/addon/morepokes/morepokes.php:24 +msgid "worship" msgstr "" -#: ../../addon/nsfw/nsfw.php:92 -msgid "General Purpose Content Filter" +#: ../../extend/addon/addon/morepokes/morepokes.php:24 +msgid "worshipped" msgstr "" -#: ../../addon/nsfw/nsfw.php:110 -msgid "NSFW Settings saved." +#: ../../extend/addon/addon/morepokes/morepokes.php:25 +msgid "kiss" msgstr "" -#: ../../addon/nsfw/nsfw.php:207 -msgid "Possible adult content" +#: ../../extend/addon/addon/morepokes/morepokes.php:25 +msgid "kissed" msgstr "" -#: ../../addon/nsfw/nsfw.php:211 -#, php-format -msgid "%s - view" +#: ../../extend/addon/addon/morepokes/morepokes.php:26 +msgid "tempt" msgstr "" -#: ../../addon/ijpost/ijpost.php:42 -msgid "Post to Insanejournal" +#: ../../extend/addon/addon/morepokes/morepokes.php:26 +msgid "tempted" msgstr "" -#: ../../addon/ijpost/ijpost.php:73 -msgid "Enable InsaneJournal Post Plugin" +#: ../../extend/addon/addon/morepokes/morepokes.php:27 +msgid "raise eyebrows at" msgstr "" -#: ../../addon/ijpost/ijpost.php:77 -msgid "InsaneJournal username" +#: ../../extend/addon/addon/morepokes/morepokes.php:27 +msgid "raised their eyebrows at" msgstr "" -#: ../../addon/ijpost/ijpost.php:81 -msgid "InsaneJournal password" +#: ../../extend/addon/addon/morepokes/morepokes.php:28 +msgid "insult" msgstr "" -#: ../../addon/ijpost/ijpost.php:85 -msgid "Post to InsaneJournal by default" +#: ../../extend/addon/addon/morepokes/morepokes.php:28 +msgid "insulted" msgstr "" -#: ../../addon/ijpost/ijpost.php:89 -msgid "InsaneJournal Post Settings" +#: ../../extend/addon/addon/morepokes/morepokes.php:29 +msgid "praise" msgstr "" -#: ../../addon/ijpost/ijpost.php:104 -msgid "Insane Journal Settings saved." +#: ../../extend/addon/addon/morepokes/morepokes.php:29 +msgid "praised" msgstr "" -#: ../../addon/js_upload/js_upload.php:44 -msgid "Upload a file" +#: ../../extend/addon/addon/morepokes/morepokes.php:30 +msgid "be dubious of" msgstr "" -#: ../../addon/js_upload/js_upload.php:45 -msgid "Drop files here to upload" +#: ../../extend/addon/addon/morepokes/morepokes.php:30 +msgid "was dubious of" msgstr "" -#: ../../addon/js_upload/js_upload.php:47 -msgid "Failed" +#: ../../extend/addon/addon/morepokes/morepokes.php:31 +msgid "eat" msgstr "" -#: ../../addon/js_upload/js_upload.php:315 -msgid "No files were uploaded." +#: ../../extend/addon/addon/morepokes/morepokes.php:31 +msgid "ate" msgstr "" -#: ../../addon/js_upload/js_upload.php:322 -msgid "Uploaded file is empty" +#: ../../extend/addon/addon/morepokes/morepokes.php:32 +msgid "giggle and fawn at" msgstr "" -#: ../../addon/js_upload/js_upload.php:335 -msgid "Image exceeds size limit of " +#: ../../extend/addon/addon/morepokes/morepokes.php:32 +msgid "giggled and fawned at" msgstr "" -#: ../../addon/js_upload/js_upload.php:347 -msgid "File has an invalid extension, it should be one of " +#: ../../extend/addon/addon/morepokes/morepokes.php:33 +msgid "doubt" msgstr "" -#: ../../addon/js_upload/js_upload.php:359 -msgid "Upload was cancelled, or server error encountered" +#: ../../extend/addon/addon/morepokes/morepokes.php:33 +msgid "doubted" msgstr "" -#: ../../addon/dwpost/dwpost.php:42 -msgid "Post to Dreamwidth" +#: ../../extend/addon/addon/morepokes/morepokes.php:34 +msgid "glare" msgstr "" -#: ../../addon/dwpost/dwpost.php:73 -msgid "Enable Dreamwidth Post Plugin" +#: ../../extend/addon/addon/morepokes/morepokes.php:34 +msgid "glared at" msgstr "" -#: ../../addon/dwpost/dwpost.php:77 -msgid "Dreamwidth username" +#: ../../extend/addon/addon/morepokes/morepokes.php:35 +msgid "fuck" msgstr "" -#: ../../addon/dwpost/dwpost.php:81 -msgid "Dreamwidth password" +#: ../../extend/addon/addon/morepokes/morepokes.php:35 +msgid "fucked" msgstr "" -#: ../../addon/dwpost/dwpost.php:85 -msgid "Post to Dreamwidth by default" +#: ../../extend/addon/addon/morepokes/morepokes.php:36 +msgid "bonk" msgstr "" -#: ../../addon/dwpost/dwpost.php:89 -msgid "Dreamwidth Post Settings" +#: ../../extend/addon/addon/morepokes/morepokes.php:36 +msgid "bonked" msgstr "" -#: ../../addon/firefox/firefox.php:23 -msgid "Install Firefox Sharing Tools" +#: ../../extend/addon/addon/morepokes/morepokes.php:37 +msgid "declare undying love for" msgstr "" -#: ../../addon/firefox/firefox.php:34 -msgid "Share content from Firefox to $Projectname" +#: ../../extend/addon/addon/morepokes/morepokes.php:37 +msgid "declared undying love for" msgstr "" -#: ../../addon/firefox/firefox.php:37 -msgid "Install Firefox Sharing Tools to this web browser" +#: ../../extend/addon/addon/msgfooter/msgfooter.php:46 +#: ../../extend/addon/addon/xmpp/xmpp.php:91 +msgid "Save Settings" msgstr "" -#: ../../addon/dirstats/dirstats.php:94 -msgid "Hubzilla Directory Stats" +#: ../../extend/addon/addon/msgfooter/msgfooter.php:47 +msgid "text to include in all outgoing posts from this site" msgstr "" -#: ../../addon/dirstats/dirstats.php:95 -msgid "Total Hubs" +#: ../../extend/addon/addon/nofed/nofed.php:42 +msgid "Federate" msgstr "" -#: ../../addon/dirstats/dirstats.php:97 -msgid "Hubzilla Hubs" +#: ../../extend/addon/addon/nofed/nofed.php:56 +msgid "nofed Settings saved." msgstr "" -#: ../../addon/dirstats/dirstats.php:99 -msgid "Friendica Hubs" +#: ../../extend/addon/addon/nofed/nofed.php:72 +msgid "Allow Federation Toggle" msgstr "" -#: ../../addon/dirstats/dirstats.php:101 -msgid "Diaspora Pods" +#: ../../extend/addon/addon/nofed/nofed.php:76 +msgid "Federate posts by default" msgstr "" -#: ../../addon/dirstats/dirstats.php:103 -msgid "Hubzilla Channels" +#: ../../extend/addon/addon/nofed/nofed.php:80 +msgid "NoFed Settings" msgstr "" -#: ../../addon/dirstats/dirstats.php:105 -msgid "Friendica Channels" +#: ../../extend/addon/addon/nsabait/nsabait.php:125 +msgid "Nsabait Settings updated." msgstr "" -#: ../../addon/dirstats/dirstats.php:107 -msgid "Diaspora Channels" +#: ../../extend/addon/addon/nsabait/nsabait.php:157 +msgid "Enable NSAbait Plugin" msgstr "" -#: ../../addon/dirstats/dirstats.php:109 -msgid "Aged 35 and above" +#: ../../extend/addon/addon/nsabait/nsabait.php:161 +msgid "NSAbait Settings" msgstr "" -#: ../../addon/dirstats/dirstats.php:111 -msgid "Aged 34 and under" +#: ../../extend/addon/addon/nsfw/nsfw.php:80 +msgid "" +"This plugin looks in posts for the words/text you specify below, and " +"collapses any content containing those keywords so it is not displayed at " +"inappropriate times, such as sexual innuendo that may be improper in a work " +"setting. It is polite and recommended to tag any content containing nudity " +"with #NSFW. This filter can also match any other word/text you specify, and " +"can thereby be used as a general purpose content filter." msgstr "" -#: ../../addon/dirstats/dirstats.php:113 -msgid "Average Age" +#: ../../extend/addon/addon/nsfw/nsfw.php:84 +msgid "Enable Content filter" msgstr "" -#: ../../addon/dirstats/dirstats.php:115 -msgid "Known Chatrooms" +#: ../../extend/addon/addon/nsfw/nsfw.php:88 +msgid "Comma separated list of keywords to hide" msgstr "" -#: ../../addon/dirstats/dirstats.php:117 -msgid "Known Tags" +#: ../../extend/addon/addon/nsfw/nsfw.php:88 +msgid "Word, /regular-expression/, lang=xx, lang!=xx" msgstr "" -#: ../../addon/dirstats/dirstats.php:119 -msgid "" -"Please note Diaspora and Friendica statistics are merely those **this " -"directory** is aware of, and not all those known in the network. This also " -"applies to chatrooms," +#: ../../extend/addon/addon/nsfw/nsfw.php:92 +msgid "Not Safe For Work Settings" msgstr "" -#: ../../addon/mailhost/mailhost.php:36 -msgid "Email notification hub" +#: ../../extend/addon/addon/nsfw/nsfw.php:92 +msgid "General Purpose Content Filter" msgstr "" -#: ../../addon/mailhost/mailhost.php:36 -msgid "Hostname" +#: ../../extend/addon/addon/nsfw/nsfw.php:110 +msgid "NSFW Settings saved." msgstr "" -#: ../../addon/mailhost/mailhost.php:40 -msgid "Mailhost Settings" +#: ../../extend/addon/addon/nsfw/nsfw.php:207 +msgid "Possible adult content" msgstr "" -#: ../../addon/mailhost/mailhost.php:54 -msgid "MAILHOST Settings saved." +#: ../../extend/addon/addon/nsfw/nsfw.php:211 +#, php-format +msgid "%s - view" msgstr "" -#: ../../addon/likebanner/likebanner.php:51 -msgid "Your Webbie:" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:50 +#: ../../extend/addon/addon/openclipatar/openclipatar.php:128 +msgid "System defaults:" msgstr "" -#: ../../addon/likebanner/likebanner.php:54 -msgid "Fontsize (px):" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:54 +msgid "Preferred Clipart IDs" msgstr "" -#: ../../addon/likebanner/likebanner.php:68 -msgid "Link:" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:54 +msgid "List of preferred clipart ids. These will be shown first." msgstr "" -#: ../../addon/likebanner/likebanner.php:70 -msgid "Like us on Hubzilla" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:55 +msgid "Default Search Term" msgstr "" -#: ../../addon/likebanner/likebanner.php:72 -msgid "Embed:" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:55 +msgid "The default search term. These will be shown second." msgstr "" -#: ../../addon/redphotos/redphotos.php:106 -msgid "Photos imported" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:56 +msgid "Return After" msgstr "" -#: ../../addon/redphotos/redphotos.php:129 -msgid "Redmatrix Photo Album Import" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:56 +msgid "Page to load after image selection." msgstr "" -#: ../../addon/redphotos/redphotos.php:130 -msgid "This will import all your Redmatrix photo albums to this channel." +#: ../../extend/addon/addon/openclipatar/openclipatar.php:58 +#: ../../include/nav.php:107 ../../include/channel.php:1047 +msgid "Edit Profile" msgstr "" -#: ../../addon/redphotos/redphotos.php:131 -#: ../../addon/redfiles/redfiles.php:121 -msgid "Redmatrix Server base URL" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:59 +msgid "Profile List" msgstr "" -#: ../../addon/redphotos/redphotos.php:132 -#: ../../addon/redfiles/redfiles.php:122 -msgid "Redmatrix Login Username" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:61 +msgid "Order of Preferred" msgstr "" -#: ../../addon/redphotos/redphotos.php:133 -#: ../../addon/redfiles/redfiles.php:123 -msgid "Redmatrix Login Password" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:61 +msgid "Sort order of preferred clipart ids." msgstr "" -#: ../../addon/redphotos/redphotos.php:134 -msgid "Import just this album" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:62 +#: ../../extend/addon/addon/openclipatar/openclipatar.php:68 +msgid "Newest first" msgstr "" -#: ../../addon/redphotos/redphotos.php:134 -msgid "Leave blank to import all albums" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:65 +msgid "As entered" msgstr "" -#: ../../addon/redphotos/redphotos.php:135 -msgid "Maximum count to import" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:67 +msgid "Order of other" msgstr "" -#: ../../addon/redphotos/redphotos.php:135 -msgid "0 or blank to import all available" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:67 +msgid "Sort order of other clipart ids." msgstr "" -#: ../../addon/irc/irc.php:45 -msgid "Channels to auto connect" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:69 +msgid "Most downloaded first" msgstr "" -#: ../../addon/irc/irc.php:45 ../../addon/irc/irc.php:49 -msgid "Comma separated list" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:70 +msgid "Most liked first" msgstr "" -#: ../../addon/irc/irc.php:49 ../../addon/irc/irc.php:96 -msgid "Popular Channels" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:72 +msgid "Preferred IDs Message" msgstr "" -#: ../../addon/irc/irc.php:53 -msgid "IRC Settings" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:72 +msgid "Message to display above preferred results." msgstr "" -#: ../../addon/irc/irc.php:69 -msgid "IRC settings saved." +#: ../../extend/addon/addon/openclipatar/openclipatar.php:78 +msgid "Uploaded by: " msgstr "" -#: ../../addon/irc/irc.php:74 -msgid "IRC Chatroom" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:78 +msgid "Drawn by: " msgstr "" -#: ../../addon/ljpost/ljpost.php:42 -msgid "Post to LiveJournal" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:192 +msgid "Or select from a free OpenClipart.org image:" msgstr "" -#: ../../addon/ljpost/ljpost.php:70 -msgid "Enable LiveJournal Post Plugin" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:195 +msgid "Search Term" msgstr "" -#: ../../addon/ljpost/ljpost.php:74 -msgid "LiveJournal username" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:232 +msgid "Unknown error. Please try again later." msgstr "" -#: ../../addon/ljpost/ljpost.php:78 -msgid "LiveJournal password" +#: ../../extend/addon/addon/openclipatar/openclipatar.php:308 +msgid "Profile photo updated successfully." msgstr "" -#: ../../addon/ljpost/ljpost.php:82 -msgid "Post to LiveJournal by default" +#: ../../extend/addon/addon/openstreetmap/openstreetmap.php:146 +msgid "View Larger" msgstr "" -#: ../../addon/ljpost/ljpost.php:86 -msgid "LiveJournal Post Settings" +#: ../../extend/addon/addon/openstreetmap/openstreetmap.php:169 +msgid "Tile Server URL" msgstr "" -#: ../../addon/ljpost/ljpost.php:101 -msgid "LiveJournal Settings saved." +#: ../../extend/addon/addon/openstreetmap/openstreetmap.php:169 +msgid "" +"A list of <a href=\"http://wiki.openstreetmap.org/wiki/TMS\" target=\"_blank" +"\">public tile servers</a>" msgstr "" -#: ../../addon/openid/openid.php:49 +#: ../../extend/addon/addon/openstreetmap/openstreetmap.php:170 +msgid "Nominatim (reverse geocoding) Server URL" +msgstr "" + +#: ../../extend/addon/addon/openstreetmap/openstreetmap.php:170 msgid "" -"We encountered a problem while logging in with the OpenID you provided. " -"Please check the correct spelling of the ID." +"A list of <a href=\"http://wiki.openstreetmap.org/wiki/Nominatim\" target=" +"\"_blank\">Nominatim servers</a>" msgstr "" -#: ../../addon/openid/openid.php:49 -msgid "The error message was:" +#: ../../extend/addon/addon/openstreetmap/openstreetmap.php:171 +msgid "Default zoom" msgstr "" -#: ../../addon/openid/MysqlProvider.php:52 -msgid "First Name" +#: ../../extend/addon/addon/openstreetmap/openstreetmap.php:171 +msgid "" +"The default zoom level. (1:world, 18:highest, also depends on tile server)" msgstr "" -#: ../../addon/openid/MysqlProvider.php:53 -msgid "Last Name" +#: ../../extend/addon/addon/openstreetmap/openstreetmap.php:172 +msgid "Include marker on map" msgstr "" -#: ../../addon/openid/MysqlProvider.php:54 ../../addon/redred/redred.php:111 -msgid "Nickname" +#: ../../extend/addon/addon/openstreetmap/openstreetmap.php:172 +msgid "Include a marker on the map." msgstr "" -#: ../../addon/openid/MysqlProvider.php:55 -msgid "Full Name" +#: ../../extend/addon/addon/pageheader/pageheader.php:43 +msgid "Message to display on every page on this server" msgstr "" -#: ../../addon/openid/MysqlProvider.php:61 -msgid "Profile Photo 16px" +#: ../../extend/addon/addon/pageheader/pageheader.php:48 +msgid "Pageheader Settings" msgstr "" -#: ../../addon/openid/MysqlProvider.php:62 -msgid "Profile Photo 32px" +#: ../../extend/addon/addon/pageheader/pageheader.php:64 +msgid "pageheader Settings saved." msgstr "" -#: ../../addon/openid/MysqlProvider.php:63 -msgid "Profile Photo 48px" +#: ../../extend/addon/addon/piwik/piwik.php:85 +msgid "" +"This website is tracked using the <a href='http://www.piwik.org'>Piwik</a> " +"analytics tool." msgstr "" -#: ../../addon/openid/MysqlProvider.php:64 -msgid "Profile Photo 64px" +#: ../../extend/addon/addon/piwik/piwik.php:88 +#, php-format +msgid "" +"If you do not want that your visits are logged this way you <a href='%s'>can " +"set a cookie to prevent Piwik from tracking further visits of the site</a> " +"(opt-out)." msgstr "" -#: ../../addon/openid/MysqlProvider.php:65 -msgid "Profile Photo 80px" +#: ../../extend/addon/addon/piwik/piwik.php:96 +msgid "Piwik Base URL" msgstr "" -#: ../../addon/openid/MysqlProvider.php:66 -msgid "Profile Photo 128px" +#: ../../extend/addon/addon/piwik/piwik.php:96 +msgid "" +"Absolute path to your Piwik installation. (without protocol (http/s), with " +"trailing slash)" msgstr "" -#: ../../addon/openid/MysqlProvider.php:67 -msgid "Timezone" +#: ../../extend/addon/addon/piwik/piwik.php:97 +msgid "Site ID" msgstr "" -#: ../../addon/openid/MysqlProvider.php:70 -msgid "Birth Year" +#: ../../extend/addon/addon/piwik/piwik.php:98 +msgid "Show opt-out cookie link?" msgstr "" -#: ../../addon/openid/MysqlProvider.php:71 -msgid "Birth Month" +#: ../../extend/addon/addon/piwik/piwik.php:99 +msgid "Asynchronous tracking" msgstr "" -#: ../../addon/openid/MysqlProvider.php:72 -msgid "Birth Day" +#: ../../extend/addon/addon/piwik/piwik.php:100 +msgid "Enable frontend JavaScript error tracking" msgstr "" -#: ../../addon/openid/MysqlProvider.php:73 -msgid "Birthdate" +#: ../../extend/addon/addon/piwik/piwik.php:100 +msgid "This feature requires Piwik >= 2.2.0" msgstr "" -#: ../../addon/openid/Mod_Openid.php:30 -msgid "OpenID protocol error. No ID returned." +#: ../../extend/addon/addon/planets/planets.php:121 +msgid "Planets Settings updated." msgstr "" -#: ../../addon/openid/Mod_Openid.php:188 ../../include/auth.php:286 -msgid "Login failed." +#: ../../extend/addon/addon/planets/planets.php:153 +msgid "Enable Planets Plugin" msgstr "" -#: ../../addon/openid/Mod_Id.php:85 ../../include/selectors.php:49 -#: ../../include/selectors.php:66 -msgid "Male" +#: ../../extend/addon/addon/planets/planets.php:157 +msgid "Planets Settings" msgstr "" -#: ../../addon/openid/Mod_Id.php:87 ../../include/selectors.php:49 -#: ../../include/selectors.php:66 -msgid "Female" +#: ../../extend/addon/addon/pumpio/pumpio.php:148 +msgid "You are now authenticated to pumpio." msgstr "" -#: ../../addon/randpost/randpost.php:97 -msgid "You're welcome." +#: ../../extend/addon/addon/pumpio/pumpio.php:149 +msgid "return to the featured settings page" msgstr "" -#: ../../addon/randpost/randpost.php:98 -msgid "Ah shucks..." +#: ../../extend/addon/addon/pumpio/pumpio.php:163 +msgid "Post to Pump.io" msgstr "" -#: ../../addon/randpost/randpost.php:99 -msgid "Don't mention it." +#: ../../extend/addon/addon/pumpio/pumpio.php:198 +msgid "Pump.io servername" msgstr "" -#: ../../addon/randpost/randpost.php:100 -msgid "<blush>" +#: ../../extend/addon/addon/pumpio/pumpio.php:198 +msgid "Without \"http://\" or \"https://\"" msgstr "" -#: ../../addon/startpage/startpage.php:109 -msgid "Page to load after login" +#: ../../extend/addon/addon/pumpio/pumpio.php:202 +msgid "Pump.io username" msgstr "" -#: ../../addon/startpage/startpage.php:109 -msgid "" -"Examples: "apps", "network?f=&gid=37" (privacy " -"collection), "channel" or "notifications/system" (leave " -"blank for default network page (grid)." +#: ../../extend/addon/addon/pumpio/pumpio.php:202 +msgid "Without the servername" msgstr "" -#: ../../addon/startpage/startpage.php:113 -msgid "Startpage Settings" +#: ../../extend/addon/addon/pumpio/pumpio.php:213 +msgid "You are not authenticated to pumpio" msgstr "" -#: ../../addon/morepokes/morepokes.php:19 -msgid "bitchslap" +#: ../../extend/addon/addon/pumpio/pumpio.php:215 +msgid "(Re-)Authenticate your pump.io connection" msgstr "" -#: ../../addon/morepokes/morepokes.php:19 -msgid "bitchslapped" +#: ../../extend/addon/addon/pumpio/pumpio.php:219 +msgid "Enable pump.io Post Plugin" msgstr "" -#: ../../addon/morepokes/morepokes.php:20 -msgid "shag" +#: ../../extend/addon/addon/pumpio/pumpio.php:223 +msgid "Post to pump.io by default" msgstr "" -#: ../../addon/morepokes/morepokes.php:20 -msgid "shagged" +#: ../../extend/addon/addon/pumpio/pumpio.php:227 +msgid "Should posts be public" msgstr "" -#: ../../addon/morepokes/morepokes.php:21 -msgid "patent" +#: ../../extend/addon/addon/pumpio/pumpio.php:231 +msgid "Mirror all public posts" msgstr "" -#: ../../addon/morepokes/morepokes.php:21 -msgid "patented" +#: ../../extend/addon/addon/pumpio/pumpio.php:237 +msgid "Pump.io Post Settings" msgstr "" -#: ../../addon/morepokes/morepokes.php:22 -msgid "hug" +#: ../../extend/addon/addon/pumpio/pumpio.php:266 +msgid "PumpIO Settings saved." msgstr "" -#: ../../addon/morepokes/morepokes.php:22 -msgid "hugged" +#: ../../extend/addon/addon/qrator/qrator.php:48 +msgid "QR code" msgstr "" -#: ../../addon/morepokes/morepokes.php:23 -msgid "murder" +#: ../../extend/addon/addon/qrator/qrator.php:63 +msgid "QR Generator" msgstr "" -#: ../../addon/morepokes/morepokes.php:23 -msgid "murdered" +#: ../../extend/addon/addon/qrator/qrator.php:64 +msgid "Enter some text" msgstr "" -#: ../../addon/morepokes/morepokes.php:24 -msgid "worship" +#: ../../extend/addon/addon/rainbowtag/rainbowtag.php:81 +msgid "Enable Rainbowtag" msgstr "" -#: ../../addon/morepokes/morepokes.php:24 -msgid "worshipped" +#: ../../extend/addon/addon/rainbowtag/rainbowtag.php:85 +msgid "Rainbowtag Settings" msgstr "" -#: ../../addon/morepokes/morepokes.php:25 -msgid "kiss" +#: ../../extend/addon/addon/rainbowtag/rainbowtag.php:101 +msgid "Rainbowtag Settings saved." msgstr "" -#: ../../addon/morepokes/morepokes.php:25 -msgid "kissed" +#: ../../extend/addon/addon/randpost/randpost.php:97 +msgid "You're welcome." msgstr "" -#: ../../addon/morepokes/morepokes.php:26 -msgid "tempt" +#: ../../extend/addon/addon/randpost/randpost.php:98 +msgid "Ah shucks..." msgstr "" -#: ../../addon/morepokes/morepokes.php:26 -msgid "tempted" +#: ../../extend/addon/addon/randpost/randpost.php:99 +msgid "Don't mention it." msgstr "" -#: ../../addon/morepokes/morepokes.php:27 -msgid "raise eyebrows at" +#: ../../extend/addon/addon/randpost/randpost.php:100 +msgid "<blush>" msgstr "" -#: ../../addon/morepokes/morepokes.php:27 -msgid "raised their eyebrows at" +#: ../../extend/addon/addon/redfiles/redfiles.php:119 +msgid "Redmatrix File Storage Import" msgstr "" -#: ../../addon/morepokes/morepokes.php:28 -msgid "insult" +#: ../../extend/addon/addon/redfiles/redfiles.php:120 +msgid "This will import all your Redmatrix cloud files to this channel." msgstr "" -#: ../../addon/morepokes/morepokes.php:28 -msgid "insulted" +#: ../../extend/addon/addon/redfiles/redfiles.php:121 +#: ../../extend/addon/addon/redphotos/redphotos.php:131 +msgid "Redmatrix Server base URL" msgstr "" -#: ../../addon/morepokes/morepokes.php:29 -msgid "praise" +#: ../../extend/addon/addon/redfiles/redfiles.php:122 +#: ../../extend/addon/addon/redphotos/redphotos.php:132 +msgid "Redmatrix Login Username" msgstr "" -#: ../../addon/morepokes/morepokes.php:29 -msgid "praised" +#: ../../extend/addon/addon/redfiles/redfiles.php:123 +#: ../../extend/addon/addon/redphotos/redphotos.php:133 +msgid "Redmatrix Login Password" msgstr "" -#: ../../addon/morepokes/morepokes.php:30 -msgid "be dubious of" +#: ../../extend/addon/addon/redfiles/redfilehelper.php:64 +msgid "file" msgstr "" -#: ../../addon/morepokes/morepokes.php:30 -msgid "was dubious of" +#: ../../extend/addon/addon/redphotos/redphotos.php:106 +msgid "Photos imported" msgstr "" -#: ../../addon/morepokes/morepokes.php:31 -msgid "eat" +#: ../../extend/addon/addon/redphotos/redphotos.php:129 +msgid "Redmatrix Photo Album Import" msgstr "" -#: ../../addon/morepokes/morepokes.php:31 -msgid "ate" +#: ../../extend/addon/addon/redphotos/redphotos.php:130 +msgid "This will import all your Redmatrix photo albums to this channel." msgstr "" -#: ../../addon/morepokes/morepokes.php:32 -msgid "giggle and fawn at" +#: ../../extend/addon/addon/redphotos/redphotos.php:134 +msgid "Import just this album" msgstr "" -#: ../../addon/morepokes/morepokes.php:32 -msgid "giggled and fawned at" +#: ../../extend/addon/addon/redphotos/redphotos.php:134 +msgid "Leave blank to import all albums" msgstr "" -#: ../../addon/morepokes/morepokes.php:33 -msgid "doubt" +#: ../../extend/addon/addon/redphotos/redphotos.php:135 +msgid "Maximum count to import" msgstr "" -#: ../../addon/morepokes/morepokes.php:33 -msgid "doubted" +#: ../../extend/addon/addon/redphotos/redphotos.php:135 +msgid "0 or blank to import all available" msgstr "" -#: ../../addon/morepokes/morepokes.php:34 -msgid "glare" +#: ../../extend/addon/addon/redred/redred.php:45 +msgid "Post to Red" msgstr "" -#: ../../addon/morepokes/morepokes.php:34 -msgid "glared at" +#: ../../extend/addon/addon/redred/redred.php:60 +msgid "Channel is required." msgstr "" -#: ../../addon/morepokes/morepokes.php:35 -msgid "fuck" +#: ../../extend/addon/addon/redred/redred.php:76 +msgid "redred Settings saved." msgstr "" -#: ../../addon/morepokes/morepokes.php:35 -msgid "fucked" +#: ../../extend/addon/addon/redred/redred.php:95 +msgid "Allow posting to another Hubzilla Channel" msgstr "" -#: ../../addon/morepokes/morepokes.php:36 -msgid "bonk" +#: ../../extend/addon/addon/redred/redred.php:99 +msgid "Send public postings to Hubzilla channel by default" msgstr "" -#: ../../addon/morepokes/morepokes.php:36 -msgid "bonked" +#: ../../extend/addon/addon/redred/redred.php:103 +msgid "Hubzilla API Path" msgstr "" -#: ../../addon/morepokes/morepokes.php:37 -msgid "declare undying love for" +#: ../../extend/addon/addon/redred/redred.php:103 +#: ../../extend/addon/addon/rtof/rtof.php:89 +msgid "https://{sitename}/api" msgstr "" -#: ../../addon/morepokes/morepokes.php:37 -msgid "declared undying love for" +#: ../../extend/addon/addon/redred/redred.php:107 +msgid "Hubzilla login name" +msgstr "" + +<<<<<<< HEAD +#: ../../extend/addon/addon/redred/redred.php:111 +msgid "Hubzilla channel name" +msgstr "" + +#: ../../extend/addon/addon/redred/redred.php:111 +#: ../../extend/addon/addon/openid/MysqlProvider.php:54 +msgid "Nickname" msgstr "" +#: ../../extend/addon/addon/redred/redred.php:119 +msgid "Hubzilla Crosspost Settings" +msgstr "" + +#: ../../extend/addon/addon/rtof/rtof.php:45 +msgid "Post to Friendica" +msgstr "" + +#: ../../extend/addon/addon/rtof/rtof.php:62 +msgid "rtof Settings saved." +msgstr "" + +#: ../../extend/addon/addon/rtof/rtof.php:81 +msgid "Allow posting to Friendica" +======= #: ../../addon/diaspora/diaspora.php:675 msgid "Diaspora Protocol Settings updated." msgstr "" @@ -9434,1989 +11062,2186 @@ msgstr "" #: ../../addon/diaspora/diaspora.php:712 msgid "Diaspora Protocol Settings" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../addon/diaspora/import_diaspora.php:16 -msgid "No username found in import file." +#: ../../extend/addon/addon/rtof/rtof.php:85 +msgid "Send public postings to Friendica by default" msgstr "" -#: ../../addon/diaspora/import_diaspora.php:41 ../../include/import.php:62 -msgid "Unable to create a unique channel address. Import failed." +#: ../../extend/addon/addon/rtof/rtof.php:89 +msgid "Friendica API Path" msgstr "" -#: ../../addon/gitwiki/Mod_Gitwiki.php:107 -msgid "Error retrieving wiki" +#: ../../extend/addon/addon/rtof/rtof.php:93 +msgid "Friendica login name" msgstr "" -#: ../../addon/gitwiki/Mod_Gitwiki.php:114 -msgid "Error creating zip file export folder" +#: ../../extend/addon/addon/rtof/rtof.php:97 +msgid "Friendica password" msgstr "" -#: ../../addon/gitwiki/Mod_Gitwiki.php:132 -msgid "Error downloading wiki: " +#: ../../extend/addon/addon/rtof/rtof.php:101 +msgid "Hubzilla to Friendica Post Settings" msgstr "" -#: ../../addon/testdrive/testdrive.php:104 -#, php-format -msgid "Your account on %s will expire in a few days." +#: ../../extend/addon/addon/sendzid/sendzid.php:25 +msgid "Extended Identity Sharing" msgstr "" -#: ../../addon/testdrive/testdrive.php:105 -msgid "Your $Productname test account is about to expire." +#: ../../extend/addon/addon/sendzid/sendzid.php:26 +msgid "" +"Share your identity with all websites on the internet. When disabled, " +"identity is only shared with sites in the matrix." msgstr "" -#: ../../addon/rainbowtag/rainbowtag.php:81 -msgid "Enable Rainbowtag" +#: ../../extend/addon/addon/skeleton/skeleton.php:59 +msgid "Some setting" msgstr "" -#: ../../addon/rainbowtag/rainbowtag.php:85 -msgid "Rainbowtag Settings" +#: ../../extend/addon/addon/skeleton/skeleton.php:61 +msgid "A setting" msgstr "" -#: ../../addon/rainbowtag/rainbowtag.php:101 -msgid "Rainbowtag Settings saved." +#: ../../extend/addon/addon/skeleton/skeleton.php:64 +msgid "Skeleton Settings" msgstr "" -#: ../../addon/upload_limits/upload_limits.php:25 -msgid "Show Upload Limits" +#: ../../extend/addon/addon/smileybutton/smileybutton.php:273 +msgid "Deactivate the feature" msgstr "" -#: ../../addon/upload_limits/upload_limits.php:27 -msgid "Hubzilla configured maximum size: " +#: ../../extend/addon/addon/smileybutton/smileybutton.php:277 +msgid "Hide the button and show the smilies directly." msgstr "" -#: ../../addon/upload_limits/upload_limits.php:28 -msgid "PHP upload_max_filesize: " +#: ../../extend/addon/addon/smileybutton/smileybutton.php:281 +msgid "Smileybutton Settings" msgstr "" -#: ../../addon/upload_limits/upload_limits.php:29 -msgid "PHP post_max_size (must be larger than upload_max_filesize): " +#: ../../extend/addon/addon/startpage/startpage.php:109 +msgid "Page to load after login" msgstr "" -#: ../../addon/visage/visage.php:93 -msgid "Recent Channel/Profile Viewers" +#: ../../extend/addon/addon/startpage/startpage.php:109 +msgid "" +"Examples: "apps", "network?f=&gid=37" (privacy " +"collection), "channel" or "notifications/system" (leave " +"blank for default network page (grid)." msgstr "" -#: ../../addon/visage/visage.php:98 -msgid "This plugin/addon has not been configured." +#: ../../extend/addon/addon/startpage/startpage.php:113 +msgid "Startpage Settings" msgstr "" -#: ../../addon/visage/visage.php:99 -#, php-format -msgid "Please visit the Visage settings on %s" +#: ../../extend/addon/addon/statusnet/statusnet.php:143 +msgid "Post to GNU social" msgstr "" -#: ../../addon/visage/visage.php:99 -msgid "your feature settings page" +#: ../../extend/addon/addon/statusnet/statusnet.php:195 +msgid "" +"Please contact your site administrator.<br />The provided API URL is not " +"valid." msgstr "" -#: ../../addon/visage/visage.php:112 -msgid "No entries." +#: ../../extend/addon/addon/statusnet/statusnet.php:232 +msgid "We could not contact the GNU social API with the Path you entered." msgstr "" -#: ../../addon/visage/visage.php:166 -msgid "Enable Visage Visitor Logging" +#: ../../extend/addon/addon/statusnet/statusnet.php:266 +msgid "GNU social settings updated." msgstr "" -#: ../../addon/visage/visage.php:170 -msgid "Visage Settings" +#: ../../extend/addon/addon/statusnet/statusnet.php:310 +msgid "Globally Available GNU social OAuthKeys" msgstr "" -#: ../../addon/nsabait/nsabait.php:125 -msgid "Nsabait Settings updated." +#: ../../extend/addon/addon/statusnet/statusnet.php:312 +msgid "" +"There are preconfigured OAuth key pairs for some GNU social servers " +"available. If you are using one of them, please use these credentials.<br /" +">If not feel free to connect to any other GNU social instance (see below)." msgstr "" -#: ../../addon/nsabait/nsabait.php:157 -msgid "Enable NSAbait Plugin" +#: ../../extend/addon/addon/statusnet/statusnet.php:327 +msgid "Provide your own OAuth Credentials" msgstr "" -#: ../../addon/nsabait/nsabait.php:161 -msgid "NSAbait Settings" +#: ../../extend/addon/addon/statusnet/statusnet.php:329 +msgid "" +"No consumer key pair for GNU social found. Register your Hubzilla Account as " +"an desktop client on your GNU social account, copy the consumer key pair " +"here and enter the API base root.<br />Before you register your own OAuth " +"key pair ask the administrator if there is already a key pair for this " +"Hubzilla installation at your favourite GNU social installation." msgstr "" -#: ../../addon/mailtest/mailtest.php:19 -msgid "Send test email" +#: ../../extend/addon/addon/statusnet/statusnet.php:333 +msgid "OAuth Consumer Key" msgstr "" -#: ../../addon/mailtest/mailtest.php:50 ../../addon/hubwall/hubwall.php:50 -msgid "No recipients found." +#: ../../extend/addon/addon/statusnet/statusnet.php:337 +msgid "OAuth Consumer Secret" msgstr "" -#: ../../addon/mailtest/mailtest.php:66 -msgid "Mail sent." +#: ../../extend/addon/addon/statusnet/statusnet.php:341 +msgid "Base API Path" msgstr "" -#: ../../addon/mailtest/mailtest.php:68 -msgid "Sending of mail failed." +#: ../../extend/addon/addon/statusnet/statusnet.php:341 +msgid "Remember the trailing /" msgstr "" -#: ../../addon/mailtest/mailtest.php:77 -msgid "Mail Test" +#: ../../extend/addon/addon/statusnet/statusnet.php:345 +msgid "GNU social application name" msgstr "" -#: ../../addon/mailtest/mailtest.php:96 ../../addon/hubwall/hubwall.php:92 -msgid "Message subject" +#: ../../extend/addon/addon/statusnet/statusnet.php:368 +msgid "" +"To connect to your GNU social account click the button below to get a " +"security code from GNU social which you have to copy into the input box " +"below and submit the form. Only your <strong>public</strong> posts will be " +"posted to GNU social." msgstr "" -#: ../../addon/diaspora_reconnect/diaspora_reconnect.php:44 -#, php-format -msgid "Reconnecting %d connections" +#: ../../extend/addon/addon/statusnet/statusnet.php:370 +msgid "Log in with GNU social" msgstr "" -#: ../../addon/diaspora_reconnect/diaspora_reconnect.php:63 -msgid "Diaspora Reconnect" +#: ../../extend/addon/addon/statusnet/statusnet.php:373 +msgid "Copy the security code from GNU social here" msgstr "" -#: ../../addon/diaspora_reconnect/diaspora_reconnect.php:65 -msgid "" -"Use this form to re-establish Diaspora connections which were initially made " -"from a different hub." +#: ../../extend/addon/addon/statusnet/statusnet.php:383 +msgid "Cancel Connection Process" msgstr "" -#: ../../addon/diaspora_reconnect/diaspora_reconnect.php:70 -msgid "Reconnect" +#: ../../extend/addon/addon/statusnet/statusnet.php:385 +msgid "Current GNU social API is" msgstr "" -#: ../../addon/openstreetmap/openstreetmap.php:146 -msgid "View Larger" +#: ../../extend/addon/addon/statusnet/statusnet.php:389 +msgid "Cancel GNU social Connection" msgstr "" -#: ../../addon/openstreetmap/openstreetmap.php:169 -msgid "Tile Server URL" +#: ../../extend/addon/addon/statusnet/statusnet.php:401 +#: ../../extend/addon/addon/twitter/twitter.php:232 +msgid "Currently connected to: " msgstr "" -#: ../../addon/openstreetmap/openstreetmap.php:169 +#: ../../extend/addon/addon/statusnet/statusnet.php:406 msgid "" -"A list of <a href=\"http://wiki.openstreetmap.org/wiki/TMS\" target=\"_blank" -"\">public tile servers</a>" +"<strong>Note</strong>: Due your privacy settings (<em>Hide your profile " +"details from unknown viewers?</em>) the link potentially included in public " +"postings relayed to GNU social will lead the visitor to a blank page " +"informing the visitor that the access to your profile has been restricted." msgstr "" -#: ../../addon/openstreetmap/openstreetmap.php:170 -msgid "Nominatim (reverse geocoding) Server URL" +#: ../../extend/addon/addon/statusnet/statusnet.php:411 +msgid "Allow posting to GNU social" msgstr "" -#: ../../addon/openstreetmap/openstreetmap.php:170 +#: ../../extend/addon/addon/statusnet/statusnet.php:411 msgid "" -"A list of <a href=\"http://wiki.openstreetmap.org/wiki/Nominatim\" target=" -"\"_blank\">Nominatim servers</a>" +"If enabled your public postings can be posted to the associated GNU-social " +"account" msgstr "" -#: ../../addon/openstreetmap/openstreetmap.php:171 -msgid "Default zoom" +#: ../../extend/addon/addon/statusnet/statusnet.php:415 +msgid "Post to GNU social by default" msgstr "" -#: ../../addon/openstreetmap/openstreetmap.php:171 +#: ../../extend/addon/addon/statusnet/statusnet.php:415 msgid "" -"The default zoom level. (1:world, 18:highest, also depends on tile server)" +"If enabled your public postings will be posted to the associated GNU-social " +"account by default" msgstr "" -#: ../../addon/openstreetmap/openstreetmap.php:172 -msgid "Include marker on map" +#: ../../extend/addon/addon/statusnet/statusnet.php:424 +#: ../../extend/addon/addon/twitter/twitter.php:255 +msgid "Clear OAuth configuration" msgstr "" -#: ../../addon/openstreetmap/openstreetmap.php:172 -msgid "Include a marker on the map." +#: ../../extend/addon/addon/statusnet/statusnet.php:432 +msgid "GNU social Post Settings" msgstr "" -#: ../../addon/msgfooter/msgfooter.php:46 ../../addon/xmpp/xmpp.php:91 -msgid "Save Settings" +#: ../../extend/addon/addon/statusnet/statusnet.php:891 +msgid "API URL" msgstr "" -#: ../../addon/msgfooter/msgfooter.php:47 -msgid "text to include in all outgoing posts from this site" +#: ../../extend/addon/addon/statusnet/statusnet.php:894 +msgid "Application name" msgstr "" -#: ../../addon/rtof/rtof.php:45 -msgid "Post to Friendica" +#: ../../extend/addon/addon/superblock/superblock.php:112 +msgid "Currently blocked" msgstr "" -#: ../../addon/rtof/rtof.php:62 -msgid "rtof Settings saved." +#: ../../extend/addon/addon/superblock/superblock.php:114 +msgid "No channels currently blocked" msgstr "" -#: ../../addon/rtof/rtof.php:81 -msgid "Allow posting to Friendica" +#: ../../extend/addon/addon/superblock/superblock.php:120 +msgid "\"Superblock\" Settings" msgstr "" -#: ../../addon/rtof/rtof.php:85 -msgid "Send public postings to Friendica by default" +#: ../../extend/addon/addon/superblock/superblock.php:345 +msgid "Block Completely" msgstr "" -#: ../../addon/rtof/rtof.php:89 -msgid "Friendica API Path" +#: ../../extend/addon/addon/superblock/superblock.php:394 +msgid "superblock settings updated" msgstr "" -#: ../../addon/rtof/rtof.php:89 ../../addon/redred/redred.php:103 -msgid "https://{sitename}/api" +#: ../../extend/addon/addon/testdrive/testdrive.php:104 +#, php-format +msgid "Your account on %s will expire in a few days." msgstr "" -#: ../../addon/rtof/rtof.php:93 -msgid "Friendica login name" +#: ../../extend/addon/addon/testdrive/testdrive.php:105 +msgid "Your $Productname test account is about to expire." msgstr "" -#: ../../addon/rtof/rtof.php:97 -msgid "Friendica password" +#: ../../extend/addon/addon/tictac/tictac.php:21 +msgid "Three Dimensional Tic-Tac-Toe" msgstr "" -#: ../../addon/rtof/rtof.php:101 -msgid "Hubzilla to Friendica Post Settings" +#: ../../extend/addon/addon/tictac/tictac.php:54 +msgid "3D Tic-Tac-Toe" msgstr "" -#: ../../addon/jappixmini/jappixmini.php:305 ../../include/channel.php:1153 -#: ../../include/channel.php:1310 +<<<<<<< HEAD +#: ../../extend/addon/addon/tictac/tictac.php:59 +msgid "New game" +======= +#: ../../addon/jappixmini/jappixmini.php:305 ../../include/channel.php:1139 +#: ../../include/channel.php:1296 msgid "Status:" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../addon/jappixmini/jappixmini.php:309 -msgid "Activate addon" +#: ../../extend/addon/addon/tictac/tictac.php:60 +msgid "New game with handicap" msgstr "" -#: ../../addon/jappixmini/jappixmini.php:313 -msgid "Hide Jappixmini Chat-Widget from the webinterface" +#: ../../extend/addon/addon/tictac/tictac.php:61 +msgid "" +"Three dimensional tic-tac-toe is just like the traditional game except that " +"it is played on multiple levels simultaneously. " msgstr "" -#: ../../addon/jappixmini/jappixmini.php:318 -msgid "Jabber username" +#: ../../extend/addon/addon/tictac/tictac.php:62 +msgid "" +"In this case there are three levels. You win by getting three in a row on " +"any level, as well as up, down, and diagonally across the different levels." msgstr "" -#: ../../addon/jappixmini/jappixmini.php:324 -msgid "Jabber server" +#: ../../extend/addon/addon/tictac/tictac.php:64 +msgid "" +"The handicap game disables the center position on the middle level because " +"the player claiming this square often has an unfair advantage." msgstr "" -#: ../../addon/jappixmini/jappixmini.php:330 -msgid "Jabber BOSH host URL" +#: ../../extend/addon/addon/tictac/tictac.php:183 +msgid "You go first..." msgstr "" -#: ../../addon/jappixmini/jappixmini.php:337 -msgid "Jabber password" +#: ../../extend/addon/addon/tictac/tictac.php:188 +msgid "I'm going first this time..." msgstr "" -#: ../../addon/jappixmini/jappixmini.php:343 -msgid "Encrypt Jabber password with Hubzilla password" +#: ../../extend/addon/addon/tictac/tictac.php:194 +msgid "You won!" msgstr "" -#: ../../addon/jappixmini/jappixmini.php:347 ../../addon/redred/redred.php:115 -msgid "Hubzilla password" +#: ../../extend/addon/addon/tictac/tictac.php:200 +#: ../../extend/addon/addon/tictac/tictac.php:225 +msgid "\"Cat\" game!" msgstr "" -#: ../../addon/jappixmini/jappixmini.php:351 -#: ../../addon/jappixmini/jappixmini.php:355 -msgid "Approve subscription requests from Hubzilla contacts automatically" +#: ../../extend/addon/addon/tictac/tictac.php:223 +msgid "I won!" msgstr "" -#: ../../addon/jappixmini/jappixmini.php:359 -msgid "Purge internal list of jabber addresses of contacts" +#: ../../extend/addon/addon/tour/tour.php:75 +msgid "Edit your profile and change settings." msgstr "" -#: ../../addon/jappixmini/jappixmini.php:364 -msgid "Configuration Help" +#: ../../extend/addon/addon/tour/tour.php:76 +msgid "Click here to see activity from your connections." msgstr "" -#: ../../addon/jappixmini/jappixmini.php:371 -msgid "Jappix Mini Settings" +#: ../../extend/addon/addon/tour/tour.php:77 +msgid "Click here to see your channel home." msgstr "" -#: ../../addon/superblock/superblock.php:112 -msgid "Currently blocked" +#: ../../extend/addon/addon/tour/tour.php:78 +msgid "You can access your private messages from here." msgstr "" -#: ../../addon/superblock/superblock.php:114 -msgid "No channels currently blocked" +#: ../../extend/addon/addon/tour/tour.php:79 +msgid "Create new events here." msgstr "" -#: ../../addon/superblock/superblock.php:120 -msgid "\"Superblock\" Settings" +#: ../../extend/addon/addon/tour/tour.php:80 +msgid "" +"You can accept new connections and change permissions for existing ones " +"here. You can also e.g. create groups of contacts." msgstr "" -#: ../../addon/superblock/superblock.php:345 -msgid "Block Completely" +#: ../../extend/addon/addon/tour/tour.php:81 +msgid "System notifications will arrive here" msgstr "" -#: ../../addon/superblock/superblock.php:394 -msgid "superblock settings updated" +#: ../../extend/addon/addon/tour/tour.php:82 +msgid "Search for content and users" msgstr "" -#: ../../addon/nofed/nofed.php:42 -msgid "Federate" +#: ../../extend/addon/addon/tour/tour.php:83 +msgid "Browse for new contacts" msgstr "" -#: ../../addon/nofed/nofed.php:56 -msgid "nofed Settings saved." +#: ../../extend/addon/addon/tour/tour.php:84 +msgid "Launch installed apps" msgstr "" -#: ../../addon/nofed/nofed.php:72 -msgid "Allow Federation Toggle" +#: ../../extend/addon/addon/tour/tour.php:85 +msgid "Looking for help? Click here." msgstr "" -#: ../../addon/nofed/nofed.php:76 -msgid "Federate posts by default" +#: ../../extend/addon/addon/tour/tour.php:86 +msgid "" +"New events have occurred in your network. Click here to see what has " +"happened!" msgstr "" -#: ../../addon/nofed/nofed.php:80 -msgid "NoFed Settings" +#: ../../extend/addon/addon/tour/tour.php:87 +msgid "You have received a new private message. Click here to see from who!" msgstr "" -#: ../../addon/redred/redred.php:45 -msgid "Post to Red" +#: ../../extend/addon/addon/tour/tour.php:88 +msgid "There are events this week. Click here too see which!" msgstr "" -#: ../../addon/redred/redred.php:60 -msgid "Channel is required." +#: ../../extend/addon/addon/tour/tour.php:89 +msgid "You have received a new introduction. Click here to see who!" msgstr "" -#: ../../addon/redred/redred.php:76 -msgid "redred Settings saved." +#: ../../extend/addon/addon/tour/tour.php:90 +msgid "" +"There is a new system notification. Click here to see what has happened!" msgstr "" -#: ../../addon/redred/redred.php:95 -msgid "Allow posting to another Hubzilla Channel" +#: ../../extend/addon/addon/tour/tour.php:93 +msgid "Click here to share text, images, videos and sound." msgstr "" -#: ../../addon/redred/redred.php:99 -msgid "Send public postings to Hubzilla channel by default" +#: ../../extend/addon/addon/tour/tour.php:94 +msgid "You can write an optional title for your update (good for long posts)." msgstr "" -#: ../../addon/redred/redred.php:103 -msgid "Hubzilla API Path" +#: ../../extend/addon/addon/tour/tour.php:95 +msgid "Entering some categories here makes it easier to find your post later." msgstr "" -#: ../../addon/redred/redred.php:107 -msgid "Hubzilla login name" +#: ../../extend/addon/addon/tour/tour.php:96 +msgid "Share photos, links, location, etc." msgstr "" -#: ../../addon/redred/redred.php:111 -msgid "Hubzilla channel name" +#: ../../extend/addon/addon/tour/tour.php:97 +msgid "" +"Only want to share content for a while? Make it expire at a certain date." msgstr "" -#: ../../addon/redred/redred.php:119 -msgid "Hubzilla Crosspost Settings" +#: ../../extend/addon/addon/tour/tour.php:98 +msgid "You can password protect content." msgstr "" -#: ../../addon/logrot/logrot.php:36 -msgid "Logfile archive directory" +#: ../../extend/addon/addon/tour/tour.php:99 +msgid "Choose who you share with." msgstr "" -#: ../../addon/logrot/logrot.php:36 -msgid "Directory to store rotated logs" +#: ../../extend/addon/addon/tour/tour.php:101 +msgid "Click here when you are done." msgstr "" -#: ../../addon/logrot/logrot.php:37 -msgid "Logfile size in bytes before rotating" +#: ../../extend/addon/addon/tour/tour.php:104 +msgid "Adjust from which channels posts should be displayed." msgstr "" -#: ../../addon/logrot/logrot.php:38 -msgid "Number of logfiles to retain" +#: ../../extend/addon/addon/tour/tour.php:105 +msgid "Only show posts from channels in the specified privacy group." msgstr "" -#: ../../addon/frphotos/frphotos.php:91 -msgid "Friendica Photo Album Import" +#: ../../extend/addon/addon/tour/tour.php:109 +msgid "" +"Easily find posts containing tags (keywords preceded by the \"#\" symbol)." msgstr "" -#: ../../addon/frphotos/frphotos.php:92 -msgid "This will import all your Friendica photo albums to this Red channel." +#: ../../extend/addon/addon/tour/tour.php:110 +msgid "Easily find posts in given category." msgstr "" -#: ../../addon/frphotos/frphotos.php:93 -msgid "Friendica Server base URL" +#: ../../extend/addon/addon/tour/tour.php:111 +msgid "Easily find posts by date." msgstr "" -#: ../../addon/frphotos/frphotos.php:94 -msgid "Friendica Login Username" +#: ../../extend/addon/addon/tour/tour.php:112 +msgid "" +"Suggested users who have volounteered to be shown as suggestions, and who we " +"think you might find interesting." msgstr "" -#: ../../addon/frphotos/frphotos.php:95 -msgid "Friendica Login Password" +#: ../../extend/addon/addon/tour/tour.php:113 +msgid "Here you see channels you have connected to." msgstr "" -#: ../../addon/donate/donate.php:21 -msgid "Project Servers and Resources" +#: ../../extend/addon/addon/tour/tour.php:114 +msgid "Save your search so you can repeat it at a later date." msgstr "" -#: ../../addon/donate/donate.php:22 -msgid "Project Creator and Tech Lead" +#: ../../extend/addon/addon/tour/tour.php:117 +msgid "" +"If you see this icon you can be sure that the sender is who it say it is. It " +"is normal that it is not always possible to verify the sender, so the icon " +"will be missing sometimes. There is usually no need to worry about that." msgstr "" -#: ../../addon/donate/donate.php:23 -msgid "Admin, developer, directorymin, support bloke" +#: ../../extend/addon/addon/tour/tour.php:118 +msgid "" +"Danger! It seems someone tried to forge a message! This message is not " +"necessarily from who it says it is from!" msgstr "" -#: ../../addon/donate/donate.php:50 +#: ../../extend/addon/addon/tour/tour.php:125 msgid "" -"And the hundreds of other people and organisations who helped make the " -"Hubzilla possible." +"Welcome to Hubzilla! Would you like to see a tour of the UI?</p> <p>You can " +"pause it at any time and continue where you left off by reloading the page, " +"or navigting to another page.</p><p>You can also advance by pressing the " +"return key" msgstr "" -#: ../../addon/donate/donate.php:53 -msgid "" -"The Redmatrix/Hubzilla projects are provided primarily by volunteers giving " -"their time and expertise - and often paying out of pocket for services they " -"share with others." +#: ../../extend/addon/addon/twitter/twitter.php:99 +msgid "Post to Twitter" msgstr "" -#: ../../addon/donate/donate.php:54 -msgid "" -"There is no corporate funding and no ads, and we do not collect and sell " -"your personal information. (We don't control your personal information - " -"<strong>you do</strong>.)" +#: ../../extend/addon/addon/twitter/twitter.php:154 +msgid "Twitter settings updated." msgstr "" -#: ../../addon/donate/donate.php:55 +#: ../../extend/addon/addon/twitter/twitter.php:183 msgid "" -"Help support our ground-breaking work in decentralisation, web identity, and " -"privacy." +"No consumer key pair for Twitter found. Please contact your site " +"administrator." msgstr "" -#: ../../addon/donate/donate.php:57 +#: ../../extend/addon/addon/twitter/twitter.php:205 msgid "" -"Your donations keep servers and services running and also helps us to " -"provide innovative new features and continued development." +"At this Hubzilla instance the Twitter plugin was enabled but you have not " +"yet connected your account to your Twitter account. To do so click the " +"button below to get a PIN from Twitter which you have to copy into the input " +"box below and submit the form. Only your <strong>public</strong> posts will " +"be posted to Twitter." msgstr "" -#: ../../addon/donate/donate.php:60 -msgid "Donate" +#: ../../extend/addon/addon/twitter/twitter.php:207 +msgid "Log in with Twitter" +msgstr "" + +#: ../../extend/addon/addon/twitter/twitter.php:210 +msgid "Copy the PIN from Twitter here" msgstr "" -#: ../../addon/donate/donate.php:62 +#: ../../extend/addon/addon/twitter/twitter.php:237 msgid "" -"Choose a project, developer, or public hub to support with a one-time " -"donation" +"<strong>Note:</strong> Due your privacy settings (<em>Hide your profile " +"details from unknown viewers?</em>) the link potentially included in public " +"postings relayed to Twitter will lead the visitor to a blank page informing " +"the visitor that the access to your profile has been restricted." msgstr "" -#: ../../addon/donate/donate.php:63 -msgid "Donate Now" +#: ../../extend/addon/addon/twitter/twitter.php:242 +msgid "Allow posting to Twitter" msgstr "" -#: ../../addon/donate/donate.php:64 +#: ../../extend/addon/addon/twitter/twitter.php:242 msgid "" -"<strong><em>Or</em></strong> become a project sponsor (Hubzilla Project only)" +"If enabled your public postings can be posted to the associated Twitter " +"account" msgstr "" -#: ../../addon/donate/donate.php:65 -msgid "" -"Please indicate if you would like your first name or full name (or nothing) " -"to appear in our sponsor listing" +#: ../../extend/addon/addon/twitter/twitter.php:246 +msgid "Send public postings to Twitter by default" msgstr "" -#: ../../addon/donate/donate.php:66 -msgid "Sponsor" +#: ../../extend/addon/addon/twitter/twitter.php:246 +msgid "" +"If enabled your public postings will be posted to the associated Twitter " +"account by default" msgstr "" -#: ../../addon/donate/donate.php:69 -msgid "Special thanks to: " +#: ../../extend/addon/addon/twitter/twitter.php:264 +msgid "Twitter Post Settings" msgstr "" -#: ../../addon/chords/Mod_Chords.php:44 -msgid "" -"This is a fairly comprehensive and complete guitar chord dictionary which " -"will list most of the available ways to play a certain chord, starting from " -"the base of the fingerboard up to a few frets beyond the twelfth fret " -"(beyond which everything repeats). A couple of non-standard tunings are " -"provided for the benefit of slide players, etc." +#: ../../extend/addon/addon/twitter/twitter.php:773 +#: ../../extend/addon/addon/rendezvous/rendezvous.php:95 +msgid "Submit Settings" msgstr "" -#: ../../addon/chords/Mod_Chords.php:46 -msgid "" -"Chord names start with a root note (A-G) and may include sharps (#) and " -"flats (b). This software will parse most of the standard naming conventions " -"such as maj, min, dim, sus(2 or 4), aug, with optional repeating elements." +#: ../../extend/addon/addon/upload_limits/upload_limits.php:25 +msgid "Show Upload Limits" msgstr "" -#: ../../addon/chords/Mod_Chords.php:48 -msgid "" -"Valid examples include A, A7, Am7, Amaj7, Amaj9, Ammaj7, Aadd4, Asus2Add4, " -"E7b13b11 ..." +#: ../../extend/addon/addon/upload_limits/upload_limits.php:27 +msgid "Hubzilla configured maximum size: " msgstr "" -#: ../../addon/chords/Mod_Chords.php:51 -msgid "Guitar Chords" +#: ../../extend/addon/addon/upload_limits/upload_limits.php:28 +msgid "PHP upload_max_filesize: " msgstr "" -#: ../../addon/chords/Mod_Chords.php:52 -msgid "The complete online chord dictionary" +#: ../../extend/addon/addon/upload_limits/upload_limits.php:29 +msgid "PHP post_max_size (must be larger than upload_max_filesize): " msgstr "" -#: ../../addon/chords/Mod_Chords.php:57 -msgid "Tuning" +#: ../../extend/addon/addon/visage/visage.php:93 +msgid "Recent Channel/Profile Viewers" msgstr "" -#: ../../addon/chords/Mod_Chords.php:58 -msgid "Chord name: example: Em7" +#: ../../extend/addon/addon/visage/visage.php:98 +msgid "This plugin/addon has not been configured." msgstr "" -#: ../../addon/chords/Mod_Chords.php:59 -msgid "Show for left handed stringing" +#: ../../extend/addon/addon/visage/visage.php:99 +#, php-format +msgid "Please visit the Visage settings on %s" msgstr "" -#: ../../addon/chords/chords.php:33 -msgid "Quick Reference" +#: ../../extend/addon/addon/visage/visage.php:99 +msgid "your feature settings page" msgstr "" -#: ../../addon/libertree/libertree.php:38 -msgid "Post to Libertree" +#: ../../extend/addon/addon/visage/visage.php:112 +msgid "No entries." msgstr "" -#: ../../addon/libertree/libertree.php:69 -msgid "Enable Libertree Post Plugin" +#: ../../extend/addon/addon/visage/visage.php:166 +msgid "Enable Visage Visitor Logging" msgstr "" -#: ../../addon/libertree/libertree.php:73 -msgid "Libertree API token" +#: ../../extend/addon/addon/visage/visage.php:170 +msgid "Visage Settings" msgstr "" -#: ../../addon/libertree/libertree.php:77 -msgid "Libertree site URL" +#: ../../extend/addon/addon/wholikesme/wholikesme.php:29 +msgid "Who likes me?" msgstr "" -#: ../../addon/libertree/libertree.php:81 -msgid "Post to Libertree by default" +#: ../../extend/addon/addon/wppost/wppost.php:45 +msgid "Post to WordPress" msgstr "" -#: ../../addon/libertree/libertree.php:85 -msgid "Libertree Post Settings" +#: ../../extend/addon/addon/wppost/wppost.php:82 +msgid "Enable WordPress Post Plugin" msgstr "" -#: ../../addon/libertree/libertree.php:99 -msgid "Libertree Settings saved." +#: ../../extend/addon/addon/wppost/wppost.php:86 +msgid "WordPress username" msgstr "" -#: ../../addon/flattrwidget/flattrwidget.php:45 -msgid "Flattr this!" +#: ../../extend/addon/addon/wppost/wppost.php:90 +msgid "WordPress password" msgstr "" -#: ../../addon/flattrwidget/flattrwidget.php:83 -msgid "Flattr widget settings updated." +#: ../../extend/addon/addon/wppost/wppost.php:94 +msgid "WordPress API URL" msgstr "" -#: ../../addon/flattrwidget/flattrwidget.php:100 -msgid "Flattr user" +#: ../../extend/addon/addon/wppost/wppost.php:95 +msgid "Typically https://your-blog.tld/xmlrpc.php" msgstr "" -#: ../../addon/flattrwidget/flattrwidget.php:104 -msgid "URL of the Thing to flattr" +#: ../../extend/addon/addon/wppost/wppost.php:98 +msgid "WordPress blogid" msgstr "" -#: ../../addon/flattrwidget/flattrwidget.php:104 -msgid "If empty channel URL is used" +#: ../../extend/addon/addon/wppost/wppost.php:99 +msgid "For multi-user sites such as wordpress.com, otherwise leave blank" msgstr "" -#: ../../addon/flattrwidget/flattrwidget.php:108 -msgid "Title of the Thing to flattr" +#: ../../extend/addon/addon/wppost/wppost.php:105 +msgid "Post to WordPress by default" msgstr "" -#: ../../addon/flattrwidget/flattrwidget.php:108 -msgid "If empty \"channel name on The Hubzilla\" will be used" +#: ../../extend/addon/addon/wppost/wppost.php:109 +msgid "Forward comments (requires hubzilla_wp plugin)" msgstr "" -#: ../../addon/flattrwidget/flattrwidget.php:112 -msgid "Static or dynamic flattr button" +#: ../../extend/addon/addon/wppost/wppost.php:113 +msgid "WordPress Post Settings" msgstr "" -#: ../../addon/flattrwidget/flattrwidget.php:112 -msgid "static" +#: ../../extend/addon/addon/wppost/wppost.php:129 +msgid "Wordpress Settings saved." msgstr "" -#: ../../addon/flattrwidget/flattrwidget.php:112 -msgid "dynamic" +#: ../../extend/addon/addon/xmpp/xmpp.php:31 +msgid "XMPP settings updated." msgstr "" -#: ../../addon/flattrwidget/flattrwidget.php:116 -msgid "Alignment of the widget" +#: ../../extend/addon/addon/xmpp/xmpp.php:53 +msgid "Enable Chat" msgstr "" -#: ../../addon/flattrwidget/flattrwidget.php:116 -msgid "left" +#: ../../extend/addon/addon/xmpp/xmpp.php:58 +msgid "Individual credentials" msgstr "" -#: ../../addon/flattrwidget/flattrwidget.php:116 -msgid "right" +#: ../../extend/addon/addon/xmpp/xmpp.php:64 +msgid "Jabber BOSH server" msgstr "" -#: ../../addon/flattrwidget/flattrwidget.php:120 -msgid "Enable Flattr widget" +#: ../../extend/addon/addon/xmpp/xmpp.php:69 +msgid "XMPP Settings" msgstr "" -#: ../../addon/flattrwidget/flattrwidget.php:124 -msgid "Flattr Widget Settings" +#: ../../extend/addon/addon/xmpp/xmpp.php:92 +msgid "Jabber BOSH host" msgstr "" -#: ../../addon/statusnet/statusnet.php:143 -msgid "Post to GNU social" +#: ../../extend/addon/addon/xmpp/xmpp.php:93 +msgid "Use central userbase" msgstr "" -#: ../../addon/statusnet/statusnet.php:195 +#: ../../extend/addon/addon/xmpp/xmpp.php:93 msgid "" -"Please contact your site administrator.<br />The provided API URL is not " -"valid." +"If enabled, members will automatically login to an ejabberd server that has " +"to be installed on this machine with synchronized credentials via the " +"\"auth_ejabberd.php\" script." msgstr "" -#: ../../addon/statusnet/statusnet.php:232 -msgid "We could not contact the GNU social API with the Path you entered." +#: ../../extend/addon/addon/cdav/include/widgets.php:37 +msgid "Select Channel" msgstr "" -#: ../../addon/statusnet/statusnet.php:266 -msgid "GNU social settings updated." +#: ../../extend/addon/addon/cdav/include/widgets.php:42 +msgid "Read-write" msgstr "" -#: ../../addon/statusnet/statusnet.php:310 -msgid "Globally Available GNU social OAuthKeys" +#: ../../extend/addon/addon/cdav/include/widgets.php:43 +msgid "Read-only" msgstr "" -#: ../../addon/statusnet/statusnet.php:312 -msgid "" -"There are preconfigured OAuth key pairs for some GNU social servers " -"available. If you are using one of them, please use these credentials.<br /" -">If not feel free to connect to any other GNU social instance (see below)." +#: ../../extend/addon/addon/cdav/include/widgets.php:116 +msgid "My Calendars" msgstr "" -#: ../../addon/statusnet/statusnet.php:327 -msgid "Provide your own OAuth Credentials" +#: ../../extend/addon/addon/cdav/include/widgets.php:118 +msgid "Shared Calendars" msgstr "" -#: ../../addon/statusnet/statusnet.php:329 -msgid "" -"No consumer key pair for GNU social found. Register your Hubzilla Account as " -"an desktop client on your GNU social account, copy the consumer key pair " -"here and enter the API base root.<br />Before you register your own OAuth " -"key pair ask the administrator if there is already a key pair for this " -"Hubzilla installation at your favourite GNU social installation." +#: ../../extend/addon/addon/cdav/include/widgets.php:122 +msgid "Share this calendar" msgstr "" -#: ../../addon/statusnet/statusnet.php:333 -msgid "OAuth Consumer Key" +#: ../../extend/addon/addon/cdav/include/widgets.php:124 +msgid "Calendar name and color" msgstr "" -#: ../../addon/statusnet/statusnet.php:337 -msgid "OAuth Consumer Secret" +#: ../../extend/addon/addon/cdav/include/widgets.php:126 +msgid "Create new calendar" msgstr "" -#: ../../addon/statusnet/statusnet.php:341 -msgid "Base API Path" +#: ../../extend/addon/addon/cdav/include/widgets.php:128 +msgid "Calendar Name" msgstr "" -#: ../../addon/statusnet/statusnet.php:341 -msgid "Remember the trailing /" +#: ../../extend/addon/addon/cdav/include/widgets.php:129 +msgid "Calendar Tools" msgstr "" -#: ../../addon/statusnet/statusnet.php:345 -msgid "GNU social application name" +#: ../../extend/addon/addon/cdav/include/widgets.php:130 +msgid "Import calendar" msgstr "" -#: ../../addon/statusnet/statusnet.php:368 -msgid "" -"To connect to your GNU social account click the button below to get a " -"security code from GNU social which you have to copy into the input box " -"below and submit the form. Only your <strong>public</strong> posts will be " -"posted to GNU social." +#: ../../extend/addon/addon/cdav/include/widgets.php:131 +msgid "Select a calendar to import to" msgstr "" -#: ../../addon/statusnet/statusnet.php:370 -msgid "Log in with GNU social" +#: ../../extend/addon/addon/cdav/include/widgets.php:158 +msgid "Addressbooks" msgstr "" -#: ../../addon/statusnet/statusnet.php:373 -msgid "Copy the security code from GNU social here" +#: ../../extend/addon/addon/cdav/include/widgets.php:160 +msgid "Addressbook name" msgstr "" -#: ../../addon/statusnet/statusnet.php:383 -msgid "Cancel Connection Process" +#: ../../extend/addon/addon/cdav/include/widgets.php:162 +msgid "Create new addressbook" msgstr "" -#: ../../addon/statusnet/statusnet.php:385 -msgid "Current GNU social API is" +#: ../../extend/addon/addon/cdav/include/widgets.php:163 +msgid "Addressbook Name" msgstr "" -#: ../../addon/statusnet/statusnet.php:389 -msgid "Cancel GNU social Connection" +#: ../../extend/addon/addon/cdav/include/widgets.php:165 +msgid "Addressbook Tools" msgstr "" -#: ../../addon/statusnet/statusnet.php:401 ../../addon/twitter/twitter.php:232 -msgid "Currently connected to: " +#: ../../extend/addon/addon/cdav/include/widgets.php:166 +msgid "Import addressbook" msgstr "" -#: ../../addon/statusnet/statusnet.php:406 -msgid "" -"<strong>Note</strong>: Due your privacy settings (<em>Hide your profile " -"details from unknown viewers?</em>) the link potentially included in public " -"postings relayed to GNU social will lead the visitor to a blank page " -"informing the visitor that the access to your profile has been restricted." +#: ../../extend/addon/addon/cdav/include/widgets.php:167 +msgid "Select an addressbook to import to" msgstr "" -#: ../../addon/statusnet/statusnet.php:411 -msgid "Allow posting to GNU social" +#: ../../extend/addon/addon/cdav/cdav.php:36 +msgid "Errors encountered creating database table: " msgstr "" -#: ../../addon/statusnet/statusnet.php:411 -msgid "" -"If enabled your public postings can be posted to the associated GNU-social " -"account" +#: ../../extend/addon/addon/cdav/cdav.php:197 +msgid "Default Calendar" msgstr "" -#: ../../addon/statusnet/statusnet.php:415 -msgid "Post to GNU social by default" +#: ../../extend/addon/addon/cdav/cdav.php:206 +msgid "Default Addressbook" msgstr "" -#: ../../addon/statusnet/statusnet.php:415 -msgid "" -"If enabled your public postings will be posted to the associated GNU-social " -"account by default" +#: ../../extend/addon/addon/cdav/cdav.php:215 +msgid "CalDAV/CardDAV Settings saved." msgstr "" -#: ../../addon/statusnet/statusnet.php:424 ../../addon/twitter/twitter.php:255 -msgid "Clear OAuth configuration" +#: ../../extend/addon/addon/cdav/cdav.php:234 +msgid "Enable CalDAV/CardDAV Server for this channel" msgstr "" -#: ../../addon/statusnet/statusnet.php:432 -msgid "GNU social Post Settings" +#: ../../extend/addon/addon/cdav/cdav.php:237 +#, php-format +msgid "Your CalDAV resources are located at %s " msgstr "" -#: ../../addon/statusnet/statusnet.php:891 -msgid "API URL" +#: ../../extend/addon/addon/cdav/cdav.php:240 +#, php-format +msgid "Your CardDAV resources are located at %s " msgstr "" -#: ../../addon/statusnet/statusnet.php:894 -msgid "Application name" +#: ../../extend/addon/addon/cdav/cdav.php:246 +msgid "CalDAV/CardDAV Settings" msgstr "" -#: ../../addon/qrator/qrator.php:48 -msgid "QR code" +#: ../../extend/addon/addon/cdav/cdav.php:272 +#: ../../include/connections.php:670 +msgid "Home, Voice" msgstr "" -#: ../../addon/qrator/qrator.php:63 -msgid "QR Generator" +#: ../../extend/addon/addon/cdav/cdav.php:273 +#: ../../include/connections.php:671 +msgid "Home, Fax" msgstr "" -#: ../../addon/qrator/qrator.php:64 -msgid "Enter some text" +#: ../../extend/addon/addon/cdav/cdav.php:275 +#: ../../include/connections.php:673 +msgid "Work, Voice" msgstr "" -#: ../../addon/chess/chess.php:276 ../../addon/chess/chess.php:433 -msgid "Invalid game." +#: ../../extend/addon/addon/cdav/cdav.php:276 +#: ../../include/connections.php:674 +msgid "Work, Fax" msgstr "" -#: ../../addon/chess/chess.php:282 ../../addon/chess/chess.php:439 -msgid "You are not a player in this game." +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:744 +msgid "INVALID EVENT DISMISSED!" msgstr "" -#: ../../addon/chess/chess.php:315 -msgid "You must be a local channel to create a game." +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:745 +msgid "Summary: " msgstr "" -#: ../../addon/chess/chess.php:333 -msgid "You must select one opponent that is not yourself." +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:746 +msgid "Date: " msgstr "" -#: ../../addon/chess/chess.php:336 -msgid "Creating new game..." +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:747 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:754 +msgid "Reason: " msgstr "" -#: ../../addon/chess/chess.php:342 -msgid "You must select white or black." +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:752 +msgid "INVALID CARD DISMISSED!" msgstr "" -#: ../../addon/chess/chess.php:349 -msgid "Error creating new game." +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:753 +msgid "Name: " msgstr "" -#: ../../addon/chess/chess.php:381 ../../include/channel.php:913 +<<<<<<< HEAD +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:770 +msgid "" +"You have to enable this plugin in Feature/Addon Settings > CalDAV/CardDAV " +"Settings before you can use it." +======= +#: ../../addon/chess/chess.php:381 ../../include/channel.php:899 msgid "Requested channel is not available." +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../addon/chess/chess.php:395 -msgid "You must select a local channel /chess/channelname" +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:836 +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:837 +msgid "Example: YYYY-MM-DD HH:mm" msgstr "" -#: ../../addon/chess/chess.php:923 -msgid "Enable notifications" +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:837 +msgid "End date and time" msgstr "" -#: ../../addon/twitter/twitter.php:99 -msgid "Post to Twitter" +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:852 +msgid "List month" msgstr "" -#: ../../addon/twitter/twitter.php:154 -msgid "Twitter settings updated." +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:853 +msgid "List week" msgstr "" -#: ../../addon/twitter/twitter.php:183 -msgid "" -"No consumer key pair for Twitter found. Please contact your site " -"administrator." +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:854 +msgid "List day" msgstr "" -#: ../../addon/twitter/twitter.php:205 -msgid "" -"At this Hubzilla instance the Twitter plugin was enabled but you have not " -"yet connected your account to your Twitter account. To do so click the " -"button below to get a PIN from Twitter which you have to copy into the input " -"box below and submit the form. Only your <strong>public</strong> posts will " -"be posted to Twitter." +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:861 +msgid "More" msgstr "" -#: ../../addon/twitter/twitter.php:207 -msgid "Log in with Twitter" +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:862 +msgid "Less" msgstr "" -#: ../../addon/twitter/twitter.php:210 -msgid "Copy the PIN from Twitter here" +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:863 +msgid "Select calendar" msgstr "" -#: ../../addon/twitter/twitter.php:237 -msgid "" -"<strong>Note:</strong> Due your privacy settings (<em>Hide your profile " -"details from unknown viewers?</em>) the link potentially included in public " -"postings relayed to Twitter will lead the visitor to a blank page informing " -"the visitor that the access to your profile has been restricted." +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:865 +msgid "Delete all" msgstr "" -#: ../../addon/twitter/twitter.php:242 -msgid "Allow posting to Twitter" +#: ../../extend/addon/addon/cdav/Mod_Cdav.php:867 +msgid "Sorry! Editing of recurrent events is not yet implemented." msgstr "" -#: ../../addon/twitter/twitter.php:242 -msgid "" -"If enabled your public postings can be posted to the associated Twitter " -"account" +#: ../../extend/addon/addon/chess/chess.php:276 +#: ../../extend/addon/addon/chess/chess.php:433 +msgid "Invalid game." msgstr "" -#: ../../addon/twitter/twitter.php:246 -msgid "Send public postings to Twitter by default" +#: ../../extend/addon/addon/chess/chess.php:282 +#: ../../extend/addon/addon/chess/chess.php:439 +msgid "You are not a player in this game." msgstr "" -#: ../../addon/twitter/twitter.php:246 -msgid "" -"If enabled your public postings will be posted to the associated Twitter " -"account by default" +#: ../../extend/addon/addon/chess/chess.php:315 +msgid "You must be a local channel to create a game." msgstr "" -#: ../../addon/twitter/twitter.php:264 -msgid "Twitter Post Settings" +#: ../../extend/addon/addon/chess/chess.php:333 +msgid "You must select one opponent that is not yourself." msgstr "" -#: ../../addon/smileybutton/smileybutton.php:211 -msgid "Deactivate the feature" +#: ../../extend/addon/addon/chess/chess.php:336 +msgid "Creating new game..." msgstr "" -#: ../../addon/smileybutton/smileybutton.php:215 -msgid "Hide the button and show the smilies directly." +#: ../../extend/addon/addon/chess/chess.php:342 +msgid "You must select white or black." msgstr "" -#: ../../addon/smileybutton/smileybutton.php:219 -msgid "Smileybutton Settings" +#: ../../extend/addon/addon/chess/chess.php:349 +msgid "Error creating new game." msgstr "" -#: ../../addon/piwik/piwik.php:85 -msgid "" -"This website is tracked using the <a href='http://www.piwik.org'>Piwik</a> " -"analytics tool." +#: ../../extend/addon/addon/chess/chess.php:381 ../../include/channel.php:898 +msgid "Requested channel is not available." msgstr "" -#: ../../addon/piwik/piwik.php:88 -#, php-format -msgid "" -"If you do not want that your visits are logged this way you <a href='%s'>can " -"set a cookie to prevent Piwik from tracking further visits of the site</a> " -"(opt-out)." +#: ../../extend/addon/addon/chess/chess.php:395 +msgid "You must select a local channel /chess/channelname" msgstr "" -#: ../../addon/piwik/piwik.php:96 -msgid "Piwik Base URL" +#: ../../extend/addon/addon/chess/chess.php:923 +msgid "Enable notifications" msgstr "" -#: ../../addon/piwik/piwik.php:96 -msgid "" -"Absolute path to your Piwik installation. (without protocol (http/s), with " -"trailing slash)" +#: ../../extend/addon/addon/likebanner/likebanner.php:51 +msgid "Your Webbie:" msgstr "" -#: ../../addon/piwik/piwik.php:97 -msgid "Site ID" +#: ../../extend/addon/addon/likebanner/likebanner.php:54 +msgid "Fontsize (px):" msgstr "" -#: ../../addon/piwik/piwik.php:98 -msgid "Show opt-out cookie link?" +#: ../../extend/addon/addon/likebanner/likebanner.php:68 +msgid "Link:" msgstr "" -#: ../../addon/piwik/piwik.php:99 -msgid "Asynchronous tracking" +#: ../../extend/addon/addon/likebanner/likebanner.php:70 +msgid "Like us on Hubzilla" msgstr "" -#: ../../addon/piwik/piwik.php:100 -msgid "Enable frontend JavaScript error tracking" +#: ../../extend/addon/addon/likebanner/likebanner.php:72 +msgid "Embed:" msgstr "" -#: ../../addon/piwik/piwik.php:100 -msgid "This feature requires Piwik >= 2.2.0" +#: ../../extend/addon/addon/openid/Mod_Id.php:85 +#: ../../include/selectors.php:49 ../../include/selectors.php:66 +msgid "Male" msgstr "" -#: ../../addon/tour/tour.php:75 -msgid "Edit your profile and change settings." +#: ../../extend/addon/addon/openid/Mod_Id.php:87 +#: ../../include/selectors.php:49 ../../include/selectors.php:66 +msgid "Female" msgstr "" -#: ../../addon/tour/tour.php:76 -msgid "Click here to see activity from your connections." +#: ../../extend/addon/addon/openid/MysqlProvider.php:52 +msgid "First Name" msgstr "" -#: ../../addon/tour/tour.php:77 -msgid "Click here to see your channel home." +#: ../../extend/addon/addon/openid/MysqlProvider.php:53 +msgid "Last Name" msgstr "" -#: ../../addon/tour/tour.php:78 -msgid "You can access your private messages from here." +#: ../../extend/addon/addon/openid/MysqlProvider.php:55 +msgid "Full Name" msgstr "" -#: ../../addon/tour/tour.php:79 -msgid "Create new events here." +#: ../../extend/addon/addon/openid/MysqlProvider.php:61 +msgid "Profile Photo 16px" msgstr "" -#: ../../addon/tour/tour.php:80 -msgid "" -"You can accept new connections and change permissions for existing ones " -"here. You can also e.g. create groups of contacts." +#: ../../extend/addon/addon/openid/MysqlProvider.php:62 +msgid "Profile Photo 32px" msgstr "" -#: ../../addon/tour/tour.php:81 -msgid "System notifications will arrive here" +#: ../../extend/addon/addon/openid/MysqlProvider.php:63 +msgid "Profile Photo 48px" msgstr "" -#: ../../addon/tour/tour.php:82 -msgid "Search for content and users" +#: ../../extend/addon/addon/openid/MysqlProvider.php:64 +msgid "Profile Photo 64px" msgstr "" -#: ../../addon/tour/tour.php:83 -msgid "Browse for new contacts" +#: ../../extend/addon/addon/openid/MysqlProvider.php:65 +msgid "Profile Photo 80px" msgstr "" -#: ../../addon/tour/tour.php:84 -msgid "Launch installed apps" +#: ../../extend/addon/addon/openid/MysqlProvider.php:66 +msgid "Profile Photo 128px" msgstr "" -#: ../../addon/tour/tour.php:85 -msgid "Looking for help? Click here." +#: ../../extend/addon/addon/openid/MysqlProvider.php:67 +msgid "Timezone" msgstr "" -#: ../../addon/tour/tour.php:86 -msgid "" -"New events have occurred in your network. Click here to see what has " -"happened!" +#: ../../extend/addon/addon/openid/MysqlProvider.php:70 +msgid "Birth Year" msgstr "" -#: ../../addon/tour/tour.php:87 -msgid "You have received a new private message. Click here to see from who!" +#: ../../extend/addon/addon/openid/MysqlProvider.php:71 +msgid "Birth Month" msgstr "" -#: ../../addon/tour/tour.php:88 -msgid "There are events this week. Click here too see which!" +#: ../../extend/addon/addon/openid/MysqlProvider.php:72 +msgid "Birth Day" msgstr "" -#: ../../addon/tour/tour.php:89 -msgid "You have received a new introduction. Click here to see who!" +#: ../../extend/addon/addon/openid/MysqlProvider.php:73 +msgid "Birthdate" msgstr "" -#: ../../addon/tour/tour.php:90 +#: ../../extend/addon/addon/openid/openid.php:49 msgid "" -"There is a new system notification. Click here to see what has happened!" +"We encountered a problem while logging in with the OpenID you provided. " +"Please check the correct spelling of the ID." msgstr "" -#: ../../addon/tour/tour.php:93 -msgid "Click here to share text, images, videos and sound." +#: ../../extend/addon/addon/openid/openid.php:49 +msgid "The error message was:" msgstr "" -#: ../../addon/tour/tour.php:94 -msgid "You can write an optional title for your update (good for long posts)." +#: ../../extend/addon/addon/openid/Mod_Openid.php:30 +msgid "OpenID protocol error. No ID returned." msgstr "" -#: ../../addon/tour/tour.php:95 -msgid "Entering some categories here makes it easier to find your post later." +#: ../../extend/addon/addon/openid/Mod_Openid.php:188 +#: ../../include/auth.php:286 +msgid "Login failed." msgstr "" -#: ../../addon/tour/tour.php:96 -msgid "Share photos, links, location, etc." +#: ../../extend/addon/addon/mailtest/mailtest.php:19 +msgid "Send test email" msgstr "" -#: ../../addon/tour/tour.php:97 -msgid "" -"Only want to share content for a while? Make it expire at a certain date." +#: ../../extend/addon/addon/mailtest/mailtest.php:66 +msgid "Mail sent." msgstr "" -#: ../../addon/tour/tour.php:98 -msgid "You can password protect content." +#: ../../extend/addon/addon/mailtest/mailtest.php:68 +msgid "Sending of mail failed." msgstr "" -#: ../../addon/tour/tour.php:99 -msgid "Choose who you share with." +#: ../../extend/addon/addon/mailtest/mailtest.php:77 +msgid "Mail Test" msgstr "" -#: ../../addon/tour/tour.php:101 -msgid "Click here when you are done." +#: ../../extend/addon/addon/rendezvous/rendezvous.php:57 +msgid "Errors encountered deleting database table " msgstr "" -#: ../../addon/tour/tour.php:104 -msgid "Adjust from which channels posts should be displayed." +#: ../../extend/addon/addon/rendezvous/rendezvous.php:96 +msgid "Drop tables when uninstalling?" msgstr "" -#: ../../addon/tour/tour.php:105 -msgid "Only show posts from channels in the specified privacy group." +#: ../../extend/addon/addon/rendezvous/rendezvous.php:96 +msgid "" +"If checked, the Rendezvous database tables will be deleted when the plugin " +"is uninstalled." +msgstr "" + +#: ../../extend/addon/addon/rendezvous/rendezvous.php:97 +msgid "Mapbox Access Token" msgstr "" -#: ../../addon/tour/tour.php:109 +#: ../../extend/addon/addon/rendezvous/rendezvous.php:97 msgid "" -"Easily find posts containing tags (keywords preceded by the \"#\" symbol)." +"If you enter a Mapbox access token, it will be used to retrieve map tiles " +"from Mapbox instead of the default OpenStreetMap tile server." msgstr "" -#: ../../addon/tour/tour.php:110 -msgid "Easily find posts in given category." +#: ../../extend/addon/addon/rendezvous/rendezvous.php:162 +msgid "Rendezvous" msgstr "" -#: ../../addon/tour/tour.php:111 -msgid "Easily find posts by date." +#: ../../extend/addon/addon/rendezvous/rendezvous.php:167 +msgid "" +"This identity has been deleted by another member due to inactivity. Please " +"press the \"New identity\" button or refresh the page to register a new " +"identity. You may use the same name." +msgstr "" + +#: ../../extend/addon/addon/rendezvous/rendezvous.php:168 +msgid "Welcome to Rendezvous!" msgstr "" -#: ../../addon/tour/tour.php:112 +#: ../../extend/addon/addon/rendezvous/rendezvous.php:169 msgid "" -"Suggested users who have volounteered to be shown as suggestions, and who we " -"think you might find interesting." +"Enter your name to join this rendezvous. To begin sharing your location with " +"the other members, tap the GPS control. When your location is discovered, a " +"red dot will appear and others will be able to see you on the map." msgstr "" -#: ../../addon/tour/tour.php:113 -msgid "Here you see channels you have connected to." +#: ../../extend/addon/addon/rendezvous/rendezvous.php:171 +msgid "Let's meet here" msgstr "" -#: ../../addon/tour/tour.php:114 -msgid "Save your search so you can repeat it at a later date." +#: ../../extend/addon/addon/rendezvous/rendezvous.php:174 +msgid "New marker" msgstr "" -#: ../../addon/tour/tour.php:117 -msgid "" -"If you see this icon you can be sure that the sender is who it say it is. It " -"is normal that it is not always possible to verify the sender, so the icon " -"will be missing sometimes. There is usually no need to worry about that." +#: ../../extend/addon/addon/rendezvous/rendezvous.php:175 +msgid "Edit marker" msgstr "" -#: ../../addon/tour/tour.php:118 -msgid "" -"Danger! It seems someone tried to forge a message! This message is not " -"necessarily from who it says it is from!" +#: ../../extend/addon/addon/rendezvous/rendezvous.php:176 +msgid "New identity" msgstr "" -#: ../../addon/tour/tour.php:125 -msgid "" -"Welcome to Hubzilla! Would you like to see a tour of the UI?</p> <p>You can " -"pause it at any time and continue where you left off by reloading the page, " -"or navigting to another page.</p><p>You can also advance by pressing the " -"return key" +#: ../../extend/addon/addon/rendezvous/rendezvous.php:177 +msgid "Delete marker" msgstr "" -#: ../../addon/sendzid/sendzid.php:25 -msgid "Extended Identity Sharing" +#: ../../extend/addon/addon/rendezvous/rendezvous.php:178 +msgid "Delete member" msgstr "" -#: ../../addon/sendzid/sendzid.php:26 +#: ../../extend/addon/addon/rendezvous/rendezvous.php:179 +msgid "Edit proximity alert" +msgstr "" + +#: ../../extend/addon/addon/rendezvous/rendezvous.php:180 msgid "" -"Share your identity with all websites on the internet. When disabled, " -"identity is only shared with sites in the matrix." +"A proximity alert will be issued when this member is within a certain radius " +"of you.<br><br>Enter a radius in meters (0 to disable):" msgstr "" -#: ../../addon/tictac/tictac.php:21 -msgid "Three Dimensional Tic-Tac-Toe" +#: ../../extend/addon/addon/rendezvous/rendezvous.php:180 +#: ../../extend/addon/addon/rendezvous/rendezvous.php:185 +msgid "distance" msgstr "" -#: ../../addon/tictac/tictac.php:54 -msgid "3D Tic-Tac-Toe" +#: ../../extend/addon/addon/rendezvous/rendezvous.php:181 +msgid "Proximity alert distance (meters)" msgstr "" -#: ../../addon/tictac/tictac.php:59 -msgid "New game" +#: ../../extend/addon/addon/rendezvous/rendezvous.php:182 +#: ../../extend/addon/addon/rendezvous/rendezvous.php:184 +msgid "" +"A proximity alert will be issued when you are within a certain radius of the " +"marker location.<br><br>Enter a radius in meters (0 to disable):" msgstr "" -#: ../../addon/tictac/tictac.php:60 -msgid "New game with handicap" +#: ../../extend/addon/addon/rendezvous/rendezvous.php:183 +msgid "Marker proximity alert" msgstr "" -#: ../../addon/tictac/tictac.php:61 -msgid "" -"Three dimensional tic-tac-toe is just like the traditional game except that " -"it is played on multiple levels simultaneously. " +#: ../../extend/addon/addon/rendezvous/rendezvous.php:186 +msgid "Reminder note" msgstr "" -#: ../../addon/tictac/tictac.php:62 +#: ../../extend/addon/addon/rendezvous/rendezvous.php:187 msgid "" -"In this case there are three levels. You win by getting three in a row on " -"any level, as well as up, down, and diagonally across the different levels." +"Enter a note to be displayed when you are within the specified proximity..." msgstr "" -#: ../../addon/tictac/tictac.php:64 -msgid "" -"The handicap game disables the center position on the middle level because " -"the player claiming this square often has an unfair advantage." +#: ../../extend/addon/addon/rendezvous/rendezvous.php:199 +msgid "Add new rendezvous" msgstr "" -#: ../../addon/tictac/tictac.php:183 -msgid "You go first..." +#: ../../extend/addon/addon/rendezvous/rendezvous.php:200 +msgid "" +"Create a new rendezvous and share the access link with those you wish to " +"invite to the group. Those who open the link become members of the " +"rendezvous. They can view other member locations, add markers to the map, or " +"share their own locations with the group." msgstr "" -#: ../../addon/tictac/tictac.php:188 -msgid "I'm going first this time..." +#: ../../extend/addon/addon/firefox/firefox.php:23 +msgid "Install Firefox Sharing Tools" msgstr "" -#: ../../addon/tictac/tictac.php:194 -msgid "You won!" +#: ../../extend/addon/addon/firefox/firefox.php:34 +msgid "Share content from Firefox to $Projectname" msgstr "" -#: ../../addon/tictac/tictac.php:200 ../../addon/tictac/tictac.php:225 -msgid "\"Cat\" game!" +#: ../../extend/addon/addon/firefox/firefox.php:37 +msgid "Install Firefox Sharing Tools to this web browser" msgstr "" -#: ../../addon/tictac/tictac.php:223 -msgid "I won!" +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:107 +msgid "Error retrieving wiki" msgstr "" -#: ../../addon/pageheader/pageheader.php:43 -msgid "Message to display on every page on this server" +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:114 +msgid "Error creating zip file export folder" msgstr "" -#: ../../addon/pageheader/pageheader.php:48 -msgid "Pageheader Settings" +#: ../../extend/addon/addon/gitwiki/Mod_Gitwiki.php:132 +msgid "Error downloading wiki: " msgstr "" -#: ../../addon/pageheader/pageheader.php:64 -msgid "pageheader Settings saved." +#: ../../extend/addon/addon/opensearch/opensearch.php:26 +#, php-format +msgctxt "opensearch" +msgid "Search %1$s (%2$s)" msgstr "" -#: ../../addon/moremoods/moremoods.php:19 -msgid "lonely" +#: ../../extend/addon/addon/opensearch/opensearch.php:28 +msgctxt "opensearch" +msgid "$Projectname" msgstr "" -#: ../../addon/moremoods/moremoods.php:20 -msgid "drunk" +#: ../../extend/addon/addon/opensearch/opensearch.php:43 +msgid "Search $Projectname" msgstr "" -#: ../../addon/moremoods/moremoods.php:21 -msgid "horny" +#: ../../include/dba/dba_driver.php:189 +#, php-format +msgid "Cannot locate DNS info for database server '%s'" msgstr "" -#: ../../addon/moremoods/moremoods.php:22 -msgid "stoned" +#: ../../include/language.php:367 ../../include/text.php:1787 +msgid "default" msgstr "" -#: ../../addon/moremoods/moremoods.php:23 -msgid "fucked up" +#: ../../include/language.php:380 +msgid "Select an alternate language" msgstr "" -#: ../../addon/moremoods/moremoods.php:24 -msgid "clusterfucked" +#: ../../include/import.php:41 +msgid "" +"Cannot create a duplicate channel identifier on this system. Import failed." msgstr "" -#: ../../addon/moremoods/moremoods.php:25 -msgid "crazy" +#: ../../include/import.php:62 +msgid "Unable to create a unique channel address. Import failed." msgstr "" -#: ../../addon/moremoods/moremoods.php:26 -msgid "hurt" +#: ../../include/import.php:105 +msgid "Cloned channel not found. Import failed." msgstr "" -#: ../../addon/moremoods/moremoods.php:27 -msgid "sleepy" +#: ../../include/photos.php:111 +#, php-format +msgid "Image exceeds website size limit of %lu bytes" msgstr "" -#: ../../addon/moremoods/moremoods.php:28 -msgid "grumpy" +#: ../../include/photos.php:118 +msgid "Image file is empty." msgstr "" -#: ../../addon/moremoods/moremoods.php:29 -msgid "high" +#: ../../include/photos.php:257 +msgid "Photo storage failed." msgstr "" -#: ../../addon/moremoods/moremoods.php:30 -msgid "semi-conscious" +#: ../../include/photos.php:297 +msgid "a new photo" msgstr "" -#: ../../addon/moremoods/moremoods.php:31 -msgid "in love" +#: ../../include/photos.php:301 +#, php-format +msgctxt "photo_upload" +msgid "%1$s posted %2$s to %3$s" msgstr "" -#: ../../addon/moremoods/moremoods.php:32 -msgid "in lust" +#: ../../include/photos.php:524 ../../include/conversation.php:1777 +msgid "Photo Albums" msgstr "" -#: ../../addon/moremoods/moremoods.php:33 -msgid "naked" +#: ../../include/photos.php:529 +msgid "Upload New Photos" msgstr "" -#: ../../addon/moremoods/moremoods.php:34 -msgid "stinky" +#: ../../include/account.php:35 +msgid "Not a valid email address" msgstr "" -#: ../../addon/moremoods/moremoods.php:35 -msgid "sweaty" +#: ../../include/account.php:37 +msgid "Your email domain is not among those allowed on this site" msgstr "" -#: ../../addon/moremoods/moremoods.php:36 -msgid "bleeding out" +#: ../../include/account.php:43 +msgid "Your email address is already registered at this site." msgstr "" -#: ../../addon/moremoods/moremoods.php:37 -msgid "victorious" +#: ../../include/account.php:75 +msgid "An invitation is required." msgstr "" -#: ../../addon/moremoods/moremoods.php:38 -msgid "defeated" +#: ../../include/account.php:79 +msgid "Invitation could not be verified." msgstr "" -#: ../../addon/moremoods/moremoods.php:39 -msgid "envious" +#: ../../include/account.php:130 +msgid "Please enter the required information." msgstr "" -#: ../../addon/moremoods/moremoods.php:40 -msgid "jealous" +#: ../../include/account.php:198 +msgid "Failed to store account information." msgstr "" -#: ../../addon/xmpp/xmpp.php:31 -msgid "XMPP settings updated." +#: ../../include/account.php:263 +#, php-format +msgid "Registration confirmation for %s" msgstr "" -#: ../../addon/xmpp/xmpp.php:53 -msgid "Enable Chat" +#: ../../include/account.php:330 +#, php-format +msgid "Registration request at %s" msgstr "" -#: ../../addon/xmpp/xmpp.php:58 -msgid "Individual credentials" +#: ../../include/account.php:352 +msgid "your registration password" msgstr "" -#: ../../addon/xmpp/xmpp.php:64 -msgid "Jabber BOSH server" +#: ../../include/account.php:358 ../../include/account.php:420 +#, php-format +msgid "Registration details for %s" msgstr "" -#: ../../addon/xmpp/xmpp.php:69 -msgid "XMPP Settings" +#: ../../include/account.php:431 +msgid "Account approved." msgstr "" -#: ../../addon/xmpp/xmpp.php:92 -msgid "Jabber BOSH host" +#: ../../include/account.php:471 +#, php-format +msgid "Registration revoked for %s" msgstr "" -#: ../../addon/xmpp/xmpp.php:93 -msgid "Use central userbase" +#: ../../include/account.php:756 ../../include/account.php:758 +msgid "Click here to upgrade." msgstr "" -#: ../../addon/xmpp/xmpp.php:93 -msgid "" -"If enabled, members will automatically login to an ejabberd server that has " -"to be installed on this machine with synchronized credentials via the " -"\"auth_ejabberd.php\" script." +#: ../../include/account.php:764 +msgid "This action exceeds the limits set by your subscription plan." msgstr "" -#: ../../addon/wholikesme/wholikesme.php:29 -msgid "Who likes me?" +#: ../../include/account.php:769 +msgid "This action is not available under your subscription plan." msgstr "" -#: ../../addon/pumpio/pumpio.php:148 -msgid "You are now authenticated to pumpio." +#: ../../include/text.php:478 +msgid "prev" msgstr "" -#: ../../addon/pumpio/pumpio.php:149 -msgid "return to the featured settings page" +#: ../../include/text.php:480 +msgid "first" msgstr "" -#: ../../addon/pumpio/pumpio.php:163 -msgid "Post to Pump.io" +#: ../../include/text.php:509 +msgid "last" msgstr "" -#: ../../addon/pumpio/pumpio.php:198 -msgid "Pump.io servername" +#: ../../include/text.php:512 +msgid "next" msgstr "" -#: ../../addon/pumpio/pumpio.php:198 -msgid "Without \"http://\" or \"https://\"" +#: ../../include/text.php:523 +msgid "older" msgstr "" -#: ../../addon/pumpio/pumpio.php:202 -msgid "Pump.io username" +#: ../../include/text.php:525 +msgid "newer" msgstr "" -#: ../../addon/pumpio/pumpio.php:202 -msgid "Without the servername" +#: ../../include/text.php:945 +msgid "No connections" msgstr "" -#: ../../addon/pumpio/pumpio.php:213 -msgid "You are not authenticated to pumpio" +#: ../../include/text.php:970 +#, php-format +msgid "View all %s connections" msgstr "" -#: ../../addon/pumpio/pumpio.php:215 -msgid "(Re-)Authenticate your pump.io connection" +#: ../../include/text.php:1115 ../../include/text.php:1120 +msgid "poke" msgstr "" -#: ../../addon/pumpio/pumpio.php:219 -msgid "Enable pump.io Post Plugin" +#: ../../include/text.php:1115 ../../include/text.php:1120 +#: ../../include/conversation.php:239 +msgid "poked" msgstr "" -#: ../../addon/pumpio/pumpio.php:223 -msgid "Post to pump.io by default" +#: ../../include/text.php:1121 +msgid "ping" msgstr "" -#: ../../addon/pumpio/pumpio.php:227 -msgid "Should posts be public" +#: ../../include/text.php:1121 +msgid "pinged" msgstr "" -#: ../../addon/pumpio/pumpio.php:231 -msgid "Mirror all public posts" +#: ../../include/text.php:1122 +msgid "prod" msgstr "" -#: ../../addon/pumpio/pumpio.php:237 -msgid "Pump.io Post Settings" +#: ../../include/text.php:1122 +msgid "prodded" msgstr "" -#: ../../addon/pumpio/pumpio.php:266 -msgid "PumpIO Settings saved." +#: ../../include/text.php:1123 +msgid "slap" msgstr "" -#: ../../addon/ldapauth/ldapauth.php:61 -msgid "An account has been created for you." +#: ../../include/text.php:1123 +msgid "slapped" msgstr "" -#: ../../addon/ldapauth/ldapauth.php:68 -msgid "Authentication successful but rejected: account creation is disabled." +#: ../../include/text.php:1124 +msgid "finger" msgstr "" -#: ../../addon/opensearch/opensearch.php:43 -msgid "Search $Projectname" +#: ../../include/text.php:1124 +msgid "fingered" msgstr "" -#: ../../addon/redfiles/redfiles.php:119 -msgid "Redmatrix File Storage Import" +#: ../../include/text.php:1125 +msgid "rebuff" msgstr "" -#: ../../addon/redfiles/redfiles.php:120 -msgid "This will import all your Redmatrix cloud files to this channel." +#: ../../include/text.php:1125 +msgid "rebuffed" msgstr "" +<<<<<<< HEAD +#: ../../include/text.php:1137 +msgid "happy" +======= #: ../../addon/redfiles/redfilehelper.php:64 msgid "file" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../addon/hubwall/hubwall.php:19 -msgid "Send email to all members" +#: ../../include/text.php:1138 +msgid "sad" msgstr "" -#: ../../addon/hubwall/hubwall.php:33 -#, php-format -msgid "$1%s Administrator" +#: ../../include/text.php:1139 +msgid "mellow" msgstr "" -#: ../../addon/hubwall/hubwall.php:73 -#, php-format -msgid "%1$d of %2$d messages sent." +#: ../../include/text.php:1140 +msgid "tired" msgstr "" -#: ../../addon/hubwall/hubwall.php:81 -msgid "Send email to all hub members." +#: ../../include/text.php:1141 +msgid "perky" msgstr "" -#: ../../addon/hubwall/hubwall.php:93 -msgid "Sender Email address" +#: ../../include/text.php:1142 +msgid "angry" msgstr "" -#: ../../addon/hubwall/hubwall.php:94 -msgid "Test mode (only send to hub administrator)" +#: ../../include/text.php:1143 +msgid "stupefied" msgstr "" -#: ../../include/selectors.php:30 -msgid "Frequently" +#: ../../include/text.php:1144 +msgid "puzzled" msgstr "" -#: ../../include/selectors.php:31 -msgid "Hourly" +#: ../../include/text.php:1145 +msgid "interested" msgstr "" -#: ../../include/selectors.php:32 -msgid "Twice daily" +#: ../../include/text.php:1146 +msgid "bitter" msgstr "" -#: ../../include/selectors.php:33 -msgid "Daily" +#: ../../include/text.php:1147 +msgid "cheerful" msgstr "" -#: ../../include/selectors.php:34 -msgid "Weekly" +#: ../../include/text.php:1148 +msgid "alive" msgstr "" -#: ../../include/selectors.php:35 -msgid "Monthly" +#: ../../include/text.php:1149 +msgid "annoyed" msgstr "" -#: ../../include/selectors.php:49 -msgid "Currently Male" +#: ../../include/text.php:1150 +msgid "anxious" msgstr "" -#: ../../include/selectors.php:49 -msgid "Currently Female" +#: ../../include/text.php:1151 +msgid "cranky" msgstr "" -#: ../../include/selectors.php:49 -msgid "Mostly Male" +#: ../../include/text.php:1152 +msgid "disturbed" msgstr "" -#: ../../include/selectors.php:49 -msgid "Mostly Female" +#: ../../include/text.php:1153 +msgid "frustrated" msgstr "" -#: ../../include/selectors.php:49 -msgid "Transgender" +#: ../../include/text.php:1154 +msgid "depressed" msgstr "" -#: ../../include/selectors.php:49 -msgid "Intersex" +#: ../../include/text.php:1155 +msgid "motivated" msgstr "" -#: ../../include/selectors.php:49 -msgid "Transsexual" +#: ../../include/text.php:1156 +msgid "relaxed" msgstr "" -#: ../../include/selectors.php:49 -msgid "Hermaphrodite" +#: ../../include/text.php:1157 +msgid "surprised" msgstr "" -#: ../../include/selectors.php:49 -msgid "Neuter" +#: ../../include/text.php:1328 ../../include/js_strings.php:70 +msgid "Monday" msgstr "" -#: ../../include/selectors.php:49 -msgid "Non-specific" +#: ../../include/text.php:1328 ../../include/js_strings.php:71 +msgid "Tuesday" msgstr "" -#: ../../include/selectors.php:49 -msgid "Undecided" +#: ../../include/text.php:1328 ../../include/js_strings.php:72 +msgid "Wednesday" msgstr "" -#: ../../include/selectors.php:85 ../../include/selectors.php:104 -msgid "Males" +#: ../../include/text.php:1328 ../../include/js_strings.php:73 +msgid "Thursday" msgstr "" -#: ../../include/selectors.php:85 ../../include/selectors.php:104 -msgid "Females" +#: ../../include/text.php:1328 ../../include/js_strings.php:74 +msgid "Friday" msgstr "" -#: ../../include/selectors.php:85 -msgid "Gay" +#: ../../include/text.php:1328 ../../include/js_strings.php:75 +msgid "Saturday" msgstr "" -#: ../../include/selectors.php:85 -msgid "Lesbian" +#: ../../include/text.php:1328 ../../include/js_strings.php:69 +msgid "Sunday" msgstr "" -#: ../../include/selectors.php:85 -msgid "No Preference" +#: ../../include/text.php:1332 ../../include/js_strings.php:45 +msgid "January" msgstr "" -#: ../../include/selectors.php:85 -msgid "Bisexual" +#: ../../include/text.php:1332 ../../include/js_strings.php:46 +msgid "February" msgstr "" -#: ../../include/selectors.php:85 -msgid "Autosexual" +#: ../../include/text.php:1332 ../../include/js_strings.php:47 +msgid "March" msgstr "" -#: ../../include/selectors.php:85 -msgid "Abstinent" +#: ../../include/text.php:1332 ../../include/js_strings.php:48 +msgid "April" msgstr "" -#: ../../include/selectors.php:85 -msgid "Virgin" +#: ../../include/text.php:1332 +msgid "May" msgstr "" -#: ../../include/selectors.php:85 -msgid "Deviant" +#: ../../include/text.php:1332 ../../include/js_strings.php:50 +msgid "June" msgstr "" -#: ../../include/selectors.php:85 -msgid "Fetish" +#: ../../include/text.php:1332 ../../include/js_strings.php:51 +msgid "July" msgstr "" -#: ../../include/selectors.php:85 -msgid "Oodles" +#: ../../include/text.php:1332 ../../include/js_strings.php:52 +msgid "August" msgstr "" -#: ../../include/selectors.php:85 -msgid "Nonsexual" +#: ../../include/text.php:1332 ../../include/js_strings.php:53 +msgid "September" msgstr "" -#: ../../include/selectors.php:123 ../../include/selectors.php:140 -msgid "Single" +#: ../../include/text.php:1332 ../../include/js_strings.php:54 +msgid "October" msgstr "" -#: ../../include/selectors.php:123 -msgid "Lonely" +#: ../../include/text.php:1332 ../../include/js_strings.php:55 +msgid "November" msgstr "" -#: ../../include/selectors.php:123 -msgid "Available" +#: ../../include/text.php:1332 ../../include/js_strings.php:56 +msgid "December" msgstr "" -#: ../../include/selectors.php:123 -msgid "Unavailable" +#: ../../include/text.php:1409 ../../include/text.php:1413 +msgid "Unknown Attachment" msgstr "" -#: ../../include/selectors.php:123 -msgid "Has crush" +#: ../../include/text.php:1415 +msgid "unknown" msgstr "" -#: ../../include/selectors.php:123 -msgid "Infatuated" +#: ../../include/text.php:1451 +msgid "remove category" msgstr "" -#: ../../include/selectors.php:123 ../../include/selectors.php:140 -msgid "Dating" +#: ../../include/text.php:1525 +msgid "remove from file" msgstr "" -#: ../../include/selectors.php:123 -msgid "Unfaithful" +#: ../../include/text.php:1795 +msgid "Page layout" msgstr "" -#: ../../include/selectors.php:123 -msgid "Sex Addict" +#: ../../include/text.php:1795 +msgid "You can create your own with the layouts tool" msgstr "" -#: ../../include/selectors.php:123 -msgid "Friends/Benefits" +#: ../../include/text.php:1823 +msgid "Page content type" msgstr "" -#: ../../include/selectors.php:123 -msgid "Casual" +#: ../../include/text.php:1956 +msgid "activity" msgstr "" -#: ../../include/selectors.php:123 -msgid "Engaged" +#: ../../include/text.php:2019 +msgid "a-z, 0-9, -, _, and . only" msgstr "" -#: ../../include/selectors.php:123 ../../include/selectors.php:140 -msgid "Married" +#: ../../include/text.php:2291 +msgid "Design Tools" msgstr "" -#: ../../include/selectors.php:123 -msgid "Imaginarily married" +#: ../../include/text.php:2297 +msgid "Pages" msgstr "" -#: ../../include/selectors.php:123 -msgid "Partners" +#: ../../include/text.php:2319 +msgid "Import website..." msgstr "" -#: ../../include/selectors.php:123 ../../include/selectors.php:140 -msgid "Cohabiting" +#: ../../include/text.php:2320 +msgid "Select folder to import" msgstr "" -#: ../../include/selectors.php:123 -msgid "Common law" +#: ../../include/text.php:2321 +msgid "Import from a zipped folder:" msgstr "" -#: ../../include/selectors.php:123 -msgid "Happy" +#: ../../include/text.php:2322 +msgid "Import from cloud files:" msgstr "" -#: ../../include/selectors.php:123 -msgid "Not looking" +#: ../../include/text.php:2323 +msgid "/cloud/channel/path/to/folder" msgstr "" -#: ../../include/selectors.php:123 -msgid "Swinger" +#: ../../include/text.php:2324 +msgid "Enter path to website files" msgstr "" -#: ../../include/selectors.php:123 -msgid "Betrayed" +#: ../../include/text.php:2325 +msgid "Select folder" msgstr "" -#: ../../include/selectors.php:123 ../../include/selectors.php:140 -msgid "Separated" +#: ../../include/text.php:2326 +msgid "Export website..." msgstr "" -#: ../../include/selectors.php:123 -msgid "Unstable" +#: ../../include/text.php:2327 +msgid "Export to a zip file" msgstr "" -#: ../../include/selectors.php:123 ../../include/selectors.php:140 -msgid "Divorced" +#: ../../include/text.php:2328 +msgid "website.zip" msgstr "" -#: ../../include/selectors.php:123 -msgid "Imaginarily divorced" +#: ../../include/text.php:2329 +msgid "Enter a name for the zip file." msgstr "" -#: ../../include/selectors.php:123 ../../include/selectors.php:140 -msgid "Widowed" +#: ../../include/text.php:2330 +msgid "Export to cloud files" msgstr "" -#: ../../include/selectors.php:123 -msgid "Uncertain" +#: ../../include/text.php:2331 +msgid "/path/to/export/folder" msgstr "" -#: ../../include/selectors.php:123 ../../include/selectors.php:140 -msgid "It's complicated" +#: ../../include/text.php:2332 +msgid "Enter a path to a cloud files destination." msgstr "" -#: ../../include/selectors.php:123 -msgid "Don't care" +#: ../../include/text.php:2333 +msgid "Specify folder" msgstr "" -#: ../../include/selectors.php:123 -msgid "Ask me" +#: ../../include/taxonomy.php:228 ../../include/taxonomy.php:249 +msgid "Tags" msgstr "" -#: ../../include/conversation.php:200 -#, php-format -msgid "%1$s is now connected with %2$s" +#: ../../include/taxonomy.php:293 +msgid "Keywords" msgstr "" -#: ../../include/conversation.php:235 -#, php-format -msgid "%1$s poked %2$s" +#: ../../include/taxonomy.php:314 +msgid "have" msgstr "" -#: ../../include/conversation.php:239 ../../include/text.php:1115 -#: ../../include/text.php:1120 -msgid "poked" +#: ../../include/taxonomy.php:314 +msgid "has" msgstr "" -#: ../../include/conversation.php:689 -#, php-format -msgid "View %s's profile @ %s" +#: ../../include/taxonomy.php:315 +msgid "want" msgstr "" -#: ../../include/conversation.php:709 -msgid "Categories:" +#: ../../include/taxonomy.php:315 +msgid "wants" msgstr "" -#: ../../include/conversation.php:710 -msgid "Filed under:" +#: ../../include/taxonomy.php:316 +msgid "likes" msgstr "" -#: ../../include/conversation.php:735 -msgid "View in context" +#: ../../include/taxonomy.php:317 +msgid "dislikes" msgstr "" -#: ../../include/conversation.php:832 -msgid "remove" +#: ../../include/connections.php:127 +msgid "New window" +msgstr "" + +#: ../../include/connections.php:128 +msgid "Open the selected location in a different window or browser tab" msgstr "" -#: ../../include/conversation.php:836 ../../include/nav.php:262 +<<<<<<< HEAD +#: ../../include/zot.php:646 +msgid "Invalid data packet" +======= +#: ../../include/conversation.php:838 ../../include/nav.php:272 msgid "Loading..." +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../include/conversation.php:837 -msgid "Delete Selected Items" +#: ../../include/zot.php:662 +msgid "Unable to verify channel signature" msgstr "" -#: ../../include/conversation.php:880 -msgid "View Source" +#: ../../include/zot.php:2313 +#, php-format +msgid "Unable to verify site signature for %s" msgstr "" -#: ../../include/conversation.php:890 -msgid "Follow Thread" +#: ../../include/zot.php:3762 +msgid "invalid target signature" msgstr "" -#: ../../include/conversation.php:899 -msgid "Unfollow Thread" +#: ../../include/datetime.php:147 +msgid "Birthday" msgstr "" -#: ../../include/conversation.php:990 -msgid "Activity/Posts" +#: ../../include/datetime.php:149 +msgid "Age: " msgstr "" -#: ../../include/conversation.php:1010 -msgid "Edit Connection" +#: ../../include/datetime.php:151 +msgid "YYYY-MM-DD or MM-DD" msgstr "" -#: ../../include/conversation.php:1020 -msgid "Message" +#: ../../include/datetime.php:286 ../../boot.php:2419 +msgid "never" msgstr "" -#: ../../include/conversation.php:1154 -#, php-format -msgid "%s likes this." +#: ../../include/datetime.php:292 +msgid "less than a second ago" msgstr "" -#: ../../include/conversation.php:1154 +#: ../../include/datetime.php:310 #, php-format -msgid "%s doesn't like this." +msgctxt "e.g. 22 hours ago, 1 minute ago" +msgid "%1$d %2$s ago" msgstr "" -#: ../../include/conversation.php:1158 -#, php-format -msgid "<span %1$s>%2$d people</span> like this." -msgid_plural "<span %1$s>%2$d people</span> like this." +#: ../../include/datetime.php:321 +msgctxt "relative_date" +msgid "year" +msgid_plural "years" msgstr[0] "" msgstr[1] "" -#: ../../include/conversation.php:1160 -#, php-format -msgid "<span %1$s>%2$d people</span> don't like this." -msgid_plural "<span %1$s>%2$d people</span> don't like this." +#: ../../include/datetime.php:324 +msgctxt "relative_date" +msgid "month" +msgid_plural "months" msgstr[0] "" msgstr[1] "" -#: ../../include/conversation.php:1166 -msgid "and" -msgstr "" +#: ../../include/datetime.php:327 +msgctxt "relative_date" +msgid "week" +msgid_plural "weeks" +msgstr[0] "" +msgstr[1] "" -#: ../../include/conversation.php:1169 -#, php-format -msgid ", and %d other people" -msgid_plural ", and %d other people" +#: ../../include/datetime.php:330 +msgctxt "relative_date" +msgid "day" +msgid_plural "days" msgstr[0] "" msgstr[1] "" -#: ../../include/conversation.php:1170 +#: ../../include/datetime.php:333 +msgctxt "relative_date" +msgid "hour" +msgid_plural "hours" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/datetime.php:336 +msgctxt "relative_date" +msgid "minute" +msgid_plural "minutes" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/datetime.php:339 +msgctxt "relative_date" +msgid "second" +msgid_plural "seconds" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/datetime.php:576 #, php-format -msgid "%s like this." +msgid "%1$s's birthday" msgstr "" -#: ../../include/conversation.php:1170 +#: ../../include/datetime.php:577 #, php-format -msgid "%s don't like this." +msgid "Happy Birthday %1$s" msgstr "" -#: ../../include/conversation.php:1213 -msgid "Set your location" +#: ../../include/selectors.php:30 +msgid "Frequently" msgstr "" -#: ../../include/conversation.php:1214 -msgid "Clear browser location" +#: ../../include/selectors.php:31 +msgid "Hourly" msgstr "" -#: ../../include/conversation.php:1262 -msgid "Tag term:" +#: ../../include/selectors.php:32 +msgid "Twice daily" msgstr "" -#: ../../include/conversation.php:1263 -msgid "Where are you right now?" +#: ../../include/selectors.php:33 +msgid "Daily" msgstr "" -#: ../../include/conversation.php:1268 -msgid "Choose a different album..." +#: ../../include/selectors.php:34 +msgid "Weekly" msgstr "" -#: ../../include/conversation.php:1272 -msgid "Comments enabled" +#: ../../include/selectors.php:35 +msgid "Monthly" msgstr "" -#: ../../include/conversation.php:1273 -msgid "Comments disabled" +#: ../../include/selectors.php:49 +msgid "Currently Male" msgstr "" -#: ../../include/conversation.php:1311 -msgid "Page link name" +<<<<<<< HEAD +#: ../../include/selectors.php:49 +msgid "Currently Female" msgstr "" -#: ../../include/conversation.php:1314 -msgid "Post as" +#: ../../include/selectors.php:49 +msgid "Mostly Male" msgstr "" -#: ../../include/conversation.php:1328 -msgid "Toggle voting" +#: ../../include/selectors.php:49 +msgid "Mostly Female" msgstr "" -#: ../../include/conversation.php:1331 -msgid "Disable comments" +#: ../../include/selectors.php:49 +msgid "Transgender" msgstr "" -#: ../../include/conversation.php:1332 -msgid "Toggle comments" +#: ../../include/selectors.php:49 +msgid "Intersex" msgstr "" -#: ../../include/conversation.php:1340 -msgid "Categories (optional, comma-separated list)" +#: ../../include/selectors.php:49 +msgid "Transsexual" msgstr "" -#: ../../include/conversation.php:1363 -msgid "Other networks and post services" +#: ../../include/selectors.php:49 +msgid "Hermaphrodite" msgstr "" -#: ../../include/conversation.php:1369 -msgid "Set publish date" +#: ../../include/selectors.php:49 +msgid "Neuter" +msgstr "" + +#: ../../include/selectors.php:49 +msgid "Non-specific" +msgstr "" + +#: ../../include/selectors.php:49 +msgid "Undecided" +msgstr "" + +#: ../../include/selectors.php:85 ../../include/selectors.php:104 +msgid "Males" +msgstr "" + +#: ../../include/selectors.php:85 ../../include/selectors.php:104 +msgid "Females" +msgstr "" + +#: ../../include/selectors.php:85 +msgid "Gay" +msgstr "" + +#: ../../include/selectors.php:85 +msgid "Lesbian" +msgstr "" + +#: ../../include/selectors.php:85 +msgid "No Preference" +msgstr "" + +#: ../../include/selectors.php:85 +msgid "Bisexual" +msgstr "" + +#: ../../include/selectors.php:85 +msgid "Autosexual" +msgstr "" + +#: ../../include/selectors.php:85 +msgid "Abstinent" +msgstr "" + +#: ../../include/selectors.php:85 +msgid "Virgin" +msgstr "" + +#: ../../include/selectors.php:85 +msgid "Deviant" +msgstr "" + +#: ../../include/selectors.php:85 +msgid "Fetish" +msgstr "" + +#: ../../include/selectors.php:85 +msgid "Oodles" +msgstr "" + +#: ../../include/selectors.php:85 +msgid "Nonsexual" +msgstr "" + +#: ../../include/selectors.php:123 ../../include/selectors.php:140 +msgid "Single" msgstr "" -#: ../../include/conversation.php:1632 +#: ../../include/selectors.php:123 +msgid "Lonely" +msgstr "" +======= +#: ../../include/conversation.php:1634 msgid "Discover" msgstr "" -#: ../../include/conversation.php:1635 +#: ../../include/conversation.php:1637 msgid "Imported public streams" msgstr "" -#: ../../include/conversation.php:1640 +#: ../../include/conversation.php:1642 msgid "Commented Order" msgstr "" -#: ../../include/conversation.php:1643 +#: ../../include/conversation.php:1645 msgid "Sort by Comment Date" msgstr "" -#: ../../include/conversation.php:1647 +#: ../../include/conversation.php:1649 msgid "Posted Order" msgstr "" -#: ../../include/conversation.php:1650 +#: ../../include/conversation.php:1652 msgid "Sort by Post Date" msgstr "" -#: ../../include/conversation.php:1658 +#: ../../include/conversation.php:1660 msgid "Posts that mention or involve you" msgstr "" -#: ../../include/conversation.php:1667 +#: ../../include/conversation.php:1669 msgid "Activity Stream - by date" msgstr "" -#: ../../include/conversation.php:1673 +#: ../../include/conversation.php:1675 msgid "Starred" msgstr "" -#: ../../include/conversation.php:1676 +#: ../../include/conversation.php:1678 msgid "Favourite Posts" msgstr "" -#: ../../include/conversation.php:1683 +#: ../../include/conversation.php:1685 msgid "Spam" msgstr "" -#: ../../include/conversation.php:1686 +#: ../../include/conversation.php:1688 msgid "Posts flagged as SPAM" msgstr "" -#: ../../include/conversation.php:1761 ../../include/nav.php:365 +#: ../../include/conversation.php:1763 ../../include/nav.php:372 msgid "Status Messages and Posts" msgstr "" -#: ../../include/conversation.php:1774 ../../include/nav.php:378 +#: ../../include/conversation.php:1776 ../../include/nav.php:385 msgid "Profile Details" msgstr "" -#: ../../include/conversation.php:1784 ../../include/nav.php:388 +#: ../../include/conversation.php:1786 ../../include/nav.php:395 #: ../../include/photos.php:528 msgid "Photo Albums" msgstr "" -#: ../../include/conversation.php:1792 ../../include/nav.php:396 +#: ../../include/conversation.php:1794 ../../include/nav.php:403 msgid "Files and Storage" msgstr "" -#: ../../include/conversation.php:1828 ../../include/nav.php:431 +#: ../../include/conversation.php:1830 ../../include/nav.php:438 msgid "Bookmarks" msgstr "" -#: ../../include/conversation.php:1831 ../../include/nav.php:434 +#: ../../include/conversation.php:1833 ../../include/nav.php:441 msgid "Saved Bookmarks" msgstr "" -#: ../../include/conversation.php:1842 ../../include/nav.php:445 +#: ../../include/conversation.php:1844 ../../include/nav.php:452 msgid "View Webpages" msgstr "" -#: ../../include/conversation.php:1911 +#: ../../include/conversation.php:1913 msgctxt "noun" msgid "Attending" msgid_plural "Attending" msgstr[0] "" msgstr[1] "" -#: ../../include/conversation.php:1914 +#: ../../include/conversation.php:1916 msgctxt "noun" msgid "Not Attending" msgid_plural "Not Attending" msgstr[0] "" msgstr[1] "" -#: ../../include/conversation.php:1917 +#: ../../include/conversation.php:1919 msgctxt "noun" msgid "Undecided" msgid_plural "Undecided" msgstr[0] "" msgstr[1] "" -#: ../../include/conversation.php:1920 +#: ../../include/conversation.php:1922 msgctxt "noun" msgid "Agree" msgid_plural "Agrees" msgstr[0] "" msgstr[1] "" -#: ../../include/conversation.php:1923 +#: ../../include/conversation.php:1925 msgctxt "noun" msgid "Disagree" msgid_plural "Disagrees" msgstr[0] "" msgstr[1] "" -#: ../../include/conversation.php:1926 +#: ../../include/conversation.php:1928 msgctxt "noun" msgid "Abstain" msgid_plural "Abstains" msgstr[0] "" msgstr[1] "" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 -#: ../../include/permissions.php:35 -msgid "Can view my normal stream and posts" +#: ../../include/selectors.php:123 +msgid "Available" +msgstr "" + +#: ../../include/selectors.php:123 +msgid "Unavailable" msgstr "" -#: ../../include/permissions.php:39 -msgid "Can view my webpages" +#: ../../include/selectors.php:123 +msgid "Has crush" +msgstr "" + +#: ../../include/selectors.php:123 +msgid "Infatuated" +msgstr "" + +#: ../../include/selectors.php:123 ../../include/selectors.php:140 +msgid "Dating" +msgstr "" + +#: ../../include/selectors.php:123 +msgid "Unfaithful" msgstr "" -#: ../../include/permissions.php:43 -msgid "Can post on my channel page (\"wall\")" +#: ../../include/selectors.php:123 +msgid "Sex Addict" msgstr "" -#: ../../include/permissions.php:46 -msgid "Can like/dislike stuff" +#: ../../include/selectors.php:123 +msgid "Friends/Benefits" msgstr "" -#: ../../include/permissions.php:46 -msgid "Profiles and things other than posts/comments" +#: ../../include/selectors.php:123 +msgid "Casual" msgstr "" -#: ../../include/permissions.php:48 -msgid "Can forward to all my channel contacts via post @mentions" +#: ../../include/selectors.php:123 +msgid "Engaged" msgstr "" -#: ../../include/permissions.php:48 -msgid "Advanced - useful for creating group forum channels" +#: ../../include/selectors.php:123 ../../include/selectors.php:140 +msgid "Married" msgstr "" -#: ../../include/permissions.php:49 -msgid "Can chat with me (when available)" +#: ../../include/selectors.php:123 +msgid "Imaginarily married" msgstr "" -#: ../../include/permissions.php:50 -msgid "Can write to my file storage and photos" +#: ../../include/selectors.php:123 +msgid "Partners" msgstr "" -#: ../../include/permissions.php:51 -msgid "Can edit my webpages" +#: ../../include/selectors.php:123 ../../include/selectors.php:140 +msgid "Cohabiting" msgstr "" -#: ../../include/permissions.php:53 -msgid "Somewhat advanced - very useful in open communities" +#: ../../include/selectors.php:123 +msgid "Common law" msgstr "" -#: ../../include/permissions.php:55 -msgid "Can administer my channel resources" +#: ../../include/selectors.php:123 +msgid "Happy" msgstr "" -#: ../../include/permissions.php:55 -msgid "Extremely advanced. Leave this alone unless you know what you are doing" +#: ../../include/selectors.php:123 +msgid "Not looking" msgstr "" -#: ../../include/dir_fns.php:141 -msgid "Directory Options" +#: ../../include/selectors.php:123 +msgid "Swinger" msgstr "" -#: ../../include/dir_fns.php:143 -msgid "Safe Mode" +#: ../../include/selectors.php:123 +msgid "Betrayed" msgstr "" -#: ../../include/dir_fns.php:144 -msgid "Public Forums Only" +#: ../../include/selectors.php:123 ../../include/selectors.php:140 +msgid "Separated" msgstr "" -#: ../../include/dir_fns.php:145 -msgid "This Website Only" +#: ../../include/selectors.php:123 +msgid "Unstable" +msgstr "" + +#: ../../include/selectors.php:123 ../../include/selectors.php:140 +msgid "Divorced" +msgstr "" + +#: ../../include/selectors.php:123 +msgid "Imaginarily divorced" +msgstr "" + +#: ../../include/selectors.php:123 ../../include/selectors.php:140 +msgid "Widowed" +msgstr "" + +#: ../../include/selectors.php:123 +msgid "Uncertain" +msgstr "" + +#: ../../include/selectors.php:123 ../../include/selectors.php:140 +msgid "It's complicated" +msgstr "" + +#: ../../include/selectors.php:123 +msgid "Don't care" +msgstr "" + +#: ../../include/selectors.php:123 +msgid "Ask me" +msgstr "" + +#: ../../include/auth.php:148 +msgid "Logged out." +msgstr "" + +#: ../../include/auth.php:275 +msgid "Failed authentication" msgstr "" #: ../../include/bookmarks.php:34 @@ -11424,455 +13249,592 @@ msgstr "" msgid "%1$s's bookmarks" msgstr "" -#: ../../include/import.php:41 -msgid "" -"Cannot create a duplicate channel identifier on this system. Import failed." +#: ../../include/attach.php:250 ../../include/attach.php:339 +msgid "Item was not found." msgstr "" -#: ../../include/import.php:105 -msgid "Cloned channel not found. Import failed." +#: ../../include/attach.php:500 +msgid "No source file." msgstr "" -#: ../../include/text.php:478 -msgid "prev" +#: ../../include/attach.php:522 +msgid "Cannot locate file to replace" msgstr "" -#: ../../include/text.php:480 -msgid "first" +#: ../../include/attach.php:540 +msgid "Cannot locate file to revise/update" msgstr "" -#: ../../include/text.php:509 -msgid "last" +#: ../../include/attach.php:671 +#, php-format +msgid "File exceeds size limit of %d" msgstr "" -#: ../../include/text.php:512 -msgid "next" +#: ../../include/attach.php:685 +#, php-format +msgid "You have reached your limit of %1$.0f Mbytes attachment storage." msgstr "" -#: ../../include/text.php:523 -msgid "older" +#: ../../include/attach.php:855 +msgid "File upload failed. Possible system limit or action terminated." msgstr "" -#: ../../include/text.php:525 -msgid "newer" +#: ../../include/attach.php:868 +msgid "Stored file could not be verified. Upload failed." msgstr "" -#: ../../include/text.php:945 -msgid "No connections" +#: ../../include/attach.php:923 ../../include/attach.php:939 +msgid "Path not available." msgstr "" -#: ../../include/text.php:970 +#: ../../include/attach.php:988 ../../include/attach.php:1153 +msgid "Empty pathname" +msgstr "" + +#: ../../include/attach.php:1014 +msgid "duplicate filename or path" +msgstr "" + +#: ../../include/attach.php:1039 +msgid "Path not found." +msgstr "" + +#: ../../include/attach.php:1107 +msgid "mkdir failed." +msgstr "" + +#: ../../include/attach.php:1111 +msgid "database storage failed." +msgstr "" + +#: ../../include/attach.php:1159 +msgid "Empty path" +msgstr "" + +#: ../../include/page_widgets.php:7 +msgid "New Page" +msgstr "" + +#: ../../include/contact_widgets.php:11 #, php-format -msgid "View all %s connections" +msgid "%d invitation available" +msgid_plural "%d invitations available" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/contact_widgets.php:19 +msgid "Find Channels" msgstr "" -#: ../../include/text.php:1115 ../../include/text.php:1120 -msgid "poke" +#: ../../include/contact_widgets.php:20 +msgid "Enter name or interest" msgstr "" -#: ../../include/text.php:1121 -msgid "ping" +#: ../../include/contact_widgets.php:21 +msgid "Connect/Follow" msgstr "" -#: ../../include/text.php:1121 -msgid "pinged" +#: ../../include/contact_widgets.php:22 +msgid "Examples: Robert Morgenstein, Fishing" msgstr "" -#: ../../include/text.php:1122 -msgid "prod" +#: ../../include/contact_widgets.php:26 +msgid "Random Profile" msgstr "" -#: ../../include/text.php:1122 -msgid "prodded" +#: ../../include/contact_widgets.php:27 +msgid "Invite Friends" msgstr "" -#: ../../include/text.php:1123 -msgid "slap" +#: ../../include/contact_widgets.php:29 +msgid "Advanced example: name=fred and country=iceland" msgstr "" -#: ../../include/text.php:1123 -msgid "slapped" +#: ../../include/contact_widgets.php:122 +#, php-format +msgid "%d connection in common" +msgid_plural "%d connections in common" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/contact_widgets.php:127 +msgid "show more" msgstr "" -#: ../../include/text.php:1124 -msgid "finger" +#: ../../include/nav.php:88 +msgid "Remote authentication" msgstr "" -#: ../../include/text.php:1124 -msgid "fingered" +#: ../../include/nav.php:88 +msgid "Click to authenticate to your home hub" msgstr "" -#: ../../include/text.php:1125 -msgid "rebuff" +#: ../../include/nav.php:99 ../../include/nav.php:123 ../../boot.php:1590 +msgid "Logout" msgstr "" -#: ../../include/text.php:1125 -msgid "rebuffed" +#: ../../include/nav.php:99 ../../include/nav.php:123 +msgid "End this session" msgstr "" -#: ../../include/text.php:1137 -msgid "happy" +#: ../../include/nav.php:102 +msgid "Your profile page" msgstr "" -#: ../../include/text.php:1138 -msgid "sad" +<<<<<<< HEAD +#: ../../include/nav.php:105 +msgid "Manage/Edit profiles" msgstr "" -#: ../../include/text.php:1139 -msgid "mellow" +#: ../../include/nav.php:107 +msgid "Edit your profile" msgstr "" -#: ../../include/text.php:1140 -msgid "tired" +#: ../../include/nav.php:113 +msgid "Sign in" msgstr "" -#: ../../include/text.php:1141 -msgid "perky" +#: ../../include/nav.php:138 +msgid "Take me home" msgstr "" -#: ../../include/text.php:1142 -msgid "angry" +#: ../../include/nav.php:140 +msgid "Log me out of this site" msgstr "" -#: ../../include/text.php:1143 -msgid "stupefied" +#: ../../include/nav.php:145 +msgid "Create an account" msgstr "" -#: ../../include/text.php:1144 -msgid "puzzled" +#: ../../include/nav.php:157 +msgid "Help and documentation" msgstr "" -#: ../../include/text.php:1145 -msgid "interested" +#: ../../include/nav.php:160 +msgid "Search site @name, #tag, ?docs, content" msgstr "" -#: ../../include/text.php:1146 -msgid "bitter" +#: ../../include/nav.php:172 +msgid "Grid" msgstr "" -#: ../../include/text.php:1147 -msgid "cheerful" +#: ../../include/nav.php:172 +msgid "Your grid" msgstr "" -#: ../../include/text.php:1148 -msgid "alive" +#: ../../include/nav.php:173 +msgid "View your network/grid" msgstr "" -#: ../../include/text.php:1149 -msgid "annoyed" +#: ../../include/nav.php:174 +msgid "Mark all grid notifications seen" msgstr "" -#: ../../include/text.php:1150 -msgid "anxious" +#: ../../include/nav.php:176 +msgid "Channel home" msgstr "" -#: ../../include/text.php:1151 -msgid "cranky" +#: ../../include/nav.php:177 +msgid "View your channel home" msgstr "" -#: ../../include/text.php:1152 -msgid "disturbed" +#: ../../include/nav.php:178 +msgid "Mark all channel notifications seen" msgstr "" -#: ../../include/text.php:1153 -msgid "frustrated" +#: ../../include/nav.php:184 +msgid "Notices" msgstr "" -#: ../../include/text.php:1154 -msgid "depressed" +#: ../../include/nav.php:184 +msgid "Notifications" msgstr "" -#: ../../include/text.php:1155 -msgid "motivated" +#: ../../include/nav.php:185 +msgid "View all notifications" msgstr "" -#: ../../include/text.php:1156 -msgid "relaxed" +#: ../../include/nav.php:188 +msgid "Private mail" msgstr "" -#: ../../include/text.php:1157 -msgid "surprised" +#: ../../include/nav.php:189 +msgid "View your private messages" +msgstr "" + +#: ../../include/nav.php:190 +msgid "Mark all private messages seen" +msgstr "" + +#: ../../include/nav.php:196 +msgid "Event Calendar" msgstr "" -#: ../../include/text.php:1333 ../../include/js_strings.php:70 +#: ../../include/nav.php:197 +msgid "View events" +msgstr "" + +#: ../../include/nav.php:198 +msgid "Mark all events seen" +msgstr "" + +#: ../../include/nav.php:201 +msgid "Manage Your Channels" +msgstr "" + +#: ../../include/nav.php:203 +msgid "Account/Channel Settings" +msgstr "" + +#: ../../include/nav.php:211 +msgid "Site Setup and Configuration" +msgstr "" + +#: ../../include/nav.php:268 ../../include/conversation.php:838 +msgid "Loading..." +msgstr "" + +#: ../../include/nav.php:273 +msgid "@name, #tag, ?doc, content" +msgstr "" + +#: ../../include/nav.php:274 +msgid "Please wait..." +msgstr "" + +#: ../../include/nav.php:276 +msgid "Add Apps" +msgstr "" + +#: ../../include/channel.php:33 +msgid "Unable to obtain identity information from database" +msgstr "" + +#: ../../include/channel.php:67 +msgid "Empty name" +msgstr "" + +#: ../../include/channel.php:70 +msgid "Name too long" +msgstr "" + +#: ../../include/channel.php:181 +msgid "No account identifier" +msgstr "" + +#: ../../include/channel.php:193 +msgid "Nickname is required." +msgstr "" + +#: ../../include/channel.php:207 +msgid "Reserved nickname. Please choose another." +msgstr "" + +#: ../../include/channel.php:212 +msgid "" +"Nickname has unsupported characters or is already being used on this site." +msgstr "" + +#: ../../include/channel.php:271 +msgid "Unable to retrieve created identity" +msgstr "" + +#: ../../include/channel.php:343 +msgid "Default Profile" +msgstr "" + +#: ../../include/channel.php:1044 +msgid "Create New Profile" +msgstr "" + +#: ../../include/channel.php:1064 +msgid "Visible to everybody" +msgstr "" + +#: ../../include/channel.php:1137 ../../include/channel.php:1231 +msgid "Gender:" +msgstr "" + +#: ../../include/channel.php:1139 ../../include/channel.php:1286 +msgid "Homepage:" +msgstr "" + +#: ../../include/channel.php:1140 +msgid "Online Now" +======= +#: ../../include/text.php:1335 ../../include/js_strings.php:70 msgid "Monday" msgstr "" -#: ../../include/text.php:1333 ../../include/js_strings.php:71 +#: ../../include/text.php:1335 ../../include/js_strings.php:71 msgid "Tuesday" msgstr "" -#: ../../include/text.php:1333 ../../include/js_strings.php:72 +#: ../../include/text.php:1335 ../../include/js_strings.php:72 msgid "Wednesday" msgstr "" -#: ../../include/text.php:1333 ../../include/js_strings.php:73 +#: ../../include/text.php:1335 ../../include/js_strings.php:73 msgid "Thursday" msgstr "" -#: ../../include/text.php:1333 ../../include/js_strings.php:74 +#: ../../include/text.php:1335 ../../include/js_strings.php:74 msgid "Friday" msgstr "" -#: ../../include/text.php:1333 ../../include/js_strings.php:75 +#: ../../include/text.php:1335 ../../include/js_strings.php:75 msgid "Saturday" msgstr "" -#: ../../include/text.php:1333 ../../include/js_strings.php:69 +#: ../../include/text.php:1335 ../../include/js_strings.php:69 msgid "Sunday" msgstr "" -#: ../../include/text.php:1337 ../../include/js_strings.php:45 +#: ../../include/text.php:1339 ../../include/js_strings.php:45 msgid "January" msgstr "" -#: ../../include/text.php:1337 ../../include/js_strings.php:46 +#: ../../include/text.php:1339 ../../include/js_strings.php:46 msgid "February" msgstr "" -#: ../../include/text.php:1337 ../../include/js_strings.php:47 +#: ../../include/text.php:1339 ../../include/js_strings.php:47 msgid "March" msgstr "" -#: ../../include/text.php:1337 ../../include/js_strings.php:48 +#: ../../include/text.php:1339 ../../include/js_strings.php:48 msgid "April" msgstr "" -#: ../../include/text.php:1337 +#: ../../include/text.php:1339 msgid "May" msgstr "" -#: ../../include/text.php:1337 ../../include/js_strings.php:50 +#: ../../include/text.php:1339 ../../include/js_strings.php:50 msgid "June" msgstr "" -#: ../../include/text.php:1337 ../../include/js_strings.php:51 +#: ../../include/text.php:1339 ../../include/js_strings.php:51 msgid "July" msgstr "" -#: ../../include/text.php:1337 ../../include/js_strings.php:52 +#: ../../include/text.php:1339 ../../include/js_strings.php:52 msgid "August" msgstr "" -#: ../../include/text.php:1337 ../../include/js_strings.php:53 +#: ../../include/text.php:1339 ../../include/js_strings.php:53 msgid "September" msgstr "" -#: ../../include/text.php:1337 ../../include/js_strings.php:54 +#: ../../include/text.php:1339 ../../include/js_strings.php:54 msgid "October" msgstr "" -#: ../../include/text.php:1337 ../../include/js_strings.php:55 +#: ../../include/text.php:1339 ../../include/js_strings.php:55 msgid "November" msgstr "" -#: ../../include/text.php:1337 ../../include/js_strings.php:56 +#: ../../include/text.php:1339 ../../include/js_strings.php:56 msgid "December" msgstr "" -#: ../../include/text.php:1401 ../../include/text.php:1405 +#: ../../include/text.php:1403 ../../include/text.php:1407 msgid "Unknown Attachment" msgstr "" -#: ../../include/text.php:1407 ../../include/feedutils.php:745 +#: ../../include/text.php:1409 msgid "unknown" msgstr "" -#: ../../include/text.php:1443 +#: ../../include/text.php:1445 msgid "remove category" msgstr "" -#: ../../include/text.php:1517 +#: ../../include/text.php:1519 msgid "remove from file" msgstr "" -#: ../../include/text.php:1636 ../../include/message.php:12 -msgid "Download binary/encrypted content" -msgstr "" - -#: ../../include/text.php:1795 ../../include/language.php:367 +#: ../../include/text.php:1781 ../../include/language.php:367 msgid "default" msgstr "" -#: ../../include/text.php:1803 +#: ../../include/text.php:1789 msgid "Page layout" msgstr "" -#: ../../include/text.php:1803 +#: ../../include/text.php:1789 msgid "You can create your own with the layouts tool" msgstr "" -#: ../../include/text.php:1831 +#: ../../include/text.php:1817 msgid "Page content type" msgstr "" -#: ../../include/text.php:1964 +#: ../../include/text.php:1950 msgid "activity" msgstr "" -#: ../../include/text.php:2277 +#: ../../include/text.php:2264 msgid "Design Tools" msgstr "" -#: ../../include/text.php:2283 +#: ../../include/text.php:2270 msgid "Pages" msgstr "" -#: ../../include/text.php:2305 +#: ../../include/text.php:2292 msgid "Import website..." msgstr "" -#: ../../include/text.php:2306 +#: ../../include/text.php:2293 msgid "Select folder to import" msgstr "" -#: ../../include/text.php:2307 +#: ../../include/text.php:2294 msgid "Import from a zipped folder:" msgstr "" -#: ../../include/text.php:2308 +#: ../../include/text.php:2295 msgid "Import from cloud files:" msgstr "" -#: ../../include/text.php:2309 +#: ../../include/text.php:2296 msgid "/cloud/channel/path/to/folder" msgstr "" -#: ../../include/text.php:2310 +#: ../../include/text.php:2297 msgid "Enter path to website files" msgstr "" -#: ../../include/text.php:2311 +#: ../../include/text.php:2298 msgid "Select folder" msgstr "" -#: ../../include/text.php:2312 +#: ../../include/text.php:2299 msgid "Export website..." msgstr "" -#: ../../include/text.php:2313 +#: ../../include/text.php:2300 msgid "Export to a zip file" msgstr "" -#: ../../include/text.php:2314 +#: ../../include/text.php:2301 msgid "website.zip" msgstr "" -#: ../../include/text.php:2315 +#: ../../include/text.php:2302 msgid "Enter a name for the zip file." msgstr "" -#: ../../include/text.php:2316 +#: ../../include/text.php:2303 msgid "Export to cloud files" msgstr "" -#: ../../include/text.php:2317 +#: ../../include/text.php:2304 msgid "/path/to/export/folder" msgstr "" -#: ../../include/text.php:2318 +#: ../../include/text.php:2305 msgid "Enter a path to a cloud files destination." msgstr "" -#: ../../include/text.php:2319 +#: ../../include/text.php:2306 msgid "Specify folder" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../include/contact_widgets.php:11 -#, php-format -msgid "%d invitation available" -msgid_plural "%d invitations available" -msgstr[0] "" -msgstr[1] "" +#: ../../include/channel.php:1236 +msgid "Like this channel" +msgstr "" -#: ../../include/contact_widgets.php:19 -msgid "Find Channels" +#: ../../include/channel.php:1260 +msgid "j F, Y" msgstr "" -#: ../../include/contact_widgets.php:20 -msgid "Enter name or interest" +#: ../../include/channel.php:1261 +msgid "j F" msgstr "" -#: ../../include/contact_widgets.php:21 -msgid "Connect/Follow" +#: ../../include/channel.php:1268 +msgid "Birthday:" msgstr "" -#: ../../include/contact_widgets.php:22 -msgid "Examples: Robert Morgenstein, Fishing" +#: ../../include/channel.php:1281 +#, php-format +msgid "for %1$d %2$s" msgstr "" -#: ../../include/contact_widgets.php:26 -msgid "Random Profile" +#: ../../include/channel.php:1284 +msgid "Sexual Preference:" msgstr "" -#: ../../include/contact_widgets.php:27 -msgid "Invite Friends" +#: ../../include/channel.php:1290 +msgid "Tags:" msgstr "" -#: ../../include/contact_widgets.php:29 -msgid "Advanced example: name=fred and country=iceland" +#: ../../include/channel.php:1292 +msgid "Political Views:" msgstr "" -#: ../../include/contact_widgets.php:122 -#, php-format -msgid "%d connection in common" -msgid_plural "%d connections in common" -msgstr[0] "" -msgstr[1] "" +#: ../../include/channel.php:1294 +msgid "Religion:" +msgstr "" -#: ../../include/contact_widgets.php:127 -msgid "show more" +#: ../../include/channel.php:1298 +msgid "Hobbies/Interests:" msgstr "" -#: ../../include/markdown.php:377 -msgid "Attachments:" +#: ../../include/channel.php:1300 +msgid "Likes:" msgstr "" -#: ../../include/markdown.php:474 ../../include/event.php:22 -#: ../../include/event.php:69 -msgid "l F d, Y \\@ g:i A" +#: ../../include/channel.php:1302 +msgid "Dislikes:" msgstr "" -#: ../../include/markdown.php:476 -msgid "$Projectname event notification:" +#: ../../include/channel.php:1304 +msgid "Contact information and Social Networks:" msgstr "" -#: ../../include/markdown.php:480 ../../include/event.php:30 -#: ../../include/event.php:73 -msgid "Starts:" +#: ../../include/channel.php:1306 +msgid "My other channels:" msgstr "" -#: ../../include/markdown.php:488 ../../include/event.php:40 -#: ../../include/event.php:77 -msgid "Finishes:" +#: ../../include/channel.php:1308 +msgid "Musical interests:" msgstr "" -#: ../../include/follow.php:26 -msgid "Channel is blocked on this site." +#: ../../include/channel.php:1310 +msgid "Books, literature:" msgstr "" -#: ../../include/follow.php:31 -msgid "Channel location missing." +#: ../../include/channel.php:1312 +msgid "Television:" msgstr "" -#: ../../include/follow.php:73 -msgid "Response from remote channel was incomplete." +#: ../../include/channel.php:1314 +msgid "Film/dance/culture/entertainment:" msgstr "" -#: ../../include/follow.php:90 -msgid "Channel was deleted and no longer exists." +#: ../../include/channel.php:1316 +msgid "Love/Romance:" msgstr "" -#: ../../include/follow.php:140 ../../include/follow.php:175 -msgid "Protocol disabled." +#: ../../include/channel.php:1318 +msgid "Work/employment:" msgstr "" -#: ../../include/follow.php:163 -msgid "Channel discovery failed." +#: ../../include/channel.php:1320 +msgid "School/education:" msgstr "" -#: ../../include/follow.php:202 -msgid "Cannot connect to yourself." +#: ../../include/channel.php:1343 +msgid "Like this thing" +msgstr "" + +#: ../../include/channel.php:2114 +#, php-format +msgid "User '%s' deleted" msgstr "" #: ../../include/js_strings.php:5 @@ -12122,365 +14084,649 @@ msgctxt "calendar" msgid "All day" msgstr "" -#: ../../include/message.php:40 +<<<<<<< HEAD +#: ../../include/dir_fns.php:141 +msgid "Directory Options" +msgstr "" + +#: ../../include/dir_fns.php:143 +msgid "Safe Mode" +======= +#: ../../include/message.php:30 msgid "Unable to determine sender." msgstr "" -#: ../../include/message.php:79 +#: ../../include/message.php:69 msgid "No recipient provided." msgstr "" -#: ../../include/message.php:84 +#: ../../include/message.php:74 msgid "[no subject]" msgstr "" -#: ../../include/message.php:238 +#: ../../include/message.php:227 msgid "Stored post could not be verified." +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../include/activities.php:41 -msgid " and " +#: ../../include/dir_fns.php:144 +msgid "Public Forums Only" msgstr "" -#: ../../include/activities.php:49 -msgid "public profile" +#: ../../include/dir_fns.php:145 +msgid "This Website Only" msgstr "" -#: ../../include/activities.php:58 -#, php-format -msgid "%1$s changed %2$s to “%3$s”" +#: ../../include/group.php:26 +msgid "" +"A deleted group with this name was revived. Existing item permissions " +"<strong>may</strong> apply to this group and any future members. If this is " +"not what you intended, please create another group with a different name." msgstr "" -#: ../../include/activities.php:59 -#, php-format -msgid "Visit %1$s's %2$s" +#: ../../include/group.php:268 +msgid "Add new connections to this privacy group" msgstr "" -#: ../../include/activities.php:62 -#, php-format -msgid "%1$s has an updated %2$s, changing %3$s." +#: ../../include/group.php:309 +msgid "edit" msgstr "" -#: ../../include/attach.php:250 ../../include/attach.php:339 -msgid "Item was not found." +#: ../../include/group.php:331 ../../include/features.php:292 +msgid "Privacy Groups" msgstr "" -#: ../../include/attach.php:500 -msgid "No source file." +#: ../../include/group.php:332 +msgid "Edit group" msgstr "" -#: ../../include/attach.php:522 -msgid "Cannot locate file to replace" +#: ../../include/group.php:333 +msgid "Add privacy group" msgstr "" -#: ../../include/attach.php:540 -msgid "Cannot locate file to revise/update" +#: ../../include/group.php:334 +msgid "Channels not in any privacy group" msgstr "" -#: ../../include/attach.php:671 +#: ../../include/event.php:22 ../../include/event.php:69 +msgid "l F d, Y \\@ g:i A" +msgstr "" + +#: ../../include/event.php:30 ../../include/event.php:73 +msgid "Starts:" +msgstr "" + +#: ../../include/event.php:40 ../../include/event.php:77 +msgid "Finishes:" +msgstr "" + +#: ../../include/event.php:1008 +msgid "This event has been added to your calendar." +msgstr "" + +#: ../../include/event.php:1208 +msgid "Not specified" +msgstr "" + +#: ../../include/event.php:1209 +msgid "Needs Action" +msgstr "" + +#: ../../include/event.php:1210 +msgid "Completed" +msgstr "" + +#: ../../include/event.php:1211 +msgid "In Process" +msgstr "" + +#: ../../include/event.php:1212 +msgid "Cancelled" +msgstr "" + +#: ../../include/conversation.php:200 #, php-format -msgid "File exceeds size limit of %d" +msgid "%1$s is now connected with %2$s" msgstr "" -#: ../../include/attach.php:685 +#: ../../include/conversation.php:235 #, php-format -msgid "You have reached your limit of %1$.0f Mbytes attachment storage." +msgid "%1$s poked %2$s" msgstr "" -#: ../../include/attach.php:855 -msgid "File upload failed. Possible system limit or action terminated." +#: ../../include/conversation.php:691 +#, php-format +msgid "View %s's profile @ %s" msgstr "" -#: ../../include/attach.php:868 -msgid "Stored file could not be verified. Upload failed." +#: ../../include/conversation.php:711 +msgid "Categories:" msgstr "" -#: ../../include/attach.php:923 ../../include/attach.php:939 -msgid "Path not available." +<<<<<<< HEAD +#: ../../include/conversation.php:712 +msgid "Filed under:" msgstr "" -#: ../../include/attach.php:988 ../../include/attach.php:1153 -msgid "Empty pathname" +#: ../../include/conversation.php:737 +msgid "View in context" msgstr "" -#: ../../include/attach.php:1014 -msgid "duplicate filename or path" +#: ../../include/conversation.php:834 +msgid "remove" msgstr "" -#: ../../include/attach.php:1039 -msgid "Path not found." +#: ../../include/conversation.php:839 +msgid "Delete Selected Items" msgstr "" -#: ../../include/attach.php:1107 -msgid "mkdir failed." +#: ../../include/conversation.php:882 +msgid "View Source" msgstr "" -#: ../../include/attach.php:1111 -msgid "database storage failed." +#: ../../include/conversation.php:892 +msgid "Follow Thread" msgstr "" -#: ../../include/attach.php:1159 -msgid "Empty path" +#: ../../include/conversation.php:901 +msgid "Unfollow Thread" msgstr "" -#: ../../include/security.php:117 -msgid "guest:" +#: ../../include/conversation.php:992 +msgid "Activity/Posts" msgstr "" -#: ../../include/security.php:531 -msgid "" -"The form security token was not correct. This probably happened because the " -"form has been opened for too long (>3 hours) before submitting it." +#: ../../include/conversation.php:1012 +msgid "Edit Connection" +msgstr "" + +#: ../../include/conversation.php:1022 +msgid "Message" msgstr "" -#: ../../include/items.php:883 ../../include/items.php:930 +#: ../../include/conversation.php:1156 +======= +#: ../../include/items.php:869 ../../include/items.php:916 msgid "(Unknown)" msgstr "" -#: ../../include/items.php:1124 +#: ../../include/items.php:1110 msgid "Visible to anybody on the internet." msgstr "" -#: ../../include/items.php:1126 +#: ../../include/items.php:1112 msgid "Visible to you only." msgstr "" -#: ../../include/items.php:1128 +#: ../../include/items.php:1114 msgid "Visible to anybody in this network." msgstr "" -#: ../../include/items.php:1130 +#: ../../include/items.php:1116 msgid "Visible to anybody authenticated." msgstr "" -#: ../../include/items.php:1132 +#: ../../include/items.php:1118 #, php-format msgid "Visible to anybody on %s." msgstr "" -#: ../../include/items.php:1134 +#: ../../include/items.php:1120 msgid "Visible to all connections." msgstr "" -#: ../../include/items.php:1136 +#: ../../include/items.php:1122 msgid "Visible to approved connections." msgstr "" -#: ../../include/items.php:1138 +#: ../../include/items.php:1124 msgid "Visible to specific connections." msgstr "" -#: ../../include/items.php:3963 +#: ../../include/items.php:3938 msgid "Privacy group is empty." msgstr "" -#: ../../include/items.php:3970 +#: ../../include/items.php:3945 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 #, php-format -msgid "Privacy group: %s" +msgid "%s likes this." msgstr "" -#: ../../include/items.php:3982 +<<<<<<< HEAD +#: ../../include/conversation.php:1156 +#, php-format +msgid "%s doesn't like this." +msgstr "" + +#: ../../include/conversation.php:1160 +#, php-format +msgid "<span %1$s>%2$d people</span> like this." +msgid_plural "<span %1$s>%2$d people</span> like this." +msgstr[0] "" +msgstr[1] "" + +#: ../../include/conversation.php:1162 +======= +#: ../../include/items.php:3957 msgid "Connection not found." msgstr "" -#: ../../include/items.php:4335 +#: ../../include/items.php:4310 msgid "profile photo" msgstr "" -#: ../../include/items.php:4528 +#: ../../include/items.php:4506 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 #, php-format -msgid "[Edited %s]" +msgid "<span %1$s>%2$d people</span> don't like this." +msgid_plural "<span %1$s>%2$d people</span> don't like this." +msgstr[0] "" +msgstr[1] "" + +<<<<<<< HEAD +#: ../../include/conversation.php:1168 +msgid "and" msgstr "" -#: ../../include/items.php:4528 +#: ../../include/conversation.php:1171 +#, php-format +msgid ", and %d other people" +msgid_plural ", and %d other people" +msgstr[0] "" +msgstr[1] "" +======= +#: ../../include/items.php:4506 msgctxt "edit_activity" msgid "Post" msgstr "" -#: ../../include/items.php:4528 +#: ../../include/items.php:4506 msgctxt "edit_activity" msgid "Comment" msgstr "" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 -#: ../../include/channel.php:33 -msgid "Unable to obtain identity information from database" +#: ../../include/conversation.php:1172 +#, php-format +msgid "%s like this." msgstr "" -#: ../../include/channel.php:68 -msgid "Empty name" +#: ../../include/conversation.php:1172 +#, php-format +msgid "%s don't like this." msgstr "" -#: ../../include/channel.php:71 -msgid "Name too long" +#: ../../include/conversation.php:1215 +msgid "Set your location" msgstr "" -#: ../../include/channel.php:182 -msgid "No account identifier" +#: ../../include/conversation.php:1216 +msgid "Clear browser location" msgstr "" -#: ../../include/channel.php:194 -msgid "Nickname is required." +#: ../../include/conversation.php:1264 +msgid "Tag term:" msgstr "" -#: ../../include/channel.php:208 -msgid "Reserved nickname. Please choose another." +#: ../../include/conversation.php:1265 +msgid "Where are you right now?" msgstr "" -#: ../../include/channel.php:213 -msgid "" -"Nickname has unsupported characters or is already being used on this site." +#: ../../include/conversation.php:1270 +msgid "Choose a different album..." msgstr "" -#: ../../include/channel.php:271 -msgid "Unable to retrieve created identity" +#: ../../include/conversation.php:1274 +msgid "Comments enabled" msgstr "" -#: ../../include/channel.php:343 -msgid "Default Profile" +#: ../../include/conversation.php:1275 +msgid "Comments disabled" +msgstr "" + +<<<<<<< HEAD +#: ../../include/conversation.php:1313 +msgid "Page link name" +msgstr "" + +#: ../../include/conversation.php:1316 +msgid "Post as" +msgstr "" + +#: ../../include/conversation.php:1330 +msgid "Toggle voting" +msgstr "" + +#: ../../include/conversation.php:1333 +msgid "Disable comments" +msgstr "" + +#: ../../include/conversation.php:1334 +msgid "Toggle comments" +msgstr "" + +#: ../../include/conversation.php:1342 +msgid "Categories (optional, comma-separated list)" +msgstr "" + +#: ../../include/conversation.php:1365 +msgid "Other networks and post services" +msgstr "" + +#: ../../include/conversation.php:1371 +msgid "Set publish date" +msgstr "" + +#: ../../include/conversation.php:1625 +msgid "Discover" +msgstr "" + +#: ../../include/conversation.php:1628 +msgid "Imported public streams" +msgstr "" + +#: ../../include/conversation.php:1633 +msgid "Commented Order" +msgstr "" + +#: ../../include/conversation.php:1636 +msgid "Sort by Comment Date" +msgstr "" + +#: ../../include/conversation.php:1640 +msgid "Posted Order" +msgstr "" + +#: ../../include/conversation.php:1643 +msgid "Sort by Post Date" +msgstr "" + +#: ../../include/conversation.php:1651 +msgid "Posts that mention or involve you" +msgstr "" + +#: ../../include/conversation.php:1660 +msgid "Activity Stream - by date" +msgstr "" + +#: ../../include/conversation.php:1666 +msgid "Starred" +msgstr "" + +#: ../../include/conversation.php:1669 +msgid "Favourite Posts" +msgstr "" + +#: ../../include/conversation.php:1676 +msgid "Spam" +msgstr "" + +#: ../../include/conversation.php:1679 +msgid "Posts flagged as SPAM" +msgstr "" + +#: ../../include/conversation.php:1754 +msgid "Status Messages and Posts" +msgstr "" + +#: ../../include/conversation.php:1767 +msgid "Profile Details" +msgstr "" + +#: ../../include/conversation.php:1785 +msgid "Files and Storage" +msgstr "" + +#: ../../include/conversation.php:1821 +msgid "Bookmarks" +msgstr "" + +#: ../../include/conversation.php:1824 +msgid "Saved Bookmarks" +msgstr "" + +#: ../../include/conversation.php:1835 +msgid "View Webpages" +msgstr "" + +#: ../../include/conversation.php:1904 +msgctxt "noun" +msgid "Attending" +msgid_plural "Attending" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/conversation.php:1907 +msgctxt "noun" +msgid "Not Attending" +msgid_plural "Not Attending" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/conversation.php:1910 +msgctxt "noun" +msgid "Undecided" +msgid_plural "Undecided" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/conversation.php:1913 +msgctxt "noun" +msgid "Agree" +msgid_plural "Agrees" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/conversation.php:1916 +msgctxt "noun" +msgid "Disagree" +msgid_plural "Disagrees" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/conversation.php:1919 +msgctxt "noun" +msgid "Abstain" +msgid_plural "Abstains" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/help.php:33 +msgid "Help:" msgstr "" -#: ../../include/channel.php:1059 +#: ../../include/help.php:65 +msgid "Not Found" +======= +#: ../../include/channel.php:1045 msgid "Create New Profile" msgstr "" -#: ../../include/channel.php:1079 +#: ../../include/channel.php:1065 msgid "Visible to everybody" msgstr "" -#: ../../include/channel.php:1152 ../../include/channel.php:1266 +#: ../../include/channel.php:1138 ../../include/channel.php:1252 msgid "Gender:" msgstr "" -#: ../../include/channel.php:1154 ../../include/channel.php:1321 +#: ../../include/channel.php:1140 ../../include/channel.php:1307 msgid "Homepage:" msgstr "" -#: ../../include/channel.php:1155 +#: ../../include/channel.php:1141 msgid "Online Now" msgstr "" -#: ../../include/channel.php:1271 +#: ../../include/channel.php:1257 msgid "Like this channel" msgstr "" -#: ../../include/channel.php:1295 +#: ../../include/channel.php:1281 msgid "j F, Y" msgstr "" -#: ../../include/channel.php:1296 +#: ../../include/channel.php:1282 msgid "j F" msgstr "" -#: ../../include/channel.php:1303 +#: ../../include/channel.php:1289 msgid "Birthday:" msgstr "" -#: ../../include/channel.php:1316 +#: ../../include/channel.php:1302 #, php-format msgid "for %1$d %2$s" msgstr "" -#: ../../include/channel.php:1319 +#: ../../include/channel.php:1305 msgid "Sexual Preference:" msgstr "" -#: ../../include/channel.php:1325 +#: ../../include/channel.php:1311 msgid "Tags:" msgstr "" -#: ../../include/channel.php:1327 +#: ../../include/channel.php:1313 msgid "Political Views:" msgstr "" -#: ../../include/channel.php:1329 +#: ../../include/channel.php:1315 msgid "Religion:" msgstr "" -#: ../../include/channel.php:1333 +#: ../../include/channel.php:1319 msgid "Hobbies/Interests:" msgstr "" -#: ../../include/channel.php:1335 +#: ../../include/channel.php:1321 msgid "Likes:" msgstr "" -#: ../../include/channel.php:1337 +#: ../../include/channel.php:1323 msgid "Dislikes:" msgstr "" -#: ../../include/channel.php:1339 +#: ../../include/channel.php:1325 msgid "Contact information and Social Networks:" msgstr "" -#: ../../include/channel.php:1341 +#: ../../include/channel.php:1327 msgid "My other channels:" msgstr "" -#: ../../include/channel.php:1343 +#: ../../include/channel.php:1329 msgid "Musical interests:" msgstr "" -#: ../../include/channel.php:1345 +#: ../../include/channel.php:1331 msgid "Books, literature:" msgstr "" -#: ../../include/channel.php:1347 +#: ../../include/channel.php:1333 msgid "Television:" msgstr "" -#: ../../include/channel.php:1349 +#: ../../include/channel.php:1335 msgid "Film/dance/culture/entertainment:" msgstr "" -#: ../../include/channel.php:1351 +#: ../../include/channel.php:1337 msgid "Love/Romance:" msgstr "" -#: ../../include/channel.php:1353 +#: ../../include/channel.php:1339 msgid "Work/employment:" msgstr "" -#: ../../include/channel.php:1355 +#: ../../include/channel.php:1341 msgid "School/education:" msgstr "" -#: ../../include/channel.php:1378 +#: ../../include/channel.php:1364 msgid "Like this thing" msgstr "" -#: ../../include/channel.php:2148 +#: ../../include/channel.php:2139 #, php-format msgid "User '%s' deleted" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../include/event.php:1004 -msgid "This event has been added to your calendar." +#: ../../include/security.php:117 +msgid "guest:" msgstr "" -#: ../../include/event.php:1204 -msgid "Not specified" +#: ../../include/security.php:532 +msgid "" +"The form security token was not correct. This probably happened because the " +"form has been opened for too long (>3 hours) before submitting it." msgstr "" -#: ../../include/event.php:1205 -msgid "Needs Action" +#: ../../include/message.php:30 +msgid "Unable to determine sender." msgstr "" -#: ../../include/event.php:1206 -msgid "Completed" +#: ../../include/message.php:67 +msgid "No recipient provided." msgstr "" -#: ../../include/event.php:1207 -msgid "In Process" +#: ../../include/message.php:72 +msgid "[no subject]" msgstr "" -#: ../../include/event.php:1208 -msgid "Cancelled" +#: ../../include/message.php:223 +msgid "Stored post could not be verified." msgstr "" #: ../../include/network.php:776 msgid "view full size" msgstr "" +<<<<<<< HEAD +#: ../../include/network.php:1490 +msgid "No Subject" +msgstr "" + +#: ../../include/network.php:1744 ../../include/network.php:1745 +msgid "Friendica" +msgstr "" + +#: ../../include/network.php:1746 +msgid "OStatus" +msgstr "" + +#: ../../include/network.php:1747 +msgid "GNU-Social" +msgstr "" + +#: ../../include/network.php:1748 +msgid "RSS/Atom" +msgstr "" + +#: ../../include/network.php:1750 +msgid "Diaspora" +msgstr "" + +#: ../../include/network.php:1751 +msgid "Facebook" +msgstr "" + +#: ../../include/network.php:1752 +msgid "Zot" +msgstr "" + +#: ../../include/network.php:1753 +msgid "LinkedIn" +msgstr "" + +#: ../../include/network.php:1754 +msgid "XMPP/IM" +msgstr "" + +#: ../../include/network.php:1755 +======= #: ../../include/network.php:2042 msgid "No Subject" msgstr "" @@ -12522,17 +14768,10 @@ msgid "XMPP/IM" msgstr "" #: ../../include/network.php:2321 +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgid "MySpace" msgstr "" -#: ../../include/page_widgets.php:7 -msgid "New Page" -msgstr "" - -#: ../../include/language.php:380 -msgid "Select an alternate language" -msgstr "" - #: ../../include/acl_selectors.php:208 msgid "Who can see this?" msgstr "" @@ -12562,54 +14801,143 @@ msgid "" "permissions set who is allowed to view the post." msgstr "" -#: ../../include/dba/dba_driver.php:189 +#: ../../include/activities.php:41 +msgid " and " +msgstr "" + +#: ../../include/activities.php:49 +msgid "public profile" +msgstr "" + +#: ../../include/activities.php:58 #, php-format -msgid "Cannot locate DNS info for database server '%s'" +msgid "%1$s changed %2$s to “%3$s”" msgstr "" -#: ../../include/bbcode.php:194 ../../include/bbcode.php:1097 -#: ../../include/bbcode.php:1100 ../../include/bbcode.php:1105 -#: ../../include/bbcode.php:1108 ../../include/bbcode.php:1111 -#: ../../include/bbcode.php:1114 ../../include/bbcode.php:1119 -#: ../../include/bbcode.php:1122 ../../include/bbcode.php:1127 -#: ../../include/bbcode.php:1130 ../../include/bbcode.php:1133 -#: ../../include/bbcode.php:1136 +#: ../../include/activities.php:59 +#, php-format +msgid "Visit %1$s's %2$s" +msgstr "" + +#: ../../include/activities.php:62 +#, php-format +msgid "%1$s has an updated %2$s, changing %3$s." +msgstr "" + +#: ../../include/items.php:842 ../../include/items.php:889 +msgid "(Unknown)" +msgstr "" + +#: ../../include/items.php:1080 +msgid "Visible to anybody on the internet." +msgstr "" + +#: ../../include/items.php:1082 +msgid "Visible to you only." +msgstr "" + +#: ../../include/items.php:1084 +msgid "Visible to anybody in this network." +msgstr "" + +#: ../../include/items.php:1086 +msgid "Visible to anybody authenticated." +msgstr "" + +#: ../../include/items.php:1088 +#, php-format +msgid "Visible to anybody on %s." +msgstr "" + +#: ../../include/items.php:1090 +msgid "Visible to all connections." +msgstr "" + +#: ../../include/items.php:1092 +msgid "Visible to approved connections." +msgstr "" + +#: ../../include/items.php:1094 +msgid "Visible to specific connections." +msgstr "" + +#: ../../include/items.php:3863 +msgid "Privacy group is empty." +msgstr "" + +#: ../../include/items.php:3870 +#, php-format +msgid "Privacy group: %s" +msgstr "" + +#: ../../include/items.php:3882 +msgid "Connection not found." +msgstr "" + +#: ../../include/items.php:4231 +msgid "profile photo" +msgstr "" + +#: ../../include/items.php:4427 +#, php-format +msgid "[Edited %s]" +msgstr "" + +#: ../../include/items.php:4427 +msgctxt "edit_activity" +msgid "Post" +msgstr "" + +#: ../../include/items.php:4427 +msgctxt "edit_activity" +msgid "Comment" +msgstr "" + +#: ../../include/bbcode.php:134 ../../include/bbcode.php:1040 +#: ../../include/bbcode.php:1043 ../../include/bbcode.php:1048 +#: ../../include/bbcode.php:1051 ../../include/bbcode.php:1054 +#: ../../include/bbcode.php:1057 ../../include/bbcode.php:1062 +#: ../../include/bbcode.php:1065 ../../include/bbcode.php:1070 +#: ../../include/bbcode.php:1073 ../../include/bbcode.php:1076 +#: ../../include/bbcode.php:1079 msgid "Image/photo" msgstr "" -#: ../../include/bbcode.php:233 ../../include/bbcode.php:1147 +#: ../../include/bbcode.php:173 ../../include/bbcode.php:1090 msgid "Encrypted content" msgstr "" -#: ../../include/bbcode.php:249 +#: ../../include/bbcode.php:189 #, php-format msgid "Install %s element: " msgstr "" -#: ../../include/bbcode.php:253 +#: ../../include/bbcode.php:193 #, php-format msgid "" "This post contains an installable %s element, however you lack permissions " "to install it on this site." msgstr "" -#: ../../include/bbcode.php:332 +#: ../../include/bbcode.php:272 #, php-format msgid "%1$s wrote the following %2$s %3$s" msgstr "" -#: ../../include/bbcode.php:409 ../../include/bbcode.php:417 +#: ../../include/bbcode.php:349 ../../include/bbcode.php:357 msgid "Click to open/close" msgstr "" -#: ../../include/bbcode.php:417 +#: ../../include/bbcode.php:357 msgid "spoiler" msgstr "" -#: ../../include/bbcode.php:1085 +#: ../../include/bbcode.php:1028 msgid "$1 wrote:" msgstr "" +<<<<<<< HEAD +======= #: ../../include/oembed.php:315 msgid " by " msgstr "" @@ -12626,6 +14954,7 @@ msgstr "" msgid "Embedding disabled" msgstr "" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 #: ../../include/features.php:58 msgid "General Features" msgstr "" @@ -12817,10 +15146,6 @@ msgstr "" msgid "Ability to select posts by date ranges" msgstr "" -#: ../../include/features.php:292 ../../include/group.php:331 -msgid "Privacy Groups" -msgstr "" - #: ../../include/features.php:293 msgid "Enable management and selection of privacy groups" msgstr "" @@ -12881,6 +15206,7 @@ msgstr "" msgid "Post Categories" msgstr "" +<<<<<<< HEAD #: ../../include/features.php:373 msgid "Add categories to your posts" msgstr "" @@ -12931,187 +15257,89 @@ msgid "" "channel" msgstr "" -#: ../../include/taxonomy.php:258 ../../include/taxonomy.php:279 -msgid "Tags" -msgstr "" - -#: ../../include/taxonomy.php:323 -msgid "Keywords" -msgstr "" - -#: ../../include/taxonomy.php:344 -msgid "have" -msgstr "" - -#: ../../include/taxonomy.php:344 -msgid "has" -msgstr "" - -#: ../../include/taxonomy.php:345 -msgid "want" -msgstr "" - -#: ../../include/taxonomy.php:345 -msgid "wants" -msgstr "" - -#: ../../include/taxonomy.php:346 -msgid "likes" -msgstr "" - -#: ../../include/taxonomy.php:347 -msgid "dislikes" -msgstr "" - -#: ../../include/account.php:35 -msgid "Not a valid email address" -msgstr "" - -#: ../../include/account.php:37 -msgid "Your email domain is not among those allowed on this site" -msgstr "" - -#: ../../include/account.php:43 -msgid "Your email address is already registered at this site." -msgstr "" - -#: ../../include/account.php:75 -msgid "An invitation is required." +#: ../../include/follow.php:26 +msgid "Channel is blocked on this site." msgstr "" -#: ../../include/account.php:79 -msgid "Invitation could not be verified." +#: ../../include/follow.php:31 +msgid "Channel location missing." msgstr "" -#: ../../include/account.php:130 -msgid "Please enter the required information." +#: ../../include/follow.php:73 +msgid "Response from remote channel was incomplete." msgstr "" -#: ../../include/account.php:198 -msgid "Failed to store account information." +#: ../../include/follow.php:90 +msgid "Channel was deleted and no longer exists." msgstr "" -#: ../../include/account.php:263 -#, php-format -msgid "Registration confirmation for %s" +#: ../../include/follow.php:140 ../../include/follow.php:175 +msgid "Protocol disabled." msgstr "" -#: ../../include/account.php:330 -#, php-format -msgid "Registration request at %s" +#: ../../include/follow.php:163 +msgid "Channel discovery failed." msgstr "" -#: ../../include/account.php:352 -msgid "your registration password" +#: ../../include/follow.php:202 +msgid "Cannot connect to yourself." msgstr "" -#: ../../include/account.php:358 ../../include/account.php:420 -#, php-format -msgid "Registration details for %s" +#: ../../include/oembed.php:308 +msgid " by " msgstr "" -#: ../../include/account.php:431 -msgid "Account approved." +#: ../../include/oembed.php:309 +msgid " on " msgstr "" -#: ../../include/account.php:471 -#, php-format -msgid "Registration revoked for %s" +#: ../../include/oembed.php:338 +msgid "Embedded content" msgstr "" -#: ../../include/account.php:756 ../../include/account.php:758 -msgid "Click here to upgrade." +#: ../../include/oembed.php:347 +msgid "Embedding disabled" msgstr "" -#: ../../include/account.php:764 -msgid "This action exceeds the limits set by your subscription plan." +#: ../../util/nconfig.php:34 +msgid "Source channel not found." msgstr "" -#: ../../include/account.php:769 -msgid "This action is not available under your subscription plan." +#: ../../view/theme/redbasic/php/config.php:9 +msgid "Focus (Hubzilla default)" msgstr "" -#: ../../include/datetime.php:147 -msgid "Birthday" +#: ../../view/theme/redbasic/php/config.php:88 +msgid "Theme settings" msgstr "" -#: ../../include/datetime.php:149 -msgid "Age: " +#: ../../view/theme/redbasic/php/config.php:89 +msgid "Narrow navbar" msgstr "" -#: ../../include/datetime.php:151 -msgid "YYYY-MM-DD or MM-DD" +#: ../../view/theme/redbasic/php/config.php:90 +msgid "Navigation bar background color" msgstr "" -#: ../../include/datetime.php:292 -msgid "less than a second ago" +#: ../../view/theme/redbasic/php/config.php:91 +msgid "Navigation bar icon color " msgstr "" -#: ../../include/datetime.php:310 -#, php-format -msgctxt "e.g. 22 hours ago, 1 minute ago" -msgid "%1$d %2$s ago" +#: ../../view/theme/redbasic/php/config.php:92 +msgid "Navigation bar active icon color " msgstr "" -#: ../../include/datetime.php:321 -msgctxt "relative_date" -msgid "year" -msgid_plural "years" -msgstr[0] "" -msgstr[1] "" - -#: ../../include/datetime.php:324 -msgctxt "relative_date" -msgid "month" -msgid_plural "months" -msgstr[0] "" -msgstr[1] "" - -#: ../../include/datetime.php:327 -msgctxt "relative_date" -msgid "week" -msgid_plural "weeks" -msgstr[0] "" -msgstr[1] "" - -#: ../../include/datetime.php:330 -msgctxt "relative_date" -msgid "day" -msgid_plural "days" -msgstr[0] "" -msgstr[1] "" - -#: ../../include/datetime.php:333 -msgctxt "relative_date" -msgid "hour" -msgid_plural "hours" -msgstr[0] "" -msgstr[1] "" - -#: ../../include/datetime.php:336 -msgctxt "relative_date" -msgid "minute" -msgid_plural "minutes" -msgstr[0] "" -msgstr[1] "" - -#: ../../include/datetime.php:339 -msgctxt "relative_date" -msgid "second" -msgid_plural "seconds" -msgstr[0] "" -msgstr[1] "" - -#: ../../include/datetime.php:576 -#, php-format -msgid "%1$s's birthday" +#: ../../view/theme/redbasic/php/config.php:93 +msgid "Link color" msgstr "" -#: ../../include/datetime.php:577 -#, php-format -msgid "Happy Birthday %1$s" +#: ../../view/theme/redbasic/php/config.php:94 +msgid "Set font-color for banner" msgstr "" +#: ../../view/theme/redbasic/php/config.php:95 +msgid "Set the background color" +======= #: ../../include/nav.php:92 msgid "Remote authentication" msgstr "" @@ -13200,10 +15428,6 @@ msgstr "" msgid "View all notifications" msgstr "" -#: ../../include/nav.php:190 -msgid "Mark all system notifications seen" -msgstr "" - #: ../../include/nav.php:192 msgid "Private mail" msgstr "" @@ -13240,49 +15464,59 @@ msgstr "" msgid "Site Setup and Configuration" msgstr "" -#: ../../include/nav.php:267 +#: ../../include/nav.php:277 msgid "@name, #tag, ?doc, content" msgstr "" -#: ../../include/nav.php:268 +#: ../../include/nav.php:278 msgid "Please wait..." msgstr "" -#: ../../include/nav.php:271 +#: ../../include/nav.php:280 msgid "Add Apps" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../include/nav.php:272 -msgid "Arrange Apps" +#: ../../view/theme/redbasic/php/config.php:96 +msgid "Set the background image" msgstr "" -#: ../../include/nav.php:273 -msgid "Toggle System Apps" +#: ../../view/theme/redbasic/php/config.php:97 +msgid "Set the background color of items" msgstr "" -#: ../../include/photos.php:115 -#, php-format -msgid "Image exceeds website size limit of %lu bytes" +#: ../../view/theme/redbasic/php/config.php:98 +msgid "Set the background color of comments" msgstr "" -#: ../../include/photos.php:122 -msgid "Image file is empty." +#: ../../view/theme/redbasic/php/config.php:99 +msgid "Set font-size for the entire application" msgstr "" -#: ../../include/photos.php:261 -msgid "Photo storage failed." +#: ../../view/theme/redbasic/php/config.php:99 +msgid "Examples: 1rem, 100%, 16px" msgstr "" -#: ../../include/photos.php:301 -msgid "a new photo" +<<<<<<< HEAD +#: ../../view/theme/redbasic/php/config.php:100 +msgid "Set font-color for posts and comments" msgstr "" -#: ../../include/photos.php:305 -#, php-format -msgctxt "photo_upload" -msgid "%1$s posted %2$s to %3$s" +#: ../../view/theme/redbasic/php/config.php:101 +msgid "Set radius of corners" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:101 +msgid "Example: 4px" msgstr "" +#: ../../view/theme/redbasic/php/config.php:102 +msgid "Set shadow depth of photos" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:103 +msgid "Set maximum width of content region in pixel" +======= #: ../../include/photos.php:533 msgid "Upload New Photos" msgstr "" @@ -13300,57 +15534,65 @@ msgstr "" msgid "Unable to verify site signature for %s" msgstr "" -#: ../../include/zot.php:3762 +#: ../../include/zot.php:3764 msgid "invalid target signature" +>>>>>>> 3645eb18f8b3a591ed6250a85d0e4805ed3615d1 msgstr "" -#: ../../include/group.php:26 -msgid "" -"A deleted group with this name was revived. Existing item permissions " -"<strong>may</strong> apply to this group and any future members. If this is " -"not what you intended, please create another group with a different name." +#: ../../view/theme/redbasic/php/config.php:103 +msgid "Leave empty for default width" msgstr "" -#: ../../include/group.php:268 -msgid "Add new connections to this privacy group" +#: ../../view/theme/redbasic/php/config.php:104 +msgid "Left align page content" msgstr "" -#: ../../include/group.php:309 -msgid "edit" +#: ../../view/theme/redbasic/php/config.php:105 +msgid "Set size of conversation author photo" msgstr "" -#: ../../include/group.php:332 -msgid "Edit group" +#: ../../view/theme/redbasic/php/config.php:106 +msgid "Set size of followup author photos" msgstr "" -#: ../../include/group.php:333 -msgid "Add privacy group" +#: ../../boot.php:1571 +msgid "Create an account to access services and applications" msgstr "" -#: ../../include/group.php:334 -msgid "Channels not in any privacy group" +#: ../../boot.php:1593 +msgid "Login/Email" msgstr "" -#: ../../include/connections.php:128 -msgid "New window" +#: ../../boot.php:1594 +msgid "Password" msgstr "" -#: ../../include/connections.php:129 -msgid "Open the selected location in a different window or browser tab" +#: ../../boot.php:1595 +msgid "Remember me" msgstr "" -#: ../../include/auth.php:148 -msgid "Logged out." +#: ../../boot.php:1598 +msgid "Forgot your password?" msgstr "" -#: ../../include/auth.php:275 -msgid "Failed authentication" +#: ../../boot.php:2136 +msgid "toggle mobile" msgstr "" -#: ../../include/help.php:33 -msgid "Help:" +#: ../../boot.php:2289 +#, php-format +msgid "[$Projectname] Website SSL error for %s" msgstr "" -#: ../../include/help.php:65 -msgid "Not Found" +#: ../../boot.php:2294 +msgid "Website SSL certificate is not valid. Please correct." +msgstr "" + +#: ../../boot.php:2413 +#, php-format +msgid "[$Projectname] Cron tasks not running on %s" +msgstr "" + +#: ../../boot.php:2418 +msgid "Cron/Scheduled tasks not running." msgstr "" diff --git a/util/typo.php b/util/typo.php index a8d363340..e25e57601 100644 --- a/util/typo.php +++ b/util/typo.php @@ -12,7 +12,6 @@ App::init(); -// $a = new App(); echo "Directory: include\n"; $files = glob('include/*.php'); diff --git a/vendor/autoload.php b/vendor/autoload.php index 8b4926c3d..063a1b7e1 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -2,6 +2,6 @@ // autoload.php @generated by Composer -require_once __DIR__ . '/composer/autoload_real.php'; +require_once __DIR__ . '/composer' . '/autoload_real.php'; return ComposerAutoloaderInit7b34d7e50a62201ec5d5e526a5b8b35d::getLoader(); diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php index 2c72175e7..795376e87 100644 --- a/vendor/composer/ClassLoader.php +++ b/vendor/composer/ClassLoader.php @@ -53,9 +53,8 @@ class ClassLoader private $useIncludePath = false; private $classMap = array(); + private $classMapAuthoritative = false; - private $missingClasses = array(); - private $apcuPrefix; public function getPrefixes() { @@ -273,26 +272,6 @@ class ClassLoader } /** - * APCu prefix to use to cache found/not-found classes, if the extension is enabled. - * - * @param string|null $apcuPrefix - */ - public function setApcuPrefix($apcuPrefix) - { - $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; - } - - /** - * The APCu prefix in use, or null if APCu caching is not enabled. - * - * @return string|null - */ - public function getApcuPrefix() - { - return $this->apcuPrefix; - } - - /** * Registers this instance as an autoloader. * * @param bool $prepend Whether to prepend the autoloader or not @@ -334,34 +313,29 @@ class ClassLoader */ public function findFile($class) { + // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 + if ('\\' == $class[0]) { + $class = substr($class, 1); + } + // class map lookup if (isset($this->classMap[$class])) { return $this->classMap[$class]; } - if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + if ($this->classMapAuthoritative) { return false; } - if (null !== $this->apcuPrefix) { - $file = apcu_fetch($this->apcuPrefix.$class, $hit); - if ($hit) { - return $file; - } - } $file = $this->findFileWithExtension($class, '.php'); // Search for Hack files if we are running on HHVM - if (false === $file && defined('HHVM_VERSION')) { + if ($file === null && defined('HHVM_VERSION')) { $file = $this->findFileWithExtension($class, '.hh'); } - if (null !== $this->apcuPrefix) { - apcu_add($this->apcuPrefix.$class, $file); - } - - if (false === $file) { + if ($file === null) { // Remember that this class does not exist. - $this->missingClasses[$class] = true; + return $this->classMap[$class] = false; } return $file; @@ -429,8 +403,6 @@ class ClassLoader if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { return $file; } - - return false; } } diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE index f27399a04..ecd380626 100644 --- a/vendor/composer/LICENSE +++ b/vendor/composer/LICENSE @@ -1,21 +1,430 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: Composer +Upstream-Contact: Jordi Boggiano <j.boggiano@seld.be> +Source: https://github.com/composer/composer Copyright (c) Nils Adermann, Jordi Boggiano -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: +Files: res/cacert.pem +Copyright: 2015, Mozilla Foundation +License: MPL-2.0 -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Files: src/Composer/Util/RemoteFilesystem.php + src/Composer/Util/TlsHelper.php +Copyright: 2016, Nils Adermann <naderman@naderman.de> + 2016, Jordi Boggiano <j.boggiano@seld.be> + 2013, Evan Coury <me@evancoury.com> +License: Expat and BSD-2-Clause -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +License: BSD-2-Clause + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + . + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + . + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +License: Expat + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished + to do so, subject to the following conditions: + . + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +License: MPL-2.0 + 1. Definitions + -------------- + . + 1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + . + 1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + . + 1.3. "Contribution" + means Covered Software of a particular Contributor. + . + 1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + . + 1.5. "Incompatible With Secondary Licenses" + means + . + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + . + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + . + 1.6. "Executable Form" + means any form of the work other than Source Code Form. + . + 1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + . + 1.8. "License" + means this document. + . + 1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + . + 1.10. "Modifications" + means any of the following: + . + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + . + (b) any new file in Source Code Form that contains any Covered + Software. + . + 1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + . + 1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + . + 1.13. "Source Code Form" + means the form of the work preferred for making modifications. + . + 1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + . + 2. License Grants and Conditions + -------------------------------- + . + 2.1. Grants + . + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + . + (a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + . + (b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + . + 2.2. Effective Date + . + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + . + 2.3. Limitations on Grant Scope + . + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + . + (a) for any code that a Contributor has removed from Covered Software; + or + . + (b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + . + (c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + . + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + . + 2.4. Subsequent Licenses + . + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + . + 2.5. Representation + . + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights + to grant the rights to its Contributions conveyed by this License. + . + 2.6. Fair Use + . + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + . + 2.7. Conditions + . + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted + in Section 2.1. + . + 3. Responsibilities + ------------------- + . + 3.1. Distribution of Source Form + . + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + . + 3.2. Distribution of Executable Form + . + If You distribute Covered Software in Executable Form then: + . + (a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + . + (b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + . + 3.3. Distribution of a Larger Work + . + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + . + 3.4. Notices + . + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, + or limitations of liability) contained within the Source Code Form of + the Covered Software, except that You may alter any license notices to + the extent required to remedy known factual inaccuracies. + . + 3.5. Application of Additional Terms + . + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + . + 4. Inability to Comply Due to Statute or Regulation + --------------------------------------------------- + . + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Software due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description must + be placed in a text file included with all distributions of the Covered + Software under this License. Except to the extent prohibited by statute + or regulation, such description must be sufficiently detailed for a + recipient of ordinary skill to be able to understand it. + . + 5. Termination + -------------- + . + 5.1. The rights granted under this License will terminate automatically + if You fail to comply with any of its terms. However, if You become + compliant, then the rights granted under this License from a particular + Contributor are reinstated (a) provisionally, unless and until such + Contributor explicitly and finally terminates Your grants, and (b) on an + ongoing basis, if such Contributor fails to notify You of the + non-compliance by some reasonable means prior to 60 days after You have + come back into compliance. Moreover, Your grants from a particular + Contributor are reinstated on an ongoing basis if such Contributor + notifies You of the non-compliance by some reasonable means, this is the + first time You have received notice of non-compliance with this License + from such Contributor, and You become compliant prior to 30 days after + Your receipt of the notice. + . + 5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + . + 5.3. In the event of termination under Sections 5.1 or 5.2 above, all + end user license agreements (excluding distributors and resellers) which + have been validly granted by You or Your distributors under this License + prior to termination shall survive termination. + . + ************************************************************************ + * * + * 6. Disclaimer of Warranty * + * ------------------------- * + * * + * Covered Software is provided under this License on an "as is" * + * basis, without warranty of any kind, either expressed, implied, or * + * statutory, including, without limitation, warranties that the * + * Covered Software is free of defects, merchantable, fit for a * + * particular purpose or non-infringing. The entire risk as to the * + * quality and performance of the Covered Software is with You. * + * Should any Covered Software prove defective in any respect, You * + * (not any Contributor) assume the cost of any necessary servicing, * + * repair, or correction. This disclaimer of warranty constitutes an * + * essential part of this License. No use of any Covered Software is * + * authorized under this License except under this disclaimer. * + * * + ************************************************************************ + . + ************************************************************************ + * * + * 7. Limitation of Liability * + * -------------------------- * + * * + * Under no circumstances and under no legal theory, whether tort * + * (including negligence), contract, or otherwise, shall any * + * Contributor, or anyone who distributes Covered Software as * + * permitted above, be liable to You for any direct, indirect, * + * special, incidental, or consequential damages of any character * + * including, without limitation, damages for lost profits, loss of * + * goodwill, work stoppage, computer failure or malfunction, or any * + * and all other commercial damages or losses, even if such party * + * shall have been informed of the possibility of such damages. This * + * limitation of liability shall not apply to liability for death or * + * personal injury resulting from such party's negligence to the * + * extent applicable law prohibits such limitation. Some * + * jurisdictions do not allow the exclusion or limitation of * + * incidental or consequential damages, so this exclusion and * + * limitation may not apply to You. * + * * + ************************************************************************ + . + 8. Litigation + ------------- + . + Any litigation relating to this License may be brought only in the + courts of a jurisdiction where the defendant maintains its principal + place of business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. + Nothing in this Section shall prevent a party's ability to bring + cross-claims or counter-claims. + . + 9. Miscellaneous + ---------------- + . + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides + that the language of a contract shall be construed against the drafter + shall not be used to construe this License against a Contributor. + . + 10. Versions of the License + --------------------------- + . + 10.1. New Versions + . + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + . + 10.2. Effect of New Versions + . + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + . + 10.3. Modified Versions + . + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + . + 10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses + . + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + . + Exhibit A - Source Code Form License Notice + ------------------------------------------- + . + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + . + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to look + for such a notice. + . + You may add additional accurate notices of copyright ownership. + . + Exhibit B - "Incompatible With Secondary Licenses" Notice + --------------------------------------------------------- + . + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index bcae78e29..6200547d3 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -23,35 +23,24 @@ class ComposerAutoloaderInit7b34d7e50a62201ec5d5e526a5b8b35d self::$loader = $loader = new \Composer\Autoload\ClassLoader(); spl_autoload_unregister(array('ComposerAutoloaderInit7b34d7e50a62201ec5d5e526a5b8b35d', 'loadClassLoader')); - $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); - if ($useStaticLoader) { - require_once __DIR__ . '/autoload_static.php'; - - call_user_func(\Composer\Autoload\ComposerStaticInit7b34d7e50a62201ec5d5e526a5b8b35d::getInitializer($loader)); - } else { - $map = require __DIR__ . '/autoload_namespaces.php'; - foreach ($map as $namespace => $path) { - $loader->set($namespace, $path); - } + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } - $map = require __DIR__ . '/autoload_psr4.php'; - foreach ($map as $namespace => $path) { - $loader->setPsr4($namespace, $path); - } + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } - $classMap = require __DIR__ . '/autoload_classmap.php'; - if ($classMap) { - $loader->addClassMap($classMap); - } + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); } $loader->register(true); - if ($useStaticLoader) { - $includeFiles = Composer\Autoload\ComposerStaticInit7b34d7e50a62201ec5d5e526a5b8b35d::$files; - } else { - $includeFiles = require __DIR__ . '/autoload_files.php'; - } + $includeFiles = require __DIR__ . '/autoload_files.php'; foreach ($includeFiles as $fileIdentifier => $file) { composerRequire7b34d7e50a62201ec5d5e526a5b8b35d($fileIdentifier, $file); } diff --git a/vendor/sabre/dav/bin/build.php b/vendor/sabre/dav/bin/build.php index c4ba20941..c4ba20941 100644..100755 --- a/vendor/sabre/dav/bin/build.php +++ b/vendor/sabre/dav/bin/build.php diff --git a/vendor/sabre/dav/bin/googlecode_upload.py b/vendor/sabre/dav/bin/googlecode_upload.py index caafd5ded..caafd5ded 100644..100755 --- a/vendor/sabre/dav/bin/googlecode_upload.py +++ b/vendor/sabre/dav/bin/googlecode_upload.py diff --git a/vendor/sabre/dav/bin/migrateto20.php b/vendor/sabre/dav/bin/migrateto20.php index 77236804f..77236804f 100644..100755 --- a/vendor/sabre/dav/bin/migrateto20.php +++ b/vendor/sabre/dav/bin/migrateto20.php diff --git a/vendor/sabre/dav/bin/migrateto21.php b/vendor/sabre/dav/bin/migrateto21.php index c81ee5cca..c81ee5cca 100644..100755 --- a/vendor/sabre/dav/bin/migrateto21.php +++ b/vendor/sabre/dav/bin/migrateto21.php diff --git a/vendor/sabre/dav/bin/migrateto30.php b/vendor/sabre/dav/bin/migrateto30.php index 9ca77c13c..9ca77c13c 100644..100755 --- a/vendor/sabre/dav/bin/migrateto30.php +++ b/vendor/sabre/dav/bin/migrateto30.php diff --git a/vendor/sabre/dav/bin/migrateto32.php b/vendor/sabre/dav/bin/migrateto32.php index 7567aeb60..7567aeb60 100644..100755 --- a/vendor/sabre/dav/bin/migrateto32.php +++ b/vendor/sabre/dav/bin/migrateto32.php diff --git a/vendor/sabre/dav/bin/sabredav.php b/vendor/sabre/dav/bin/sabredav.php index 950075d1a..950075d1a 100644..100755 --- a/vendor/sabre/dav/bin/sabredav.php +++ b/vendor/sabre/dav/bin/sabredav.php diff --git a/view/css/bootstrap-red.css b/view/css/bootstrap-red.css index 04db6193d..1918f399b 100644 --- a/view/css/bootstrap-red.css +++ b/view/css/bootstrap-red.css @@ -38,7 +38,7 @@ nav .badge { } #navbar-collapse-1 i { - font-size: 1rem; + font-size: 1.0rem; } nav .dropdown-menu { diff --git a/view/css/cdav_addressbook.css b/view/css/cdav_addressbook.css new file mode 100644 index 000000000..038358e43 --- /dev/null +++ b/view/css/cdav_addressbook.css @@ -0,0 +1,103 @@ +.vcard-header { + cursor: pointer; + padding: 7px 10px; + margin-bottom: 3px; +} + +.vcard-header:hover, +.vcard-header.active { + background-color: rgb(238,238,238); + cursor: pointer; +} + +.vcard-header.active:hover { + cursor: initial; +} + +.vcard-add-field { + margin-top: 8px; + display: none; +} + +.vcard-cancel { + margin: 6px 10px; + height: 32px; + line-height: 32px; + color: #777; + font-size: 16px; + + cursor: pointer; + display: none; + float: right; +} + +.vcard-info { + display: none; +} + +.vcard-nophoto { + display: inline-block; + width: 32px; + height: 32px; + border-radius: 4px; + border: 1px solid #ccc; + text-align: center; + font-size: 20px; + color: #fff; + background-color: #ddd; +} + +.vcard-photo { + width: 32px; + height: 32px; + border-radius: 4px; + border: 1px solid #ccc; + text-align: center; +} + +.vcard-fn-preview, +input.vcard-fn { + font-size: 16px !important; + margin-left: 5px; +} + +.vcard-email-preview, +.vcard-tel-preview { + color: #999; +} + + +.vcard-fn, +#create_form, +#more_block { + display: none; +} + +input.vcard-fn, +.vcard-fn-create input, +.vcard-org input, +.vcard-title input, +.vcard-tel input, +.vcard-email input, +.vcard-impp input, +.vcard-url input, +.vcard-adr input, +.vcard-note input { + padding: 0px; + margin-left: 5px; + border-width: 0px 0px 1px 0px; + border-radius: 0px; + background-color: transparent; + min-width: 160px; +} + +#template-form-vcard-org, +#template-form-vcard-title, +#template-form-vcard-tel, +#template-form-vcard-email, +#template-form-vcard-impp, +#template-form-vcard-url, +#template-form-vcard-adr, +#template-form-vcard-note { + display: none; +} diff --git a/view/css/cdav_calendar.css b/view/css/cdav_calendar.css new file mode 100644 index 000000000..d68278a63 --- /dev/null +++ b/view/css/cdav_calendar.css @@ -0,0 +1,22 @@ +/* fix borders */ + +.fc th:first-child, +.fc td:first-child { + border-left-width: 0px; +} + +.fc th:last-child, +.fc td:last-child { + border-right-width: 0px; + border-bottom-width: 0px; +} + +.fc-unthemed th, +.fc-unthemed td, +.fc-unthemed thead, +.fc-unthemed tbody, +.fc-unthemed .fc-divider, +.fc-unthemed .fc-row, +.fc-unthemed .fc-popover { + border-color: #ccc !important; +} diff --git a/view/de/htconfig.tpl b/view/de/htconfig.tpl index 9d4333fb0..46bf0de14 100644 --- a/view/de/htconfig.tpl +++ b/view/de/htconfig.tpl @@ -34,13 +34,6 @@ App::$config['system']['baseurl'] = '{{$siteurl}}'; App::$config['system']['sitename'] = "Hubzilla"; App::$config['system']['location_hash'] = '{{$site_id}}'; -// Choices are 'basic', 'standard', and 'pro'. -// basic sets up the sevrer for basic social networking and removes "complicated" features -// standard provides most desired features except e-commerce -// pro gives you access to everything - -App::$config['system']['server_role'] = '{{$server_role}}'; - // These lines set additional security headers to be sent with all responses // You may wish to set transport_security_header to 0 if your server already sends // this header. content_security_policy may need to be disabled if you wish to diff --git a/view/en-au/htconfig.tpl b/view/en-au/htconfig.tpl index 090bbf06f..cefcba727 100644 --- a/view/en-au/htconfig.tpl +++ b/view/en-au/htconfig.tpl @@ -34,13 +34,6 @@ App::$config['system']['baseurl'] = '{{$siteurl}}'; App::$config['system']['sitename'] = "Hubzilla"; App::$config['system']['location_hash'] = '{{$site_id}}'; -// Choices are 'basic', 'standard', and 'pro'. -// basic sets up the sevrer for basic social networking and removes "complicated" features -// standard provides most desired features except e-commerce -// pro gives you access to everything - -App::$config['system']['server_role'] = '{{$server_role}}'; - // These lines set additional security headers to be sent with all responses // You may wish to set transport_security_header to 0 if your server already sends // this header. content_security_policy may need to be disabled if you wish to diff --git a/view/en-gb/htconfig.tpl b/view/en-gb/htconfig.tpl index 515957b36..ea458d664 100644 --- a/view/en-gb/htconfig.tpl +++ b/view/en-gb/htconfig.tpl @@ -34,14 +34,6 @@ App::$config['system']['baseurl'] = '{{$siteurl}}'; App::$config['system']['sitename'] = "Hubzilla"; App::$config['system']['location_hash'] = '{{$site_id}}'; - -// Choices are 'basic', 'standard', and 'pro'. -// basic sets up the sevrer for basic social networking and removes "complicated" features -// standard provides most desired features except e-commerce -// pro gives you access to everything - -App::$config['system']['server_role'] = '{{$server_role}}'; - // These lines set additional security headers to be sent with all responses // You may wish to set transport_security_header to 0 if your server already sends // this header. content_security_policy may need to be disabled if you wish to diff --git a/view/en/htconfig.tpl b/view/en/htconfig.tpl index 042c89797..8159b6d44 100644 --- a/view/en/htconfig.tpl +++ b/view/en/htconfig.tpl @@ -34,15 +34,6 @@ App::$config['system']['baseurl'] = '{{$siteurl}}'; App::$config['system']['sitename'] = "Hubzilla"; App::$config['system']['location_hash'] = '{{$site_id}}'; -// Choices are 'basic', 'standard', and 'pro'. -// basic sets up the server for basic social networking and removes "complicated" features -// standard provides most desired features except e-commerce -// pro disables protocol federation plugins and only supports the zot protocol -// if you are in doubt or are unsure, it is strongly advised that you select 'standard'. - -App::$config['system']['server_role'] = '{{$server_role}}'; - - // These lines set additional security headers to be sent with all responses // You may wish to set transport_security_header to 0 if your server already sends // this header. content_security_policy may need to be disabled if you wish to diff --git a/view/fr/htconfig.tpl b/view/fr/htconfig.tpl index fae8e3f98..ddc1d1053 100644 --- a/view/fr/htconfig.tpl +++ b/view/fr/htconfig.tpl @@ -35,15 +35,6 @@ App::$config['system']['baseurl'] = '{{$siteurl}}'; App::$config['system']['sitename'] = "Hubzilla"; App::$config['system']['location_hash'] = '{{$site_id}}'; -// Choices are 'basic', 'standard', and 'pro'. -// basic sets up the sevrer for basic social networking and removes "complicated" features -// standard provides most desired features except e-commerce -// pro gives you access to everything - -App::$config['system']['server_role'] = '{{$server_role}}'; - - - // These lines set additional security headers to be sent with all responses // You may wish to set transport_security_header to 0 if your server already sends // this header. content_security_policy may need to be disabled if you wish to diff --git a/view/it/htconfig.tpl b/view/it/htconfig.tpl index ea3f5b5c2..5acb0ebe2 100644 --- a/view/it/htconfig.tpl +++ b/view/it/htconfig.tpl @@ -34,14 +34,6 @@ App::$config['system']['baseurl'] = '{{$siteurl}}'; App::$config['system']['sitename'] = "Hubzilla"; App::$config['system']['location_hash'] = '{{$site_id}}'; -// Choices are 'basic', 'standard', and 'pro'. -// basic sets up the sevrer for basic social networking and removes "complicated" features -// standard provides most desired features except e-commerce -// pro gives you access to everything - -App::$config['system']['server_role'] = '{{$server_role}}'; - - // These lines set additional security headers to be sent with all responses // You may wish to set transport_security_header to 0 if your server already sends // this header. content_security_policy may need to be disabled if you wish to diff --git a/view/nb-no/htconfig.tpl b/view/nb-no/htconfig.tpl index ea3f5b5c2..5acb0ebe2 100644 --- a/view/nb-no/htconfig.tpl +++ b/view/nb-no/htconfig.tpl @@ -34,14 +34,6 @@ App::$config['system']['baseurl'] = '{{$siteurl}}'; App::$config['system']['sitename'] = "Hubzilla"; App::$config['system']['location_hash'] = '{{$site_id}}'; -// Choices are 'basic', 'standard', and 'pro'. -// basic sets up the sevrer for basic social networking and removes "complicated" features -// standard provides most desired features except e-commerce -// pro gives you access to everything - -App::$config['system']['server_role'] = '{{$server_role}}'; - - // These lines set additional security headers to be sent with all responses // You may wish to set transport_security_header to 0 if your server already sends // this header. content_security_policy may need to be disabled if you wish to diff --git a/view/pdl/mod_cdav.pdl b/view/pdl/mod_cdav.pdl new file mode 100644 index 000000000..ae26810c4 --- /dev/null +++ b/view/pdl/mod_cdav.pdl @@ -0,0 +1,3 @@ +[region=aside] +[widget=cdav][/widget] +[/region] diff --git a/view/pt-br/htconfig.tpl b/view/pt-br/htconfig.tpl index ea3f5b5c2..5acb0ebe2 100644 --- a/view/pt-br/htconfig.tpl +++ b/view/pt-br/htconfig.tpl @@ -34,14 +34,6 @@ App::$config['system']['baseurl'] = '{{$siteurl}}'; App::$config['system']['sitename'] = "Hubzilla"; App::$config['system']['location_hash'] = '{{$site_id}}'; -// Choices are 'basic', 'standard', and 'pro'. -// basic sets up the sevrer for basic social networking and removes "complicated" features -// standard provides most desired features except e-commerce -// pro gives you access to everything - -App::$config['system']['server_role'] = '{{$server_role}}'; - - // These lines set additional security headers to be sent with all responses // You may wish to set transport_security_header to 0 if your server already sends // this header. content_security_policy may need to be disabled if you wish to diff --git a/view/ru/htconfig.tpl b/view/ru/htconfig.tpl index 00da08c91..58a18fbd0 100644 --- a/view/ru/htconfig.tpl +++ b/view/ru/htconfig.tpl @@ -34,13 +34,6 @@ App::$config['system']['baseurl'] = '{{$siteurl}}'; App::$config['system']['sitename'] = "Hubzilla"; App::$config['system']['location_hash'] = '{{$site_id}}'; -// Choices are 'basic', 'standard', and 'pro'. -// basic sets up the sevrer for basic social networking and removes "complicated" features -// standard provides most desired features except e-commerce -// pro gives you access to everything - -App::$config['system']['server_role'] = '{{$server_role}}'; - // Your choices are REGISTER_OPEN, REGISTER_APPROVE, or REGISTER_CLOSED. // Be certain to create your own personal account before setting // REGISTER_CLOSED. 'register_text' (if set) will be displayed prominently on diff --git a/view/sv/htconfig.tpl b/view/sv/htconfig.tpl index 00da08c91..58a18fbd0 100644 --- a/view/sv/htconfig.tpl +++ b/view/sv/htconfig.tpl @@ -34,13 +34,6 @@ App::$config['system']['baseurl'] = '{{$siteurl}}'; App::$config['system']['sitename'] = "Hubzilla"; App::$config['system']['location_hash'] = '{{$site_id}}'; -// Choices are 'basic', 'standard', and 'pro'. -// basic sets up the sevrer for basic social networking and removes "complicated" features -// standard provides most desired features except e-commerce -// pro gives you access to everything - -App::$config['system']['server_role'] = '{{$server_role}}'; - // Your choices are REGISTER_OPEN, REGISTER_APPROVE, or REGISTER_CLOSED. // Be certain to create your own personal account before setting // REGISTER_CLOSED. 'register_text' (if set) will be displayed prominently on diff --git a/view/theme/redbasic/css/style.css b/view/theme/redbasic/css/style.css index 510f7c80b..71ae085ea 100644 --- a/view/theme/redbasic/css/style.css +++ b/view/theme/redbasic/css/style.css @@ -427,6 +427,10 @@ footer { right: 5px; } +.contact-delete-btn { + margin-right: 32px; +} + #contact-block { width: 100%; } diff --git a/view/theme/redbasic/php/theme.php b/view/theme/redbasic/php/theme.php index a1147a5b4..2b90ae85f 100644 --- a/view/theme/redbasic/php/theme.php +++ b/view/theme/redbasic/php/theme.php @@ -5,7 +5,7 @@ * * Description: Hubzilla standard theme * * Version: 2.1 * * MinVersion: 2.3.1 - * * MaxVersion: 3.0 + * * MaxVersion: 6.0 * * Author: Fabrixxm * * Maintainer: Mike Macgirvin * * Maintainer: Mario Vavti diff --git a/view/theme/redbasic/schema/dark.css b/view/theme/redbasic/schema/dark.css index 4154c88fa..b1aa5e07a 100644 --- a/view/theme/redbasic/schema/dark.css +++ b/view/theme/redbasic/schema/dark.css @@ -139,6 +139,10 @@ option { background-color: #111; } +.nav-link.active { + color:#000 !important; +} + a.btn, aside a { font-weight: 400 !important; } diff --git a/view/tpl/abook_edit.tpl b/view/tpl/abook_edit.tpl index 9fb5c4b18..146030494 100755 --- a/view/tpl/abook_edit.tpl +++ b/view/tpl/abook_edit.tpl @@ -59,6 +59,12 @@ {{$loc_text}} {{$locstr}} </div> {{/if}} + {{if $unclonable}} + <div> + <br>{{$unclonable}} + </div> + <br> + {{/if}} {{if $last_update}} <div> {{$lastupdtext}} {{$last_update}} diff --git a/view/tpl/admin_account_edit.tpl b/view/tpl/admin_account_edit.tpl index 82d137de4..239d9084a 100644 --- a/view/tpl/admin_account_edit.tpl +++ b/view/tpl/admin_account_edit.tpl @@ -8,12 +8,7 @@ {{include file="field_password.tpl" field=$pass1}} {{include file="field_password.tpl" field=$pass2}} - -{{if $z_server_role == 'pro'}} {{include file="field_select.tpl" field=$account_level}} -{{else}} -<input type="hidden" name="account_level" value="{{$account_level.2}}" /> -{{/if}} {{include file="field_select.tpl" field=$account_language}} {{include file="field_input.tpl" field=$service_class}} diff --git a/view/tpl/admin_site.tpl b/view/tpl/admin_site.tpl index 6fd0fd9ce..e995f82b2 100755 --- a/view/tpl/admin_site.tpl +++ b/view/tpl/admin_site.tpl @@ -41,12 +41,9 @@ <input type='hidden' name='form_security_token' value='{{$form_security_token}}'> {{include file="field_input.tpl" field=$sitename}} - {{include file="field_select.tpl" field=$server_role}} - {{if $z_server_role == 'pro'}} {{include file="field_select.tpl" field=$techlevel}} {{include file="field_checkbox.tpl" field=$techlock}} - {{/if}} {{include file="field_textarea.tpl" field=$banner}} {{include file="field_textarea.tpl" field=$siteinfo}} diff --git a/view/tpl/admin_summary.tpl b/view/tpl/admin_summary.tpl index ca94b0ef7..8125703d7 100755 --- a/view/tpl/admin_summary.tpl +++ b/view/tpl/admin_summary.tpl @@ -12,7 +12,7 @@ </dl> <dl> <dt>{{$accounts.0}}</dt> - <dd>{{foreach from=$accounts.1 item=acc name=account}}<span title="{{$acc.label}}">{{$acc.val}}</span>{{if !$smarty.foreach.account.last}} / {{/if}}{{/foreach}}</dd> + <dd>{{foreach from=$accounts.1 item=acc name=account}}<span title="{{$acc.label}}">{{$acc.val}} {{$acc.label}}</span>{{if !$smarty.foreach.account.last}} / {{/if}}{{/foreach}}</dd> </dl> <dl> <dt>{{$pending.0}}</dt> @@ -20,7 +20,7 @@ </dl> <dl> <dt>{{$channels.0}}</dt> - <dd>{{foreach from=$channels.1 item=ch name=chan}}<span title="{{$ch.label}}">{{$ch.val}}</span>{{if !$smarty.foreach.chan.last}} / {{/if}}{{/foreach}}</dd> + <dd>{{foreach from=$channels.1 item=ch name=chan}}<span title="{{$ch.label}}">{{$ch.val}} {{$ch.label}}</span>{{if !$smarty.foreach.chan.last}} / {{/if}}{{/foreach}}</dd> </dl> <dl> <dt>{{$plugins.0}}</dt> diff --git a/view/tpl/cdav_addressbook.tpl b/view/tpl/cdav_addressbook.tpl new file mode 100644 index 000000000..587a95caa --- /dev/null +++ b/view/tpl/cdav_addressbook.tpl @@ -0,0 +1,462 @@ +<script> +$(document).ready(function() { + + $(document).on('click', '.vcard-header, .vcard-cancel-btn', updateView); + $(document).on('click', '.add-field', doAdd); + $(document).on('click', '.remove-field', doRemove); + + function updateView() { + var id = $(this).data('id'); + var action = $(this).data('action'); + var header = $('#vcard-header-' + id); + var cancel = $('#vcard-cancel-' + id); + var addField = $('#vcard-add-field-' + id); + var info = $('#vcard-info-' + id); + var vcardPreview = $('#vcard-preview-' + id); + var fn = $('#vcard-fn-' + id); + + if(action === 'open') { + $(header).addClass('active'); + $(cancel).show(); + $(addField).show(); + $(info).show(); + $(fn).show(); + $(vcardPreview).hide(); + } + else { + $(header).removeClass('active'); + $(cancel).hide(); + $(addField).hide(); + $(info).hide(); + $(fn).hide(); + $(vcardPreview).show(); + } + } + + function doAdd(e) { + e.preventDefault(); + var what = $(this).data('add'); + var id = $(this).data('id'); + var element = '#template-form-' + what; + var where = '#card_form_' + id; + + $(element + ' .remove-field').attr('data-id', id) + + if(what === 'vcard-adr') { + var adrCount = $(where + ' .form-' + what).length; + var attrName = 'adr[' + adrCount + '][]'; + $(element + ' input').attr('name', attrName); + } + + if(what === 'vcard-org' || what === 'vcard-title' || what === 'vcard-note') { + $(where + ' .add-' + what).hide() + } + + $(element).clone().removeAttr('id').appendTo(where + ' .form-' + what + '-wrapper'); + } + + function doRemove() { + var what = $(this).data('remove'); + var element = $(this).parents('div.form-' + what); + var where = '#card_form_' + $(this).data('id'); + + if(what === 'vcard-org' || what === 'vcard-title' || what === 'vcard-note') { + $(where + ' .add-' + what).show() + } + + $(element).remove(); + } + +}); +</script> +<div id="template-form-vcard-org" class="form-group form-vcard-org"> + <div class="form-group form-vcard-org"> + <input type="text" name="org" value="" placeholder="{{$org_label}}"> + <i data-remove="vcard-org" data-id="" class="fa fa-trash-o remove-field drop-icons fakelink"></i> + </div> +</div> + +<div id="template-form-vcard-title" class="form-group form-vcard-title"> + <div class="form-group form-vcard-title"> + <input type="text" name="title" value="" placeholder="{{$title_label}}"> + <i data-remove="vcard-title" data-id="" class="fa fa-trash-o remove-field drop-icons fakelink"></i> + </div> +</div> + +<div id="template-form-vcard-tel" class="form-group form-vcard-tel"> + <select name="tel_type[]"> + <option value="CELL">{{$mobile}}</option> + <option value="HOME">{{$home}}</option> + <option value="WORK">{{$work}}</option> + <option value="OTHER">{{$other}}</option> + </select> + <input type="text" name="tel[]" value="" placeholder="{{$tel_label}}"> + <i data-remove="vcard-tel" data-id="" class="fa fa-trash-o remove-field drop-icons fakelink"></i> +</div> + +<div id="template-form-vcard-email" class="form-group form-vcard-email"> + <select name="email_type[]"> + <option value="HOME">{{$home}}</option> + <option value="WORK">{{$work}}</option> + <option value="OTHER">{{$other}}</option> + </select> + <input type="text" name="email[]" value="" placeholder="{{$email_label}}"> + <i data-remove="vcard-email" data-id="" class="fa fa-trash-o remove-field drop-icons fakelink"></i> +</div> + +<div id="template-form-vcard-impp" class="form-group form-vcard-impp"> + <select name="impp_type[]"> + <option value="HOME">{{$home}}</option> + <option value="WORK">{{$work}}</option> + <option value="OTHER">{{$other}}</option> + </select> + <input type="text" name="impp[]" value="" placeholder="{{$impp_label}}"> + <i data-remove="vcard-impp" data-id="" class="fa fa-trash-o remove-field drop-icons fakelink"></i> +</div> + +<div id="template-form-vcard-url" class="form-group form-vcard-url"> + <select name="url_type[]"> + <option value="HOME">{{$home}}</option> + <option value="WORK">{{$work}}</option> + <option value="OTHER">{{$other}}</option> + </select> + <input type="text" name="url[]" value="" placeholder="{{$url_label}}"> + <i data-remove="vcard-url" data-id="" class="fa fa-trash-o remove-field drop-icons fakelink"></i> +</div> + +<div id="template-form-vcard-adr" class="form-group form-vcard-adr"> + <div class="form-group"> + <select name="adr_type[]"> + <option value="HOME">{{$home}}</option> + <option value="WORK">{{$work}}</option> + <option value="OTHER">{{$other}}</option> + </select> + <label>{{$adr_label}}</label> + <i data-remove="vcard-adr" data-id="" class="fa fa-trash-o remove-field drop-icons fakelink"></i> + </div> + <div class="form-group"> + <input type="text" name="" value="" placeholder="{{$po_box}}"> + </div> + <div class="form-group"> + <input type="text" name="" value="" placeholder="{{$extra}}"> + </div> + <div class="form-group"> + <input type="text" name="" value="" placeholder="{{$street}}"> + </div> + <div class="form-group"> + <input type="text" name="" value="" placeholder="{{$locality}}"> + </div> + <div class="form-group"> + <input type="text" name="" value="" placeholder="{{$region}}"> + </div> + <div class="form-group"> + <input type="text" name="" value="" placeholder="{{$zip_code}}"> + </div> + <div class="form-group"> + <input type="text" name="" value="" placeholder="{{$country}}"> + </div> +</div> + +<div id="template-form-vcard-note" class="form-group form-vcard-note"> + <label>{{$note_label}}</label> + <i data-remove="vcard-note" data-id="" class="fa fa-trash-o remove-field drop-icons fakelink"></i> + <textarea name="note" class="form-control"></textarea> +</div> + +<div class="generic-content-wrapper"> + <div class="section-title-wrapper"> + <button type="button" class="btn btn-success btn-sm float-right" onclick="openClose('create_form')"><i class="fa fa-plus-circle"></i> {{$add_card}}</button> + <h2>{{$displayname}}</h2> + </div> + <div id="create_form" class="section-content-tools-wrapper"> + <form id="card_form_new" method="post" action=""> + <input type="hidden" name="target" value="{{$id}}"> + <div class="dropdown pull-right"> + <button data-toggle="dropdown" type="button" class="btn btn-outline-secondary btn-sm dropdown-toggle"><i class="fa fa-plus"></i> {{$add_field}}</button> + <div class="dropdown-menu dropdown-menu-right"> + <a class="dropdown-item add-vcard-org add-field" style="display: none" href="#" data-add="vcard-org" data-id="new">{{$org_label}}</a> + <a class="dropdown-item add-vcard-title add-field" style="display: none" href="#" data-add="vcard-title" data-id="new">{{$title_label}}</a> + <a class="dropdown-item add-vcard-tel add-field" href="#" data-add="vcard-tel" data-id="new">{{$tel_label}}</a> + <a class="dropdown-item add-vcard-email add-field" href="#" data-add="vcard-email" data-id="new">{{$email_label}}</a> + <a class="dropdown-item add-vcard-impp add-field" href="#" data-add="vcard-impp" data-id="new">{{$impp_label}}</a> + <a class="dropdown-item add-vcard-url add-field" href="#" data-add="vcard-url" data-id="new">{{$url_label}}</a> + <a class="dropdown-item add-vcard-adr add-field" href="#" data-add="vcard-adr" data-id="new">{{$adr_label}}</a> + <a class="dropdown-item add-vcard-note add-field" href="#" data-add="vcard-note" data-id="new">{{$note_label}}</a> + </div> + </div> + + <div class="vcard-fn-create form-group"> + <div class="form-vcard-fn-wrapper"> + <div class="form-group form-vcard-fn"> + <div class="vcard-nophoto"><i class="fa fa-user"></i></div><input type="text" name="fn" value="" placeholder="{{$name_label}}"> + </div> + </div> + </div> + + <div class="vcard-org form-group"> + <div class="form-vcard-org-wrapper"> + <div class="form-group form-vcard-org"> + <input type="text" name="org" value="" placeholder="{{$org_label}}"> + <i data-remove="vcard-org" data-id="new" class="fa fa-trash-o remove-field drop-icons fakelink"></i> + </div> + </div> + </div> + + <div class="vcard-title form-group"> + <div class="form-vcard-title-wrapper"> + <div class="form-group form-vcard-title"> + <input type="text" name="title" value="" placeholder="{{$title_label}}"> + <i data-remove="vcard-title" data-id="new" class="fa fa-trash-o remove-field drop-icons fakelink"></i> + </div> + </div> + </div> + + <div class="vcard-tel form-group"> + <div class="form-vcard-tel-wrapper"> + <div class="form-group form-vcard-tel"> + <select name="tel_type[]"> + <option value="CELL">{{$mobile}}</option> + <option value="HOME">{{$home}}</option> + <option value="WORK">{{$work}}</option> + <option value="OTHER">{{$other}}</option> + </select> + <input type="text" name="tel[]" value="" placeholder="{{$tel_label}}"> + <i data-remove="vcard-tel" data-id="new" class="fa fa-trash-o remove-field drop-icons fakelink"></i> + </div> + </div> + </div> + + + <div class="vcard-email form-group"> + <div class="form-vcard-email-wrapper"> + <div class="form-group form-vcard-email"> + <select name="email_type[]"> + <option value="HOME">{{$home}}</option> + <option value="WORK">{{$work}}</option> + <option value="OTHER">{{$other}}</option> + </select> + <input type="text" name="email[]" value="" placeholder="{{$email_label}}"> + <i data-remove="vcard-email" data-id="new" class="fa fa-trash-o remove-field drop-icons fakelink"></i> + </div> + </div> + </div> + + <div class="vcard-impp form-group"> + <div class="form-vcard-impp-wrapper"> + </div> + </div> + + <div class="vcard-url form-group"> + <div class="form-vcard-url-wrapper"> + </div> + </div> + + <div class="vcard-adr form-group"> + <div class="form-vcard-adr-wrapper"> + </div> + </div> + + <div class="vcard-note form-group"> + <div class="form-vcard-note-wrapper"> + </div> + </div> + + <button type="submit" name="create" value="create_card" class="btn btn-primary btn-sm pull-right">{{$create}}</button> + <button type="button" class="btn btn-outline-secondary btn-sm" onclick="openClose('create_form')">{{$cancel}}</button> + <div class="clear"></div> + </form> + </div> + + {{foreach $cards as $card}} + <form id="card_form_{{$card.id}}" method="post" action=""> + <input type="hidden" name="target" value="{{$id}}"> + <input type="hidden" name="uri" value="{{$card.uri}}"> + <div class="section-content-wrapper-np"> + <div id="vcard-cancel-{{$card.id}}" class="vcard-cancel vcard-cancel-btn" data-id="{{$card.id}}" data-action="cancel"><i class="fa fa-close"></i></div> + <div id="vcard-add-field-{{$card.id}}" class="dropdown pull-right vcard-add-field"> + <button data-toggle="dropdown" type="button" class="btn btn-outline-secondary btn-sm dropdown-toggle"><i class="fa fa-plus"></i> {{$add_field}}</button> + <div class="dropdown-menu dropdown-menu-right"> + <a class="dropdown-item add-vcard-org add-field"{{if $card.org}} style="display: none"{{/if}} href="#" data-add="vcard-org" data-id="{{$card.id}}">{{$org_label}}</a> + <a class="dropdown-item add-vcard-title add-field"{{if $card.title}} style="display: none"{{/if}} href="#" data-add="vcard-title" data-id="{{$card.id}}">{{$title_label}}</a> + <a class="dropdown-item add-vcard-tel add-field" href="#" data-add="vcard-tel" data-id="{{$card.id}}">{{$tel_label}}</a> + <a class="dropdown-item add-vcard-email add-field" href="#" data-add="vcard-email" data-id="{{$card.id}}">{{$email_label}}</a> + <a class="dropdown-item add-vcard-impp add-field" href="#" data-add="vcard-impp" data-id="{{$card.id}}">{{$impp_label}}</a> + <a class="dropdown-item add-vcard-url add-field" href="#" data-add="vcard-url" data-id="{{$card.id}}">{{$url_label}}</a> + <a class="dropdown-item add-vcard-adr add-field" href="#" data-add="vcard-adr" data-id="{{$card.id}}">{{$adr_label}}</a> + <a class="dropdown-item add-vcard-note add-field"{{if $card.note}} style="display: none"{{/if}} href="#" data-add="vcard-note" data-id="{{$card.id}}">{{$note_label}}</a> + </div> + </div> + <div id="vcard-header-{{$card.id}}" class="vcard-header" data-id="{{$card.id}}" data-action="open"> + {{if $card.photo}}<img class="vcard-photo" src="{{$card.photo}}" width="32px" height="32px">{{else}}<div class="vcard-nophoto"><i class="fa fa-user"></i></div>{{/if}} + <span id="vcard-preview-{{$card.id}}" class="vcard-preview"> + {{if $card.fn}}<span class="vcard-fn-preview">{{$card.fn}}</span>{{/if}} + {{if $card.emails.0.address}}<span class="vcard-email-preview hidden-xs">{{$card.emails.0.address}}</span>{{/if}} + {{if $card.tels.0}}<span class="vcard-tel-preview hidden-xs">{{$card.tels.0.nr}}</span>{{/if}} + </span> + <input id="vcard-fn-{{$card.id}}" class="vcard-fn" type="text" name="fn" value="{{$card.fn}}" size="{{$card.fn|count_characters:true}}" placeholder="{{$name_label}}"> + </div> + </div> + <div id="vcard-info-{{$card.id}}" class="vcard-info section-content-wrapper"> + + <div class="vcard-org form-group"> + <div class="form-vcard-org-wrapper"> + {{if $card.org}} + <div class="form-group form-vcard-org"> + <input type="text" name="org" value="{{$card.org}}" size="{{$card.org|count_characters:true}}" placeholder="{{$org_label}}"> + <i data-remove="vcard-org" data-id="{{$card.id}}" class="fa fa-trash-o remove-field drop-icons fakelink"></i> + </div> + {{/if}} + </div> + </div> + + <div class="vcard-title form-group"> + <div class="form-vcard-title-wrapper"> + {{if $card.title}} + <div class="form-group form-vcard-title"> + <input type="text" name="title" value="{{$card.title}}" size="{{$card.title|count_characters:true}}" placeholder="{{$title_label}}"> + <i data-remove="vcard-title" data-id="{{$card.id}}" class="fa fa-trash-o remove-field drop-icons fakelink"></i> + </div> + {{/if}} + </div> + </div> + + + <div class="vcard-tel form-group"> + <div class="form-vcard-tel-wrapper"> + {{if $card.tels}} + {{foreach $card.tels as $tel}} + <div class="form-group form-vcard-tel"> + <select name="tel_type[]"> + <option value=""{{if $tel.type.0 != 'CELL' && $tel.type.0 != 'HOME' && $tel.type.0 != 'WORK' && $tel.type.0 != 'OTHER'}} selected="selected"{{/if}}>{{$tel.type.1}}</option> + <option value="CELL"{{if $tel.type.0 == 'CELL'}} selected="selected"{{/if}}>{{$mobile}}</option> + <option value="HOME"{{if $tel.type.0 == 'HOME'}} selected="selected"{{/if}}>{{$home}}</option> + <option value="WORK"{{if $tel.type.0 == 'WORK'}} selected="selected"{{/if}}>{{$work}}</option> + <option value="OTHER"{{if $tel.type.0 == 'OTHER'}} selected="selected"{{/if}}>{{$other}}</option> + </select> + <input type="text" name="tel[]" value="{{$tel.nr}}" size="{{$tel.nr|count_characters:true}}" placeholder="{{$tel_label}}"> + <i data-remove="vcard-tel" data-id="{{$card.id}}" class="fa fa-trash-o remove-field drop-icons fakelink"></i> + </div> + {{/foreach}} + {{/if}} + </div> + </div> + + + <div class="vcard-email form-group"> + <div class="form-vcard-email-wrapper"> + {{if $card.emails}} + {{foreach $card.emails as $email}} + <div class="form-group form-vcard-email"> + <select name="email_type[]"> + <option value=""{{if $email.type.0 != 'HOME' && $email.type.0 != 'WORK' && $email.type.0 != 'OTHER'}} selected="selected"{{/if}}>{{$email.type.1}}</option> + <option value="HOME"{{if $email.type.0 == 'HOME'}} selected="selected"{{/if}}>{{$home}}</option> + <option value="WORK"{{if $email.type.0 == 'WORK'}} selected="selected"{{/if}}>{{$work}}</option> + <option value="OTHER"{{if $email.type.0 == 'OTHER'}} selected="selected"{{/if}}>{{$other}}</option> + </select> + <input type="text" name="email[]" value="{{$email.address}}" size="{{$email.address|count_characters:true}}" placeholder="{{$email_label}}"> + <i data-remove="vcard-email" data-id="{{$card.id}}" class="fa fa-trash-o remove-field drop-icons fakelink"></i> + </div> + {{/foreach}} + {{/if}} + </div> + </div> + + <div class="vcard-impp form-group"> + <div class="form-vcard-impp-wrapper"> + {{if $card.impps}} + {{foreach $card.impps as $impp}} + <div class="form-group form-vcard-impp"> + <select name="impp_type[]"> + <option value=""{{if $impp.type.0 != 'HOME' && $impp.type.0 != 'WORK' && $impp.type.0 != 'OTHER'}} selected="selected"{{/if}}>{{$impp.type.1}}</option> + <option value="HOME"{{if $impp.type.0 == 'HOME'}} selected="selected"{{/if}}>{{$home}}</option> + <option value="WORK"{{if $impp.type.0 == 'WORK'}} selected="selected"{{/if}}>{{$work}}</option> + <option value="OTHER"{{if $impp.type.0 == 'OTHER'}} selected="selected"{{/if}}>{{$other}}</option> + </select> + <input type="text" name="impp[]" value="{{$impp.address}}" size="{{$impp.address|count_characters:true}}" placeholder="{{$impp_label}}"> + <i data-remove="vcard-impp" data-id="{{$card.id}}" class="fa fa-trash-o remove-field drop-icons fakelink"></i> + </div> + {{/foreach}} + {{/if}} + </div> + </div> + + <div class="vcard-url form-group"> + <div class="form-vcard-url-wrapper"> + {{if $card.urls}} + {{foreach $card.urls as $url}} + <div class="form-group form-vcard-url"> + <select name="url_type[]"> + <option value=""{{if $url.type.0 != 'HOME' && $url.type.0 != 'WORK' && $url.type.0 != 'OTHER'}} selected="selected"{{/if}}>{{$url.type.1}}</option> + <option value="HOME"{{if $url.type.0 == 'HOME'}} selected="selected"{{/if}}>{{$home}}</option> + <option value="WORK"{{if $url.type.0 == 'WORK'}} selected="selected"{{/if}}>{{$work}}</option> + <option value="OTHER"{{if $url.type.0 == 'OTHER'}} selected="selected"{{/if}}>{{$other}}</option> + </select> + <input type="text" name="url[]" value="{{$url.address}}" size="{{$url.address|count_characters:true}}" placeholder="{{$url_label}}"> + <i data-remove="vcard-url" data-id="{{$card.id}}" class="fa fa-trash-o remove-field drop-icons fakelink"></i> + </div> + {{/foreach}} + {{/if}} + </div> + </div> + + <div class="vcard-adr form-group"> + <div class="form-vcard-adr-wrapper"> + {{if $card.adrs}} + {{foreach $card.adrs as $adr}} + <div class="form-group form-vcard-adr"> + <div class="form-group"> + <label>{{$adr_label}}</label> + <select name="adr_type[]"> + <option value=""{{if $adr.type.0 != 'HOME' && $adr.type.0 != 'WORK' && $adr.type.0 != 'OTHER'}} selected="selected"{{/if}}>{{$adr.type.1}}</option> + <option value="HOME"{{if $adr.type.0 == 'HOME'}} selected="selected"{{/if}}>{{$home}}</option> + <option value="WORK"{{if $adr.type.0 == 'WORK'}} selected="selected"{{/if}}>{{$work}}</option> + <option value="OTHER"{{if $adr.type.0 == 'OTHER'}} selected="selected"{{/if}}>{{$other}}</option> + </select> + <i data-remove="vcard-adr" data-id="{{$card.id}}" class="fa fa-trash-o remove-field drop-icons fakelink"></i> + </div> + <div class="form-group"> + <input type="text" name="adr[{{$adr@index}}][]" value="{{$adr.address.0}}" size="{{$adr.address.0|count_characters:true}}" placeholder="{{$po_box}}"> + </div> + <div class="form-group"> + <input type="text" name="adr[{{$adr@index}}][]" value="{{$adr.address.1}}" size="{{$adr.address.1|count_characters:true}}" placeholder="{{$extra}}"> + </div> + <div class="form-group"> + <input type="text" name="adr[{{$adr@index}}][]" value="{{$adr.address.2}}" size="{{$adr.address.2|count_characters:true}}" placeholder="{{$street}}"> + </div> + <div class="form-group"> + <input type="text" name="adr[{{$adr@index}}][]" value="{{$adr.address.3}}" size="{{$adr.address.3|count_characters:true}}" placeholder="{{$locality}}"> + </div> + <div class="form-group"> + <input type="text" name="adr[{{$adr@index}}][]" value="{{$adr.address.4}}" size="{{$adr.address.4|count_characters:true}}" placeholder="{{$region}}"> + </div> + <div class="form-group"> + <input type="text" name="adr[{{$adr@index}}][]" value="{{$adr.address.5}}" size="{{$adr.address.5|count_characters:true}}" placeholder="{{$zip_code}}"> + </div> + <div class="form-group"> + <input type="text" name="adr[{{$adr@index}}][]" value="{{$adr.address.6}}" size="{{$adr.address.6|count_characters:true}}" placeholder="{{$country}}"> + </div> + </div> + {{/foreach}} + {{/if}} + </div> + </div> + + <div class="vcard-note form-group form-vcard-note"> + <div class="form-vcard-note-wrapper"> + {{if $card.note}} + <label>{{$note_label}}</label> + <i data-remove="vcard-note" data-id="{{$card.id}}" class="fa fa-trash-o remove-field drop-icons fakelink"></i> + <textarea name="note" class="form-control">{{$card.note}}</textarea> + {{/if}} + </div> + </div> + + + <button type="submit" name="update" value="update_card" class="btn btn-primary btn-sm pull-right">{{$update}}</button> + <button type="submit" name="delete" value="delete_card" class="btn btn-danger btn-sm">{{$delete}}</button> + <button type="button" class="btn btn-outline-secondary btn-sm vcard-cancel-btn" data-id="{{$card.id}}" data-action="cancel">{{$cancel}}</button> + <div class="clear"></div> + </div> + </form> + {{/foreach}} +</div> diff --git a/view/tpl/cdav_calendar.tpl b/view/tpl/cdav_calendar.tpl new file mode 100644 index 000000000..5d683d751 --- /dev/null +++ b/view/tpl/cdav_calendar.tpl @@ -0,0 +1,349 @@ +<script> + +var new_event = []; +var new_event_id = Math.random().toString(36).substring(7); +var views = {'month' : '{{$month}}', 'agendaWeek' : '{{$week}}', 'agendaDay' : '{{$day}}', 'listMonth' : '{{$list_month}}', 'listWeek' : '{{$list_week}}', 'listDay' : '{{$list_day}}'}; + +$(document).ready(function() { + $('#calendar').fullCalendar({ + eventSources: [ {{$sources}} ], + + header: false, + eventTextColor: 'white', + + lang: '{{$lang}}', + firstDay: {{$first_day}}, + + monthNames: aStr['monthNames'], + monthNamesShort: aStr['monthNamesShort'], + dayNames: aStr['dayNames'], + dayNamesShort: aStr['dayNamesShort'], + allDayText: aStr['allday'], + + timeFormat: 'HH:mm', + timezone: 'local', + + defaultTimedEventDuration: '01:00:00', + snapDuration: '00:15:00', + + dayClick: function(date, jsEvent, view) { + + if(new_event.length) + $('#calendar').fullCalendar( 'removeEventSource', new_event); + + $('#event_uri').val(''); + $('#id_title').val('New event'); + $('#calendar_select').val($("#calendar_select option:first").val()).attr('disabled', false); + $('#id_dtstart').val(date.format()); + $('#id_dtend').val(date.hasTime() ? date.add(1, 'hours').format() : date.add(1, 'days').format()); + $('#id_description').val(''); + $('#id_location').val(''); + $('#event_submit').val('create_event').html('Create'); + $('#event_delete').hide(); + + new_event = [{ id: new_event_id, title : 'New event', start: $('#id_dtstart').val(), end: $('#id_dtend').val(), editable: true, color: '#bbb' }] + $('#calendar').fullCalendar( 'addEventSource', new_event); + }, + + eventClick: function(event, jsEvent, view) { + + if(event.id == new_event_id) { + $(window).scrollTop(0); + $('.section-content-tools-wrapper, #event_form_wrapper').show(); + $('#recurrence_warning').hide(); + $('#id_title').focus().val(''); + return false; + } + + if($('main').hasClass('fullscreen') && view.type !== 'month' && event.rw) + $('#calendar').fullCalendar('option', 'height', 'auto'); + + if(new_event.length && event.rw) { + $('#calendar').fullCalendar( 'removeEventSource', new_event); + } + + if(!event.recurrent && event.rw) { + var start_clone = moment(event.start); + var noend_allday = start_clone.add(1, 'day').format('YYYY-MM-DD'); + + $(window).scrollTop(0); + $('.section-content-tools-wrapper, #event_form_wrapper').show(); + $('#recurrence_warning').hide(); + $('#id_title').focus(); + + $('#event_uri').val(event.uri); + $('#id_title').val(event.title); + $('#calendar_select').val(event.calendar_id[0] + ':' + event.calendar_id[1]).attr('disabled', true); + $('#id_dtstart').val(event.start.format()); + $('#id_dtend').val(event.end ? event.end.format() : event.start.hasTime() ? '' : noend_allday); + $('#id_description').val(event.description); + $('#id_location').val(event.location); + $('#event_submit').val('update_event').html('Update'); + $('#event_delete').show(); + } + else if(event.recurrent && event.rw) { + $('.section-content-tools-wrapper, #recurrence_warning').show(); + $('#event_form_wrapper').hide(); + $('#event_uri').val(event.uri); + $('#calendar_select').val(event.calendar_id[0] + ':' + event.calendar_id[1]).attr('disabled', true); + } + }, + + eventResize: function(event, delta, revertFunc) { + + $('#id_title').val(event.title); + $('#id_dtstart').val(event.start.format()); + $('#id_dtend').val(event.end.format()); + + $.post( 'cdav/calendar', { + 'update': 'resize', + 'id[]': event.calendar_id, + 'uri': event.uri, + 'dtstart': event.start ? event.start.format() : '', + 'dtend': event.end ? event.end.format() : '' + }) + .fail(function() { + revertFunc(); + }); + }, + + eventDrop: function(event, delta, revertFunc) { + + var start_clone = moment(event.start); + var noend_allday = start_clone.add(1, 'day').format('YYYY-MM-DD'); + + $('#id_title').val(event.title); + $('#id_dtstart').val(event.start.format()); + $('#id_dtend').val(event.end ? event.end.format() : event.start.hasTime() ? '' : noend_allday); + + $.post( 'cdav/calendar', { + 'update': 'drop', + 'id[]': event.calendar_id, + 'uri': event.uri, + 'dtstart': event.start ? event.start.format() : '', + 'dtend': event.end ? event.end.format() : event.start.hasTime() ? '' : noend_allday + }) + .fail(function() { + revertFunc(); + }); + }, + + loading: function(isLoading, view) { + $('#events-spinner').spin('tiny'); + $('#events-spinner > i').css('color', 'transparent'); + if(!isLoading) { + $('#events-spinner').spin(false); + $('#events-spinner > i').css('color', ''); + } + } + }); + + // echo the title + var view = $('#calendar').fullCalendar('getView'); + + $('#title').text(view.title); + + $('#view_selector').html(views[view.name]); + + $('.color-edit').colorpicker({ input: '.color-edit-input' }); + + $(document).on('click','#fullscreen-btn', on_fullscreen); + $(document).on('click','#inline-btn', on_inline); + + $(document).on('click','#event_submit', on_submit); + $(document).on('click','#event_more', on_more); + $(document).on('click','#event_cancel, #event_cancel_recurrent', reset_form); + $(document).on('click','#event_delete, #event_delete_recurrent', on_delete); + +}); + +function changeView(action, viewName) { + $('#calendar').fullCalendar(action, viewName); + var view = $('#calendar').fullCalendar('getView'); + + if($('main').hasClass('fullscreen')) + if(view.name !== 'month') + $('.section-content-tools-wrapper').css('display') === 'none' ? on_fullscreen() : on_inline() ; + else + on_fullscreen(); + else + on_inline(); + + $('#title').text(view.title); + $('#view_selector').html(views[view.name]); +} + +function add_remove_json_source(source, color, editable, status) { + + if(status === undefined) + status = 'fa-calendar-check-o'; + + if(status === 'drop') { + reset_form(); + $('#calendar').fullCalendar( 'removeEventSource', source ); + return; + } + + var parts = source.split('/'); + var id = parts[4]; + + var selector = '#calendar-btn-' + id; + + if($(selector).hasClass('fa-calendar-o')) { + $('#calendar').fullCalendar( 'addEventSource', { url: source, color: color, editable: editable }); + $(selector).removeClass('fa-calendar-o'); + $(selector).addClass(status); + $.get('/cdav/calendar/switch/' + id + '/1'); + } + else { + $('#calendar').fullCalendar( 'removeEventSource', source ); + $(selector).removeClass(status); + $(selector).addClass('fa-calendar-o'); + $.get('/cdav/calendar/switch/' + id + '/0'); + } +} + +function on_fullscreen() { + var view = $('#calendar').fullCalendar('getView'); + if(($('.section-content-tools-wrapper').css('display') === 'none') || ($('.section-content-tools-wrapper').css('display') !== 'none' && view.type === 'month')) + $('#calendar').fullCalendar('option', 'height', $(window).height() - $('.section-title-wrapper').outerHeight(true) - 2); // -2 is for border width (.generic-content-wrapper top and bottom) of .generic-content-wrapper +} + +function on_inline() { + var view = $('#calendar').fullCalendar('getView'); + ((view.type === 'month') ? $('#calendar').fullCalendar('option', 'height', '') : $('#calendar').fullCalendar('option', 'height', 'auto')); +} + +function on_submit() { + $.post( 'cdav/calendar', { + 'submit': $('#event_submit').val(), + 'target': $('#calendar_select').val(), + 'uri': $('#event_uri').val(), + 'title': $('#id_title').val(), + 'dtstart': $('#id_dtstart').val(), + 'dtend': $('#id_dtend').val(), + 'description': $('#id_description').val(), + 'location': $('#id_location').val() + }) + .done(function() { + $('#calendar').fullCalendar( 'refetchEventSources', [ {{$sources}} ] ); + reset_form(); + }); +} + +function on_delete() { + $.post( 'cdav/calendar', { + 'delete': 'delete', + 'target': $('#calendar_select').val(), + 'uri': $('#event_uri').val(), + }) + .done(function() { + $('#calendar').fullCalendar( 'refetchEventSources', [ {{$sources}} ] ); + reset_form(); + }); +} + +function reset_form() { + $('.section-content-tools-wrapper, #event_form_wrapper, #recurrence_warning').hide(); + + $('#event_submit').val(''); + $('#calendar_select').val(''); + $('#event_uri').val(''); + $('#id_title').val(''); + $('#id_dtstart').val(''); + $('#id_dtend').val(''); + + if(new_event.length) + $('#calendar').fullCalendar( 'removeEventSource', new_event); + + if($('#more_block').hasClass('open')) + on_more(); + + if($('main').hasClass('fullscreen')) + on_fullscreen(); +} + +function on_more() { + if($('#more_block').hasClass('open')) { + $('#event_more').html('<i class="fa fa-caret-down"></i> {{$more}}'); + $('#more_block').removeClass('open').hide(); + } + else { + $('#event_more').html('<i class="fa fa-caret-up"></i> {{$less}}'); + $('#more_block').addClass('open').show(); + } +} + +</script> + +<div class="generic-content-wrapper"> + <div class="section-title-wrapper"> + <div class="float-right"> + <div class="dropdown"> + <button id="view_selector" type="button" class="btn btn-outline-secondary btn-sm dropdown-toggle" data-toggle="dropdown"></button> + <div class="dropdown-menu"> + <a class="dropdown-item" href="#" onclick="changeView('changeView', 'month'); return false;">{{$month}}</a></li> + <a class="dropdown-item" href="#" onclick="changeView('changeView', 'agendaWeek'); return false;">{{$week}}</a></li> + <a class="dropdown-item" href="#" onclick="changeView('changeView', 'agendaDay'); return false;">{{$day}}</a></li> + <div class="dropdown-divider"></div> + <a class="dropdown-item" href="#" onclick="changeView('changeView', 'listMonth'); return false;">{{$list_month}}</a></li> + <a class="dropdown-item" href="#" onclick="changeView('changeView', 'listWeek'); return false;">{{$list_week}}</a></li> + <a class="dropdown-item" href="#" onclick="changeView('changeView', 'listDay'); return false;">{{$list_day}}</a></li> + </div> + <div class="btn-group"> + <button class="btn btn-outline-secondary btn-sm" onclick="changeView('prev', false);" title="{{$prev}}"><i class="fa fa-backward"></i></button> + <button id="events-spinner" class="btn btn-outline-secondary btn-sm" onclick="changeView('today', false);" title="{{$today}}"><i class="fa fa-bullseye"></i></button> + <button class="btn btn-outline-secondary btn-sm" onclick="changeView('next', false);" title="{{$next}}"><i class="fa fa-forward"></i></button> + </div> + <button id="fullscreen-btn" type="button" class="btn btn-outline-secondary btn-sm" onclick="makeFullScreen();"><i class="fa fa-expand"></i></button> + <button id="inline-btn" type="button" class="btn btn-outline-secondary btn-sm" onclick="makeFullScreen(false);"><i class="fa fa-compress"></i></button> + </div> + </div> + <h2 id="title"></h2> + <div class="clear"></div> + </div> + <div class="section-content-tools-wrapper" style="display: none"> + <div id="recurrence_warning" style="display: none"> + <div class="section-content-warning-wrapper"> + {{$recurrence_warning}} + </div> + <div> + <button id="event_delete_recurrent" type="button" class="btn btn-danger btn-sm">{{$delete_all}}</button> + <button id="event_cancel_recurrent" type="button" class="btn btn-outline-secondary btn-sm">{{$cancel}}</button> + </div> + </div> + <div id="event_form_wrapper" style="display: none"> + <form id="event_form" method="post" action=""> + <input id="event_uri" type="hidden" name="uri" value=""> + {{include file="field_input.tpl" field=$title}} + <label for="calendar_select">{{$calendar_select_label}}</label> + <select id="calendar_select" name="target" class="form-control form-group"> + {{foreach $writable_calendars as $writable_calendar}} + <option value="{{$writable_calendar.id.0}}:{{$writable_calendar.id.1}}">{{$writable_calendar.displayname}}{{if $writable_calendar.sharer}} ({{$writable_calendar.sharer}}){{/if}}</option> + {{/foreach}} + </select> + <div id="more_block" style="display: none;"> + {{include file="field_input.tpl" field=$dtstart}} + {{include file="field_input.tpl" field=$dtend}} + {{include file="field_textarea.tpl" field=$description}} + {{include file="field_textarea.tpl" field=$location}} + </div> + <div class="form-group"> + <div class="pull-right"> + <button id="event_more" type="button" class="btn btn-outline-secondary btn-sm"><i class="fa fa-caret-down"></i> {{$more}}</button> + <button id="event_submit" type="button" value="" class="btn btn-primary btn-sm"></button> + + </div> + <div> + <button id="event_delete" type="button" class="btn btn-danger btn-sm">{{$delete}}</button> + <button id="event_cancel" type="button" class="btn btn-outline-secondary btn-sm">{{$cancel}}</button> + </div> + <div class="clear"></div> + </div> + </form> + </div> + </div> + <div class="section-content-wrapper-np"> + <div id="calendar"></div> + </div> +</div> diff --git a/view/tpl/cdav_widget_addressbook.tpl b/view/tpl/cdav_widget_addressbook.tpl new file mode 100644 index 000000000..c875dc977 --- /dev/null +++ b/view/tpl/cdav_widget_addressbook.tpl @@ -0,0 +1,66 @@ +<div class="widget"> + <h3>{{$addressbooks_label}}</h3> + {{foreach $addressbooks as $addressbook}} + <div id="addressbook-{{$addressbook.id}}" class="ml-3"> + <div class="form-group"> + <i class="fa fa-user generic-icons"></i><a href="/cdav/addressbook/{{$addressbook.id}}">{{$addressbook.displayname}}</a> + <div class="float-right"> + <i id="edit-icon" class="fa fa-pencil fakelink generic-icons" onclick="openClose('edit-addressbook-{{$addressbook.id}}')"></i> + <a href="/cdav/addressbooks/{{$addressbook.ownernick}}/{{$addressbook.uri}}/?export"><i id="download-icon" class="fa fa-cloud-download fakelink generic-icons"></i></a> + <a href="#" onclick="dropItem('/cdav/addressbook/drop/{{$addressbook.id}}', '#addressbook-{{$addressbook.id}}'); return false;"><i class="fa fa-trash-o drop-icons"></i></a> + </div> + </div> + <div id="edit-addressbook-{{$addressbook.id}}" class="sub-menu" style="display: none;"> + <form id="edit-addressbook-{{$addressbook.id}}" method="post" action=""> + <label for="edit-{{$addressbook.id}}">{{$edit_label}}</label> + <div id="edit-form-{{$addressbook.id}}" class="form-group"> + <input id="id-{{$addressbook.id}}" name="id" type="hidden" value="{{$addressbook.id}}"> + <input id="edit-{{$addressbook.id}}" name="{DAV:}displayname" type="text" value="{{$addressbook.displayname}}" class="form-control"> + </div> + <div class="form-group"> + <button type="submit" name="edit" value="edit" class="btn btn-primary btn-sm">{{$edit}}</button> + </div> + </form> + </div> + </div> + {{/foreach}} +</div> + +<div class="widget"> + <h3>{{$tools_label}}</h3> + <ul class="nav nav-pills flex-column"> + <li class="nav-item"> + <a class="nav-link" href="#" onclick="openClose('create-addressbook'); return false;"><i class="fa fa-user-plus generic-icons"></i> {{$create_label}}</a> + </li> + <div id="create-addressbook" class="sub-menu-wrapper"> + <div class="sub-menu"> + <form method="post" action=""> + <div class="form-group"> + <input id="create" name="{DAV:}displayname" type="text" placeholder="{{$create_placeholder}}" class="form-control form-group"> + <button type="submit" name="create" value="create" class="btn btn-primary btn-sm">{{$create}}</button> + </div> + </form> + </div> + </div> + <li class="nav-item"> + <a class="nav-link" href="#" onclick="openClose('upload-form'); return false;"><i class="fa fa-cloud-upload generic-icons"></i> {{$import_label}}</a> + </li> + <div id="upload-form" class="sub-menu-wrapper"> + <div class="sub-menu"> + <div class="form-group"> + <select id="import" name="target" class="form-control"> + <option value="">{{$import_placeholder}}</option> + {{foreach $addressbooks as $addressbook}} + <option value="{{$addressbook.id}}">{{$addressbook.displayname}}</option> + {{/foreach}} + </select> + </div> + <div class="form-group"> + <input class="form-control-file w-100" id="addressbook-upload-choose" type="file" name="userfile" /> + </div> + <button class="btn btn-primary btn-sm" type="submit" name="a_upload" value="a_upload">{{$upload}}</button> + </form> + </div> + </div> + </ul> +</div> diff --git a/view/tpl/cdav_widget_calendar.tpl b/view/tpl/cdav_widget_calendar.tpl new file mode 100644 index 000000000..ec2257a19 --- /dev/null +++ b/view/tpl/cdav_widget_calendar.tpl @@ -0,0 +1,121 @@ +{{if $my_calendars}} +<div class="widget"> + <h3>{{$my_calendars_label}}</h3> + {{foreach $my_calendars as $calendar}} + <div id="calendar-{{$calendar.calendarid}}"> + <div class="ml-3{{if !$calendar@last}} form-group{{/if}}"> + <i id="calendar-btn-{{$calendar.calendarid}}" class="fa {{if $calendar.switch}}fa-calendar-check-o{{else}}fa-calendar-o{{/if}} generic-icons fakelink" onclick="add_remove_json_source('{{$calendar.json_source}}', '{{$calendar.color}}', {{$calendar.editable}})" style="color: {{$calendar.color}};"></i>{{$calendar.displayname}} + <div class="float-right"> + <i id="edit-icon" class="fa fa-pencil fakelink generic-icons" onclick="openClose('edit-calendar-{{$calendar.calendarid}}')"></i> + <a href="/cdav/calendars/{{$calendar.ownernick}}/{{$calendar.uri}}/?export"><i id="download-icon" class="fa fa-cloud-download fakelink generic-icons"></i></a> + <i id="share-icon" class="fa fa-share-alt fakelink generic-icons" onclick="openClose('share-calendar-{{$calendar.calendarid}}')"></i> + <a href="#" onclick="var drop = dropItem('/cdav/calendar/drop/{{$calendar.calendarid}}/{{$calendar.instanceid}}', '#calendar-{{$calendar.calendarid}}'); if(drop) { add_remove_json_source('{{$calendar.json_source}}', '{{$calendar.color}}', {{$calendar.editable}}, 'drop'); } return false;"><i class="fa fa-trash-o drop-icons"></i></a> + </div> + <div id="share-calendar-{{$calendar.calendarid}}" class="sub-menu" style="display: none; border-color: {{$calendar.color}};"> + {{if $calendar.sharees}} + {{foreach $calendar.sharees as $sharee}} + <div id="sharee-{{$calendar.calendarid}}" class="form-group"> + <i class="fa fa-share generic-icons"></i>{{$sharee.name}} {{$sharee.access}} + <div class="pull-right"> + <a href="#" onclick="dropItem('/cdav/calendar/dropsharee/{{$calendar.calendarid}}/{{$calendar.instanceid}}/{{$sharee.hash}}', '#sharee-{{$calendar.calendarid}}'); return false;"><i class="fa fa-trash-o drop-icons"></i></a> + </div> + </div> + {{/foreach}} + {{/if}} + <form method="post" action=""> + <label for="share-{{$calendar.calendarid}}">{{$share_label}}</label> + <input name="calendarid" type="hidden" value="{{$calendar.calendarid}}"> + <input name="instanceid" type="hidden" value="{{$calendar.instanceid}}"> + <div class="form-group"> + <select id="share-{{$calendar.calendarid}}" name="sharee" class="form-control"> + {{$sharee_options}} + </select> + </div> + <div class="form-group"> + <select name="access" class="form-control"> + {{$access_options}} + </select> + </div> + <div class="form-group"> + <button type="submit" name="share" value="share" class="btn btn-primary btn-sm">{{$share}}</button> + </div> + </form> + </div> + <div id="edit-calendar-{{$calendar.calendarid}}" class="sub-menu" style="display: none; border-color: {{$calendar.color}};"> + <form id="edit-calendar-{{$calendar.calendarid}}" method="post" action="" class="colorpicker-component color-edit"> + <input id="id-{{$calendar.calendarid}}" name="id" type="hidden" value="{{$calendar.calendarid}}:{{$calendar.instanceid}}"> + <input id="color-{{$calendar.calendarid}}" name="color" type="hidden" value="{{$calendar.color}}" class="color-edit-input"> + <label for="edit-form-{{$calendar.calendarid}}">{{$edit_label}}</label> + <div id="edit-form-{{$calendar.calendarid}}" class="input-group form-group"> + <input id="create-{{$calendar.calendarid}}" name="{DAV:}displayname" type="text" value="{{$calendar.displayname}}" class="form-control"> + <span class="input-group-addon"><i></i></span> + </div> + <div class="form-group"> + <button type="submit" name="edit" value="edit" class="btn btn-primary btn-sm">{{$edit}}</button> + </div> + </form> + </div> + </div> + </div> + {{/foreach}} +</div> +{{/if}} + +{{if $shared_calendars}} +<div class="widget"> + <h3>{{$shared_calendars_label}}</h3> + {{foreach $shared_calendars as $calendar}} + <div id="shared-calendar-{{$calendar.calendarid}}" class="ml-3{{if !$calendar@last}} form-group{{/if}}"> + <i id="calendar-btn-{{$calendar.calendarid}}" class="fa {{if $calendar.switch}}{{if $calendar.access == 'read-write'}}fa-calendar-check-o{{else}}fa-calendar-times-o{{/if}}{{else}}fa-calendar-o{{/if}} generic-icons fakelink" onclick="add_remove_json_source('{{$calendar.json_source}}', '{{$calendar.color}}', {{$calendar.editable}}, {{if $calendar.access == 'read-write'}}'fa-calendar-check-o'{{else}}'fa-calendar-times-o'{{/if}})" style="color: {{$calendar.color}};"></i>{{$calendar.displayname}} ({{$calendar.sharer}}) + <div class="pull-right"> + <a href="/cdav/calendars/{{$calendar.ownernick}}/{{$calendar.uri}}/?export"><i id="download-icon" class="fa fa-cloud-download fakelink generic-icons"></i></a> + <a href="#" onclick="var drop = dropItem('/cdav/calendar/drop/{{$calendar.calendarid}}/{{$calendar.instanceid}}', '#shared-calendar-{{$calendar.calendarid}}'); if(drop) { add_remove_json_source('{{$calendar.json_source}}', '{{$calendar.color}}', {{$calendar.editable}}, 'drop'); } return false;"><i class="fa fa-trash-o drop-icons"></i></a> + </div> + </div> + {{/foreach}} +</div> +{{/if}} + +<div class="widget"> + <h3>{{$tools_label}}</h3> + <div class="nav nav-pills flex-column"> + <li class="nav-item"> + <a class="nav-link" href="#" onclick="openClose('create-calendar'); return false;"><i class="fa fa-calendar-plus-o generic-icons"></i> {{$create_label}}</a> + </li> + <div id="create-calendar" class="sub-menu-wrapper"> + <div class="sub-menu"> + <form method="post" action="" class="colorpicker-component color-edit"> + <input id="color" name="color" type="hidden" value="#3a87ad" class="color-edit-input"> + <div id="create-form" class="input-group form-group"> + <input id="create" name="{DAV:}displayname" type="text" placeholder="{{$create_placeholder}}" class="form-control"> + <span class="input-group-addon"><i></i></span> + </div> + <div class="form-group"> + <button type="submit" name="create" value="create" class="btn btn-primary btn-sm">{{$create}}</button> + </div> + </form> + </div> + </div> + <li class="nav-item"> + <a class="nav-link" href="#" onclick="openClose('upload-form'); return false;"><i class="fa fa-cloud-upload generic-icons"></i> {{$import_label}}</a> + </li> + <div id="upload-form" class="sub-menu-wrapper"> + <div class="sub-menu"> + <form enctype="multipart/form-data" method="post" action=""> + <div class="form-group"> + <select id="import" name="target" class="form-control"> + <option value="">{{$import_placeholder}}</option> + {{foreach $writable_calendars as $writable_calendar}} + <option value="{{$writable_calendar.id.0}}:{{$writable_calendar.id.1}}">{{$writable_calendar.displayname}}</option> + {{/foreach}} + </select> + </div> + <div class="form-group"> + <input class="form-control-file w-100" id="event-upload-choose" type="file" name="userfile" /> + </div> + <button class="btn btn-primary btn-sm" type="submit" name="c_upload" value="c_upload">{{$upload}}</button> + </form> + </div> + </div> + </div> +</div> diff --git a/view/tpl/connection_template.tpl b/view/tpl/connection_template.tpl index 16915abda..8e49c9e27 100755 --- a/view/tpl/connection_template.tpl +++ b/view/tpl/connection_template.tpl @@ -8,8 +8,8 @@ <a href="connedit/{{$contact.id}}/ignore" class="btn btn-warning btn-sm" title="{{$contact.ignore_hover}}"><i class="fa fa-ban"></i> {{$contact.ignore}}</a> {{/if}} - <a href="#" class="btn btn-danger btn-sm" title="{{$contact.delete_hover}}" onclick="dropItem('{{$contact.deletelink}}', '#contact-entry-wrapper-{{$contact.id}}'); return false;"><i class="fa fa-trash-o"></i> {{$contact.delete}}</a> - <a href="{{$contact.link}}" class="btn btn-outline-secondary btn-sm" title="{{$contact.edit_hover}}"><i class="fa fa-pencil"></i></a> + <a href="#" class="btn btn-danger btn-sm contact-delete-btn" title="{{$contact.delete_hover}}" onclick="dropItem('{{$contact.deletelink}}', '#contact-entry-wrapper-{{$contact.id}}'); return false;"><i class="fa fa-trash-o"></i> {{$contact.delete}}</a> + <a href="{{$contact.link}}" class="btn btn-outline-secondary btn-sm" title="{{$contact.edit_hover}}"><i class="fa fa-pencil"></i> {{$contact.edit}}</a> {{if $contact.approve}} </form> {{/if}} diff --git a/view/tpl/diaspora_vcard.tpl b/view/tpl/diaspora_vcard.tpl deleted file mode 100644 index 017eb555c..000000000 --- a/view/tpl/diaspora_vcard.tpl +++ /dev/null @@ -1,69 +0,0 @@ -<div style="display:none;"> - <dl class="entity_uid"> - <dt>Uid</dt> - <dd> - <span class="uid p-uid">{{$diaspora.guid}}</span> - </dd> - </dl> - <dl class='entity_nickname'> - <dt>Nickname</dt> - <dd> - <span class="nickname p-nickname">{{$diaspora.nickname}}</span> - </dd> - </dl> - <dl class='entity_full_name'> - <dt>Full name</dt> - <dd> - <span class='fn p-name'>{{$diaspora.fullname}}</span> - </dd> - </dl> - - <dl class='entity_first_name'> - <dt>First name</dt> - <dd> - <span class='given_name p-given-name'>{{$diaspora.firstname}}</span> - </dd> - </dl> - <dl class='entity_family_name'> - <dt>Family name</dt> - <dd> - <span class='family_name p-family-name'>{{$diaspora.lastname}}</span> - </dd> - </dl> - <dl class="entity_url"> - <dt>URL</dt> - <dd> - <a href="{{$diaspora.podloc}}/" id="pod_location" class="url" rel="me" >{{$diaspora.podloc}}/</a> - </dd> - </dl> - <dl class="entity_photo"> - <dt>Photo</dt> - <dd> - <img class="photo u-photo avatar" height="300" width="300" src="{{$diaspora.photo300}}" /> - </dd> - </dl> - <dl class="entity_photo_medium"> - <dt>Photo</dt> - <dd> - <img class="photo u-photo avatar" height="100" width="100" src="{{$diaspora.photo100}}" /> - </dd> - </dl> - <dl class="entity_photo_small"> - <dt>Photo</dt> - <dd> - <img class="photo u-photo avatar" height="50" width="50" src="{{$diaspora.photo50}}" /> - </dd> - </dl> - <dl class="entity_searchable"> - <dt>Searchable</dt> - <dd> - <span class="searchable">{{$diaspora.searchable}}</span> - </dd> - </dl> - <dl class="entity_key"> - <dt>Key</dt> - <dd> - <pre class="key">{{$diaspora.pubkey}}</pre> - </dd> - </dl> -</div> diff --git a/view/tpl/install_settings.tpl b/view/tpl/install_settings.tpl index f7a0108a8..62dcbb8b3 100755 --- a/view/tpl/install_settings.tpl +++ b/view/tpl/install_settings.tpl @@ -19,7 +19,6 @@ {{include file="field_input.tpl" field=$adminmail}} {{include file="field_input.tpl" field=$siteurl}} -{{include file="field_select.tpl" field=$server_role}} {{include file="field_select_grouped.tpl" field=$timezone}} diff --git a/view/tpl/nav.tpl b/view/tpl/nav.tpl index f71feafe6..051797658 100755 --- a/view/tpl/nav.tpl +++ b/view/tpl/nav.tpl @@ -83,7 +83,7 @@ </a> <div id="nav-network-menu" class="dropdown-menu" rel="network"> <a class="dropdown-item" id="nav-network-see-all" href="{{$nav.network.all.0}}">{{$nav.network.all.1}}</a> - <a class="dropdown-item" id="nav-network-mark-all"href="#" onclick="markRead('network'); return false;">{{$nav.network.mark.1}}</a> + <a class="dropdown-item" id="nav-network-mark-all" href="#" onclick="markRead('network'); return false;">{{$nav.network.mark.1}}</a> {{$emptynotifications}} </div> </li> diff --git a/view/tpl/profile_vcard.tpl b/view/tpl/profile_vcard.tpl index 9bd534fd8..f51f0719c 100755 --- a/view/tpl/profile_vcard.tpl +++ b/view/tpl/profile_vcard.tpl @@ -43,18 +43,15 @@ </dl> {{/if}} - {{if $gender}}<dl class="mf"><dt class="gender-label">{{$gender}}</dt> <dd class="p-gender">{{$profile.gender}}</dd></dl>{{/if}} + {{if $gender}}<dl class="mf"><dt class="gender-label">{{$gender}}</dt> <dd class="p-gender">{{if $profile.gender_icon}}<i class="fa fa-{{$profile.gender_icon}}"></i> {{/if}}{{$profile.gender}}</dd></dl>{{/if}} {{if $marital}}<dl class="marital"><dt class="marital-label"><span class="heart"><i class="fa fa-heart"></i> </span>{{$marital}}</dt><dd class="marital-text">{{$profile.marital}}</dd></dl>{{/if}} {{if $homepage}}<dl class="homepage"><dt class="homepage-label">{{$homepage}}</dt><dd class="homepage-url u-url">{{$profile.homepage}}</dd></dl>{{/if}} - {{if $diaspora}} - {{include file="diaspora_vcard.tpl"}} - {{/if}} - +<div class="hcard-addon"></div> </div> -<div id="clear"></div> +<div class="clear"></div> {{$rating}} diff --git a/view/tpl/profile_vcard_short.tpl b/view/tpl/profile_vcard_short.tpl index 0984a4e5f..5d87d52c6 100755 --- a/view/tpl/profile_vcard_short.tpl +++ b/view/tpl/profile_vcard_short.tpl @@ -30,10 +30,6 @@ {{if $homepage}}<dl class="homepage"><dt class="homepage-label">{{$homepage}}</dt><dd class="homepage-url">{{$profile.homepage}}</dd></dl>{{/if}} - {{if $diaspora}} - {{include file="diaspora_vcard.tpl"}} - {{/if}} - <div id="clear"></div> {{$chanmenu}} diff --git a/view/tpl/settings.tpl b/view/tpl/settings.tpl index dd5fecb43..6673e5815 100755 --- a/view/tpl/settings.tpl +++ b/view/tpl/settings.tpl @@ -1,6 +1,6 @@ <div class="generic-content-wrapper"> <div class="section-title-wrapper"> - {{if $server_role != 'basic'}}<a title="{{$removechannel}}" class="btn btn-danger btn-sm pull-right" href="removeme"><i class="fa fa-trash-o"></i> {{$removeme}}</a>{{/if}} + <a title="{{$removechannel}}" class="btn btn-danger btn-sm pull-right" href="removeme"><i class="fa fa-trash-o"></i> {{$removeme}}</a> <h2>{{$ptitle}}</h2> <div class="clear"></div> </div> @@ -44,12 +44,9 @@ </div> <div id="privacy-settings-collapse" class="collapse" role="tabpanel" aria-labelledby="privacy-settings"> <div class="section-content-tools-wrapper"> - {{if $server_role != 'basic'}} {{include file="field_select_grouped.tpl" field=$role}} - {{/if}} - <div id="advanced-perm" style="display:{{if $permissions_set && $server_role != 'basic' }}none{{else}}block{{/if}};"> + <div id="advanced-perm" style="display:{{if $permissions_set}}none{{else}}block{{/if}};"> - {{if $server_role != 'basic'}} <div class="form-group"> <button type="button" class="btn btn-outline-secondary" data-toggle="modal" data-target="#apsModal">{{$lbl_p2macro}}</button> </div> @@ -71,7 +68,7 @@ </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div><!-- /.modal --> - {{/if}} + <div id="settings-default-perms" class="form-group" > <button type="button" class="btn btn-outline-secondary" data-toggle="modal" data-target="#aclModal"><i id="jot-perms-icon" class="fa"></i> {{$permissions}}</button> </div> diff --git a/view/tpl/settings_account.tpl b/view/tpl/settings_account.tpl index b7fdfb9a9..dd1d0d0c9 100755 --- a/view/tpl/settings_account.tpl +++ b/view/tpl/settings_account.tpl @@ -12,7 +12,7 @@ {{include file="field_password.tpl" field=$password1}} {{include file="field_password.tpl" field=$password2}} - {{if $z_server_role == 'pro' && ! $techlock}} + {{if ! $techlock}} {{include file="field_select.tpl" field=$techlevel}} {{else}} <input type="hidden" name="techlevel" value="{{$techlevel.2}}" /> diff --git a/view/tpl/xrd_diaspora.tpl b/view/tpl/xrd_diaspora.tpl deleted file mode 100644 index aa0d8c740..000000000 --- a/view/tpl/xrd_diaspora.tpl +++ /dev/null @@ -1,3 +0,0 @@ - <Link rel="http://joindiaspora.com/seed_location" type="text/html" href="{{$baseurl}}/" /> - <Link rel="http://joindiaspora.com/guid" type="text/html" href="{{$dspr_guid}}" /> - <Link rel="diaspora-public-key" type="RSA" href="{{$dspr_key}}" /> diff --git a/view/tpl/xrd_person.tpl b/view/tpl/xrd_person.tpl index 93fdcb1df..52adb54e3 100755 --- a/view/tpl/xrd_person.tpl +++ b/view/tpl/xrd_person.tpl @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"> - <Subject>{{$accturi}}</Subject> + <Subject>{{$subject}}</Subject> {{if $aliases}}{{foreach $aliases as $a}} <Alias>{{$a}}</Alias> {{/foreach}}{{/if}} @@ -22,10 +22,7 @@ href="{{$hcard_url}}" /> <Link rel="http://ostatus.org/schema/1.0/subscribe" template="{{$subscribe}}" /> - - <Link rel="magic-public-key" + <Link rel="magic-public-key" href="{{$modexp}}" /> - {{$dspr}} - </XRD> |