Controller: refactoring ($app access)

"GistService" renamed as "Gist"
Authentication
This commit is contained in:
Simon Vieille 2015-11-23 13:19:13 +01:00
parent ed37fbf453
commit 51d736cb1a
14 changed files with 271 additions and 67 deletions

View file

@ -1,6 +1,7 @@
<?php <?php
use Symfony\Component\Routing\Loader\YamlFileLoader; use Symfony\Component\Routing\Loader\YamlFileLoader;
use Gist\ControllerResolver;
$app['routing.file'] = 'routing.yml'; $app['routing.file'] = 'routing.yml';
@ -13,3 +14,13 @@ $app['routes'] = $app->extend('routes', function ($routes, $app) {
return $routes; return $routes;
}); });
$app['resolver'] = $app->share(function () use ($app) {
if (isset($app['logger'])){
$logger = $app['logger'];
} else{
$logger = null;
}
return new ControllerResolver($app, isset($app['logger']) ? $app['logger'] : null);
});

View file

@ -1,7 +1,7 @@
<?php <?php
use GitWrapper\GitWrapper; use GitWrapper\GitWrapper;
use Gist\Service\GistService; use Gist\Service\Gist;
$app['gist_path'] = $app['root_path'].'/data/git'; $app['gist_path'] = $app['root_path'].'/data/git';
@ -14,5 +14,5 @@ $app['git_working_copy'] = $app->share(function ($app) {
}); });
$app['gist'] = $app->share(function ($app) { $app['gist'] = $app->share(function ($app) {
return new GistService($app['gist_path'], $app['git_wrapper'], $app['git_working_copy'], $app['geshi']); return new Gist($app['gist_path'], $app['git_wrapper'], $app['git_working_copy'], $app['geshi']);
}); });

View file

