diff --git a/.gitignore b/.gitignore index 4749dea19d..4ae39ed7fa 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,7 @@ nbproject # WebFinger .well-known /.buildpath +3rdparty/autoload.php +3rdparty/composer/ +3rdparty/symfony/ +composer.lock diff --git a/3rdparty/bin/composer b/3rdparty/bin/composer new file mode 100755 index 0000000000..7999bd4ff6 Binary files /dev/null and b/3rdparty/bin/composer differ diff --git a/apps/files/appinfo/routes.php b/apps/files/appinfo/routes.php new file mode 100644 index 0000000000..e1ab560803 --- /dev/null +++ b/apps/files/appinfo/routes.php @@ -0,0 +1,12 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +$this->create('download', 'download{file}') + ->requirements(array('file' => '.*')) + ->actionInclude('files/download.php'); + diff --git a/apps/files/index.php b/apps/files/index.php index a2cf87d027..43a559d034 100644 --- a/apps/files/index.php +++ b/apps/files/index.php @@ -87,11 +87,11 @@ foreach( explode( '/', $dir ) as $i ) { // make breadcrumb und filelist markup $list = new OCP\Template( 'files', 'part.list', '' ); $list->assign( 'files', $files, false ); -$list->assign( 'baseURL', OCP\Util::linkTo('files', 'index.php').'&dir=', false); +$list->assign( 'baseURL', OCP\Util::linkTo('files', 'index.php').'?dir=', false); $list->assign( 'downloadURL', OCP\Util::linkTo('files', 'download.php').'?file=', false); $breadcrumbNav = new OCP\Template( 'files', 'part.breadcrumb', '' ); $breadcrumbNav->assign( 'breadcrumb', $breadcrumb, false ); -$breadcrumbNav->assign( 'baseURL', OCP\Util::linkTo('files', 'index.php').'&dir=', false); +$breadcrumbNav->assign( 'baseURL', OCP\Util::linkTo('files', 'index.php').'?dir=', false); $upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize')); $post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size')); diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js index e184cbfa91..0cf4a05222 100644 --- a/apps/files/js/fileactions.js +++ b/apps/files/js/fileactions.js @@ -185,7 +185,7 @@ FileActions.register('all','Rename', OC.PERMISSION_UPDATE, function(){return OC. }); FileActions.register('dir','Open', OC.PERMISSION_READ, '', function(filename){ - window.location=OC.linkTo('files', 'index.php') + '&dir='+encodeURIComponent($('#dir').val()).replace(/%2F/g, '/')+'/'+encodeURIComponent(filename); + window.location=OC.linkTo('files', 'index.php') + '?dir='+encodeURIComponent($('#dir').val()).replace(/%2F/g, '/')+'/'+encodeURIComponent(filename); }); FileActions.setDefault('dir','Open'); diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 6b49f62266..f08e412921 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -46,7 +46,7 @@ var FileList={ html = $('').attr({ "data-type": "dir", "data-size": size, "data-file": name, "data-permissions": $('#permissions').val()}); td = $('').attr({"class": "filename", "style": 'background-image:url('+OC.imagePath('core', 'filetypes/folder.png')+')' }); td.append(''); - link_elem = $('').attr({ "class": "name", "href": OC.linkTo('files', 'index.php')+"&dir="+ encodeURIComponent($('#dir').val()+'/'+name).replace(/%2F/g, '/') }); + link_elem = $('').attr({ "class": "name", "href": OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent($('#dir').val()+'/'+name).replace(/%2F/g, '/') }); link_elem.append($('').addClass('nametext').text(name)); link_elem.append($('').attr({'class': 'uploadtext', 'currentUploads': 0})); td.append(link_elem); diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php index aa108f9840..d343945149 100644 --- a/apps/user_ldap/lib/access.php +++ b/apps/user_ldap/lib/access.php @@ -25,7 +25,6 @@ namespace OCA\user_ldap\lib; abstract class Access { protected $connection; - //never ever check this var directly, always use getPagedSearchResultState protected $pagedSearchedSuccessful; @@ -512,32 +511,8 @@ abstract class Access { return array(); } - //TODO: lines 516:540 into a function of its own. $pagedSearchOK as return - //check wether paged query should be attempted - $pagedSearchOK = false; - if($this->connection->hasPagedResultSupport && !is_null($limit)) { - $offset = intval($offset); //can be null - //get the cookie from the search for the previous search, required by LDAP - $cookie = $this->getPagedResultCookie($filter, $limit, $offset); - if(empty($cookie) && ($offset > 0)) { - //no cookie known, although the offset is not 0. Maybe cache run out. We need to start all over *sigh* (btw, Dear Reader, did you need LDAP paged searching was designed by MSFT?) - $reOffset = ($offset - $limit) < 0 ? 0 : $offset - $limit; - //a bit recursive, $offset of 0 is the exit - $this->search($filter, $base, $attr, $limit, $reOffset, true); - $cookie = $this->getPagedResultCookie($filter, $limit, $offset); - //still no cookie? obviously, the server does not like us. Let's skip paging efforts. - //TODO: remember this, probably does not change in the next request... - if(empty($cookie)) { - $cookie = null; - } - } - if(!is_null($cookie)) { - $pagedSearchOK = ldap_control_paged_result($link_resource, $limit, false, $cookie); - \OCP\Util::writeLog('user_ldap', 'Ready for a paged search', \OCP\Util::DEBUG); - } else { - \OCP\Util::writeLog('user_ldap', 'No paged search for us, Cpt., Limit '.$limit.' Offset '.$offset, \OCP\Util::DEBUG); - } - } + //check wether paged search should be attempted + $pagedSearchOK = $this->initPagedSearch($filter, $base, $attr, $limit, $offset); $sr = ldap_search($link_resource, $base, $filter, $attr); $findings = ldap_get_entries($link_resource, $sr ); @@ -551,7 +526,7 @@ abstract class Access { return; } //if count is bigger, then the server does not support paged search. Instead, he did a normal search. We set a flag here, so the callee knows how to deal with it. - //TODO: Not used, just make a count on the returned values in the callee + //TODO: Instead, slice findings or selection later if($findings['count'] <= $limit) { $this->pagedSearchedSuccessful = true; } @@ -604,8 +579,15 @@ abstract class Access { } } } -// die(var_dump($selection)); - return $selection; + $findings = $selection; + } + if(!$this->pagedSearchedSuccessful + || ( + !is_null($limit) + || !is_null($offset) + ) + ) { + $findings = array_slice($findings, intval($offset), $limit); } return $findings; } @@ -775,4 +757,47 @@ abstract class Access { return $result; } + + /** + * @brief prepares a paged search, if possible + * @param $filter the LDAP filter for the search + * @param $base the LDAP subtree that shall be searched + * @param $attr optional, when a certain attribute shall be filtered outside + * @param $limit + * @param $offset + * + */ + private function initPagedSearch($filter, $base, $attr, $limit, $offset) { + $pagedSearchOK = false; + if($this->connection->hasPagedResultSupport && !is_null($limit)) { + $offset = intval($offset); //can be null + //get the cookie from the search for the previous search, required by LDAP + $cookie = $this->getPagedResultCookie($filter, $limit, $offset); + if(empty($cookie) && ($offset > 0)) { + //no cookie known, although the offset is not 0. Maybe cache run out. We need to start all over *sigh* (btw, Dear Reader, did you need LDAP paged searching was designed by MSFT?) + $reOffset = ($offset - $limit) < 0 ? 0 : $offset - $limit; + //a bit recursive, $offset of 0 is the exit + \OCP\Util::writeLog('user_ldap', 'Looking for cookie L/O '.$limit.'/'.$reOffset, \OCP\Util::INFO); + $this->search($filter, $base, $attr, $limit, $reOffset, true); + $cookie = $this->getPagedResultCookie($filter, $limit, $offset); + //still no cookie? obviously, the server does not like us. Let's skip paging efforts. + //TODO: remember this, probably does not change in the next request... + if(empty($cookie)) { + $cookie = null; + } + } + if(!is_null($cookie)) { + if($offset > 0) { + \OCP\Util::writeLog('user_ldap', 'Cookie '.$cookie, \OCP\Util::INFO); + } + $pagedSearchOK = ldap_control_paged_result($this->connection->getConnectionResource(), $limit, false, $cookie); + \OCP\Util::writeLog('user_ldap', 'Ready for a paged search', \OCP\Util::INFO); + } else { + \OCP\Util::writeLog('user_ldap', 'No paged search for us, Cpt., Limit '.$limit.' Offset '.$offset, \OCP\Util::INFO); + } + } + + return $pagedSearchOK; + } + } \ No newline at end of file diff --git a/apps/user_ldap/user_ldap.php b/apps/user_ldap/user_ldap.php index e95bd24fbd..916d3f1d46 100644 --- a/apps/user_ldap/user_ldap.php +++ b/apps/user_ldap/user_ldap.php @@ -119,20 +119,11 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface { $this->connection->ldapGroupDisplayName.'='.$search )); - \OCP\Util::writeLog('user_ldap', 'getUsers: Get users filter '.$filter, \OCP\Util::DEBUG); + \OCP\Util::writeLog('user_ldap', 'getUsers: Options: search '.$search.' limit '.$limit.' offset '.$offset.' Filter: '.$filter, \OCP\Util::DEBUG); //do the search and translate results to owncloud names $ldap_users = $this->fetchListOfUsers($filter, array($this->connection->ldapUserDisplayName, 'dn'), $limit, $offset); $ldap_users = $this->ownCloudUserNames($ldap_users); - - if(!$this->getPagedSearchResultState()) { - \OCP\Util::writeLog('user_ldap', 'getUsers: We got old-style results', \OCP\Util::DEBUG); - //if not supported, a 'normal' search has run automatically, we just need to get our slice of the cake. And we cache the general search, too - $this->connection->writeToCache('getUsers-'.$search, $ldap_users); - $ldap_users = array_slice($ldap_users, $offset, $limit); - } else { - //debug message only - \OCP\Util::writeLog('user_ldap', 'getUsers: We got paged results', \OCP\Util::DEBUG); - } + \OCP\Util::writeLog('user_ldap', 'getUsers: '.count($ldap_users). ' Users found', \OCP\Util::DEBUG); $this->connection->writeToCache($cachekey, $ldap_users); return $ldap_users; diff --git a/autotest.sh b/autotest.sh index 56296c6a51..744bcdbe8f 100755 --- a/autotest.sh +++ b/autotest.sh @@ -9,7 +9,7 @@ DATADIR=data-autotest BASEDIR=$PWD -# create autoconfig for sqlite, mysql and (soon) postgresql +# create autoconfig for sqlite, mysql and postgresql cat > ./tests/autoconfig-sqlite.php <=5.3.2", + "symfony/routing": "2.0.*" + }, + "config": { + "vendor-dir": "3rdparty" + } +} diff --git a/core/ajax/appconfig.php b/core/ajax/appconfig.php index 1b43afa74f..4f26dedc79 100644 --- a/core/ajax/appconfig.php +++ b/core/ajax/appconfig.php @@ -5,7 +5,6 @@ * See the COPYING-README file. */ -require_once "../../lib/base.php"; OC_Util::checkAdminUser(); OCP\JSON::callCheck(); diff --git a/core/ajax/requesttoken.php b/core/ajax/requesttoken.php index 705330b2c3..9d43a72285 100644 --- a/core/ajax/requesttoken.php +++ b/core/ajax/requesttoken.php @@ -26,7 +26,6 @@ * @return json: success/error state indicator including a fresh request token * @author Christian Reiner */ -require_once '../../lib/base.php'; // don't load apps or filesystem for this task $RUNTIME_NOAPPS = true; diff --git a/core/ajax/share.php b/core/ajax/share.php index 84e84be5ac..0fa162fb37 100644 --- a/core/ajax/share.php +++ b/core/ajax/share.php @@ -18,7 +18,6 @@ * You should have received a copy of the GNU Affero General Public * License along with this library. If not, see . */ -require_once '../../lib/base.php'; OC_JSON::checkLoggedIn(); OCP\JSON::callCheck(); diff --git a/core/ajax/translations.php b/core/ajax/translations.php index 75679da2c0..e22cbad470 100644 --- a/core/ajax/translations.php +++ b/core/ajax/translations.php @@ -21,9 +21,6 @@ * */ -// Init owncloud -require_once '../../lib/base.php'; - $app = $_POST["app"]; $l = OC_L10N::get( $app ); diff --git a/core/ajax/vcategories/add.php b/core/ajax/vcategories/add.php index 81fa06dbf1..8d31275dbf 100644 --- a/core/ajax/vcategories/add.php +++ b/core/ajax/vcategories/add.php @@ -14,7 +14,6 @@ function debug($msg) { OC_Log::write('core', 'ajax/vcategories/add.php: '.$msg, OC_Log::DEBUG); } -require_once '../../../lib/base.php'; OC_JSON::checkLoggedIn(); $category = isset($_GET['category'])?strip_tags($_GET['category']):null; $app = isset($_GET['app'])?$_GET['app']:null; diff --git a/core/ajax/vcategories/delete.php b/core/ajax/vcategories/delete.php index cd46a25b79..74b0220870 100644 --- a/core/ajax/vcategories/delete.php +++ b/core/ajax/vcategories/delete.php @@ -15,7 +15,6 @@ function debug($msg) { OC_Log::write('core', 'ajax/vcategories/delete.php: '.$msg, OC_Log::DEBUG); } -require_once '../../../lib/base.php'; OC_JSON::checkLoggedIn(); $app = isset($_POST['app'])?$_POST['app']:null; $categories = isset($_POST['categories'])?$_POST['categories']:null; diff --git a/core/ajax/vcategories/edit.php b/core/ajax/vcategories/edit.php index a0e67841c5..caeebcaa94 100644 --- a/core/ajax/vcategories/edit.php +++ b/core/ajax/vcategories/edit.php @@ -15,7 +15,6 @@ function debug($msg) { OC_Log::write('core', 'ajax/vcategories/edit.php: '.$msg, OC_Log::DEBUG); } -require_once '../../../lib/base.php'; OC_JSON::checkLoggedIn(); $app = isset($_GET['app'])?$_GET['app']:null; diff --git a/core/js/js.js b/core/js/js.js index c5e32f3c27..130d413296 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -95,9 +95,9 @@ var OC={ var isCore=OC.coreApps.indexOf(app)!==-1, link=OC.webroot; if((file.substring(file.length-3) === 'php' || file.substring(file.length-3) === 'css') && !isCore){ - link+='/?app=' + app; + link+='/index.php/apps/' + app; if (file != 'index.php') { - link+='&getfile='; + link+='/'; if(type){ link+=encodeURI(type + '/'); } @@ -113,7 +113,12 @@ var OC={ } link+=file; }else{ - link+='/'; + if ((app == 'settings' || app == 'core') && type == 'ajax') { + link+='/index.php/'; + } + else { + link+='/'; + } if(!isCore){ link+='apps/'; } diff --git a/core/js/router.js b/core/js/router.js new file mode 100644 index 0000000000..8b66f5a05c --- /dev/null +++ b/core/js/router.js @@ -0,0 +1,73 @@ +OC.router_base_url = OC.webroot + '/index.php/', +OC.Router = { + routes_request: $.ajax(OC.router_base_url + 'core/routes.json', { + dataType: 'json', + success: function(jsondata) { + if (jsondata.status == 'success') { + OC.Router.routes = jsondata.data; + } + } + }), + generate:function(name, opt_params) { + if (!('routes' in this)) { + if(this.routes_request.state() != 'resolved') { + alert('wait');// wait + } + } + if (!(name in this.routes)) { + throw new Error('The route "' + name + '" does not exist.'); + } + var route = this.routes[name]; + var params = opt_params || {}; + var unusedParams = $.extend(true, {}, params); + var url = ''; + var optional = true; + $(route.tokens).each(function(i, token) { + if ('text' === token[0]) { + url = token[1] + url; + optional = false; + + return; + } + + if ('variable' === token[0]) { + if (false === optional || !(token[3] in route.defaults) + || ((token[3] in params) && params[token[3]] != route.defaults[token[3]])) { + var value; + if (token[3] in params) { + value = params[token[3]]; + delete unusedParams[token[3]]; + } else if (token[3] in route.defaults) { + value = route.defaults[token[3]]; + } else if (optional) { + return; + } else { + throw new Error('The route "' + name + '" requires the parameter "' + token[3] + '".'); + } + + var empty = true === value || false === value || '' === value; + + if (!empty || !optional) { + url = token[1] + encodeURIComponent(value).replace(/%2F/g, '/') + url; + } + + optional = false; + } + + return; + } + + throw new Error('The token type "' + token[0] + '" is not supported.'); + }); + if (url === '') { + url = '/'; + } + + unusedParams = $.param(unusedParams); + if (unusedParams.length > 0) { + url += '?'+unusedParams; + } + + return OC.router_base_url + url; + } +}; diff --git a/core/lostpassword/controller.php b/core/lostpassword/controller.php new file mode 100644 index 0000000000..e616fe7dff --- /dev/null +++ b/core/lostpassword/controller.php @@ -0,0 +1,83 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_Core_LostPassword_Controller { + protected static function displayLostPasswordPage($error, $requested) { + OC_Template::printGuestPage('core/lostpassword', 'lostpassword', array('error' => $error, 'requested' => $requested)); + } + + protected static function displayResetPasswordPage($success, $args) { + $route_args = array(); + $route_args['token'] = $args['token']; + $route_args['user'] = $args['user']; + OC_Template::printGuestPage('core/lostpassword', 'resetpassword', array('success' => $success, 'args' => $route_args)); + } + + protected static function checkToken($user, $token) { + return OC_Preferences::getValue($user, 'owncloud', 'lostpassword') === hash('sha256', $token); + } + + public static function index($args) { + self::displayLostPasswordPage(false, false); + } + + public static function sendEmail($args) { + if (OC_User::userExists($_POST['user'])) { + $token = hash('sha256', OC_Util::generate_random_bytes(30).OC_Config::getValue('passwordsalt', '')); + OC_Preferences::setValue($_POST['user'], 'owncloud', 'lostpassword', hash('sha256', $token)); // Hash the token again to prevent timing attacks + $email = OC_Preferences::getValue($_POST['user'], 'settings', 'email', ''); + if (!empty($email)) { + $link = OC_Helper::linkToRoute('core_lostpassword_reset', array('user' => $_POST['user'], 'token' => $token)); + $link = OC_Helper::makeURLAbsolute($link); + + $tmpl = new OC_Template('core/lostpassword', 'email'); + $tmpl->assign('link', $link, false); + $msg = $tmpl->fetchPage(); + $l = OC_L10N::get('core'); + $from = 'lostpassword-noreply@' . OCP\Util::getServerHost(); + OC_Mail::send($email, $_POST['user'], $l->t('ownCloud password reset'), $msg, $from, 'ownCloud'); + echo('Mailsent'); + + self::displayLostPasswordPage(false, true); + } else { + self::displayLostPasswordPage(true, false); + } + } else { + self::displayLostPasswordPage(true, false); + } + } + + public static function reset($args) { + // Someone wants to reset their password: + if(self::checkToken($args['user'], $args['token'])) { + self::displayResetPasswordPage(false, $args); + } else { + // Someone lost their password + self::displayLostPasswordPage(false, false); + } + } + + public static function resetPassword($args) { + if (self::checkToken($args['user'], $args['token'])) { + if (isset($_POST['password'])) { + if (OC_User::setPassword($args['user'], $_POST['password'])) { + OC_Preferences::deleteKey($args['user'], 'owncloud', 'lostpassword'); + OC_User::unsetMagicInCookie(); + self::displayResetPasswordPage(true, $args); + } else { + self::displayResetPasswordPage(false, $args); + } + } else { + self::reset($args); + } + } else { + // Someone lost their password + self::displayLostPasswordPage(false, false); + } + } +} diff --git a/core/lostpassword/index.php b/core/lostpassword/index.php deleted file mode 100644 index 1da5bce8ea..0000000000 --- a/core/lostpassword/index.php +++ /dev/null @@ -1,35 +0,0 @@ - $_POST['user'], 'token' => $token)); - $tmpl = new OC_Template('core/lostpassword', 'email'); - $tmpl->assign('link', $link, false); - $msg = $tmpl->fetchPage(); - $l = OC_L10N::get('core'); - $from = 'lostpassword-noreply@' . OCP\Util::getServerHost(); - OC_MAIL::send($email, $_POST['user'], $l->t('ownCloud password reset'), $msg, $from, 'ownCloud'); - echo('sent'); - } - OC_Template::printGuestPage('core/lostpassword', 'lostpassword', array('error' => false, 'requested' => true)); - } else { - OC_Template::printGuestPage('core/lostpassword', 'lostpassword', array('error' => true, 'requested' => false)); - } -} else { - OC_Template::printGuestPage('core/lostpassword', 'lostpassword', array('error' => false, 'requested' => false)); -} diff --git a/core/lostpassword/resetpassword.php b/core/lostpassword/resetpassword.php deleted file mode 100644 index 7cd383921d..0000000000 --- a/core/lostpassword/resetpassword.php +++ /dev/null @@ -1,27 +0,0 @@ - true)); - } else { - OC_Template::printGuestPage('core/lostpassword', 'resetpassword', array('success' => false)); - } - } else { - OC_Template::printGuestPage('core/lostpassword', 'resetpassword', array('success' => false)); - } -} else { - // Someone lost their password - OC_Template::printGuestPage('core/lostpassword', 'lostpassword', array('error' => false, 'requested' => false)); -} diff --git a/core/lostpassword/templates/lostpassword.php b/core/lostpassword/templates/lostpassword.php index 4b871963b8..55c070f3e0 100644 --- a/core/lostpassword/templates/lostpassword.php +++ b/core/lostpassword/templates/lostpassword.php @@ -1,11 +1,11 @@ -
+
t('You will receive a link to reset your password via Email.'); ?> - t('Requested'); ?> + t('Reset email send.'); ?> - t('Login failed!'); ?> + t('Request failed!'); ?>

