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
use Symfony\Component\Routing\Loader\YamlFileLoader;
use Gist\ControllerResolver;
$app['routing.file'] = 'routing.yml';
@ -13,3 +14,13 @@ $app['routes'] = $app->extend('routes', function ($routes, $app) {
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
use GitWrapper\GitWrapper;
use Gist\Service\GistService;
use Gist\Service\Gist;
$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) {
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;
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Gist\Model\Gist;
use Symfony\Component\HttpFoundation\JsonResponse;
@ -16,8 +15,10 @@ use Gist\Form\ApiUpdateGistForm;
*/
class ApiController extends Controller
{
public function createAction(Request $request, Application $app)
public function createAction(Request $request)
{
$app = $this->getApp();
if (false === $request->isMethod('post')) {
return $this->invalidMethodResponse('POST method is required.');
}
@ -53,9 +54,11 @@ class ApiController extends Controller
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')) {
return $this->invalidMethodResponse('POST method is required.');
}

View file

@ -14,8 +14,22 @@ use Symfony\Component\HttpFoundation\Response;
*/
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(
$app['twig']->render(
'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);
if (null === $gist) {
@ -39,7 +55,7 @@ class Controller
return null;
}
$content = $this->getContentByCommit($app, $gist, $commit, $history);
$content = $this->getContentByCommit($gist, $commit, $history);
return array(
'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) {
$commit = $history[0]['commit'];
} else {
@ -72,8 +90,10 @@ class Controller
return $app['gist']->getContent($gist, $commit);
}
public function getUser(Application $app)
public function getUser()
{
$app = $this->getApp();
$securityContext = $app['security'];
$securityToken = $securityContext->getToken();
@ -84,10 +104,12 @@ class Controller
return $securityToken->getUser();
}
public function render($template, array $params, Application $app)
public function render($template, array $params)
{
$app = $this->getApp();
if (!isset($params['user'])) {
$params['user'] = $this->getUser($app);
$params['user'] = $this->getUser();
}
return $app['twig']->render(

View file

@ -2,7 +2,6 @@
namespace Gist\Controller;
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Gist\Form\CreateGistForm;
use Gist\Form\CloneGistForm;
@ -16,8 +15,10 @@ use Symfony\Component\HttpFoundation\RedirectResponse;
*/
class EditController extends Controller
{
public function createAction(Request $request, Application $app)
public function createAction(Request $request)
{
$app = $this->getApp();
$data = array(
'type' => 'html',
'cipher' => 'no',
@ -30,7 +31,7 @@ class EditController extends Controller
$form->submit($request);
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(
'gist' => isset($gist) ? $gist : null,
'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(
'type' => $viewOptions['gist']->getType(),
@ -81,6 +83,6 @@ class EditController extends Controller
$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;
use Gist\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Silex\Application;
use Gist\Model\User;
use Gist\Form\UserRegisterForm;
use Gist\Form\UserLoginForm;
@ -16,8 +14,10 @@ use Symfony\Component\HttpFoundation\Response;
*/
class LoginController extends Controller
{
public function registerAction(Request $request, Application $app)
public function registerAction(Request $request)
{
$app = $this->getApp();
if (false === $app['enable_registration']) {
return new Response('', 403);
}
@ -55,13 +55,14 @@ class LoginController extends Controller
'form' => $form->createView(),
'error' => isset($error) ? $error : '',
'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']) {
return new Response('', 403);
}
@ -86,17 +87,15 @@ class LoginController extends Controller
[
'form' => $form->createView(),
'error' => isset($error) ? $error : '',
],
$app
]
);
}
public function loginCheckAction()
{
}
public function logoutAction()
{
}
}

View file

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

View file

@ -14,34 +14,38 @@ use Symfony\Component\HttpFoundation\Response;
*/
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)) {
return $this->render('View/view.html.twig', $viewOptions, $app);
return $this->render('View/view.html.twig', $viewOptions);
} 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)) {
return $app['twig']->render('View/embed.html.twig', $viewOptions);
} 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(
$this->render('View/embedJs.html.twig', $viewOptions, $app),
$this->render('View/embedJs.html.twig', $viewOptions),
200,
array(
'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)) {
return new Response(
@ -62,13 +66,15 @@ class ViewController extends Controller
)
);
} 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)) {
$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);
if (null === $gist) {
return $this->notFoundResponse($app);
return $this->notFoundResponse();
}
$history = $app['gist']->getHistory($gist);
if (empty($history)) {
return $this->notFoundResponse($app);
return $this->notFoundResponse();
}
return $this->render(
@ -107,8 +115,7 @@ class ViewController extends Controller
array(
'gist' => $gist,
'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"?>
<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="title" type="VARCHAR" size="255" required="false" />
<column name="cipher" type="BOOLEAN" required="true" defaultValue="false" />
@ -15,7 +15,7 @@
<behavior name="timestampable"/>
</table>
<table name="user">
<table name="user" isCrossRef="true">
<column name="id" type="INTEGER" primaryKey="true" required="true" autoIncrement="true"/>
<column name="username" 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;
use Gist\Model\Gist;
use Gist\Model\Gist as GistModel;
use GitWrapper\GitWorkingCopy;
use GitWrapper\GitWrapper;
use GitWrapper\GitCommand;
use GeSHi;
use Gist\Model\GistQuery;
use Gist\Model\User;
/**
* Class GistService
* Class Gist
* @author Simon Vieille <simon@deblan.fr>
*/
class GistService
class Gist
{
protected $gistPath;
@ -36,7 +37,7 @@ class GistService
return GistQuery::create()->find();
}
public function getHistory(Gist $gist)
public function getHistory(GistModel $gist)
{
$command = GitCommand::getInstance('log', '--format=medium', $gist->getFile());
$command->setDirectory($this->gistPath);
@ -70,7 +71,7 @@ class GistService
return $history;
}
public function getContent(Gist $gist, $commit)
public function getContent(GistModel $gist, $commit)
{
$command = GitCommand::getInstance('cat-file', '-p', $commit.':'.$gist->getFile());
$command->setDirectory($this->gistPath);
@ -79,7 +80,7 @@ class GistService
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->generateFilename();
@ -90,12 +91,16 @@ class GistService
->add($gist->getFile())
->commit('Init');
if (is_object($user) && $user instanceof User) {
$gist->setUser($user);
}
$gist->save();
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']);