@ -2,7 +2,6 @@
namespace Gist\Controller; namespace Gist\Controller;
use Silex\Application;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Gist\Model\Gist; use Gist\Model\Gist;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
@ -16,8 +15,10 @@ use Gist\Form\ApiUpdateGistForm;
*/ */
class ApiController extends Controller class ApiController extends Controller
{ {
public function createAction(Request $request, Application $app) public function createAction(Request $request)
{ {
$app = $this->getApp();
if (false === $request->isMethod('post')) { if (false === $request->isMethod('post')) {
return $this->invalidMethodResponse('POST method is required.'); return $this->invalidMethodResponse('POST method is required.');
} }
@ -53,9 +54,11 @@ class ApiController extends Controller
return $this->invalidRequestResponse('Invalid field(s)'); return $this->invalidRequestResponse('Invalid field(s)');
} }
public function updateAction(Request $request, Application $app, $gist) public function updateAction(Request $request, $gist)
{ {
$app = $this->getApp();
if (false === $request->isMethod('post')) { if (false === $request->isMethod('post')) {
return $this->invalidMethodResponse('POST method is required.'); return $this->invalidMethodResponse('POST method is required.');
} }

View file

@ -14,8 +14,22 @@ use Symfony\Component\HttpFoundation\Response;
*/ */
class Controller class Controller
{ {
protected function notFoundResponse(Application $app) protected $app;
public function __construct(Application $app)
{ {
$this->app = $app;
}
public function getApp()
{
return $this->app;
}
protected function notFoundResponse()
{
$app = $this->getApp();
return new Response( return new Response(
$app['twig']->render( $app['twig']->render(
'View/notFound.html.twig', 'View/notFound.html.twig',
@ -25,8 +39,10 @@ class Controller
); );
} }
protected function getViewOptions(Request $request, Application $app, $gist, $commit) protected function getViewOptions(Request $request, $gist, $commit)
{ {
$app = $this->getApp();
$gist = GistQuery::create()->findOneByFile($gist); $gist = GistQuery::create()->findOneByFile($gist);
if (null === $gist) { if (null === $gist) {
@ -39,7 +55,7 @@ class Controller
return null; return null;
} }
$content = $this->getContentByCommit($app, $gist, $commit, $history); $content = $this->getContentByCommit($gist, $commit, $history);
return array( return array(
'gist' => $gist, 'gist' => $gist,
@ -51,8 +67,10 @@ class Controller
); );
} }
protected function getContentByCommit(Application $app, Gist $gist, &$commit, $history) protected function getContentByCommit(Gist $gist, &$commit, $history)
{ {
$app = $this->getApp();
if ($commit === 0) { if ($commit === 0) {
$commit = $history[0]['commit']; $commit = $history[0]['commit'];
} else { } else {
@ -72,8 +90,10 @@ class Controller
return $app['gist']->getContent($gist, $commit); return $app['gist']->getContent($gist, $commit);
} }
public function getUser(Application $app) public function getUser()
{ {
$app = $this->getApp();
$securityContext = $app['security']; $securityContext = $app['security'];
$securityToken = $securityContext->getToken(); $securityToken = $securityContext->getToken();
@ -84,10 +104,12 @@ class Controller
return $securityToken->getUser(); return $securityToken->getUser();
} }
public function render($template, array $params, Application $app) public function render($template, array $params)
{ {
$app = $this->getApp();
if (!isset($params['user'])) { if (!isset($params['user'])) {
$params['user'] = $this->getUser($app); $params['user'] = $this->getUser();
} }
return $app['twig']->render( return $app['twig']->render(

View file

@ -2,7 +2,6 @@
namespace Gist\Controller; namespace Gist\Controller;
use Silex\Application;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Gist\Form\CreateGistForm; use Gist\Form\CreateGistForm;
use Gist\Form\CloneGistForm; use Gist\Form\CloneGistForm;
@ -16,8 +15,10 @@ use Symfony\Component\HttpFoundation\RedirectResponse;
*/ */
class EditController extends Controller class EditController extends Controller
{ {
public function createAction(Request $request, Application $app) public function createAction(Request $request)
{ {
$app = $this->getApp();
$data = array( $data = array(
'type' => 'html', 'type' => 'html',
'cipher' => 'no', 'cipher' => 'no',
@ -30,7 +31,7 @@ class EditController extends Controller
$form->submit($request); $form->submit($request);
if ($form->isValid()) { if ($form->isValid()) {
$gist = $app['gist']->create(new Gist(), $form->getData()); $gist = $app['gist']->create(new Gist(), $form->getData(), $this->getUser());
} }
} }
@ -39,14 +40,15 @@ class EditController extends Controller
array( array(
'gist' => isset($gist) ? $gist : null, 'gist' => isset($gist) ? $gist : null,
'form' => $form->createView(), 'form' => $form->createView(),
), )
$app
); );
} }
public function cloneAction(Request $request, Application $app, $gist, $commit) public function cloneAction(Request $request, $gist, $commit)
{ {
$viewOptions = $this->getViewOptions($request, $app, $gist, $commit); $app = $this->getApp();
$viewOptions = $this->getViewOptions($request, $gist, $commit);
$data = array( $data = array(
'type' => $viewOptions['gist']->getType(), 'type' => $viewOptions['gist']->getType(),
@ -81,6 +83,6 @@ class EditController extends Controller
$viewOptions['form'] = $form->createView(); $viewOptions['form'] = $form->createView();
return $this->render('Edit/clone.html.twig', $viewOptions, $app); return $this->render('Edit/clone.html.twig', $viewOptions);
} }
} }

View file

@ -2,9 +2,7 @@
namespace Gist\Controller; namespace Gist\Controller;
use Gist\Controller\Controller;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Silex\Application;
use Gist\Model\User; use Gist\Model\User;
use Gist\Form\UserRegisterForm; use Gist\Form\UserRegisterForm;
use Gist\Form\UserLoginForm; use Gist\Form\UserLoginForm;
@ -16,8 +14,10 @@ use Symfony\Component\HttpFoundation\Response;
*/ */
class LoginController extends Controller class LoginController extends Controller
{ {
public function registerAction(Request $request, Application $app) public function registerAction(Request $request)
{ {
$app = $this->getApp();
if (false === $app['enable_registration']) { if (false === $app['enable_registration']) {
return new Response('', 403); return new Response('', 403);
} }
@ -55,13 +55,14 @@ class LoginController extends Controller
'form' => $form->createView(), 'form' => $form->createView(),
'error' => isset($error) ? $error : '', 'error' => isset($error) ? $error : '',
'success' => isset($success) ? $success : '', 'success' => isset($success) ? $success : '',
], ]
$app
); );
} }
public function loginAction(Request $request, Application $app) public function loginAction(Request $request)
{ {
$app = $this->getApp();
if (false === $app['enable_login']) { if (false === $app['enable_login']) {
return new Response('', 403); return new Response('', 403);
} }
@ -86,17 +87,15 @@ class LoginController extends Controller
[ [
'form' => $form->createView(), 'form' => $form->createView(),
'error' => isset($error) ? $error : '', 'error' => isset($error) ? $error : '',
], ]
$app
); );
} }
public function loginCheckAction() public function loginCheckAction()
{ {
} }
public function logoutAction() public function logoutAction()
{ {
} }
} }

View file

@ -2,9 +2,7 @@
namespace Gist\Controller; namespace Gist\Controller;
use Gist\Controller\Controller;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Silex\Application;
/** /**
* Class MyController * Class MyController
@ -12,10 +10,8 @@ use Silex\Application;
*/ */
class MyController extends Controller class MyController extends Controller
{ {
public function myAction(Request $request, Application $app) public function myAction(Request $request)
{ {
echo '<pre>', var_dump($this->getUser($app)), '</pre>'; $app = $this->getApp();
die;
} }
} }

View file

@ -14,34 +14,38 @@ use Symfony\Component\HttpFoundation\Response;
*/ */
class ViewController extends Controller class ViewController extends Controller
{ {
public function viewAction(Request $request, Application $app, $gist, $commit) public function viewAction(Request $request, $gist, $commit)
{ {
$viewOptions = $this->getViewOptions($request, $app, $gist, $commit); $app = $this->getApp();
$viewOptions = $this->getViewOptions($request, $gist, $commit);
if (is_array($viewOptions)) { if (is_array($viewOptions)) {
return $this->render('View/view.html.twig', $viewOptions, $app); return $this->render('View/view.html.twig', $viewOptions);
} else { } else {
return $this->notFoundResponse($app); return $this->notFoundResponse();
} }
} }
public function embedAction(Request $request, Application $app, $gist, $commit) public function embedAction(Request $request, $gist, $commit)
{ {
$viewOptions = $this->getViewOptions($request, $app, $gist, $commit); $app = $this->getApp();
$viewOptions = $this->getViewOptions($request, $gist, $commit);
if (is_array($viewOptions)) { if (is_array($viewOptions)) {
return $app['twig']->render('View/embed.html.twig', $viewOptions); return $app['twig']->render('View/embed.html.twig', $viewOptions);
} else { } else {
return $this->notFoundResponse($app); return $this->notFoundResponse();
} }
} }
public function embedJsAction(Request $request, Application $app, $gist, $commit) public function embedJsAction(Request $request, $gist, $commit)
{ {
$viewOptions = $this->getViewOptions($request, $app, $gist, $commit); $viewOptions = $this->getViewOptions($request, $gist, $commit);
return new Response( return new Response(
$this->render('View/embedJs.html.twig', $viewOptions, $app), $this->render('View/embedJs.html.twig', $viewOptions),
200, 200,
array( array(
'Content-Type' => 'text/javascript', 'Content-Type' => 'text/javascript',
@ -49,9 +53,9 @@ class ViewController extends Controller
); );
} }
public function rawAction(Request $request, Application $app, $gist, $commit) public function rawAction(Request $request, $gist, $commit)
{ {
$viewOptions = $this->getViewOptions($request, $app, $gist, $commit); $viewOptions = $this->getViewOptions($request, $gist, $commit);
if (is_array($viewOptions)) { if (is_array($viewOptions)) {
return new Response( return new Response(
@ -62,13 +66,15 @@ class ViewController extends Controller
) )
); );
} else { } else {
return $this->notFoundResponse($app); return $this->notFoundResponse();
} }
} }
public function downloadAction(Request $request, Application $app, $gist, $commit) public function downloadAction(Request $request, $gist, $commit)
{ {
$viewOptions = $this->getViewOptions($request, $app, $gist, $commit); $app = $this->getApp();
$viewOptions = $this->getViewOptions($request, $gist, $commit);
if (is_array($viewOptions)) { if (is_array($viewOptions)) {
$gist = $viewOptions['gist']; $gist = $viewOptions['gist'];
@ -88,18 +94,20 @@ class ViewController extends Controller
} }
} }
public function revisionsAction(Request $request, Application $app, $gist) public function revisionsAction(Request $request, $gist)
{ {
$app = $this->getApp();
$gist = GistQuery::create()->findOneByFile($gist); $gist = GistQuery::create()->findOneByFile($gist);
if (null === $gist) { if (null === $gist) {
return $this->notFoundResponse($app); return $this->notFoundResponse();
} }
$history = $app['gist']->getHistory($gist); $history = $app['gist']->getHistory($gist);
if (empty($history)) { if (empty($history)) {
return $this->notFoundResponse($app); return $this->notFoundResponse();
} }
return $this->render( return $this->render(
@ -107,8 +115,7 @@ class ViewController extends Controller
array( array(
'gist' => $gist, 'gist' => $gist,
'history' => $history, 'history' => $history,
), )
$app
); );
} }
} }

View file

@ -0,0 +1,19 @@
<?php
namespace Gist;
use Silex\ControllerResolver as BaseControllerResolver;
use Gist\Application;
/**
* Class DecoratorControllerResolver
* @author Simon Vieille <simon@deblan.fr>
*/
class ControllerResolver extends BaseControllerResolver
{
protected function instantiateController($class)
{
return new $class($this->app);
}
}

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<database defaultIdMethod="native" name="default" namespace="Gist\Model"> <database defaultIdMethod="native" name="default" namespace="Gist\Model">
<table name="gist"> <table name="gist" isCrossRef="true">
<column name="id" type="INTEGER" primaryKey="true" required="true" autoIncrement="true"/> <column name="id" type="INTEGER" primaryKey="true" required="true" autoIncrement="true"/>
<column name="title" type="VARCHAR" size="255" required="false" /> <column name="title" type="VARCHAR" size="255" required="false" />
<column name="cipher" type="BOOLEAN" required="true" defaultValue="false" /> <column name="cipher" type="BOOLEAN" required="true" defaultValue="false" />
@ -15,7 +15,7 @@
<behavior name="timestampable"/> <behavior name="timestampable"/>
</table> </table>
<table name="user"> <table name="user" isCrossRef="true">
<column name="id" type="INTEGER" primaryKey="true" required="true" autoIncrement="true"/> <column name="id" type="INTEGER" primaryKey="true" required="true" autoIncrement="true"/>
<column name="username" type="VARCHAR" size="255" required="true" /> <column name="username" type="VARCHAR" size="255" required="true" />
<column name="password" type="VARCHAR" size="255" required="true" /> <column name="password" type="VARCHAR" size="255" required="true" />

View file

@ -0,0 +1,41 @@
<?php
namespace Gist\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGenerator;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
/**
* Class AuthenticationEntryPoint
* @author Simon Vieille <simon@deblan.fr>
*/
class AuthenticationEntryPoint implements AuthenticationEntryPointInterface
{
protected $urlGenerator;
public function __construct(UrlGenerator $urlGenerator)
{
$this->urlGenerator = $urlGenerator;
}
public function start(Request $request, AuthenticationException $authException = null)
{
if ($request->isXmlHttpRequest()) {
$response = new Response(json_encode([]), 401);
$response->headers->set('Content-Type', 'application/json');
return $response;
}
if ($authException->getMessage() !== 'Full authentication is required to access this resource.') {
$params = ['error' => 1];
} else {
$params = [];
}
return new RedirectResponse($this->urlGenerator->generate('_login', $params));
}
}

View file

@ -0,0 +1,50 @@
<?php
namespace Gist\Security;
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGenerator;
/**
* Class AuthenticationListener
* @author Simon Vieille <simon@deblan.fr>
*/
class AuthenticationListener implements ListenerInterface
{
protected $tokenStorage;
protected $authenticationManager;
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager)
{
$this->tokenStorage = $tokenStorage;
$this->authenticationManager = $authenticationManager;
}
public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
$username = $request->get('_username');
$password = $request->get('_password');
if (!empty($username)) {
$token = new UsernamePasswordToken($username, $password, 'default');
try {
$authToken = $this->authenticationManager->authenticate($token);
$this->tokenStorage->setToken($token);
return;
} catch (AuthenticationException $failed) {
$this->tokenStorage->setToken(null);
return;
}
}
}
}

View file

@ -0,0 +1,49 @@
<?php
namespace Gist\Security;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Gist\Service\UserProvider;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
/**
* Class AuthenticationProvider
* @author Simon Vieille <simon@deblan.fr>
*/
class AuthenticationProvider implements AuthenticationProviderInterface
{
protected $userProvider;
public function __construct(UserProvider $userProvider)
{
$this->userProvider = $userProvider;
}
public function authenticate(TokenInterface $token)
{
$user = $this->userProvider->loadUserByUsername($token->getUser());
if ($user) {
$isValid = $this->userProvider->getEncoder()->isPasswordValid(
$user->getPassword(),
$token->getCredentials(),
$user->getSalt()
);
if (!$isValid) {
throw new AuthenticationException('Authentication failed.');
}
return;
}
throw new AuthenticationException('Authentication failed.');
}
public function supports(TokenInterface $token)
{
return $token instanceof UsernamePasswordToken;
}
}

View file

@ -2,18 +2,19 @@
namespace Gist\Service; namespace Gist\Service;
use Gist\Model\Gist; use Gist\Model\Gist as GistModel;
use GitWrapper\GitWorkingCopy; use GitWrapper\GitWorkingCopy;
use GitWrapper\GitWrapper; use GitWrapper\GitWrapper;
use GitWrapper\GitCommand; use GitWrapper\GitCommand;
use GeSHi; use GeSHi;
use Gist\Model\GistQuery; use Gist\Model\GistQuery;
use Gist\Model\User;
/** /**
* Class GistService * Class Gist
* @author Simon Vieille <simon@deblan.fr> * @author Simon Vieille <simon@deblan.fr>
*/ */
class GistService class Gist
{ {
protected $gistPath; protected $gistPath;
@ -36,7 +37,7 @@ class GistService
return GistQuery::create()->find(); return GistQuery::create()->find();
} }
public function getHistory(Gist $gist) public function getHistory(GistModel $gist)
{ {
$command = GitCommand::getInstance('log', '--format=medium', $gist->getFile()); $command = GitCommand::getInstance('log', '--format=medium', $gist->getFile());
$command->setDirectory($this->gistPath); $command->setDirectory($this->gistPath);
@ -70,7 +71,7 @@ class GistService
return $history; return $history;
} }
public function getContent(Gist $gist, $commit) public function getContent(GistModel $gist, $commit)
{ {
$command = GitCommand::getInstance('cat-file', '-p', $commit.':'.$gist->getFile()); $command = GitCommand::getInstance('cat-file', '-p', $commit.':'.$gist->getFile());
$command->setDirectory($this->gistPath); $command->setDirectory($this->gistPath);
@ -79,7 +80,7 @@ class GistService
return $this->gitWrapper->run($command); return $this->gitWrapper->run($command);
} }
public function create(Gist $gist, array $data) public function create(GistModel $gist, array $data, $user = null)
{ {
$gist->hydrateWith($data); $gist->hydrateWith($data);
$gist->generateFilename(); $gist->generateFilename();
@ -90,12 +91,16 @@ class GistService
->add($gist->getFile()) ->add($gist->getFile())
->commit('Init'); ->commit('Init');
if (is_object($user) && $user instanceof User) {
$gist->setUser($user);
}
$gist->save(); $gist->save();
return $gist; return $gist;
} }
public function commit(Gist $gist, array $data) public function commit(GistModel $gist, array $data)
{ {
file_put_contents($this->gistPath.'/'.$gist->getFile(), $data['content']); file_put_contents($this->gistPath.'/'.$gist->getFile(), $data['content']);