From cd20f54f34221c8baf73d387a9a2b1560ef9041b Mon Sep 17 00:00:00 2001 From: Nicolas Le Goff Date: Thu, 12 Jul 2012 19:55:58 +0200 Subject: [PATCH 1/9] add Root/Account Controller --- lib/Alchemy/Phrasea/Application/Root.php | 43 +-- .../Phrasea/Controller/Root/Account.php | 266 ++++++++++++++++++ lib/Alchemy/Phrasea/Core.php | 5 +- lib/Alchemy/Phrasea/Security/Firewall.php | 30 ++ .../Phrasea/Controller/Root/AccountTest.php | 77 +++++ .../Alchemy/Phrasea/Security/FirewallTest.php | 39 +++ 6 files changed, 442 insertions(+), 18 deletions(-) create mode 100644 lib/Alchemy/Phrasea/Controller/Root/Account.php create mode 100644 lib/Alchemy/Phrasea/Security/Firewall.php create mode 100644 tests/Alchemy/Phrasea/Controller/Root/AccountTest.php create mode 100644 tests/Alchemy/Phrasea/Security/FirewallTest.php diff --git a/lib/Alchemy/Phrasea/Application/Root.php b/lib/Alchemy/Phrasea/Application/Root.php index 4b47b35a74..4ff58a6817 100644 --- a/lib/Alchemy/Phrasea/Application/Root.php +++ b/lib/Alchemy/Phrasea/Application/Root.php @@ -11,8 +11,9 @@ namespace Alchemy\Phrasea\Application; -use Symfony\Component\HttpFoundation\Response; use Alchemy\Phrasea\Controller\Root as Controller; +use Silex\Application as SilexApp; +use Symfony\Component\HttpFoundation\Response; /** * @@ -20,17 +21,19 @@ * @link www.phraseanet.com */ return call_user_func(function() { - $app = new \Silex\Application(); + $app = new SilexApp(); $app['Core'] = \bootstrap::getCore(); - if ( ! \setup::is_installed()) { - $response = new \Symfony\Component\HttpFoundation\RedirectResponse('/setup/'); - - return $response->send(); - } + $app->before(function () use ($app) { + // redirect the user to the setup screen + // if Phraseanet in not set up + if ( ! \setup::is_installed()) { + return $app->redirect("/setup/"); + } + }); - $app->get('/', function() use ($app) { + $app->get('/', function(SilexApp $app) { $browser = \Browser::getInstance(); if ($browser->isMobile()) { return $app->redirect("/login/?redirect=/lightbox"); @@ -41,17 +44,12 @@ } }); - $app->get('/robots.txt', function() use ($app) { - $appbox = \appbox::get_instance($app['Core']); - - $registry = $appbox->get_registry(); + $app->get('/robots.txt', function(SilexApp $app) { - if ($registry->get('GV_allow_search_engine') === true) { - $buffer = "User-Agent: *\n" - . "Allow: /\n"; + if ($app['Core']['Registry']->get('GV_allow_search_engine') === true) { + $buffer = "User-Agent: *\n" . "Allow: /\n"; } else { - $buffer = "User-Agent: *\n" - . "Disallow: /\n"; + $buffer = "User-Agent: *\n" . "Disallow: /\n"; } $response = new Response($buffer, 200, array('Content-Type' => 'text/plain')); @@ -61,6 +59,17 @@ }); $app->mount('/feeds/', new Controller\RSSFeeds()); + $app->mount('/account/', new Controller\Account()); + + $app->error(function (\Exception $e, $code) use ($app) { + + if ($e instanceof \Exception_Forbidden) { + $code = 403; + } else { + return new Response(Response::$statusTexts[500], 500); + } + }); + return $app; } diff --git a/lib/Alchemy/Phrasea/Controller/Root/Account.php b/lib/Alchemy/Phrasea/Controller/Root/Account.php new file mode 100644 index 0000000000..5207f2608b --- /dev/null +++ b/lib/Alchemy/Phrasea/Controller/Root/Account.php @@ -0,0 +1,266 @@ +get('GV_RootPath') . 'lib/classes/deprecated/inscript.api.php'; + + $controllers->before(function() use ($app) { + $app['Core']['Firewall']->requireAuthentication($app); + }); + + /** + * New account route + * + * name : display_account + * + * description : Display form to create a new account + * + * method : GET + * + * parameters : none + * + * return : HTML Response + */ + $controllers->get('/', $this->call('displayAccount')) + ->bind('display_account'); + + /** + * Create account route + * + * name : update_account + * + * description : update your account informations + * + * method : POST + * + * parameters : + * 'gender' + * 'lastname' + * 'firstname' + * 'job' + * 'lastname' + * 'company' + * 'function' + * 'activity' + * 'phone' + * 'fax' + * 'address' + * 'zip_code' + * 'geoname_id' + * 'dest_ftp' + * 'default_data_ftp' + * 'prefix_ftp_folder' + * 'notice' + * 'bases' + * 'mail_notifications' + * 'request_notifications' + * 'demand' + * 'notifications' + * 'active_ftp' + * 'address_ftp' + * 'login_ftp' + * 'password_ftp' + * 'pass_if_ftp' + * 'retry_ftp' + * + * + * return : HTML Response + */ + $controllers->post('/', $this->call('updateAccount')) + ->bind('update_account'); + + return $controllers; + } + + /** + * Display account form + * + * @param Application $app A Silex application where the controller is mounted on + * @param Request $request The current request + * + * @return Response + */ + public function displayAccount(Application $app, Request $request) + { + $appbox = \appbox::get_instance($app['Core']); + $user = $app['Core']->getAuthenticatedUser(); + $evtMngr = \eventsmanager_broker::getInstance($appbox, $app['Core']); + + switch ($notice = $request->get('notice', '')) { + case 'password-update-ok': + $notice = _('login::notification: Mise a jour du mot de passe avec succes'); + break; + case 'account-update-ok': + $notice = _('login::notification: Changements enregistres'); + break; + case 'account-update-bad': + $notice = _('forms::erreurs lors de l\'enregistrement des modifications'); + break; + case 'demand-ok': + $notice = _('login::notification: Vos demandes ont ete prises en compte'); + break; + } + + return new Response($app['Core']['Twig']->display('user/account.html.twig', array( + 'geonames' => new \geonames(), + 'user' => $user, + 'notice' => $notice, + 'inscriptions' => giveMeBases($user->get_id()), + 'evt_mngr' => $evtMngr, + 'notifications' => $evtMngr->list_notifications_available($user->get_id()), + ))); + } + + /** + * Update account informations + * + * @param Application $app A Silex application where the controller is mounted on + * @param Request $request The current request + * + * @return Response + */ + public function updateAccount(Application $app, Request $request) + { + $appbox = \appbox::get_instance($app['Core']); + $user = $app['Core']->getAuthenticatedUser(); + $evtMngr = \eventsmanager_broker::getInstance($appbox, $app['Core']); + $notice = 'account-update-bad'; + + $demands = (array) $request->get('demand', array()); + + if (0 === count($demands)) { + $register = new \appbox_register($appbox); + + foreach ($demands as $baseId) { + try { + $register->add_request($user, \collection::get_from_base_id($baseId)); + $notice = 'demand-ok'; + } catch (\Exception $e) { + + } + } + } + + $accountFields = array( + 'form_gender', + 'form_firstname', + 'form_lastname', + 'form_address', + 'form_zip', + 'form_phone', + 'form_fax', + 'form_function', + 'form_company', + 'form_activity', + 'form_geonameid', + 'form_addrFTP', + 'form_loginFTP', + 'form_pwdFTP', + 'form_destFTP', + 'form_prefixFTPfolder' + ); + + if (0 === count(array_diff($accountFields, array_keys($request->request->all())))) { + $defaultDatas = 0; + + if ($datas = (array) $request->get("form_defaultdataFTP", array())) { + if (in_array('document', $datas)) { + $defaultDatas += 4; + } + + if (in_array('preview', $datas)) { + $defaultDatas += 2; + } + + if (in_array('caption', $datas)) { + $defaultDatas += 1; + } + } + + try { + $appbox->get_connection()->beginTransaction(); + + $user->set_gender($request->get("form_gender")) + ->set_firstname($request->get("form_firstname")) + ->set_lastname($request->get("form_lastname")) + ->set_address($request->get("form_address")) + ->set_zip($request->get("form_zip")) + ->set_tel($request->get("form_phone")) + ->set_fax($request->get("form_fax")) + ->set_job($request->get("form_activity")) + ->set_company($request->get("form_company")) + ->set_position($request->get("form_function")) + ->set_geonameid($request->get("form_geonameid")) + ->set_mail_notifications((bool) $request->get("mail_notifications")) + ->set_activeftp($request->get("form_activeFTP")) + ->set_ftp_address($request->get("form_addrFTP")) + ->set_ftp_login($request->get("form_loginFTP")) + ->set_ftp_password($request->get("form_pwdFTP")) + ->set_ftp_passif($request->get("form_passifFTP")) + ->set_ftp_dir($request->get("form_destFTP")) + ->set_ftp_dir_prefix($request->get("form_prefixFTPfolder")) + ->set_defaultftpdatas($defaultDatas); + + $appbox->get_connection()->commit(); + + $notice = 'account-update-ok'; + } catch (Exception $e) { + $appbox->get_connection()->rollBack(); + } + } + + $requestedNotifications = (array) $request->get('notifications', array()); + + foreach ($evtMngr->list_notifications_available($user->get_id()) as $notifications) { + foreach ($notifications as $notification) { + $notifId = (int) $notification['id']; + $notifName = sprintf('notification_%d', $notifId); + + if (isset($requestedNotifications[$notifId])) { + $user->setPrefs($notifName, '1'); + } else { + $user->setPrefs($notifName, '0'); + } + } + } + + return $app->redirect(sprintf('/account/?notice=%s', $notice), 201); + } + + /** + * Prefix the method to call with the controller class name + * + * @param string $method The method to call + * @return string + */ + private function call($method) + { + return sprintf('%s::%s', __CLASS__, $method); + } +} diff --git a/lib/Alchemy/Phrasea/Core.php b/lib/Alchemy/Phrasea/Core.php index c77efaee6e..c154ce418b 100644 --- a/lib/Alchemy/Phrasea/Core.php +++ b/lib/Alchemy/Phrasea/Core.php @@ -11,7 +11,6 @@ namespace Alchemy\Phrasea; -use Alchemy\Phrasea\Core\Configuration; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Serializer; @@ -102,6 +101,10 @@ public function __construct($environement = null) return new \Alchemy\Phrasea\Cache\Manager($core, $file); }); + $this['Firewall'] = $this->share(function() { + return new Security\Firewall(); + }); + /** * Set Entity Manager using configuration */ diff --git a/lib/Alchemy/Phrasea/Security/Firewall.php b/lib/Alchemy/Phrasea/Security/Firewall.php new file mode 100644 index 0000000000..2590eb07f7 --- /dev/null +++ b/lib/Alchemy/Phrasea/Security/Firewall.php @@ -0,0 +1,30 @@ +isAuthenticated()) { + try { + $session = \appbox::get_instance($app['Core'])->get_session(); + $session->open_phrasea_session(); + } catch (\Exception $e) { + + return $app->redirect('/login/logout.php'); + } + } else { + + return $app->redirect('/login/'); + } + + if ($app['Core']->getAuthenticatedUser()->is_guest()) { + + return $app->redirect('/login/'); + } + } +} diff --git a/tests/Alchemy/Phrasea/Controller/Root/AccountTest.php b/tests/Alchemy/Phrasea/Controller/Root/AccountTest.php new file mode 100644 index 0000000000..bd098e9484 --- /dev/null +++ b/tests/Alchemy/Phrasea/Controller/Root/AccountTest.php @@ -0,0 +1,77 @@ +client = $this->createClient(); + } + + public function createApplication() + { + $app = require __DIR__ . '/../../../../../lib/Alchemy/Phrasea/Application/Root.php'; + + $app['debug'] = true; + unset($app['exception_handler']); + + return $app; + } + + public function testGetAccount() + { + $this->client->request('GET', '/account/'); + + $response = $this->client->getResponse(); + + $this->assertTrue($response->isOk()); + } + + public function testUpdateAccount() + { + $core = \bootstrap::getCore(); + $appbox = \appbox::get_instance($core); + + $bases = array(); + foreach ($appbox->get_databoxes() as $databox) { + foreach ($databox->get_collections() as $collection) { + $bases[] = $collection->get_base_id(); + } + } + + if(0 === count($bases)) { + $this->markTestSkipped('No collections'); + } + + $this->client->request('POST', '/account/', array( + 'demand' => $bases, + 'form_gender' => 'M', + 'form_firstname' => 'gros', + 'form_lastname' => 'minet', + 'form_address' => 'rue du lac', + 'form_zip' => '75005', + 'form_phone' => '+33645787878', + 'form_fax' => '+33145787845', + 'form_function' => 'astronaute', + 'form_company' => 'NASA', + 'form_activity' => 'Space', + 'form_geonameid' => '', + 'form_addrFTP' => '', + 'form_loginFTP' => '', + 'form_pwdFTP' => '', + 'form_destFTP' => '', + 'form_prefixFTPfolder' => '', + 'form_defaultdataFTP' => array('document', 'preview', 'caption'), + 'mail_notifications' => '1' + )); + + $response = $this->client->getResponse(); + + $this->assertTrue($response->isOk()); + + $this->assertEquals('minet', $core->getAUthenticatedUser()->get_lastname()); + } +} diff --git a/tests/Alchemy/Phrasea/Security/FirewallTest.php b/tests/Alchemy/Phrasea/Security/FirewallTest.php new file mode 100644 index 0000000000..57cfb4a80e --- /dev/null +++ b/tests/Alchemy/Phrasea/Security/FirewallTest.php @@ -0,0 +1,39 @@ +client = $this->createClient(); + } + + public function testRequiredAuth() + { + $core = \bootstrap::getCore(); + $response = $core['Firewall']->requireAuthentication($this->app); + $this->assertNull($response); + $appbox = \appbox::get_instance($core); + $session = $appbox->get_session(); + $session->logout(); + $response = $core['Firewall']->requireAuthentication($this->app); + $this->assertTrue($response->isRedirect()); + $this->assertEquals('/login/', $response->headers->get('location')); + } +} + +?> From ec161e28530cd83005f151d86fe926f49bca07e4 Mon Sep 17 00:00:00 2001 From: Nicolas Le Goff Date: Thu, 12 Jul 2012 20:24:01 +0200 Subject: [PATCH 2/9] fix display account form --- .../Phrasea/Controller/Root/Account.php | 2 +- templates/web/user/account.html.twig | 66 +++++++++++-------- 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Root/Account.php b/lib/Alchemy/Phrasea/Controller/Root/Account.php index 5207f2608b..5398dee067 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/Account.php +++ b/lib/Alchemy/Phrasea/Controller/Root/Account.php @@ -127,7 +127,7 @@ public function displayAccount(Application $app, Request $request) break; } - return new Response($app['Core']['Twig']->display('user/account.html.twig', array( + return new Response($app['Core']['Twig']->render('user/account.html.twig', array( 'geonames' => new \geonames(), 'user' => $user, 'notice' => $notice, diff --git a/templates/web/user/account.html.twig b/templates/web/user/account.html.twig index 069ab0ea16..26e7f1938d 100644 --- a/templates/web/user/account.html.twig +++ b/templates/web/user/account.html.twig @@ -17,7 +17,7 @@ $( "#tab-account-cat").tabs({ ajaxOptions: { error: function( xhr, status, index, anchor ) { - $( anchor.hash ).html("<{% trans 'Erreur lors du chargement' %}"); + $( anchor.hash ).html("{% trans 'Erreur lors du chargement' %}"); } } }); @@ -266,7 +266,7 @@ - {% for sbasId, baseIsnc in inscriptions %} - {% if baseIsnc['CollsRegistered'] or baseInsc['CollsRefuse'] or baseInsc['CollsWait'] or baseInsc['CollsIntime'] or baseInsc['CollsOuttime'] or baseInsc['CollsNonactif'] or baseInsc['CollsCGU'] or baseInsc['Colls'] %} + {% for sbasId, baseInsc in inscriptions %} + {% if baseInsc['CollsRegistered'] or baseInsc['CollsRefuse'] or baseInsc['CollsWait'] or baseInsc['CollsIntime'] or baseInsc['CollsOuttime'] or baseInsc['CollsNonactif'] or baseInsc['CollsCGU'] or baseInsc['Colls'] %} - + {% endif %} - {% if baseInsc['CollsRegistered'] %} - {% for collId, isTrue in baseInsc['CollsRegistered'] %} - {{ base_id == (sbasId |base_from_coll(collId)) }} - - - + {% if baseInsc['CollsRegistered'] is not none %} + {% for base in baseInsc['CollsRegistered']%} + {% for collId, isTrue in base %} + {{ base_id == sbasId |base_from_coll(collId) }} + + + + {% endfor %} {% endfor %} - + + + {% endif %} {% if baseInsc['CollsRefuse'] %} {% for collId, isTrue in baseInsc['CollsRefuse'] %} - {{ base_id == (sbasId |base_from_coll(collId)) }} + {{ base_id == sbasId |base_from_coll(collId) }} {% endfor %} - + + + {% endif %} {% if baseInsc['CollsWait'] %} {% for collId, isTrue in baseInsc['CollsWait'] %} - {{ base_id == (sbasId |base_from_coll(collId)) }} + {{ base_id == sbasId |base_from_coll(collId) }} @@ -537,11 +545,11 @@ {% if baseInsc['CollsIntime'] %} {% for collId, isTrue in baseInsc['CollsIntime'] %} - {{ base_id == (sbasId |base_from_coll(collId)) }} + {{ base_id == sbasId |base_from_coll(collId) }} @@ -552,11 +560,11 @@ {% if baseInsc['CollsOuttime'] %} {% for collId, isTrue in baseInsc['CollsOuttime'] %} - {{ base_id == (sbasId |base_from_coll(collId)) }} + {{ base_id == sbasId |base_from_coll(collId) }} @@ -571,7 +579,7 @@ @@ -592,7 +600,7 @@ {% endif %} {% for collId, collName in baseInsc['Colls'] %} - {{ base_id == (sbasId |base_from_coll(collId)) }} + {{ base_id == sbasId |base_from_coll(collId) }} @@ -605,7 +613,7 @@ {% endif %} {% if baseInsc['CollsCGU'] %} {% for collId, collDesc in baseInsc['CollsCGU'] %} - {{ base_id == (sbasId |base_from_coll(collId)) }} + {{ base_id == sbasId |base_from_coll(collId) }} From 146b949de4a1bfdf18dc6f6bfee3a9680cfa3348 Mon Sep 17 00:00:00 2001 From: Nicolas Le Goff Date: Thu, 12 Jul 2012 20:27:12 +0200 Subject: [PATCH 3/9] fix update form --- tests/Alchemy/Phrasea/Controller/Root/AccountTest.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/Alchemy/Phrasea/Controller/Root/AccountTest.php b/tests/Alchemy/Phrasea/Controller/Root/AccountTest.php index bd098e9484..2d4224932f 100644 --- a/tests/Alchemy/Phrasea/Controller/Root/AccountTest.php +++ b/tests/Alchemy/Phrasea/Controller/Root/AccountTest.php @@ -69,9 +69,7 @@ public function testUpdateAccount() )); $response = $this->client->getResponse(); - - $this->assertTrue($response->isOk()); - + $this->assertTrue($response->isRedirect()); $this->assertEquals('minet', $core->getAUthenticatedUser()->get_lastname()); } } From 5085e0e351f5d0c7adf1a09ddf977b721dcfca5f Mon Sep 17 00:00:00 2001 From: Nicolas Le Goff Date: Thu, 12 Jul 2012 20:30:46 +0200 Subject: [PATCH 4/9] remove error handler --- lib/Alchemy/Phrasea/Application/Root.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/Alchemy/Phrasea/Application/Root.php b/lib/Alchemy/Phrasea/Application/Root.php index 4ff58a6817..e0dc12507f 100644 --- a/lib/Alchemy/Phrasea/Application/Root.php +++ b/lib/Alchemy/Phrasea/Application/Root.php @@ -61,16 +61,6 @@ $app->mount('/feeds/', new Controller\RSSFeeds()); $app->mount('/account/', new Controller\Account()); - $app->error(function (\Exception $e, $code) use ($app) { - - if ($e instanceof \Exception_Forbidden) { - $code = 403; - } else { - return new Response(Response::$statusTexts[500], 500); - } - }); - - return $app; } ); From 967706f77bc9b679d419d8965a95d13538569138 Mon Sep 17 00:00:00 2001 From: Nicolas Le Goff Date: Fri, 13 Jul 2012 11:19:14 +0200 Subject: [PATCH 5/9] change link from /account.php to /account/ --- templates/web/common/menubar.twig | 2 +- templates/web/user/account.html.twig | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/web/common/menubar.twig b/templates/web/common/menubar.twig index fc61f25503..3a3647705f 100644 --- a/templates/web/common/menubar.twig +++ b/templates/web/common/menubar.twig @@ -138,7 +138,7 @@ {% trans 'Guest' %} {% else %} - + {{user.get_login()}} diff --git a/templates/web/user/account.html.twig b/templates/web/user/account.html.twig index 26e7f1938d..43fd36a3d1 100644 --- a/templates/web/user/account.html.twig +++ b/templates/web/user/account.html.twig @@ -269,7 +269,7 @@ {% if notice | trim != '' %}
{{ notice }}
{% endif %} - +
{% trans 'Informations personnelles' %} @@ -476,7 +476,7 @@
- +
- {% if notice != '' %} + {% if notice | trim != '' %}
{{ notice }}
{% endif %}
@@ -483,50 +483,58 @@
   

{{ sbasId |sbas_names }}

{{ sbasId | sbas_names }}

- {% trans 'login::register: acces authorise sur la collection ' %}{{ sbasId |sbas_names }} - {% if (isTrue |trim) != '' %} - {% trans 'login::register::CGU: lire les CGU' %} - {% endif %} -
+ {% trans 'login::register: acces authorise sur la collection ' %}{{ sbasId |sbas_names }} + {% if isTrue | trim != '' %} + {% trans 'login::register::CGU: lire les CGU' %} + {% endif %} +
+
{% trans 'login::register: acces refuse sur la collection ' %}{{ sbasId |sbas_names }} - {% if (isTrue |trim) != '' %} + {% if isTrue | trim != '' %} {% trans 'login::register::CGU: lire les CGU' %} {% endif %}
+
{% trans 'login::register: en attente d\'acces sur' %} {{ sbasId |sbas_names }} - {% if (isTrue |trim) != '' %} + {% if isTrue | trim != '' %} {% trans 'login::register::CGU: lire les CGU' %} {% endif %}
{% trans 'login::register: acces temporaire sur' %} {{ sbasId |sbas_names }} - {% if (isTrue |trim) != '' %} + {% if isTrue |trim != '' %} {% trans 'login::register::CGU: lire les CGU' %} {% endif %}
{% trans 'login::register: acces temporaire termine sur ' %}{{ sbasId |sbas_names }} - {% if (isTrue |trim) != '' %} + {% if isTrue |trim != '' %} {% trans 'login::register::CGU: lire les CGU' %} {% endif %}
{% trans 'login::register: acces supendu sur' %} {{ sbasId |sbas_names }} - {% if (isTrue |trim) != '' %} + {% if isTrue |trim != '' %} {% trans 'login::register::CGU: lire les CGU' %} {% endif %}
{{ collName }}

From c01ac38c080ed52989d4e5f10cb35019f9e690aa Mon Sep 17 00:00:00 2001 From: Nicolas Le Goff Date: Fri, 13 Jul 2012 16:52:15 +0200 Subject: [PATCH 6/9] add /developers/ route --- config/nginx.rewrite.rules | 2 + lib/Alchemy/Phrasea/Application/OAuth2.php | 201 ----- lib/Alchemy/Phrasea/Application/Root.php | 10 +- .../Phrasea/Controller/Root/Account.php | 153 +++- .../Phrasea/Controller/Root/Developers.php | 416 ++++++++++ lib/Alchemy/Phrasea/Security/Firewall.php | 9 +- lib/classes/API/OAuth2/Account.class.php | 3 +- lib/classes/API/OAuth2/Application.class.php | 5 + templates/web/account/access.html.twig | 168 ++++ templates/web/account/account.html.twig | 220 ++++++ .../web/account/authorized_apps.html.twig | 107 +++ templates/web/account/base.html.twig | 44 ++ templates/web/account/sessions.html.twig | 67 ++ .../web/developers/application.html.twig | 90 +++ .../web/developers/application_form.html.twig | 105 +++ .../web/developers/applications.html.twig | 62 ++ templates/web/developers/header.html.twig | 177 +++++ templates/web/user/account.html.twig | 724 ------------------ www/.htaccess | 2 + www/skins/login/css/main.css | 6 + 20 files changed, 1635 insertions(+), 936 deletions(-) create mode 100644 lib/Alchemy/Phrasea/Controller/Root/Developers.php create mode 100644 templates/web/account/access.html.twig create mode 100644 templates/web/account/account.html.twig create mode 100644 templates/web/account/authorized_apps.html.twig create mode 100644 templates/web/account/base.html.twig create mode 100644 templates/web/account/sessions.html.twig create mode 100644 templates/web/developers/application.html.twig create mode 100644 templates/web/developers/application_form.html.twig create mode 100644 templates/web/developers/applications.html.twig create mode 100644 templates/web/developers/header.html.twig delete mode 100644 templates/web/user/account.html.twig diff --git a/config/nginx.rewrite.rules b/config/nginx.rewrite.rules index 5e54b68b17..069105ae8b 100644 --- a/config/nginx.rewrite.rules +++ b/config/nginx.rewrite.rules @@ -45,6 +45,8 @@ rewrite ^/prod/notifications/.*$ /prod/router.php last; rewrite ^/robots.txt$ /index.php last; rewrite ^/feeds/.*$ /index.php last; +rewrite ^/account/.*$ /index.php last; +rewrite ^/developers/.*$ /index.php last; rewrite ^/lightbox/.*$ /lightbox/index.php last; rewrite ^/api/v1/.*$ /api/v1/index.php last; diff --git a/lib/Alchemy/Phrasea/Application/OAuth2.php b/lib/Alchemy/Phrasea/Application/OAuth2.php index 32ad573ae3..9ab1734710 100644 --- a/lib/Alchemy/Phrasea/Application/OAuth2.php +++ b/lib/Alchemy/Phrasea/Application/OAuth2.php @@ -201,207 +201,6 @@ return; }); - /****************************************************************** - * MANAGEMENT APPS - * - * - */ - /** - * list of all authorized apps by logged user - */ - $route = '/applications'; - $app->get($route, function() use ($app) { - $apps = \API_OAuth2_Application::load_app_by_user($app['appbox'], $app['Core']->getAuthenticatedUser()); - - return $app['response']('api/auth/applications.twig', array("apps" => $apps, 'user' => $app['Core']->getAuthenticatedUser())); - }); - - /** - * list of apps created by user - */ - $route = "/applications/dev"; - $app->get($route, function() use ($app) { - $rs = \API_OAuth2_Application::load_dev_app_by_user($app['appbox'], $app['Core']->getAuthenticatedUser()); - - return $app['response']('api/auth/application_dev.twig', array("apps" => $rs)); - }); - - /** - * display a new app form - */ - $route = "/applications/dev/new"; - $app->get($route, function() use ($app) { - $var = array("violations" => null, 'form' => null, 'request' => $app['request']); - - return $app['response']('api/auth/application_dev_new.twig', $var); - }); - - $route = "/applications/dev/create"; - $app->post($route, function() use ($app) { - $submit = false; - if ($app['request']->get("type") == "desktop") { - $post = new \API_OAuth2_Form_DevAppDesktop($app['request']); - } else { - $post = new \API_OAuth2_Form_DevAppInternet($app['request']); - } - - $violations = $app['validator']->validate($post); - - if ($violations->count() == 0) - $submit = true; - - $request = $app['request']; - - if ($submit) { - $application = \API_OAuth2_Application::create($app['appbox'], $app['Core']->getAuthenticatedUser(), $post->getName()); - $application->set_description($post->getDescription()) - ->set_redirect_uri($post->getSchemeCallback() . $post->getCallback()) - ->set_type($post->getType()) - ->set_website($post->getSchemeWebsite() . $post->getWebsite()); - - return $app->redirect("/api/oauthv2/applications/dev/" . $application->get_id() . "/show"); - } - - $var = array( - "violations" => $violations, - "form" => $post - ); - - return $app['response']('api/auth/application_dev_new.twig', $var); - }); - - /** - * show details of app identified by its id - */ - $route = "/applications/dev/{id}/show"; - $app->get($route, function($id) use ($app) { - $client = new \API_OAuth2_Application($app['appbox'], $id); - $token = $client->get_user_account($app['Core']->getAuthenticatedUser())->get_token()->get_value(); - $var = array("app" => $client, "user" => $app['Core']->getAuthenticatedUser(), "token" => $token); - - return $app['response']('api/auth/application_dev_show.twig', $var); - })->assert('id', '\d+'); - - /** - * revoke access from a user to the app - * identified by account id - */ - $route = "/applications/revoke_access/"; - $app->post($route, function() use ($app) { - $result = array("ok" => false); - try { - $account = new \API_OAuth2_Account($app['appbox'], $app['request']->get('account_id')); - $account->set_revoked((bool) $app['request']->get('revoke')); - $result['ok'] = true; - } catch (\Exception $e) { - - } - - $Serializer = $app['Core']['Serializer']; - - return new Response( - $Serializer->serialize($result, 'json') - , 200 - , array("content-type" => "application/json") - ); - }); - - /** - * revoke access from a user to the app - * identified by account id - */ - $route = "/applications/{appId}/grant_password/"; - $app->post($route, function($appId) use ($app) { - $result = array("ok" => false); - try { - $client = new \API_OAuth2_Application($app['appbox'], $appId); - $client->set_grant_password((bool) $app['request']->get('grant')); - $result['ok'] = true; - } catch (\Exception $e) { - - } - - $Serializer = $app['Core']['Serializer']; - - return new Response( - $Serializer->serialize($result, 'json') - , 200 - , array("content-type" => "application/json") - ); - }); - - $route = "/applications/{id}/generate_access_token/"; - $app->post($route, function($id) use ($app) { - $result = array("ok" => false); - try { - $client = new \API_OAuth2_Application($app['appbox'], $id); - $account = $client->get_user_account($app['Core']->getAuthenticatedUser()); - - $token = $account->get_token(); - - if ($token instanceof API_OAuth2_Token) - $token->renew(); - else - $token = \API_OAuth2_Token::create($app['appbox'], $account); - - $result = array( - "ok" => true - , 'token' => $token->get_value() - ); - } catch (\Exception $e) { - - } - - $Serializer = $app['Core']['Serializer']; - - return new Response( - $Serializer->serialize($result, 'json') - , 200 - , array("content-type" => "application/json") - ); - })->assert('id', '\d+'); - - $route = "/applications/oauth_callback"; - $app->post($route, function() use ($app) { - $app_id = $app['request']->request->get("app_id"); - $app_callback = $app["request"]->request->get("callback"); - $result = array("success" => false); - try { - $client = new \API_OAuth2_Application($app['appbox'], $app_id); - $client->set_redirect_uri($app_callback); - $result['success'] = true; - } catch (\Exception $e) { - - } - - $Serializer = $app['Core']['Serializer']; - - return new Response( - $Serializer->serialize($result, 'json') - , 200 - , array("content-type" => "application/json") - ); - }); - - $route = "/applications/{id}"; - $app->delete($route, function($id) use ($app) { - $result = array("success" => false); - try { - $client = new \API_OAuth2_Application($app['appbox'], $id); - $client->delete(); - $result['success'] = true; - } catch (\Exception $e) { - - } - - $Serializer = $app['Core']['Serializer']; - - return new Response( - $Serializer->serialize($result, 'json') - , 200 - , array("content-type" => "application/json") - ); - })->assert('id', '\d+'); /** * ******************************************************************* * diff --git a/lib/Alchemy/Phrasea/Application/Root.php b/lib/Alchemy/Phrasea/Application/Root.php index e0dc12507f..5b8ed6f7ae 100644 --- a/lib/Alchemy/Phrasea/Application/Root.php +++ b/lib/Alchemy/Phrasea/Application/Root.php @@ -13,6 +13,7 @@ use Alchemy\Phrasea\Controller\Root as Controller; use Silex\Application as SilexApp; +use Silex\Provider\ValidatorServiceProvider; use Symfony\Component\HttpFoundation\Response; /** @@ -25,12 +26,10 @@ $app['Core'] = \bootstrap::getCore(); + $app->register(new ValidatorServiceProvider()); + $app->before(function () use ($app) { - // redirect the user to the setup screen - // if Phraseanet in not set up - if ( ! \setup::is_installed()) { - return $app->redirect("/setup/"); - } + $app['Core']['Firewall']->requireSetup($app); }); $app->get('/', function(SilexApp $app) { @@ -60,6 +59,7 @@ $app->mount('/feeds/', new Controller\RSSFeeds()); $app->mount('/account/', new Controller\Account()); + $app->mount('/developers/', new Controller\Developers()); return $app; } diff --git a/lib/Alchemy/Phrasea/Controller/Root/Account.php b/lib/Alchemy/Phrasea/Controller/Root/Account.php index 5398dee067..22dfc7b93f 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/Account.php +++ b/lib/Alchemy/Phrasea/Controller/Root/Account.php @@ -15,6 +15,7 @@ use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\JsonResponse; /** * @@ -28,8 +29,6 @@ public function connect(Application $app) { $controllers = $app['controllers_factory']; - require_once $app['Core']['Registry']->get('GV_RootPath') . 'lib/classes/deprecated/inscript.api.php'; - $controllers->before(function() use ($app) { $app['Core']['Firewall']->requireAuthentication($app); }); @@ -95,9 +94,156 @@ public function connect(Application $app) $controllers->post('/', $this->call('updateAccount')) ->bind('update_account'); + /** + * Give account access + * + * name : account_access + * + * description : Display form to create a new account + * + * method : GET + * + * parameters : none + * + * return : HTML Response + */ + $controllers->get('/access/', $this->call('accountAccess')) + ->bind('account_access'); + + /** + * Give account open sessions + * + * name : account_sessions + * + * description : Display form to create a new account + * + * method : GET + * + * parameters : none + * + * return : HTML Response + */ + $controllers->get('/security/sessions/', $this->call('accountSessionsAccess')) + ->bind('account_sessions'); + + /** + * Give authorized applications that can access user informations + * + * name : account_auth_apps + * + * description : Display form to create a new account + * + * method : GET + * + * parameters : none + * + * return : HTML Response + */ + $controllers->get('/security/applications/', $this->call('accountAuthorizedApps')) + ->bind('account_auth_apps'); + + /** + * Grant access to an authorized app + * + * name : grant_app_access + * + * description : Display form to create a new account + * + * method : GET + * + * parameters : none + * + * return : HTML Response + */ + $controllers->get('/security/application/{application_id}/grant/', $this->call('grantAccess')) + ->assert('application_id', '\d+') + ->bind('grant_app_access'); + return $controllers; } + /** + * Display authorized applications that can access user informations + * + * @param Application $app A Silex application where the controller is mounted on + * @param Request $request The current request + * + * @return Response + */ + public function grantAccess(Application $app, Request $request, $application_id) + { + if ( ! $request->isXmlHttpRequest() || ! array_key_exists($request->getMimeType('json'), array_flip($request->getAcceptableContentTypes()))) { + $app->abort(400, _('Bad request format, only JSON is allowed')); + } + + $appbox = \appbox::get_instance($app['Core']); + $error = false; + + try { + $account = \API_OAuth2_Account::load_with_user( + $appbox + , new \API_OAuth2_Application($appbox, $application_id) + , $app['Core']->getAuthenticatedUser() + ); + } catch (\Exception_NotFound $e) { + $error = true; + } + + $account->set_revoked((bool) $request->get('revoke'), false); + + return new JsonResponse(array('success' => ! $error)); + } + + /** + * Display authorized applications that can access user informations + * + * @param Application $app A Silex application where the controller is mounted on + * @param Request $request The current request + * + * @return Response + */ + public function accountAuthorizedApps(Application $app, Request $request) + { + $user = $app['Core']->getAuthenticatedUser(); + + return $app['Core']['Twig']->render('account/authorized_apps.html.twig', array( + "apps" => \API_OAuth2_Application::load_app_by_user(\appbox::get_instance($app['Core']), $user), + 'user' => $user + )); + } + + /** + * Display account session accesss + * + * @param Application $app A Silex application where the controller is mounted on + * @param Request $request The current request + * + * @return Response + */ + public function accountSessionsAccess(Application $app, Request $request) + { + return new Response($app['Core']['Twig']->render('account/sessions.html.twig')); + } + + /** + * Display account base access + * + * @param Application $app A Silex application where the controller is mounted on + * @param Request $request The current request + * + * @return Response + */ + public function accountAccess(Application $app, Request $request) + { + require_once $app['Core']['Registry']->get('GV_RootPath') . 'lib/classes/deprecated/inscript.api.php'; + + $user = $app['Core']->getAuthenticatedUser(); + + return new Response($app['Core']['Twig']->render('account/access.html.twig', array( + 'inscriptions' => giveMeBases($user->get_id()) + ))); + } + /** * Display account form * @@ -127,11 +273,10 @@ public function displayAccount(Application $app, Request $request) break; } - return new Response($app['Core']['Twig']->render('user/account.html.twig', array( + return new Response($app['Core']['Twig']->render('account/account.html.twig', array( 'geonames' => new \geonames(), 'user' => $user, 'notice' => $notice, - 'inscriptions' => giveMeBases($user->get_id()), 'evt_mngr' => $evtMngr, 'notifications' => $evtMngr->list_notifications_available($user->get_id()), ))); diff --git a/lib/Alchemy/Phrasea/Controller/Root/Developers.php b/lib/Alchemy/Phrasea/Controller/Root/Developers.php new file mode 100644 index 0000000000..3aeb51cb4d --- /dev/null +++ b/lib/Alchemy/Phrasea/Controller/Root/Developers.php @@ -0,0 +1,416 @@ +before(function() use ($app) { + $app['Core']['Firewall']->requireAuthentication($app); + }); + + /** + * List of apps created by the user + * + * name : list_dev_apps + * + * description : Display form to create a new account + * + * method : GET + * + * parameters : none + * + * return : HTML Response + */ + $controllers->get('/applications/', $this->call('listApps')) + ->bind('list_dev_apps'); + + + + /** + * Get the form to create a new application + * + * name : form_dev_app + * + * description : Display form to create a new account + * + * method : GET + * + * parameters : none + * + * return : HTML Response + */ + $controllers->get('/application/new/', $this->call('displayFormApp')) + ->bind('form_dev_app'); + + /** + * Create a new app + * + * name : create_dev_app + * + * description : Display form to create a new account + * + * method : POST + * + * parameters : none + * + * return : HTML Response + */ + $controllers->post('/application/', $this->call('newApp')) + ->bind('create_dev_app'); + + + /** + * Get application information + * + * name : get_dev_app + * + * description : Display form to create a new account + * + * method : GET + * + * parameters : none + * + * return : HTML Response + */ + $controllers->get('/application/{id}/', $this->call('getApp')) + ->assert('id', '\d+') + ->bind('get_dev_app'); + + /** + * Delete application + * + * name : delete_dev_app + * + * description : Delete selected application + * + * method : GET + * + * parameters : none + * + * return : HTML Response + */ + $controllers->delete('/application/{id}/', $this->call('deleteApp')) + ->assert('id', '\d+') + ->bind('delete_dev_app'); + + /** + * Authorize application to use a grant password type, which allow end user to + * authenticate himself with their credentials (login/password) + * + * name : grant_password_auth + * + * description : Display form to create a new account + * + * method : POST + * + * parameters : none + * + * return : HTML Response + */ + $controllers->post('/application/{id}/authorize_grant_password/', $this->call('authorizeGrantpassword')) + ->assert('id', '\d+') + ->bind('grant_password_auth'); + + /** + * Renew access token + * + * name : renew_access_token + * + * description : Regenerate an access token for the current app linked to the authenticated user + * + * method : POST + * + * parameters : none + * + * return : HTML Response + */ + $controllers->post('/application/{id}/access_token/', $this->call('renewAccessToken')) + ->assert('id', '\d+') + ->bind('renew_access_token'); + + /** + * Renew access token + * + * name : renew_app_callback + * + * description : Regenerate an access token for the current app linked to the authenticated user + * + * method : POST + * + * parameters : none + * + * return : HTML Response + */ + $controllers->post('/application/{id}/callback/', $this->call('renewAppCallback')) + ->assert('id', '\d+') + ->bind('renew_app_callback'); + + return $controllers; + } + + /** + * Delete application + * + * @param Application $app A Silex application where the controller is mounted on + * @param Request $request The current request + * @param integer $id The application id + * + * @return Response + */ + public function deleteApp(Application $app, Request $request, $id) + { + if ( ! $request->isXmlHttpRequest() || ! array_key_exists($request->getMimeType('json'), array_flip($request->getAcceptableContentTypes()))) { + $app->abort(400, _('Bad request format, only JSON is allowed')); + } + + $error = false; + + try { + $clientApp = new \API_OAuth2_Application(\appbox::get_instance($app['Core']), $id); + $clientApp->delete(); + } catch (\Exception_NotFound $e) { + $error = true; + } + + return new JsonResponse(array('success' => ! $error)); + } + + /** + * Change application callback + * + * @param Application $app A Silex application where the controller is mounted on + * @param Request $request The current request + * @param integer $id The application id + * + * @return Response + */ + public function renewAppCallback(Application $app, Request $request, $id) + { + if ( ! $request->isXmlHttpRequest() || ! array_key_exists($request->getMimeType('json'), array_flip($request->getAcceptableContentTypes()))) { + $app->abort(400, _('Bad request format, only JSON is allowed')); + } + + $error = false; + + try { + $clientApp = new \API_OAuth2_Application(\appbox::get_instance($app['Core']), $id); + + if ($callback = $request->get("callback")) { + $clientApp->set_redirect_uri($callback); + } else { + $error = true; + } + } catch (\Exception_NotFound $e) { + $error = true; + } + + return new JsonResponse(array('success' => ! $error)); + } + + /** + * Authorize application to use a grant password type + * + * @param Application $app A Silex application where the controller is mounted on + * @param Request $request The current request + * @param integer $id The application id + * + * @return Response + */ + public function renewAccessToken(Application $app, Request $request, $id) + { + if ( ! $request->isXmlHttpRequest() || ! array_key_exists($request->getMimeType('json'), array_flip($request->getAcceptableContentTypes()))) { + $app->abort(400, _('Bad request format, only JSON is allowed')); + } + + $appbox = \appbox::get_instance($app['Core']); + $error = false; + $accessToken = null; + + try { + $clientApp = new \API_OAuth2_Application($appbox, $id); + $account = $clientApp->get_user_account($app['Core']->getAuthenticatedUser()); + + $token = $account->get_token(); + + if ($token instanceof \API_OAuth2_Token) { + $token->renew(); + } else { + $token = \API_OAuth2_Token::create($appbox, $account); + } + + $accessToken = $token->get_value(); + } catch (\Exception $e) { + $error = true; + } + + return new JsonResponse(array('success' => ! $error, 'token' => $accessToken)); + } + + /** + * Authorize application to use a grant password type + * + * @param Application $app A Silex application where the controller is mounted on + * @param Request $request The current request + * @param integer $id The application id + * + * @return Response + */ + public function authorizeGrantpassword(Application $app, Request $request, $id) + { + if ( ! $request->isXmlHttpRequest() || ! array_key_exists($request->getMimeType('json'), array_flip($request->getAcceptableContentTypes()))) { + $app->abort(400, _('Bad request format, only JSON is allowed')); + } + + $error = false; + + try { + $clientApp = new \API_OAuth2_Application(\appbox::get_instance($app['Core']), $id); + } catch (\Exception_NotFound $e) { + $error = true; + } + + $clientApp->set_grant_password((bool) $request->get('grant', false)); + + return new JsonResponse(array('success' => ! $error)); + } + + /** + * Create a new developer applications + * + * @param Application $app A Silex application where the controller is mounted on + * @param Request $request The current request + * + * @return Response + */ + public function newApp(Application $app, Request $request) + { + $error = false; + + if ($request->get("type") == "desktop") { + $form = new \API_OAuth2_Form_DevAppDesktop($app['request']); + } else { + $form = new \API_OAuth2_Form_DevAppInternet($app['request']); + } + + $violations = $app['validator']->validate($form); + + if ($violations->count() == 0) { + $error = true; + } + + if ($error) { + $application = \API_OAuth2_Application::create(\appbox::get_instance($app['Core']), $app['Core']->getAuthenticatedUser(), $form->getName()); + $application + ->set_description($form->getDescription()) + ->set_redirect_uri($form->getSchemeCallback() . $form->getCallback()) + ->set_type($form->getType()) + ->set_website($form->getSchemeWebsite() . $form->getWebsite()); + + return $app->redirect(sprintf('/developers/application/%d/', $application->get_id())); + } + + $var = array( + "violations" => $violations, + "form" => $form + ); + + return $app['Core']['Twig']->render('/developers/application.html.twig', $var); + } + + /** + * List of apps created by the user + * + * @param Application $app A Silex application where the controller is mounted on + * @param Request $request The current request + * + * @return Response + */ + public function listApps(Application $app, Request $request) + { + return $app['Core']['Twig']->render('developers/applications.html.twig', array( + "apps" => \API_OAuth2_Application::load_dev_app_by_user( + \appbox::get_instance($app['Core']), $app['Core']->getAuthenticatedUser() + ))); + } + + /** + * Display form application + * + * @param Application $app A Silex application where the controller is mounted on + * @param Request $request The current request + * + * @return Response + */ + public function displayFormApp(Application $app, Request $request) + { + return $app['Core']['Twig']->render('developers/application_form.html.twig', array( + "violations" => null, + 'form' => null, + 'request' => $request + )); + } + + /** + * Get application information + * + * @param Application $app A Silex application where the controller is mounted on + * @param Request $request The current request + * @param integer $id The application id + * + * @return Response + */ + public function getApp(Application $app, Request $request, $id) + { + $user = $app['Core']->getAuthenticatedUser(); + + try { + $client = new \API_OAuth2_Application(\appbox::get_instance($app['Core']), $id); + } catch (\Exception_NotFound $e) { + $app->abort(404); + } + + $token = $client->get_user_account($user)->get_token()->get_value(); + + return $app['Core']['Twig']->render('developers/application.html.twig', array( + "app" => $client, + "user" => $user, + "token" => $token + )); + } + + /** + * Prefix the method to call with the controller class name + * + * @param string $method The method to call + * @return string + */ + private function call($method) + { + return sprintf('%s::%s', __CLASS__, $method); + } +} diff --git a/lib/Alchemy/Phrasea/Security/Firewall.php b/lib/Alchemy/Phrasea/Security/Firewall.php index 2590eb07f7..e73185172e 100644 --- a/lib/Alchemy/Phrasea/Security/Firewall.php +++ b/lib/Alchemy/Phrasea/Security/Firewall.php @@ -7,6 +7,13 @@ class Firewall { + public function requireSetUp(Application $app) + { + if ( ! \setup::is_installed()) { + return $app->redirect("/setup/"); + } + } + public function requireAuthentication(Application $app) { if ($app['Core']->isAuthenticated()) { @@ -23,7 +30,7 @@ public function requireAuthentication(Application $app) } if ($app['Core']->getAuthenticatedUser()->is_guest()) { - + return $app->redirect('/login/'); } } diff --git a/lib/classes/API/OAuth2/Account.class.php b/lib/classes/API/OAuth2/Account.class.php index 09a65dec80..01ccb12b53 100644 --- a/lib/classes/API/OAuth2/Account.class.php +++ b/lib/classes/API/OAuth2/Account.class.php @@ -281,8 +281,9 @@ public static function load_with_user(appbox &$appbox, API_OAuth2_Application $a $row = $stmt->fetch(PDO::FETCH_ASSOC); $stmt->closeCursor(); - if ( ! $row) + if ( ! $row) { throw new Exception_NotFound(); + } return new self($appbox, $row['api_account_id']); } diff --git a/lib/classes/API/OAuth2/Application.class.php b/lib/classes/API/OAuth2/Application.class.php index ea09d36da1..b756786293 100644 --- a/lib/classes/API/OAuth2/Application.class.php +++ b/lib/classes/API/OAuth2/Application.class.php @@ -145,6 +145,11 @@ public function __construct(appbox &$appbox, $application_id) $stmt = $this->appbox->get_connection()->prepare($sql); $stmt->execute(array(':application_id' => $this->id)); + + if (0 === $stmt->rowCount()) { + throw new \Exception_NotFound(sprintf('Application with id %d not found', $this->id)); + } + $row = $stmt->fetch(PDO::FETCH_ASSOC); $stmt->closeCursor(); $this->creator = ! $row['creator'] ? null : User_Adapter::getInstance($row['creator'], $this->appbox); diff --git a/templates/web/account/access.html.twig b/templates/web/account/access.html.twig new file mode 100644 index 0000000000..d1471f0f4d --- /dev/null +++ b/templates/web/account/access.html.twig @@ -0,0 +1,168 @@ +{% extends 'account/base.html.twig' %} + +{% block content %} + +
 
+ + + + + + {% for sbasId, baseInsc in inscriptions %} + {% if baseInsc['CollsRegistered'] or baseInsc['CollsRefuse'] or baseInsc['CollsWait'] or baseInsc['CollsIntime'] or baseInsc['CollsOuttime'] or baseInsc['CollsNonactif'] or baseInsc['CollsCGU'] or baseInsc['Colls'] %} + + + + {% endif %} + + {% if baseInsc['CollsRegistered'] is not none %} + {% for base in baseInsc['CollsRegistered']%} + {% for collId, isTrue in base %} + {{ base_id == sbasId |base_from_coll(collId) }} + + + + {% endfor %} + {% endfor %} + + + + {% endif %} + + {% if baseInsc['CollsRefuse'] %} + {% for collId, isTrue in baseInsc['CollsRefuse'] %} + {{ base_id == sbasId |base_from_coll(collId) }} + + + + {% endfor %} + + + + {% endif %} + + {% if baseInsc['CollsWait'] %} + {% for collId, isTrue in baseInsc['CollsWait'] %} + {{ base_id == sbasId |base_from_coll(collId) }} + + + + {% endfor %} + + {% endif %} + + {% if baseInsc['CollsIntime'] %} + {% for collId, isTrue in baseInsc['CollsIntime'] %} + {{ base_id == sbasId |base_from_coll(collId) }} + + + + {% endfor %} + + {% endif %} + + {% if baseInsc['CollsOuttime'] %} + {% for collId, isTrue in baseInsc['CollsOuttime'] %} + {{ base_id == sbasId |base_from_coll(collId) }} + + + + {% endfor %} + + {% endif %} + + {% if baseInsc['CollsNonactif'] %} + {% for collId, isTrue in baseInsc['CollsNonactif'] %} + {{ base_id == (sbasId |base_from_coll(collId)) }} + + + + {% endfor %} + + {% endif %} + + {% if (baseInsc['CollsCGU'] or baseInsc['Colls']) and baseInsc['inscript'] %} + {{ noDemand == false }} + {% if baseInsc['Colls'] %} + {% if baseInsc['CGU'] %} + + + + + + + {% endif %} + {% for collId, collName in baseInsc['Colls'] %} + {{ base_id == sbasId |base_from_coll(collId) }} + + + + + + {% endfor %} + {% endif %} + {% if baseInsc['CollsCGU'] %} + {% for collId, collDesc in baseInsc['CollsCGU'] %} + {{ base_id == sbasId |base_from_coll(collId) }} + + + + + + + + + + + + + + + {% endfor %} + {% endif %} + {% endif %} + {% endfor %} +
   

{{ sbasId | sbas_names }}

+ {% trans 'login::register: acces authorise sur la collection ' %}{{ sbasId |sbas_names }} + {% if isTrue | trim != '' %} + {% trans 'login::register::CGU: lire les CGU' %} + {% endif %} +
+
+ {% trans 'login::register: acces refuse sur la collection ' %}{{ sbasId |sbas_names }} + {% if isTrue | trim != '' %} + {% trans 'login::register::CGU: lire les CGU' %} + {% endif %} +
+
+ {% trans 'login::register: en attente d\'acces sur' %} {{ sbasId |sbas_names }} + {% if isTrue | trim != '' %} + {% trans 'login::register::CGU: lire les CGU' %} + {% endif %} +
+ {% trans 'login::register: acces temporaire sur' %} {{ sbasId |sbas_names }} + {% if isTrue |trim != '' %} + {% trans 'login::register::CGU: lire les CGU' %} + {% endif %} +
+ {% trans 'login::register: acces temporaire termine sur ' %}{{ sbasId |sbas_names }} + {% if isTrue |trim != '' %} + {% trans 'login::register::CGU: lire les CGU' %} + {% endif %} +
+ {% trans 'login::register: acces supendu sur' %} {{ sbasId |sbas_names }} + {% if isTrue |trim != '' %} + {% trans 'login::register::CGU: lire les CGU' %} + {% endif %} +
{% trans 'login::register: L\'acces aux bases ci-dessous implique l\'acceptation des Conditions Generales d\'Utilisation (CGU) suivantes' %}
{{ baseInsc['CGU'] }}
{{ collName }} + + {% trans 'login::register: Faire une demande d\'acces' %} +

{% trans 'login::register: L\'acces aux bases ci-dessous implique l\'acceptation des Conditions Generales d\'Utilisation (CGU) suivantes' %}
+
{{ collDesc['CGU'] }}
+
{{ collDesc['name'] }} + + {% trans 'login::register: Faire une demande d\'acces' %} +
+ + +{% endblock %} \ No newline at end of file diff --git a/templates/web/account/account.html.twig b/templates/web/account/account.html.twig new file mode 100644 index 0000000000..f7e7d661b6 --- /dev/null +++ b/templates/web/account/account.html.twig @@ -0,0 +1,220 @@ +{% extends 'account/base.html.twig' %} + +{% block head %} + + +{% endblock %} + +{% block content %} + + + + +
+ {% if notice | trim != '' %} +
{{ notice }}
+ {% endif %} +
+
+ + {% trans 'Informations personnelles' %} + +
+ +
+

{{ user.get_login() }}

+

+
+
+
+ +
+ +

+
+
+
+ +
+ +

+
+
+
+ +
+ +

+
+
+
+ + +
+
+ +
+ +

+
+
+
+ +
+ +

+
+
+
+ +
+ +

+
+
+
+ +
+
+

+
+
+
+ +
+ +

+
+
+
+ +
+ +

+
+
+
+ +
+ +

+
+
+
+ +
+ +

+
+
+
+ +
+ +

+
+
+ + {% trans 'Notification par email' %} + {% for notification_group, nots in notifications%} +

{{ notification_group }}

+ {% for notification in nots %} +
+ +
+ +

+
+
+ {% endfor %} + {% endfor %} + + {% trans 'FTP' %} +
+ +
+ +

+
+
+
+
+ +
+ +

+
+
+
+ +
+ +

+
+
+
+ +
+ +

+
+
+
+ +
+ +

+
+
+
+ +
+ +

+
+
+
+ +
+ +

+
+
+
+ +
+ +

+
+
+
+ +
+ +
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/templates/web/account/authorized_apps.html.twig b/templates/web/account/authorized_apps.html.twig new file mode 100644 index 0000000000..d24dee9edc --- /dev/null +++ b/templates/web/account/authorized_apps.html.twig @@ -0,0 +1,107 @@ +{% extends 'account/base.html.twig' %} + +{% block head %} + +{% endblock %} +{% block content %} + + + + + + + +
+
+

{% trans 'Vous avez autorise ces applications a acceder a votre compte' %}

+ {% if apps|length > 0 %} +
    + {% for app in apps %} +
  • +
    + {% set account = app.get_user_account(user) %} + {% if account.is_revoked() is empty %} + + {% else %} + + {% endif %} + + + {{app.get_name()}} + + {% if user is not none %} + {% set user_name = app.get_creator().get_display_name() %} + {% trans %} + par {{user_name}} + {% endtrans %} + {% endif%} + + + {{app.get_created_on()|prettyDate}} + + {{app.get_description() }} +
    +
  • + {%endfor%} +
+ {% else %} +
+ {% trans 'Aucune application n\'a accés à vos données.' %} +
+ {% endif %} +
+
+
+

{% trans 'Applications' %}

+

+ {% trans 'Naviguez et gerez les applications que vous souhaitez autoriser a acceder a vos informations Phraseanet' %} +

+

{% trans 'Developpeurs' %}

+

+ {% trans 'Les developpeurs peuvent editer l\'enregistrement de leurs application grace a l\'onglet "developpeurs" ci-dessus' %} +

+
+
+{% endblock %} \ No newline at end of file diff --git a/templates/web/account/base.html.twig b/templates/web/account/base.html.twig new file mode 100644 index 0000000000..18aadc36be --- /dev/null +++ b/templates/web/account/base.html.twig @@ -0,0 +1,44 @@ + + + {{ registry.get('GV_homeTitle') }} {% trans 'login:: Mon compte'%} + + + + + {% block head %}{% endblock %} + + + +
+
+ + + + + +
+ {{ registry.get('GV_homeTitle') }} + {% trans 'login:: Mon compte' %} + +
+
+
+ +
+ © Copyright Alchemy 2005-{{ "now"|date("Y") }} +
+
+
+ + diff --git a/templates/web/account/sessions.html.twig b/templates/web/account/sessions.html.twig new file mode 100644 index 0000000000..1af4b95bc5 --- /dev/null +++ b/templates/web/account/sessions.html.twig @@ -0,0 +1,67 @@ +{% extends 'account/base.html.twig' %} + +{% block content %} +
+ + + + + + + + + + + + + + + + + {% for row in session.get_my_sessions() %} + + + + + + + + + + {% endfor %} + +
+ {% trans 'Mes sessions' %} +
+ + {% trans 'Date de connexion' %} + + {% trans 'Dernier access' %} + + {% trans 'IP' %} + + {% trans 'Browser' %} + + {% trans 'ecran' %} + + {% trans 'Session persistante' %} +
+ {% if session.get_ses_id() != row['session_id'] %} + + {% endif %} + + {{ row['created_on'] |getDate }} + + {{ row['lastaccess'] |getDate }} + + {{ row['ip'] }} + {{ row['ip_infos'] }} + + {{ row['browser'] }} {{ row['browser_version'] }} + + {{ row['screen'] }} + + {% if row['token'] %}oui{% endif %} +
+
+{% endblock %} \ No newline at end of file diff --git a/templates/web/developers/application.html.twig b/templates/web/developers/application.html.twig new file mode 100644 index 0000000000..7091ac0708 --- /dev/null +++ b/templates/web/developers/application.html.twig @@ -0,0 +1,90 @@ +{% extends 'account/base.html.twig' %} + +{% use "developers/header.html.twig" with header as parent_header %} + +{% block head %} + {{ block('parent_header') }} +{% endblock %} + +{% block content %} + +

{% trans 'Application' %}

+ +
+ +
+

{% trans 'settings OAuth' %}

+

{% trans 'Les parametres oauth de votre application.' %}

+ + + + + + + + + + + + + {% if app.get_type == constant('API_OAuth2_Application::DESKTOP_TYPE') %} + + {% else %} + + {%endif%} + + + + + + + + + + + + + + +
Client ID{{app.get_client_id}}
Client Secret{{app.get_client_secret}}
{% trans 'URL de callback' %} + {{app.get_redirect_uri}} + {{app.get_redirect_uri}} + + +
Authorize endpoint{{registry.get('GV_ServerName')}}api/oauthv2/authorize
Access endpoint{{registry.get('GV_ServerName')}}api/oauthv2/token
{% trans 'Activer le grant_type de type password pour votre application' %}
+ +

{% trans 'Votre token d\'access' %}

+

{% trans 'Les paramétres oauth de votre application.' %}

+ + + + + + + + + + + +
+ {% trans 'Token' %} + + + {% if not token is none %} + {{token|default('')}} + {% else %} + {% trans 'Le token n\'a pas encore ete genere' %} + {% endif %} + +
+
+ +
+{% endblock %} diff --git a/templates/web/developers/application_form.html.twig b/templates/web/developers/application_form.html.twig new file mode 100644 index 0000000000..ae62a9a555 --- /dev/null +++ b/templates/web/developers/application_form.html.twig @@ -0,0 +1,105 @@ +{% extends 'account/base.html.twig' %} + +{% use "developers/header.html.twig" with header as parent_header %} + +{% block head %} + {{ block('parent_header') }} +{% endblock %} + +{# form input macro #} +{% macro input(name, value, violations, property, type, size) %} + {% if violations is none %} + + {% else %} + {% set hasError = "false" %} + {% for violation in violations %} + {% if violation.getPropertyPath == property and hasError == "false" %} + {% set hasError = "true" %} + +
{{ violation.getInvalidValue }} - {{violation.getMessage}}
+ {% endif %} + {% endfor %} + {% if hasError == "false" %} + + {% endif %} + {% endif %} +{% endmacro %} + +{# form textare macro #} +{% macro textarea(name, value, violations,property, rows, cols) %} + {% if violations is none %} + + {% else %} + {% set hasError = "false" %} + {% for violation in violations %} + {% if violation.getPropertyPath == property and hasError == "false" %} + {% set hasError = "true" %} + +
{{violation.getMessage}}
+ {% endif %} + {% endfor %} + {% if hasError == "false" %} + + {% endif %} + {% endif %} +{% endmacro %} + +{% block content %} +
+ {% if form is none %} + {% set name, description, website, callback = '', '', '', ''%} + {% set app_type = 'web'%} + {% else %} + {% set name = form.name %} + {% set description = form.description %} + {% set website = form.website %} + {% set callback = form.callback %} + {% set app_type = form.type %} + {% endif %} + + + + + + + + + + + + + + + + + + {% if app_type == "web" %} + + + + + {% endif %} + + + +
{{ _self.input("name", name, violations, 'name') }}
{{ _self.textarea("description", description, 'description', violations, 5, 17) }}
+ + {{ _self.input("website", website, violations, 'urlwebsite') }}
{% trans 'Application web' %} + + {% trans 'Application desktop' %} +
+ + {{ _self.input("callback", callback, violations, 'urlcallback') }}
+
+
+ +
+{% endblock %} diff --git a/templates/web/developers/applications.html.twig b/templates/web/developers/applications.html.twig new file mode 100644 index 0000000000..0f9c67e725 --- /dev/null +++ b/templates/web/developers/applications.html.twig @@ -0,0 +1,62 @@ +{% extends 'account/base.html.twig' %} + +{% use "developers/header.html.twig" with header as parent_header %} + +{% block head %} + {{ block('parent_header') }} +{% endblock %} + +{% block content %} + + + + + + + +
+
+

Phraseanet Developper Center

+

{% trans 'Mes applications' %}

+ {% if apps|length > 0 %} +
    + {% for app in apps %} +
  • +
    + + + + + {{app.get_name()}} + + + + {{app.get_description() }} + {{app.get_website()}} +
    +
  • + {%endfor%} +
+ {% else %} +
+ {% trans 'Aucune application creee.' %} +
+ {% endif %} +
+
+
+
+ + +
+ {% trans 'Decouvrez la documentation' %} +
+
+ + +
+ {% trans 'Creez une application pour commencer a utiliser l\'API Phraseanet' %} +
+
+
+{% endblock %} \ No newline at end of file diff --git a/templates/web/developers/header.html.twig b/templates/web/developers/header.html.twig new file mode 100644 index 0000000000..519ebe6d2f --- /dev/null +++ b/templates/web/developers/header.html.twig @@ -0,0 +1,177 @@ +{% block header %} + +{% endblock %} \ No newline at end of file diff --git a/templates/web/user/account.html.twig b/templates/web/user/account.html.twig deleted file mode 100644 index 43fd36a3d1..0000000000 --- a/templates/web/user/account.html.twig +++ /dev/null @@ -1,724 +0,0 @@ - - - {{ registry.get('GV_homeTitle') }} {% trans 'login:: Mon compte'%} - - - - - - - - - - -
-
- - - - - -
{{ registry.get('GV_homeTitle') }}{% trans 'login:: Mon compte' %} -
-
-
-
-
- - -
- - - - -
- {% if notice | trim != '' %} -
{{ notice }}
- {% endif %} -
-
- - {% trans 'Informations personnelles' %} - -
- -
-

{{ user.get_login() }}

-

-
-
-
- -
- -

-
-
-
- -
- -

-
-
-
- -
- -

-
-
-
- - -
-
- -
- -

-
-
-
- -
- -

-
-
-
- -
- -

-
-
-
- -
-
-

-
-
-
- -
- -

-
-
-
- -
- -

-
-
-
- -
- -

-
-
-
- -
- -

-
-
-
- -
- -

-
-
- - {% trans 'Notification par email' %} - {% for notification_group, nots in notifications%} -

{{ notification_group }}

- {% for notification in nots %} -
- -
- -

-
-
- {% endfor %} - {% endfor %} - - {% trans 'FTP' %} -
- -
- -

-
-
-
-
- -
- -

-
-
-
- -
- -

-
-
-
- -
- -

-
-
-
- -
- -

-
-
-
- -
- -

-
-
-
- -
- -

-
-
-
- -
- -

-
-
-
- -
- -
-
-
-
-
- - -
-
- - - - - - - {% for sbasId, baseInsc in inscriptions %} - {% if baseInsc['CollsRegistered'] or baseInsc['CollsRefuse'] or baseInsc['CollsWait'] or baseInsc['CollsIntime'] or baseInsc['CollsOuttime'] or baseInsc['CollsNonactif'] or baseInsc['CollsCGU'] or baseInsc['Colls'] %} - - - - {% endif %} - - {% if baseInsc['CollsRegistered'] is not none %} - {% for base in baseInsc['CollsRegistered']%} - {% for collId, isTrue in base %} - {{ base_id == sbasId |base_from_coll(collId) }} - - - - {% endfor %} - {% endfor %} - - - - {% endif %} - - {% if baseInsc['CollsRefuse'] %} - {% for collId, isTrue in baseInsc['CollsRefuse'] %} - {{ base_id == sbasId |base_from_coll(collId) }} - - - - {% endfor %} - - - - {% endif %} - - {% if baseInsc['CollsWait'] %} - {% for collId, isTrue in baseInsc['CollsWait'] %} - {{ base_id == sbasId |base_from_coll(collId) }} - - - - {% endfor %} - - {% endif %} - - {% if baseInsc['CollsIntime'] %} - {% for collId, isTrue in baseInsc['CollsIntime'] %} - {{ base_id == sbasId |base_from_coll(collId) }} - - - - {% endfor %} - - {% endif %} - - {% if baseInsc['CollsOuttime'] %} - {% for collId, isTrue in baseInsc['CollsOuttime'] %} - {{ base_id == sbasId |base_from_coll(collId) }} - - - - {% endfor %} - - {% endif %} - - {% if baseInsc['CollsNonactif'] %} - {% for collId, isTrue in baseInsc['CollsNonactif'] %} - {{ base_id == (sbasId |base_from_coll(collId)) }} - - - - {% endfor %} - - {% endif %} - - {% if (baseInsc['CollsCGU'] or baseInsc['Colls']) and baseInsc['inscript'] %} - {{ noDemand == false }} - {% if baseInsc['Colls'] %} - {% if baseInsc['CGU'] %} - - - - - - - {% endif %} - {% for collId, collName in baseInsc['Colls'] %} - {{ base_id == sbasId |base_from_coll(collId) }} - - - - - - {% endfor %} - {% endif %} - {% if baseInsc['CollsCGU'] %} - {% for collId, collDesc in baseInsc['CollsCGU'] %} - {{ base_id == sbasId |base_from_coll(collId) }} - - - - - - - - - - - - - - - {% endfor %} - {% endif %} - {% endif %} - {% endfor %} -
   

{{ sbasId | sbas_names }}

- {% trans 'login::register: acces authorise sur la collection ' %}{{ sbasId |sbas_names }} - {% if isTrue | trim != '' %} - {% trans 'login::register::CGU: lire les CGU' %} - {% endif %} -
-
- {% trans 'login::register: acces refuse sur la collection ' %}{{ sbasId |sbas_names }} - {% if isTrue | trim != '' %} - {% trans 'login::register::CGU: lire les CGU' %} - {% endif %} -
-
- {% trans 'login::register: en attente d\'acces sur' %} {{ sbasId |sbas_names }} - {% if isTrue | trim != '' %} - {% trans 'login::register::CGU: lire les CGU' %} - {% endif %} -
- {% trans 'login::register: acces temporaire sur' %} {{ sbasId |sbas_names }} - {% if isTrue |trim != '' %} - {% trans 'login::register::CGU: lire les CGU' %} - {% endif %} -
- {% trans 'login::register: acces temporaire termine sur ' %}{{ sbasId |sbas_names }} - {% if isTrue |trim != '' %} - {% trans 'login::register::CGU: lire les CGU' %} - {% endif %} -
- {% trans 'login::register: acces supendu sur' %} {{ sbasId |sbas_names }} - {% if isTrue |trim != '' %} - {% trans 'login::register::CGU: lire les CGU' %} - {% endif %} -
{% trans 'login::register: L\'acces aux bases ci-dessous implique l\'acceptation des Conditions Generales d\'Utilisation (CGU) suivantes' %}
{{ baseInsc['CGU'] }}
{{ collName }} - - {% trans 'login::register: Faire une demande d\'acces' %} -

{% trans 'login::register: L\'acces aux bases ci-dessous implique l\'acceptation des Conditions Generales d\'Utilisation (CGU) suivantes' %}
-
{{ collDesc['CGU'] }}
-
{{ collDesc['name'] }} - - {% trans 'login::register: Faire une demande d\'acces' %} -
- -
-
- - -
- - - - - - - - - - - - - - - - - {% for row in session.get_my_sessions() %} - - - - - - - - - - {% endfor %} - -
- {% trans 'Mes sessions' %} -
- - {% trans 'Date de connexion' %} - - {% trans 'Dernier access' %} - - {% trans 'IP' %} - - {% trans 'Browser' %} - - {% trans 'ecran' %} - - {% trans 'Session persistante' %} -
- {% if session.get_ses_id() != row['session_id'] %} - - {% endif %} - - {{ row['created_on'] |getDate }} - - {{ row['lastaccess'] |getDate }} - - {{ row['ip'] }} - {{ row['ip_infos'] }} - - {{ row['browser'] }} {{ row['browser_version'] }} - - {{ row['screen'] }} - - {% if row['token'] %}oui{% endif %} -
-
- - -
- - -
- -
-
-
- © Copyright Alchemy 2005-{{ "now"|date("Y") }} -
-
-
- - diff --git a/www/.htaccess b/www/.htaccess index 211328fe0b..9285d7bef0 100644 --- a/www/.htaccess +++ b/www/.htaccess @@ -47,6 +47,8 @@ RewriteRule ^robots.txt$ /index.php [L] RewriteRule ^feeds/.*$ /index.php [L] + RewriteRule ^account/.*$ /index.php [L] + RewriteRule ^developers/.*$ /index.php [L] # RewriteRule ^atom\/(cooliris)+\/?([0-9]*)\/?$ /cooliris.php?item_id=$2 [L] diff --git a/www/skins/login/css/main.css b/www/skins/login/css/main.css index 69ea5b1a36..bb5b9d748d 100644 --- a/www/skins/login/css/main.css +++ b/www/skins/login/css/main.css @@ -49,3 +49,9 @@ label { legend + .control-group { margin-top: 10px; } + +#id-main .account-menu li { + display: inline-block; + width:130px; + font-size:16px; +} \ No newline at end of file From ed8db3307cf46dfa90306c3036cbfc13098f663b Mon Sep 17 00:00:00 2001 From: Nicolas Le Goff Date: Fri, 13 Jul 2012 17:15:19 +0200 Subject: [PATCH 7/9] Update doc blocks --- .../Phrasea/Controller/Root/Developers.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Root/Developers.php b/lib/Alchemy/Phrasea/Controller/Root/Developers.php index 3aeb51cb4d..a851c39655 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/Developers.php +++ b/lib/Alchemy/Phrasea/Controller/Root/Developers.php @@ -38,7 +38,7 @@ public function connect(Application $app) * * name : list_dev_apps * - * description : Display form to create a new account + * description : List all user applications * * method : GET * @@ -56,7 +56,7 @@ public function connect(Application $app) * * name : form_dev_app * - * description : Display form to create a new account + * description : Display form to create a new user application * * method : GET * @@ -72,7 +72,7 @@ public function connect(Application $app) * * name : create_dev_app * - * description : Display form to create a new account + * description : POST request to create a new user app * * method : POST * @@ -89,7 +89,7 @@ public function connect(Application $app) * * name : get_dev_app * - * description : Display form to create a new account + * description : Get application information * * method : GET * @@ -119,12 +119,12 @@ public function connect(Application $app) ->bind('delete_dev_app'); /** - * Authorize application to use a grant password type, which allow end user to - * authenticate himself with their credentials (login/password) + * Allow authentification paswword grant method * * name : grant_password_auth * - * description : Display form to create a new account + * description : Authorize application to use a grant password type, which allow end user to + * authenticate himself with their credentials (login/password) * * method : POST * @@ -154,11 +154,11 @@ public function connect(Application $app) ->bind('renew_access_token'); /** - * Renew access token + * Update application callback * * name : renew_app_callback * - * description : Regenerate an access token for the current app linked to the authenticated user + * description : Change callback used by application * * method : POST * From 82dce9b93b3c983039f478b48fa9f2072b9522c8 Mon Sep 17 00:00:00 2001 From: Nicolas Le Goff Date: Fri, 13 Jul 2012 19:29:43 +0200 Subject: [PATCH 8/9] add /forgot-password/ & rename route name to be consistent --- .../Phrasea/Controller/Root/Account.php | 197 ++++++++++++++++-- .../Phrasea/Controller/Root/Developers.php | 32 +-- .../forgot-password.html.twig} | 73 +++---- .../web/developers/applications.html.twig | 2 +- 4 files changed, 235 insertions(+), 69 deletions(-) rename templates/web/{user/forgotpwd.html.twig => account/forgot-password.html.twig} (73%) diff --git a/lib/Alchemy/Phrasea/Controller/Root/Account.php b/lib/Alchemy/Phrasea/Controller/Root/Account.php index 22dfc7b93f..ddb704f331 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/Account.php +++ b/lib/Alchemy/Phrasea/Controller/Root/Account.php @@ -36,7 +36,7 @@ public function connect(Application $app) /** * New account route * - * name : display_account + * name : get_account * * description : Display form to create a new account * @@ -47,12 +47,12 @@ public function connect(Application $app) * return : HTML Response */ $controllers->get('/', $this->call('displayAccount')) - ->bind('display_account'); + ->bind('get_account'); /** * Create account route * - * name : update_account + * name : create_account * * description : update your account informations * @@ -92,7 +92,40 @@ public function connect(Application $app) * return : HTML Response */ $controllers->post('/', $this->call('updateAccount')) - ->bind('update_account'); + ->bind('create_account'); + + + /** + * Forgot password + * + * name : account_forgot_password + * + * description : Display form to renew password + * + * method : GET + * + * parameters : none + * + * return : HTML Response + */ + $controllers->get('/forgot-password/', $this->call('displayForgotPasswordForm')) + ->bind('account_forgot_password'); + + /** + * Renew password + * + * name : account_renew_password + * + * description : Register the new user password + * + * method : POST + * + * parameters : none + * + * return : HTML Response + */ + $controllers->post('/forgot-password/', $this->call('renewPassword')) + ->bind('post_account_forgot_password'); /** * Give account access @@ -113,7 +146,7 @@ public function connect(Application $app) /** * Give account open sessions * - * name : account_sessions + * name : account_security_sessions * * description : Display form to create a new account * @@ -124,12 +157,12 @@ public function connect(Application $app) * return : HTML Response */ $controllers->get('/security/sessions/', $this->call('accountSessionsAccess')) - ->bind('account_sessions'); + ->bind('account_security_sessions'); /** * Give authorized applications that can access user informations * - * name : account_auth_apps + * name : account_security_applications * * description : Display form to create a new account * @@ -140,12 +173,12 @@ public function connect(Application $app) * return : HTML Response */ $controllers->get('/security/applications/', $this->call('accountAuthorizedApps')) - ->bind('account_auth_apps'); + ->bind('account_security_applications'); /** * Grant access to an authorized app * - * name : grant_app_access + * name : account_security_applications_grant * * description : Display form to create a new account * @@ -157,11 +190,151 @@ public function connect(Application $app) */ $controllers->get('/security/application/{application_id}/grant/', $this->call('grantAccess')) ->assert('application_id', '\d+') - ->bind('grant_app_access'); + ->bind('account_security_applications_grant'); return $controllers; } + /** + * Submit the new password + * + * @param Application $app A Silex application where the controller is mounted on + * @param Request $request The current request + * @return Response + */ + public function renewPassword(Application $app, Request $request) + { + $appbox = \appbox::get_instance($app['Core']); + + // send mail + if ('' !== $mail = trim($request->get('mail', ''))) { + if ( ! \PHPMailer::ValidateAddress($mail)) { + return $app->redirect('/account/forgot-password/?error=invalidmail'); + } + + try { + $user = \User_Adapter::getInstance(\User_Adapter::get_usr_id_from_email($mail), $appbox); + } catch (\Exception $e) { + return $app->redirect('/account/forgot-password/?error=noaccount'); + } + + $token = \random::getUrlToken(\random::TYPE_PASSWORD, $user->get_id(), new \DateTime('+1 day')); + + if ($token) { + $url = sprintf('%slogin/forgotpwd.php?token=%s', $app['Registry']->get('GV_ServerName'), $token); + + if (\mail::forgot_passord($email, $user->get_login(), $url)) { + return $app->redirect('/account/forgot-password/?sent=ok'); + } else { + return $app->redirect('/account/forgot-password/?error=mailserver'); + } + } + + return $app->redirect('/account/forgot-password/?error=noaccount'); + } + + if (null !== $token = $request->get('token') + && null !== $password = $request->get('form_password') + && null !== $passwordConfirm = $request->get('form_password_confirm')) { + + if ($password !== $passwordConfirm) { + + return $app->redirect('/account/forgot-password/?pass-error=pass-match'); + } elseif (strlen(trim($password)) < 5) { + + return $app->redirect('/account/forgot-password/?pass-error=pass-short'); + } elseif (trim($password) != str_replace(array("\r\n", "\n", "\r", "\t", " "), "_", $password)) { + + return $app->redirect('/account/forgot-password/?pass-error=pass-invalid'); + } + + try { + $datas = \random::helloToken($token); + + $user = \User_Adapter::getInstance($datas['usr_id'], $appbox); + $user->set_password($passwordConfirm); + + \random::removeToken($token); + + return $app->redirect('/login/?confirm=password-update-ok'); + } catch (\Exception_NotFound $e) { + + } + } + } + + /** + * Get the fogot password form + * + * @param Application $app A Silex application where the controller is mounted on + * @param Request $request The current request + * @return Response + */ + public function displayForgotPasswordForm(Application $app, Request $request) + { + $tokenize = false; + $errorMsg = $request->get('error'); + + if (null !== $token = $request->get('token')) { + try { + \random::helloToken($token); + $tokenize = true; + } catch (\Exception $e) { + $errorMsg = 'token'; + } + } + + if (null !== $errorMsg) { + switch ($errorMsg) { + case 'invalidmail': + $errorMsg = _('Invalid email address'); + break; + case 'mailserver': + $errorMsg = _('phraseanet::erreur: Echec du serveur mail'); + break; + case 'noaccount': + $errorMsg = _('phraseanet::erreur: Le compte n\'a pas ete trouve'); + break; + case 'mail': + $errorMsg = _('phraseanet::erreur: Echec du serveur mail'); + break; + case 'token': + $errorMsg = _('phraseanet::erreur: l\'url n\'est plus valide'); + break; + } + } + + if (null !== $sentMsg = $request->get('sent')) { + switch ($sentMsg) { + case 'ok': + $sentMsg = _('phraseanet:: Un email vient de vous etre envoye'); + break; + } + } + + if (null !== $passwordMsg = $request->get('pass-error')) { + switch ($sentMsg) { + case 'pass-match': + $sentMsg = _('forms::les mots de passe ne correspondent pas'); + break; + case 'pass-short': + $sentMsg = _('forms::la valeur donnee est trop courte'); + break; + case 'pass-invalid': + $sentMsg = _('forms::la valeur donnee contient des caracteres invalides'); + break; + } + } + + return new Response($app['Core']['Twig']->render('account/forgot-password.html.twig', array( + 'needed' => array(), + 'tokenize' => $tokenize, + 'passwordMsg' => $passwordMsg, + 'errorMsg' => $errorMsg, + 'sentMsg' => $sentMsg + ))); + } + /** * Display authorized applications that can access user informations * @@ -237,10 +410,8 @@ public function accountAccess(Application $app, Request $request) { require_once $app['Core']['Registry']->get('GV_RootPath') . 'lib/classes/deprecated/inscript.api.php'; - $user = $app['Core']->getAuthenticatedUser(); - return new Response($app['Core']['Twig']->render('account/access.html.twig', array( - 'inscriptions' => giveMeBases($user->get_id()) + 'inscriptions' => giveMeBases($app['Core']->getAuthenticatedUser()->get_id()) ))); } diff --git a/lib/Alchemy/Phrasea/Controller/Root/Developers.php b/lib/Alchemy/Phrasea/Controller/Root/Developers.php index a851c39655..1b4c9e5c58 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/Developers.php +++ b/lib/Alchemy/Phrasea/Controller/Root/Developers.php @@ -36,7 +36,7 @@ public function connect(Application $app) /** * List of apps created by the user * - * name : list_dev_apps + * name : developers_applications * * description : List all user applications * @@ -47,14 +47,14 @@ public function connect(Application $app) * return : HTML Response */ $controllers->get('/applications/', $this->call('listApps')) - ->bind('list_dev_apps'); + ->bind('developers_applications'); /** * Get the form to create a new application * - * name : form_dev_app + * name : developers_application_new * * description : Display form to create a new user application * @@ -65,12 +65,12 @@ public function connect(Application $app) * return : HTML Response */ $controllers->get('/application/new/', $this->call('displayFormApp')) - ->bind('form_dev_app'); + ->bind('developers_application_new'); /** * Create a new app * - * name : create_dev_app + * name : developers_application * * description : POST request to create a new user app * @@ -81,13 +81,13 @@ public function connect(Application $app) * return : HTML Response */ $controllers->post('/application/', $this->call('newApp')) - ->bind('create_dev_app'); + ->bind('developers_application'); /** * Get application information * - * name : get_dev_app + * name : developers_application * * description : Get application information * @@ -99,12 +99,12 @@ public function connect(Application $app) */ $controllers->get('/application/{id}/', $this->call('getApp')) ->assert('id', '\d+') - ->bind('get_dev_app'); + ->bind('developers_application'); /** * Delete application * - * name : delete_dev_app + * name : delete_developers_application * * description : Delete selected application * @@ -116,12 +116,12 @@ public function connect(Application $app) */ $controllers->delete('/application/{id}/', $this->call('deleteApp')) ->assert('id', '\d+') - ->bind('delete_dev_app'); + ->bind('delete_developers_application'); /** * Allow authentification paswword grant method * - * name : grant_password_auth + * name : developers_application_authorize_grant_password * * description : Authorize application to use a grant password type, which allow end user to * authenticate himself with their credentials (login/password) @@ -134,12 +134,12 @@ public function connect(Application $app) */ $controllers->post('/application/{id}/authorize_grant_password/', $this->call('authorizeGrantpassword')) ->assert('id', '\d+') - ->bind('grant_password_auth'); + ->bind('developers_application_authorize_grant_password'); /** * Renew access token * - * name : renew_access_token + * name : developers_application_token * * description : Regenerate an access token for the current app linked to the authenticated user * @@ -151,12 +151,12 @@ public function connect(Application $app) */ $controllers->post('/application/{id}/access_token/', $this->call('renewAccessToken')) ->assert('id', '\d+') - ->bind('renew_access_token'); + ->bind('developers_application_token'); /** * Update application callback * - * name : renew_app_callback + * name : application_callback * * description : Change callback used by application * @@ -168,7 +168,7 @@ public function connect(Application $app) */ $controllers->post('/application/{id}/callback/', $this->call('renewAppCallback')) ->assert('id', '\d+') - ->bind('renew_app_callback'); + ->bind('application_callback'); return $controllers; } diff --git a/templates/web/user/forgotpwd.html.twig b/templates/web/account/forgot-password.html.twig similarity index 73% rename from templates/web/user/forgotpwd.html.twig rename to templates/web/account/forgot-password.html.twig index 085ecac13a..75844f8a3d 100644 --- a/templates/web/user/forgotpwd.html.twig +++ b/templates/web/account/forgot-password.html.twig @@ -9,7 +9,7 @@
- + @@ -45,10 +45,14 @@ $("#password-reset").validate( { rules: { - + form_password_confirm: { + required:true + } }, messages: { - + form_password_confirm : { + equalTo:'{% trans 'forms::les mots de passe ne correspondent pas' %}' + } }, errorPlacement: function(error, element) { error.prependTo( element.parent().parent().next().find('.form_alert') ); @@ -56,21 +60,27 @@ } ); - $('#form_password').rules("add",{password: "#form_login"}); - $('#form_password_confirm').rules("add",{equalTo: "#form_password"}); + $('#form_password').rules("add",{ + password: "#form_login" + }); + + $('#form_password_confirm').rules("add",{ + equalTo: "#form_password" + }); + $("#form_password").valid(); }); - {% if parm['salt'] %} + {% if app.request.get('salt') %}
{% trans 'Pour ameliorer la securite de l\'application, vous devez mettre a jour votre mot de passe.' %}
{% trans 'Cette tache ne pouvant etre automatisee, merci de bien vouloir la realiser.' %}
{% endif %} - +
get('GV_homeTitle') ?>
{{ registry.get('GV_homeTitle') }}
@@ -81,7 +91,9 @@
- + {% if passwordMsg is not none %} + {{ passwordMsg }} + {% endif %}
 
@@ -101,18 +113,20 @@
- + {% if passwordMsg is not none %} + {{ passwordMsg }} + {% endif %}
- + - {% trans 'login:: Retour a l\'accueil' %} + {% trans 'login:: Retour a l\'accueil' %}
@@ -120,35 +134,16 @@ {% endif %} - {% if tokenError %} - {% set parm = {'error': 'token'} %} - {% endif %} - - {% if not tokenize and not tokenError %} - - {% if not parm['error'] == null %} - switch ($parm['error']) { - case 'mailserver': - echo '
{% trans 'phraseanet::erreur: Echec du serveur mail' %}
- break; - case 'noaccount': - echo '
{% trans 'phraseanet::erreur: Le compte n\'a pas ete trouve' %}
- break; - case 'mail': - echo '
{% trans 'phraseanet::erreur: Echec du serveur mail' %}
- break; - case 'token': - echo '
{% trans 'phraseanet::erreur: l\'url n\'est plus valide' %}
- break; - } + {% if not tokenize %} + + {% if errorMsg is not none %} +
{{ errorMsg }}
{% endif %} - {% if not parm['sent'] == null %} - switch ($parm['sent']) { - case 'ok': - echo '
{% trans 'phraseanet:: Un email vient de vous etre envoye' %}
- break; - } + + {% if sentMsg is not none %} +
{{ sentMsg }}
{% endif %} +
{% trans 'login:: Forgot your password' %}
@@ -160,7 +155,7 @@
{% endif %} diff --git a/templates/web/developers/applications.html.twig b/templates/web/developers/applications.html.twig index 0f9c67e725..3cad3147c7 100644 --- a/templates/web/developers/applications.html.twig +++ b/templates/web/developers/applications.html.twig @@ -12,7 +12,7 @@
-

Phraseanet Developper Center

+

Phraseanet Developer Center

{% trans 'Mes applications' %}

{% if apps|length > 0 %}
    From 5873eca1703d544d2cd07463157c7fceef864f90 Mon Sep 17 00:00:00 2001 From: Nicolas Le Goff Date: Fri, 13 Jul 2012 19:34:52 +0200 Subject: [PATCH 9/9] replace forgot-password url & delete olf forgotpassword.php file --- .../Phrasea/Controller/Root/Account.php | 2 +- templates/mobile/login/index.twig | 2 +- .../login/index_layout_displaycooliris.twig | 2 +- .../web/login/index_layout_displayscroll.twig | 2 +- .../web/login/index_layout_displayx1.twig | 2 +- www/login/authenticate.php | 2 +- www/login/forgotpwd.php | 283 ------------------ 7 files changed, 6 insertions(+), 289 deletions(-) delete mode 100644 www/login/forgotpwd.php diff --git a/lib/Alchemy/Phrasea/Controller/Root/Account.php b/lib/Alchemy/Phrasea/Controller/Root/Account.php index ddb704f331..fd9c42b229 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/Account.php +++ b/lib/Alchemy/Phrasea/Controller/Root/Account.php @@ -221,7 +221,7 @@ public function renewPassword(Application $app, Request $request) $token = \random::getUrlToken(\random::TYPE_PASSWORD, $user->get_id(), new \DateTime('+1 day')); if ($token) { - $url = sprintf('%slogin/forgotpwd.php?token=%s', $app['Registry']->get('GV_ServerName'), $token); + $url = sprintf('%saccount/forgot-password/?token=%s', $app['Registry']->get('GV_ServerName'), $token); if (\mail::forgot_passord($email, $user->get_login(), $url)) { return $app->redirect('/account/forgot-password/?sent=ok'); diff --git a/templates/mobile/login/index.twig b/templates/mobile/login/index.twig index 61974a8756..70a5877218 100644 --- a/templates/mobile/login/index.twig +++ b/templates/mobile/login/index.twig @@ -48,7 +48,7 @@
    • - + {% trans 'login:: Forgot your password' %}
    • diff --git a/templates/web/login/index_layout_displaycooliris.twig b/templates/web/login/index_layout_displaycooliris.twig index 596d8bb463..1184dc9daa 100644 --- a/templates/web/login/index_layout_displaycooliris.twig +++ b/templates/web/login/index_layout_displaycooliris.twig @@ -5,7 +5,7 @@ {{login.get_guest_link|raw}}
diff --git a/templates/web/login/index_layout_displayscroll.twig b/templates/web/login/index_layout_displayscroll.twig index 2b08bad5b5..6ce1b46690 100644 --- a/templates/web/login/index_layout_displayscroll.twig +++ b/templates/web/login/index_layout_displayscroll.twig @@ -5,7 +5,7 @@ {{login.get_guest_link|raw}}
- + {% trans 'login:: Forgot your password' %}
diff --git a/templates/web/login/index_layout_displayx1.twig b/templates/web/login/index_layout_displayx1.twig index dc26db2841..302481c3e6 100644 --- a/templates/web/login/index_layout_displayx1.twig +++ b/templates/web/login/index_layout_displayx1.twig @@ -39,7 +39,7 @@
- + {% trans 'login:: Forgot your password' %}
diff --git a/www/login/authenticate.php b/www/login/authenticate.php index e7e0403eea..7f31e25f7f 100644 --- a/www/login/authenticate.php +++ b/www/login/authenticate.php @@ -83,7 +83,7 @@ $usr_id = User_Adapter::get_usr_id_from_login($parm['login']); $url = random::getUrlToken(\random::TYPE_PASSWORD, $usr_id, $date); - $url = '/login/forgotpwd.php?token=' . $url . '&salt=1'; + $url = '/account/forgot-password/?token=' . $url . '&salt=1'; return phrasea::redirect($url); } catch (\Exception $e) { diff --git a/www/login/forgotpwd.php b/www/login/forgotpwd.php deleted file mode 100644 index 2e4e3580e6..0000000000 --- a/www/login/forgotpwd.php +++ /dev/null @@ -1,283 +0,0 @@ -get_session(); -$registry = $appbox->get_registry(); - -$request = http_request::getInstance(); -$parm = $request->get_parms('salt', 'error', 'sent', 'token', 'form_password', 'form_password_confirm', 'mail'); - -$needed = array(); - -if (isset($parm["mail"]) && trim($parm["mail"]) != "") { - if ( ! PHPMailer::ValidateAddress($parm['mail'])) { - return phrasea::redirect('/login/forgotpwd.php?error=noaccount'); - } - - try { - $usr_id = User_Adapter::get_usr_id_from_email($parm['mail']); - $user = User_Adapter::getInstance($usr_id, $appbox); - } catch (Exception $e) { - return phrasea::redirect('/login/forgotpwd.php?error=noaccount'); - } - - $date = new DateTime('1 day'); - $url = random::getUrlToken(\random::TYPE_PASSWORD, $user->get_id(), $date); - - if ($url !== false) { - $url = $registry->get('GV_ServerName') . 'login/forgotpwd.php?token=' . $url; - if (mail::forgot_passord($parm['mail'], $user->get_login(), $url) === true) { - return phrasea::redirect('/login/forgotpwd.php?sent=ok'); - } else { - return phrasea::redirect('/login/forgotpwd.php?error=mailserver'); - } - } - - return phrasea::redirect('/login/forgotpwd.php?error=noaccount'); -} -if (isset($parm['token']) && isset($parm['form_password']) && isset($parm['form_password_confirm'])) { - if ($parm['form_password'] !== $parm['form_password_confirm']) - $needed['form_password'] = $needed['form_password_confirm'] = _('forms::les mots de passe ne correspondent pas'); - elseif (strlen(trim($parm['form_password'])) < 5) - $needed['form_password'] = _('forms::la valeur donnee est trop courte'); - elseif (trim($parm['form_password']) != str_replace(array("\r\n", "\n", "\r", "\t", " "), "_", $parm['form_password'])) - $needed['form_password'] = _('forms::la valeur donnee contient des caracteres invalides'); - - if (count($needed) == 0) { - - try { - $datas = random::helloToken($parm['token']); - $user = User_Adapter::getInstance($datas['usr_id'], $appbox); - $user->set_password($parm['form_password_confirm']); - random::removeToken($parm['token']); - - return phrasea::redirect('/login/index.php?confirm=password-update-ok'); - } catch (Exception_NotFound $e) { - - } - } -} - -$tokenize = $tokenError = false; - -if ($parm['token'] !== null) { - try { - random::helloToken($parm['token']); - $tokenize = true; - } catch (\Exception_NotFound $e) { - $tokenError = true; - } -} - -phrasea::headers(); - -$parameters = array( - 'parm' => $parm, - 'tokenize' => $tokenize, - 'tokenError' => $tokenError, -); - -$Core['Twig']->display('user/forgotpwd.html.twig', $parameters); - -return; -?> - - - - - - <?php echo _('admin::compte-utilisateur changer mon mot de passe'); ?> - - -
-
- - - - - -
get('GV_homeTitle') ?>
-
-
-
-
- -
-
- - - - - - - - - -
-
- -
- -
- - - - - - - - - - - - - - - - -
-
- -
-
-
- -
-
 
-
-
-
-
-
-
- -
- -
-
-
- -
-
- - - - -
-
- '; - - if ($parm['error'] !== null) { - switch ($parm['error']) { - case 'mailserver': - echo '
' . _('phraseanet::erreur: Echec du serveur mail') . '
'; - break; - case 'noaccount': - echo '
' . _('phraseanet::erreur: Le compte n\'a pas ete trouve') . '
'; - break; - case 'mail': - echo '
' . _('phraseanet::erreur: Echec du serveur mail') . '
'; - break; - case 'token': - echo '
' . _('phraseanet::erreur: l\'url n\'est plus valide') . '
'; - break; - } - } - if ($parm['sent'] !== null) { - switch ($parm['sent']) { - case 'ok': - echo '
' . _('phraseanet:: Un email vient de vous etre envoye') . '
'; - break; - } - } - ?> -
- -
-
- -
-
- -
-
- - -
- - -
-
-
-
© Copyright Alchemy 2005-
-
-
- -