diff --git a/core/lostpassword/templates/resetpassword.php b/core/lostpassword/templates/resetpassword.php index 56257de7f1..0ab32acca6 100644 --- a/core/lostpassword/templates/resetpassword.php +++ b/core/lostpassword/templates/resetpassword.php @@ -1,8 +1,8 @@ - +

t('Your password was reset'); ?>

-

t('To login page'); ?>

+

t('To login page'); ?>

diff --git a/core/routes.php b/core/routes.php new file mode 100644 index 0000000000..7cf2749884 --- /dev/null +++ b/core/routes.php @@ -0,0 +1,60 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +require_once('settings/routes.php'); + +// Core ajax actions +// AppConfig +$this->create('core_ajax_appconfig', '/core/ajax/appconfig.php') + ->actionInclude('core/ajax/appconfig.php'); +// RequestToken +$this->create('core_ajax_requesttoken', '/core/ajax/requesttoken.php') + ->actionInclude('core/ajax/requesttoken.php'); +// Share +$this->create('core_ajax_share', '/core/ajax/share.php') + ->actionInclude('core/ajax/share.php'); +// Translations +$this->create('core_ajax_translations', '/core/ajax/translations.php') + ->actionInclude('core/ajax/translations.php'); +// VCategories +$this->create('core_ajax_vcategories_add', '/core/ajax/vcategories/add.php') + ->actionInclude('core/ajax/vcategories/add.php'); +$this->create('core_ajax_vcategories_delete', '/core/ajax/vcategories/delete.php') + ->actionInclude('core/ajax/vcategories/delete.php'); +$this->create('core_ajax_vcategories_edit', '/core/ajax/vcategories/edit.php') + ->actionInclude('core/ajax/vcategories/edit.php'); +// Routing +$this->create('core_ajax_routes', '/core/routes.json') + ->action('OC_Router', 'JSRoutes'); + +OC::$CLASSPATH['OC_Core_LostPassword_Controller'] = 'core/lostpassword/controller.php'; +$this->create('core_lostpassword_index', '/lostpassword/') + ->get() + ->action('OC_Core_LostPassword_Controller', 'index'); +$this->create('core_lostpassword_send_email', '/lostpassword/') + ->post() + ->action('OC_Core_LostPassword_Controller', 'sendEmail'); +$this->create('core_lostpassword_reset', '/lostpassword/reset/{token}/{user}') + ->get() + ->action('OC_Core_LostPassword_Controller', 'reset'); +$this->create('core_lostpassword_reset_password', '/lostpassword/reset/{token}/{user}') + ->post() + ->action('OC_Core_LostPassword_Controller', 'resetPassword'); + +// Not specifically routed +$this->create('app_css', '/apps/{app}/{file}') + ->requirements(array('file' => '.*.css')) + ->action('OC', 'loadCSSFile'); +$this->create('app_index_script', '/apps/{app}/') + ->defaults(array('file' => 'index.php')) + //->requirements(array('file' => '.*.php')) + ->action('OC', 'loadAppScriptFile'); +$this->create('app_script', '/apps/{app}/{file}') + ->defaults(array('file' => 'index.php')) + ->requirements(array('file' => '.*.php')) + ->action('OC', 'loadAppScriptFile'); diff --git a/cron.php b/cron.php index f13b284b81..fb76c2de42 100644 --- a/cron.php +++ b/cron.php @@ -23,9 +23,18 @@ // Unfortunately we need this class for shutdown function class my_temporary_cron_class { public static $sent = false; + public static $lockfile = ""; + public static $keeplock = false; } +// We use this function to handle (unexpected) shutdowns function handleUnexpectedShutdown() { + // Delete lockfile + if( !my_temporary_cron_class::$keeplock && file_exists( my_temporary_cron_class::$lockfile )){ + unlink( my_temporary_cron_class::$lockfile ); + } + + // Say goodbye if the app did not shutdown properly if( !my_temporary_cron_class::$sent ) { if( OC::$CLI ) { echo 'Unexpected error!'.PHP_EOL; @@ -48,7 +57,7 @@ if( !OC_Config::getValue( 'installed', false )) { register_shutdown_function('handleUnexpectedShutdown'); // Exit if background jobs are disabled! -$appmode = OC_Appconfig::getValue( 'core', 'backgroundjobs_mode', 'ajax' ); +$appmode = OC_BackgroundJob::getExecutionType(); if( $appmode == 'none' ) { my_temporary_cron_class::$sent = true; if( OC::$CLI ) { @@ -61,29 +70,42 @@ if( $appmode == 'none' ) { } if( OC::$CLI ) { + // Create lock file first + my_temporary_cron_class::$lockfile = OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' ).'/cron.lock'; + + // We call ownCloud from the CLI (aka cron) if( $appmode != 'cron' ) { - OC_Appconfig::setValue( 'core', 'backgroundjobs_mode', 'cron' ); + // Use cron in feature! + OC_BackgroundJob::setExecutionType('cron' ); } // check if backgroundjobs is still running - $pid = OC_Appconfig::getValue( 'core', 'backgroundjobs_pid', false ); - if( $pid !== false ) { - // FIXME: check if $pid is still alive (*nix/mswin). if so then exit + if( file_exists( my_temporary_cron_class::$lockfile )){ + my_temporary_cron_class::$keeplock = true; + my_temporary_cron_class::$sent = true; + echo "Another instance of cron.php is still running!"; + exit( 1 ); } - // save pid - OC_Appconfig::setValue( 'core', 'backgroundjobs_pid', getmypid()); + + // Create a lock file + touch( my_temporary_cron_class::$lockfile ); // Work OC_BackgroundJob_Worker::doAllSteps(); } else{ + // We call cron.php from some website if( $appmode == 'cron' ) { + // Cron is cron :-P OC_JSON::error( array( 'data' => array( 'message' => 'Backgroundjobs are using system cron!'))); } else{ + // Work and success :-) OC_BackgroundJob_Worker::doNextStep(); OC_JSON::success(); } } + +// done! my_temporary_cron_class::$sent = true; exit(); diff --git a/lib/app.php b/lib/app.php index 8f5b5fe78f..b05d841e63 100755 --- a/lib/app.php +++ b/lib/app.php @@ -282,33 +282,33 @@ class OC_App{ // by default, settings only contain the help menu if(OC_Config::getValue('knowledgebaseenabled', true)==true) { $settings = array( - array( "id" => "help", "order" => 1000, "href" => OC_Helper::linkTo( "settings", "help.php" ), "name" => $l->t("Help"), "icon" => OC_Helper::imagePath( "settings", "help.svg" )) + array( "id" => "help", "order" => 1000, "href" => OC_Helper::linkToRoute( "settings_help" ), "name" => $l->t("Help"), "icon" => OC_Helper::imagePath( "settings", "help.svg" )) ); } // if the user is logged-in if (OC_User::isLoggedIn()) { // personal menu - $settings[] = array( "id" => "personal", "order" => 1, "href" => OC_Helper::linkTo( "settings", "personal.php" ), "name" => $l->t("Personal"), "icon" => OC_Helper::imagePath( "settings", "personal.svg" )); + $settings[] = array( "id" => "personal", "order" => 1, "href" => OC_Helper::linkToRoute( "settings_personal" ), "name" => $l->t("Personal"), "icon" => OC_Helper::imagePath( "settings", "personal.svg" )); // if there are some settings forms if(!empty(self::$settingsForms)) // settings menu - $settings[]=array( "id" => "settings", "order" => 1000, "href" => OC_Helper::linkTo( "settings", "settings.php" ), "name" => $l->t("Settings"), "icon" => OC_Helper::imagePath( "settings", "settings.svg" )); + $settings[]=array( "id" => "settings", "order" => 1000, "href" => OC_Helper::linkToRoute( "settings_settings" ), "name" => $l->t("Settings"), "icon" => OC_Helper::imagePath( "settings", "settings.svg" )); //SubAdmins are also allowed to access user management if(OC_SubAdmin::isSubAdmin($_SESSION["user_id"]) || OC_Group::inGroup( $_SESSION["user_id"], "admin" )) { // admin users menu - $settings[] = array( "id" => "core_users", "order" => 2, "href" => OC_Helper::linkTo( "settings", "users.php" ), "name" => $l->t("Users"), "icon" => OC_Helper::imagePath( "settings", "users.svg" )); + $settings[] = array( "id" => "core_users", "order" => 2, "href" => OC_Helper::linkToRoute( "settings_users" ), "name" => $l->t("Users"), "icon" => OC_Helper::imagePath( "settings", "users.svg" )); } // if the user is an admin if(OC_Group::inGroup( $_SESSION["user_id"], "admin" )) { // admin apps menu - $settings[] = array( "id" => "core_apps", "order" => 3, "href" => OC_Helper::linkTo( "settings", "apps.php" ).'?installed', "name" => $l->t("Apps"), "icon" => OC_Helper::imagePath( "settings", "apps.svg" )); + $settings[] = array( "id" => "core_apps", "order" => 3, "href" => OC_Helper::linkToRoute( "settings_apps" ).'?installed', "name" => $l->t("Apps"), "icon" => OC_Helper::imagePath( "settings", "apps.svg" )); - $settings[]=array( "id" => "admin", "order" => 1000, "href" => OC_Helper::linkTo( "settings", "admin.php" ), "name" => $l->t("Admin"), "icon" => OC_Helper::imagePath( "settings", "admin.svg" )); + $settings[]=array( "id" => "admin", "order" => 1000, "href" => OC_Helper::linkToRoute( "settings_admin" ), "name" => $l->t("Admin"), "icon" => OC_Helper::imagePath( "settings", "admin.svg" )); } } @@ -484,6 +484,12 @@ class OC_App{ public static function getCurrentApp() { $script=substr($_SERVER["SCRIPT_NAME"], strlen(OC::$WEBROOT)+1); $topFolder=substr($script, 0, strpos($script, '/')); + if (empty($topFolder)) { + $path_info = OC_Request::getPathInfo(); + if ($path_info) { + $topFolder=substr($path_info, 1, strpos($path_info, '/', 1)-1); + } + } if($topFolder=='apps') { $length=strlen($topFolder); return substr($script, $length+1, strpos($script, '/', $length+1)-$length-1); diff --git a/lib/backgroundjob.php b/lib/backgroundjob.php new file mode 100644 index 0000000000..6415f5b84a --- /dev/null +++ b/lib/backgroundjob.php @@ -0,0 +1,52 @@ +. +* +*/ + +/** + * This class does the dirty work. + */ +class OC_BackgroundJob{ + /** + * @brief get the execution type of background jobs + * @return string + * + * This method returns the type how background jobs are executed. If the user + * did not select something, the type is ajax. + */ + public static function getExecutionType() { + return OC_Appconfig::getValue( 'core', 'backgroundjobs_mode', 'ajax' ); + } + + /** + * @brief sets the background jobs execution type + * @param $type execution type + * @return boolean + * + * This method sets the execution type of the background jobs. Possible types + * are "none", "ajax", "webcron", "cron" + */ + public static function setExecutionType( $type ) { + if( !in_array( $type, array('none', 'ajax', 'webcron', 'cron'))){ + return false; + } + return OC_Appconfig::setValue( 'core', 'backgroundjobs_mode', $type ); + } +} diff --git a/lib/base.php b/lib/base.php index 778f0fe732..365a257f6f 100644 --- a/lib/base.php +++ b/lib/base.php @@ -67,6 +67,10 @@ class OC{ * check if owncloud runs in cli mode */ public static $CLI = false; + /* + * OC router + */ + protected static $router = null; /** * SPL autoload */ @@ -96,6 +100,9 @@ class OC{ elseif(strpos($className, 'Sabre_')===0) { $path = str_replace('_', '/', $className) . '.php'; } + elseif(strpos($className, 'Symfony\\Component\\Routing\\')===0) { + $path = 'symfony/routing/'.str_replace('\\', '/', $className) . '.php'; + } elseif(strpos($className, 'Test_')===0) { $path = 'tests/lib/'.strtolower(str_replace('_', '/', substr($className, 5)) . '.php'); } @@ -256,6 +263,7 @@ class OC{ OC_Util::addScript( "config" ); //OC_Util::addScript( "multiselect" ); OC_Util::addScript('search', 'result'); + OC_Util::addScript('router'); if( OC_Config::getValue( 'installed', false )) { if( OC_Appconfig::getValue( 'core', 'backgroundjobs_mode', 'ajax' ) == 'ajax' ) { @@ -296,6 +304,15 @@ class OC{ $_SESSION['LAST_ACTIVITY'] = time(); } + public static function getRouter() { + if (!isset(OC::$router)) { + OC::$router = new OC_Router(); + OC::$router->loadRoutes(); + } + + return OC::$router; + } + public static function init() { // register autoloader spl_autoload_register(array('OC','autoload')); @@ -471,9 +488,21 @@ class OC{ header('location: '.OC_Helper::linkToRemote('webdav')); return; } + try { + OC::getRouter()->match(OC_Request::getPathInfo()); + return; + } catch (Symfony\Component\Routing\Exception\ResourceNotFoundException $e) { + //header('HTTP/1.0 404 Not Found'); + } catch (Symfony\Component\Routing\Exception\MethodNotAllowedException $e) { + OC_Response::setStatus(405); + return; + } + $app = OC::$REQUESTEDAPP; + $file = OC::$REQUESTEDFILE; + $param = array('app' => $app, 'file' => $file); // Handle app css files - if(substr(OC::$REQUESTEDFILE, -3) == 'css') { - self::loadCSSFile(); + if(substr($file, -3) == 'css') { + self::loadCSSFile($param); return; } // Someone is logged in : @@ -485,13 +514,12 @@ class OC{ OC_User::logout(); header("Location: ".OC::$WEBROOT.'/'); }else{ - $app = OC::$REQUESTEDAPP; - $file = OC::$REQUESTEDFILE; if(is_null($file)) { - $file = 'index.php'; + $param['file'] = 'index.php'; } - $file_ext = substr($file, -3); - if ($file_ext != 'php'|| !self::loadAppScriptFile($app, $file)) { + $file_ext = substr($param['file'], -3); + if ($file_ext != 'php' + || !self::loadAppScriptFile($param)) { header('HTTP/1.0 404 Not Found'); } } @@ -501,7 +529,10 @@ class OC{ self::handleLogin(); } - protected static function loadAppScriptFile($app, $file) { + public static function loadAppScriptFile($param) { + OC_App::loadApps(); + $app = $param['app']; + $file = $param['file']; $app_path = OC_App::getAppPath($app); $file = $app_path . '/' . $file; unset($app, $app_path); @@ -512,9 +543,9 @@ class OC{ return false; } - protected static function loadCSSFile() { - $app = OC::$REQUESTEDAPP; - $file = OC::$REQUESTEDFILE; + public static function loadCSSFile($param) { + $app = $param['app']; + $file = $param['file']; $app_path = OC_App::getAppPath($app); if (file_exists($app_path . '/' . $file)) { $app_web_path = OC_App::getAppWebPath($app); diff --git a/lib/helper.php b/lib/helper.php index aa453ad750..6f7ada39c1 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -28,6 +28,20 @@ class OC_Helper { private static $mimetypes=array(); private static $tmpFiles=array(); + /** + * @brief Creates an url using a defined route + * @param $route + * @param $parameters + * @param $args array with param=>value, will be appended to the returned url + * @returns the url + * + * Returns a url to the given app and file. + */ + public static function linkToRoute( $route, $parameters = array() ) { + $urlLinkTo = OC::getRouter()->generate($route, $parameters); + return $urlLinkTo; + } + /** * @brief Creates an url * @param string $app app @@ -44,8 +58,8 @@ class OC_Helper { // Check if the app is in the app folder if( $app_path && file_exists( $app_path.'/'.$file )) { if(substr($file, -3) == 'php' || substr($file, -3) == 'css') { - $urlLinkTo = OC::$WEBROOT . '/?app=' . $app; - $urlLinkTo .= ($file!='index.php')?'&getfile=' . urlencode($file):''; + $urlLinkTo = OC::$WEBROOT . '/index.php/apps/' . $app; + $urlLinkTo .= ($file!='index.php') ? '/' . $file : ''; }else{ $urlLinkTo = OC_App::getAppWebPath($app) . '/' . $file; } diff --git a/lib/ocs.php b/lib/ocs.php index c6bcd2c06e..0bcbee4e45 100644 --- a/lib/ocs.php +++ b/lib/ocs.php @@ -23,7 +23,8 @@ * */ - +use Symfony\Component\Routing\Exception\ResourceNotFoundException; +use Symfony\Component\Routing\Exception\MethodNotAllowedException; /** * Class to handle open collaboration services API requests @@ -92,91 +93,144 @@ class OC_OCS { exit(); } - // preprocess url - $url = strtolower($_SERVER['REQUEST_URI']); - if(substr($url, (strlen($url)-1))<>'/') $url.='/'; - $ex=explode('/', $url); - $paracount=count($ex); $format = self::readData($method, 'format', 'text', ''); - // eventhandler + $router = new OC_Router(); + $router->useCollection('root'); // CONFIG - // apiconfig - GET - CONFIG - if(($method=='get') and ($ex[$paracount-3] == 'v1.php') and ($ex[$paracount-2] == 'config')) { - OC_OCS::apiconfig($format); + $router->create('config', '/config.{format}') + ->defaults(array('format' => $format)) + ->action('OC_OCS', 'apiConfig') + ->requirements(array('format'=>'xml|json')); // PERSON - // personcheck - POST - PERSON/CHECK - } elseif(($method=='post') and ($ex[$paracount-4] == 'v1.php') and ($ex[$paracount-3]=='person') and ($ex[$paracount-2] == 'check')) { - $login = self::readData($method, 'login', 'text'); - $passwd = self::readData($method, 'password', 'text'); - OC_OCS::personcheck($format, $login, $passwd); + $router->create('person_check', '/person/check.{format}') + ->post() + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $login = OC_OCS::readData('post', 'login', 'text'); + $passwd = OC_OCS::readData('post', 'password', 'text'); + OC_OCS::personCheck($format,$login,$passwd); + }) + ->requirements(array('format'=>'xml|json')); // ACTIVITY // activityget - GET ACTIVITY page,pagesize als urlparameter - }elseif(($method=='get') and ($ex[$paracount-3] == 'v1.php') and ($ex[$paracount-2] == 'activity')) { - $page = self::readData($method, 'page', 'int', 0); - $pagesize = self::readData($method, 'pagesize', 'int', 10); - if($pagesize<1 or $pagesize>100) $pagesize=10; - OC_OCS::activityget($format, $page, $pagesize); - + $router->create('activity_get', '/activity.{format}') + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $page = OC_OCS::readData('get', 'page', 'int', 0); + $pagesize = OC_OCS::readData('get', 'pagesize', 'int', 10); + if($pagesize<1 or $pagesize>100) $pagesize=10; + OC_OCS::activityGet($format, $page, $pagesize); + }) + ->requirements(array('format'=>'xml|json')); // activityput - POST ACTIVITY - }elseif(($method=='post') and ($ex[$paracount-3] == 'v1.php') and ($ex[$paracount-2] == 'activity')) { - $message = self::readData($method, 'message', 'text'); - OC_OCS::activityput($format, $message); - + $router->create('activity_put', '/activity.{format}') + ->post() + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $message = OC_OCS::readData('post', 'message', 'text'); + OC_OCS::activityPut($format,$message); + }) + ->requirements(array('format'=>'xml|json')); // PRIVATEDATA // get - GET DATA - }elseif(($method=='get') and ($ex[$paracount-4] == 'v1.php') and ($ex[$paracount-2] == 'getattribute')) { - OC_OCS::privateDataGet($format); - - }elseif(($method=='get') and ($ex[$paracount-5] == 'v1.php') and ($ex[$paracount-3] == 'getattribute')) { - $app=$ex[$paracount-2]; - OC_OCS::privateDataGet($format, $app); - }elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-4] == 'getattribute')) { - - $key=$ex[$paracount-2]; - $app=$ex[$paracount-3]; - OC_OCS::privateDataGet($format, $app, $key); - + $router->create('privatedata_get', + '/privatedata/getattribute/{app}/{key}.{format}') + ->defaults(array('app' => '', 'key' => '', 'format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $app = addslashes(strip_tags($parameters['app'])); + $key = addslashes(strip_tags($parameters['key'])); + OC_OCS::privateDataGet($format, $app, $key); + }) + ->requirements(array('format'=>'xml|json')); // set - POST DATA - }elseif(($method=='post') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-4] == 'setattribute')) { - $key=$ex[$paracount-2]; - $app=$ex[$paracount-3]; - $value = self::readData($method, 'value', 'text'); - OC_OCS::privatedataset($format, $app, $key, $value); + $router->create('privatedata_set', + '/privatedata/setattribute/{app}/{key}.{format}') + ->post() + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $app = addslashes(strip_tags($parameters['app'])); + $key = addslashes(strip_tags($parameters['key'])); + $value=OC_OCS::readData('post', 'value', 'text'); + OC_OCS::privateDataSet($format, $app, $key, $value); + }) + ->requirements(array('format'=>'xml|json')); // delete - POST DATA - }elseif(($method=='post') and ($ex[$paracount-6] =='v1.php') and ($ex[$paracount-4] == 'deleteattribute')) { - $key=$ex[$paracount-2]; - $app=$ex[$paracount-3]; - OC_OCS::privatedatadelete($format, $app, $key); + $router->create('privatedata_delete', + '/privatedata/deleteattribute/{app}/{key}.{format}') + ->post() + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $app = addslashes(strip_tags($parameters['app'])); + $key = addslashes(strip_tags($parameters['key'])); + OC_OCS::privateDataDelete($format, $app, $key); + }) + ->requirements(array('format'=>'xml|json')); // CLOUD // systemWebApps - }elseif(($method=='get') and ($ex[$paracount-5] == 'v1.php') and ($ex[$paracount-4]=='cloud') and ($ex[$paracount-3] == 'system') and ($ex[$paracount-2] == 'webapps')) { - OC_OCS::systemwebapps($format); + $router->create('system_webapps', + '/cloud/system/webapps.{format}') + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + OC_OCS::systemwebapps($format); + }) + ->requirements(array('format'=>'xml|json')); // quotaget - }elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'quota')) { - $user=$ex[$paracount-3]; - OC_OCS::quotaget($format, $user); - + $router->create('quota_get', + '/cloud/user/{user}.{format}') + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $user = $parameters['user']; + OC_OCS::quotaGet($format, $user); + }) + ->requirements(array('format'=>'xml|json')); // quotaset - }elseif(($method=='post') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'quota')) { - $user=$ex[$paracount-3]; - $quota = self::readData('post', 'quota', 'int'); - OC_OCS::quotaset($format, $user, $quota); + $router->create('quota_set', + '/cloud/user/{user}.{format}') + ->post() + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $user = $parameters['user']; + $quota = self::readData('post', 'quota', 'int'); + OC_OCS::quotaSet($format, $user, $quota); + }) + ->requirements(array('format'=>'xml|json')); // keygetpublic - }elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'publickey')) { - $user=$ex[$paracount-3]; - OC_OCS::publicKeyGet($format, $user); + $router->create('keygetpublic', + '/cloud/user/{user}/publickey.{format}') + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $user = $parameters['user']; + OC_OCS::publicKeyGet($format,$user); + }) + ->requirements(array('format'=>'xml|json')); // keygetprivate - }elseif(($method=='get') and ($ex[$paracount-6] == 'v1.php') and ($ex[$paracount-5]=='cloud') and ($ex[$paracount-4] == 'user') and ($ex[$paracount-2] == 'privatekey')) { - $user=$ex[$paracount-3]; - OC_OCS::privateKeyGet($format, $user); + $router->create('keygetpublic', + '/cloud/user/{user}/privatekey.{format}') + ->defaults(array('format' => $format)) + ->action(function ($parameters) { + $format = $parameters['format']; + $user = $parameters['user']; + OC_OCS::privateKeyGet($format,$user); + }) + ->requirements(array('format'=>'xml|json')); // add more calls here @@ -190,13 +244,14 @@ class OC_OCS { // sharing // versioning // news (rss) - - - - }else{ + try { + $router->match($_SERVER['PATH_INFO']); + } catch (ResourceNotFoundException $e) { $txt='Invalid query, please check the syntax. API specifications are here: http://www.freedesktop.org/wiki/Specifications/open-collaboration-services. DEBUG OUTPUT:'."\n"; $txt.=OC_OCS::getdebugoutput(); echo(OC_OCS::generatexml($format, 'failed', 999, $txt)); + } catch (MethodNotAllowedException $e) { + OC_Response::setStatus(405); } exit(); } @@ -378,7 +433,8 @@ class OC_OCS { * @param string $format * @return string xml/json */ - private static function apiConfig($format) { + public static function apiConfig($parameters) { + $format = $parameters['format']; $user=OC_OCS::checkpassword(false); $url=substr(OCP\Util::getServerHost().$_SERVER['SCRIPT_NAME'], 0, -11).''; diff --git a/lib/public/backgroundjob.php b/lib/public/backgroundjob.php index aba7d2b762..24a17836f7 100644 --- a/lib/public/backgroundjob.php +++ b/lib/public/backgroundjob.php @@ -46,6 +46,29 @@ namespace OCP; * is done it will be deleted from the list. */ class BackgroundJob { + /** + * @brief get the execution type of background jobs + * @return string + * + * This method returns the type how background jobs are executed. If the user + * did not select something, the type is ajax. + */ + public static function getExecutionType() { + return \OC_BackgroundJob::getExecutionType(); + } + + /** + * @brief sets the background jobs execution type + * @param $type execution type + * @return boolean + * + * This method sets the execution type of the background jobs. Possible types + * are "none", "ajax", "webcron", "cron" + */ + public static function setExecutionType( $type ) { + return \OC_BackgroundJob::setExecutionType( $type ); + } + /** * @brief creates a regular task * @param $klass class name diff --git a/lib/route.php b/lib/route.php new file mode 100644 index 0000000000..89af829d3d --- /dev/null +++ b/lib/route.php @@ -0,0 +1,112 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +use Symfony\Component\Routing\Route; + +class OC_Route extends Route { + /** + * Specify the method when this route is to be used + * + * @param string $method HTTP method (uppercase) + */ + public function method($method) { + $this->setRequirement('_method', strtoupper($method)); + return $this; + } + + /** + * Specify POST as the method to use with this route + */ + public function post() { + $this->method('POST'); + return $this; + } + + /** + * Specify GET as the method to use with this route + */ + public function get() { + $this->method('GET'); + return $this; + } + + /** + * Specify PUT as the method to use with this route + */ + public function put() { + $this->method('PUT'); + return $this; + } + + /** + * Specify DELETE as the method to use with this route + */ + public function delete() { + $this->method('DELETE'); + return $this; + } + + /** + * Defaults to use for this route + * + * @param array $defaults The defaults + */ + public function defaults($defaults) { + $action = $this->getDefault('action'); + $this->setDefaults($defaults); + if (isset($defaults['action'])) { + $action = $defaults['action']; + } + $this->action($action); + return $this; + } + + /** + * Requirements for this route + * + * @param array $requirements The requirements + */ + public function requirements($requirements) { + $method = $this->getRequirement('_method'); + $this->setRequirements($requirements); + if (isset($requirements['_method'])) { + $method = $requirements['_method']; + } + if ($method) { + $this->method($method); + } + return $this; + } + + /** + * The action to execute when this route matches + * @param string|callable $class the class or a callable + * @param string $function the function to use with the class + * + * This function is called with $class set to a callable or + * to the class with $function + */ + public function action($class, $function = null) { + $action = array($class, $function); + if (is_null($function)) { + $action = $class; + } + $this->setDefault('action', $action); + return $this; + } + + /** + * The action to execute when this route matches, includes a file like + * it is called directly + * @param $file + */ + public function actionInclude($file) { + $function = create_function('$param', 'unset($param["_route"]);$_GET=array_merge($_GET,$param);unset($param);require_once "'.$file.'";'); + $this->action($function); + } +} diff --git a/lib/router.php b/lib/router.php new file mode 100644 index 0000000000..a471a06802 --- /dev/null +++ b/lib/router.php @@ -0,0 +1,146 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +use Symfony\Component\Routing\Matcher\UrlMatcher; +use Symfony\Component\Routing\Generator\UrlGenerator; +use Symfony\Component\Routing\RequestContext; +use Symfony\Component\Routing\RouteCollection; +//use Symfony\Component\Routing\Route; + +class OC_Router { + protected $collections = array(); + protected $collection = null; + protected $root = null; + + protected $generator= null; + + public function __construct() { + $baseUrl = OC_Helper::linkTo('', 'index.php'); + $method = $_SERVER['REQUEST_METHOD']; + $host = OC_Request::serverHost(); + $schema = OC_Request::serverProtocol(); + $this->context = new RequestContext($baseUrl, $method, $host, $schema); + // TODO cache + $this->root = $this->getCollection('root'); + } + + /** + * loads the api routes + */ + public function loadRoutes() { + foreach(OC_APP::getEnabledApps() as $app){ + $file = OC_App::getAppPath($app).'/appinfo/routes.php'; + if(file_exists($file)){ + $this->useCollection($app); + require_once($file); + $collection = $this->getCollection($app); + $this->root->addCollection($collection, '/apps/'.$app); + } + } + $this->useCollection('root'); + require_once('core/routes.php'); + } + + protected function getCollection($name) { + if (!isset($this->collections[$name])) { + $this->collections[$name] = new RouteCollection(); + } + return $this->collections[$name]; + } + + /** + * Sets the collection to use for adding routes + * + * @param string $name Name of the colletion to use. + */ + public function useCollection($name) { + $this->collection = $this->getCollection($name); + } + + /** + * Create a OC_Route. + * + * @param string $name Name of the route to create. + * @param string $pattern The pattern to match + * @param array $defaults An array of default parameter values + * @param array $requirements An array of requirements for parameters (regexes) + */ + public function create($name, $pattern, array $defaults = array(), array $requirements = array()) { + $route = new OC_Route($pattern, $defaults, $requirements); + $this->collection->add($name, $route); + return $route; + } + + /** + * Find the route matching $url. + * + * @param string $url The url to find + */ + public function match($url) { + $matcher = new UrlMatcher($this->root, $this->context); + $parameters = $matcher->match($url); + if (isset($parameters['action'])) { + $action = $parameters['action']; + if (!is_callable($action)) { + var_dump($action); + throw new Exception('not a callable action'); + } + unset($parameters['action']); + call_user_func($action, $parameters); + } elseif (isset($parameters['file'])) { + include ($parameters['file']); + } else { + throw new Exception('no action available'); + } + } + + /** + * Get the url generator + * + */ + public function getGenerator() + { + if (null !== $this->generator) { + return $this->generator; + } + + return $this->generator = new UrlGenerator($this->root, $this->context); + } + + /** + * Generate url based on $name and $parameters + * + * @param string $name Name of the route to use. + * @param array $parameters Parameters for the route + */ + public function generate($name, $parameters = array(), $absolute = false) + { + return $this->getGenerator()->generate($name, $parameters, $absolute); + } + + /** + * Generate JSON response for routing in javascript + */ + public static function JSRoutes() + { + // TODO: http caching + $routes = array(); + $router = OC::getRouter(); + $root = $router->getCollection('root'); + foreach($root->all() as $name => $route) { + $compiled_route = $route->compile(); + $defaults = $route->getDefaults(); + unset($defaults['action']); + $routes[$name] = array( + 'tokens' => $compiled_route->getTokens(), + 'defaults' => $defaults, + ); + } + OCP\JSON::success ( array( 'data' => $routes ) ); + } +} diff --git a/lib/search/provider/file.php b/lib/search/provider/file.php index 456e12b5ec..4d88c2a87f 100644 --- a/lib/search/provider/file.php +++ b/lib/search/provider/file.php @@ -16,7 +16,7 @@ class OC_Search_Provider_File extends OC_Search_Provider{ $link = OC_Helper::linkTo( 'files', 'index.php', array('dir' => $path)); $type = (string)$l->t('Files'); }else{ - $link = OC_Helper::linkTo( 'files', 'download.php', array('file' => $path)); + $link = OC_Helper::linkToRoute( 'download', array('file' => $path)); $mimeBase = $fileData['mimepart']; switch($mimeBase) { case 'audio': diff --git a/settings/admin.php b/settings/admin.php index a36f219038..9cb70353f9 100755 --- a/settings/admin.php +++ b/settings/admin.php @@ -5,8 +5,8 @@ * See the COPYING-README file. */ -require_once '../lib/base.php'; OC_Util::checkAdminUser(); +OC_App::loadApps(); OC_Util::addStyle( "settings", "settings" ); OC_Util::addScript( "settings", "admin" ); diff --git a/settings/ajax/apps/ocs.php b/settings/ajax/apps/ocs.php index fb78cc8924..4d6f1116e7 100644 --- a/settings/ajax/apps/ocs.php +++ b/settings/ajax/apps/ocs.php @@ -6,9 +6,6 @@ * See the COPYING-README file. */ -// Init owncloud -require_once '../../../lib/base.php'; - OC_JSON::checkAdminUser(); $l = OC_L10N::get('settings'); diff --git a/settings/ajax/changepassword.php b/settings/ajax/changepassword.php index 12d3b67037..a0fe5947b6 100644 --- a/settings/ajax/changepassword.php +++ b/settings/ajax/changepassword.php @@ -1,8 +1,5 @@ array( "message" => $l->t("Unable to delete user") ))); -} \ No newline at end of file +} diff --git a/settings/ajax/setlanguage.php b/settings/ajax/setlanguage.php index 42eea7a96f..aebb1b31b6 100644 --- a/settings/ajax/setlanguage.php +++ b/settings/ajax/setlanguage.php @@ -1,8 +1,5 @@ OC_Preferences::getValue($user, 'files', 'quota', 'default')); } } -OC_JSON::success(array('data' => $users)); \ No newline at end of file +OC_JSON::success(array('data' => $users)); diff --git a/settings/apps.php b/settings/apps.php index a1c1bf6aa5..8134b44143 100644 --- a/settings/apps.php +++ b/settings/apps.php @@ -21,8 +21,8 @@ * */ -require_once '../lib/base.php'; OC_Util::checkAdminUser(); +OC_App::loadApps(); // Load the files we need OC_Util::addStyle( "settings", "settings" ); diff --git a/settings/help.php b/settings/help.php index 9157308dd5..69a5ec9c14 100644 --- a/settings/help.php +++ b/settings/help.php @@ -5,9 +5,8 @@ * See the COPYING-README file. */ -require_once '../lib/base.php'; OC_Util::checkLoggedIn(); - +OC_App::loadApps(); // Load the files we need OC_Util::addStyle( "settings", "settings" ); diff --git a/settings/js/users.js b/settings/js/users.js index 20bd94993b..1474ebcdd8 100644 --- a/settings/js/users.js +++ b/settings/js/users.js @@ -130,7 +130,7 @@ var UserList={ if (typeof UserList.offset === 'undefined') { UserList.offset = $('tbody tr').length; } - $.get(OC.filePath('settings', 'ajax', 'userlist.php'), { offset: UserList.offset }, function(result) { + $.get(OC.Router.generate('settings_ajax_userlist', { offset: UserList.offset }), function(result) { if (result.status === 'success') { $.each(result.data, function(index, user) { var tr = UserList.add(user.name, user.groups, user.subadmin, user.quota, false); diff --git a/settings/personal.php b/settings/personal.php index 5a267ec284..ab4bfaaf82 100644 --- a/settings/personal.php +++ b/settings/personal.php @@ -5,8 +5,8 @@ * See the COPYING-README file. */ -require_once '../lib/base.php'; OC_Util::checkLoggedIn(); +OC_App::loadApps(); // Highlight navigation entry OC_Util::addScript( 'settings', 'personal' ); diff --git a/settings/routes.php b/settings/routes.php new file mode 100644 index 0000000000..4f4f83e454 --- /dev/null +++ b/settings/routes.php @@ -0,0 +1,62 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +// Settings pages +$this->create('settings_help', '/settings/help') + ->actionInclude('settings/help.php'); +$this->create('settings_personal', '/settings/personal') + ->actionInclude('settings/personal.php'); +$this->create('settings_settings', '/settings') + ->actionInclude('settings/settings.php'); +$this->create('settings_users', '/settings/users') + ->actionInclude('settings/users.php'); +$this->create('settings_apps', '/settings/apps') + ->actionInclude('settings/apps.php'); +$this->create('settings_admin', '/settings/admin') + ->actionInclude('settings/admin.php'); +// Settings ajax actions +// users +$this->create('settings_ajax_userlist', '/settings/ajax/userlist') + ->actionInclude('settings/ajax/userlist.php'); +$this->create('settings_ajax_createuser', '/settings/ajax/createuser.php') + ->actionInclude('settings_ajax_createuser'); +$this->create('settings_ajax_removeuser', '/settings/ajax/removeuser.php') + ->actionInclude('settings/ajax/removeuser.php'); +$this->create('settings_ajax_setquota', '/settings/ajax/setquota.php') + ->actionInclude('settings/ajax/setquota.php'); +$this->create('settings_ajax_creategroup', '/settings/ajax/creategroup.php') + ->actionInclude('settings_ajax_creategroup'); +$this->create('settings_ajax_togglegroups', '/settings/ajax/togglegroups.php') + ->actionInclude('settings/ajax/togglegroups.php'); +$this->create('settings_ajax_togglesubadmins', '/settings/ajax/togglesubadmins.php') + ->actionInclude('settings/ajax/togglesubadmins.php'); +$this->create('settings_ajax_removegroup', '/settings/ajax/removegroup.php') + ->actionInclude('settings/ajax/removegroup.php'); +$this->create('settings_ajax_changepassword', '/settings/ajax/changepassword.php') + ->actionInclude('settings/ajax/changepassword.php'); +// personel +$this->create('settings_ajax_lostpassword', '/settings/ajax/lostpassword.php') + ->actionInclude('settings/ajax/lostpassword.php'); +$this->create('settings_ajax_setlanguage', '/settings/ajax/setlanguage.php') + ->actionInclude('settings/ajax/setlanguage.php'); +// apps +$this->create('settings_ajax_apps_ocs', '/settings/ajax/apps/ocs.php') + ->actionInclude('settings/ajax/apps/ocs.php'); +$this->create('settings_ajax_enableapp', '/settings/ajax/enableapp.php') + ->actionInclude('settings/ajax/enableapp.php'); +$this->create('settings_ajax_disableapp', '/settings/ajax/disableapp.php') + ->actionInclude('settings/ajax/disableapp.php'); +// admin +$this->create('settings_ajax_getlog', '/settings/ajax/getlog.php') + ->actionInclude('settings/ajax/getlog.php'); +$this->create('settings_ajax_setloglevel', '/settings/ajax/setloglevel.php') + ->actionInclude('settings/ajax/setloglevel.php'); + +// apps/user_openid +$this->create('settings_ajax_openid', '/settings/ajax/openid.php') + ->actionInclude('settings/ajax/openid.php'); diff --git a/settings/settings.php b/settings/settings.php index 68c07ff60f..add94b5b01 100644 --- a/settings/settings.php +++ b/settings/settings.php @@ -5,9 +5,9 @@ * See the COPYING-README file. */ -require_once '../lib/base.php'; OC_Util::checkLoggedIn(); OC_Util::verifyUser(); +OC_App::loadApps(); OC_Util::addStyle( 'settings', 'settings' ); OC_App::setActiveNavigationEntry( 'settings' ); diff --git a/settings/users.php b/settings/users.php index e76505cc78..6eaae47453 100644 --- a/settings/users.php +++ b/settings/users.php @@ -5,8 +5,8 @@ * See the COPYING-README file. */ -require_once '../lib/base.php'; OC_Util::checkSubAdminUser(); +OC_App::loadApps(); // We have some javascript foo! OC_Util::addScript( 'settings', 'users' ); @@ -57,4 +57,4 @@ $tmpl->assign( 'subadmins', $subadmins); $tmpl->assign( 'numofgroups', count($accessiblegroups)); $tmpl->assign( 'quota_preset', $quotaPreset); $tmpl->assign( 'default_quota', $defaultQuota); -$tmpl->printPage(); \ No newline at end of file +$tmpl->printPage(); diff --git a/tests/enable_all.php b/tests/enable_all.php new file mode 100644 index 0000000000..02e35518d6 --- /dev/null +++ b/tests/enable_all.php @@ -0,0 +1,20 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +require_once __DIR__.'/../lib/base.php'; + +OC_App::enable('calendar'); +OC_App::enable('contacts'); +OC_App::enable('files_archive'); +OC_App::enable('mozilla_sync'); +OC_App::enable('news'); +OC_App::enable('provisioning_api'); +OC_App::enable('user_external'); +OC_App::enable('provisioning_api'); +OC_App::enable('provisioning_api'); + diff --git a/tests/preseed-config.php b/tests/preseed-config.php new file mode 100644 index 0000000000..7eadccbe76 --- /dev/null +++ b/tests/preseed-config.php @@ -0,0 +1,19 @@ + false, + 'apps_paths' => + array ( + 0 => + array ( + 'path' => OC::$SERVERROOT.'/apps', + 'url' => '/apps', + 'writable' => false, + ), + 1 => + array ( + 'path' => OC::$SERVERROOT.'/apps2', + 'url' => '/apps2', + 'writable' => false, + ) + ), +);